diff options
215 files changed, 17516 insertions, 4560 deletions
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt index 1a1ac2e560e9..f47e56bcf78d 100644 --- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt +++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt | |||
| @@ -18,6 +18,7 @@ atmel,24c02 i2c serial eeprom (24cxx) | |||
| 18 | atmel,at97sc3204t i2c trusted platform module (TPM) | 18 | atmel,at97sc3204t i2c trusted platform module (TPM) |
| 19 | capella,cm32181 CM32181: Ambient Light Sensor | 19 | capella,cm32181 CM32181: Ambient Light Sensor |
| 20 | catalyst,24c32 i2c serial eeprom | 20 | catalyst,24c32 i2c serial eeprom |
| 21 | cirrus,cs42l51 Cirrus Logic CS42L51 audio codec | ||
| 21 | dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock | 22 | dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock |
| 22 | dallas,ds1338 I2C RTC with 56-Byte NV RAM | 23 | dallas,ds1338 I2C RTC with 56-Byte NV RAM |
| 23 | dallas,ds1339 I2C Serial Real-Time Clock | 24 | dallas,ds1339 I2C Serial Real-Time Clock |
diff --git a/Documentation/devicetree/bindings/misc/atmel-ssc.txt b/Documentation/devicetree/bindings/misc/atmel-ssc.txt index 60960b2755f4..efc98ea1f23d 100644 --- a/Documentation/devicetree/bindings/misc/atmel-ssc.txt +++ b/Documentation/devicetree/bindings/misc/atmel-ssc.txt | |||
| @@ -17,6 +17,14 @@ Required properties for devices compatible with "atmel,at91sam9g45-ssc": | |||
| 17 | See Documentation/devicetree/bindings/dma/atmel-dma.txt for details. | 17 | See Documentation/devicetree/bindings/dma/atmel-dma.txt for details. |
| 18 | - dma-names: Must be "tx", "rx". | 18 | - dma-names: Must be "tx", "rx". |
| 19 | 19 | ||
| 20 | Optional properties: | ||
| 21 | - atmel,clk-from-rk-pin: bool property. | ||
| 22 | - When SSC works in slave mode, according to the hardware design, the | ||
| 23 | clock can get from TK pin, and also can get from RK pin. So, add | ||
| 24 | this parameter to choose where the clock from. | ||
| 25 | - By default the clock is from TK pin, if the clock from RK pin, this | ||
| 26 | property is needed. | ||
| 27 | |||
| 20 | Examples: | 28 | Examples: |
| 21 | - PDC transfer: | 29 | - PDC transfer: |
| 22 | ssc0: ssc@fffbc000 { | 30 | ssc0: ssc@fffbc000 { |
diff --git a/Documentation/devicetree/bindings/sound/da9055.txt b/Documentation/devicetree/bindings/sound/da9055.txt new file mode 100644 index 000000000000..ed1b7cc6f249 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/da9055.txt | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | * Dialog DA9055 Audio CODEC | ||
| 2 | |||
| 3 | DA9055 provides Audio CODEC support (I2C only). | ||
| 4 | |||
| 5 | The Audio CODEC device in DA9055 has it's own I2C address which is configurable, | ||
| 6 | so the device is instantiated separately from the PMIC (MFD) device. | ||
| 7 | |||
| 8 | For details on accompanying PMIC I2C device, see the following: | ||
| 9 | Documentation/devicetree/bindings/mfd/da9055.txt | ||
| 10 | |||
| 11 | Required properties: | ||
| 12 | |||
| 13 | - compatible: "dlg,da9055-codec" | ||
| 14 | - reg: Specifies the I2C slave address | ||
| 15 | |||
| 16 | |||
| 17 | Example: | ||
| 18 | |||
| 19 | codec: da9055-codec@1a { | ||
| 20 | compatible = "dlg,da9055-codec"; | ||
| 21 | reg = <0x1a>; | ||
| 22 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt index 865178d5cdf3..963e100514c2 100644 --- a/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-evm-audio.txt | |||
| @@ -5,12 +5,19 @@ Required properties: | |||
| 5 | - ti,model : The user-visible name of this sound complex. | 5 | - ti,model : The user-visible name of this sound complex. |
| 6 | - ti,audio-codec : The phandle of the TLV320AIC3x audio codec | 6 | - ti,audio-codec : The phandle of the TLV320AIC3x audio codec |
| 7 | - ti,mcasp-controller : The phandle of the McASP controller | 7 | - ti,mcasp-controller : The phandle of the McASP controller |
| 8 | - ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec | ||
| 9 | - ti,audio-routing : A list of the connections between audio components. | 8 | - ti,audio-routing : A list of the connections between audio components. |
| 10 | Each entry is a pair of strings, the first being the connection's sink, | 9 | Each entry is a pair of strings, the first being the connection's sink, |
| 11 | the second being the connection's source. Valid names for sources and | 10 | the second being the connection's source. Valid names for sources and |
| 12 | sinks are the codec's pins, and the jacks on the board: | 11 | sinks are the codec's pins, and the jacks on the board: |
| 13 | 12 | ||
| 13 | Optional properties: | ||
| 14 | - ti,codec-clock-rate : The Codec Clock rate (in Hz) applied to the Codec. | ||
| 15 | - clocks : Reference to the master clock | ||
| 16 | - clock-names : The clock should be named "mclk" | ||
| 17 | - Either codec-clock-rate or the codec-clock reference has to be defined. If | ||
| 18 | the both are defined the driver attempts to set referenced clock to the | ||
| 19 | defined rate and takes the rate from the clock reference. | ||
| 20 | |||
| 14 | Board connectors: | 21 | Board connectors: |
| 15 | 22 | ||
| 16 | * Headphone Jack | 23 | * Headphone Jack |
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt new file mode 100644 index 000000000000..0d7985c864af --- /dev/null +++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | Audio complex for Eukrea boards with tlv320aic23 codec. | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible : "eukrea,asoc-tlv320" | ||
| 5 | - eukrea,model : The user-visible name of this sound complex. | ||
| 6 | - ssi-controller : The phandle of the SSI controller. | ||
| 7 | - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). | ||
| 8 | - fsl,mux-ext-port : The external port of the i.MX audio muxer. | ||
| 9 | |||
| 10 | Note: The AUDMUX port numbering should start at 1, which is consistent with | ||
| 11 | hardware manual. | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | sound { | ||
| 16 | compatible = "eukrea,asoc-tlv320"; | ||
| 17 | eukrea,model = "imx51-eukrea-tlv320aic23"; | ||
| 18 | ssi-controller = <&ssi2>; | ||
| 19 | fsl,mux-int-port = <2>; | ||
| 20 | fsl,mux-ext-port = <3>; | ||
| 21 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index d7b99fa637b5..aeb8c4a0b88d 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt | |||
| @@ -34,6 +34,10 @@ Required properties: | |||
| 34 | that ESAI would work in the synchronous mode, which means all the settings | 34 | that ESAI would work in the synchronous mode, which means all the settings |
| 35 | for Receiving would be duplicated from Transmition related registers. | 35 | for Receiving would be duplicated from Transmition related registers. |
| 36 | 36 | ||
| 37 | - big-endian : If this property is absent, the native endian mode will | ||
| 38 | be in use as default, or the big endian mode will be in use for all the | ||
| 39 | device registers. | ||
| 40 | |||
| 37 | Example: | 41 | Example: |
| 38 | 42 | ||
| 39 | esai: esai@02024000 { | 43 | esai: esai@02024000 { |
| @@ -46,5 +50,6 @@ esai: esai@02024000 { | |||
| 46 | dma-names = "rx", "tx"; | 50 | dma-names = "rx", "tx"; |
| 47 | fsl,fifo-depth = <128>; | 51 | fsl,fifo-depth = <128>; |
| 48 | fsl,esai-synchronous; | 52 | fsl,esai-synchronous; |
| 53 | big-endian; | ||
| 49 | status = "disabled"; | 54 | status = "disabled"; |
| 50 | }; | 55 | }; |
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt index f2ae335670f5..3e9e82c8eab3 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt | |||
| @@ -29,6 +29,10 @@ Required properties: | |||
| 29 | can also be referred to TxClk_Source | 29 | can also be referred to TxClk_Source |
| 30 | bit of register SPDIF_STC. | 30 | bit of register SPDIF_STC. |
| 31 | 31 | ||
| 32 | - big-endian : If this property is absent, the native endian mode will | ||
| 33 | be in use as default, or the big endian mode will be in use for all the | ||
| 34 | device registers. | ||
| 35 | |||
| 32 | Example: | 36 | Example: |
| 33 | 37 | ||
| 34 | spdif: spdif@02004000 { | 38 | spdif: spdif@02004000 { |
| @@ -50,5 +54,6 @@ spdif: spdif@02004000 { | |||
| 50 | "rxtx5", "rxtx6", | 54 | "rxtx5", "rxtx6", |
| 51 | "rxtx7"; | 55 | "rxtx7"; |
| 52 | 56 | ||
| 57 | big-endian; | ||
| 53 | status = "okay"; | 58 | status = "okay"; |
| 54 | }; | 59 | }; |
diff --git a/Documentation/devicetree/bindings/sound/pcm512x.txt b/Documentation/devicetree/bindings/sound/pcm512x.txt new file mode 100644 index 000000000000..faff75e64573 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/pcm512x.txt | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | PCM512x audio CODECs | ||
| 2 | |||
| 3 | These devices support both I2C and SPI (configured with pin strapping | ||
| 4 | on the board). | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | |||
| 8 | - compatible : One of "ti,pcm5121" or "ti,pcm5122" | ||
| 9 | |||
| 10 | - reg : the I2C address of the device for I2C, the chip select | ||
| 11 | number for SPI. | ||
| 12 | |||
| 13 | - AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the | ||
| 14 | device, as covered in bindings/regulator/regulator.txt | ||
| 15 | |||
| 16 | Optional properties: | ||
| 17 | |||
| 18 | - clocks : A clock specifier for the clock connected as SCLK. If this | ||
| 19 | is absent the device will be configured to clock from BCLK. | ||
| 20 | |||
| 21 | Example: | ||
| 22 | |||
| 23 | pcm5122: pcm5122@4c { | ||
| 24 | compatible = "ti,pcm5122"; | ||
| 25 | reg = <0x4c>; | ||
| 26 | |||
| 27 | AVDD-supply = <®_3v3_analog>; | ||
| 28 | DVDD-supply = <®_1v8>; | ||
| 29 | CPVDD-supply = <®_3v3>; | ||
| 30 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt index 19c84df5fffa..b30c222f9cd3 100644 --- a/Documentation/devicetree/bindings/sound/simple-card.txt +++ b/Documentation/devicetree/bindings/sound/simple-card.txt | |||
| @@ -8,13 +8,18 @@ Required properties: | |||
| 8 | 8 | ||
| 9 | Optional properties: | 9 | Optional properties: |
| 10 | 10 | ||
| 11 | - simple-audio-card,name : User specified audio sound card name, one string | ||
| 12 | property. | ||
| 11 | - simple-audio-card,format : CPU/CODEC common audio format. | 13 | - simple-audio-card,format : CPU/CODEC common audio format. |
| 12 | "i2s", "right_j", "left_j" , "dsp_a" | 14 | "i2s", "right_j", "left_j" , "dsp_a" |
| 13 | "dsp_b", "ac97", "pdm", "msb", "lsb" | 15 | "dsp_b", "ac97", "pdm", "msb", "lsb" |
| 16 | - simple-audio-card,widgets : Please refer to widgets.txt. | ||
| 14 | - simple-audio-card,routing : A list of the connections between audio components. | 17 | - simple-audio-card,routing : A list of the connections between audio components. |
| 15 | Each entry is a pair of strings, the first being the | 18 | Each entry is a pair of strings, the first being the |
| 16 | connection's sink, the second being the connection's | 19 | connection's sink, the second being the connection's |
| 17 | source. | 20 | source. |
| 21 | - dai-tdm-slot-num : Please refer to tdm-slot.txt. | ||
| 22 | - dai-tdm-slot-width : Please refer to tdm-slot.txt. | ||
| 18 | 23 | ||
| 19 | Required subnodes: | 24 | Required subnodes: |
| 20 | 25 | ||
| @@ -42,11 +47,19 @@ Example: | |||
| 42 | 47 | ||
| 43 | sound { | 48 | sound { |
| 44 | compatible = "simple-audio-card"; | 49 | compatible = "simple-audio-card"; |
| 50 | simple-audio-card,name = "VF610-Tower-Sound-Card"; | ||
| 45 | simple-audio-card,format = "left_j"; | 51 | simple-audio-card,format = "left_j"; |
| 52 | simple-audio-card,widgets = | ||
| 53 | "Microphone", "Microphone Jack", | ||
| 54 | "Headphone", "Headphone Jack", | ||
| 55 | "Speaker", "External Speaker"; | ||
| 46 | simple-audio-card,routing = | 56 | simple-audio-card,routing = |
| 47 | "MIC_IN", "Mic Jack", | 57 | "MIC_IN", "Microphone Jack", |
| 48 | "Headphone Jack", "HP_OUT", | 58 | "Headphone Jack", "HP_OUT", |
| 49 | "Ext Spk", "LINE_OUT"; | 59 | "External Speaker", "LINE_OUT"; |
| 60 | |||
| 61 | dai-tdm-slot-num = <2>; | ||
| 62 | dai-tdm-slot-width = <8>; | ||
| 50 | 63 | ||
| 51 | simple-audio-card,cpu { | 64 | simple-audio-card,cpu { |
| 52 | sound-dai = <&sh_fsi2 0>; | 65 | sound-dai = <&sh_fsi2 0>; |
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt new file mode 100644 index 000000000000..062f5ec36f9b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sirf-audio-codec.txt | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | SiRF internal audio CODEC | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | |||
| 5 | - compatible : "sirf,atlas6-audio-codec" or "sirf,prima2-audio-codec" | ||
| 6 | |||
| 7 | - reg : the register address of the device. | ||
| 8 | |||
| 9 | - clocks: the clock of SiRF internal audio codec | ||
| 10 | |||
| 11 | Example: | ||
| 12 | |||
| 13 | audiocodec: audiocodec@b0040000 { | ||
| 14 | compatible = "sirf,atlas6-audio-codec"; | ||
| 15 | reg = <0xb0040000 0x10000>; | ||
| 16 | clocks = <&clks 27>; | ||
| 17 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio-port.txt b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt new file mode 100644 index 000000000000..1f66de3c8f00 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sirf-audio-port.txt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | * SiRF SoC audio port | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "sirf,audio-port" | ||
| 5 | - reg: Base address and size entries: | ||
| 6 | - dmas: List of DMA controller phandle and DMA request line ordered pairs. | ||
| 7 | - dma-names: Identifier string for each DMA request line in the dmas property. | ||
| 8 | These strings correspond 1:1 with the ordered pairs in dmas. | ||
| 9 | |||
| 10 | One of the DMA channels will be responsible for transmission (should be | ||
| 11 | named "tx") and one for reception (should be named "rx"). | ||
| 12 | |||
| 13 | Example: | ||
| 14 | |||
| 15 | audioport: audioport@b0040000 { | ||
| 16 | compatible = "sirf,audio-port"; | ||
| 17 | reg = <0xb0040000 0x10000>; | ||
| 18 | dmas = <&dmac1 3>, <&dmac1 8>; | ||
| 19 | dma-names = "rx", "tx"; | ||
| 20 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/sirf-audio.txt b/Documentation/devicetree/bindings/sound/sirf-audio.txt new file mode 100644 index 000000000000..c88882ca3704 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sirf-audio.txt | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | * SiRF atlas6 and prima2 internal audio codec and port based audio setups | ||
| 2 | |||
| 3 | Required properties: | ||
| 4 | - compatible: "sirf,sirf-audio-card" | ||
| 5 | - sirf,audio-platform: phandle for the platform node | ||
| 6 | - sirf,audio-codec: phandle for the SiRF internal codec node | ||
| 7 | |||
| 8 | Optional properties: | ||
| 9 | - hp-pa-gpios: Need to be present if the board need control external | ||
| 10 | headphone amplifier. | ||
| 11 | - spk-pa-gpios: Need to be present if the board need control external | ||
| 12 | speaker amplifier. | ||
| 13 | - hp-switch-gpios: Need to be present if the board capable to detect jack | ||
| 14 | insertion, removal. | ||
| 15 | |||
| 16 | Available audio endpoints for the audio-routing table: | ||
| 17 | |||
| 18 | Board connectors: | ||
| 19 | * Headset Stereophone | ||
| 20 | * Ext Spk | ||
| 21 | * Line In | ||
| 22 | * Mic | ||
| 23 | |||
| 24 | SiRF internal audio codec pins: | ||
| 25 | * HPOUTL | ||
| 26 | * HPOUTR | ||
| 27 | * SPKOUT | ||
| 28 | * Ext Mic | ||
| 29 | * Mic Bias | ||
| 30 | |||
| 31 | Example: | ||
| 32 | |||
| 33 | sound { | ||
| 34 | compatible = "sirf,sirf-audio-card"; | ||
| 35 | sirf,audio-codec = <&audiocodec>; | ||
| 36 | sirf,audio-platform = <&audioport>; | ||
| 37 | hp-pa-gpios = <&gpio 44 0>; | ||
| 38 | spk-pa-gpios = <&gpio 46 0>; | ||
| 39 | hp-switch-gpios = <&gpio 45 0>; | ||
| 40 | }; | ||
| 41 | |||
diff --git a/Documentation/devicetree/bindings/sound/tdm-slot.txt b/Documentation/devicetree/bindings/sound/tdm-slot.txt new file mode 100644 index 000000000000..6a2c84247f91 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tdm-slot.txt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | TDM slot: | ||
| 2 | |||
| 3 | This specifies audio DAI's TDM slot. | ||
| 4 | |||
| 5 | TDM slot properties: | ||
| 6 | dai-tdm-slot-num : Number of slots in use. | ||
| 7 | dai-tdm-slot-width : Width in bits for each slot. | ||
| 8 | |||
| 9 | For instance: | ||
| 10 | dai-tdm-slot-num = <2>; | ||
| 11 | dai-tdm-slot-width = <8>; | ||
| 12 | |||
| 13 | And for each spcified driver, there could be one .of_xlate_tdm_slot_mask() | ||
| 14 | to specify a explicit mapping of the channels and the slots. If it's absent | ||
| 15 | the default snd_soc_of_xlate_tdm_slot_mask() will be used to generating the | ||
| 16 | tx and rx masks. | ||
| 17 | |||
| 18 | For snd_soc_of_xlate_tdm_slot_mask(), the tx and rx masks will use a 1 bit | ||
| 19 | for an active slot as default, and the default active bits are at the LSB of | ||
| 20 | the masks. | ||
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt new file mode 100644 index 000000000000..5e2741af27be --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | Texas Instruments - tlv320aic32x4 Codec module | ||
| 2 | |||
| 3 | The tlv320aic32x4 serial control bus communicates through I2C protocols | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible: Should be "ti,tlv320aic32x4" | ||
| 7 | - reg: I2C slave address | ||
| 8 | - supply-*: Required supply regulators are: | ||
| 9 | "iov" - digital IO power supply | ||
| 10 | "ldoin" - LDO power supply | ||
| 11 | "dv" - Digital core power supply | ||
| 12 | "av" - Analog core power supply | ||
| 13 | If you supply ldoin, dv and av are optional. Otherwise they are required | ||
| 14 | See regulator/regulator.txt for more information about the detailed binding | ||
| 15 | format. | ||
| 16 | |||
| 17 | Optional properties: | ||
| 18 | - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt | ||
| 19 | - clocks/clock-names: Clock named 'mclk' for the master clock of the codec. | ||
| 20 | See clock/clock-bindings.txt for information about the detailed format. | ||
| 21 | |||
| 22 | |||
| 23 | Example: | ||
| 24 | |||
| 25 | codec: tlv320aic32x4@18 { | ||
| 26 | compatible = "ti,tlv320aic32x4"; | ||
| 27 | reg = <0x18>; | ||
| 28 | clocks = <&clks 201>; | ||
| 29 | clock-names = "mclk"; | ||
| 30 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 9d8ea14db490..5e6040c2c2e9 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt | |||
| @@ -6,7 +6,6 @@ Required properties: | |||
| 6 | 6 | ||
| 7 | - compatible - "string" - One of: | 7 | - compatible - "string" - One of: |
| 8 | "ti,tlv320aic3x" - Generic TLV320AIC3x device | 8 | "ti,tlv320aic3x" - Generic TLV320AIC3x device |
| 9 | "ti,tlv320aic32x4" - TLV320AIC32x4 | ||
| 10 | "ti,tlv320aic33" - TLV320AIC33 | 9 | "ti,tlv320aic33" - TLV320AIC33 |
| 11 | "ti,tlv320aic3007" - TLV320AIC3007 | 10 | "ti,tlv320aic3007" - TLV320AIC3007 |
| 12 | "ti,tlv320aic3106" - TLV320AIC3106 | 11 | "ti,tlv320aic3106" - TLV320AIC3106 |
diff --git a/Documentation/devicetree/bindings/sound/widgets.txt b/Documentation/devicetree/bindings/sound/widgets.txt new file mode 100644 index 000000000000..b6de5ba3b2de --- /dev/null +++ b/Documentation/devicetree/bindings/sound/widgets.txt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | Widgets: | ||
| 2 | |||
| 3 | This mainly specifies audio off-codec DAPM widgets. | ||
| 4 | |||
| 5 | Each entry is a pair of strings in DT: | ||
| 6 | |||
| 7 | "template-wname", "user-supplied-wname" | ||
| 8 | |||
| 9 | The "template-wname" being the template widget name and currently includes: | ||
| 10 | "Microphone", "Line", "Headphone" and "Speaker". | ||
| 11 | |||
| 12 | The "user-supplied-wname" being the user specified widget name. | ||
| 13 | |||
| 14 | For instance: | ||
| 15 | simple-audio-widgets = | ||
| 16 | "Microphone", "Microphone Jack", | ||
| 17 | "Line", "Line In Jack", | ||
| 18 | "Line", "Line Out Jack", | ||
| 19 | "Headphone", "Headphone Jack", | ||
| 20 | "Speaker", "Speaker External"; | ||
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6a19515f8a45..4b2ed0c9e80d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
| @@ -2240,6 +2240,18 @@ int regmap_get_val_bytes(struct regmap *map) | |||
| 2240 | } | 2240 | } |
| 2241 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); | 2241 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); |
| 2242 | 2242 | ||
| 2243 | int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 2244 | unsigned int *val) | ||
| 2245 | { | ||
| 2246 | if (!map->format.parse_val) | ||
| 2247 | return -EINVAL; | ||
| 2248 | |||
| 2249 | *val = map->format.parse_val(buf); | ||
| 2250 | |||
| 2251 | return 0; | ||
| 2252 | } | ||
| 2253 | EXPORT_SYMBOL_GPL(regmap_parse_val); | ||
| 2254 | |||
| 2243 | static int __init regmap_initcall(void) | 2255 | static int __init regmap_initcall(void) |
| 2244 | { | 2256 | { |
| 2245 | regmap_debugfs_initcall(); | 2257 | regmap_debugfs_initcall(); |
diff --git a/drivers/misc/atmel-ssc.c b/drivers/misc/atmel-ssc.c index 5be808406edc..22de13727641 100644 --- a/drivers/misc/atmel-ssc.c +++ b/drivers/misc/atmel-ssc.c | |||
| @@ -150,6 +150,12 @@ static int ssc_probe(struct platform_device *pdev) | |||
| 150 | return -ENODEV; | 150 | return -ENODEV; |
| 151 | ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat; | 151 | ssc->pdata = (struct atmel_ssc_platform_data *)plat_dat; |
| 152 | 152 | ||
| 153 | if (pdev->dev.of_node) { | ||
| 154 | struct device_node *np = pdev->dev.of_node; | ||
| 155 | ssc->clk_from_rk_pin = | ||
| 156 | of_property_read_bool(np, "atmel,clk-from-rk-pin"); | ||
| 157 | } | ||
| 158 | |||
| 153 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 159 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 154 | ssc->regs = devm_ioremap_resource(&pdev->dev, regs); | 160 | ssc->regs = devm_ioremap_resource(&pdev->dev, regs); |
| 155 | if (IS_ERR(ssc->regs)) | 161 | if (IS_ERR(ssc->regs)) |
diff --git a/include/linux/atmel-ssc.h b/include/linux/atmel-ssc.h index 66a0e5384edd..571a12ebb018 100644 --- a/include/linux/atmel-ssc.h +++ b/include/linux/atmel-ssc.h | |||
| @@ -18,6 +18,7 @@ struct ssc_device { | |||
| 18 | struct clk *clk; | 18 | struct clk *clk; |
| 19 | int user; | 19 | int user; |
| 20 | int irq; | 20 | int irq; |
| 21 | bool clk_from_rk_pin; | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | struct ssc_device * __must_check ssc_request(unsigned int ssc_num); | 24 | struct ssc_device * __must_check ssc_request(unsigned int ssc_num); |
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index fdf3aa376eb2..3ddaa634b19d 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h | |||
| @@ -1702,9 +1702,9 @@ | |||
| 1702 | /* | 1702 | /* |
| 1703 | * R373 (0x175) - FLL1 Control 5 | 1703 | * R373 (0x175) - FLL1 Control 5 |
| 1704 | */ | 1704 | */ |
| 1705 | #define ARIZONA_FLL1_FRATIO_MASK 0x0700 /* FLL1_FRATIO - [10:8] */ | 1705 | #define ARIZONA_FLL1_FRATIO_MASK 0x0F00 /* FLL1_FRATIO - [11:8] */ |
| 1706 | #define ARIZONA_FLL1_FRATIO_SHIFT 8 /* FLL1_FRATIO - [10:8] */ | 1706 | #define ARIZONA_FLL1_FRATIO_SHIFT 8 /* FLL1_FRATIO - [11:8] */ |
| 1707 | #define ARIZONA_FLL1_FRATIO_WIDTH 3 /* FLL1_FRATIO - [10:8] */ | 1707 | #define ARIZONA_FLL1_FRATIO_WIDTH 4 /* FLL1_FRATIO - [11:8] */ |
| 1708 | #define ARIZONA_FLL1_OUTDIV_MASK 0x000E /* FLL1_OUTDIV - [3:1] */ | 1708 | #define ARIZONA_FLL1_OUTDIV_MASK 0x000E /* FLL1_OUTDIV - [3:1] */ |
| 1709 | #define ARIZONA_FLL1_OUTDIV_SHIFT 1 /* FLL1_OUTDIV - [3:1] */ | 1709 | #define ARIZONA_FLL1_OUTDIV_SHIFT 1 /* FLL1_OUTDIV - [3:1] */ |
| 1710 | #define ARIZONA_FLL1_OUTDIV_WIDTH 3 /* FLL1_OUTDIV - [3:1] */ | 1710 | #define ARIZONA_FLL1_OUTDIV_WIDTH 3 /* FLL1_OUTDIV - [3:1] */ |
diff --git a/include/linux/platform_data/adau1977.h b/include/linux/platform_data/adau1977.h new file mode 100644 index 000000000000..bed11d908f92 --- /dev/null +++ b/include/linux/platform_data/adau1977.h | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | /* | ||
| 2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 6 | * | ||
| 7 | * Licensed under the GPL-2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __LINUX_PLATFORM_DATA_ADAU1977_H__ | ||
| 11 | #define __LINUX_PLATFORM_DATA_ADAU1977_H__ | ||
| 12 | |||
| 13 | /** | ||
| 14 | * enum adau1977_micbias - ADAU1977 MICBIAS pin voltage setting | ||
| 15 | * @ADAU1977_MICBIAS_5V0: MICBIAS is set to 5.0 V | ||
| 16 | * @ADAU1977_MICBIAS_5V5: MICBIAS is set to 5.5 V | ||
| 17 | * @ADAU1977_MICBIAS_6V0: MICBIAS is set to 6.0 V | ||
| 18 | * @ADAU1977_MICBIAS_6V5: MICBIAS is set to 6.5 V | ||
| 19 | * @ADAU1977_MICBIAS_7V0: MICBIAS is set to 7.0 V | ||
| 20 | * @ADAU1977_MICBIAS_7V5: MICBIAS is set to 7.5 V | ||
| 21 | * @ADAU1977_MICBIAS_8V0: MICBIAS is set to 8.0 V | ||
| 22 | * @ADAU1977_MICBIAS_8V5: MICBIAS is set to 8.5 V | ||
| 23 | * @ADAU1977_MICBIAS_9V0: MICBIAS is set to 9.0 V | ||
| 24 | */ | ||
| 25 | enum adau1977_micbias { | ||
| 26 | ADAU1977_MICBIAS_5V0 = 0x0, | ||
| 27 | ADAU1977_MICBIAS_5V5 = 0x1, | ||
| 28 | ADAU1977_MICBIAS_6V0 = 0x2, | ||
| 29 | ADAU1977_MICBIAS_6V5 = 0x3, | ||
| 30 | ADAU1977_MICBIAS_7V0 = 0x4, | ||
| 31 | ADAU1977_MICBIAS_7V5 = 0x5, | ||
| 32 | ADAU1977_MICBIAS_8V0 = 0x6, | ||
| 33 | ADAU1977_MICBIAS_8V5 = 0x7, | ||
| 34 | ADAU1977_MICBIAS_9V0 = 0x8, | ||
| 35 | }; | ||
| 36 | |||
| 37 | /** | ||
| 38 | * struct adau1977_platform_data - Platform configuration data for the ADAU1977 | ||
| 39 | * @micbias: Specifies the voltage for the MICBIAS pin | ||
| 40 | */ | ||
| 41 | struct adau1977_platform_data { | ||
| 42 | enum adau1977_micbias micbias; | ||
| 43 | }; | ||
| 44 | |||
| 45 | #endif | ||
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index 9efc04dd255a..709c6f7e2f8c 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | /* arch/arm/plat-samsung/include/plat/audio.h | 1 | /* |
| 2 | * | ||
| 3 | * Copyright (c) 2009 Samsung Electronics Co. Ltd | 2 | * Copyright (c) 2009 Samsung Electronics Co. Ltd |
| 4 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | 3 | * Author: Jaswinder Singh <jassi.brar@samsung.com> |
| 5 | * | 4 | * |
diff --git a/include/linux/platform_data/asoc-s3c24xx_simtec.h b/include/linux/platform_data/asoc-s3c24xx_simtec.h index 376af5286a3e..d220e54123aa 100644 --- a/include/linux/platform_data/asoc-s3c24xx_simtec.h +++ b/include/linux/platform_data/asoc-s3c24xx_simtec.h | |||
| @@ -1,5 +1,4 @@ | |||
| 1 | /* arch/arm/plat-samsung/include/plat/audio-simtec.h | 1 | /* |
| 2 | * | ||
| 3 | * Copyright 2008 Simtec Electronics | 2 | * Copyright 2008 Simtec Electronics |
| 4 | * http://armlinux.simtec.co.uk/ | 3 | * http://armlinux.simtec.co.uk/ |
| 5 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
diff --git a/include/linux/platform_data/davinci_asp.h b/include/linux/platform_data/davinci_asp.h index 5245992b0367..85ad68f9206a 100644 --- a/include/linux/platform_data/davinci_asp.h +++ b/include/linux/platform_data/davinci_asp.h | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | 18 | ||
| 19 | #include <linux/genalloc.h> | 19 | #include <linux/genalloc.h> |
| 20 | 20 | ||
| 21 | struct snd_platform_data { | 21 | struct davinci_mcasp_pdata { |
| 22 | u32 tx_dma_offset; | 22 | u32 tx_dma_offset; |
| 23 | u32 rx_dma_offset; | 23 | u32 rx_dma_offset; |
| 24 | int asp_chan_q; /* event queue number for ASP channel */ | 24 | int asp_chan_q; /* event queue number for ASP channel */ |
| @@ -87,6 +87,8 @@ struct snd_platform_data { | |||
| 87 | int tx_dma_channel; | 87 | int tx_dma_channel; |
| 88 | int rx_dma_channel; | 88 | int rx_dma_channel; |
| 89 | }; | 89 | }; |
| 90 | /* TODO: Fix arch/arm/mach-davinci/ users and remove this define */ | ||
| 91 | #define snd_platform_data davinci_mcasp_pdata | ||
| 90 | 92 | ||
| 91 | enum { | 93 | enum { |
| 92 | MCASP_VERSION_1 = 0, /* DM646x */ | 94 | MCASP_VERSION_1 = 0, /* DM646x */ |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 4149f1a9b003..3e1a2e4a92ad 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
| @@ -423,6 +423,8 @@ bool regmap_check_range_table(struct regmap *map, unsigned int reg, | |||
| 423 | 423 | ||
| 424 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | 424 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, |
| 425 | int num_regs); | 425 | int num_regs); |
| 426 | int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 427 | unsigned int *val); | ||
| 426 | 428 | ||
| 427 | static inline bool regmap_reg_in_range(unsigned int reg, | 429 | static inline bool regmap_reg_in_range(unsigned int reg, |
| 428 | const struct regmap_range *range) | 430 | const struct regmap_range *range) |
| @@ -695,6 +697,13 @@ static inline int regmap_register_patch(struct regmap *map, | |||
| 695 | return -EINVAL; | 697 | return -EINVAL; |
| 696 | } | 698 | } |
| 697 | 699 | ||
| 700 | static inline int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 701 | unsigned int *val) | ||
| 702 | { | ||
| 703 | WARN_ONCE(1, "regmap API is disabled"); | ||
| 704 | return -EINVAL; | ||
| 705 | } | ||
| 706 | |||
| 698 | static inline struct regmap *dev_get_regmap(struct device *dev, | 707 | static inline struct regmap *dev_get_regmap(struct device *dev, |
| 699 | const char *name) | 708 | const char *name) |
| 700 | { | 709 | { |
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 6add6ccc811e..34a3c02a4576 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h | |||
| @@ -34,17 +34,17 @@ | |||
| 34 | * B : SSI direction | 34 | * B : SSI direction |
| 35 | */ | 35 | */ |
| 36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) | 36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) |
| 37 | #define RSND_SSI_SYNC (1 << 29) /* SSI34_sync etc */ | ||
| 38 | |||
| 39 | #define RSND_SSI_PLAY (1 << 24) | 37 | #define RSND_SSI_PLAY (1 << 24) |
| 40 | 38 | ||
| 39 | #define RSND_SSI(_dma_id, _pio_irq, _flags) \ | ||
| 40 | { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } | ||
| 41 | #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ | 41 | #define RSND_SSI_SET(_dai_id, _dma_id, _pio_irq, _flags) \ |
| 42 | { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } | 42 | { .dai_id = _dai_id, .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } |
| 43 | #define RSND_SSI_UNUSED \ | 43 | #define RSND_SSI_UNUSED \ |
| 44 | { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } | 44 | { .dai_id = -1, .dma_id = -1, .pio_irq = -1, .flags = 0 } |
| 45 | 45 | ||
| 46 | struct rsnd_ssi_platform_info { | 46 | struct rsnd_ssi_platform_info { |
| 47 | int dai_id; | 47 | int dai_id; /* will be removed */ |
| 48 | int dma_id; | 48 | int dma_id; |
| 49 | int pio_irq; | 49 | int pio_irq; |
| 50 | u32 flags; | 50 | u32 flags; |
| @@ -55,9 +55,31 @@ struct rsnd_ssi_platform_info { | |||
| 55 | */ | 55 | */ |
| 56 | #define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ | 56 | #define RSND_SCU_USE_HPBIF (1 << 31) /* it needs RSND_SSI_DEPENDENT */ |
| 57 | 57 | ||
| 58 | struct rsnd_scu_platform_info { | 58 | #define RSND_SRC(rate, _dma_id) \ |
| 59 | { .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, } | ||
| 60 | #define RSND_SRC_SET(rate, _dma_id) \ | ||
| 61 | { .flags = RSND_SCU_USE_HPBIF, .convert_rate = rate, .dma_id = _dma_id, } | ||
| 62 | #define RSND_SRC_UNUSED \ | ||
| 63 | { .flags = 0, .convert_rate = 0, .dma_id = 0, } | ||
| 64 | |||
| 65 | #define rsnd_scu_platform_info rsnd_src_platform_info | ||
| 66 | #define src_info scu_info | ||
| 67 | #define src_info_nr scu_info_nr | ||
| 68 | |||
| 69 | struct rsnd_src_platform_info { | ||
| 59 | u32 flags; | 70 | u32 flags; |
| 60 | u32 convert_rate; /* sampling rate convert */ | 71 | u32 convert_rate; /* sampling rate convert */ |
| 72 | int dma_id; /* for Gen2 SCU */ | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct rsnd_dai_path_info { | ||
| 76 | struct rsnd_ssi_platform_info *ssi; | ||
| 77 | struct rsnd_src_platform_info *src; | ||
| 78 | }; | ||
| 79 | |||
| 80 | struct rsnd_dai_platform_info { | ||
| 81 | struct rsnd_dai_path_info playback; | ||
| 82 | struct rsnd_dai_path_info capture; | ||
| 61 | }; | 83 | }; |
| 62 | 84 | ||
| 63 | /* | 85 | /* |
| @@ -75,8 +97,10 @@ struct rcar_snd_info { | |||
| 75 | u32 flags; | 97 | u32 flags; |
| 76 | struct rsnd_ssi_platform_info *ssi_info; | 98 | struct rsnd_ssi_platform_info *ssi_info; |
| 77 | int ssi_info_nr; | 99 | int ssi_info_nr; |
| 78 | struct rsnd_scu_platform_info *scu_info; | 100 | struct rsnd_src_platform_info *src_info; |
| 79 | int scu_info_nr; | 101 | int src_info_nr; |
| 102 | struct rsnd_dai_platform_info *dai_info; | ||
| 103 | int dai_info_nr; | ||
| 80 | int (*start)(int id); | 104 | int (*start)(int id); |
| 81 | int (*stop)(int id); | 105 | int (*stop)(int id); |
| 82 | }; | 106 | }; |
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h index 6c74527d4926..9b0ac77177b6 100644 --- a/include/sound/simple_card.h +++ b/include/sound/simple_card.h | |||
| @@ -18,6 +18,8 @@ struct asoc_simple_dai { | |||
| 18 | const char *name; | 18 | const char *name; |
| 19 | unsigned int fmt; | 19 | unsigned int fmt; |
| 20 | unsigned int sysclk; | 20 | unsigned int sysclk; |
| 21 | int slots; | ||
| 22 | int slot_width; | ||
| 21 | }; | 23 | }; |
| 22 | 24 | ||
| 23 | struct asoc_simple_card_info { | 25 | struct asoc_simple_card_info { |
| @@ -29,10 +31,6 @@ struct asoc_simple_card_info { | |||
| 29 | unsigned int daifmt; | 31 | unsigned int daifmt; |
| 30 | struct asoc_simple_dai cpu_dai; | 32 | struct asoc_simple_dai cpu_dai; |
| 31 | struct asoc_simple_dai codec_dai; | 33 | struct asoc_simple_dai codec_dai; |
| 32 | |||
| 33 | /* used in simple-card.c */ | ||
| 34 | struct snd_soc_dai_link snd_link; | ||
| 35 | struct snd_soc_card snd_card; | ||
| 36 | }; | 34 | }; |
| 37 | 35 | ||
| 38 | #endif /* __SIMPLE_CARD_H */ | 36 | #endif /* __SIMPLE_CARD_H */ |
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 71f27c403194..2f66d5e8cd15 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h | |||
| @@ -142,6 +142,8 @@ struct snd_soc_dai_ops { | |||
| 142 | * Called by soc_card drivers, normally in their hw_params. | 142 | * Called by soc_card drivers, normally in their hw_params. |
| 143 | */ | 143 | */ |
| 144 | int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); | 144 | int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); |
| 145 | int (*of_xlate_tdm_slot_mask)(unsigned int slots, | ||
| 146 | unsigned int *tx_mask, unsigned int *rx_mask); | ||
| 145 | int (*set_tdm_slot)(struct snd_soc_dai *dai, | 147 | int (*set_tdm_slot)(struct snd_soc_dai *dai, |
| 146 | unsigned int tx_mask, unsigned int rx_mask, | 148 | unsigned int tx_mask, unsigned int rx_mask, |
| 147 | int slots, int slot_width); | 149 | int slots, int slot_width); |
| @@ -270,6 +272,7 @@ struct snd_soc_dai { | |||
| 270 | /* parent platform/codec */ | 272 | /* parent platform/codec */ |
| 271 | struct snd_soc_platform *platform; | 273 | struct snd_soc_platform *platform; |
| 272 | struct snd_soc_codec *codec; | 274 | struct snd_soc_codec *codec; |
| 275 | struct snd_soc_component *component; | ||
| 273 | 276 | ||
| 274 | struct snd_soc_card *card; | 277 | struct snd_soc_card *card; |
| 275 | 278 | ||
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 6e89ef6c11c1..ef78f562f4a8 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
| @@ -108,13 +108,9 @@ struct device; | |||
| 108 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | 108 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ |
| 109 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | 109 | .kcontrol_news = wcontrols, .num_kcontrols = 1} |
| 110 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 110 | #define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
| 111 | { .id = snd_soc_dapm_virt_mux, .name = wname, \ | 111 | SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) |
| 112 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | ||
| 113 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | ||
| 114 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ | 112 | #define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \ |
| 115 | { .id = snd_soc_dapm_value_mux, .name = wname, \ | 113 | SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) |
| 116 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | ||
| 117 | .kcontrol_news = wcontrols, .num_kcontrols = 1} | ||
| 118 | 114 | ||
| 119 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ | 115 | /* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */ |
| 120 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ | 116 | #define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\ |
| @@ -172,10 +168,8 @@ struct device; | |||
| 172 | .event = wevent, .event_flags = wflags} | 168 | .event = wevent, .event_flags = wflags} |
| 173 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ | 169 | #define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \ |
| 174 | wevent, wflags) \ | 170 | wevent, wflags) \ |
| 175 | { .id = snd_soc_dapm_virt_mux, .name = wname, \ | 171 | SND_SOC_DAPM_MUX_E(wname, wreg, wshift, winvert, wcontrols, wevent, \ |
| 176 | SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \ | 172 | wflags) |
| 177 | .kcontrol_news = wcontrols, .num_kcontrols = 1, \ | ||
| 178 | .event = wevent, .event_flags = wflags} | ||
| 179 | 173 | ||
| 180 | /* additional sequencing control within an event type */ | 174 | /* additional sequencing control within an event type */ |
| 181 | #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ | 175 | #define SND_SOC_DAPM_PGA_S(wname, wsubseq, wreg, wshift, winvert, \ |
| @@ -311,12 +305,8 @@ struct device; | |||
| 311 | .get = snd_soc_dapm_get_enum_double, \ | 305 | .get = snd_soc_dapm_get_enum_double, \ |
| 312 | .put = snd_soc_dapm_put_enum_double, \ | 306 | .put = snd_soc_dapm_put_enum_double, \ |
| 313 | .private_value = (unsigned long)&xenum } | 307 | .private_value = (unsigned long)&xenum } |
| 314 | #define SOC_DAPM_ENUM_VIRT(xname, xenum) \ | 308 | #define SOC_DAPM_ENUM_VIRT(xname, xenum) \ |
| 315 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 309 | SOC_DAPM_ENUM(xname, xenum) |
| 316 | .info = snd_soc_info_enum_double, \ | ||
| 317 | .get = snd_soc_dapm_get_enum_virt, \ | ||
| 318 | .put = snd_soc_dapm_put_enum_virt, \ | ||
| 319 | .private_value = (unsigned long)&xenum } | ||
| 320 | #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ | 310 | #define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ |
| 321 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 311 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| 322 | .info = snd_soc_info_enum_double, \ | 312 | .info = snd_soc_info_enum_double, \ |
| @@ -324,11 +314,7 @@ struct device; | |||
| 324 | .put = xput, \ | 314 | .put = xput, \ |
| 325 | .private_value = (unsigned long)&xenum } | 315 | .private_value = (unsigned long)&xenum } |
| 326 | #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ | 316 | #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ |
| 327 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 317 | SOC_DAPM_ENUM(xname, xenum) |
| 328 | .info = snd_soc_info_enum_double, \ | ||
| 329 | .get = snd_soc_dapm_get_value_enum_double, \ | ||
| 330 | .put = snd_soc_dapm_put_value_enum_double, \ | ||
| 331 | .private_value = (unsigned long)&xenum } | ||
| 332 | #define SOC_DAPM_PIN_SWITCH(xname) \ | 318 | #define SOC_DAPM_PIN_SWITCH(xname) \ |
| 333 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \ | 319 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname " Switch", \ |
| 334 | .info = snd_soc_dapm_info_pin_switch, \ | 320 | .info = snd_soc_dapm_info_pin_switch, \ |
| @@ -392,14 +378,6 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
| 392 | struct snd_ctl_elem_value *ucontrol); | 378 | struct snd_ctl_elem_value *ucontrol); |
| 393 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | 379 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
| 394 | struct snd_ctl_elem_value *ucontrol); | 380 | struct snd_ctl_elem_value *ucontrol); |
| 395 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
| 396 | struct snd_ctl_elem_value *ucontrol); | ||
| 397 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
| 398 | struct snd_ctl_elem_value *ucontrol); | ||
| 399 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 400 | struct snd_ctl_elem_value *ucontrol); | ||
| 401 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 402 | struct snd_ctl_elem_value *ucontrol); | ||
| 403 | int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, | 381 | int snd_soc_dapm_info_pin_switch(struct snd_kcontrol *kcontrol, |
| 404 | struct snd_ctl_elem_info *uinfo); | 382 | struct snd_ctl_elem_info *uinfo); |
| 405 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, | 383 | int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol, |
| @@ -461,6 +439,7 @@ int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, | |||
| 461 | int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, | 439 | int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm, |
| 462 | const char *pin); | 440 | const char *pin); |
| 463 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); | 441 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm); |
| 442 | int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm); | ||
| 464 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | 443 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, |
| 465 | const char *pin); | 444 | const char *pin); |
| 466 | int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | 445 | int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, |
| @@ -470,7 +449,6 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, | |||
| 470 | void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec); | 449 | void snd_soc_dapm_auto_nc_codec_pins(struct snd_soc_codec *codec); |
| 471 | 450 | ||
| 472 | /* Mostly internal - should not normally be used */ | 451 | /* Mostly internal - should not normally be used */ |
| 473 | void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason); | ||
| 474 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); | 452 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); |
| 475 | 453 | ||
| 476 | /* dapm path query */ | 454 | /* dapm path query */ |
| @@ -484,8 +462,6 @@ enum snd_soc_dapm_type { | |||
| 484 | snd_soc_dapm_input = 0, /* input pin */ | 462 | snd_soc_dapm_input = 0, /* input pin */ |
| 485 | snd_soc_dapm_output, /* output pin */ | 463 | snd_soc_dapm_output, /* output pin */ |
| 486 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ | 464 | snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */ |
| 487 | snd_soc_dapm_virt_mux, /* virtual version of snd_soc_dapm_mux */ | ||
| 488 | snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */ | ||
| 489 | snd_soc_dapm_mixer, /* mixes several analog signals together */ | 465 | snd_soc_dapm_mixer, /* mixes several analog signals together */ |
| 490 | snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */ | 466 | snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */ |
| 491 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ | 467 | snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */ |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 9a001472b96a..959f38949967 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -45,6 +45,11 @@ | |||
| 45 | ((unsigned long)&(struct soc_mixer_control) \ | 45 | ((unsigned long)&(struct soc_mixer_control) \ |
| 46 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 46 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
| 47 | .max = xmax, .platform_max = xmax, .invert = xinvert}) | 47 | .max = xmax, .platform_max = xmax, .invert = xinvert}) |
| 48 | #define SOC_DOUBLE_R_S_VALUE(xlreg, xrreg, xshift, xmin, xmax, xsign_bit, xinvert) \ | ||
| 49 | ((unsigned long)&(struct soc_mixer_control) \ | ||
| 50 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | ||
| 51 | .max = xmax, .min = xmin, .platform_max = xmax, .sign_bit = xsign_bit, \ | ||
| 52 | .invert = xinvert}) | ||
| 48 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ | 53 | #define SOC_DOUBLE_R_RANGE_VALUE(xlreg, xrreg, xshift, xmin, xmax, xinvert) \ |
| 49 | ((unsigned long)&(struct soc_mixer_control) \ | 54 | ((unsigned long)&(struct soc_mixer_control) \ |
| 50 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ | 55 | {.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \ |
| @@ -152,6 +157,15 @@ | |||
| 152 | {.reg = xreg, .rreg = xrreg, \ | 157 | {.reg = xreg, .rreg = xrreg, \ |
| 153 | .shift = xshift, .rshift = xshift, \ | 158 | .shift = xshift, .rshift = xshift, \ |
| 154 | .max = xmax, .min = xmin} } | 159 | .max = xmax, .min = xmin} } |
| 160 | #define SOC_DOUBLE_R_S_TLV(xname, reg_left, reg_right, xshift, xmin, xmax, xsign_bit, xinvert, tlv_array) \ | ||
| 161 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ | ||
| 162 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
| 163 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
| 164 | .tlv.p = (tlv_array), \ | ||
| 165 | .info = snd_soc_info_volsw, \ | ||
| 166 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ | ||
| 167 | .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \ | ||
| 168 | xmin, xmax, xsign_bit, xinvert) } | ||
| 155 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 169 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
| 156 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 170 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
| 157 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 171 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
| @@ -162,30 +176,28 @@ | |||
| 162 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 176 | .private_value = (unsigned long)&(struct soc_mixer_control) \ |
| 163 | {.reg = xreg, .min = xmin, .max = xmax, \ | 177 | {.reg = xreg, .min = xmin, .max = xmax, \ |
| 164 | .platform_max = xmax} } | 178 | .platform_max = xmax} } |
| 165 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \ | 179 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \ |
| 166 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 180 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
| 167 | .max = xmax, .texts = xtexts, \ | 181 | .items = xitems, .texts = xtexts, \ |
| 168 | .mask = xmax ? roundup_pow_of_two(xmax) - 1 : 0} | 182 | .mask = xitems ? roundup_pow_of_two(xitems) - 1 : 0} |
| 169 | #define SOC_ENUM_SINGLE(xreg, xshift, xmax, xtexts) \ | 183 | #define SOC_ENUM_SINGLE(xreg, xshift, xitems, xtexts) \ |
| 170 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmax, xtexts) | 184 | SOC_ENUM_DOUBLE(xreg, xshift, xshift, xitems, xtexts) |
| 171 | #define SOC_ENUM_SINGLE_EXT(xmax, xtexts) \ | 185 | #define SOC_ENUM_SINGLE_EXT(xitems, xtexts) \ |
| 172 | { .max = xmax, .texts = xtexts } | 186 | { .items = xitems, .texts = xtexts } |
| 173 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xmax, xtexts, xvalues) \ | 187 | #define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \ |
| 174 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 188 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
| 175 | .mask = xmask, .max = xmax, .texts = xtexts, .values = xvalues} | 189 | .mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues} |
| 176 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xmax, xtexts, xvalues) \ | 190 | #define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \ |
| 177 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xmax, xtexts, xvalues) | 191 | SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues) |
| 192 | #define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \ | ||
| 193 | SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts) | ||
| 178 | #define SOC_ENUM(xname, xenum) \ | 194 | #define SOC_ENUM(xname, xenum) \ |
| 179 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 195 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ |
| 180 | .info = snd_soc_info_enum_double, \ | 196 | .info = snd_soc_info_enum_double, \ |
| 181 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ | 197 | .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \ |
| 182 | .private_value = (unsigned long)&xenum } | 198 | .private_value = (unsigned long)&xenum } |
| 183 | #define SOC_VALUE_ENUM(xname, xenum) \ | 199 | #define SOC_VALUE_ENUM(xname, xenum) \ |
| 184 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\ | 200 | SOC_ENUM(xname, xenum) |
| 185 | .info = snd_soc_info_enum_double, \ | ||
| 186 | .get = snd_soc_get_value_enum_double, \ | ||
| 187 | .put = snd_soc_put_value_enum_double, \ | ||
| 188 | .private_value = (unsigned long)&xenum } | ||
| 189 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ | 201 | #define SOC_SINGLE_EXT(xname, xreg, xshift, xmax, xinvert,\ |
| 190 | xhandler_get, xhandler_put) \ | 202 | xhandler_get, xhandler_put) \ |
| 191 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | 203 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ |
| @@ -272,17 +284,19 @@ | |||
| 272 | * ARRAY_SIZE internally | 284 | * ARRAY_SIZE internally |
| 273 | */ | 285 | */ |
| 274 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ | 286 | #define SOC_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xtexts) \ |
| 275 | struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ | 287 | const struct soc_enum name = SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, \ |
| 276 | ARRAY_SIZE(xtexts), xtexts) | 288 | ARRAY_SIZE(xtexts), xtexts) |
| 277 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ | 289 | #define SOC_ENUM_SINGLE_DECL(name, xreg, xshift, xtexts) \ |
| 278 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) | 290 | SOC_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xtexts) |
| 279 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ | 291 | #define SOC_ENUM_SINGLE_EXT_DECL(name, xtexts) \ |
| 280 | struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) | 292 | const struct soc_enum name = SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(xtexts), xtexts) |
| 281 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ | 293 | #define SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift_l, xshift_r, xmask, xtexts, xvalues) \ |
| 282 | struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ | 294 | const struct soc_enum name = SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, \ |
| 283 | ARRAY_SIZE(xtexts), xtexts, xvalues) | 295 | ARRAY_SIZE(xtexts), xtexts, xvalues) |
| 284 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ | 296 | #define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \ |
| 285 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) | 297 | SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues) |
| 298 | #define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \ | ||
| 299 | const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts) | ||
| 286 | 300 | ||
| 287 | /* | 301 | /* |
| 288 | * Component probe and remove ordering levels for components with runtime | 302 | * Component probe and remove ordering levels for components with runtime |
| @@ -413,6 +427,10 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, | |||
| 413 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | 427 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, |
| 414 | const char *dai_link); | 428 | const char *dai_link); |
| 415 | 429 | ||
| 430 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd); | ||
| 431 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream); | ||
| 432 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream); | ||
| 433 | |||
| 416 | /* Utility functions to get clock rates from various things */ | 434 | /* Utility functions to get clock rates from various things */ |
| 417 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); | 435 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); |
| 418 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); | 436 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); |
| @@ -496,10 +514,6 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
| 496 | struct snd_ctl_elem_value *ucontrol); | 514 | struct snd_ctl_elem_value *ucontrol); |
| 497 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | 515 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, |
| 498 | struct snd_ctl_elem_value *ucontrol); | 516 | struct snd_ctl_elem_value *ucontrol); |
| 499 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 500 | struct snd_ctl_elem_value *ucontrol); | ||
| 501 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 502 | struct snd_ctl_elem_value *ucontrol); | ||
| 503 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | 517 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, |
| 504 | struct snd_ctl_elem_info *uinfo); | 518 | struct snd_ctl_elem_info *uinfo); |
| 505 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info | 519 | #define snd_soc_info_bool_ext snd_ctl_boolean_mono_info |
| @@ -656,12 +670,19 @@ struct snd_soc_component { | |||
| 656 | const char *name; | 670 | const char *name; |
| 657 | int id; | 671 | int id; |
| 658 | struct device *dev; | 672 | struct device *dev; |
| 673 | |||
| 674 | unsigned int active; | ||
| 675 | |||
| 676 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | ||
| 677 | |||
| 659 | struct list_head list; | 678 | struct list_head list; |
| 660 | 679 | ||
| 661 | struct snd_soc_dai_driver *dai_drv; | 680 | struct snd_soc_dai_driver *dai_drv; |
| 662 | int num_dai; | 681 | int num_dai; |
| 663 | 682 | ||
| 664 | const struct snd_soc_component_driver *driver; | 683 | const struct snd_soc_component_driver *driver; |
| 684 | |||
| 685 | struct list_head dai_list; | ||
| 665 | }; | 686 | }; |
| 666 | 687 | ||
| 667 | /* SoC Audio Codec device */ | 688 | /* SoC Audio Codec device */ |
| @@ -683,7 +704,6 @@ struct snd_soc_codec { | |||
| 683 | 704 | ||
| 684 | /* runtime */ | 705 | /* runtime */ |
| 685 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | 706 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ |
| 686 | unsigned int active; | ||
| 687 | unsigned int cache_bypass:1; /* Suppress access to the cache */ | 707 | unsigned int cache_bypass:1; /* Suppress access to the cache */ |
| 688 | unsigned int suspended:1; /* Codec is in suspend PM state */ | 708 | unsigned int suspended:1; /* Codec is in suspend PM state */ |
| 689 | unsigned int probed:1; /* Codec has been probed */ | 709 | unsigned int probed:1; /* Codec has been probed */ |
| @@ -709,7 +729,6 @@ struct snd_soc_codec { | |||
| 709 | 729 | ||
| 710 | /* dapm */ | 730 | /* dapm */ |
| 711 | struct snd_soc_dapm_context dapm; | 731 | struct snd_soc_dapm_context dapm; |
| 712 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | ||
| 713 | 732 | ||
| 714 | #ifdef CONFIG_DEBUG_FS | 733 | #ifdef CONFIG_DEBUG_FS |
| 715 | struct dentry *debugfs_codec_root; | 734 | struct dentry *debugfs_codec_root; |
| @@ -1067,6 +1086,7 @@ struct soc_mixer_control { | |||
| 1067 | int min, max, platform_max; | 1086 | int min, max, platform_max; |
| 1068 | int reg, rreg; | 1087 | int reg, rreg; |
| 1069 | unsigned int shift, rshift; | 1088 | unsigned int shift, rshift; |
| 1089 | unsigned int sign_bit; | ||
| 1070 | unsigned int invert:1; | 1090 | unsigned int invert:1; |
| 1071 | unsigned int autodisable:1; | 1091 | unsigned int autodisable:1; |
| 1072 | }; | 1092 | }; |
| @@ -1085,11 +1105,10 @@ struct soc_mreg_control { | |||
| 1085 | 1105 | ||
| 1086 | /* enumerated kcontrol */ | 1106 | /* enumerated kcontrol */ |
| 1087 | struct soc_enum { | 1107 | struct soc_enum { |
| 1088 | unsigned short reg; | 1108 | int reg; |
| 1089 | unsigned short reg2; | ||
| 1090 | unsigned char shift_l; | 1109 | unsigned char shift_l; |
| 1091 | unsigned char shift_r; | 1110 | unsigned char shift_r; |
| 1092 | unsigned int max; | 1111 | unsigned int items; |
| 1093 | unsigned int mask; | 1112 | unsigned int mask; |
| 1094 | const char * const *texts; | 1113 | const char * const *texts; |
| 1095 | const unsigned int *values; | 1114 | const unsigned int *values; |
| @@ -1168,11 +1187,51 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) | |||
| 1168 | return 1; | 1187 | return 1; |
| 1169 | } | 1188 | } |
| 1170 | 1189 | ||
| 1190 | static inline unsigned int snd_soc_enum_val_to_item(struct soc_enum *e, | ||
| 1191 | unsigned int val) | ||
| 1192 | { | ||
| 1193 | unsigned int i; | ||
| 1194 | |||
| 1195 | if (!e->values) | ||
| 1196 | return val; | ||
| 1197 | |||
| 1198 | for (i = 0; i < e->items; i++) | ||
| 1199 | if (val == e->values[i]) | ||
| 1200 | return i; | ||
| 1201 | |||
| 1202 | return 0; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | static inline unsigned int snd_soc_enum_item_to_val(struct soc_enum *e, | ||
| 1206 | unsigned int item) | ||
| 1207 | { | ||
| 1208 | if (!e->values) | ||
| 1209 | return item; | ||
| 1210 | |||
| 1211 | return e->values[item]; | ||
| 1212 | } | ||
| 1213 | |||
| 1214 | static inline bool snd_soc_component_is_active( | ||
| 1215 | struct snd_soc_component *component) | ||
| 1216 | { | ||
| 1217 | return component->active != 0; | ||
| 1218 | } | ||
| 1219 | |||
| 1220 | static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec) | ||
| 1221 | { | ||
| 1222 | return snd_soc_component_is_active(&codec->component); | ||
| 1223 | } | ||
| 1224 | |||
| 1171 | int snd_soc_util_init(void); | 1225 | int snd_soc_util_init(void); |
| 1172 | void snd_soc_util_exit(void); | 1226 | void snd_soc_util_exit(void); |
| 1173 | 1227 | ||
| 1174 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, | 1228 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, |
| 1175 | const char *propname); | 1229 | const char *propname); |
| 1230 | int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, | ||
| 1231 | const char *propname); | ||
| 1232 | int snd_soc_of_parse_tdm_slot(struct device_node *np, | ||
| 1233 | unsigned int *slots, | ||
| 1234 | unsigned int *slot_width); | ||
| 1176 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | 1235 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
| 1177 | const char *propname); | 1236 | const char *propname); |
| 1178 | unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | 1237 | unsigned int snd_soc_of_parse_daifmt(struct device_node *np, |
| @@ -1188,4 +1247,15 @@ extern struct dentry *snd_soc_debugfs_root; | |||
| 1188 | 1247 | ||
| 1189 | extern const struct dev_pm_ops snd_soc_pm_ops; | 1248 | extern const struct dev_pm_ops snd_soc_pm_ops; |
| 1190 | 1249 | ||
| 1250 | /* Helper functions */ | ||
| 1251 | static inline void snd_soc_dapm_mutex_lock(struct snd_soc_dapm_context *dapm) | ||
| 1252 | { | ||
| 1253 | mutex_lock(&dapm->card->dapm_mutex); | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | static inline void snd_soc_dapm_mutex_unlock(struct snd_soc_dapm_context *dapm) | ||
| 1257 | { | ||
| 1258 | mutex_unlock(&dapm->card->dapm_mutex); | ||
| 1259 | } | ||
| 1260 | |||
| 1191 | #endif | 1261 | #endif |
diff --git a/include/trace/events/hswadsp.h b/include/trace/events/hswadsp.h new file mode 100644 index 000000000000..0f78bbb02002 --- /dev/null +++ b/include/trace/events/hswadsp.h | |||
| @@ -0,0 +1,384 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM hswadsp | ||
| 3 | |||
| 4 | #if !defined(_TRACE_HSWADSP_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_HSWADSP_H | ||
| 6 | |||
| 7 | #include <linux/types.h> | ||
| 8 | #include <linux/ktime.h> | ||
| 9 | #include <linux/tracepoint.h> | ||
| 10 | |||
| 11 | struct sst_hsw; | ||
| 12 | struct sst_hsw_stream; | ||
| 13 | struct sst_hsw_ipc_stream_free_req; | ||
| 14 | struct sst_hsw_ipc_volume_req; | ||
| 15 | struct sst_hsw_ipc_stream_alloc_req; | ||
| 16 | struct sst_hsw_audio_data_format_ipc; | ||
| 17 | struct sst_hsw_ipc_stream_info_reply; | ||
| 18 | struct sst_hsw_ipc_device_config_req; | ||
| 19 | |||
| 20 | DECLARE_EVENT_CLASS(sst_irq, | ||
| 21 | |||
| 22 | TP_PROTO(uint32_t status, uint32_t mask), | ||
| 23 | |||
| 24 | TP_ARGS(status, mask), | ||
| 25 | |||
| 26 | TP_STRUCT__entry( | ||
| 27 | __field( unsigned int, status ) | ||
| 28 | __field( unsigned int, mask ) | ||
| 29 | ), | ||
| 30 | |||
| 31 | TP_fast_assign( | ||
| 32 | __entry->status = status; | ||
| 33 | __entry->mask = mask; | ||
| 34 | ), | ||
| 35 | |||
| 36 | TP_printk("status 0x%8.8x mask 0x%8.8x", | ||
| 37 | (unsigned int)__entry->status, (unsigned int)__entry->mask) | ||
| 38 | ); | ||
| 39 | |||
| 40 | DEFINE_EVENT(sst_irq, sst_irq_busy, | ||
| 41 | |||
| 42 | TP_PROTO(unsigned int status, unsigned int mask), | ||
| 43 | |||
| 44 | TP_ARGS(status, mask) | ||
| 45 | |||
| 46 | ); | ||
| 47 | |||
| 48 | DEFINE_EVENT(sst_irq, sst_irq_done, | ||
| 49 | |||
| 50 | TP_PROTO(unsigned int status, unsigned int mask), | ||
| 51 | |||
| 52 | TP_ARGS(status, mask) | ||
| 53 | |||
| 54 | ); | ||
| 55 | |||
| 56 | DECLARE_EVENT_CLASS(ipc, | ||
| 57 | |||
| 58 | TP_PROTO(const char *name, int val), | ||
| 59 | |||
| 60 | TP_ARGS(name, val), | ||
| 61 | |||
| 62 | TP_STRUCT__entry( | ||
| 63 | __string( name, name ) | ||
| 64 | __field( unsigned int, val ) | ||
| 65 | ), | ||
| 66 | |||
| 67 | TP_fast_assign( | ||
| 68 | __assign_str(name, name); | ||
| 69 | __entry->val = val; | ||
| 70 | ), | ||
| 71 | |||
| 72 | TP_printk("%s 0x%8.8x", __get_str(name), (unsigned int)__entry->val) | ||
| 73 | |||
| 74 | ); | ||
| 75 | |||
| 76 | DEFINE_EVENT(ipc, ipc_request, | ||
| 77 | |||
| 78 | TP_PROTO(const char *name, int val), | ||
| 79 | |||
| 80 | TP_ARGS(name, val) | ||
| 81 | |||
| 82 | ); | ||
| 83 | |||
| 84 | DEFINE_EVENT(ipc, ipc_reply, | ||
| 85 | |||
| 86 | TP_PROTO(const char *name, int val), | ||
| 87 | |||
| 88 | TP_ARGS(name, val) | ||
| 89 | |||
| 90 | ); | ||
| 91 | |||
| 92 | DEFINE_EVENT(ipc, ipc_pending_reply, | ||
| 93 | |||
| 94 | TP_PROTO(const char *name, int val), | ||
| 95 | |||
| 96 | TP_ARGS(name, val) | ||
| 97 | |||
| 98 | ); | ||
| 99 | |||
| 100 | DEFINE_EVENT(ipc, ipc_notification, | ||
| 101 | |||
| 102 | TP_PROTO(const char *name, int val), | ||
| 103 | |||
| 104 | TP_ARGS(name, val) | ||
| 105 | |||
| 106 | ); | ||
| 107 | |||
| 108 | DEFINE_EVENT(ipc, ipc_error, | ||
| 109 | |||
| 110 | TP_PROTO(const char *name, int val), | ||
| 111 | |||
| 112 | TP_ARGS(name, val) | ||
| 113 | |||
| 114 | ); | ||
| 115 | |||
| 116 | DECLARE_EVENT_CLASS(stream_position, | ||
| 117 | |||
| 118 | TP_PROTO(unsigned int id, unsigned int pos), | ||
| 119 | |||
| 120 | TP_ARGS(id, pos), | ||
| 121 | |||
| 122 | TP_STRUCT__entry( | ||
| 123 | __field( unsigned int, id ) | ||
| 124 | __field( unsigned int, pos ) | ||
| 125 | ), | ||
| 126 | |||
| 127 | TP_fast_assign( | ||
| 128 | __entry->id = id; | ||
| 129 | __entry->pos = pos; | ||
| 130 | ), | ||
| 131 | |||
| 132 | TP_printk("id %d position 0x%x", | ||
| 133 | (unsigned int)__entry->id, (unsigned int)__entry->pos) | ||
| 134 | ); | ||
| 135 | |||
| 136 | DEFINE_EVENT(stream_position, stream_read_position, | ||
| 137 | |||
| 138 | TP_PROTO(unsigned int id, unsigned int pos), | ||
| 139 | |||
| 140 | TP_ARGS(id, pos) | ||
| 141 | |||
| 142 | ); | ||
| 143 | |||
| 144 | DEFINE_EVENT(stream_position, stream_write_position, | ||
| 145 | |||
| 146 | TP_PROTO(unsigned int id, unsigned int pos), | ||
| 147 | |||
| 148 | TP_ARGS(id, pos) | ||
| 149 | |||
| 150 | ); | ||
| 151 | |||
| 152 | TRACE_EVENT(hsw_stream_buffer, | ||
| 153 | |||
| 154 | TP_PROTO(struct sst_hsw_stream *stream), | ||
| 155 | |||
| 156 | TP_ARGS(stream), | ||
| 157 | |||
| 158 | TP_STRUCT__entry( | ||
| 159 | __field( int, id ) | ||
| 160 | __field( int, pt_addr ) | ||
| 161 | __field( int, num_pages ) | ||
| 162 | __field( int, ring_size ) | ||
| 163 | __field( int, ring_offset ) | ||
| 164 | __field( int, first_pfn ) | ||
| 165 | ), | ||
| 166 | |||
| 167 | TP_fast_assign( | ||
| 168 | __entry->id = stream->host_id; | ||
| 169 | __entry->pt_addr = stream->request.ringinfo.ring_pt_address; | ||
| 170 | __entry->num_pages = stream->request.ringinfo.num_pages; | ||
| 171 | __entry->ring_size = stream->request.ringinfo.ring_size; | ||
| 172 | __entry->ring_offset = stream->request.ringinfo.ring_offset; | ||
| 173 | __entry->first_pfn = stream->request.ringinfo.ring_first_pfn; | ||
| 174 | ), | ||
| 175 | |||
| 176 | TP_printk("stream %d ring addr 0x%x pages %d size 0x%x offset 0x%x PFN 0x%x", | ||
| 177 | (int) __entry->id, (int)__entry->pt_addr, | ||
| 178 | (int)__entry->num_pages, (int)__entry->ring_size, | ||
| 179 | (int)__entry->ring_offset, (int)__entry->first_pfn) | ||
| 180 | ); | ||
| 181 | |||
| 182 | TRACE_EVENT(hsw_stream_alloc_reply, | ||
| 183 | |||
| 184 | TP_PROTO(struct sst_hsw_stream *stream), | ||
| 185 | |||
| 186 | TP_ARGS(stream), | ||
| 187 | |||
| 188 | TP_STRUCT__entry( | ||
| 189 | __field( int, id ) | ||
| 190 | __field( int, stream_id ) | ||
| 191 | __field( int, mixer_id ) | ||
| 192 | __field( int, peak0 ) | ||
| 193 | __field( int, peak1 ) | ||
| 194 | __field( int, vol0 ) | ||
| 195 | __field( int, vol1 ) | ||
| 196 | ), | ||
| 197 | |||
| 198 | TP_fast_assign( | ||
| 199 | __entry->id = stream->host_id; | ||
| 200 | __entry->stream_id = stream->reply.stream_hw_id; | ||
| 201 | __entry->mixer_id = stream->reply.mixer_hw_id; | ||
| 202 | __entry->peak0 = stream->reply.peak_meter_register_address[0]; | ||
| 203 | __entry->peak1 = stream->reply.peak_meter_register_address[1]; | ||
| 204 | __entry->vol0 = stream->reply.volume_register_address[0]; | ||
| 205 | __entry->vol1 = stream->reply.volume_register_address[1]; | ||
| 206 | ), | ||
| 207 | |||
| 208 | TP_printk("stream %d hw id %d mixer %d peak 0x%x:0x%x vol 0x%x,0x%x", | ||
| 209 | (int) __entry->id, (int) __entry->stream_id, (int)__entry->mixer_id, | ||
| 210 | (int)__entry->peak0, (int)__entry->peak1, | ||
| 211 | (int)__entry->vol0, (int)__entry->vol1) | ||
| 212 | ); | ||
| 213 | |||
| 214 | TRACE_EVENT(hsw_mixer_info_reply, | ||
| 215 | |||
| 216 | TP_PROTO(struct sst_hsw_ipc_stream_info_reply *reply), | ||
| 217 | |||
| 218 | TP_ARGS(reply), | ||
| 219 | |||
| 220 | TP_STRUCT__entry( | ||
| 221 | __field( int, mixer_id ) | ||
| 222 | __field( int, peak0 ) | ||
| 223 | __field( int, peak1 ) | ||
| 224 | __field( int, vol0 ) | ||
| 225 | __field( int, vol1 ) | ||
| 226 | ), | ||
| 227 | |||
| 228 | TP_fast_assign( | ||
| 229 | __entry->mixer_id = reply->mixer_hw_id; | ||
| 230 | __entry->peak0 = reply->peak_meter_register_address[0]; | ||
| 231 | __entry->peak1 = reply->peak_meter_register_address[1]; | ||
| 232 | __entry->vol0 = reply->volume_register_address[0]; | ||
| 233 | __entry->vol1 = reply->volume_register_address[1]; | ||
| 234 | ), | ||
| 235 | |||
| 236 | TP_printk("mixer id %d peak 0x%x:0x%x vol 0x%x,0x%x", | ||
| 237 | (int)__entry->mixer_id, | ||
| 238 | (int)__entry->peak0, (int)__entry->peak1, | ||
| 239 | (int)__entry->vol0, (int)__entry->vol1) | ||
| 240 | ); | ||
| 241 | |||
| 242 | TRACE_EVENT(hsw_stream_data_format, | ||
| 243 | |||
| 244 | TP_PROTO(struct sst_hsw_stream *stream, | ||
| 245 | struct sst_hsw_audio_data_format_ipc *req), | ||
| 246 | |||
| 247 | TP_ARGS(stream, req), | ||
| 248 | |||
| 249 | TP_STRUCT__entry( | ||
| 250 | __field( uint32_t, id ) | ||
| 251 | __field( uint32_t, frequency ) | ||
| 252 | __field( uint32_t, bitdepth ) | ||
| 253 | __field( uint32_t, map ) | ||
| 254 | __field( uint32_t, config ) | ||
| 255 | __field( uint32_t, style ) | ||
| 256 | __field( uint8_t, ch_num ) | ||
| 257 | __field( uint8_t, valid_bit ) | ||
| 258 | ), | ||
| 259 | |||
| 260 | TP_fast_assign( | ||
| 261 | __entry->id = stream->host_id; | ||
| 262 | __entry->frequency = req->frequency; | ||
| 263 | __entry->bitdepth = req->bitdepth; | ||
| 264 | __entry->map = req->map; | ||
| 265 | __entry->config = req->config; | ||
| 266 | __entry->style = req->style; | ||
| 267 | __entry->ch_num = req->ch_num; | ||
| 268 | __entry->valid_bit = req->valid_bit; | ||
| 269 | ), | ||
| 270 | |||
| 271 | TP_printk("stream %d freq %d depth %d map 0x%x config 0x%x style 0x%x ch %d bits %d", | ||
| 272 | (int) __entry->id, (uint32_t)__entry->frequency, | ||
| 273 | (uint32_t)__entry->bitdepth, (uint32_t)__entry->map, | ||
| 274 | (uint32_t)__entry->config, (uint32_t)__entry->style, | ||
| 275 | (uint8_t)__entry->ch_num, (uint8_t)__entry->valid_bit) | ||
| 276 | ); | ||
| 277 | |||
| 278 | TRACE_EVENT(hsw_stream_alloc_request, | ||
| 279 | |||
| 280 | TP_PROTO(struct sst_hsw_stream *stream, | ||
| 281 | struct sst_hsw_ipc_stream_alloc_req *req), | ||
| 282 | |||
| 283 | TP_ARGS(stream, req), | ||
| 284 | |||
| 285 | TP_STRUCT__entry( | ||
| 286 | __field( uint32_t, id ) | ||
| 287 | __field( uint8_t, path_id ) | ||
| 288 | __field( uint8_t, stream_type ) | ||
| 289 | __field( uint8_t, format_id ) | ||
| 290 | ), | ||
| 291 | |||
| 292 | TP_fast_assign( | ||
| 293 | __entry->id = stream->host_id; | ||
| 294 | __entry->path_id = req->path_id; | ||
| 295 | __entry->stream_type = req->stream_type; | ||
| 296 | __entry->format_id = req->format_id; | ||
| 297 | ), | ||
| 298 | |||
| 299 | TP_printk("stream %d path %d type %d format %d", | ||
| 300 | (int) __entry->id, (uint8_t)__entry->path_id, | ||
| 301 | (uint8_t)__entry->stream_type, (uint8_t)__entry->format_id) | ||
| 302 | ); | ||
| 303 | |||
| 304 | TRACE_EVENT(hsw_stream_free_req, | ||
| 305 | |||
| 306 | TP_PROTO(struct sst_hsw_stream *stream, | ||
| 307 | struct sst_hsw_ipc_stream_free_req *req), | ||
| 308 | |||
| 309 | TP_ARGS(stream, req), | ||
| 310 | |||
| 311 | TP_STRUCT__entry( | ||
| 312 | __field( int, id ) | ||
| 313 | __field( int, stream_id ) | ||
| 314 | ), | ||
| 315 | |||
| 316 | TP_fast_assign( | ||
| 317 | __entry->id = stream->host_id; | ||
| 318 | __entry->stream_id = req->stream_id; | ||
| 319 | ), | ||
| 320 | |||
| 321 | TP_printk("stream %d hw id %d", | ||
| 322 | (int) __entry->id, (int) __entry->stream_id) | ||
| 323 | ); | ||
| 324 | |||
| 325 | TRACE_EVENT(hsw_volume_req, | ||
| 326 | |||
| 327 | TP_PROTO(struct sst_hsw_stream *stream, | ||
| 328 | struct sst_hsw_ipc_volume_req *req), | ||
| 329 | |||
| 330 | TP_ARGS(stream, req), | ||
| 331 | |||
| 332 | TP_STRUCT__entry( | ||
| 333 | __field( int, id ) | ||
| 334 | __field( uint32_t, channel ) | ||
| 335 | __field( uint32_t, target_volume ) | ||
| 336 | __field( uint64_t, curve_duration ) | ||
| 337 | __field( uint32_t, curve_type ) | ||
| 338 | ), | ||
| 339 | |||
| 340 | TP_fast_assign( | ||
| 341 | __entry->id = stream->host_id; | ||
| 342 | __entry->channel = req->channel; | ||
| 343 | __entry->target_volume = req->target_volume; | ||
| 344 | __entry->curve_duration = req->curve_duration; | ||
| 345 | __entry->curve_type = req->curve_type; | ||
| 346 | ), | ||
| 347 | |||
| 348 | TP_printk("stream %d chan 0x%x vol %d duration %llu type %d", | ||
| 349 | (int) __entry->id, (uint32_t) __entry->channel, | ||
| 350 | (uint32_t)__entry->target_volume, | ||
| 351 | (uint64_t)__entry->curve_duration, | ||
| 352 | (uint32_t)__entry->curve_type) | ||
| 353 | ); | ||
| 354 | |||
| 355 | TRACE_EVENT(hsw_device_config_req, | ||
| 356 | |||
| 357 | TP_PROTO(struct sst_hsw_ipc_device_config_req *req), | ||
| 358 | |||
| 359 | TP_ARGS(req), | ||
| 360 | |||
| 361 | TP_STRUCT__entry( | ||
| 362 | __field( uint32_t, ssp ) | ||
| 363 | __field( uint32_t, clock_freq ) | ||
| 364 | __field( uint32_t, mode ) | ||
| 365 | __field( uint16_t, clock_divider ) | ||
| 366 | ), | ||
| 367 | |||
| 368 | TP_fast_assign( | ||
| 369 | __entry->ssp = req->ssp_interface; | ||
| 370 | __entry->clock_freq = req->clock_frequency; | ||
| 371 | __entry->mode = req->mode; | ||
| 372 | __entry->clock_divider = req->clock_divider; | ||
| 373 | ), | ||
| 374 | |||
| 375 | TP_printk("SSP %d Freq %d mode %d div %d", | ||
| 376 | (uint32_t)__entry->ssp, | ||
| 377 | (uint32_t)__entry->clock_freq, (uint32_t)__entry->mode, | ||
| 378 | (uint32_t)__entry->clock_divider) | ||
| 379 | ); | ||
| 380 | |||
| 381 | #endif /* _TRACE_HSWADSP_H */ | ||
| 382 | |||
| 383 | /* This part must be outside protection */ | ||
| 384 | #include <trace/define_trace.h> | ||
diff --git a/include/trace/events/intel-sst.h b/include/trace/events/intel-sst.h new file mode 100644 index 000000000000..76c72d3f1902 --- /dev/null +++ b/include/trace/events/intel-sst.h | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM intel-sst | ||
| 3 | |||
| 4 | #if !defined(_TRACE_INTEL_SST_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_INTEL_SST_H | ||
| 6 | |||
| 7 | #include <linux/types.h> | ||
| 8 | #include <linux/ktime.h> | ||
| 9 | #include <linux/tracepoint.h> | ||
| 10 | |||
| 11 | DECLARE_EVENT_CLASS(sst_ipc_msg, | ||
| 12 | |||
| 13 | TP_PROTO(unsigned int val), | ||
| 14 | |||
| 15 | TP_ARGS(val), | ||
| 16 | |||
| 17 | TP_STRUCT__entry( | ||
| 18 | __field( unsigned int, val ) | ||
| 19 | ), | ||
| 20 | |||
| 21 | TP_fast_assign( | ||
| 22 | __entry->val = val; | ||
| 23 | ), | ||
| 24 | |||
| 25 | TP_printk("0x%8.8x", (unsigned int)__entry->val) | ||
| 26 | ); | ||
| 27 | |||
| 28 | DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_tx, | ||
| 29 | |||
| 30 | TP_PROTO(unsigned int val), | ||
| 31 | |||
| 32 | TP_ARGS(val) | ||
| 33 | |||
| 34 | ); | ||
| 35 | |||
| 36 | DEFINE_EVENT(sst_ipc_msg, sst_ipc_msg_rx, | ||
| 37 | |||
| 38 | TP_PROTO(unsigned int val), | ||
| 39 | |||
| 40 | TP_ARGS(val) | ||
| 41 | |||
| 42 | ); | ||
| 43 | |||
| 44 | DECLARE_EVENT_CLASS(sst_ipc_mailbox, | ||
| 45 | |||
| 46 | TP_PROTO(unsigned int offset, unsigned int val), | ||
| 47 | |||
| 48 | TP_ARGS(offset, val), | ||
| 49 | |||
| 50 | TP_STRUCT__entry( | ||
| 51 | __field( unsigned int, offset ) | ||
| 52 | __field( unsigned int, val ) | ||
| 53 | ), | ||
| 54 | |||
| 55 | TP_fast_assign( | ||
| 56 | __entry->offset = offset; | ||
| 57 | __entry->val = val; | ||
| 58 | ), | ||
| 59 | |||
| 60 | TP_printk(" 0x%4.4x = 0x%8.8x", | ||
| 61 | (unsigned int)__entry->offset, (unsigned int)__entry->val) | ||
| 62 | ); | ||
| 63 | |||
| 64 | DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_rdata, | ||
| 65 | |||
| 66 | TP_PROTO(unsigned int offset, unsigned int val), | ||
| 67 | |||
| 68 | TP_ARGS(offset, val) | ||
| 69 | |||
| 70 | ); | ||
| 71 | |||
| 72 | DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_inbox_wdata, | ||
| 73 | |||
| 74 | TP_PROTO(unsigned int offset, unsigned int val), | ||
| 75 | |||
| 76 | TP_ARGS(offset, val) | ||
| 77 | |||
| 78 | ); | ||
| 79 | |||
| 80 | DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_rdata, | ||
| 81 | |||
| 82 | TP_PROTO(unsigned int offset, unsigned int val), | ||
| 83 | |||
| 84 | TP_ARGS(offset, val) | ||
| 85 | |||
| 86 | ); | ||
| 87 | |||
| 88 | DEFINE_EVENT(sst_ipc_mailbox, sst_ipc_outbox_wdata, | ||
| 89 | |||
| 90 | TP_PROTO(unsigned int offset, unsigned int val), | ||
| 91 | |||
| 92 | TP_ARGS(offset, val) | ||
| 93 | |||
| 94 | ); | ||
| 95 | |||
| 96 | DECLARE_EVENT_CLASS(sst_ipc_mailbox_info, | ||
| 97 | |||
| 98 | TP_PROTO(unsigned int size), | ||
| 99 | |||
| 100 | TP_ARGS(size), | ||
| 101 | |||
| 102 | TP_STRUCT__entry( | ||
| 103 | __field( unsigned int, size ) | ||
| 104 | ), | ||
| 105 | |||
| 106 | TP_fast_assign( | ||
| 107 | __entry->size = size; | ||
| 108 | ), | ||
| 109 | |||
| 110 | TP_printk("Mailbox bytes 0x%8.8x", (unsigned int)__entry->size) | ||
| 111 | ); | ||
| 112 | |||
| 113 | DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_read, | ||
| 114 | |||
| 115 | TP_PROTO(unsigned int size), | ||
| 116 | |||
| 117 | TP_ARGS(size) | ||
| 118 | |||
| 119 | ); | ||
| 120 | |||
| 121 | DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_inbox_write, | ||
| 122 | |||
| 123 | TP_PROTO(unsigned int size), | ||
| 124 | |||
| 125 | TP_ARGS(size) | ||
| 126 | |||
| 127 | ); | ||
| 128 | |||
| 129 | DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_read, | ||
| 130 | |||
| 131 | TP_PROTO(unsigned int size), | ||
| 132 | |||
| 133 | TP_ARGS(size) | ||
| 134 | |||
| 135 | ); | ||
| 136 | |||
| 137 | DEFINE_EVENT(sst_ipc_mailbox_info, sst_ipc_outbox_write, | ||
| 138 | |||
| 139 | TP_PROTO(unsigned int size), | ||
| 140 | |||
| 141 | TP_ARGS(size) | ||
| 142 | |||
| 143 | ); | ||
| 144 | |||
| 145 | #endif /* _TRACE_SST_H */ | ||
| 146 | |||
| 147 | /* This part must be outside protection */ | ||
| 148 | #include <trace/define_trace.h> | ||
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a2104671f51d..5dcf88bed9b7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -1242,6 +1242,7 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par | |||
| 1242 | return -EINVAL; | 1242 | return -EINVAL; |
| 1243 | return 0; | 1243 | return 0; |
| 1244 | } | 1244 | } |
| 1245 | EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64); | ||
| 1245 | 1246 | ||
| 1246 | /** | 1247 | /** |
| 1247 | * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval | 1248 | * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval |
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index d62ce483a443..0060b31cc3f3 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
| @@ -50,6 +50,7 @@ source "sound/soc/pxa/Kconfig" | |||
| 50 | source "sound/soc/samsung/Kconfig" | 50 | source "sound/soc/samsung/Kconfig" |
| 51 | source "sound/soc/s6000/Kconfig" | 51 | source "sound/soc/s6000/Kconfig" |
| 52 | source "sound/soc/sh/Kconfig" | 52 | source "sound/soc/sh/Kconfig" |
| 53 | source "sound/soc/sirf/Kconfig" | ||
| 53 | source "sound/soc/spear/Kconfig" | 54 | source "sound/soc/spear/Kconfig" |
| 54 | source "sound/soc/tegra/Kconfig" | 55 | source "sound/soc/tegra/Kconfig" |
| 55 | source "sound/soc/txx9/Kconfig" | 56 | source "sound/soc/txx9/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 62a1822e77bf..5f1df02984f8 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
| @@ -27,6 +27,7 @@ obj-$(CONFIG_SND_SOC) += pxa/ | |||
| 27 | obj-$(CONFIG_SND_SOC) += samsung/ | 27 | obj-$(CONFIG_SND_SOC) += samsung/ |
| 28 | obj-$(CONFIG_SND_SOC) += s6000/ | 28 | obj-$(CONFIG_SND_SOC) += s6000/ |
| 29 | obj-$(CONFIG_SND_SOC) += sh/ | 29 | obj-$(CONFIG_SND_SOC) += sh/ |
| 30 | obj-$(CONFIG_SND_SOC) += sirf/ | ||
| 30 | obj-$(CONFIG_SND_SOC) += spear/ | 31 | obj-$(CONFIG_SND_SOC) += spear/ |
| 31 | obj-$(CONFIG_SND_SOC) += tegra/ | 32 | obj-$(CONFIG_SND_SOC) += tegra/ |
| 32 | obj-$(CONFIG_SND_SOC) += txx9/ | 33 | obj-$(CONFIG_SND_SOC) += txx9/ |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e634eb78ed03..4789619a52d8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
| @@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260 | |||
| 58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC | 58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC |
| 59 | select SND_ATMEL_SOC_PDC | 59 | select SND_ATMEL_SOC_PDC |
| 60 | select SND_ATMEL_SOC_SSC | 60 | select SND_ATMEL_SOC_SSC |
| 61 | select SND_SOC_TLV320AIC23 | 61 | select SND_SOC_TLV320AIC23_I2C |
| 62 | help | 62 | help |
| 63 | Say Y here to support sound on AFEB9260 board. | 63 | Say Y here to support sound on AFEB9260 board. |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1ead3c977a51..de433cfd044c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
| @@ -341,6 +341,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 341 | { | 341 | { |
| 342 | int id = dai->id; | 342 | int id = dai->id; |
| 343 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; | 343 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; |
| 344 | struct ssc_device *ssc = ssc_p->ssc; | ||
| 344 | struct atmel_pcm_dma_params *dma_params; | 345 | struct atmel_pcm_dma_params *dma_params; |
| 345 | int dir, channels, bits; | 346 | int dir, channels, bits; |
| 346 | u32 tfmr, rfmr, tcmr, rcmr; | 347 | u32 tfmr, rfmr, tcmr, rcmr; |
| @@ -466,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 466 | | SSC_BF(RCMR_START, start_event) | 467 | | SSC_BF(RCMR_START, start_event) |
| 467 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 468 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
| 468 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 469 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
| 469 | | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); | 470 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
| 471 | SSC_CKS_PIN : SSC_CKS_CLOCK); | ||
| 470 | 472 | ||
| 471 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 473 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
| 472 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | 474 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
| @@ -481,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 481 | | SSC_BF(TCMR_START, start_event) | 483 | | SSC_BF(TCMR_START, start_event) |
| 482 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 484 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
| 483 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | 485 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
| 484 | | SSC_BF(TCMR_CKS, SSC_CKS_PIN); | 486 | | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? |
| 487 | SSC_CKS_CLOCK : SSC_CKS_PIN); | ||
| 485 | 488 | ||
| 486 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 489 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
| 487 | | SSC_BF(TFMR_FSDEN, 0) | 490 | | SSC_BF(TFMR_FSDEN, 0) |
| @@ -550,7 +553,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 550 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 553 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
| 551 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 554 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
| 552 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 555 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
| 553 | | SSC_BF(RCMR_CKS, SSC_CKS_PIN); | 556 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
| 557 | SSC_CKS_PIN : SSC_CKS_CLOCK); | ||
| 554 | 558 | ||
| 555 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 559 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
| 556 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | 560 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
| @@ -565,7 +569,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
| 565 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) | 569 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) |
| 566 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 570 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
| 567 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | 571 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
| 568 | | SSC_BF(TCMR_CKS, SSC_CKS_PIN); | 572 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
| 573 | SSC_CKS_CLOCK : SSC_CKS_PIN); | ||
| 569 | 574 | ||
| 570 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 575 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
| 571 | | SSC_BF(TFMR_FSDEN, 0) | 576 | | SSC_BF(TFMR_FSDEN, 0) |
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index f15bff1548f8..174bd546c08b 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
| @@ -155,25 +155,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | |||
| 155 | return ret; | 155 | return ret; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | /* Add specific widgets */ | ||
| 159 | snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, | ||
| 160 | ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); | ||
| 161 | /* Set up specific audio path interconnects */ | ||
| 162 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
| 163 | |||
| 164 | /* not connected */ | 158 | /* not connected */ |
| 165 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | 159 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); |
| 166 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | 160 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); |
| 167 | 161 | ||
| 168 | #ifdef ENABLE_MIC_INPUT | 162 | #ifndef ENABLE_MIC_INPUT |
| 169 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); | 163 | snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); |
| 170 | #else | ||
| 171 | snd_soc_dapm_nc_pin(dapm, "Int Mic"); | ||
| 172 | #endif | 164 | #endif |
| 173 | 165 | ||
| 174 | /* always connected */ | ||
| 175 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | ||
| 176 | |||
| 177 | return 0; | 166 | return 0; |
| 178 | } | 167 | } |
| 179 | 168 | ||
| @@ -194,6 +183,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { | |||
| 194 | .dai_link = &at91sam9g20ek_dai, | 183 | .dai_link = &at91sam9g20ek_dai, |
| 195 | .num_links = 1, | 184 | .num_links = 1, |
| 196 | .set_bias_level = at91sam9g20ek_set_bias_level, | 185 | .set_bias_level = at91sam9g20ek_set_bias_level, |
| 186 | |||
| 187 | .dapm_widgets = at91sam9g20ek_dapm_widgets, | ||
| 188 | .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), | ||
| 189 | .dapm_routes = intercon, | ||
| 190 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
| 197 | }; | 191 | }; |
| 198 | 192 | ||
| 199 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) | 193 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) |
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 4544d8eb1452..6347d5910138 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
| @@ -14,7 +14,8 @@ config SND_BF5XX_SOC_SSM2602 | |||
| 14 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI | 14 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
| 15 | select SND_BF5XX_SOC_I2S if !BF60x | 15 | select SND_BF5XX_SOC_I2S if !BF60x |
| 16 | select SND_BF6XX_SOC_I2S if BF60x | 16 | select SND_BF6XX_SOC_I2S if BF60x |
| 17 | select SND_SOC_SSM2602 | 17 | select SND_SOC_SSM2602_SPI if SPI_MASTER |
| 18 | select SND_SOC_SSM2602_I2C if I2C | ||
| 18 | help | 19 | help |
| 19 | Say Y if you want to add support for the Analog Devices | 20 | Say Y if you want to add support for the Analog Devices |
| 20 | SSM2602 Audio Codec Add-On Card. | 21 | SSM2602 Audio Codec Add-On Card. |
| @@ -46,7 +47,8 @@ config SND_SOC_BFIN_EVAL_ADAV80X | |||
| 46 | tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" | 47 | tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" |
| 47 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI | 48 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
| 48 | select SND_BF5XX_SOC_I2S | 49 | select SND_BF5XX_SOC_I2S |
| 49 | select SND_SOC_ADAV80X | 50 | select SND_SOC_ADAV801 if SPI_MASTER |
| 51 | select SND_SOC_ADAV803 if I2C | ||
| 50 | help | 52 | help |
| 51 | Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or | 53 | Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or |
| 52 | EVAL-ADAV803 board connected to one of the Blackfin evaluation boards | 54 | EVAL-ADAV803 board connected to one of the Blackfin evaluation boards |
| @@ -67,7 +69,8 @@ config SND_BF5XX_SOC_AD193X | |||
| 67 | tristate "SoC AD193X Audio support for Blackfin" | 69 | tristate "SoC AD193X Audio support for Blackfin" |
| 68 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI | 70 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
| 69 | select SND_BF5XX_SOC_I2S | 71 | select SND_BF5XX_SOC_I2S |
| 70 | select SND_SOC_AD193X | 72 | select SND_SOC_AD193X_I2C if I2C |
| 73 | select SND_SOC_AD193X_SPI if SPI_MASTER | ||
| 71 | help | 74 | help |
| 72 | Say Y if you want to add support for AD193X codec on Blackfin. | 75 | Say Y if you want to add support for AD193X codec on Blackfin. |
| 73 | This driver supports AD1936, AD1937, AD1938 and AD1939. | 76 | This driver supports AD1936, AD1937, AD1938 and AD1939. |
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 06f938deda15..5477c5475923 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | config SND_EP93XX_SOC | 1 | config SND_EP93XX_SOC |
| 2 | tristate "SoC Audio support for the Cirrus Logic EP93xx series" | 2 | tristate "SoC Audio support for the Cirrus Logic EP93xx series" |
| 3 | depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC | 3 | depends on ARCH_EP93XX || COMPILE_TEST |
| 4 | select SND_SOC_GENERIC_DMAENGINE_PCM | 4 | select SND_SOC_GENERIC_DMAENGINE_PCM |
| 5 | help | 5 | help |
| 6 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
| @@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15 | |||
| 18 | tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" | 18 | tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" |
| 19 | depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 | 19 | depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 |
| 20 | select SND_EP93XX_SOC_I2S | 20 | select SND_EP93XX_SOC_I2S |
| 21 | select SND_SOC_TLV320AIC23 | 21 | select SND_SOC_TLV320AIC23_I2C |
| 22 | help | 22 | help |
| 23 | Say Y or M here if you want to add support for I2S audio on the | 23 | Say Y or M here if you want to add support for I2S audio on the |
| 24 | Bluewater Systems Snapper CL15 module. | 24 | Bluewater Systems Snapper CL15 module. |
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 647a72cda005..8703244ee9fb 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
| @@ -448,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"}; | |||
| 448 | 448 | ||
| 449 | static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; | 449 | static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; |
| 450 | 450 | ||
| 451 | static const struct soc_enum pm860x_hs1_opamp_enum = | 451 | static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum, |
| 452 | SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts); | 452 | PM860X_HS1_CTRL, 5, pm860x_opamp_texts); |
| 453 | 453 | ||
| 454 | static const struct soc_enum pm860x_hs2_opamp_enum = | 454 | static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum, |
| 455 | SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts); | 455 | PM860X_HS2_CTRL, 5, pm860x_opamp_texts); |
| 456 | 456 | ||
| 457 | static const struct soc_enum pm860x_hs1_pa_enum = | 457 | static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum, |
| 458 | SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts); | 458 | PM860X_HS1_CTRL, 3, pm860x_pa_texts); |
| 459 | 459 | ||
| 460 | static const struct soc_enum pm860x_hs2_pa_enum = | 460 | static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum, |
| 461 | SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts); | 461 | PM860X_HS2_CTRL, 3, pm860x_pa_texts); |
| 462 | 462 | ||
| 463 | static const struct soc_enum pm860x_lo1_opamp_enum = | 463 | static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum, |
| 464 | SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts); | 464 | PM860X_LO1_CTRL, 5, pm860x_opamp_texts); |
| 465 | 465 | ||
| 466 | static const struct soc_enum pm860x_lo2_opamp_enum = | 466 | static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum, |
| 467 | SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts); | 467 | PM860X_LO2_CTRL, 5, pm860x_opamp_texts); |
| 468 | 468 | ||
| 469 | static const struct soc_enum pm860x_lo1_pa_enum = | 469 | static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum, |
| 470 | SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts); | 470 | PM860X_LO1_CTRL, 3, pm860x_pa_texts); |
| 471 | 471 | ||
| 472 | static const struct soc_enum pm860x_lo2_pa_enum = | 472 | static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum, |
| 473 | SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts); | 473 | PM860X_LO2_CTRL, 3, pm860x_pa_texts); |
| 474 | 474 | ||
| 475 | static const struct soc_enum pm860x_spk_pa_enum = | 475 | static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum, |
| 476 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts); | 476 | PM860X_EAR_CTRL_1, 5, pm860x_pa_texts); |
| 477 | 477 | ||
| 478 | static const struct soc_enum pm860x_ear_pa_enum = | 478 | static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum, |
| 479 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts); | 479 | PM860X_EAR_CTRL_2, 0, pm860x_pa_texts); |
| 480 | 480 | ||
| 481 | static const struct soc_enum pm860x_spk_ear_opamp_enum = | 481 | static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum, |
| 482 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts); | 482 | PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts); |
| 483 | 483 | ||
| 484 | static const struct snd_kcontrol_new pm860x_snd_controls[] = { | 484 | static const struct snd_kcontrol_new pm860x_snd_controls[] = { |
| 485 | SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, | 485 | SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, |
| @@ -561,8 +561,8 @@ static const char *aif1_text[] = { | |||
| 561 | "PCM L", "PCM R", | 561 | "PCM L", "PCM R", |
| 562 | }; | 562 | }; |
| 563 | 563 | ||
| 564 | static const struct soc_enum aif1_enum = | 564 | static SOC_ENUM_SINGLE_DECL(aif1_enum, |
| 565 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text); | 565 | PM860X_PCM_IFACE_3, 6, aif1_text); |
| 566 | 566 | ||
| 567 | static const struct snd_kcontrol_new aif1_mux = | 567 | static const struct snd_kcontrol_new aif1_mux = |
| 568 | SOC_DAPM_ENUM("PCM Mux", aif1_enum); | 568 | SOC_DAPM_ENUM("PCM Mux", aif1_enum); |
| @@ -572,8 +572,8 @@ static const char *i2s_din_text[] = { | |||
| 572 | "DIN", "DIN1", | 572 | "DIN", "DIN1", |
| 573 | }; | 573 | }; |
| 574 | 574 | ||
| 575 | static const struct soc_enum i2s_din_enum = | 575 | static SOC_ENUM_SINGLE_DECL(i2s_din_enum, |
| 576 | SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text); | 576 | PM860X_I2S_IFACE_3, 1, i2s_din_text); |
| 577 | 577 | ||
| 578 | static const struct snd_kcontrol_new i2s_din_mux = | 578 | static const struct snd_kcontrol_new i2s_din_mux = |
| 579 | SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); | 579 | SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); |
| @@ -583,8 +583,8 @@ static const char *i2s_mic_text[] = { | |||
| 583 | "Ex PA", "ADC", | 583 | "Ex PA", "ADC", |
| 584 | }; | 584 | }; |
| 585 | 585 | ||
| 586 | static const struct soc_enum i2s_mic_enum = | 586 | static SOC_ENUM_SINGLE_DECL(i2s_mic_enum, |
| 587 | SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text); | 587 | PM860X_I2S_IFACE_3, 4, i2s_mic_text); |
| 588 | 588 | ||
| 589 | static const struct snd_kcontrol_new i2s_mic_mux = | 589 | static const struct snd_kcontrol_new i2s_mic_mux = |
| 590 | SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); | 590 | SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); |
| @@ -594,8 +594,8 @@ static const char *adcl_text[] = { | |||
| 594 | "ADCR", "ADCL", | 594 | "ADCR", "ADCL", |
| 595 | }; | 595 | }; |
| 596 | 596 | ||
| 597 | static const struct soc_enum adcl_enum = | 597 | static SOC_ENUM_SINGLE_DECL(adcl_enum, |
| 598 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text); | 598 | PM860X_PCM_IFACE_3, 4, adcl_text); |
| 599 | 599 | ||
| 600 | static const struct snd_kcontrol_new adcl_mux = | 600 | static const struct snd_kcontrol_new adcl_mux = |
| 601 | SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); | 601 | SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); |
| @@ -605,8 +605,8 @@ static const char *adcr_text[] = { | |||
| 605 | "ADCL", "ADCR", | 605 | "ADCL", "ADCR", |
| 606 | }; | 606 | }; |
| 607 | 607 | ||
| 608 | static const struct soc_enum adcr_enum = | 608 | static SOC_ENUM_SINGLE_DECL(adcr_enum, |
| 609 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text); | 609 | PM860X_PCM_IFACE_3, 2, adcr_text); |
| 610 | 610 | ||
| 611 | static const struct snd_kcontrol_new adcr_mux = | 611 | static const struct snd_kcontrol_new adcr_mux = |
| 612 | SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); | 612 | SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); |
| @@ -616,8 +616,8 @@ static const char *adcr_ec_text[] = { | |||
| 616 | "ADCR", "EC", | 616 | "ADCR", "EC", |
| 617 | }; | 617 | }; |
| 618 | 618 | ||
| 619 | static const struct soc_enum adcr_ec_enum = | 619 | static SOC_ENUM_SINGLE_DECL(adcr_ec_enum, |
| 620 | SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text); | 620 | PM860X_ADC_EN_2, 3, adcr_ec_text); |
| 621 | 621 | ||
| 622 | static const struct snd_kcontrol_new adcr_ec_mux = | 622 | static const struct snd_kcontrol_new adcr_ec_mux = |
| 623 | SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); | 623 | SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); |
| @@ -627,8 +627,8 @@ static const char *ec_text[] = { | |||
| 627 | "Left", "Right", "Left + Right", | 627 | "Left", "Right", "Left + Right", |
| 628 | }; | 628 | }; |
| 629 | 629 | ||
| 630 | static const struct soc_enum ec_enum = | 630 | static SOC_ENUM_SINGLE_DECL(ec_enum, |
| 631 | SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text); | 631 | PM860X_EC_PATH, 1, ec_text); |
| 632 | 632 | ||
| 633 | static const struct snd_kcontrol_new ec_mux = | 633 | static const struct snd_kcontrol_new ec_mux = |
| 634 | SOC_DAPM_ENUM("EC Mux", ec_enum); | 634 | SOC_DAPM_ENUM("EC Mux", ec_enum); |
| @@ -638,36 +638,36 @@ static const char *dac_text[] = { | |||
| 638 | }; | 638 | }; |
| 639 | 639 | ||
| 640 | /* DAC Headset 1 Mux / Mux10 */ | 640 | /* DAC Headset 1 Mux / Mux10 */ |
| 641 | static const struct soc_enum dac_hs1_enum = | 641 | static SOC_ENUM_SINGLE_DECL(dac_hs1_enum, |
| 642 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text); | 642 | PM860X_ANA_INPUT_SEL_1, 0, dac_text); |
| 643 | 643 | ||
| 644 | static const struct snd_kcontrol_new dac_hs1_mux = | 644 | static const struct snd_kcontrol_new dac_hs1_mux = |
| 645 | SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); | 645 | SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); |
| 646 | 646 | ||
| 647 | /* DAC Headset 2 Mux / Mux11 */ | 647 | /* DAC Headset 2 Mux / Mux11 */ |
| 648 | static const struct soc_enum dac_hs2_enum = | 648 | static SOC_ENUM_SINGLE_DECL(dac_hs2_enum, |
| 649 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text); | 649 | PM860X_ANA_INPUT_SEL_1, 2, dac_text); |
| 650 | 650 | ||
| 651 | static const struct snd_kcontrol_new dac_hs2_mux = | 651 | static const struct snd_kcontrol_new dac_hs2_mux = |
| 652 | SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); | 652 | SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); |
| 653 | 653 | ||
| 654 | /* DAC Lineout 1 Mux / Mux12 */ | 654 | /* DAC Lineout 1 Mux / Mux12 */ |
| 655 | static const struct soc_enum dac_lo1_enum = | 655 | static SOC_ENUM_SINGLE_DECL(dac_lo1_enum, |
| 656 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text); | 656 | PM860X_ANA_INPUT_SEL_1, 4, dac_text); |
| 657 | 657 | ||
| 658 | static const struct snd_kcontrol_new dac_lo1_mux = | 658 | static const struct snd_kcontrol_new dac_lo1_mux = |
| 659 | SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); | 659 | SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); |
| 660 | 660 | ||
| 661 | /* DAC Lineout 2 Mux / Mux13 */ | 661 | /* DAC Lineout 2 Mux / Mux13 */ |
| 662 | static const struct soc_enum dac_lo2_enum = | 662 | static SOC_ENUM_SINGLE_DECL(dac_lo2_enum, |
| 663 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text); | 663 | PM860X_ANA_INPUT_SEL_1, 6, dac_text); |
| 664 | 664 | ||
| 665 | static const struct snd_kcontrol_new dac_lo2_mux = | 665 | static const struct snd_kcontrol_new dac_lo2_mux = |
| 666 | SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); | 666 | SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); |
| 667 | 667 | ||
| 668 | /* DAC Spearker Earphone Mux / Mux14 */ | 668 | /* DAC Spearker Earphone Mux / Mux14 */ |
| 669 | static const struct soc_enum dac_spk_ear_enum = | 669 | static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum, |
| 670 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text); | 670 | PM860X_ANA_INPUT_SEL_2, 0, dac_text); |
| 671 | 671 | ||
| 672 | static const struct snd_kcontrol_new dac_spk_ear_mux = | 672 | static const struct snd_kcontrol_new dac_spk_ear_mux = |
| 673 | SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); | 673 | SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); |
| @@ -677,29 +677,29 @@ static const char *in_text[] = { | |||
| 677 | "Digital", "Analog", | 677 | "Digital", "Analog", |
| 678 | }; | 678 | }; |
| 679 | 679 | ||
| 680 | static const struct soc_enum hs1_enum = | 680 | static SOC_ENUM_SINGLE_DECL(hs1_enum, |
| 681 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text); | 681 | PM860X_ANA_TO_ANA, 0, in_text); |
| 682 | 682 | ||
| 683 | static const struct snd_kcontrol_new hs1_mux = | 683 | static const struct snd_kcontrol_new hs1_mux = |
| 684 | SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); | 684 | SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); |
| 685 | 685 | ||
| 686 | /* Headset 2 Mux / Mux16 */ | 686 | /* Headset 2 Mux / Mux16 */ |
| 687 | static const struct soc_enum hs2_enum = | 687 | static SOC_ENUM_SINGLE_DECL(hs2_enum, |
| 688 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text); | 688 | PM860X_ANA_TO_ANA, 1, in_text); |
| 689 | 689 | ||
| 690 | static const struct snd_kcontrol_new hs2_mux = | 690 | static const struct snd_kcontrol_new hs2_mux = |
| 691 | SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); | 691 | SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); |
| 692 | 692 | ||
| 693 | /* Lineout 1 Mux / Mux17 */ | 693 | /* Lineout 1 Mux / Mux17 */ |
| 694 | static const struct soc_enum lo1_enum = | 694 | static SOC_ENUM_SINGLE_DECL(lo1_enum, |
| 695 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text); | 695 | PM860X_ANA_TO_ANA, 2, in_text); |
| 696 | 696 | ||
| 697 | static const struct snd_kcontrol_new lo1_mux = | 697 | static const struct snd_kcontrol_new lo1_mux = |
| 698 | SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); | 698 | SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); |
| 699 | 699 | ||
| 700 | /* Lineout 2 Mux / Mux18 */ | 700 | /* Lineout 2 Mux / Mux18 */ |
| 701 | static const struct soc_enum lo2_enum = | 701 | static SOC_ENUM_SINGLE_DECL(lo2_enum, |
| 702 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text); | 702 | PM860X_ANA_TO_ANA, 3, in_text); |
| 703 | 703 | ||
| 704 | static const struct snd_kcontrol_new lo2_mux = | 704 | static const struct snd_kcontrol_new lo2_mux = |
| 705 | SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); | 705 | SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); |
| @@ -709,8 +709,8 @@ static const char *spk_text[] = { | |||
| 709 | "Earpiece", "Speaker", | 709 | "Earpiece", "Speaker", |
| 710 | }; | 710 | }; |
| 711 | 711 | ||
| 712 | static const struct soc_enum spk_enum = | 712 | static SOC_ENUM_SINGLE_DECL(spk_enum, |
| 713 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text); | 713 | PM860X_ANA_TO_ANA, 6, spk_text); |
| 714 | 714 | ||
| 715 | static const struct snd_kcontrol_new spk_demux = | 715 | static const struct snd_kcontrol_new spk_demux = |
| 716 | SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); | 716 | SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); |
| @@ -720,8 +720,8 @@ static const char *mic_text[] = { | |||
| 720 | "Mic 1", "Mic 2", | 720 | "Mic 1", "Mic 2", |
| 721 | }; | 721 | }; |
| 722 | 722 | ||
| 723 | static const struct soc_enum mic_enum = | 723 | static SOC_ENUM_SINGLE_DECL(mic_enum, |
| 724 | SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text); | 724 | PM860X_ADC_ANA_4, 4, mic_text); |
| 725 | 725 | ||
| 726 | static const struct snd_kcontrol_new mic_mux = | 726 | static const struct snd_kcontrol_new mic_mux = |
| 727 | SOC_DAPM_ENUM("MIC Mux", mic_enum); | 727 | SOC_DAPM_ENUM("MIC Mux", mic_enum); |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 983d087aa92a..32d7a6f04b7d 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI | |||
| 8 | default y if I2C=y | 8 | default y if I2C=y |
| 9 | default y if SPI_MASTER=y | 9 | default y if SPI_MASTER=y |
| 10 | 10 | ||
| 11 | menu "CODEC drivers" | ||
| 12 | |||
| 11 | config SND_SOC_ALL_CODECS | 13 | config SND_SOC_ALL_CODECS |
| 12 | tristate "Build all ASoC CODEC drivers" | 14 | tristate "Build all ASoC CODEC drivers" |
| 13 | depends on COMPILE_TEST | 15 | depends on COMPILE_TEST |
| @@ -16,15 +18,20 @@ config SND_SOC_ALL_CODECS | |||
| 16 | select SND_SOC_AB8500_CODEC if ABX500_CORE | 18 | select SND_SOC_AB8500_CODEC if ABX500_CORE |
| 17 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 19 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS |
| 18 | select SND_SOC_AD1836 if SPI_MASTER | 20 | select SND_SOC_AD1836 if SPI_MASTER |
| 19 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI | 21 | select SND_SOC_AD193X_SPI if SPI_MASTER |
| 22 | select SND_SOC_AD193X_I2C if I2C | ||
| 20 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS | 23 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS |
| 21 | select SND_SOC_AD73311 | 24 | select SND_SOC_AD73311 |
| 22 | select SND_SOC_ADAU1373 if I2C | 25 | select SND_SOC_ADAU1373 if I2C |
| 23 | select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI | 26 | select SND_SOC_ADAV801 if SPI_MASTER |
| 27 | select SND_SOC_ADAV803 if I2C | ||
| 28 | select SND_SOC_ADAU1977_SPI if SPI_MASTER | ||
| 29 | select SND_SOC_ADAU1977_I2C if I2C | ||
| 24 | select SND_SOC_ADAU1701 if I2C | 30 | select SND_SOC_ADAU1701 if I2C |
| 25 | select SND_SOC_ADS117X | 31 | select SND_SOC_ADS117X |
| 26 | select SND_SOC_AK4104 if SPI_MASTER | 32 | select SND_SOC_AK4104 if SPI_MASTER |
| 27 | select SND_SOC_AK4535 if I2C | 33 | select SND_SOC_AK4535 if I2C |
| 34 | select SND_SOC_AK4554 | ||
| 28 | select SND_SOC_AK4641 if I2C | 35 | select SND_SOC_AK4641 if I2C |
| 29 | select SND_SOC_AK4642 if I2C | 36 | select SND_SOC_AK4642 if I2C |
| 30 | select SND_SOC_AK4671 if I2C | 37 | select SND_SOC_AK4671 if I2C |
| @@ -59,19 +66,24 @@ config SND_SOC_ALL_CODECS | |||
| 59 | select SND_SOC_PCM1681 if I2C | 66 | select SND_SOC_PCM1681 if I2C |
| 60 | select SND_SOC_PCM1792A if SPI_MASTER | 67 | select SND_SOC_PCM1792A if SPI_MASTER |
| 61 | select SND_SOC_PCM3008 | 68 | select SND_SOC_PCM3008 |
| 69 | select SND_SOC_PCM512x_I2C if I2C | ||
| 70 | select SND_SOC_PCM512x_SPI if SPI_MASTER | ||
| 62 | select SND_SOC_RT5631 if I2C | 71 | select SND_SOC_RT5631 if I2C |
| 63 | select SND_SOC_RT5640 if I2C | 72 | select SND_SOC_RT5640 if I2C |
| 64 | select SND_SOC_SGTL5000 if I2C | 73 | select SND_SOC_SGTL5000 if I2C |
| 65 | select SND_SOC_SI476X if MFD_SI476X_CORE | 74 | select SND_SOC_SI476X if MFD_SI476X_CORE |
| 75 | select SND_SOC_SIRF_AUDIO_CODEC | ||
| 66 | select SND_SOC_SN95031 if INTEL_SCU_IPC | 76 | select SND_SOC_SN95031 if INTEL_SCU_IPC |
| 67 | select SND_SOC_SPDIF | 77 | select SND_SOC_SPDIF |
| 68 | select SND_SOC_SSM2518 if I2C | 78 | select SND_SOC_SSM2518 if I2C |
| 69 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI | 79 | select SND_SOC_SSM2602_SPI if SPI_MASTER |
| 80 | select SND_SOC_SSM2602_I2C if I2C | ||
| 70 | select SND_SOC_STA32X if I2C | 81 | select SND_SOC_STA32X if I2C |
| 71 | select SND_SOC_STA529 if I2C | 82 | select SND_SOC_STA529 if I2C |
| 72 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 83 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
| 73 | select SND_SOC_TAS5086 if I2C | 84 | select SND_SOC_TAS5086 if I2C |
| 74 | select SND_SOC_TLV320AIC23 if I2C | 85 | select SND_SOC_TLV320AIC23_I2C if I2C |
| 86 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | ||
| 75 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 87 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
| 76 | select SND_SOC_TLV320AIC32X4 if I2C | 88 | select SND_SOC_TLV320AIC32X4 if I2C |
| 77 | select SND_SOC_TLV320AIC3X if I2C | 89 | select SND_SOC_TLV320AIC3X if I2C |
| @@ -182,6 +194,14 @@ config SND_SOC_AD1836 | |||
| 182 | config SND_SOC_AD193X | 194 | config SND_SOC_AD193X |
| 183 | tristate | 195 | tristate |
| 184 | 196 | ||
| 197 | config SND_SOC_AD193X_SPI | ||
| 198 | tristate | ||
| 199 | select SND_SOC_AD193X | ||
| 200 | |||
| 201 | config SND_SOC_AD193X_I2C | ||
| 202 | tristate | ||
| 203 | select SND_SOC_AD193X | ||
| 204 | |||
| 185 | config SND_SOC_AD1980 | 205 | config SND_SOC_AD1980 |
| 186 | tristate | 206 | tristate |
| 187 | 207 | ||
| @@ -189,41 +209,66 @@ config SND_SOC_AD73311 | |||
| 189 | tristate | 209 | tristate |
| 190 | 210 | ||
| 191 | config SND_SOC_ADAU1701 | 211 | config SND_SOC_ADAU1701 |
| 212 | tristate "Analog Devices ADAU1701 CODEC" | ||
| 213 | depends on I2C | ||
| 192 | select SND_SOC_SIGMADSP | 214 | select SND_SOC_SIGMADSP |
| 193 | tristate | ||
| 194 | 215 | ||
| 195 | config SND_SOC_ADAU1373 | 216 | config SND_SOC_ADAU1373 |
| 196 | tristate | 217 | tristate |
| 197 | 218 | ||
| 219 | config SND_SOC_ADAU1977 | ||
| 220 | tristate | ||
| 221 | |||
| 222 | config SND_SOC_ADAU1977_SPI | ||
| 223 | tristate | ||
| 224 | select SND_SOC_ADAU1977 | ||
| 225 | select REGMAP_SPI | ||
| 226 | |||
| 227 | config SND_SOC_ADAU1977_I2C | ||
| 228 | tristate | ||
| 229 | select SND_SOC_ADAU1977 | ||
| 230 | select REGMAP_I2C | ||
| 231 | |||
| 198 | config SND_SOC_ADAV80X | 232 | config SND_SOC_ADAV80X |
| 199 | tristate | 233 | tristate |
| 200 | 234 | ||
| 235 | config SND_SOC_ADAV801 | ||
| 236 | tristate | ||
| 237 | select SND_SOC_ADAV80X | ||
| 238 | |||
| 239 | config SND_SOC_ADAV803 | ||
| 240 | tristate | ||
| 241 | select SND_SOC_ADAV80X | ||
| 242 | |||
| 201 | config SND_SOC_ADS117X | 243 | config SND_SOC_ADS117X |
| 202 | tristate | 244 | tristate |
| 203 | 245 | ||
| 204 | config SND_SOC_AK4104 | 246 | config SND_SOC_AK4104 |
| 205 | tristate | 247 | tristate "AKM AK4104 CODEC" |
| 248 | depends on SPI_MASTER | ||
| 206 | 249 | ||
| 207 | config SND_SOC_AK4535 | 250 | config SND_SOC_AK4535 |
| 208 | tristate | 251 | tristate |
| 209 | 252 | ||
| 210 | config SND_SOC_AK4554 | 253 | config SND_SOC_AK4554 |
| 211 | tristate | 254 | tristate "AKM AK4554 CODEC" |
| 212 | 255 | ||
| 213 | config SND_SOC_AK4641 | 256 | config SND_SOC_AK4641 |
| 214 | tristate | 257 | tristate |
| 215 | 258 | ||
| 216 | config SND_SOC_AK4642 | 259 | config SND_SOC_AK4642 |
| 217 | tristate | 260 | tristate "AKM AK4642 CODEC" |
| 261 | depends on I2C | ||
| 218 | 262 | ||
| 219 | config SND_SOC_AK4671 | 263 | config SND_SOC_AK4671 |
| 220 | tristate | 264 | tristate |
| 221 | 265 | ||
| 222 | config SND_SOC_AK5386 | 266 | config SND_SOC_AK5386 |
| 223 | tristate | 267 | tristate "AKM AK5638 CODEC" |
| 224 | 268 | ||
| 225 | config SND_SOC_ALC5623 | 269 | config SND_SOC_ALC5623 |
| 226 | tristate | 270 | tristate |
| 271 | |||
| 227 | config SND_SOC_ALC5632 | 272 | config SND_SOC_ALC5632 |
| 228 | tristate | 273 | tristate |
| 229 | 274 | ||
| @@ -234,14 +279,17 @@ config SND_SOC_CS42L51 | |||
| 234 | tristate | 279 | tristate |
| 235 | 280 | ||
| 236 | config SND_SOC_CS42L52 | 281 | config SND_SOC_CS42L52 |
| 237 | tristate | 282 | tristate "Cirrus Logic CS42L52 CODEC" |
| 283 | depends on I2C | ||
| 238 | 284 | ||
| 239 | config SND_SOC_CS42L73 | 285 | config SND_SOC_CS42L73 |
| 240 | tristate | 286 | tristate "Cirrus Logic CS42L73 CODEC" |
| 287 | depends on I2C | ||
| 241 | 288 | ||
| 242 | # Cirrus Logic CS4270 Codec | 289 | # Cirrus Logic CS4270 Codec |
| 243 | config SND_SOC_CS4270 | 290 | config SND_SOC_CS4270 |
| 244 | tristate | 291 | tristate "Cirrus Logic CS4270 CODEC" |
| 292 | depends on I2C | ||
| 245 | 293 | ||
| 246 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 294 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
| 247 | # Select if you are affected by the errata where the part will not function | 295 | # Select if you are affected by the errata where the part will not function |
| @@ -252,7 +300,8 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
| 252 | depends on SND_SOC_CS4270 | 300 | depends on SND_SOC_CS4270 |
| 253 | 301 | ||
| 254 | config SND_SOC_CS4271 | 302 | config SND_SOC_CS4271 |
| 255 | tristate | 303 | tristate "Cirrus Logic CS4271 CODEC" |
| 304 | depends on SND_SOC_I2C_AND_SPI | ||
| 256 | 305 | ||
| 257 | config SND_SOC_CX20442 | 306 | config SND_SOC_CX20442 |
| 258 | tristate | 307 | tristate |
| @@ -283,6 +332,9 @@ config SND_SOC_BT_SCO | |||
| 283 | config SND_SOC_DMIC | 332 | config SND_SOC_DMIC |
| 284 | tristate | 333 | tristate |
| 285 | 334 | ||
| 335 | config SND_SOC_HDMI_CODEC | ||
| 336 | tristate "HDMI stub CODEC" | ||
| 337 | |||
| 286 | config SND_SOC_ISABELLE | 338 | config SND_SOC_ISABELLE |
| 287 | tristate | 339 | tristate |
| 288 | 340 | ||
| @@ -301,18 +353,32 @@ config SND_SOC_MAX98095 | |||
| 301 | config SND_SOC_MAX9850 | 353 | config SND_SOC_MAX9850 |
| 302 | tristate | 354 | tristate |
| 303 | 355 | ||
| 304 | config SND_SOC_HDMI_CODEC | ||
| 305 | tristate | ||
| 306 | |||
| 307 | config SND_SOC_PCM1681 | 356 | config SND_SOC_PCM1681 |
| 308 | tristate | 357 | tristate "Texas Instruments PCM1681 CODEC" |
| 358 | depends on I2C | ||
| 309 | 359 | ||
| 310 | config SND_SOC_PCM1792A | 360 | config SND_SOC_PCM1792A |
| 311 | tristate | 361 | tristate "Texas Instruments PCM1792A CODEC" |
| 362 | depends on SPI_MASTER | ||
| 312 | 363 | ||
| 313 | config SND_SOC_PCM3008 | 364 | config SND_SOC_PCM3008 |
| 314 | tristate | 365 | tristate |
| 315 | 366 | ||
| 367 | config SND_SOC_PCM512x | ||
| 368 | tristate | ||
| 369 | |||
| 370 | config SND_SOC_PCM512x_I2C | ||
| 371 | tristate "Texas Instruments PCM512x CODECs - I2C" | ||
| 372 | depends on I2C | ||
| 373 | select SND_SOC_PCM512x | ||
| 374 | select REGMAP_I2C | ||
| 375 | |||
| 376 | config SND_SOC_PCM512x_SPI | ||
| 377 | tristate "Texas Instruments PCM512x CODECs - SPI" | ||
| 378 | depends on SPI_MASTER | ||
| 379 | select SND_SOC_PCM512x | ||
| 380 | select REGMAP_SPI | ||
| 381 | |||
| 316 | config SND_SOC_RT5631 | 382 | config SND_SOC_RT5631 |
| 317 | tristate | 383 | tristate |
| 318 | 384 | ||
| @@ -321,7 +387,8 @@ config SND_SOC_RT5640 | |||
| 321 | 387 | ||
| 322 | #Freescale sgtl5000 codec | 388 | #Freescale sgtl5000 codec |
| 323 | config SND_SOC_SGTL5000 | 389 | config SND_SOC_SGTL5000 |
| 324 | tristate | 390 | tristate "Freescale SGTL5000 CODEC" |
| 391 | depends on I2C | ||
| 325 | 392 | ||
| 326 | config SND_SOC_SI476X | 393 | config SND_SOC_SI476X |
| 327 | tristate | 394 | tristate |
| @@ -330,11 +397,15 @@ config SND_SOC_SIGMADSP | |||
| 330 | tristate | 397 | tristate |
| 331 | select CRC32 | 398 | select CRC32 |
| 332 | 399 | ||
| 400 | config SND_SOC_SIRF_AUDIO_CODEC | ||
| 401 | tristate "SiRF SoC internal audio codec" | ||
| 402 | select REGMAP_MMIO | ||
| 403 | |||
| 333 | config SND_SOC_SN95031 | 404 | config SND_SOC_SN95031 |
| 334 | tristate | 405 | tristate |
| 335 | 406 | ||
| 336 | config SND_SOC_SPDIF | 407 | config SND_SOC_SPDIF |
| 337 | tristate | 408 | tristate "S/PDIF CODEC" |
| 338 | 409 | ||
| 339 | config SND_SOC_SSM2518 | 410 | config SND_SOC_SSM2518 |
| 340 | tristate | 411 | tristate |
| @@ -342,6 +413,14 @@ config SND_SOC_SSM2518 | |||
| 342 | config SND_SOC_SSM2602 | 413 | config SND_SOC_SSM2602 |
| 343 | tristate | 414 | tristate |
| 344 | 415 | ||
| 416 | config SND_SOC_SSM2602_SPI | ||
| 417 | select SND_SOC_SSM2602 | ||
| 418 | tristate | ||
| 419 | |||
| 420 | config SND_SOC_SSM2602_I2C | ||
| 421 | select SND_SOC_SSM2602 | ||
| 422 | tristate | ||
| 423 | |||
| 345 | config SND_SOC_STA32X | 424 | config SND_SOC_STA32X |
| 346 | tristate | 425 | tristate |
| 347 | 426 | ||
| @@ -352,11 +431,20 @@ config SND_SOC_STAC9766 | |||
| 352 | tristate | 431 | tristate |
| 353 | 432 | ||
| 354 | config SND_SOC_TAS5086 | 433 | config SND_SOC_TAS5086 |
| 355 | tristate | 434 | tristate "Texas Instruments TAS5086 speaker amplifier" |
| 435 | depends on I2C | ||
| 356 | 436 | ||
| 357 | config SND_SOC_TLV320AIC23 | 437 | config SND_SOC_TLV320AIC23 |
| 358 | tristate | 438 | tristate |
| 359 | 439 | ||
| 440 | config SND_SOC_TLV320AIC23_I2C | ||
| 441 | tristate | ||
| 442 | select SND_SOC_TLV320AIC23 | ||
| 443 | |||
| 444 | config SND_SOC_TLV320AIC23_SPI | ||
| 445 | tristate | ||
| 446 | select SND_SOC_TLV320AIC23 | ||
| 447 | |||
| 360 | config SND_SOC_TLV320AIC26 | 448 | config SND_SOC_TLV320AIC26 |
| 361 | tristate | 449 | tristate |
| 362 | depends on SPI | 450 | depends on SPI |
| @@ -365,7 +453,8 @@ config SND_SOC_TLV320AIC32X4 | |||
| 365 | tristate | 453 | tristate |
| 366 | 454 | ||
| 367 | config SND_SOC_TLV320AIC3X | 455 | config SND_SOC_TLV320AIC3X |
| 368 | tristate | 456 | tristate "Texas Instruments TLV320AIC3x CODECs" |
| 457 | depends on I2C | ||
| 369 | 458 | ||
| 370 | config SND_SOC_TLV320DAC33 | 459 | config SND_SOC_TLV320DAC33 |
| 371 | tristate | 460 | tristate |
| @@ -414,55 +503,69 @@ config SND_SOC_WM8400 | |||
| 414 | tristate | 503 | tristate |
| 415 | 504 | ||
| 416 | config SND_SOC_WM8510 | 505 | config SND_SOC_WM8510 |
| 417 | tristate | 506 | tristate "Wolfson Microelectronics WM8510 CODEC" |
| 507 | depends on SND_SOC_I2C_AND_SPI | ||
| 418 | 508 | ||
| 419 | config SND_SOC_WM8523 | 509 | config SND_SOC_WM8523 |
| 420 | tristate | 510 | tristate "Wolfson Microelectronics WM8523 DAC" |
| 511 | depends on I2C | ||
| 421 | 512 | ||
| 422 | config SND_SOC_WM8580 | 513 | config SND_SOC_WM8580 |
| 423 | tristate | 514 | tristate "Wolfson Microelectronics WM8523 CODEC" |
| 515 | depends on I2C | ||
| 424 | 516 | ||
| 425 | config SND_SOC_WM8711 | 517 | config SND_SOC_WM8711 |
| 426 | tristate | 518 | tristate "Wolfson Microelectronics WM8711 CODEC" |
| 519 | depends on SND_SOC_I2C_AND_SPI | ||
| 427 | 520 | ||
| 428 | config SND_SOC_WM8727 | 521 | config SND_SOC_WM8727 |
| 429 | tristate | 522 | tristate |
| 430 | 523 | ||
| 431 | config SND_SOC_WM8728 | 524 | config SND_SOC_WM8728 |
| 432 | tristate | 525 | tristate "Wolfson Microelectronics WM8728 DAC" |
| 526 | depends on SND_SOC_I2C_AND_SPI | ||
| 433 | 527 | ||
| 434 | config SND_SOC_WM8731 | 528 | config SND_SOC_WM8731 |
| 435 | tristate | 529 | tristate "Wolfson Microelectronics WM8731 CODEC" |
| 530 | depends on SND_SOC_I2C_AND_SPI | ||
| 436 | 531 | ||
| 437 | config SND_SOC_WM8737 | 532 | config SND_SOC_WM8737 |
| 438 | tristate | 533 | tristate "Wolfson Microelectronics WM8737 ADC" |
| 534 | depends on SND_SOC_I2C_AND_SPI | ||
| 439 | 535 | ||
| 440 | config SND_SOC_WM8741 | 536 | config SND_SOC_WM8741 |
| 441 | tristate | 537 | tristate "Wolfson Microelectronics WM8737 DAC" |
| 538 | depends on SND_SOC_I2C_AND_SPI | ||
| 442 | 539 | ||
| 443 | config SND_SOC_WM8750 | 540 | config SND_SOC_WM8750 |
| 444 | tristate | 541 | tristate "Wolfson Microelectronics WM8750 CODEC" |
| 542 | depends on SND_SOC_I2C_AND_SPI | ||
| 445 | 543 | ||
| 446 | config SND_SOC_WM8753 | 544 | config SND_SOC_WM8753 |
| 447 | tristate | 545 | tristate "Wolfson Microelectronics WM8753 CODEC" |
| 546 | depends on SND_SOC_I2C_AND_SPI | ||
| 448 | 547 | ||
| 449 | config SND_SOC_WM8770 | 548 | config SND_SOC_WM8770 |
| 450 | tristate | 549 | tristate "Wolfson Microelectronics WM8770 CODEC" |
| 550 | depends on SPI_MASTER | ||
| 451 | 551 | ||
| 452 | config SND_SOC_WM8776 | 552 | config SND_SOC_WM8776 |
| 453 | tristate | 553 | tristate "Wolfson Microelectronics WM8776 CODEC" |
| 554 | depends on SND_SOC_I2C_AND_SPI | ||
| 454 | 555 | ||
| 455 | config SND_SOC_WM8782 | 556 | config SND_SOC_WM8782 |
| 456 | tristate | 557 | tristate |
| 457 | 558 | ||
| 458 | config SND_SOC_WM8804 | 559 | config SND_SOC_WM8804 |
| 459 | tristate | 560 | tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" |
| 561 | depends on SND_SOC_I2C_AND_SPI | ||
| 460 | 562 | ||
| 461 | config SND_SOC_WM8900 | 563 | config SND_SOC_WM8900 |
| 462 | tristate | 564 | tristate |
| 463 | 565 | ||
| 464 | config SND_SOC_WM8903 | 566 | config SND_SOC_WM8903 |
| 465 | tristate | 567 | tristate "Wolfson Microelectronics WM8903 CODEC" |
| 568 | depends on I2C | ||
| 466 | 569 | ||
| 467 | config SND_SOC_WM8904 | 570 | config SND_SOC_WM8904 |
| 468 | tristate | 571 | tristate |
| @@ -480,7 +583,8 @@ config SND_SOC_WM8961 | |||
| 480 | tristate | 583 | tristate |
| 481 | 584 | ||
| 482 | config SND_SOC_WM8962 | 585 | config SND_SOC_WM8962 |
| 483 | tristate | 586 | tristate "Wolfson Microelectronics WM8962 CODEC" |
| 587 | depends on I2C | ||
| 484 | 588 | ||
| 485 | config SND_SOC_WM8971 | 589 | config SND_SOC_WM8971 |
| 486 | tristate | 590 | tristate |
| @@ -553,4 +657,7 @@ config SND_SOC_ML26124 | |||
| 553 | tristate | 657 | tristate |
| 554 | 658 | ||
| 555 | config SND_SOC_TPA6130A2 | 659 | config SND_SOC_TPA6130A2 |
| 556 | tristate | 660 | tristate "Texas Instruments TPA6130A2 headphone amplifier" |
| 661 | depends on I2C | ||
| 662 | |||
| 663 | endmenu | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bc126764a44d..cb46c4c78dc2 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
| @@ -3,11 +3,18 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o | |||
| 3 | snd-soc-ac97-objs := ac97.o | 3 | snd-soc-ac97-objs := ac97.o |
| 4 | snd-soc-ad1836-objs := ad1836.o | 4 | snd-soc-ad1836-objs := ad1836.o |
| 5 | snd-soc-ad193x-objs := ad193x.o | 5 | snd-soc-ad193x-objs := ad193x.o |
| 6 | snd-soc-ad193x-spi-objs := ad193x-spi.o | ||
| 7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o | ||
| 6 | snd-soc-ad1980-objs := ad1980.o | 8 | snd-soc-ad1980-objs := ad1980.o |
| 7 | snd-soc-ad73311-objs := ad73311.o | 9 | snd-soc-ad73311-objs := ad73311.o |
| 8 | snd-soc-adau1701-objs := adau1701.o | 10 | snd-soc-adau1701-objs := adau1701.o |
| 9 | snd-soc-adau1373-objs := adau1373.o | 11 | snd-soc-adau1373-objs := adau1373.o |
| 12 | snd-soc-adau1977-objs := adau1977.o | ||
| 13 | snd-soc-adau1977-spi-objs := adau1977-spi.o | ||
| 14 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o | ||
| 10 | snd-soc-adav80x-objs := adav80x.o | 15 | snd-soc-adav80x-objs := adav80x.o |
| 16 | snd-soc-adav801-objs := adav801.o | ||
| 17 | snd-soc-adav803-objs := adav803.o | ||
| 11 | snd-soc-ads117x-objs := ads117x.o | 18 | snd-soc-ads117x-objs := ads117x.o |
| 12 | snd-soc-ak4104-objs := ak4104.o | 19 | snd-soc-ak4104-objs := ak4104.o |
| 13 | snd-soc-ak4535-objs := ak4535.o | 20 | snd-soc-ak4535-objs := ak4535.o |
| @@ -46,6 +53,9 @@ snd-soc-hdmi-codec-objs := hdmi.o | |||
| 46 | snd-soc-pcm1681-objs := pcm1681.o | 53 | snd-soc-pcm1681-objs := pcm1681.o |
| 47 | snd-soc-pcm1792a-codec-objs := pcm1792a.o | 54 | snd-soc-pcm1792a-codec-objs := pcm1792a.o |
| 48 | snd-soc-pcm3008-objs := pcm3008.o | 55 | snd-soc-pcm3008-objs := pcm3008.o |
| 56 | snd-soc-pcm512x-objs := pcm512x.o | ||
| 57 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | ||
| 58 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | ||
| 49 | snd-soc-rt5631-objs := rt5631.o | 59 | snd-soc-rt5631-objs := rt5631.o |
| 50 | snd-soc-rt5640-objs := rt5640.o | 60 | snd-soc-rt5640-objs := rt5640.o |
| 51 | snd-soc-sgtl5000-objs := sgtl5000.o | 61 | snd-soc-sgtl5000-objs := sgtl5000.o |
| @@ -53,19 +63,24 @@ snd-soc-alc5623-objs := alc5623.o | |||
| 53 | snd-soc-alc5632-objs := alc5632.o | 63 | snd-soc-alc5632-objs := alc5632.o |
| 54 | snd-soc-sigmadsp-objs := sigmadsp.o | 64 | snd-soc-sigmadsp-objs := sigmadsp.o |
| 55 | snd-soc-si476x-objs := si476x.o | 65 | snd-soc-si476x-objs := si476x.o |
| 66 | snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o | ||
| 56 | snd-soc-sn95031-objs := sn95031.o | 67 | snd-soc-sn95031-objs := sn95031.o |
| 57 | snd-soc-spdif-tx-objs := spdif_transmitter.o | 68 | snd-soc-spdif-tx-objs := spdif_transmitter.o |
| 58 | snd-soc-spdif-rx-objs := spdif_receiver.o | 69 | snd-soc-spdif-rx-objs := spdif_receiver.o |
| 59 | snd-soc-ssm2518-objs := ssm2518.o | 70 | snd-soc-ssm2518-objs := ssm2518.o |
| 60 | snd-soc-ssm2602-objs := ssm2602.o | 71 | snd-soc-ssm2602-objs := ssm2602.o |
| 72 | snd-soc-ssm2602-spi-objs := ssm2602-spi.o | ||
| 73 | snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o | ||
| 61 | snd-soc-sta32x-objs := sta32x.o | 74 | snd-soc-sta32x-objs := sta32x.o |
| 62 | snd-soc-sta529-objs := sta529.o | 75 | snd-soc-sta529-objs := sta529.o |
| 63 | snd-soc-stac9766-objs := stac9766.o | 76 | snd-soc-stac9766-objs := stac9766.o |
| 64 | snd-soc-tas5086-objs := tas5086.o | 77 | snd-soc-tas5086-objs := tas5086.o |
| 65 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 78 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
| 79 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | ||
| 80 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | ||
| 66 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 81 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
| 67 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
| 68 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 82 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
| 83 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | ||
| 69 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 84 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
| 70 | snd-soc-twl4030-objs := twl4030.o | 85 | snd-soc-twl4030-objs := twl4030.o |
| 71 | snd-soc-twl6040-objs := twl6040.o | 86 | snd-soc-twl6040-objs := twl6040.o |
| @@ -134,11 +149,18 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o | |||
| 134 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 149 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
| 135 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o | 150 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o |
| 136 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o | 151 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o |
| 152 | obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o | ||
| 153 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o | ||
| 137 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 154 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
| 138 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 155 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
| 139 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o | 156 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o |
| 157 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o | ||
| 158 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o | ||
| 159 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o | ||
| 140 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o | 160 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o |
| 141 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | 161 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o |
| 162 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o | ||
| 163 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o | ||
| 142 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 164 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
| 143 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 165 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
| 144 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 166 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
| @@ -179,6 +201,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o | |||
| 179 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o | 201 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o |
| 180 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o | 202 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o |
| 181 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 203 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
| 204 | obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | ||
| 205 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | ||
| 206 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | ||
| 182 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 207 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
| 183 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 208 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
| 184 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 209 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
| @@ -188,14 +213,18 @@ obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | |||
| 188 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o | 213 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o |
| 189 | obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o | 214 | obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o |
| 190 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 215 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
| 216 | obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o | ||
| 217 | obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o | ||
| 191 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | 218 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o |
| 192 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | 219 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o |
| 193 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 220 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
| 194 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 221 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
| 195 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 222 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
| 223 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | ||
| 224 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | ||
| 196 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 225 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
| 197 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
| 198 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 226 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
| 227 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | ||
| 199 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 228 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
| 200 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o | 229 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o |
| 201 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o | 230 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 77f459868579..685998dd086e 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
| @@ -40,8 +40,8 @@ struct ad1836_priv { | |||
| 40 | */ | 40 | */ |
| 41 | static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; | 41 | static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; |
| 42 | 42 | ||
| 43 | static const struct soc_enum ad1836_deemp_enum = | 43 | static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum, |
| 44 | SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); | 44 | AD1836_DAC_CTRL1, 8, ad1836_deemp); |
| 45 | 45 | ||
| 46 | #define AD1836_DAC_VOLUME(x) \ | 46 | #define AD1836_DAC_VOLUME(x) \ |
| 47 | SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ | 47 | SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ |
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c new file mode 100644 index 000000000000..df3a1a415825 --- /dev/null +++ b/sound/soc/codecs/ad193x-i2c.c | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | /* | ||
| 2 | * AD1936/AD1937 audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "ad193x.h" | ||
| 16 | |||
| 17 | static const struct i2c_device_id ad193x_id[] = { | ||
| 18 | { "ad1936", 0 }, | ||
| 19 | { "ad1937", 0 }, | ||
| 20 | { } | ||
| 21 | }; | ||
| 22 | MODULE_DEVICE_TABLE(i2c, ad193x_id); | ||
| 23 | |||
| 24 | static int ad193x_i2c_probe(struct i2c_client *client, | ||
| 25 | const struct i2c_device_id *id) | ||
| 26 | { | ||
| 27 | struct regmap_config config; | ||
| 28 | |||
| 29 | config = ad193x_regmap_config; | ||
| 30 | config.val_bits = 8; | ||
| 31 | config.reg_bits = 8; | ||
| 32 | |||
| 33 | return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config)); | ||
| 34 | } | ||
| 35 | |||
| 36 | static int ad193x_i2c_remove(struct i2c_client *client) | ||
| 37 | { | ||
| 38 | snd_soc_unregister_codec(&client->dev); | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | static struct i2c_driver ad193x_i2c_driver = { | ||
| 43 | .driver = { | ||
| 44 | .name = "ad193x", | ||
| 45 | }, | ||
| 46 | .probe = ad193x_i2c_probe, | ||
| 47 | .remove = ad193x_i2c_remove, | ||
| 48 | .id_table = ad193x_id, | ||
| 49 | }; | ||
| 50 | module_i2c_driver(ad193x_i2c_driver); | ||
| 51 | |||
| 52 | MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver"); | ||
| 53 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 54 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c new file mode 100644 index 000000000000..390cef9b9dc2 --- /dev/null +++ b/sound/soc/codecs/ad193x-spi.c | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | /* | ||
| 2 | * AD1938/AD1939 audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spi/spi.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "ad193x.h" | ||
| 16 | |||
| 17 | static int ad193x_spi_probe(struct spi_device *spi) | ||
| 18 | { | ||
| 19 | struct regmap_config config; | ||
| 20 | |||
| 21 | config = ad193x_regmap_config; | ||
| 22 | config.val_bits = 8; | ||
| 23 | config.reg_bits = 16; | ||
| 24 | config.read_flag_mask = 0x09; | ||
| 25 | config.write_flag_mask = 0x08; | ||
| 26 | |||
| 27 | return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
| 28 | } | ||
| 29 | |||
| 30 | static int ad193x_spi_remove(struct spi_device *spi) | ||
| 31 | { | ||
| 32 | snd_soc_unregister_codec(&spi->dev); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | static struct spi_driver ad193x_spi_driver = { | ||
| 37 | .driver = { | ||
| 38 | .name = "ad193x", | ||
| 39 | .owner = THIS_MODULE, | ||
| 40 | }, | ||
| 41 | .probe = ad193x_spi_probe, | ||
| 42 | .remove = ad193x_spi_remove, | ||
| 43 | }; | ||
| 44 | module_spi_driver(ad193x_spi_driver); | ||
| 45 | |||
| 46 | MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver"); | ||
| 47 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
| 48 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 5a42dca535b7..9381a767e75f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
| @@ -6,12 +6,10 @@ | |||
| 6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/init.h> | ||
| 10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
| 11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
| 12 | #include <linux/device.h> | 11 | #include <linux/device.h> |
| 13 | #include <linux/i2c.h> | 12 | #include <linux/regmap.h> |
| 14 | #include <linux/spi/spi.h> | ||
| 15 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
| 16 | #include <sound/core.h> | 14 | #include <sound/core.h> |
| 17 | #include <sound/pcm.h> | 15 | #include <sound/pcm.h> |
| @@ -19,6 +17,7 @@ | |||
| 19 | #include <sound/initval.h> | 17 | #include <sound/initval.h> |
| 20 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
| 21 | #include <sound/tlv.h> | 19 | #include <sound/tlv.h> |
| 20 | |||
| 22 | #include "ad193x.h" | 21 | #include "ad193x.h" |
| 23 | 22 | ||
| 24 | /* codec private data */ | 23 | /* codec private data */ |
| @@ -32,8 +31,8 @@ struct ad193x_priv { | |||
| 32 | */ | 31 | */ |
| 33 | static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; | 32 | static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; |
| 34 | 33 | ||
| 35 | static const struct soc_enum ad193x_deemp_enum = | 34 | static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, |
| 36 | SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); | 35 | ad193x_deemp); |
| 37 | 36 | ||
| 38 | static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); | 37 | static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); |
| 39 | 38 | ||
| @@ -320,7 +319,7 @@ static struct snd_soc_dai_driver ad193x_dai = { | |||
| 320 | .ops = &ad193x_dai_ops, | 319 | .ops = &ad193x_dai_ops, |
| 321 | }; | 320 | }; |
| 322 | 321 | ||
| 323 | static int ad193x_probe(struct snd_soc_codec *codec) | 322 | static int ad193x_codec_probe(struct snd_soc_codec *codec) |
| 324 | { | 323 | { |
| 325 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | 324 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); |
| 326 | int ret; | 325 | int ret; |
| @@ -352,7 +351,7 @@ static int ad193x_probe(struct snd_soc_codec *codec) | |||
| 352 | } | 351 | } |
| 353 | 352 | ||
| 354 | static struct snd_soc_codec_driver soc_codec_dev_ad193x = { | 353 | static struct snd_soc_codec_driver soc_codec_dev_ad193x = { |
| 355 | .probe = ad193x_probe, | 354 | .probe = ad193x_codec_probe, |
| 356 | .controls = ad193x_snd_controls, | 355 | .controls = ad193x_snd_controls, |
| 357 | .num_controls = ARRAY_SIZE(ad193x_snd_controls), | 356 | .num_controls = ARRAY_SIZE(ad193x_snd_controls), |
| 358 | .dapm_widgets = ad193x_dapm_widgets, | 357 | .dapm_widgets = ad193x_dapm_widgets, |
| @@ -366,140 +365,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg) | |||
| 366 | return false; | 365 | return false; |
| 367 | } | 366 | } |
| 368 | 367 | ||
| 369 | #if defined(CONFIG_SPI_MASTER) | 368 | const struct regmap_config ad193x_regmap_config = { |
| 370 | |||
| 371 | static const struct regmap_config ad193x_spi_regmap_config = { | ||
| 372 | .val_bits = 8, | ||
| 373 | .reg_bits = 16, | ||
| 374 | .read_flag_mask = 0x09, | ||
| 375 | .write_flag_mask = 0x08, | ||
| 376 | |||
| 377 | .max_register = AD193X_NUM_REGS - 1, | 369 | .max_register = AD193X_NUM_REGS - 1, |
| 378 | .volatile_reg = adau193x_reg_volatile, | 370 | .volatile_reg = adau193x_reg_volatile, |
| 379 | }; | 371 | }; |
| 372 | EXPORT_SYMBOL_GPL(ad193x_regmap_config); | ||
| 380 | 373 | ||
| 381 | static int ad193x_spi_probe(struct spi_device *spi) | 374 | int ad193x_probe(struct device *dev, struct regmap *regmap) |
| 382 | { | 375 | { |
| 383 | struct ad193x_priv *ad193x; | 376 | struct ad193x_priv *ad193x; |
| 384 | 377 | ||
| 385 | ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), | 378 | if (IS_ERR(regmap)) |
| 386 | GFP_KERNEL); | 379 | return PTR_ERR(regmap); |
| 387 | if (ad193x == NULL) | ||
| 388 | return -ENOMEM; | ||
| 389 | |||
| 390 | ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); | ||
| 391 | if (IS_ERR(ad193x->regmap)) | ||
| 392 | return PTR_ERR(ad193x->regmap); | ||
| 393 | |||
| 394 | spi_set_drvdata(spi, ad193x); | ||
| 395 | |||
| 396 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, | ||
| 397 | &ad193x_dai, 1); | ||
| 398 | } | ||
| 399 | |||
| 400 | static int ad193x_spi_remove(struct spi_device *spi) | ||
| 401 | { | ||
| 402 | snd_soc_unregister_codec(&spi->dev); | ||
| 403 | return 0; | ||
| 404 | } | ||
| 405 | |||
| 406 | static struct spi_driver ad193x_spi_driver = { | ||
| 407 | .driver = { | ||
| 408 | .name = "ad193x", | ||
| 409 | .owner = THIS_MODULE, | ||
| 410 | }, | ||
| 411 | .probe = ad193x_spi_probe, | ||
| 412 | .remove = ad193x_spi_remove, | ||
| 413 | }; | ||
| 414 | #endif | ||
| 415 | |||
| 416 | #if IS_ENABLED(CONFIG_I2C) | ||
| 417 | |||
| 418 | static const struct regmap_config ad193x_i2c_regmap_config = { | ||
| 419 | .val_bits = 8, | ||
| 420 | .reg_bits = 8, | ||
| 421 | |||
| 422 | .max_register = AD193X_NUM_REGS - 1, | ||
| 423 | .volatile_reg = adau193x_reg_volatile, | ||
| 424 | }; | ||
| 425 | |||
| 426 | static const struct i2c_device_id ad193x_id[] = { | ||
| 427 | { "ad1936", 0 }, | ||
| 428 | { "ad1937", 0 }, | ||
| 429 | { } | ||
| 430 | }; | ||
| 431 | MODULE_DEVICE_TABLE(i2c, ad193x_id); | ||
| 432 | 380 | ||
| 433 | static int ad193x_i2c_probe(struct i2c_client *client, | 381 | ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL); |
| 434 | const struct i2c_device_id *id) | ||
| 435 | { | ||
| 436 | struct ad193x_priv *ad193x; | ||
| 437 | |||
| 438 | ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), | ||
| 439 | GFP_KERNEL); | ||
| 440 | if (ad193x == NULL) | 382 | if (ad193x == NULL) |
| 441 | return -ENOMEM; | 383 | return -ENOMEM; |
| 442 | 384 | ||
| 443 | ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); | 385 | ad193x->regmap = regmap; |
| 444 | if (IS_ERR(ad193x->regmap)) | ||
| 445 | return PTR_ERR(ad193x->regmap); | ||
| 446 | |||
| 447 | i2c_set_clientdata(client, ad193x); | ||
| 448 | |||
| 449 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, | ||
| 450 | &ad193x_dai, 1); | ||
| 451 | } | ||
| 452 | |||
| 453 | static int ad193x_i2c_remove(struct i2c_client *client) | ||
| 454 | { | ||
| 455 | snd_soc_unregister_codec(&client->dev); | ||
| 456 | return 0; | ||
| 457 | } | ||
| 458 | 386 | ||
| 459 | static struct i2c_driver ad193x_i2c_driver = { | 387 | dev_set_drvdata(dev, ad193x); |
| 460 | .driver = { | ||
| 461 | .name = "ad193x", | ||
| 462 | }, | ||
| 463 | .probe = ad193x_i2c_probe, | ||
| 464 | .remove = ad193x_i2c_remove, | ||
| 465 | .id_table = ad193x_id, | ||
| 466 | }; | ||
| 467 | #endif | ||
| 468 | |||
| 469 | static int __init ad193x_modinit(void) | ||
| 470 | { | ||
| 471 | int ret; | ||
| 472 | |||
| 473 | #if IS_ENABLED(CONFIG_I2C) | ||
| 474 | ret = i2c_add_driver(&ad193x_i2c_driver); | ||
| 475 | if (ret != 0) { | ||
| 476 | printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", | ||
| 477 | ret); | ||
| 478 | } | ||
| 479 | #endif | ||
| 480 | |||
| 481 | #if defined(CONFIG_SPI_MASTER) | ||
| 482 | ret = spi_register_driver(&ad193x_spi_driver); | ||
| 483 | if (ret != 0) { | ||
| 484 | printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", | ||
| 485 | ret); | ||
| 486 | } | ||
| 487 | #endif | ||
| 488 | return ret; | ||
| 489 | } | ||
| 490 | module_init(ad193x_modinit); | ||
| 491 | |||
| 492 | static void __exit ad193x_modexit(void) | ||
| 493 | { | ||
| 494 | #if defined(CONFIG_SPI_MASTER) | ||
| 495 | spi_unregister_driver(&ad193x_spi_driver); | ||
| 496 | #endif | ||
| 497 | 388 | ||
| 498 | #if IS_ENABLED(CONFIG_I2C) | 389 | return snd_soc_register_codec(dev, &soc_codec_dev_ad193x, |
| 499 | i2c_del_driver(&ad193x_i2c_driver); | 390 | &ad193x_dai, 1); |
| 500 | #endif | ||
| 501 | } | 391 | } |
| 502 | module_exit(ad193x_modexit); | 392 | EXPORT_SYMBOL_GPL(ad193x_probe); |
| 503 | 393 | ||
| 504 | MODULE_DESCRIPTION("ASoC ad193x driver"); | 394 | MODULE_DESCRIPTION("ASoC ad193x driver"); |
| 505 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | 395 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); |
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index 473388049992..ab9a998f15be 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h | |||
| @@ -9,6 +9,13 @@ | |||
| 9 | #ifndef __AD193X_H__ | 9 | #ifndef __AD193X_H__ |
| 10 | #define __AD193X_H__ | 10 | #define __AD193X_H__ |
| 11 | 11 | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | |||
| 14 | struct device; | ||
| 15 | |||
| 16 | extern const struct regmap_config ad193x_regmap_config; | ||
| 17 | int ad193x_probe(struct device *dev, struct regmap *regmap); | ||
| 18 | |||
| 12 | #define AD193X_PLL_CLK_CTRL0 0x00 | 19 | #define AD193X_PLL_CLK_CTRL0 0x00 |
| 13 | #define AD193X_PLL_POWERDOWN 0x01 | 20 | #define AD193X_PLL_POWERDOWN 0x01 |
| 14 | #define AD193X_PLL_INPUT_MASK 0x6 | 21 | #define AD193X_PLL_INPUT_MASK 0x6 |
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index eb836ed5271f..5223800775ad 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
| @@ -345,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = { | |||
| 345 | "Channel 5", | 345 | "Channel 5", |
| 346 | }; | 346 | }; |
| 347 | 347 | ||
| 348 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, | 348 | static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, |
| 349 | ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); | 349 | ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); |
| 350 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, | 350 | static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, |
| 351 | ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); | 351 | ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); |
| 352 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, | 352 | static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, |
| 353 | ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); | 353 | ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); |
| 354 | static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, | 354 | static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, |
| 355 | ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); | 355 | ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); |
| 356 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, | 356 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, |
| 357 | ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text); | 357 | ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text); |
| 358 | 358 | ||
| 359 | static const char *adau1373_hpf_cutoff_text[] = { | 359 | static const char *adau1373_hpf_cutoff_text[] = { |
| @@ -362,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = { | |||
| 362 | "800Hz", | 362 | "800Hz", |
| 363 | }; | 363 | }; |
| 364 | 364 | ||
| 365 | static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, | 365 | static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, |
| 366 | ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text); | 366 | ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text); |
| 367 | 367 | ||
| 368 | static const char *adau1373_bass_lpf_cutoff_text[] = { | 368 | static const char *adau1373_bass_lpf_cutoff_text[] = { |
| @@ -388,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = { | |||
| 388 | 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), | 388 | 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), |
| 389 | }; | 389 | }; |
| 390 | 390 | ||
| 391 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, | 391 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, |
| 392 | ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); | 392 | ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); |
| 393 | 393 | ||
| 394 | static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, | 394 | static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, |
| 395 | ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text, | 395 | ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text, |
| 396 | adau1373_bass_clip_level_values); | 396 | adau1373_bass_clip_level_values); |
| 397 | 397 | ||
| 398 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, | 398 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, |
| 399 | ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text); | 399 | ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text); |
| 400 | 400 | ||
| 401 | static const char *adau1373_3d_level_text[] = { | 401 | static const char *adau1373_3d_level_text[] = { |
| @@ -409,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = { | |||
| 409 | "0.16875 fs", "0.27083 fs" | 409 | "0.16875 fs", "0.27083 fs" |
| 410 | }; | 410 | }; |
| 411 | 411 | ||
| 412 | static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, | 412 | static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, |
| 413 | ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); | 413 | ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); |
| 414 | static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, | 414 | static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, |
| 415 | ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); | 415 | ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); |
| 416 | 416 | ||
| 417 | static const unsigned int adau1373_3d_tlv[] = { | 417 | static const unsigned int adau1373_3d_tlv[] = { |
| @@ -427,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = { | |||
| 427 | "Stereo", | 427 | "Stereo", |
| 428 | }; | 428 | }; |
| 429 | 429 | ||
| 430 | static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, | 430 | static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, |
| 431 | ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); | 431 | ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); |
| 432 | static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, | 432 | static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, |
| 433 | ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); | 433 | ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); |
| 434 | static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, | 434 | static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, |
| 435 | ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text); | 435 | ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text); |
| 436 | 436 | ||
| 437 | static const struct snd_kcontrol_new adau1373_controls[] = { | 437 | static const struct snd_kcontrol_new adau1373_controls[] = { |
| @@ -576,8 +576,8 @@ static const char *adau1373_decimator_text[] = { | |||
| 576 | "DMIC1", | 576 | "DMIC1", |
| 577 | }; | 577 | }; |
| 578 | 578 | ||
| 579 | static const struct soc_enum adau1373_decimator_enum = | 579 | static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum, |
| 580 | SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text); | 580 | adau1373_decimator_text); |
| 581 | 581 | ||
| 582 | static const struct snd_kcontrol_new adau1373_decimator_mux = | 582 | static const struct snd_kcontrol_new adau1373_decimator_mux = |
| 583 | SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); | 583 | SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); |
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c new file mode 100644 index 000000000000..9700e8c838c9 --- /dev/null +++ b/sound/soc/codecs/adau1977-i2c.c | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 6 | * | ||
| 7 | * Licensed under the GPL-2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/mod_devicetable.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/regmap.h> | ||
| 14 | #include <sound/soc.h> | ||
| 15 | |||
| 16 | #include "adau1977.h" | ||
| 17 | |||
| 18 | static int adau1977_i2c_probe(struct i2c_client *client, | ||
| 19 | const struct i2c_device_id *id) | ||
| 20 | { | ||
| 21 | struct regmap_config config; | ||
| 22 | |||
| 23 | config = adau1977_regmap_config; | ||
| 24 | config.val_bits = 8; | ||
| 25 | config.reg_bits = 8; | ||
| 26 | |||
| 27 | return adau1977_probe(&client->dev, | ||
| 28 | devm_regmap_init_i2c(client, &config), | ||
| 29 | id->driver_data, NULL); | ||
| 30 | } | ||
| 31 | |||
| 32 | static int adau1977_i2c_remove(struct i2c_client *client) | ||
| 33 | { | ||
| 34 | snd_soc_unregister_codec(&client->dev); | ||
| 35 | return 0; | ||
| 36 | } | ||
| 37 | |||
| 38 | static const struct i2c_device_id adau1977_i2c_ids[] = { | ||
| 39 | { "adau1977", ADAU1977 }, | ||
| 40 | { "adau1978", ADAU1978 }, | ||
| 41 | { "adau1979", ADAU1978 }, | ||
| 42 | { } | ||
| 43 | }; | ||
| 44 | MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); | ||
| 45 | |||
| 46 | static struct i2c_driver adau1977_i2c_driver = { | ||
| 47 | .driver = { | ||
| 48 | .name = "adau1977", | ||
| 49 | .owner = THIS_MODULE, | ||
| 50 | }, | ||
| 51 | .probe = adau1977_i2c_probe, | ||
| 52 | .remove = adau1977_i2c_remove, | ||
| 53 | .id_table = adau1977_i2c_ids, | ||
| 54 | }; | ||
| 55 | module_i2c_driver(adau1977_i2c_driver); | ||
| 56 | |||
| 57 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
| 58 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 59 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c new file mode 100644 index 000000000000..b05cf5da3a94 --- /dev/null +++ b/sound/soc/codecs/adau1977-spi.c | |||
| @@ -0,0 +1,76 @@ | |||
| 1 | /* | ||
| 2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 6 | * | ||
| 7 | * Licensed under the GPL-2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/mod_devicetable.h> | ||
| 11 | #include <linux/module.h> | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | #include <linux/spi/spi.h> | ||
| 14 | #include <sound/soc.h> | ||
| 15 | |||
| 16 | #include "adau1977.h" | ||
| 17 | |||
| 18 | static void adau1977_spi_switch_mode(struct device *dev) | ||
| 19 | { | ||
| 20 | struct spi_device *spi = to_spi_device(dev); | ||
| 21 | |||
| 22 | /* | ||
| 23 | * To get the device into SPI mode CLATCH has to be pulled low three | ||
| 24 | * times. Do this by issuing three dummy reads. | ||
| 25 | */ | ||
| 26 | spi_w8r8(spi, 0x00); | ||
| 27 | spi_w8r8(spi, 0x00); | ||
| 28 | spi_w8r8(spi, 0x00); | ||
| 29 | } | ||
| 30 | |||
| 31 | static int adau1977_spi_probe(struct spi_device *spi) | ||
| 32 | { | ||
| 33 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
| 34 | struct regmap_config config; | ||
| 35 | |||
| 36 | if (!id) | ||
| 37 | return -EINVAL; | ||
| 38 | |||
| 39 | config = adau1977_regmap_config; | ||
| 40 | config.val_bits = 8; | ||
| 41 | config.reg_bits = 16; | ||
| 42 | config.read_flag_mask = 0x1; | ||
| 43 | |||
| 44 | return adau1977_probe(&spi->dev, | ||
| 45 | devm_regmap_init_spi(spi, &config), | ||
| 46 | id->driver_data, adau1977_spi_switch_mode); | ||
| 47 | } | ||
| 48 | |||
| 49 | static int adau1977_spi_remove(struct spi_device *spi) | ||
| 50 | { | ||
| 51 | snd_soc_unregister_codec(&spi->dev); | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | static const struct spi_device_id adau1977_spi_ids[] = { | ||
| 56 | { "adau1977", ADAU1977 }, | ||
| 57 | { "adau1978", ADAU1978 }, | ||
| 58 | { "adau1979", ADAU1978 }, | ||
| 59 | { } | ||
| 60 | }; | ||
| 61 | MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); | ||
| 62 | |||
| 63 | static struct spi_driver adau1977_spi_driver = { | ||
| 64 | .driver = { | ||
| 65 | .name = "adau1977", | ||
| 66 | .owner = THIS_MODULE, | ||
| 67 | }, | ||
| 68 | .probe = adau1977_spi_probe, | ||
| 69 | .remove = adau1977_spi_remove, | ||
| 70 | .id_table = adau1977_spi_ids, | ||
| 71 | }; | ||
| 72 | module_spi_driver(adau1977_spi_driver); | ||
| 73 | |||
| 74 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
| 75 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 76 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c new file mode 100644 index 000000000000..fd55da7cb9d4 --- /dev/null +++ b/sound/soc/codecs/adau1977.c | |||
| @@ -0,0 +1,1018 @@ | |||
| 1 | /* | ||
| 2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 6 | * | ||
| 7 | * Licensed under the GPL-2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/delay.h> | ||
| 11 | #include <linux/device.h> | ||
| 12 | #include <linux/gpio/consumer.h> | ||
| 13 | #include <linux/i2c.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/platform_data/adau1977.h> | ||
| 17 | #include <linux/regmap.h> | ||
| 18 | #include <linux/regulator/consumer.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | |||
| 21 | #include <sound/core.h> | ||
| 22 | #include <sound/initval.h> | ||
| 23 | #include <sound/pcm.h> | ||
| 24 | #include <sound/pcm_params.h> | ||
| 25 | #include <sound/soc.h> | ||
| 26 | #include <sound/tlv.h> | ||
| 27 | |||
| 28 | #include "adau1977.h" | ||
| 29 | |||
| 30 | #define ADAU1977_REG_POWER 0x00 | ||
| 31 | #define ADAU1977_REG_PLL 0x01 | ||
| 32 | #define ADAU1977_REG_BOOST 0x02 | ||
| 33 | #define ADAU1977_REG_MICBIAS 0x03 | ||
| 34 | #define ADAU1977_REG_BLOCK_POWER_SAI 0x04 | ||
| 35 | #define ADAU1977_REG_SAI_CTRL0 0x05 | ||
| 36 | #define ADAU1977_REG_SAI_CTRL1 0x06 | ||
| 37 | #define ADAU1977_REG_CMAP12 0x07 | ||
| 38 | #define ADAU1977_REG_CMAP34 0x08 | ||
| 39 | #define ADAU1977_REG_SAI_OVERTEMP 0x09 | ||
| 40 | #define ADAU1977_REG_POST_ADC_GAIN(x) (0x0a + (x)) | ||
| 41 | #define ADAU1977_REG_MISC_CONTROL 0x0e | ||
| 42 | #define ADAU1977_REG_DIAG_CONTROL 0x10 | ||
| 43 | #define ADAU1977_REG_STATUS(x) (0x11 + (x)) | ||
| 44 | #define ADAU1977_REG_DIAG_IRQ1 0x15 | ||
| 45 | #define ADAU1977_REG_DIAG_IRQ2 0x16 | ||
| 46 | #define ADAU1977_REG_ADJUST1 0x17 | ||
| 47 | #define ADAU1977_REG_ADJUST2 0x18 | ||
| 48 | #define ADAU1977_REG_ADC_CLIP 0x19 | ||
| 49 | #define ADAU1977_REG_DC_HPF_CAL 0x1a | ||
| 50 | |||
| 51 | #define ADAU1977_POWER_RESET BIT(7) | ||
| 52 | #define ADAU1977_POWER_PWUP BIT(0) | ||
| 53 | |||
| 54 | #define ADAU1977_PLL_CLK_S BIT(4) | ||
| 55 | #define ADAU1977_PLL_MCS_MASK 0x7 | ||
| 56 | |||
| 57 | #define ADAU1977_MICBIAS_MB_VOLTS_MASK 0xf0 | ||
| 58 | #define ADAU1977_MICBIAS_MB_VOLTS_OFFSET 4 | ||
| 59 | |||
| 60 | #define ADAU1977_BLOCK_POWER_SAI_LR_POL BIT(7) | ||
| 61 | #define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE BIT(6) | ||
| 62 | #define ADAU1977_BLOCK_POWER_SAI_LDO_EN BIT(5) | ||
| 63 | |||
| 64 | #define ADAU1977_SAI_CTRL0_FMT_MASK (0x3 << 6) | ||
| 65 | #define ADAU1977_SAI_CTRL0_FMT_I2S (0x0 << 6) | ||
| 66 | #define ADAU1977_SAI_CTRL0_FMT_LJ (0x1 << 6) | ||
| 67 | #define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT (0x2 << 6) | ||
| 68 | #define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT (0x3 << 6) | ||
| 69 | |||
| 70 | #define ADAU1977_SAI_CTRL0_SAI_MASK (0x7 << 3) | ||
| 71 | #define ADAU1977_SAI_CTRL0_SAI_I2S (0x0 << 3) | ||
| 72 | #define ADAU1977_SAI_CTRL0_SAI_TDM_2 (0x1 << 3) | ||
| 73 | #define ADAU1977_SAI_CTRL0_SAI_TDM_4 (0x2 << 3) | ||
| 74 | #define ADAU1977_SAI_CTRL0_SAI_TDM_8 (0x3 << 3) | ||
| 75 | #define ADAU1977_SAI_CTRL0_SAI_TDM_16 (0x4 << 3) | ||
| 76 | |||
| 77 | #define ADAU1977_SAI_CTRL0_FS_MASK (0x7) | ||
| 78 | #define ADAU1977_SAI_CTRL0_FS_8000_12000 (0x0) | ||
| 79 | #define ADAU1977_SAI_CTRL0_FS_16000_24000 (0x1) | ||
| 80 | #define ADAU1977_SAI_CTRL0_FS_32000_48000 (0x2) | ||
| 81 | #define ADAU1977_SAI_CTRL0_FS_64000_96000 (0x3) | ||
| 82 | #define ADAU1977_SAI_CTRL0_FS_128000_192000 (0x4) | ||
| 83 | |||
| 84 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK (0x3 << 5) | ||
| 85 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32 (0x0 << 5) | ||
| 86 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24 (0x1 << 5) | ||
| 87 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16 (0x2 << 5) | ||
| 88 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK (0x1 << 4) | ||
| 89 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT (0x1 << 4) | ||
| 90 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT (0x0 << 4) | ||
| 91 | #define ADAU1977_SAI_CTRL1_LRCLK_PULSE BIT(3) | ||
| 92 | #define ADAU1977_SAI_CTRL1_MSB BIT(2) | ||
| 93 | #define ADAU1977_SAI_CTRL1_BCLKRATE_16 (0x1 << 1) | ||
| 94 | #define ADAU1977_SAI_CTRL1_BCLKRATE_32 (0x0 << 1) | ||
| 95 | #define ADAU1977_SAI_CTRL1_BCLKRATE_MASK (0x1 << 1) | ||
| 96 | #define ADAU1977_SAI_CTRL1_MASTER BIT(0) | ||
| 97 | |||
| 98 | #define ADAU1977_SAI_OVERTEMP_DRV_C(x) BIT(4 + (x)) | ||
| 99 | #define ADAU1977_SAI_OVERTEMP_DRV_HIZ BIT(3) | ||
| 100 | |||
| 101 | #define ADAU1977_MISC_CONTROL_SUM_MODE_MASK (0x3 << 6) | ||
| 102 | #define ADAU1977_MISC_CONTROL_SUM_MODE_1CH (0x2 << 6) | ||
| 103 | #define ADAU1977_MISC_CONTROL_SUM_MODE_2CH (0x1 << 6) | ||
| 104 | #define ADAU1977_MISC_CONTROL_SUM_MODE_4CH (0x0 << 6) | ||
| 105 | #define ADAU1977_MISC_CONTROL_MMUTE BIT(4) | ||
| 106 | #define ADAU1977_MISC_CONTROL_DC_CAL BIT(0) | ||
| 107 | |||
| 108 | #define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET 4 | ||
| 109 | #define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET 0 | ||
| 110 | |||
| 111 | struct adau1977 { | ||
| 112 | struct regmap *regmap; | ||
| 113 | bool right_j; | ||
| 114 | unsigned int sysclk; | ||
| 115 | enum adau1977_sysclk_src sysclk_src; | ||
| 116 | struct gpio_desc *reset_gpio; | ||
| 117 | enum adau1977_type type; | ||
| 118 | |||
| 119 | struct regulator *avdd_reg; | ||
| 120 | struct regulator *dvdd_reg; | ||
| 121 | |||
| 122 | struct snd_pcm_hw_constraint_list constraints; | ||
| 123 | |||
| 124 | struct device *dev; | ||
| 125 | void (*switch_mode)(struct device *dev); | ||
| 126 | |||
| 127 | unsigned int max_master_fs; | ||
| 128 | unsigned int slot_width; | ||
| 129 | bool enabled; | ||
| 130 | bool master; | ||
| 131 | }; | ||
| 132 | |||
| 133 | static const struct reg_default adau1977_reg_defaults[] = { | ||
| 134 | { 0x00, 0x00 }, | ||
| 135 | { 0x01, 0x41 }, | ||
| 136 | { 0x02, 0x4a }, | ||
| 137 | { 0x03, 0x7d }, | ||
| 138 | { 0x04, 0x3d }, | ||
| 139 | { 0x05, 0x02 }, | ||
| 140 | { 0x06, 0x00 }, | ||
| 141 | { 0x07, 0x10 }, | ||
| 142 | { 0x08, 0x32 }, | ||
| 143 | { 0x09, 0xf0 }, | ||
| 144 | { 0x0a, 0xa0 }, | ||
| 145 | { 0x0b, 0xa0 }, | ||
| 146 | { 0x0c, 0xa0 }, | ||
| 147 | { 0x0d, 0xa0 }, | ||
| 148 | { 0x0e, 0x02 }, | ||
| 149 | { 0x10, 0x0f }, | ||
| 150 | { 0x15, 0x20 }, | ||
| 151 | { 0x16, 0x00 }, | ||
| 152 | { 0x17, 0x00 }, | ||
| 153 | { 0x18, 0x00 }, | ||
| 154 | { 0x1a, 0x00 }, | ||
| 155 | }; | ||
| 156 | |||
| 157 | static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000); | ||
| 158 | |||
| 159 | static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = { | ||
| 160 | SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS, | ||
| 161 | 3, 0, NULL, 0) | ||
| 162 | }; | ||
| 163 | |||
| 164 | static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = { | ||
| 165 | SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI, | ||
| 166 | 4, 0, NULL, 0), | ||
| 167 | |||
| 168 | SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0), | ||
| 169 | SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0), | ||
| 170 | SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0), | ||
| 171 | SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0), | ||
| 172 | |||
| 173 | SND_SOC_DAPM_INPUT("AIN1"), | ||
| 174 | SND_SOC_DAPM_INPUT("AIN2"), | ||
| 175 | SND_SOC_DAPM_INPUT("AIN3"), | ||
| 176 | SND_SOC_DAPM_INPUT("AIN4"), | ||
| 177 | |||
| 178 | SND_SOC_DAPM_OUTPUT("VREF"), | ||
| 179 | }; | ||
| 180 | |||
| 181 | static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { | ||
| 182 | { "ADC1", NULL, "AIN1" }, | ||
| 183 | { "ADC2", NULL, "AIN2" }, | ||
| 184 | { "ADC3", NULL, "AIN3" }, | ||
| 185 | { "ADC4", NULL, "AIN4" }, | ||
| 186 | |||
| 187 | { "ADC1", NULL, "Vref" }, | ||
| 188 | { "ADC2", NULL, "Vref" }, | ||
| 189 | { "ADC3", NULL, "Vref" }, | ||
| 190 | { "ADC4", NULL, "Vref" }, | ||
| 191 | |||
| 192 | { "VREF", NULL, "Vref" }, | ||
| 193 | }; | ||
| 194 | |||
| 195 | #define ADAU1977_VOLUME(x) \ | ||
| 196 | SOC_SINGLE_TLV("ADC" #x " Capture Volume", \ | ||
| 197 | ADAU1977_REG_POST_ADC_GAIN((x) - 1), \ | ||
| 198 | 0, 255, 1, adau1977_adc_gain) | ||
| 199 | |||
| 200 | #define ADAU1977_HPF_SWITCH(x) \ | ||
| 201 | SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \ | ||
| 202 | ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) | ||
| 203 | |||
| 204 | #define ADAU1977_DC_SUB_SWITCH(x) \ | ||
| 205 | SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ | ||
| 206 | ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) | ||
| 207 | |||
| 208 | static const struct snd_kcontrol_new adau1977_snd_controls[] = { | ||
| 209 | ADAU1977_VOLUME(1), | ||
| 210 | ADAU1977_VOLUME(2), | ||
| 211 | ADAU1977_VOLUME(3), | ||
| 212 | ADAU1977_VOLUME(4), | ||
| 213 | |||
| 214 | ADAU1977_HPF_SWITCH(1), | ||
| 215 | ADAU1977_HPF_SWITCH(2), | ||
| 216 | ADAU1977_HPF_SWITCH(3), | ||
| 217 | ADAU1977_HPF_SWITCH(4), | ||
| 218 | |||
| 219 | ADAU1977_DC_SUB_SWITCH(1), | ||
| 220 | ADAU1977_DC_SUB_SWITCH(2), | ||
| 221 | ADAU1977_DC_SUB_SWITCH(3), | ||
| 222 | ADAU1977_DC_SUB_SWITCH(4), | ||
| 223 | }; | ||
| 224 | |||
| 225 | static int adau1977_reset(struct adau1977 *adau1977) | ||
| 226 | { | ||
| 227 | int ret; | ||
| 228 | |||
| 229 | /* | ||
| 230 | * The reset bit is obviously volatile, but we need to be able to cache | ||
| 231 | * the other bits in the register, so we can't just mark the whole | ||
| 232 | * register as volatile. Since this is the only place where we'll ever | ||
| 233 | * touch the reset bit just bypass the cache for this operation. | ||
| 234 | */ | ||
| 235 | regcache_cache_bypass(adau1977->regmap, true); | ||
| 236 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, | ||
| 237 | ADAU1977_POWER_RESET); | ||
| 238 | regcache_cache_bypass(adau1977->regmap, false); | ||
| 239 | if (ret) | ||
| 240 | return ret; | ||
| 241 | |||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | /* | ||
| 246 | * Returns the appropriate setting for ths FS field in the CTRL0 register | ||
| 247 | * depending on the rate. | ||
| 248 | */ | ||
| 249 | static int adau1977_lookup_fs(unsigned int rate) | ||
| 250 | { | ||
| 251 | if (rate >= 8000 && rate <= 12000) | ||
| 252 | return ADAU1977_SAI_CTRL0_FS_8000_12000; | ||
| 253 | else if (rate >= 16000 && rate <= 24000) | ||
| 254 | return ADAU1977_SAI_CTRL0_FS_16000_24000; | ||
| 255 | else if (rate >= 32000 && rate <= 48000) | ||
| 256 | return ADAU1977_SAI_CTRL0_FS_32000_48000; | ||
| 257 | else if (rate >= 64000 && rate <= 96000) | ||
| 258 | return ADAU1977_SAI_CTRL0_FS_64000_96000; | ||
| 259 | else if (rate >= 128000 && rate <= 192000) | ||
| 260 | return ADAU1977_SAI_CTRL0_FS_128000_192000; | ||
| 261 | else | ||
| 262 | return -EINVAL; | ||
| 263 | } | ||
| 264 | |||
| 265 | static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate, | ||
| 266 | unsigned int fs) | ||
| 267 | { | ||
| 268 | unsigned int mcs; | ||
| 269 | |||
| 270 | /* | ||
| 271 | * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs | ||
| 272 | * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs | ||
| 273 | * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate) | ||
| 274 | */ | ||
| 275 | |||
| 276 | rate *= 512 >> fs; | ||
| 277 | |||
| 278 | if (adau1977->sysclk % rate != 0) | ||
| 279 | return -EINVAL; | ||
| 280 | |||
| 281 | mcs = adau1977->sysclk / rate; | ||
| 282 | |||
| 283 | /* The factors configured by MCS are 1, 2, 3, 4, 6 */ | ||
| 284 | if (mcs < 1 || mcs > 6 || mcs == 5) | ||
| 285 | return -EINVAL; | ||
| 286 | |||
| 287 | mcs = mcs - 1; | ||
| 288 | if (mcs == 5) | ||
| 289 | mcs = 4; | ||
| 290 | |||
| 291 | return mcs; | ||
| 292 | } | ||
| 293 | |||
| 294 | static int adau1977_hw_params(struct snd_pcm_substream *substream, | ||
| 295 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
| 296 | { | ||
| 297 | struct snd_soc_codec *codec = dai->codec; | ||
| 298 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
| 299 | unsigned int rate = params_rate(params); | ||
| 300 | unsigned int slot_width; | ||
| 301 | unsigned int ctrl0, ctrl0_mask; | ||
| 302 | unsigned int ctrl1; | ||
| 303 | int mcs, fs; | ||
| 304 | int ret; | ||
| 305 | |||
| 306 | fs = adau1977_lookup_fs(rate); | ||
| 307 | if (fs < 0) | ||
| 308 | return fs; | ||
| 309 | |||
| 310 | if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) { | ||
| 311 | mcs = adau1977_lookup_mcs(adau1977, rate, fs); | ||
| 312 | if (mcs < 0) | ||
| 313 | return mcs; | ||
| 314 | } else { | ||
| 315 | mcs = 0; | ||
| 316 | } | ||
| 317 | |||
| 318 | ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK; | ||
| 319 | ctrl0 = fs; | ||
| 320 | |||
| 321 | if (adau1977->right_j) { | ||
| 322 | switch (params_width(params)) { | ||
| 323 | case 16: | ||
| 324 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT; | ||
| 325 | break; | ||
| 326 | case 24: | ||
| 327 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; | ||
| 328 | break; | ||
| 329 | default: | ||
| 330 | return -EINVAL; | ||
| 331 | } | ||
| 332 | ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (adau1977->master) { | ||
| 336 | switch (params_width(params)) { | ||
| 337 | case 16: | ||
| 338 | ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; | ||
| 339 | slot_width = 16; | ||
| 340 | break; | ||
| 341 | case 24: | ||
| 342 | case 32: | ||
| 343 | ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT; | ||
| 344 | slot_width = 32; | ||
| 345 | break; | ||
| 346 | default: | ||
| 347 | return -EINVAL; | ||
| 348 | } | ||
| 349 | |||
| 350 | /* In TDM mode there is a fixed slot width */ | ||
| 351 | if (adau1977->slot_width) | ||
| 352 | slot_width = adau1977->slot_width; | ||
| 353 | |||
| 354 | if (slot_width == 16) | ||
| 355 | ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16; | ||
| 356 | else | ||
| 357 | ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32; | ||
| 358 | |||
| 359 | ret = regmap_update_bits(adau1977->regmap, | ||
| 360 | ADAU1977_REG_SAI_CTRL1, | ||
| 361 | ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK | | ||
| 362 | ADAU1977_SAI_CTRL1_BCLKRATE_MASK, | ||
| 363 | ctrl1); | ||
| 364 | if (ret < 0) | ||
| 365 | return ret; | ||
| 366 | } | ||
| 367 | |||
| 368 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
| 369 | ctrl0_mask, ctrl0); | ||
| 370 | if (ret < 0) | ||
| 371 | return ret; | ||
| 372 | |||
| 373 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, | ||
| 374 | ADAU1977_PLL_MCS_MASK, mcs); | ||
| 375 | } | ||
| 376 | |||
| 377 | static int adau1977_power_disable(struct adau1977 *adau1977) | ||
| 378 | { | ||
| 379 | int ret = 0; | ||
| 380 | |||
| 381 | if (!adau1977->enabled) | ||
| 382 | return 0; | ||
| 383 | |||
| 384 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, | ||
| 385 | ADAU1977_POWER_PWUP, 0); | ||
| 386 | if (ret) | ||
| 387 | return ret; | ||
| 388 | |||
| 389 | regcache_mark_dirty(adau1977->regmap); | ||
| 390 | |||
| 391 | if (adau1977->reset_gpio) | ||
| 392 | gpiod_set_value_cansleep(adau1977->reset_gpio, 0); | ||
| 393 | |||
| 394 | regcache_cache_only(adau1977->regmap, true); | ||
| 395 | |||
| 396 | regulator_disable(adau1977->avdd_reg); | ||
| 397 | if (adau1977->dvdd_reg) | ||
| 398 | regulator_disable(adau1977->dvdd_reg); | ||
| 399 | |||
| 400 | adau1977->enabled = false; | ||
| 401 | |||
| 402 | return 0; | ||
| 403 | } | ||
| 404 | |||
| 405 | static int adau1977_power_enable(struct adau1977 *adau1977) | ||
| 406 | { | ||
| 407 | unsigned int val; | ||
| 408 | int ret = 0; | ||
| 409 | |||
| 410 | if (adau1977->enabled) | ||
| 411 | return 0; | ||
| 412 | |||
| 413 | ret = regulator_enable(adau1977->avdd_reg); | ||
| 414 | if (ret) | ||
| 415 | return ret; | ||
| 416 | |||
| 417 | if (adau1977->dvdd_reg) { | ||
| 418 | ret = regulator_enable(adau1977->dvdd_reg); | ||
| 419 | if (ret) | ||
| 420 | goto err_disable_avdd; | ||
| 421 | } | ||
| 422 | |||
| 423 | if (adau1977->reset_gpio) | ||
| 424 | gpiod_set_value_cansleep(adau1977->reset_gpio, 1); | ||
| 425 | |||
| 426 | regcache_cache_only(adau1977->regmap, false); | ||
| 427 | |||
| 428 | if (adau1977->switch_mode) | ||
| 429 | adau1977->switch_mode(adau1977->dev); | ||
| 430 | |||
| 431 | ret = adau1977_reset(adau1977); | ||
| 432 | if (ret) | ||
| 433 | goto err_disable_dvdd; | ||
| 434 | |||
| 435 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, | ||
| 436 | ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP); | ||
| 437 | if (ret) | ||
| 438 | goto err_disable_dvdd; | ||
| 439 | |||
| 440 | ret = regcache_sync(adau1977->regmap); | ||
| 441 | if (ret) | ||
| 442 | goto err_disable_dvdd; | ||
| 443 | |||
| 444 | /* | ||
| 445 | * The PLL register is not affected by the software reset. It is | ||
| 446 | * possible that the value of the register was changed to the | ||
| 447 | * default value while we were in cache only mode. In this case | ||
| 448 | * regcache_sync will skip over it and we have to manually sync | ||
| 449 | * it. | ||
| 450 | */ | ||
| 451 | ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val); | ||
| 452 | if (ret) | ||
| 453 | goto err_disable_dvdd; | ||
| 454 | |||
| 455 | if (val == 0x41) { | ||
| 456 | regcache_cache_bypass(adau1977->regmap, true); | ||
| 457 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL, | ||
| 458 | 0x41); | ||
| 459 | if (ret) | ||
| 460 | goto err_disable_dvdd; | ||
| 461 | regcache_cache_bypass(adau1977->regmap, false); | ||
| 462 | } | ||
| 463 | |||
| 464 | adau1977->enabled = true; | ||
| 465 | |||
| 466 | return ret; | ||
| 467 | |||
| 468 | err_disable_dvdd: | ||
| 469 | if (adau1977->dvdd_reg) | ||
| 470 | regulator_disable(adau1977->dvdd_reg); | ||
| 471 | err_disable_avdd: | ||
| 472 | regulator_disable(adau1977->avdd_reg); | ||
| 473 | return ret; | ||
| 474 | } | ||
| 475 | |||
| 476 | static int adau1977_set_bias_level(struct snd_soc_codec *codec, | ||
| 477 | enum snd_soc_bias_level level) | ||
| 478 | { | ||
| 479 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
| 480 | int ret = 0; | ||
| 481 | |||
| 482 | switch (level) { | ||
| 483 | case SND_SOC_BIAS_ON: | ||
| 484 | break; | ||
| 485 | case SND_SOC_BIAS_PREPARE: | ||
| 486 | break; | ||
| 487 | case SND_SOC_BIAS_STANDBY: | ||
| 488 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
| 489 | ret = adau1977_power_enable(adau1977); | ||
| 490 | break; | ||
| 491 | case SND_SOC_BIAS_OFF: | ||
| 492 | ret = adau1977_power_disable(adau1977); | ||
| 493 | break; | ||
| 494 | } | ||
| 495 | |||
| 496 | if (ret) | ||
| 497 | return ret; | ||
| 498 | |||
| 499 | codec->dapm.bias_level = level; | ||
| 500 | |||
| 501 | return 0; | ||
| 502 | } | ||
| 503 | |||
| 504 | static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
| 505 | unsigned int rx_mask, int slots, int width) | ||
| 506 | { | ||
| 507 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
| 508 | unsigned int ctrl0, ctrl1, drv; | ||
| 509 | unsigned int slot[4]; | ||
| 510 | unsigned int i; | ||
| 511 | int ret; | ||
| 512 | |||
| 513 | if (slots == 0) { | ||
| 514 | /* 0 = No fixed slot width */ | ||
| 515 | adau1977->slot_width = 0; | ||
| 516 | adau1977->max_master_fs = 192000; | ||
| 517 | return regmap_update_bits(adau1977->regmap, | ||
| 518 | ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, | ||
| 519 | ADAU1977_SAI_CTRL0_SAI_I2S); | ||
| 520 | } | ||
| 521 | |||
| 522 | if (rx_mask == 0 || tx_mask != 0) | ||
| 523 | return -EINVAL; | ||
| 524 | |||
| 525 | drv = 0; | ||
| 526 | for (i = 0; i < 4; i++) { | ||
| 527 | slot[i] = __ffs(rx_mask); | ||
| 528 | drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i); | ||
| 529 | rx_mask &= ~(1 << slot[i]); | ||
| 530 | if (slot[i] >= slots) | ||
| 531 | return -EINVAL; | ||
| 532 | if (rx_mask == 0) | ||
| 533 | break; | ||
| 534 | } | ||
| 535 | |||
| 536 | if (rx_mask != 0) | ||
| 537 | return -EINVAL; | ||
| 538 | |||
| 539 | switch (width) { | ||
| 540 | case 16: | ||
| 541 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16; | ||
| 542 | break; | ||
| 543 | case 24: | ||
| 544 | /* We can only generate 16 bit or 32 bit wide slots */ | ||
| 545 | if (adau1977->master) | ||
| 546 | return -EINVAL; | ||
| 547 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; | ||
| 548 | break; | ||
| 549 | case 32: | ||
| 550 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32; | ||
| 551 | break; | ||
| 552 | default: | ||
| 553 | return -EINVAL; | ||
| 554 | } | ||
| 555 | |||
| 556 | switch (slots) { | ||
| 557 | case 2: | ||
| 558 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2; | ||
| 559 | break; | ||
| 560 | case 4: | ||
| 561 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4; | ||
| 562 | break; | ||
| 563 | case 8: | ||
| 564 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8; | ||
| 565 | break; | ||
| 566 | case 16: | ||
| 567 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16; | ||
| 568 | break; | ||
| 569 | default: | ||
| 570 | return -EINVAL; | ||
| 571 | } | ||
| 572 | |||
| 573 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, | ||
| 574 | ADAU1977_SAI_OVERTEMP_DRV_C(0) | | ||
| 575 | ADAU1977_SAI_OVERTEMP_DRV_C(1) | | ||
| 576 | ADAU1977_SAI_OVERTEMP_DRV_C(2) | | ||
| 577 | ADAU1977_SAI_OVERTEMP_DRV_C(3), drv); | ||
| 578 | if (ret) | ||
| 579 | return ret; | ||
| 580 | |||
| 581 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12, | ||
| 582 | (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | | ||
| 583 | (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); | ||
| 584 | if (ret) | ||
| 585 | return ret; | ||
| 586 | |||
| 587 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34, | ||
| 588 | (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | | ||
| 589 | (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); | ||
| 590 | if (ret) | ||
| 591 | return ret; | ||
| 592 | |||
| 593 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
| 594 | ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0); | ||
| 595 | if (ret) | ||
| 596 | return ret; | ||
| 597 | |||
| 598 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, | ||
| 599 | ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1); | ||
| 600 | if (ret) | ||
| 601 | return ret; | ||
| 602 | |||
| 603 | adau1977->slot_width = width; | ||
| 604 | |||
| 605 | /* In master mode the maximum bitclock is 24.576 MHz */ | ||
| 606 | adau1977->max_master_fs = min(192000, 24576000 / width / slots); | ||
| 607 | |||
| 608 | return 0; | ||
| 609 | } | ||
| 610 | |||
| 611 | static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream) | ||
| 612 | { | ||
| 613 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
| 614 | unsigned int val; | ||
| 615 | |||
| 616 | if (mute) | ||
| 617 | val = ADAU1977_MISC_CONTROL_MMUTE; | ||
| 618 | else | ||
| 619 | val = 0; | ||
| 620 | |||
| 621 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL, | ||
| 622 | ADAU1977_MISC_CONTROL_MMUTE, val); | ||
| 623 | } | ||
| 624 | |||
| 625 | static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
| 626 | { | ||
| 627 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
| 628 | unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0; | ||
| 629 | bool invert_lrclk; | ||
| 630 | int ret; | ||
| 631 | |||
| 632 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 633 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 634 | adau1977->master = false; | ||
| 635 | break; | ||
| 636 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 637 | ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; | ||
| 638 | adau1977->master = true; | ||
| 639 | break; | ||
| 640 | default: | ||
| 641 | return -EINVAL; | ||
| 642 | } | ||
| 643 | |||
| 644 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
| 645 | case SND_SOC_DAIFMT_NB_NF: | ||
| 646 | invert_lrclk = false; | ||
| 647 | break; | ||
| 648 | case SND_SOC_DAIFMT_IB_NF: | ||
| 649 | block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; | ||
| 650 | invert_lrclk = false; | ||
| 651 | break; | ||
| 652 | case SND_SOC_DAIFMT_NB_IF: | ||
| 653 | invert_lrclk = true; | ||
| 654 | break; | ||
| 655 | case SND_SOC_DAIFMT_IB_IF: | ||
| 656 | block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; | ||
| 657 | invert_lrclk = true; | ||
| 658 | break; | ||
| 659 | default: | ||
| 660 | return -EINVAL; | ||
| 661 | } | ||
| 662 | |||
| 663 | adau1977->right_j = false; | ||
| 664 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 665 | case SND_SOC_DAIFMT_I2S: | ||
| 666 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; | ||
| 667 | break; | ||
| 668 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 669 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; | ||
| 670 | invert_lrclk = !invert_lrclk; | ||
| 671 | break; | ||
| 672 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 673 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; | ||
| 674 | adau1977->right_j = true; | ||
| 675 | invert_lrclk = !invert_lrclk; | ||
| 676 | break; | ||
| 677 | case SND_SOC_DAIFMT_DSP_A: | ||
| 678 | ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; | ||
| 679 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; | ||
| 680 | invert_lrclk = false; | ||
| 681 | break; | ||
| 682 | case SND_SOC_DAIFMT_DSP_B: | ||
| 683 | ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; | ||
| 684 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; | ||
| 685 | invert_lrclk = false; | ||
| 686 | break; | ||
| 687 | default: | ||
| 688 | return -EINVAL; | ||
| 689 | } | ||
| 690 | |||
| 691 | if (invert_lrclk) | ||
| 692 | block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL; | ||
| 693 | |||
| 694 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, | ||
| 695 | ADAU1977_BLOCK_POWER_SAI_LR_POL | | ||
| 696 | ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power); | ||
| 697 | if (ret) | ||
| 698 | return ret; | ||
| 699 | |||
| 700 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
| 701 | ADAU1977_SAI_CTRL0_FMT_MASK, | ||
| 702 | ctrl0); | ||
| 703 | if (ret) | ||
| 704 | return ret; | ||
| 705 | |||
| 706 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, | ||
| 707 | ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE, | ||
| 708 | ctrl1); | ||
| 709 | } | ||
| 710 | |||
| 711 | static int adau1977_startup(struct snd_pcm_substream *substream, | ||
| 712 | struct snd_soc_dai *dai) | ||
| 713 | { | ||
| 714 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
| 715 | u64 formats = 0; | ||
| 716 | |||
| 717 | if (adau1977->slot_width == 16) | ||
| 718 | formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE; | ||
| 719 | else if (adau1977->right_j || adau1977->slot_width == 24) | ||
| 720 | formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | | ||
| 721 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE; | ||
| 722 | |||
| 723 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
| 724 | SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); | ||
| 725 | |||
| 726 | if (adau1977->master) | ||
| 727 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
| 728 | SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); | ||
| 729 | |||
| 730 | if (formats != 0) | ||
| 731 | snd_pcm_hw_constraint_mask64(substream->runtime, | ||
| 732 | SNDRV_PCM_HW_PARAM_FORMAT, formats); | ||
| 733 | |||
| 734 | return 0; | ||
| 735 | } | ||
| 736 | |||
| 737 | static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
| 738 | { | ||
| 739 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
| 740 | unsigned int val; | ||
| 741 | |||
| 742 | if (tristate) | ||
| 743 | val = ADAU1977_SAI_OVERTEMP_DRV_HIZ; | ||
| 744 | else | ||
| 745 | val = 0; | ||
| 746 | |||
| 747 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, | ||
| 748 | ADAU1977_SAI_OVERTEMP_DRV_HIZ, val); | ||
| 749 | } | ||
| 750 | |||
| 751 | static const struct snd_soc_dai_ops adau1977_dai_ops = { | ||
| 752 | .startup = adau1977_startup, | ||
| 753 | .hw_params = adau1977_hw_params, | ||
| 754 | .mute_stream = adau1977_mute, | ||
| 755 | .set_fmt = adau1977_set_dai_fmt, | ||
| 756 | .set_tdm_slot = adau1977_set_tdm_slot, | ||
| 757 | .set_tristate = adau1977_set_tristate, | ||
| 758 | }; | ||
| 759 | |||
| 760 | static struct snd_soc_dai_driver adau1977_dai = { | ||
| 761 | .name = "adau1977-hifi", | ||
| 762 | .capture = { | ||
| 763 | .stream_name = "Capture", | ||
| 764 | .channels_min = 1, | ||
| 765 | .channels_max = 4, | ||
| 766 | .rates = SNDRV_PCM_RATE_KNOT, | ||
| 767 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | ||
| 768 | SNDRV_PCM_FMTBIT_S32_LE, | ||
| 769 | .sig_bits = 24, | ||
| 770 | }, | ||
| 771 | .ops = &adau1977_dai_ops, | ||
| 772 | }; | ||
| 773 | |||
| 774 | static const unsigned int adau1977_rates[] = { | ||
| 775 | 8000, 16000, 32000, 64000, 128000, | ||
| 776 | 11025, 22050, 44100, 88200, 172400, | ||
| 777 | 12000, 24000, 48000, 96000, 192000, | ||
| 778 | }; | ||
| 779 | |||
| 780 | #define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f | ||
| 781 | #define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0 | ||
| 782 | #define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00 | ||
| 783 | /* All rates >= 32000 */ | ||
| 784 | #define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c | ||
| 785 | |||
| 786 | static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq) | ||
| 787 | { | ||
| 788 | unsigned int mcs; | ||
| 789 | |||
| 790 | if (mclk % (base_freq * 128) != 0) | ||
| 791 | return false; | ||
| 792 | |||
| 793 | mcs = mclk / (128 * base_freq); | ||
| 794 | if (mcs < 1 || mcs > 6 || mcs == 5) | ||
| 795 | return false; | ||
| 796 | |||
| 797 | return true; | ||
| 798 | } | ||
| 799 | |||
| 800 | static int adau1977_set_sysclk(struct snd_soc_codec *codec, | ||
| 801 | int clk_id, int source, unsigned int freq, int dir) | ||
| 802 | { | ||
| 803 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
| 804 | unsigned int mask = 0; | ||
| 805 | unsigned int clk_src; | ||
| 806 | unsigned int ret; | ||
| 807 | |||
| 808 | if (dir != SND_SOC_CLOCK_IN) | ||
| 809 | return -EINVAL; | ||
| 810 | |||
| 811 | if (clk_id != ADAU1977_SYSCLK) | ||
| 812 | return -EINVAL; | ||
| 813 | |||
| 814 | switch (source) { | ||
| 815 | case ADAU1977_SYSCLK_SRC_MCLK: | ||
| 816 | clk_src = 0; | ||
| 817 | break; | ||
| 818 | case ADAU1977_SYSCLK_SRC_LRCLK: | ||
| 819 | clk_src = ADAU1977_PLL_CLK_S; | ||
| 820 | break; | ||
| 821 | default: | ||
| 822 | return -EINVAL; | ||
| 823 | } | ||
| 824 | |||
| 825 | if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) { | ||
| 826 | if (freq < 4000000 || freq > 36864000) | ||
| 827 | return -EINVAL; | ||
| 828 | |||
| 829 | if (adau1977_check_sysclk(freq, 32000)) | ||
| 830 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000; | ||
| 831 | if (adau1977_check_sysclk(freq, 44100)) | ||
| 832 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100; | ||
| 833 | if (adau1977_check_sysclk(freq, 48000)) | ||
| 834 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000; | ||
| 835 | |||
| 836 | if (mask == 0) | ||
| 837 | return -EINVAL; | ||
| 838 | } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) { | ||
| 839 | mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK; | ||
| 840 | } | ||
| 841 | |||
| 842 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, | ||
| 843 | ADAU1977_PLL_CLK_S, clk_src); | ||
| 844 | if (ret) | ||
| 845 | return ret; | ||
| 846 | |||
| 847 | adau1977->constraints.mask = mask; | ||
| 848 | adau1977->sysclk_src = source; | ||
| 849 | adau1977->sysclk = freq; | ||
| 850 | |||
| 851 | return 0; | ||
| 852 | } | ||
| 853 | |||
| 854 | static int adau1977_codec_probe(struct snd_soc_codec *codec) | ||
| 855 | { | ||
| 856 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
| 857 | int ret; | ||
| 858 | |||
| 859 | switch (adau1977->type) { | ||
| 860 | case ADAU1977: | ||
| 861 | ret = snd_soc_dapm_new_controls(&codec->dapm, | ||
| 862 | adau1977_micbias_dapm_widgets, | ||
| 863 | ARRAY_SIZE(adau1977_micbias_dapm_widgets)); | ||
| 864 | if (ret < 0) | ||
| 865 | return ret; | ||
| 866 | break; | ||
| 867 | default: | ||
| 868 | break; | ||
| 869 | } | ||
| 870 | |||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | |||
| 874 | static struct snd_soc_codec_driver adau1977_codec_driver = { | ||
| 875 | .probe = adau1977_codec_probe, | ||
| 876 | .set_bias_level = adau1977_set_bias_level, | ||
| 877 | .set_sysclk = adau1977_set_sysclk, | ||
| 878 | .idle_bias_off = true, | ||
| 879 | |||
| 880 | .controls = adau1977_snd_controls, | ||
| 881 | .num_controls = ARRAY_SIZE(adau1977_snd_controls), | ||
| 882 | .dapm_widgets = adau1977_dapm_widgets, | ||
| 883 | .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), | ||
| 884 | .dapm_routes = adau1977_dapm_routes, | ||
| 885 | .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), | ||
| 886 | }; | ||
| 887 | |||
| 888 | static int adau1977_setup_micbias(struct adau1977 *adau1977) | ||
| 889 | { | ||
| 890 | struct adau1977_platform_data *pdata = adau1977->dev->platform_data; | ||
| 891 | unsigned int micbias; | ||
| 892 | |||
| 893 | if (pdata) { | ||
| 894 | micbias = pdata->micbias; | ||
| 895 | if (micbias > ADAU1977_MICBIAS_9V0) | ||
| 896 | return -EINVAL; | ||
| 897 | |||
| 898 | } else { | ||
| 899 | micbias = ADAU1977_MICBIAS_8V5; | ||
| 900 | } | ||
| 901 | |||
| 902 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, | ||
| 903 | ADAU1977_MICBIAS_MB_VOLTS_MASK, | ||
| 904 | micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET); | ||
| 905 | } | ||
| 906 | |||
| 907 | int adau1977_probe(struct device *dev, struct regmap *regmap, | ||
| 908 | enum adau1977_type type, void (*switch_mode)(struct device *dev)) | ||
| 909 | { | ||
| 910 | unsigned int power_off_mask; | ||
| 911 | struct adau1977 *adau1977; | ||
| 912 | int ret; | ||
| 913 | |||
| 914 | if (IS_ERR(regmap)) | ||
| 915 | return PTR_ERR(regmap); | ||
| 916 | |||
| 917 | adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL); | ||
| 918 | if (adau1977 == NULL) | ||
| 919 | return -ENOMEM; | ||
| 920 | |||
| 921 | adau1977->dev = dev; | ||
| 922 | adau1977->type = type; | ||
| 923 | adau1977->regmap = regmap; | ||
| 924 | adau1977->switch_mode = switch_mode; | ||
| 925 | adau1977->max_master_fs = 192000; | ||
| 926 | |||
| 927 | adau1977->constraints.list = adau1977_rates; | ||
| 928 | adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); | ||
| 929 | |||
| 930 | adau1977->avdd_reg = devm_regulator_get(dev, "AVDD"); | ||
| 931 | if (IS_ERR(adau1977->avdd_reg)) | ||
| 932 | return PTR_ERR(adau1977->avdd_reg); | ||
| 933 | |||
| 934 | adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD"); | ||
| 935 | if (IS_ERR(adau1977->dvdd_reg)) { | ||
| 936 | if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV) | ||
| 937 | return PTR_ERR(adau1977->dvdd_reg); | ||
| 938 | adau1977->dvdd_reg = NULL; | ||
| 939 | } | ||
| 940 | |||
| 941 | adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); | ||
| 942 | if (IS_ERR(adau1977->reset_gpio)) { | ||
| 943 | ret = PTR_ERR(adau1977->reset_gpio); | ||
| 944 | if (ret != -ENOENT && ret != -ENOSYS) | ||
| 945 | return PTR_ERR(adau1977->reset_gpio); | ||
| 946 | adau1977->reset_gpio = NULL; | ||
| 947 | } | ||
| 948 | |||
| 949 | dev_set_drvdata(dev, adau1977); | ||
| 950 | |||
| 951 | if (adau1977->reset_gpio) { | ||
| 952 | ret = gpiod_direction_output(adau1977->reset_gpio, 0); | ||
| 953 | if (ret) | ||
| 954 | return ret; | ||
| 955 | ndelay(100); | ||
| 956 | } | ||
| 957 | |||
| 958 | ret = adau1977_power_enable(adau1977); | ||
| 959 | if (ret) | ||
| 960 | return ret; | ||
| 961 | |||
| 962 | if (type == ADAU1977) { | ||
| 963 | ret = adau1977_setup_micbias(adau1977); | ||
| 964 | if (ret) | ||
| 965 | goto err_poweroff; | ||
| 966 | } | ||
| 967 | |||
| 968 | if (adau1977->dvdd_reg) | ||
| 969 | power_off_mask = ~0; | ||
| 970 | else | ||
| 971 | power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; | ||
| 972 | |||
| 973 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, | ||
| 974 | power_off_mask, 0x00); | ||
| 975 | if (ret) | ||
| 976 | goto err_poweroff; | ||
| 977 | |||
| 978 | ret = adau1977_power_disable(adau1977); | ||
| 979 | if (ret) | ||
| 980 | return ret; | ||
| 981 | |||
| 982 | return snd_soc_register_codec(dev, &adau1977_codec_driver, | ||
| 983 | &adau1977_dai, 1); | ||
| 984 | |||
| 985 | err_poweroff: | ||
| 986 | adau1977_power_disable(adau1977); | ||
| 987 | return ret; | ||
| 988 | |||
| 989 | } | ||
| 990 | EXPORT_SYMBOL_GPL(adau1977_probe); | ||
| 991 | |||
| 992 | static bool adau1977_register_volatile(struct device *dev, unsigned int reg) | ||
| 993 | { | ||
| 994 | switch (reg) { | ||
| 995 | case ADAU1977_REG_STATUS(0): | ||
| 996 | case ADAU1977_REG_STATUS(1): | ||
| 997 | case ADAU1977_REG_STATUS(2): | ||
| 998 | case ADAU1977_REG_STATUS(3): | ||
| 999 | case ADAU1977_REG_ADC_CLIP: | ||
| 1000 | return true; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | return false; | ||
| 1004 | } | ||
| 1005 | |||
| 1006 | const struct regmap_config adau1977_regmap_config = { | ||
| 1007 | .max_register = ADAU1977_REG_DC_HPF_CAL, | ||
| 1008 | .volatile_reg = adau1977_register_volatile, | ||
| 1009 | |||
| 1010 | .cache_type = REGCACHE_RBTREE, | ||
| 1011 | .reg_defaults = adau1977_reg_defaults, | ||
| 1012 | .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), | ||
| 1013 | }; | ||
| 1014 | EXPORT_SYMBOL_GPL(adau1977_regmap_config); | ||
| 1015 | |||
| 1016 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
| 1017 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 1018 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h new file mode 100644 index 000000000000..95e714345a86 --- /dev/null +++ b/sound/soc/codecs/adau1977.h | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | /* | ||
| 2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
| 6 | * | ||
| 7 | * Licensed under the GPL-2. | ||
| 8 | */ | ||
| 9 | |||
| 10 | #ifndef __SOUND_SOC_CODECS_ADAU1977_H__ | ||
| 11 | #define __SOUND_SOC_CODECS_ADAU1977_H__ | ||
| 12 | |||
| 13 | #include <linux/regmap.h> | ||
| 14 | |||
| 15 | struct device; | ||
| 16 | |||
| 17 | enum adau1977_type { | ||
| 18 | ADAU1977, | ||
| 19 | ADAU1978, | ||
| 20 | ADAU1979, | ||
| 21 | }; | ||
| 22 | |||
| 23 | int adau1977_probe(struct device *dev, struct regmap *regmap, | ||
| 24 | enum adau1977_type type, void (*switch_mode)(struct device *dev)); | ||
| 25 | |||
| 26 | extern const struct regmap_config adau1977_regmap_config; | ||
| 27 | |||
| 28 | enum adau1977_clk_id { | ||
| 29 | ADAU1977_SYSCLK, | ||
| 30 | }; | ||
| 31 | |||
| 32 | enum adau1977_sysclk_src { | ||
| 33 | ADAU1977_SYSCLK_SRC_MCLK, | ||
| 34 | ADAU1977_SYSCLK_SRC_LRCLK, | ||
| 35 | }; | ||
| 36 | |||
| 37 | #endif | ||
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c new file mode 100644 index 000000000000..790fce33ab10 --- /dev/null +++ b/sound/soc/codecs/adav801.c | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | /* | ||
| 2 | * ADAV801 audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spi/spi.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "adav80x.h" | ||
| 16 | |||
| 17 | static const struct spi_device_id adav80x_spi_id[] = { | ||
| 18 | { "adav801", 0 }, | ||
| 19 | { } | ||
| 20 | }; | ||
| 21 | MODULE_DEVICE_TABLE(spi, adav80x_spi_id); | ||
| 22 | |||
| 23 | static int adav80x_spi_probe(struct spi_device *spi) | ||
| 24 | { | ||
| 25 | struct regmap_config config; | ||
| 26 | |||
| 27 | config = adav80x_regmap_config; | ||
| 28 | config.read_flag_mask = 0x01; | ||
| 29 | |||
| 30 | return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
| 31 | } | ||
| 32 | |||
| 33 | static int adav80x_spi_remove(struct spi_device *spi) | ||
| 34 | { | ||
| 35 | snd_soc_unregister_codec(&spi->dev); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static struct spi_driver adav80x_spi_driver = { | ||
| 40 | .driver = { | ||
| 41 | .name = "adav801", | ||
| 42 | .owner = THIS_MODULE, | ||
| 43 | }, | ||
| 44 | .probe = adav80x_spi_probe, | ||
| 45 | .remove = adav80x_spi_remove, | ||
| 46 | .id_table = adav80x_spi_id, | ||
| 47 | }; | ||
| 48 | module_spi_driver(adav80x_spi_driver); | ||
| 49 | |||
| 50 | MODULE_DESCRIPTION("ASoC ADAV801 driver"); | ||
| 51 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 52 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
| 53 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c new file mode 100644 index 000000000000..66d9fce34e62 --- /dev/null +++ b/sound/soc/codecs/adav803.c | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* | ||
| 2 | * ADAV803 audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "adav80x.h" | ||
| 16 | |||
| 17 | static const struct i2c_device_id adav803_id[] = { | ||
| 18 | { "adav803", 0 }, | ||
| 19 | { } | ||
| 20 | }; | ||
| 21 | MODULE_DEVICE_TABLE(i2c, adav803_id); | ||
| 22 | |||
| 23 | static int adav803_probe(struct i2c_client *client, | ||
| 24 | const struct i2c_device_id *id) | ||
| 25 | { | ||
| 26 | return adav80x_bus_probe(&client->dev, | ||
| 27 | devm_regmap_init_i2c(client, &adav80x_regmap_config)); | ||
| 28 | } | ||
| 29 | |||
| 30 | static int adav803_remove(struct i2c_client *client) | ||
| 31 | { | ||
| 32 | snd_soc_unregister_codec(&client->dev); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | static struct i2c_driver adav803_driver = { | ||
| 37 | .driver = { | ||
| 38 | .name = "adav803", | ||
| 39 | .owner = THIS_MODULE, | ||
| 40 | }, | ||
| 41 | .probe = adav803_probe, | ||
| 42 | .remove = adav803_remove, | ||
| 43 | .id_table = adav803_id, | ||
| 44 | }; | ||
| 45 | module_i2c_driver(adav803_driver); | ||
| 46 | |||
| 47 | MODULE_DESCRIPTION("ASoC ADAV803 driver"); | ||
| 48 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
| 49 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
| 50 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index f78b27a7c461..7470831ba756 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
| @@ -8,17 +8,15 @@ | |||
| 8 | * Licensed under the GPL-2 or later. | 8 | * Licensed under the GPL-2 or later. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/init.h> | ||
| 12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
| 13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
| 14 | #include <linux/i2c.h> | 13 | #include <linux/regmap.h> |
| 15 | #include <linux/spi/spi.h> | ||
| 16 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 17 | #include <sound/core.h> | 15 | |
| 18 | #include <sound/pcm.h> | 16 | #include <sound/pcm.h> |
| 19 | #include <sound/pcm_params.h> | 17 | #include <sound/pcm_params.h> |
| 20 | #include <sound/tlv.h> | ||
| 21 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
| 19 | #include <sound/tlv.h> | ||
| 22 | 20 | ||
| 23 | #include "adav80x.h" | 21 | #include "adav80x.h" |
| 24 | 22 | ||
| @@ -541,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
| 541 | unsigned int freq, int dir) | 539 | unsigned int freq, int dir) |
| 542 | { | 540 | { |
| 543 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 541 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
| 542 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 544 | 543 | ||
| 545 | if (dir == SND_SOC_CLOCK_IN) { | 544 | if (dir == SND_SOC_CLOCK_IN) { |
| 546 | switch (clk_id) { | 545 | switch (clk_id) { |
| @@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
| 573 | regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, | 572 | regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, |
| 574 | iclk_ctrl2); | 573 | iclk_ctrl2); |
| 575 | 574 | ||
| 576 | snd_soc_dapm_sync(&codec->dapm); | 575 | snd_soc_dapm_sync(dapm); |
| 577 | } | 576 | } |
| 578 | } else { | 577 | } else { |
| 579 | unsigned int mask; | 578 | unsigned int mask; |
| @@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
| 600 | adav80x->sysclk_pd[clk_id] = false; | 599 | adav80x->sysclk_pd[clk_id] = false; |
| 601 | } | 600 | } |
| 602 | 601 | ||
| 602 | snd_soc_dapm_mutex_lock(dapm); | ||
| 603 | |||
| 603 | if (adav80x->sysclk_pd[0]) | 604 | if (adav80x->sysclk_pd[0]) |
| 604 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | 605 | snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1"); |
| 605 | else | 606 | else |
| 606 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | 607 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1"); |
| 607 | 608 | ||
| 608 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) | 609 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) |
| 609 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); | 610 | snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2"); |
| 610 | else | 611 | else |
| 611 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | 612 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2"); |
| 612 | 613 | ||
| 613 | snd_soc_dapm_sync(&codec->dapm); | 614 | snd_soc_dapm_sync_unlocked(dapm); |
| 615 | |||
| 616 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 614 | } | 617 | } |
| 615 | 618 | ||
| 616 | return 0; | 619 | return 0; |
| @@ -722,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream, | |||
| 722 | struct snd_soc_codec *codec = dai->codec; | 725 | struct snd_soc_codec *codec = dai->codec; |
| 723 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 726 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
| 724 | 727 | ||
| 725 | if (!codec->active || !adav80x->rate) | 728 | if (!snd_soc_codec_is_active(codec) || !adav80x->rate) |
| 726 | return 0; | 729 | return 0; |
| 727 | 730 | ||
| 728 | return snd_pcm_hw_constraint_minmax(substream->runtime, | 731 | return snd_pcm_hw_constraint_minmax(substream->runtime, |
| @@ -735,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, | |||
| 735 | struct snd_soc_codec *codec = dai->codec; | 738 | struct snd_soc_codec *codec = dai->codec; |
| 736 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 739 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
| 737 | 740 | ||
| 738 | if (!codec->active) | 741 | if (!snd_soc_codec_is_active(codec)) |
| 739 | adav80x->rate = 0; | 742 | adav80x->rate = 0; |
| 740 | } | 743 | } |
| 741 | 744 | ||
| @@ -864,39 +867,26 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { | |||
| 864 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), | 867 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), |
| 865 | }; | 868 | }; |
| 866 | 869 | ||
| 867 | static int adav80x_bus_probe(struct device *dev, struct regmap *regmap) | 870 | int adav80x_bus_probe(struct device *dev, struct regmap *regmap) |
| 868 | { | 871 | { |
| 869 | struct adav80x *adav80x; | 872 | struct adav80x *adav80x; |
| 870 | int ret; | ||
| 871 | 873 | ||
| 872 | if (IS_ERR(regmap)) | 874 | if (IS_ERR(regmap)) |
| 873 | return PTR_ERR(regmap); | 875 | return PTR_ERR(regmap); |
| 874 | 876 | ||
| 875 | adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); | 877 | adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL); |
| 876 | if (!adav80x) | 878 | if (!adav80x) |
| 877 | return -ENOMEM; | 879 | return -ENOMEM; |
| 878 | 880 | ||
| 879 | |||
| 880 | dev_set_drvdata(dev, adav80x); | 881 | dev_set_drvdata(dev, adav80x); |
| 881 | adav80x->regmap = regmap; | 882 | adav80x->regmap = regmap; |
| 882 | 883 | ||
| 883 | ret = snd_soc_register_codec(dev, &adav80x_codec_driver, | 884 | return snd_soc_register_codec(dev, &adav80x_codec_driver, |
| 884 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); | 885 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); |
| 885 | if (ret) | ||
| 886 | kfree(adav80x); | ||
| 887 | |||
| 888 | return ret; | ||
| 889 | } | 886 | } |
| 887 | EXPORT_SYMBOL_GPL(adav80x_bus_probe); | ||
| 890 | 888 | ||
| 891 | static int adav80x_bus_remove(struct device *dev) | 889 | const struct regmap_config adav80x_regmap_config = { |
| 892 | { | ||
| 893 | snd_soc_unregister_codec(dev); | ||
| 894 | kfree(dev_get_drvdata(dev)); | ||
| 895 | return 0; | ||
| 896 | } | ||
| 897 | |||
| 898 | #if defined(CONFIG_SPI_MASTER) | ||
| 899 | static const struct regmap_config adav80x_spi_regmap_config = { | ||
| 900 | .val_bits = 8, | 890 | .val_bits = 8, |
| 901 | .pad_bits = 1, | 891 | .pad_bits = 1, |
| 902 | .reg_bits = 7, | 892 | .reg_bits = 7, |
| @@ -908,105 +898,7 @@ static const struct regmap_config adav80x_spi_regmap_config = { | |||
| 908 | .reg_defaults = adav80x_reg_defaults, | 898 | .reg_defaults = adav80x_reg_defaults, |
| 909 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), | 899 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), |
| 910 | }; | 900 | }; |
| 911 | 901 | EXPORT_SYMBOL_GPL(adav80x_regmap_config); | |
| 912 | static const struct spi_device_id adav80x_spi_id[] = { | ||
| 913 | { "adav801", 0 }, | ||
| 914 | { } | ||
| 915 | }; | ||
| 916 | MODULE_DEVICE_TABLE(spi, adav80x_spi_id); | ||
| 917 | |||
| 918 | static int adav80x_spi_probe(struct spi_device *spi) | ||
| 919 | { | ||
| 920 | return adav80x_bus_probe(&spi->dev, | ||
| 921 | devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); | ||
| 922 | } | ||
| 923 | |||
| 924 | static int adav80x_spi_remove(struct spi_device *spi) | ||
| 925 | { | ||
| 926 | return adav80x_bus_remove(&spi->dev); | ||
| 927 | } | ||
| 928 | |||
| 929 | static struct spi_driver adav80x_spi_driver = { | ||
| 930 | .driver = { | ||
| 931 | .name = "adav801", | ||
| 932 | .owner = THIS_MODULE, | ||
| 933 | }, | ||
| 934 | .probe = adav80x_spi_probe, | ||
| 935 | .remove = adav80x_spi_remove, | ||
| 936 | .id_table = adav80x_spi_id, | ||
| 937 | }; | ||
| 938 | #endif | ||
| 939 | |||
| 940 | #if IS_ENABLED(CONFIG_I2C) | ||
| 941 | static const struct regmap_config adav80x_i2c_regmap_config = { | ||
| 942 | .val_bits = 8, | ||
| 943 | .pad_bits = 1, | ||
| 944 | .reg_bits = 7, | ||
| 945 | |||
| 946 | .max_register = ADAV80X_PLL_OUTE, | ||
| 947 | |||
| 948 | .cache_type = REGCACHE_RBTREE, | ||
| 949 | .reg_defaults = adav80x_reg_defaults, | ||
| 950 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), | ||
| 951 | }; | ||
| 952 | |||
| 953 | static const struct i2c_device_id adav80x_i2c_id[] = { | ||
| 954 | { "adav803", 0 }, | ||
| 955 | { } | ||
| 956 | }; | ||
| 957 | MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); | ||
| 958 | |||
| 959 | static int adav80x_i2c_probe(struct i2c_client *client, | ||
| 960 | const struct i2c_device_id *id) | ||
| 961 | { | ||
| 962 | return adav80x_bus_probe(&client->dev, | ||
| 963 | devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); | ||
| 964 | } | ||
| 965 | |||
| 966 | static int adav80x_i2c_remove(struct i2c_client *client) | ||
| 967 | { | ||
| 968 | return adav80x_bus_remove(&client->dev); | ||
| 969 | } | ||
| 970 | |||
| 971 | static struct i2c_driver adav80x_i2c_driver = { | ||
| 972 | .driver = { | ||
| 973 | .name = "adav803", | ||
| 974 | .owner = THIS_MODULE, | ||
| 975 | }, | ||
| 976 | .probe = adav80x_i2c_probe, | ||
| 977 | .remove = adav80x_i2c_remove, | ||
| 978 | .id_table = adav80x_i2c_id, | ||
| 979 | }; | ||
| 980 | #endif | ||
| 981 | |||
| 982 | static int __init adav80x_init(void) | ||
| 983 | { | ||
| 984 | int ret = 0; | ||
| 985 | |||
| 986 | #if IS_ENABLED(CONFIG_I2C) | ||
| 987 | ret = i2c_add_driver(&adav80x_i2c_driver); | ||
| 988 | if (ret) | ||
| 989 | return ret; | ||
| 990 | #endif | ||
| 991 | |||
| 992 | #if defined(CONFIG_SPI_MASTER) | ||
| 993 | ret = spi_register_driver(&adav80x_spi_driver); | ||
| 994 | #endif | ||
| 995 | |||
| 996 | return ret; | ||
| 997 | } | ||
| 998 | module_init(adav80x_init); | ||
| 999 | |||
| 1000 | static void __exit adav80x_exit(void) | ||
| 1001 | { | ||
| 1002 | #if IS_ENABLED(CONFIG_I2C) | ||
| 1003 | i2c_del_driver(&adav80x_i2c_driver); | ||
| 1004 | #endif | ||
| 1005 | #if defined(CONFIG_SPI_MASTER) | ||
| 1006 | spi_unregister_driver(&adav80x_spi_driver); | ||
| 1007 | #endif | ||
| 1008 | } | ||
| 1009 | module_exit(adav80x_exit); | ||
| 1010 | 902 | ||
| 1011 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); | 903 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); |
| 1012 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 904 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h index adb0fc76d4e3..8a1d7c09dca5 100644 --- a/sound/soc/codecs/adav80x.h +++ b/sound/soc/codecs/adav80x.h | |||
| @@ -9,6 +9,13 @@ | |||
| 9 | #ifndef _ADAV80X_H | 9 | #ifndef _ADAV80X_H |
| 10 | #define _ADAV80X_H | 10 | #define _ADAV80X_H |
| 11 | 11 | ||
| 12 | #include <linux/regmap.h> | ||
| 13 | |||
| 14 | struct device; | ||
| 15 | |||
| 16 | extern const struct regmap_config adav80x_regmap_config; | ||
| 17 | int adav80x_bus_probe(struct device *dev, struct regmap *regmap); | ||
| 18 | |||
| 12 | enum adav80x_pll_src { | 19 | enum adav80x_pll_src { |
| 13 | ADAV80X_PLL_SRC_XIN, | 20 | ADAV80X_PLL_SRC_XIN, |
| 14 | ADAV80X_PLL_SRC_XTAL, | 21 | ADAV80X_PLL_SRC_XTAL, |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b4819dcd4f4d..10adf25d4c14 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
| @@ -174,8 +174,6 @@ static int ak4104_probe(struct snd_soc_codec *codec) | |||
| 174 | struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); | 174 | struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); |
| 175 | int ret; | 175 | int ret; |
| 176 | 176 | ||
| 177 | codec->control_data = ak4104->regmap; | ||
| 178 | |||
| 179 | /* set power-up and non-reset bits */ | 177 | /* set power-up and non-reset bits */ |
| 180 | ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, | 178 | ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, |
| 181 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, | 179 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, |
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 94cbe508dd37..684b56f2856a 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
| @@ -113,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0); | |||
| 113 | static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); | 113 | static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); |
| 114 | 114 | ||
| 115 | 115 | ||
| 116 | static const struct soc_enum ak4641_mono_out_enum = | 116 | static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum, |
| 117 | SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); | 117 | AK4641_SIG1, 6, ak4641_mono_out); |
| 118 | static const struct soc_enum ak4641_hp_out_enum = | 118 | static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum, |
| 119 | SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); | 119 | AK4641_MODE2, 2, ak4641_hp_out); |
| 120 | static const struct soc_enum ak4641_mic_select_enum = | 120 | static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum, |
| 121 | SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); | 121 | AK4641_MIC, 1, ak4641_mic_select); |
| 122 | static const struct soc_enum ak4641_mic_or_dac_enum = | 122 | static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum, |
| 123 | SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); | 123 | AK4641_BTIF, 4, ak4641_mic_or_dac); |
| 124 | 124 | ||
| 125 | static const struct snd_kcontrol_new ak4641_snd_controls[] = { | 125 | static const struct snd_kcontrol_new ak4641_snd_controls[] = { |
| 126 | SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), | 126 | SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 25bdf6ad4a54..deb2b44669de 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
| 16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
| 17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
| 18 | #include <linux/regmap.h> | ||
| 18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
| 20 | #include <sound/initval.h> | 21 | #include <sound/initval.h> |
| @@ -23,104 +24,99 @@ | |||
| 23 | #include "ak4671.h" | 24 | #include "ak4671.h" |
| 24 | 25 | ||
| 25 | 26 | ||
| 26 | /* codec private data */ | ||
| 27 | struct ak4671_priv { | ||
| 28 | enum snd_soc_control_type control_type; | ||
| 29 | }; | ||
| 30 | |||
| 31 | /* ak4671 register cache & default register settings */ | 27 | /* ak4671 register cache & default register settings */ |
| 32 | static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { | 28 | static const struct reg_default ak4671_reg_defaults[] = { |
| 33 | 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ | 29 | { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ |
| 34 | 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ | 30 | { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */ |
| 35 | 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ | 31 | { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */ |
| 36 | 0x02, /* AK4671_FORMAT_SELECT (0x03) */ | 32 | { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */ |
| 37 | 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ | 33 | { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ |
| 38 | 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ | 34 | { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */ |
| 39 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ | 35 | { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ |
| 40 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ | 36 | { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ |
| 41 | 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ | 37 | { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ |
| 42 | 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ | 38 | { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ |
| 43 | 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ | 39 | { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ |
| 44 | 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ | 40 | { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ |
| 45 | 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ | 41 | { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ |
| 46 | 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ | 42 | { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ |
| 47 | 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ | 43 | { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ |
| 48 | 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ | 44 | { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ |
| 49 | 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ | 45 | { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ |
| 50 | 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ | 46 | { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ |
| 51 | 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ | 47 | { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ |
| 52 | 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ | 48 | { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ |
| 53 | 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ | 49 | { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ |
| 54 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ | 50 | { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ |
| 55 | 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ | 51 | { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */ |
| 56 | 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ | 52 | { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */ |
| 57 | 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ | 53 | { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */ |
| 58 | 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ | 54 | { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */ |
| 59 | 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ | 55 | { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ |
| 60 | 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ | 56 | { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ |
| 61 | 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ | 57 | { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ |
| 62 | 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ | 58 | { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ |
| 63 | 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ | 59 | { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ |
| 64 | 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ | 60 | { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ |
| 65 | 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ | 61 | { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ |
| 66 | 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ | 62 | { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ |
| 67 | 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ | 63 | { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */ |
| 68 | 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ | 64 | { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */ |
| 69 | 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ | 65 | { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */ |
| 70 | 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ | 66 | { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */ |
| 71 | 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ | 67 | { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */ |
| 72 | 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ | 68 | { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */ |
| 73 | 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ | 69 | { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ |
| 74 | 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ | 70 | { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ |
| 75 | 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ | 71 | { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ |
| 76 | 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ | 72 | { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ |
| 77 | 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ | 73 | { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ |
| 78 | 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ | 74 | { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ |
| 79 | 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ | 75 | { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ |
| 80 | 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ | 76 | { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ |
| 81 | 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ | 77 | { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ |
| 82 | 0x00, /* this register not used */ | 78 | |
| 83 | 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ | 79 | { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */ |
| 84 | 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ | 80 | { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */ |
| 85 | 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ | 81 | { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */ |
| 86 | 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ | 82 | { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */ |
| 87 | 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ | 83 | { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */ |
| 88 | 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ | 84 | { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */ |
| 89 | 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ | 85 | { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */ |
| 90 | 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ | 86 | { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */ |
| 91 | 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ | 87 | { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */ |
| 92 | 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ | 88 | { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */ |
| 93 | 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ | 89 | { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */ |
| 94 | 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ | 90 | { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */ |
| 95 | 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ | 91 | { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */ |
| 96 | 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ | 92 | { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */ |
| 97 | 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ | 93 | { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */ |
| 98 | 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ | 94 | { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */ |
| 99 | 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ | 95 | { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */ |
| 100 | 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ | 96 | { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */ |
| 101 | 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ | 97 | { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */ |
| 102 | 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ | 98 | { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */ |
| 103 | 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ | 99 | { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */ |
| 104 | 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ | 100 | { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */ |
| 105 | 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ | 101 | { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */ |
| 106 | 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ | 102 | { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */ |
| 107 | 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ | 103 | { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */ |
| 108 | 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ | 104 | { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */ |
| 109 | 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ | 105 | { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */ |
| 110 | 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ | 106 | { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */ |
| 111 | 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ | 107 | { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */ |
| 112 | 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ | 108 | { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */ |
| 113 | 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ | 109 | { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ |
| 114 | 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ | 110 | { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ |
| 115 | 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ | 111 | { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ |
| 116 | 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ | 112 | { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */ |
| 117 | 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ | 113 | { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */ |
| 118 | 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ | 114 | { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */ |
| 119 | 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ | 115 | { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ |
| 120 | 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ | 116 | { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ |
| 121 | 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ | 117 | { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ |
| 122 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ | 118 | { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ |
| 123 | 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ | 119 | { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */ |
| 124 | }; | 120 | }; |
| 125 | 121 | ||
| 126 | /* | 122 | /* |
| @@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { | |||
| 241 | /* Input MUXs */ | 237 | /* Input MUXs */ |
| 242 | static const char *ak4671_lin_mux_texts[] = | 238 | static const char *ak4671_lin_mux_texts[] = |
| 243 | {"LIN1", "LIN2", "LIN3", "LIN4"}; | 239 | {"LIN1", "LIN2", "LIN3", "LIN4"}; |
| 244 | static const struct soc_enum ak4671_lin_mux_enum = | 240 | static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum, |
| 245 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, | 241 | AK4671_MIC_SIGNAL_SELECT, 0, |
| 246 | ARRAY_SIZE(ak4671_lin_mux_texts), | 242 | ak4671_lin_mux_texts); |
| 247 | ak4671_lin_mux_texts); | ||
| 248 | static const struct snd_kcontrol_new ak4671_lin_mux_control = | 243 | static const struct snd_kcontrol_new ak4671_lin_mux_control = |
| 249 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); | 244 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); |
| 250 | 245 | ||
| 251 | static const char *ak4671_rin_mux_texts[] = | 246 | static const char *ak4671_rin_mux_texts[] = |
| 252 | {"RIN1", "RIN2", "RIN3", "RIN4"}; | 247 | {"RIN1", "RIN2", "RIN3", "RIN4"}; |
| 253 | static const struct soc_enum ak4671_rin_mux_enum = | 248 | static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum, |
| 254 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, | 249 | AK4671_MIC_SIGNAL_SELECT, 2, |
| 255 | ARRAY_SIZE(ak4671_rin_mux_texts), | 250 | ak4671_rin_mux_texts); |
| 256 | ak4671_rin_mux_texts); | ||
| 257 | static const struct snd_kcontrol_new ak4671_rin_mux_control = | 251 | static const struct snd_kcontrol_new ak4671_rin_mux_control = |
| 258 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); | 252 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); |
| 259 | 253 | ||
| @@ -619,18 +613,14 @@ static struct snd_soc_dai_driver ak4671_dai = { | |||
| 619 | 613 | ||
| 620 | static int ak4671_probe(struct snd_soc_codec *codec) | 614 | static int ak4671_probe(struct snd_soc_codec *codec) |
| 621 | { | 615 | { |
| 622 | struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); | ||
| 623 | int ret; | 616 | int ret; |
| 624 | 617 | ||
| 625 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); | 618 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
| 626 | if (ret < 0) { | 619 | if (ret < 0) { |
| 627 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 620 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 628 | return ret; | 621 | return ret; |
| 629 | } | 622 | } |
| 630 | 623 | ||
| 631 | snd_soc_add_codec_controls(codec, ak4671_snd_controls, | ||
| 632 | ARRAY_SIZE(ak4671_snd_controls)); | ||
| 633 | |||
| 634 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 624 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 635 | 625 | ||
| 636 | return ret; | 626 | return ret; |
| @@ -646,28 +636,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { | |||
| 646 | .probe = ak4671_probe, | 636 | .probe = ak4671_probe, |
| 647 | .remove = ak4671_remove, | 637 | .remove = ak4671_remove, |
| 648 | .set_bias_level = ak4671_set_bias_level, | 638 | .set_bias_level = ak4671_set_bias_level, |
| 649 | .reg_cache_size = AK4671_CACHEREGNUM, | 639 | .controls = ak4671_snd_controls, |
| 650 | .reg_word_size = sizeof(u8), | 640 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), |
| 651 | .reg_cache_default = ak4671_reg, | ||
| 652 | .dapm_widgets = ak4671_dapm_widgets, | 641 | .dapm_widgets = ak4671_dapm_widgets, |
| 653 | .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), | 642 | .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), |
| 654 | .dapm_routes = ak4671_intercon, | 643 | .dapm_routes = ak4671_intercon, |
| 655 | .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), | 644 | .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), |
| 656 | }; | 645 | }; |
| 657 | 646 | ||
| 647 | static const struct regmap_config ak4671_regmap = { | ||
| 648 | .reg_bits = 8, | ||
| 649 | .val_bits = 8, | ||
| 650 | |||
| 651 | .max_register = AK4671_SAR_ADC_CONTROL, | ||
| 652 | .reg_defaults = ak4671_reg_defaults, | ||
| 653 | .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults), | ||
| 654 | .cache_type = REGCACHE_RBTREE, | ||
| 655 | }; | ||
| 656 | |||
| 658 | static int ak4671_i2c_probe(struct i2c_client *client, | 657 | static int ak4671_i2c_probe(struct i2c_client *client, |
| 659 | const struct i2c_device_id *id) | 658 | const struct i2c_device_id *id) |
| 660 | { | 659 | { |
| 661 | struct ak4671_priv *ak4671; | 660 | struct regmap *regmap; |
| 662 | int ret; | 661 | int ret; |
| 663 | 662 | ||
| 664 | ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv), | 663 | regmap = devm_regmap_init_i2c(client, &ak4671_regmap); |
| 665 | GFP_KERNEL); | 664 | if (IS_ERR(regmap)) { |
| 666 | if (ak4671 == NULL) | 665 | ret = PTR_ERR(regmap); |
| 667 | return -ENOMEM; | 666 | dev_err(&client->dev, "Failed to create regmap: %d\n", ret); |
| 668 | 667 | return ret; | |
| 669 | i2c_set_clientdata(client, ak4671); | 668 | } |
| 670 | ak4671->control_type = SND_SOC_I2C; | ||
| 671 | 669 | ||
| 672 | ret = snd_soc_register_codec(&client->dev, | 670 | ret = snd_soc_register_codec(&client->dev, |
| 673 | &soc_codec_dev_ak4671, &ak4671_dai, 1); | 671 | &soc_codec_dev_ak4671, &ak4671_dai, 1); |
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h index 61cb7ab7552c..394a34d3f50a 100644 --- a/sound/soc/codecs/ak4671.h +++ b/sound/soc/codecs/ak4671.h | |||
| @@ -105,8 +105,6 @@ | |||
| 105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 | 105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 |
| 106 | #define AK4671_SAR_ADC_CONTROL 0x5a | 106 | #define AK4671_SAR_ADC_CONTROL 0x5a |
| 107 | 107 | ||
| 108 | #define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) | ||
| 109 | |||
| 110 | /* Bitfield Definitions */ | 108 | /* Bitfield Definitions */ |
| 111 | 109 | ||
| 112 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ | 110 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ |
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index d3036283482a..ed506253a914 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
| 22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
| 23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
| 24 | #include <linux/regmap.h> | ||
| 24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
| 25 | #include <sound/core.h> | 26 | #include <sound/core.h> |
| 26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
| @@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)"); | |||
| 38 | 39 | ||
| 39 | /* codec private data */ | 40 | /* codec private data */ |
| 40 | struct alc5623_priv { | 41 | struct alc5623_priv { |
| 41 | enum snd_soc_control_type control_type; | 42 | struct regmap *regmap; |
| 42 | u8 id; | 43 | u8 id; |
| 43 | unsigned int sysclk; | 44 | unsigned int sysclk; |
| 44 | u16 reg_cache[ALC5623_VENDOR_ID2+2]; | ||
| 45 | unsigned int add_ctrl; | 45 | unsigned int add_ctrl; |
| 46 | unsigned int jack_det_ctrl; | 46 | unsigned int jack_det_ctrl; |
| 47 | }; | 47 | }; |
| 48 | 48 | ||
| 49 | static void alc5623_fill_cache(struct snd_soc_codec *codec) | ||
| 50 | { | ||
| 51 | int i, step = codec->driver->reg_cache_step; | ||
| 52 | u16 *cache = codec->reg_cache; | ||
| 53 | |||
| 54 | /* not really efficient ... */ | ||
| 55 | codec->cache_bypass = 1; | ||
| 56 | for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) | ||
| 57 | cache[i] = snd_soc_read(codec, i); | ||
| 58 | codec->cache_bypass = 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | static inline int alc5623_reset(struct snd_soc_codec *codec) | 49 | static inline int alc5623_reset(struct snd_soc_codec *codec) |
| 62 | { | 50 | { |
| 63 | return snd_soc_write(codec, ALC5623_RESET, 0); | 51 | return snd_soc_write(codec, ALC5623_RESET, 0); |
| @@ -228,32 +216,37 @@ static const char *alc5623_aux_out_input_sel[] = { | |||
| 228 | "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; | 216 | "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; |
| 229 | 217 | ||
| 230 | /* auxout output mux */ | 218 | /* auxout output mux */ |
| 231 | static const struct soc_enum alc5623_aux_out_input_enum = | 219 | static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, |
| 232 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel); | 220 | ALC5623_OUTPUT_MIXER_CTRL, 6, |
| 221 | alc5623_aux_out_input_sel); | ||
| 233 | static const struct snd_kcontrol_new alc5623_auxout_mux_controls = | 222 | static const struct snd_kcontrol_new alc5623_auxout_mux_controls = |
| 234 | SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); | 223 | SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); |
| 235 | 224 | ||
| 236 | /* speaker output mux */ | 225 | /* speaker output mux */ |
| 237 | static const struct soc_enum alc5623_spkout_input_enum = | 226 | static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, |
| 238 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel); | 227 | ALC5623_OUTPUT_MIXER_CTRL, 10, |
| 228 | alc5623_spkout_input_sel); | ||
| 239 | static const struct snd_kcontrol_new alc5623_spkout_mux_controls = | 229 | static const struct snd_kcontrol_new alc5623_spkout_mux_controls = |
| 240 | SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); | 230 | SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); |
| 241 | 231 | ||
| 242 | /* headphone left output mux */ | 232 | /* headphone left output mux */ |
| 243 | static const struct soc_enum alc5623_hpl_out_input_enum = | 233 | static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, |
| 244 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel); | 234 | ALC5623_OUTPUT_MIXER_CTRL, 9, |
| 235 | alc5623_hpl_out_input_sel); | ||
| 245 | static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = | 236 | static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = |
| 246 | SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); | 237 | SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); |
| 247 | 238 | ||
| 248 | /* headphone right output mux */ | 239 | /* headphone right output mux */ |
| 249 | static const struct soc_enum alc5623_hpr_out_input_enum = | 240 | static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, |
| 250 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel); | 241 | ALC5623_OUTPUT_MIXER_CTRL, 8, |
| 242 | alc5623_hpr_out_input_sel); | ||
| 251 | static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = | 243 | static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = |
| 252 | SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); | 244 | SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); |
| 253 | 245 | ||
| 254 | /* speaker output N select */ | 246 | /* speaker output N select */ |
| 255 | static const struct soc_enum alc5623_spk_n_sour_enum = | 247 | static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, |
| 256 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel); | 248 | ALC5623_OUTPUT_MIXER_CTRL, 14, |
| 249 | alc5623_spk_n_sour_sel); | ||
| 257 | static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = | 250 | static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = |
| 258 | SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); | 251 | SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); |
| 259 | 252 | ||
| @@ -338,8 +331,9 @@ SND_SOC_DAPM_VMID("Vmid"), | |||
| 338 | }; | 331 | }; |
| 339 | 332 | ||
| 340 | static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; | 333 | static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; |
| 341 | static const struct soc_enum alc5623_amp_enum = | 334 | static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, |
| 342 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names); | 335 | ALC5623_OUTPUT_MIXER_CTRL, 13, |
| 336 | alc5623_amp_names); | ||
| 343 | static const struct snd_kcontrol_new alc5623_amp_mux_controls = | 337 | static const struct snd_kcontrol_new alc5623_amp_mux_controls = |
| 344 | SOC_DAPM_ENUM("Route", alc5623_amp_enum); | 338 | SOC_DAPM_ENUM("Route", alc5623_amp_enum); |
| 345 | 339 | ||
| @@ -869,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = { | |||
| 869 | 863 | ||
| 870 | static int alc5623_suspend(struct snd_soc_codec *codec) | 864 | static int alc5623_suspend(struct snd_soc_codec *codec) |
| 871 | { | 865 | { |
| 866 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); | ||
| 867 | |||
| 872 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | 868 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 869 | regcache_cache_only(alc5623->regmap, true); | ||
| 870 | |||
| 873 | return 0; | 871 | return 0; |
| 874 | } | 872 | } |
| 875 | 873 | ||
| 876 | static int alc5623_resume(struct snd_soc_codec *codec) | 874 | static int alc5623_resume(struct snd_soc_codec *codec) |
| 877 | { | 875 | { |
| 878 | int i, step = codec->driver->reg_cache_step; | 876 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); |
| 879 | u16 *cache = codec->reg_cache; | 877 | int ret; |
| 880 | 878 | ||
| 881 | /* Sync reg_cache with the hardware */ | 879 | /* Sync reg_cache with the hardware */ |
| 882 | for (i = 2 ; i < codec->driver->reg_cache_size ; i += step) | 880 | regcache_cache_only(alc5623->regmap, false); |
| 883 | snd_soc_write(codec, i, cache[i]); | 881 | ret = regcache_sync(alc5623->regmap); |
| 882 | if (ret != 0) { | ||
| 883 | dev_err(codec->dev, "Failed to sync register cache: %d\n", | ||
| 884 | ret); | ||
| 885 | regcache_cache_only(alc5623->regmap, true); | ||
| 886 | return ret; | ||
| 887 | } | ||
| 884 | 888 | ||
| 885 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 889 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 886 | 890 | ||
| @@ -900,14 +904,14 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
| 900 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 904 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 901 | int ret; | 905 | int ret; |
| 902 | 906 | ||
| 903 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type); | 907 | codec->control_data = alc5623->regmap; |
| 908 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); | ||
| 904 | if (ret < 0) { | 909 | if (ret < 0) { |
| 905 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 910 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 906 | return ret; | 911 | return ret; |
| 907 | } | 912 | } |
| 908 | 913 | ||
| 909 | alc5623_reset(codec); | 914 | alc5623_reset(codec); |
| 910 | alc5623_fill_cache(codec); | ||
| 911 | 915 | ||
| 912 | /* power on device */ | 916 | /* power on device */ |
| 913 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 917 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| @@ -980,9 +984,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { | |||
| 980 | .suspend = alc5623_suspend, | 984 | .suspend = alc5623_suspend, |
| 981 | .resume = alc5623_resume, | 985 | .resume = alc5623_resume, |
| 982 | .set_bias_level = alc5623_set_bias_level, | 986 | .set_bias_level = alc5623_set_bias_level, |
| 983 | .reg_cache_size = ALC5623_VENDOR_ID2+2, | 987 | }; |
| 984 | .reg_word_size = sizeof(u16), | 988 | |
| 985 | .reg_cache_step = 2, | 989 | static const struct regmap_config alc5623_regmap = { |
| 990 | .reg_bits = 8, | ||
| 991 | .val_bits = 16, | ||
| 992 | .reg_stride = 2, | ||
| 993 | |||
| 994 | .max_register = ALC5623_VENDOR_ID2, | ||
| 995 | .cache_type = REGCACHE_RBTREE, | ||
| 986 | }; | 996 | }; |
| 987 | 997 | ||
| 988 | /* | 998 | /* |
| @@ -996,19 +1006,32 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
| 996 | { | 1006 | { |
| 997 | struct alc5623_platform_data *pdata; | 1007 | struct alc5623_platform_data *pdata; |
| 998 | struct alc5623_priv *alc5623; | 1008 | struct alc5623_priv *alc5623; |
| 999 | int ret, vid1, vid2; | 1009 | unsigned int vid1, vid2; |
| 1010 | int ret; | ||
| 1000 | 1011 | ||
| 1001 | vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1); | 1012 | alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), |
| 1002 | if (vid1 < 0) { | 1013 | GFP_KERNEL); |
| 1003 | dev_err(&client->dev, "failed to read I2C\n"); | 1014 | if (alc5623 == NULL) |
| 1004 | return -EIO; | 1015 | return -ENOMEM; |
| 1016 | |||
| 1017 | alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); | ||
| 1018 | if (IS_ERR(alc5623->regmap)) { | ||
| 1019 | ret = PTR_ERR(alc5623->regmap); | ||
| 1020 | dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); | ||
| 1021 | return ret; | ||
| 1022 | } | ||
| 1023 | |||
| 1024 | ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); | ||
| 1025 | if (ret < 0) { | ||
| 1026 | dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); | ||
| 1027 | return ret; | ||
| 1005 | } | 1028 | } |
| 1006 | vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); | 1029 | vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); |
| 1007 | 1030 | ||
| 1008 | vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2); | 1031 | ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); |
| 1009 | if (vid2 < 0) { | 1032 | if (ret < 0) { |
| 1010 | dev_err(&client->dev, "failed to read I2C\n"); | 1033 | dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); |
| 1011 | return -EIO; | 1034 | return ret; |
| 1012 | } | 1035 | } |
| 1013 | 1036 | ||
| 1014 | if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { | 1037 | if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { |
| @@ -1021,11 +1044,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
| 1021 | 1044 | ||
| 1022 | dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); | 1045 | dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); |
| 1023 | 1046 | ||
| 1024 | alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), | ||
| 1025 | GFP_KERNEL); | ||
| 1026 | if (alc5623 == NULL) | ||
| 1027 | return -ENOMEM; | ||
| 1028 | |||
| 1029 | pdata = client->dev.platform_data; | 1047 | pdata = client->dev.platform_data; |
| 1030 | if (pdata) { | 1048 | if (pdata) { |
| 1031 | alc5623->add_ctrl = pdata->add_ctrl; | 1049 | alc5623->add_ctrl = pdata->add_ctrl; |
| @@ -1048,7 +1066,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
| 1048 | } | 1066 | } |
| 1049 | 1067 | ||
| 1050 | i2c_set_clientdata(client, alc5623); | 1068 | i2c_set_clientdata(client, alc5623); |
| 1051 | alc5623->control_type = SND_SOC_I2C; | ||
| 1052 | 1069 | ||
| 1053 | ret = snd_soc_register_codec(&client->dev, | 1070 | ret = snd_soc_register_codec(&client->dev, |
| 1054 | &soc_codec_device_alc5623, &alc5623_dai, 1); | 1071 | &soc_codec_device_alc5623, &alc5623_dai, 1); |
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index fb001c56cf8d..d885056ad8f2 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c | |||
| @@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = { | |||
| 293 | "ADC LR", "Voice Stereo Digital"}; | 293 | "ADC LR", "Voice Stereo Digital"}; |
| 294 | 294 | ||
| 295 | /* auxout output mux */ | 295 | /* auxout output mux */ |
| 296 | static const struct soc_enum alc5632_aux_out_input_enum = | 296 | static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum, |
| 297 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel); | 297 | ALC5632_OUTPUT_MIXER_CTRL, 6, |
| 298 | alc5632_aux_out_input_sel); | ||
| 298 | static const struct snd_kcontrol_new alc5632_auxout_mux_controls = | 299 | static const struct snd_kcontrol_new alc5632_auxout_mux_controls = |
| 299 | SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); | 300 | SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); |
| 300 | 301 | ||
| 301 | /* speaker output mux */ | 302 | /* speaker output mux */ |
| 302 | static const struct soc_enum alc5632_spkout_input_enum = | 303 | static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum, |
| 303 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel); | 304 | ALC5632_OUTPUT_MIXER_CTRL, 10, |
| 305 | alc5632_spkout_input_sel); | ||
| 304 | static const struct snd_kcontrol_new alc5632_spkout_mux_controls = | 306 | static const struct snd_kcontrol_new alc5632_spkout_mux_controls = |
| 305 | SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); | 307 | SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); |
| 306 | 308 | ||
| 307 | /* headphone left output mux */ | 309 | /* headphone left output mux */ |
| 308 | static const struct soc_enum alc5632_hpl_out_input_enum = | 310 | static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum, |
| 309 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel); | 311 | ALC5632_OUTPUT_MIXER_CTRL, 9, |
| 312 | alc5632_hpl_out_input_sel); | ||
| 310 | static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = | 313 | static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = |
| 311 | SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); | 314 | SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); |
| 312 | 315 | ||
| 313 | /* headphone right output mux */ | 316 | /* headphone right output mux */ |
| 314 | static const struct soc_enum alc5632_hpr_out_input_enum = | 317 | static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum, |
| 315 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel); | 318 | ALC5632_OUTPUT_MIXER_CTRL, 8, |
| 319 | alc5632_hpr_out_input_sel); | ||
| 316 | static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = | 320 | static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = |
| 317 | SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); | 321 | SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); |
| 318 | 322 | ||
| 319 | /* speaker output N select */ | 323 | /* speaker output N select */ |
| 320 | static const struct soc_enum alc5632_spk_n_sour_enum = | 324 | static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum, |
| 321 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel); | 325 | ALC5632_OUTPUT_MIXER_CTRL, 14, |
| 326 | alc5632_spk_n_sour_sel); | ||
| 322 | static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = | 327 | static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = |
| 323 | SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); | 328 | SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); |
| 324 | 329 | ||
| 325 | /* speaker amplifier */ | 330 | /* speaker amplifier */ |
| 326 | static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; | 331 | static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; |
| 327 | static const struct soc_enum alc5632_amp_enum = | 332 | static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum, |
| 328 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names); | 333 | ALC5632_OUTPUT_MIXER_CTRL, 13, |
| 334 | alc5632_amp_names); | ||
| 329 | static const struct snd_kcontrol_new alc5632_amp_mux_controls = | 335 | static const struct snd_kcontrol_new alc5632_amp_mux_controls = |
| 330 | SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); | 336 | SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); |
| 331 | 337 | ||
| 332 | /* ADC output select */ | 338 | /* ADC output select */ |
| 333 | static const struct soc_enum alc5632_adcr_func_enum = | 339 | static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum, |
| 334 | SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); | 340 | ALC5632_DAC_FUNC_SELECT, 5, |
| 341 | alc5632_adcr_func_sel); | ||
| 335 | static const struct snd_kcontrol_new alc5632_adcr_func_controls = | 342 | static const struct snd_kcontrol_new alc5632_adcr_func_controls = |
| 336 | SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); | 343 | SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); |
| 337 | 344 | ||
| 338 | /* I2S out select */ | 345 | /* I2S out select */ |
| 339 | static const struct soc_enum alc5632_i2s_out_enum = | 346 | static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum, |
| 340 | SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); | 347 | ALC5632_I2S_OUT_CTL, 5, |
| 348 | alc5632_i2s_out_sel); | ||
| 341 | static const struct snd_kcontrol_new alc5632_i2s_out_controls = | 349 | static const struct snd_kcontrol_new alc5632_i2s_out_controls = |
| 342 | SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); | 350 | SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); |
| 343 | 351 | ||
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e4295fee8f13..29e198f57d4c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
| @@ -53,6 +53,14 @@ | |||
| 53 | #define ARIZONA_AIF_RX_ENABLES 0x1A | 53 | #define ARIZONA_AIF_RX_ENABLES 0x1A |
| 54 | #define ARIZONA_AIF_FORCE_WRITE 0x1B | 54 | #define ARIZONA_AIF_FORCE_WRITE 0x1B |
| 55 | 55 | ||
| 56 | #define ARIZONA_FLL_VCO_CORNER 141900000 | ||
| 57 | #define ARIZONA_FLL_MAX_FREF 13500000 | ||
| 58 | #define ARIZONA_FLL_MIN_FVCO 90000000 | ||
| 59 | #define ARIZONA_FLL_MAX_FRATIO 16 | ||
| 60 | #define ARIZONA_FLL_MAX_REFDIV 8 | ||
| 61 | #define ARIZONA_FLL_MIN_OUTDIV 2 | ||
| 62 | #define ARIZONA_FLL_MAX_OUTDIV 7 | ||
| 63 | |||
| 56 | #define arizona_fll_err(_fll, fmt, ...) \ | 64 | #define arizona_fll_err(_fll, fmt, ...) \ |
| 57 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 65 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
| 58 | #define arizona_fll_warn(_fll, fmt, ...) \ | 66 | #define arizona_fll_warn(_fll, fmt, ...) \ |
| @@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = { | |||
| 542 | "15ms/6dB", "30ms/6dB", | 550 | "15ms/6dB", "30ms/6dB", |
| 543 | }; | 551 | }; |
| 544 | 552 | ||
| 545 | const struct soc_enum arizona_in_vd_ramp = | 553 | SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp, |
| 546 | SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, | 554 | ARIZONA_INPUT_VOLUME_RAMP, |
| 547 | ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 555 | ARIZONA_IN_VD_RAMP_SHIFT, |
| 556 | arizona_vol_ramp_text); | ||
| 548 | EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); | 557 | EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); |
| 549 | 558 | ||
| 550 | const struct soc_enum arizona_in_vi_ramp = | 559 | SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp, |
| 551 | SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, | 560 | ARIZONA_INPUT_VOLUME_RAMP, |
| 552 | ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 561 | ARIZONA_IN_VI_RAMP_SHIFT, |
| 562 | arizona_vol_ramp_text); | ||
| 553 | EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); | 563 | EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); |
| 554 | 564 | ||
| 555 | const struct soc_enum arizona_out_vd_ramp = | 565 | SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp, |
| 556 | SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, | 566 | ARIZONA_OUTPUT_VOLUME_RAMP, |
| 557 | ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 567 | ARIZONA_OUT_VD_RAMP_SHIFT, |
| 568 | arizona_vol_ramp_text); | ||
| 558 | EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); | 569 | EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); |
| 559 | 570 | ||
| 560 | const struct soc_enum arizona_out_vi_ramp = | 571 | SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp, |
| 561 | SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, | 572 | ARIZONA_OUTPUT_VOLUME_RAMP, |
| 562 | ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 573 | ARIZONA_OUT_VI_RAMP_SHIFT, |
| 574 | arizona_vol_ramp_text); | ||
| 563 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); | 575 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); |
| 564 | 576 | ||
| 565 | static const char *arizona_lhpf_mode_text[] = { | 577 | static const char *arizona_lhpf_mode_text[] = { |
| 566 | "Low-pass", "High-pass" | 578 | "Low-pass", "High-pass" |
| 567 | }; | 579 | }; |
| 568 | 580 | ||
| 569 | const struct soc_enum arizona_lhpf1_mode = | 581 | SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode, |
| 570 | SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2, | 582 | ARIZONA_HPLPF1_1, |
| 571 | arizona_lhpf_mode_text); | 583 | ARIZONA_LHPF1_MODE_SHIFT, |
| 584 | arizona_lhpf_mode_text); | ||
| 572 | EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); | 585 | EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); |
| 573 | 586 | ||
| 574 | const struct soc_enum arizona_lhpf2_mode = | 587 | SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode, |
| 575 | SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2, | 588 | ARIZONA_HPLPF2_1, |
| 576 | arizona_lhpf_mode_text); | 589 | ARIZONA_LHPF2_MODE_SHIFT, |
| 590 | arizona_lhpf_mode_text); | ||
| 577 | EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); | 591 | EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); |
| 578 | 592 | ||
| 579 | const struct soc_enum arizona_lhpf3_mode = | 593 | SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode, |
| 580 | SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2, | 594 | ARIZONA_HPLPF3_1, |
| 581 | arizona_lhpf_mode_text); | 595 | ARIZONA_LHPF3_MODE_SHIFT, |
| 596 | arizona_lhpf_mode_text); | ||
| 582 | EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); | 597 | EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); |
| 583 | 598 | ||
| 584 | const struct soc_enum arizona_lhpf4_mode = | 599 | SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode, |
| 585 | SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2, | 600 | ARIZONA_HPLPF4_1, |
| 586 | arizona_lhpf_mode_text); | 601 | ARIZONA_LHPF4_MODE_SHIFT, |
| 602 | arizona_lhpf_mode_text); | ||
| 587 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); | 603 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); |
| 588 | 604 | ||
| 589 | static const char *arizona_ng_hold_text[] = { | 605 | static const char *arizona_ng_hold_text[] = { |
| 590 | "30ms", "120ms", "250ms", "500ms", | 606 | "30ms", "120ms", "250ms", "500ms", |
| 591 | }; | 607 | }; |
| 592 | 608 | ||
| 593 | const struct soc_enum arizona_ng_hold = | 609 | SOC_ENUM_SINGLE_DECL(arizona_ng_hold, |
| 594 | SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, | 610 | ARIZONA_NOISE_GATE_CONTROL, |
| 595 | 4, arizona_ng_hold_text); | 611 | ARIZONA_NGATE_HOLD_SHIFT, |
| 612 | arizona_ng_hold_text); | ||
| 596 | EXPORT_SYMBOL_GPL(arizona_ng_hold); | 613 | EXPORT_SYMBOL_GPL(arizona_ng_hold); |
| 597 | 614 | ||
| 598 | static const char * const arizona_in_hpf_cut_text[] = { | 615 | static const char * const arizona_in_hpf_cut_text[] = { |
| 599 | "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" | 616 | "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" |
| 600 | }; | 617 | }; |
| 601 | 618 | ||
| 602 | const struct soc_enum arizona_in_hpf_cut_enum = | 619 | SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, |
| 603 | SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, | 620 | ARIZONA_HPF_CONTROL, |
| 604 | ARRAY_SIZE(arizona_in_hpf_cut_text), | 621 | ARIZONA_IN_HPF_CUT_SHIFT, |
| 605 | arizona_in_hpf_cut_text); | 622 | arizona_in_hpf_cut_text); |
| 606 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); | 623 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); |
| 607 | 624 | ||
| 608 | static const char * const arizona_in_dmic_osr_text[] = { | 625 | static const char * const arizona_in_dmic_osr_text[] = { |
| @@ -1377,74 +1394,147 @@ struct arizona_fll_cfg { | |||
| 1377 | int gain; | 1394 | int gain; |
| 1378 | }; | 1395 | }; |
| 1379 | 1396 | ||
| 1380 | static int arizona_calc_fll(struct arizona_fll *fll, | 1397 | static int arizona_validate_fll(struct arizona_fll *fll, |
| 1381 | struct arizona_fll_cfg *cfg, | 1398 | unsigned int Fref, |
| 1382 | unsigned int Fref, | 1399 | unsigned int Fout) |
| 1383 | unsigned int Fout) | ||
| 1384 | { | 1400 | { |
| 1385 | unsigned int target, div, gcd_fll; | 1401 | unsigned int Fvco_min; |
| 1386 | int i, ratio; | 1402 | |
| 1403 | if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { | ||
| 1404 | arizona_fll_err(fll, | ||
| 1405 | "Can't scale %dMHz in to <=13.5MHz\n", | ||
| 1406 | Fref); | ||
| 1407 | return -EINVAL; | ||
| 1408 | } | ||
| 1387 | 1409 | ||
| 1388 | arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); | 1410 | Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult; |
| 1411 | if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) { | ||
| 1412 | arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", | ||
| 1413 | Fout); | ||
| 1414 | return -EINVAL; | ||
| 1415 | } | ||
| 1416 | |||
| 1417 | return 0; | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | static int arizona_find_fratio(unsigned int Fref, int *fratio) | ||
| 1421 | { | ||
| 1422 | int i; | ||
| 1423 | |||
| 1424 | /* Find an appropriate FLL_FRATIO */ | ||
| 1425 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | ||
| 1426 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | ||
| 1427 | if (fratio) | ||
| 1428 | *fratio = fll_fratios[i].fratio; | ||
| 1429 | return fll_fratios[i].ratio; | ||
| 1430 | } | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | return -EINVAL; | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | static int arizona_calc_fratio(struct arizona_fll *fll, | ||
| 1437 | struct arizona_fll_cfg *cfg, | ||
| 1438 | unsigned int target, | ||
| 1439 | unsigned int Fref, bool sync) | ||
| 1440 | { | ||
| 1441 | int init_ratio, ratio; | ||
| 1442 | int refdiv, div; | ||
| 1389 | 1443 | ||
| 1390 | /* Fref must be <=13.5MHz */ | 1444 | /* Fref must be <=13.5MHz, find initial refdiv */ |
| 1391 | div = 1; | 1445 | div = 1; |
| 1392 | cfg->refdiv = 0; | 1446 | cfg->refdiv = 0; |
| 1393 | while ((Fref / div) > 13500000) { | 1447 | while (Fref > ARIZONA_FLL_MAX_FREF) { |
| 1394 | div *= 2; | 1448 | div *= 2; |
| 1449 | Fref /= 2; | ||
| 1395 | cfg->refdiv++; | 1450 | cfg->refdiv++; |
| 1396 | 1451 | ||
| 1397 | if (div > 8) { | 1452 | if (div > ARIZONA_FLL_MAX_REFDIV) |
| 1398 | arizona_fll_err(fll, | ||
| 1399 | "Can't scale %dMHz in to <=13.5MHz\n", | ||
| 1400 | Fref); | ||
| 1401 | return -EINVAL; | 1453 | return -EINVAL; |
| 1454 | } | ||
| 1455 | |||
| 1456 | /* Find an appropriate FLL_FRATIO */ | ||
| 1457 | init_ratio = arizona_find_fratio(Fref, &cfg->fratio); | ||
| 1458 | if (init_ratio < 0) { | ||
| 1459 | arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", | ||
| 1460 | Fref); | ||
| 1461 | return init_ratio; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | switch (fll->arizona->type) { | ||
| 1465 | case WM5110: | ||
| 1466 | if (fll->arizona->rev < 3 || sync) | ||
| 1467 | return init_ratio; | ||
| 1468 | break; | ||
| 1469 | default: | ||
| 1470 | return init_ratio; | ||
| 1471 | } | ||
| 1472 | |||
| 1473 | cfg->fratio = init_ratio - 1; | ||
| 1474 | |||
| 1475 | /* Adjust FRATIO/refdiv to avoid integer mode if possible */ | ||
| 1476 | refdiv = cfg->refdiv; | ||
| 1477 | |||
| 1478 | while (div <= ARIZONA_FLL_MAX_REFDIV) { | ||
| 1479 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; | ||
| 1480 | ratio++) { | ||
| 1481 | if (target % (ratio * Fref)) { | ||
| 1482 | cfg->refdiv = refdiv; | ||
| 1483 | cfg->fratio = ratio - 1; | ||
| 1484 | return ratio; | ||
| 1485 | } | ||
| 1402 | } | 1486 | } |
| 1487 | |||
| 1488 | for (ratio = init_ratio - 1; ratio >= 0; ratio--) { | ||
| 1489 | if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < | ||
| 1490 | Fref) | ||
| 1491 | break; | ||
| 1492 | |||
| 1493 | if (target % (ratio * Fref)) { | ||
| 1494 | cfg->refdiv = refdiv; | ||
| 1495 | cfg->fratio = ratio - 1; | ||
| 1496 | return ratio; | ||
| 1497 | } | ||
| 1498 | } | ||
| 1499 | |||
| 1500 | div *= 2; | ||
| 1501 | Fref /= 2; | ||
| 1502 | refdiv++; | ||
| 1503 | init_ratio = arizona_find_fratio(Fref, NULL); | ||
| 1403 | } | 1504 | } |
| 1404 | 1505 | ||
| 1405 | /* Apply the division for our remaining calculations */ | 1506 | arizona_fll_warn(fll, "Falling back to integer mode operation\n"); |
| 1406 | Fref /= div; | 1507 | return cfg->fratio + 1; |
| 1508 | } | ||
| 1509 | |||
| 1510 | static int arizona_calc_fll(struct arizona_fll *fll, | ||
| 1511 | struct arizona_fll_cfg *cfg, | ||
| 1512 | unsigned int Fref, bool sync) | ||
| 1513 | { | ||
| 1514 | unsigned int target, div, gcd_fll; | ||
| 1515 | int i, ratio; | ||
| 1516 | |||
| 1517 | arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout); | ||
| 1407 | 1518 | ||
| 1408 | /* Fvco should be over the targt; don't check the upper bound */ | 1519 | /* Fvco should be over the targt; don't check the upper bound */ |
| 1409 | div = 1; | 1520 | div = ARIZONA_FLL_MIN_OUTDIV; |
| 1410 | while (Fout * div < 90000000 * fll->vco_mult) { | 1521 | while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) { |
| 1411 | div++; | 1522 | div++; |
| 1412 | if (div > 7) { | 1523 | if (div > ARIZONA_FLL_MAX_OUTDIV) |
| 1413 | arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", | ||
| 1414 | Fout); | ||
| 1415 | return -EINVAL; | 1524 | return -EINVAL; |
| 1416 | } | ||
| 1417 | } | 1525 | } |
| 1418 | target = Fout * div / fll->vco_mult; | 1526 | target = fll->fout * div / fll->vco_mult; |
| 1419 | cfg->outdiv = div; | 1527 | cfg->outdiv = div; |
| 1420 | 1528 | ||
| 1421 | arizona_fll_dbg(fll, "Fvco=%dHz\n", target); | 1529 | arizona_fll_dbg(fll, "Fvco=%dHz\n", target); |
| 1422 | 1530 | ||
| 1423 | /* Find an appropraite FLL_FRATIO and factor it out of the target */ | 1531 | /* Find an appropriate FLL_FRATIO and refdiv */ |
| 1424 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | 1532 | ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync); |
| 1425 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | 1533 | if (ratio < 0) |
| 1426 | cfg->fratio = fll_fratios[i].fratio; | 1534 | return ratio; |
| 1427 | ratio = fll_fratios[i].ratio; | ||
| 1428 | break; | ||
| 1429 | } | ||
| 1430 | } | ||
| 1431 | if (i == ARRAY_SIZE(fll_fratios)) { | ||
| 1432 | arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", | ||
| 1433 | Fref); | ||
| 1434 | return -EINVAL; | ||
| 1435 | } | ||
| 1436 | 1535 | ||
| 1437 | for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { | 1536 | /* Apply the division for our remaining calculations */ |
| 1438 | if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { | 1537 | Fref = Fref / (1 << cfg->refdiv); |
| 1439 | cfg->gain = fll_gains[i].gain; | ||
| 1440 | break; | ||
| 1441 | } | ||
| 1442 | } | ||
| 1443 | if (i == ARRAY_SIZE(fll_gains)) { | ||
| 1444 | arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", | ||
| 1445 | Fref); | ||
| 1446 | return -EINVAL; | ||
| 1447 | } | ||
| 1448 | 1538 | ||
| 1449 | cfg->n = target / (ratio * Fref); | 1539 | cfg->n = target / (ratio * Fref); |
| 1450 | 1540 | ||
| @@ -1469,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, | |||
| 1469 | cfg->lambda >>= 1; | 1559 | cfg->lambda >>= 1; |
| 1470 | } | 1560 | } |
| 1471 | 1561 | ||
| 1562 | for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { | ||
| 1563 | if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { | ||
| 1564 | cfg->gain = fll_gains[i].gain; | ||
| 1565 | break; | ||
| 1566 | } | ||
| 1567 | } | ||
| 1568 | if (i == ARRAY_SIZE(fll_gains)) { | ||
| 1569 | arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", | ||
| 1570 | Fref); | ||
| 1571 | return -EINVAL; | ||
| 1572 | } | ||
| 1573 | |||
| 1472 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", | 1574 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", |
| 1473 | cfg->n, cfg->theta, cfg->lambda); | 1575 | cfg->n, cfg->theta, cfg->lambda); |
| 1474 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", | 1576 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", |
| @@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, | |||
| 1496 | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | | 1598 | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | |
| 1497 | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); | 1599 | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); |
| 1498 | 1600 | ||
| 1499 | if (sync) | 1601 | if (sync) { |
| 1500 | regmap_update_bits_async(arizona->regmap, base + 0x7, | 1602 | regmap_update_bits(arizona->regmap, base + 0x7, |
| 1501 | ARIZONA_FLL1_GAIN_MASK, | 1603 | ARIZONA_FLL1_GAIN_MASK, |
| 1502 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | 1604 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); |
| 1503 | else | 1605 | } else { |
| 1504 | regmap_update_bits_async(arizona->regmap, base + 0x9, | 1606 | regmap_update_bits(arizona->regmap, base + 0x5, |
| 1505 | ARIZONA_FLL1_GAIN_MASK, | 1607 | ARIZONA_FLL1_OUTDIV_MASK, |
| 1506 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | 1608 | cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); |
| 1609 | regmap_update_bits(arizona->regmap, base + 0x9, | ||
| 1610 | ARIZONA_FLL1_GAIN_MASK, | ||
| 1611 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | ||
| 1612 | } | ||
| 1507 | 1613 | ||
| 1508 | regmap_update_bits_async(arizona->regmap, base + 2, | 1614 | regmap_update_bits_async(arizona->regmap, base + 2, |
| 1509 | ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, | 1615 | ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, |
| @@ -1526,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) | |||
| 1526 | return reg & ARIZONA_FLL1_ENA; | 1632 | return reg & ARIZONA_FLL1_ENA; |
| 1527 | } | 1633 | } |
| 1528 | 1634 | ||
| 1529 | static void arizona_enable_fll(struct arizona_fll *fll, | 1635 | static void arizona_enable_fll(struct arizona_fll *fll) |
| 1530 | struct arizona_fll_cfg *ref, | ||
| 1531 | struct arizona_fll_cfg *sync) | ||
| 1532 | { | 1636 | { |
| 1533 | struct arizona *arizona = fll->arizona; | 1637 | struct arizona *arizona = fll->arizona; |
| 1534 | int ret; | 1638 | int ret; |
| 1535 | bool use_sync = false; | 1639 | bool use_sync = false; |
| 1640 | struct arizona_fll_cfg cfg; | ||
| 1536 | 1641 | ||
| 1537 | /* | 1642 | /* |
| 1538 | * If we have both REFCLK and SYNCCLK then enable both, | 1643 | * If we have both REFCLK and SYNCCLK then enable both, |
| @@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll, | |||
| 1540 | */ | 1645 | */ |
| 1541 | if (fll->ref_src >= 0 && fll->ref_freq && | 1646 | if (fll->ref_src >= 0 && fll->ref_freq && |
| 1542 | fll->ref_src != fll->sync_src) { | 1647 | fll->ref_src != fll->sync_src) { |
| 1543 | regmap_update_bits_async(arizona->regmap, fll->base + 5, | 1648 | arizona_calc_fll(fll, &cfg, fll->ref_freq, false); |
| 1544 | ARIZONA_FLL1_OUTDIV_MASK, | ||
| 1545 | ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); | ||
| 1546 | 1649 | ||
| 1547 | arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, | 1650 | arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src, |
| 1548 | false); | 1651 | false); |
| 1549 | if (fll->sync_src >= 0) { | 1652 | if (fll->sync_src >= 0) { |
| 1550 | arizona_apply_fll(arizona, fll->base + 0x10, sync, | 1653 | arizona_calc_fll(fll, &cfg, fll->sync_freq, true); |
| 1654 | |||
| 1655 | arizona_apply_fll(arizona, fll->base + 0x10, &cfg, | ||
| 1551 | fll->sync_src, true); | 1656 | fll->sync_src, true); |
| 1552 | use_sync = true; | 1657 | use_sync = true; |
| 1553 | } | 1658 | } |
| 1554 | } else if (fll->sync_src >= 0) { | 1659 | } else if (fll->sync_src >= 0) { |
| 1555 | regmap_update_bits_async(arizona->regmap, fll->base + 5, | 1660 | arizona_calc_fll(fll, &cfg, fll->sync_freq, false); |
| 1556 | ARIZONA_FLL1_OUTDIV_MASK, | ||
| 1557 | sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); | ||
| 1558 | 1661 | ||
| 1559 | arizona_apply_fll(arizona, fll->base, sync, | 1662 | arizona_apply_fll(arizona, fll->base, &cfg, |
| 1560 | fll->sync_src, false); | 1663 | fll->sync_src, false); |
| 1561 | 1664 | ||
| 1562 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, | 1665 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, |
| @@ -1618,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll) | |||
| 1618 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, | 1721 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, |
| 1619 | unsigned int Fref, unsigned int Fout) | 1722 | unsigned int Fref, unsigned int Fout) |
| 1620 | { | 1723 | { |
| 1621 | struct arizona_fll_cfg ref, sync; | ||
| 1622 | int ret; | 1724 | int ret; |
| 1623 | 1725 | ||
| 1624 | if (fll->ref_src == source && fll->ref_freq == Fref) | 1726 | if (fll->ref_src == source && fll->ref_freq == Fref) |
| 1625 | return 0; | 1727 | return 0; |
| 1626 | 1728 | ||
| 1627 | if (fll->fout) { | 1729 | if (fll->fout && Fref > 0) { |
| 1628 | if (Fref > 0) { | 1730 | ret = arizona_validate_fll(fll, Fref, fll->fout); |
| 1629 | ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); | 1731 | if (ret != 0) |
| 1630 | if (ret != 0) | 1732 | return ret; |
| 1631 | return ret; | ||
| 1632 | } | ||
| 1633 | |||
| 1634 | if (fll->sync_src >= 0) { | ||
| 1635 | ret = arizona_calc_fll(fll, &sync, fll->sync_freq, | ||
| 1636 | fll->fout); | ||
| 1637 | if (ret != 0) | ||
| 1638 | return ret; | ||
| 1639 | } | ||
| 1640 | } | 1733 | } |
| 1641 | 1734 | ||
| 1642 | fll->ref_src = source; | 1735 | fll->ref_src = source; |
| 1643 | fll->ref_freq = Fref; | 1736 | fll->ref_freq = Fref; |
| 1644 | 1737 | ||
| 1645 | if (fll->fout && Fref > 0) { | 1738 | if (fll->fout && Fref > 0) { |
| 1646 | arizona_enable_fll(fll, &ref, &sync); | 1739 | arizona_enable_fll(fll); |
| 1647 | } | 1740 | } |
| 1648 | 1741 | ||
| 1649 | return 0; | 1742 | return 0; |
| @@ -1653,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); | |||
| 1653 | int arizona_set_fll(struct arizona_fll *fll, int source, | 1746 | int arizona_set_fll(struct arizona_fll *fll, int source, |
| 1654 | unsigned int Fref, unsigned int Fout) | 1747 | unsigned int Fref, unsigned int Fout) |
| 1655 | { | 1748 | { |
| 1656 | struct arizona_fll_cfg ref, sync; | ||
| 1657 | int ret; | 1749 | int ret; |
| 1658 | 1750 | ||
| 1659 | if (fll->sync_src == source && | 1751 | if (fll->sync_src == source && |
| @@ -1662,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, | |||
| 1662 | 1754 | ||
| 1663 | if (Fout) { | 1755 | if (Fout) { |
| 1664 | if (fll->ref_src >= 0) { | 1756 | if (fll->ref_src >= 0) { |
| 1665 | ret = arizona_calc_fll(fll, &ref, fll->ref_freq, | 1757 | ret = arizona_validate_fll(fll, fll->ref_freq, Fout); |
| 1666 | Fout); | ||
| 1667 | if (ret != 0) | 1758 | if (ret != 0) |
| 1668 | return ret; | 1759 | return ret; |
| 1669 | } | 1760 | } |
| 1670 | 1761 | ||
| 1671 | ret = arizona_calc_fll(fll, &sync, Fref, Fout); | 1762 | ret = arizona_validate_fll(fll, Fref, Fout); |
| 1672 | if (ret != 0) | 1763 | if (ret != 0) |
| 1673 | return ret; | 1764 | return ret; |
| 1674 | } | 1765 | } |
| @@ -1678,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, | |||
| 1678 | fll->fout = Fout; | 1769 | fll->fout = Fout; |
| 1679 | 1770 | ||
| 1680 | if (Fout) { | 1771 | if (Fout) { |
| 1681 | arizona_enable_fll(fll, &ref, &sync); | 1772 | arizona_enable_fll(fll); |
| 1682 | } else { | 1773 | } else { |
| 1683 | arizona_disable_fll(fll); | 1774 | arizona_disable_fll(fll); |
| 1684 | } | 1775 | } |
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index ce05fd93dc74..aef4965750c7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
| @@ -159,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg) | |||
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | struct cs4271_private { | 161 | struct cs4271_private { |
| 162 | /* SND_SOC_I2C or SND_SOC_SPI */ | ||
| 163 | unsigned int mclk; | 162 | unsigned int mclk; |
| 164 | bool master; | 163 | bool master; |
| 165 | bool deemph; | 164 | bool deemph; |
| @@ -540,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
| 540 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
| 541 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | 540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; |
| 542 | int ret; | 541 | int ret; |
| 543 | int gpio_nreset = -EINVAL; | ||
| 544 | bool amutec_eq_bmutec = false; | 542 | bool amutec_eq_bmutec = false; |
| 545 | 543 | ||
| 546 | #ifdef CONFIG_OF | 544 | #ifdef CONFIG_OF |
| 547 | if (of_match_device(cs4271_dt_ids, codec->dev)) { | 545 | if (of_match_device(cs4271_dt_ids, codec->dev)) { |
| 548 | gpio_nreset = of_get_named_gpio(codec->dev->of_node, | ||
| 549 | "reset-gpio", 0); | ||
| 550 | |||
| 551 | if (of_get_property(codec->dev->of_node, | 546 | if (of_get_property(codec->dev->of_node, |
| 552 | "cirrus,amutec-eq-bmutec", NULL)) | 547 | "cirrus,amutec-eq-bmutec", NULL)) |
| 553 | amutec_eq_bmutec = true; | 548 | amutec_eq_bmutec = true; |
| @@ -559,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
| 559 | #endif | 554 | #endif |
| 560 | 555 | ||
| 561 | if (cs4271plat) { | 556 | if (cs4271plat) { |
| 562 | if (gpio_is_valid(cs4271plat->gpio_nreset)) | ||
| 563 | gpio_nreset = cs4271plat->gpio_nreset; | ||
| 564 | |||
| 565 | amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; | 557 | amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; |
| 566 | cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; | 558 | cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; |
| 567 | } | 559 | } |
| 568 | 560 | ||
| 569 | if (gpio_nreset >= 0) | 561 | if (gpio_is_valid(cs4271->gpio_nreset)) { |
| 570 | if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) | ||
| 571 | gpio_nreset = -EINVAL; | ||
| 572 | if (gpio_nreset >= 0) { | ||
| 573 | /* Reset codec */ | 562 | /* Reset codec */ |
| 574 | gpio_direction_output(gpio_nreset, 0); | 563 | gpio_direction_output(cs4271->gpio_nreset, 0); |
| 575 | udelay(1); | 564 | udelay(1); |
| 576 | gpio_set_value(gpio_nreset, 1); | 565 | gpio_set_value(cs4271->gpio_nreset, 1); |
| 577 | /* Give the codec time to wake up */ | 566 | /* Give the codec time to wake up */ |
| 578 | udelay(1); | 567 | udelay(1); |
| 579 | } | 568 | } |
| 580 | 569 | ||
| 581 | cs4271->gpio_nreset = gpio_nreset; | ||
| 582 | |||
| 583 | ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, | 570 | ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, |
| 584 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN, | 571 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN, |
| 585 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); | 572 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); |
| @@ -625,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | |||
| 625 | .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), | 612 | .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), |
| 626 | }; | 613 | }; |
| 627 | 614 | ||
| 615 | static int cs4271_common_probe(struct device *dev, | ||
| 616 | struct cs4271_private **c) | ||
| 617 | { | ||
| 618 | struct cs4271_platform_data *cs4271plat = dev->platform_data; | ||
| 619 | struct cs4271_private *cs4271; | ||
| 620 | |||
| 621 | cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL); | ||
| 622 | if (!cs4271) | ||
| 623 | return -ENOMEM; | ||
| 624 | |||
| 625 | if (of_match_device(cs4271_dt_ids, dev)) | ||
| 626 | cs4271->gpio_nreset = | ||
| 627 | of_get_named_gpio(dev->of_node, "reset-gpio", 0); | ||
| 628 | |||
| 629 | if (cs4271plat) | ||
| 630 | cs4271->gpio_nreset = cs4271plat->gpio_nreset; | ||
| 631 | |||
| 632 | if (gpio_is_valid(cs4271->gpio_nreset)) { | ||
| 633 | int ret; | ||
| 634 | |||
| 635 | ret = devm_gpio_request(dev, cs4271->gpio_nreset, | ||
| 636 | "CS4271 Reset"); | ||
| 637 | if (ret < 0) | ||
| 638 | return ret; | ||
| 639 | } | ||
| 640 | |||
| 641 | *c = cs4271; | ||
| 642 | return 0; | ||
| 643 | } | ||
| 644 | |||
| 628 | #if defined(CONFIG_SPI_MASTER) | 645 | #if defined(CONFIG_SPI_MASTER) |
| 629 | 646 | ||
| 630 | static const struct regmap_config cs4271_spi_regmap = { | 647 | static const struct regmap_config cs4271_spi_regmap = { |
| @@ -644,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = { | |||
| 644 | static int cs4271_spi_probe(struct spi_device *spi) | 661 | static int cs4271_spi_probe(struct spi_device *spi) |
| 645 | { | 662 | { |
| 646 | struct cs4271_private *cs4271; | 663 | struct cs4271_private *cs4271; |
| 664 | int ret; | ||
| 647 | 665 | ||
| 648 | cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); | 666 | ret = cs4271_common_probe(&spi->dev, &cs4271); |
| 649 | if (!cs4271) | 667 | if (ret < 0) |
| 650 | return -ENOMEM; | 668 | return ret; |
| 651 | 669 | ||
| 652 | spi_set_drvdata(spi, cs4271); | 670 | spi_set_drvdata(spi, cs4271); |
| 653 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); | 671 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); |
| @@ -698,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client, | |||
| 698 | const struct i2c_device_id *id) | 716 | const struct i2c_device_id *id) |
| 699 | { | 717 | { |
| 700 | struct cs4271_private *cs4271; | 718 | struct cs4271_private *cs4271; |
| 719 | int ret; | ||
| 701 | 720 | ||
| 702 | cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); | 721 | ret = cs4271_common_probe(&client->dev, &cs4271); |
| 703 | if (!cs4271) | 722 | if (ret < 0) |
| 704 | return -ENOMEM; | 723 | return ret; |
| 705 | 724 | ||
| 706 | i2c_set_clientdata(client, cs4271); | 725 | i2c_set_clientdata(client, cs4271); |
| 707 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); | 726 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); |
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 7a272fa90b39..828157779057 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <sound/pcm_params.h> | 30 | #include <sound/pcm_params.h> |
| 31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
| 32 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
| 33 | #include <linux/regmap.h> | ||
| 33 | 34 | ||
| 34 | #include "cs42l51.h" | 35 | #include "cs42l51.h" |
| 35 | 36 | ||
| @@ -40,7 +41,6 @@ enum master_slave_mode { | |||
| 40 | }; | 41 | }; |
| 41 | 42 | ||
| 42 | struct cs42l51_private { | 43 | struct cs42l51_private { |
| 43 | enum snd_soc_control_type control_type; | ||
| 44 | unsigned int mclk; | 44 | unsigned int mclk; |
| 45 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ | 45 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ |
| 46 | enum master_slave_mode func; | 46 | enum master_slave_mode func; |
| @@ -52,24 +52,6 @@ struct cs42l51_private { | |||
| 52 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | 52 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ |
| 53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | 53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) |
| 54 | 54 | ||
| 55 | static int cs42l51_fill_cache(struct snd_soc_codec *codec) | ||
| 56 | { | ||
| 57 | u8 *cache = codec->reg_cache + 1; | ||
| 58 | struct i2c_client *i2c_client = to_i2c_client(codec->dev); | ||
| 59 | s32 length; | ||
| 60 | |||
| 61 | length = i2c_smbus_read_i2c_block_data(i2c_client, | ||
| 62 | CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); | ||
| 63 | if (length != CS42L51_NUMREGS) { | ||
| 64 | dev_err(&i2c_client->dev, | ||
| 65 | "I2C read failure, addr=0x%x (ret=%d vs %d)\n", | ||
| 66 | i2c_client->addr, length, CS42L51_NUMREGS); | ||
| 67 | return -EIO; | ||
| 68 | } | ||
| 69 | |||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, | 55 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, |
| 74 | struct snd_ctl_elem_value *ucontrol) | 56 | struct snd_ctl_elem_value *ucontrol) |
| 75 | { | 57 | { |
| @@ -134,8 +116,7 @@ static const char *chan_mix[] = { | |||
| 134 | "R L", | 116 | "R L", |
| 135 | }; | 117 | }; |
| 136 | 118 | ||
| 137 | static const struct soc_enum cs42l51_chan_mix = | 119 | static SOC_ENUM_SINGLE_EXT_DECL(cs42l51_chan_mix, chan_mix); |
| 138 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix); | ||
| 139 | 120 | ||
| 140 | static const struct snd_kcontrol_new cs42l51_snd_controls[] = { | 121 | static const struct snd_kcontrol_new cs42l51_snd_controls[] = { |
| 141 | SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", | 122 | SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", |
| @@ -191,22 +172,22 @@ static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, | |||
| 191 | 172 | ||
| 192 | static const char *cs42l51_dac_names[] = {"Direct PCM", | 173 | static const char *cs42l51_dac_names[] = {"Direct PCM", |
| 193 | "DSP PCM", "ADC"}; | 174 | "DSP PCM", "ADC"}; |
| 194 | static const struct soc_enum cs42l51_dac_mux_enum = | 175 | static SOC_ENUM_SINGLE_DECL(cs42l51_dac_mux_enum, |
| 195 | SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names); | 176 | CS42L51_DAC_CTL, 6, cs42l51_dac_names); |
| 196 | static const struct snd_kcontrol_new cs42l51_dac_mux_controls = | 177 | static const struct snd_kcontrol_new cs42l51_dac_mux_controls = |
| 197 | SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum); | 178 | SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum); |
| 198 | 179 | ||
| 199 | static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left", | 180 | static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left", |
| 200 | "MIC Left", "MIC+preamp Left"}; | 181 | "MIC Left", "MIC+preamp Left"}; |
| 201 | static const struct soc_enum cs42l51_adcl_mux_enum = | 182 | static SOC_ENUM_SINGLE_DECL(cs42l51_adcl_mux_enum, |
| 202 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names); | 183 | CS42L51_ADC_INPUT, 4, cs42l51_adcl_names); |
| 203 | static const struct snd_kcontrol_new cs42l51_adcl_mux_controls = | 184 | static const struct snd_kcontrol_new cs42l51_adcl_mux_controls = |
| 204 | SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum); | 185 | SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum); |
| 205 | 186 | ||
| 206 | static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right", | 187 | static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right", |
| 207 | "MIC Right", "MIC+preamp Right"}; | 188 | "MIC Right", "MIC+preamp Right"}; |
| 208 | static const struct soc_enum cs42l51_adcr_mux_enum = | 189 | static SOC_ENUM_SINGLE_DECL(cs42l51_adcr_mux_enum, |
| 209 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names); | 190 | CS42L51_ADC_INPUT, 6, cs42l51_adcr_names); |
| 210 | static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = | 191 | static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = |
| 211 | SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); | 192 | SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); |
| 212 | 193 | ||
| @@ -504,16 +485,9 @@ static struct snd_soc_dai_driver cs42l51_dai = { | |||
| 504 | 485 | ||
| 505 | static int cs42l51_probe(struct snd_soc_codec *codec) | 486 | static int cs42l51_probe(struct snd_soc_codec *codec) |
| 506 | { | 487 | { |
| 507 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
| 508 | int ret, reg; | 488 | int ret, reg; |
| 509 | 489 | ||
| 510 | ret = cs42l51_fill_cache(codec); | 490 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
| 511 | if (ret < 0) { | ||
| 512 | dev_err(codec->dev, "failed to fill register cache\n"); | ||
| 513 | return ret; | ||
| 514 | } | ||
| 515 | |||
| 516 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type); | ||
| 517 | if (ret < 0) { | 491 | if (ret < 0) { |
| 518 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 492 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
| 519 | return ret; | 493 | return ret; |
| @@ -537,8 +511,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec) | |||
| 537 | 511 | ||
| 538 | static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { | 512 | static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { |
| 539 | .probe = cs42l51_probe, | 513 | .probe = cs42l51_probe, |
| 540 | .reg_cache_size = CS42L51_NUMREGS + 1, | ||
| 541 | .reg_word_size = sizeof(u8), | ||
| 542 | 514 | ||
| 543 | .controls = cs42l51_snd_controls, | 515 | .controls = cs42l51_snd_controls, |
| 544 | .num_controls = ARRAY_SIZE(cs42l51_snd_controls), | 516 | .num_controls = ARRAY_SIZE(cs42l51_snd_controls), |
| @@ -548,38 +520,53 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { | |||
| 548 | .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), | 520 | .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), |
| 549 | }; | 521 | }; |
| 550 | 522 | ||
| 523 | static const struct regmap_config cs42l51_regmap = { | ||
| 524 | .reg_bits = 8, | ||
| 525 | .val_bits = 8, | ||
| 526 | |||
| 527 | .max_register = CS42L51_CHARGE_FREQ, | ||
| 528 | .cache_type = REGCACHE_RBTREE, | ||
| 529 | }; | ||
| 530 | |||
| 551 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, | 531 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, |
| 552 | const struct i2c_device_id *id) | 532 | const struct i2c_device_id *id) |
| 553 | { | 533 | { |
| 554 | struct cs42l51_private *cs42l51; | 534 | struct cs42l51_private *cs42l51; |
| 535 | struct regmap *regmap; | ||
| 536 | unsigned int val; | ||
| 555 | int ret; | 537 | int ret; |
| 556 | 538 | ||
| 539 | regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap); | ||
| 540 | if (IS_ERR(regmap)) { | ||
| 541 | ret = PTR_ERR(regmap); | ||
| 542 | dev_err(&i2c_client->dev, "Failed to create regmap: %d\n", | ||
| 543 | ret); | ||
| 544 | return ret; | ||
| 545 | } | ||
| 546 | |||
| 557 | /* Verify that we have a CS42L51 */ | 547 | /* Verify that we have a CS42L51 */ |
| 558 | ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); | 548 | ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); |
| 559 | if (ret < 0) { | 549 | if (ret < 0) { |
| 560 | dev_err(&i2c_client->dev, "failed to read I2C\n"); | 550 | dev_err(&i2c_client->dev, "failed to read I2C\n"); |
| 561 | goto error; | 551 | goto error; |
| 562 | } | 552 | } |
| 563 | 553 | ||
| 564 | if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && | 554 | if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && |
| 565 | (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { | 555 | (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { |
| 566 | dev_err(&i2c_client->dev, "Invalid chip id\n"); | 556 | dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val); |
| 567 | ret = -ENODEV; | 557 | ret = -ENODEV; |
| 568 | goto error; | 558 | goto error; |
| 569 | } | 559 | } |
| 570 | 560 | ||
| 571 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", | 561 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", |
| 572 | ret & 7); | 562 | val & 7); |
| 573 | 563 | ||
| 574 | cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), | 564 | cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), |
| 575 | GFP_KERNEL); | 565 | GFP_KERNEL); |
| 576 | if (!cs42l51) { | 566 | if (!cs42l51) |
| 577 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
| 578 | return -ENOMEM; | 567 | return -ENOMEM; |
| 579 | } | ||
| 580 | 568 | ||
| 581 | i2c_set_clientdata(i2c_client, cs42l51); | 569 | i2c_set_clientdata(i2c_client, cs42l51); |
| 582 | cs42l51->control_type = SND_SOC_I2C; | ||
| 583 | 570 | ||
| 584 | ret = snd_soc_register_codec(&i2c_client->dev, | 571 | ret = snd_soc_register_codec(&i2c_client->dev, |
| 585 | &soc_codec_device_cs42l51, &cs42l51_dai, 1); | 572 | &soc_codec_device_cs42l51, &cs42l51_dai, 1); |
| @@ -599,10 +586,17 @@ static const struct i2c_device_id cs42l51_id[] = { | |||
| 599 | }; | 586 | }; |
| 600 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); | 587 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); |
| 601 | 588 | ||
| 589 | static const struct of_device_id cs42l51_of_match[] = { | ||
| 590 | { .compatible = "cirrus,cs42l51", }, | ||
| 591 | { } | ||
| 592 | }; | ||
| 593 | MODULE_DEVICE_TABLE(of, cs42l51_of_match); | ||
| 594 | |||
| 602 | static struct i2c_driver cs42l51_i2c_driver = { | 595 | static struct i2c_driver cs42l51_i2c_driver = { |
| 603 | .driver = { | 596 | .driver = { |
| 604 | .name = "cs42l51-codec", | 597 | .name = "cs42l51-codec", |
| 605 | .owner = THIS_MODULE, | 598 | .owner = THIS_MODULE, |
| 599 | .of_match_table = cs42l51_of_match, | ||
| 606 | }, | 600 | }, |
| 607 | .id_table = cs42l51_id, | 601 | .id_table = cs42l51_id, |
| 608 | .probe = cs42l51_i2c_probe, | 602 | .probe = cs42l51_i2c_probe, |
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 1102ced9b20e..ea7938d9e13a 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
| @@ -210,13 +210,11 @@ static const char * const cs42l52_adca_text[] = { | |||
| 210 | static const char * const cs42l52_adcb_text[] = { | 210 | static const char * const cs42l52_adcb_text[] = { |
| 211 | "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; | 211 | "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; |
| 212 | 212 | ||
| 213 | static const struct soc_enum adca_enum = | 213 | static SOC_ENUM_SINGLE_DECL(adca_enum, |
| 214 | SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5, | 214 | CS42L52_ADC_PGA_A, 5, cs42l52_adca_text); |
| 215 | ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text); | ||
| 216 | 215 | ||
| 217 | static const struct soc_enum adcb_enum = | 216 | static SOC_ENUM_SINGLE_DECL(adcb_enum, |
| 218 | SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5, | 217 | CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text); |
| 219 | ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text); | ||
| 220 | 218 | ||
| 221 | static const struct snd_kcontrol_new adca_mux = | 219 | static const struct snd_kcontrol_new adca_mux = |
| 222 | SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); | 220 | SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); |
| @@ -229,26 +227,22 @@ static const char * const mic_bias_level_text[] = { | |||
| 229 | "0.8 +VA", "0.83 +VA", "0.91 +VA" | 227 | "0.8 +VA", "0.83 +VA", "0.91 +VA" |
| 230 | }; | 228 | }; |
| 231 | 229 | ||
| 232 | static const struct soc_enum mic_bias_level_enum = | 230 | static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum, |
| 233 | SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, | 231 | CS42L52_IFACE_CTL2, 0, mic_bias_level_text); |
| 234 | ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); | ||
| 235 | 232 | ||
| 236 | static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; | 233 | static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; |
| 237 | 234 | ||
| 238 | static const struct soc_enum mica_enum = | 235 | static SOC_ENUM_SINGLE_DECL(mica_enum, |
| 239 | SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, | 236 | CS42L52_MICA_CTL, 5, cs42l52_mic_text); |
| 240 | ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); | ||
| 241 | 237 | ||
| 242 | static const struct soc_enum micb_enum = | 238 | static SOC_ENUM_SINGLE_DECL(micb_enum, |
| 243 | SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, | 239 | CS42L52_MICB_CTL, 5, cs42l52_mic_text); |
| 244 | ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); | ||
| 245 | 240 | ||
| 246 | static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; | 241 | static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; |
| 247 | 242 | ||
| 248 | static const struct soc_enum digital_output_mux_enum = | 243 | static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum, |
| 249 | SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6, | 244 | CS42L52_ADC_MISC_CTL, 6, |
| 250 | ARRAY_SIZE(digital_output_mux_text), | 245 | digital_output_mux_text); |
| 251 | digital_output_mux_text); | ||
| 252 | 246 | ||
| 253 | static const struct snd_kcontrol_new digital_output_mux = | 247 | static const struct snd_kcontrol_new digital_output_mux = |
| 254 | SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); | 248 | SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); |
| @@ -258,18 +252,18 @@ static const char * const hp_gain_num_text[] = { | |||
| 258 | "0.7099", "0.8399", "1.000", "1.1430" | 252 | "0.7099", "0.8399", "1.000", "1.1430" |
| 259 | }; | 253 | }; |
| 260 | 254 | ||
| 261 | static const struct soc_enum hp_gain_enum = | 255 | static SOC_ENUM_SINGLE_DECL(hp_gain_enum, |
| 262 | SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5, | 256 | CS42L52_PB_CTL1, 5, |
| 263 | ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text); | 257 | hp_gain_num_text); |
| 264 | 258 | ||
| 265 | static const char * const beep_pitch_text[] = { | 259 | static const char * const beep_pitch_text[] = { |
| 266 | "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", | 260 | "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", |
| 267 | "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" | 261 | "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" |
| 268 | }; | 262 | }; |
| 269 | 263 | ||
| 270 | static const struct soc_enum beep_pitch_enum = | 264 | static SOC_ENUM_SINGLE_DECL(beep_pitch_enum, |
| 271 | SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4, | 265 | CS42L52_BEEP_FREQ, 4, |
| 272 | ARRAY_SIZE(beep_pitch_text), beep_pitch_text); | 266 | beep_pitch_text); |
| 273 | 267 | ||
| 274 | static const char * const beep_ontime_text[] = { | 268 | static const char * const beep_ontime_text[] = { |
| 275 | "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", | 269 | "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", |
| @@ -277,66 +271,66 @@ static const char * const beep_ontime_text[] = { | |||
| 277 | "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" | 271 | "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" |
| 278 | }; | 272 | }; |
| 279 | 273 | ||
| 280 | static const struct soc_enum beep_ontime_enum = | 274 | static SOC_ENUM_SINGLE_DECL(beep_ontime_enum, |
| 281 | SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0, | 275 | CS42L52_BEEP_FREQ, 0, |
| 282 | ARRAY_SIZE(beep_ontime_text), beep_ontime_text); | 276 | beep_ontime_text); |
| 283 | 277 | ||
| 284 | static const char * const beep_offtime_text[] = { | 278 | static const char * const beep_offtime_text[] = { |
| 285 | "1.23 s", "2.58 s", "3.90 s", "5.20 s", | 279 | "1.23 s", "2.58 s", "3.90 s", "5.20 s", |
| 286 | "6.60 s", "8.05 s", "9.35 s", "10.80 s" | 280 | "6.60 s", "8.05 s", "9.35 s", "10.80 s" |
| 287 | }; | 281 | }; |
| 288 | 282 | ||
| 289 | static const struct soc_enum beep_offtime_enum = | 283 | static SOC_ENUM_SINGLE_DECL(beep_offtime_enum, |
| 290 | SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5, | 284 | CS42L52_BEEP_VOL, 5, |
| 291 | ARRAY_SIZE(beep_offtime_text), beep_offtime_text); | 285 | beep_offtime_text); |
| 292 | 286 | ||
| 293 | static const char * const beep_config_text[] = { | 287 | static const char * const beep_config_text[] = { |
| 294 | "Off", "Single", "Multiple", "Continuous" | 288 | "Off", "Single", "Multiple", "Continuous" |
| 295 | }; | 289 | }; |
| 296 | 290 | ||
| 297 | static const struct soc_enum beep_config_enum = | 291 | static SOC_ENUM_SINGLE_DECL(beep_config_enum, |
| 298 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6, | 292 | CS42L52_BEEP_TONE_CTL, 6, |
| 299 | ARRAY_SIZE(beep_config_text), beep_config_text); | 293 | beep_config_text); |
| 300 | 294 | ||
| 301 | static const char * const beep_bass_text[] = { | 295 | static const char * const beep_bass_text[] = { |
| 302 | "50 Hz", "100 Hz", "200 Hz", "250 Hz" | 296 | "50 Hz", "100 Hz", "200 Hz", "250 Hz" |
| 303 | }; | 297 | }; |
| 304 | 298 | ||
| 305 | static const struct soc_enum beep_bass_enum = | 299 | static SOC_ENUM_SINGLE_DECL(beep_bass_enum, |
| 306 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1, | 300 | CS42L52_BEEP_TONE_CTL, 1, |
| 307 | ARRAY_SIZE(beep_bass_text), beep_bass_text); | 301 | beep_bass_text); |
| 308 | 302 | ||
| 309 | static const char * const beep_treble_text[] = { | 303 | static const char * const beep_treble_text[] = { |
| 310 | "5 kHz", "7 kHz", "10 kHz", " 15 kHz" | 304 | "5 kHz", "7 kHz", "10 kHz", " 15 kHz" |
| 311 | }; | 305 | }; |
| 312 | 306 | ||
| 313 | static const struct soc_enum beep_treble_enum = | 307 | static SOC_ENUM_SINGLE_DECL(beep_treble_enum, |
| 314 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3, | 308 | CS42L52_BEEP_TONE_CTL, 3, |
| 315 | ARRAY_SIZE(beep_treble_text), beep_treble_text); | 309 | beep_treble_text); |
| 316 | 310 | ||
| 317 | static const char * const ng_threshold_text[] = { | 311 | static const char * const ng_threshold_text[] = { |
| 318 | "-34dB", "-37dB", "-40dB", "-43dB", | 312 | "-34dB", "-37dB", "-40dB", "-43dB", |
| 319 | "-46dB", "-52dB", "-58dB", "-64dB" | 313 | "-46dB", "-52dB", "-58dB", "-64dB" |
| 320 | }; | 314 | }; |
| 321 | 315 | ||
| 322 | static const struct soc_enum ng_threshold_enum = | 316 | static SOC_ENUM_SINGLE_DECL(ng_threshold_enum, |
| 323 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2, | 317 | CS42L52_NOISE_GATE_CTL, 2, |
| 324 | ARRAY_SIZE(ng_threshold_text), ng_threshold_text); | 318 | ng_threshold_text); |
| 325 | 319 | ||
| 326 | static const char * const cs42l52_ng_delay_text[] = { | 320 | static const char * const cs42l52_ng_delay_text[] = { |
| 327 | "50ms", "100ms", "150ms", "200ms"}; | 321 | "50ms", "100ms", "150ms", "200ms"}; |
| 328 | 322 | ||
| 329 | static const struct soc_enum ng_delay_enum = | 323 | static SOC_ENUM_SINGLE_DECL(ng_delay_enum, |
| 330 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0, | 324 | CS42L52_NOISE_GATE_CTL, 0, |
| 331 | ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text); | 325 | cs42l52_ng_delay_text); |
| 332 | 326 | ||
| 333 | static const char * const cs42l52_ng_type_text[] = { | 327 | static const char * const cs42l52_ng_type_text[] = { |
| 334 | "Apply Specific", "Apply All" | 328 | "Apply Specific", "Apply All" |
| 335 | }; | 329 | }; |
| 336 | 330 | ||
| 337 | static const struct soc_enum ng_type_enum = | 331 | static SOC_ENUM_SINGLE_DECL(ng_type_enum, |
| 338 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6, | 332 | CS42L52_NOISE_GATE_CTL, 6, |
| 339 | ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text); | 333 | cs42l52_ng_type_text); |
| 340 | 334 | ||
| 341 | static const char * const left_swap_text[] = { | 335 | static const char * const left_swap_text[] = { |
| 342 | "Left", "LR 2", "Right"}; | 336 | "Left", "LR 2", "Right"}; |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 7b95f7cbc515..e5778c015c8d 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
| @@ -278,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1); | |||
| 278 | static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" }; | 278 | static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" }; |
| 279 | static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; | 279 | static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; |
| 280 | 280 | ||
| 281 | static const struct soc_enum pgaa_enum = | 281 | static SOC_ENUM_SINGLE_DECL(pgaa_enum, |
| 282 | SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3, | 282 | CS42L73_ADCIPC, 3, |
| 283 | ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text); | 283 | cs42l73_pgaa_text); |
| 284 | 284 | ||
| 285 | static const struct soc_enum pgab_enum = | 285 | static SOC_ENUM_SINGLE_DECL(pgab_enum, |
| 286 | SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7, | 286 | CS42L73_ADCIPC, 7, |
| 287 | ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text); | 287 | cs42l73_pgab_text); |
| 288 | 288 | ||
| 289 | static const struct snd_kcontrol_new pgaa_mux = | 289 | static const struct snd_kcontrol_new pgaa_mux = |
| 290 | SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); | 290 | SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); |
| @@ -309,9 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = { | |||
| 309 | static const char * const cs42l73_ng_delay_text[] = { | 309 | static const char * const cs42l73_ng_delay_text[] = { |
| 310 | "50ms", "100ms", "150ms", "200ms" }; | 310 | "50ms", "100ms", "150ms", "200ms" }; |
| 311 | 311 | ||
| 312 | static const struct soc_enum ng_delay_enum = | 312 | static SOC_ENUM_SINGLE_DECL(ng_delay_enum, |
| 313 | SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, | 313 | CS42L73_NGCAB, 0, |
| 314 | ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); | 314 | cs42l73_ng_delay_text); |
| 315 | 315 | ||
| 316 | static const char * const cs42l73_mono_mix_texts[] = { | 316 | static const char * const cs42l73_mono_mix_texts[] = { |
| 317 | "Left", "Right", "Mono Mix"}; | 317 | "Left", "Right", "Mono Mix"}; |
| @@ -357,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer = | |||
| 357 | static const char * const cs42l73_ip_swap_text[] = { | 357 | static const char * const cs42l73_ip_swap_text[] = { |
| 358 | "Stereo", "Mono A", "Mono B", "Swap A-B"}; | 358 | "Stereo", "Mono A", "Mono B", "Swap A-B"}; |
| 359 | 359 | ||
| 360 | static const struct soc_enum ip_swap_enum = | 360 | static SOC_ENUM_SINGLE_DECL(ip_swap_enum, |
| 361 | SOC_ENUM_SINGLE(CS42L73_MIOPC, 6, | 361 | CS42L73_MIOPC, 6, |
| 362 | ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text); | 362 | cs42l73_ip_swap_text); |
| 363 | 363 | ||
| 364 | static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; | 364 | static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; |
| 365 | 365 | ||
| 366 | static const struct soc_enum vsp_output_mux_enum = | 366 | static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum, |
| 367 | SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5, | 367 | CS42L73_MIXERCTL, 5, |
| 368 | ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); | 368 | cs42l73_spo_mixer_text); |
| 369 | 369 | ||
| 370 | static const struct soc_enum xsp_output_mux_enum = | 370 | static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, |
| 371 | SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4, | 371 | CS42L73_MIXERCTL, 4, |
| 372 | ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); | 372 | cs42l73_spo_mixer_text); |
| 373 | 373 | ||
| 374 | static const struct snd_kcontrol_new vsp_output_mux = | 374 | static const struct snd_kcontrol_new vsp_output_mux = |
| 375 | SOC_DAPM_ENUM("Route", vsp_output_mux_enum); | 375 | SOC_DAPM_ENUM("Route", vsp_output_mux_enum); |
| @@ -1108,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
| 1108 | return 0; | 1108 | return 0; |
| 1109 | } | 1109 | } |
| 1110 | 1110 | ||
| 1111 | static u32 cs42l73_asrc_rates[] = { | 1111 | static const unsigned int cs42l73_asrc_rates[] = { |
| 1112 | 8000, 11025, 12000, 16000, 22050, | 1112 | 8000, 11025, 12000, 16000, 22050, |
| 1113 | 24000, 32000, 44100, 48000 | 1113 | 24000, 32000, 44100, 48000 |
| 1114 | }; | 1114 | }; |
| @@ -1241,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate) | |||
| 1241 | 0x7F, tristate << 7); | 1241 | 0x7F, tristate << 7); |
| 1242 | } | 1242 | } |
| 1243 | 1243 | ||
| 1244 | static struct snd_pcm_hw_constraint_list constraints_12_24 = { | 1244 | static const struct snd_pcm_hw_constraint_list constraints_12_24 = { |
| 1245 | .count = ARRAY_SIZE(cs42l73_asrc_rates), | 1245 | .count = ARRAY_SIZE(cs42l73_asrc_rates), |
| 1246 | .list = cs42l73_asrc_rates, | 1246 | .list = cs42l73_asrc_rates, |
| 1247 | }; | 1247 | }; |
| @@ -1255,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream, | |||
| 1255 | return 0; | 1255 | return 0; |
| 1256 | } | 1256 | } |
| 1257 | 1257 | ||
| 1258 | /* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ | ||
| 1259 | #define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) | ||
| 1260 | |||
| 1261 | 1258 | ||
| 1262 | #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1259 | #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 1263 | SNDRV_PCM_FMTBIT_S24_LE) | 1260 | SNDRV_PCM_FMTBIT_S24_LE) |
| @@ -1278,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
| 1278 | .stream_name = "XSP Playback", | 1275 | .stream_name = "XSP Playback", |
| 1279 | .channels_min = 1, | 1276 | .channels_min = 1, |
| 1280 | .channels_max = 2, | 1277 | .channels_max = 2, |
| 1281 | .rates = CS42L73_RATES, | 1278 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1282 | .formats = CS42L73_FORMATS, | 1279 | .formats = CS42L73_FORMATS, |
| 1283 | }, | 1280 | }, |
| 1284 | .capture = { | 1281 | .capture = { |
| 1285 | .stream_name = "XSP Capture", | 1282 | .stream_name = "XSP Capture", |
| 1286 | .channels_min = 1, | 1283 | .channels_min = 1, |
| 1287 | .channels_max = 2, | 1284 | .channels_max = 2, |
| 1288 | .rates = CS42L73_RATES, | 1285 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1289 | .formats = CS42L73_FORMATS, | 1286 | .formats = CS42L73_FORMATS, |
| 1290 | }, | 1287 | }, |
| 1291 | .ops = &cs42l73_ops, | 1288 | .ops = &cs42l73_ops, |
| @@ -1298,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
| 1298 | .stream_name = "ASP Playback", | 1295 | .stream_name = "ASP Playback", |
| 1299 | .channels_min = 2, | 1296 | .channels_min = 2, |
| 1300 | .channels_max = 2, | 1297 | .channels_max = 2, |
| 1301 | .rates = CS42L73_RATES, | 1298 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1302 | .formats = CS42L73_FORMATS, | 1299 | .formats = CS42L73_FORMATS, |
| 1303 | }, | 1300 | }, |
| 1304 | .capture = { | 1301 | .capture = { |
| 1305 | .stream_name = "ASP Capture", | 1302 | .stream_name = "ASP Capture", |
| 1306 | .channels_min = 2, | 1303 | .channels_min = 2, |
| 1307 | .channels_max = 2, | 1304 | .channels_max = 2, |
| 1308 | .rates = CS42L73_RATES, | 1305 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1309 | .formats = CS42L73_FORMATS, | 1306 | .formats = CS42L73_FORMATS, |
| 1310 | }, | 1307 | }, |
| 1311 | .ops = &cs42l73_ops, | 1308 | .ops = &cs42l73_ops, |
| @@ -1318,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
| 1318 | .stream_name = "VSP Playback", | 1315 | .stream_name = "VSP Playback", |
| 1319 | .channels_min = 1, | 1316 | .channels_min = 1, |
| 1320 | .channels_max = 2, | 1317 | .channels_max = 2, |
| 1321 | .rates = CS42L73_RATES, | 1318 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1322 | .formats = CS42L73_FORMATS, | 1319 | .formats = CS42L73_FORMATS, |
| 1323 | }, | 1320 | }, |
| 1324 | .capture = { | 1321 | .capture = { |
| 1325 | .stream_name = "VSP Capture", | 1322 | .stream_name = "VSP Capture", |
| 1326 | .channels_min = 1, | 1323 | .channels_min = 1, |
| 1327 | .channels_max = 2, | 1324 | .channels_max = 2, |
| 1328 | .rates = CS42L73_RATES, | 1325 | .rates = SNDRV_PCM_RATE_KNOT, |
| 1329 | .formats = CS42L73_FORMATS, | 1326 | .formats = CS42L73_FORMATS, |
| 1330 | }, | 1327 | }, |
| 1331 | .ops = &cs42l73_ops, | 1328 | .ops = &cs42l73_ops, |
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index e62e294a8033..01e55fc72307 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c | |||
| @@ -307,29 +307,29 @@ static const char * const da7210_hpf_cutoff_txt[] = { | |||
| 307 | "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" | 307 | "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" |
| 308 | }; | 308 | }; |
| 309 | 309 | ||
| 310 | static const struct soc_enum da7210_dac_hpf_cutoff = | 310 | static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff, |
| 311 | SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt); | 311 | DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt); |
| 312 | 312 | ||
| 313 | static const struct soc_enum da7210_adc_hpf_cutoff = | 313 | static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff, |
| 314 | SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt); | 314 | DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt); |
| 315 | 315 | ||
| 316 | /* ADC and DAC voice (8kHz) high pass cutoff value */ | 316 | /* ADC and DAC voice (8kHz) high pass cutoff value */ |
| 317 | static const char * const da7210_vf_cutoff_txt[] = { | 317 | static const char * const da7210_vf_cutoff_txt[] = { |
| 318 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 318 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
| 319 | }; | 319 | }; |
| 320 | 320 | ||
| 321 | static const struct soc_enum da7210_dac_vf_cutoff = | 321 | static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff, |
| 322 | SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt); | 322 | DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt); |
| 323 | 323 | ||
| 324 | static const struct soc_enum da7210_adc_vf_cutoff = | 324 | static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff, |
| 325 | SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt); | 325 | DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt); |
| 326 | 326 | ||
| 327 | static const char *da7210_hp_mode_txt[] = { | 327 | static const char *da7210_hp_mode_txt[] = { |
| 328 | "Class H", "Class G" | 328 | "Class H", "Class G" |
| 329 | }; | 329 | }; |
| 330 | 330 | ||
| 331 | static const struct soc_enum da7210_hp_mode_sel = | 331 | static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, |
| 332 | SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt); | 332 | DA7210_HP_CFG, 0, da7210_hp_mode_txt); |
| 333 | 333 | ||
| 334 | /* ALC can be enabled only if noise suppression is disabled */ | 334 | /* ALC can be enabled only if noise suppression is disabled */ |
| 335 | static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, | 335 | static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, |
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 0c77e7ad7423..439d10387f10 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c | |||
| @@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = { | |||
| 63 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 63 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | static const struct soc_enum da7213_dac_voice_hpf_corner = | 66 | static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner, |
| 67 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, | 67 | DA7213_DAC_FILTERS1, |
| 68 | DA7213_VOICE_HPF_CORNER_MAX, | 68 | DA7213_VOICE_HPF_CORNER_SHIFT, |
| 69 | da7213_voice_hpf_corner_txt); | 69 | da7213_voice_hpf_corner_txt); |
| 70 | 70 | ||
| 71 | static const struct soc_enum da7213_adc_voice_hpf_corner = | 71 | static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner, |
| 72 | SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, | 72 | DA7213_ADC_FILTERS1, |
| 73 | DA7213_VOICE_HPF_CORNER_MAX, | 73 | DA7213_VOICE_HPF_CORNER_SHIFT, |
| 74 | da7213_voice_hpf_corner_txt); | 74 | da7213_voice_hpf_corner_txt); |
| 75 | 75 | ||
| 76 | /* ADC and DAC high pass filter cutoff value */ | 76 | /* ADC and DAC high pass filter cutoff value */ |
| 77 | static const char * const da7213_audio_hpf_corner_txt[] = { | 77 | static const char * const da7213_audio_hpf_corner_txt[] = { |
| 78 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" | 78 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | static const struct soc_enum da7213_dac_audio_hpf_corner = | 81 | static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner, |
| 82 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, | 82 | DA7213_DAC_FILTERS1 |
| 83 | DA7213_AUDIO_HPF_CORNER_MAX, | 83 | , DA7213_AUDIO_HPF_CORNER_SHIFT, |
| 84 | da7213_audio_hpf_corner_txt); | 84 | da7213_audio_hpf_corner_txt); |
| 85 | 85 | ||
| 86 | static const struct soc_enum da7213_adc_audio_hpf_corner = | 86 | static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner, |
| 87 | SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, | 87 | DA7213_ADC_FILTERS1, |
| 88 | DA7213_AUDIO_HPF_CORNER_MAX, | 88 | DA7213_AUDIO_HPF_CORNER_SHIFT, |
| 89 | da7213_audio_hpf_corner_txt); | 89 | da7213_audio_hpf_corner_txt); |
| 90 | 90 | ||
| 91 | /* Gain ramping rate value */ | 91 | /* Gain ramping rate value */ |
| 92 | static const char * const da7213_gain_ramp_rate_txt[] = { | 92 | static const char * const da7213_gain_ramp_rate_txt[] = { |
| @@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = { | |||
| 94 | "nominal rate / 32" | 94 | "nominal rate / 32" |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | static const struct soc_enum da7213_gain_ramp_rate = | 97 | static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate, |
| 98 | SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, | 98 | DA7213_GAIN_RAMP_CTRL, |
| 99 | DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); | 99 | DA7213_GAIN_RAMP_RATE_SHIFT, |
| 100 | da7213_gain_ramp_rate_txt); | ||
| 100 | 101 | ||
| 101 | /* DAC noise gate setup time value */ | 102 | /* DAC noise gate setup time value */ |
| 102 | static const char * const da7213_dac_ng_setup_time_txt[] = { | 103 | static const char * const da7213_dac_ng_setup_time_txt[] = { |
| 103 | "256 samples", "512 samples", "1024 samples", "2048 samples" | 104 | "256 samples", "512 samples", "1024 samples", "2048 samples" |
| 104 | }; | 105 | }; |
| 105 | 106 | ||
| 106 | static const struct soc_enum da7213_dac_ng_setup_time = | 107 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time, |
| 107 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 108 | DA7213_DAC_NG_SETUP_TIME, |
| 108 | DA7213_DAC_NG_SETUP_TIME_SHIFT, | 109 | DA7213_DAC_NG_SETUP_TIME_SHIFT, |
| 109 | DA7213_DAC_NG_SETUP_TIME_MAX, | 110 | da7213_dac_ng_setup_time_txt); |
| 110 | da7213_dac_ng_setup_time_txt); | ||
| 111 | 111 | ||
| 112 | /* DAC noise gate rampup rate value */ | 112 | /* DAC noise gate rampup rate value */ |
| 113 | static const char * const da7213_dac_ng_rampup_txt[] = { | 113 | static const char * const da7213_dac_ng_rampup_txt[] = { |
| 114 | "0.02 ms/dB", "0.16 ms/dB" | 114 | "0.02 ms/dB", "0.16 ms/dB" |
| 115 | }; | 115 | }; |
| 116 | 116 | ||
| 117 | static const struct soc_enum da7213_dac_ng_rampup_rate = | 117 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate, |
| 118 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 118 | DA7213_DAC_NG_SETUP_TIME, |
| 119 | DA7213_DAC_NG_RAMPUP_RATE_SHIFT, | 119 | DA7213_DAC_NG_RAMPUP_RATE_SHIFT, |
| 120 | DA7213_DAC_NG_RAMP_RATE_MAX, | 120 | da7213_dac_ng_rampup_txt); |
| 121 | da7213_dac_ng_rampup_txt); | ||
| 122 | 121 | ||
| 123 | /* DAC noise gate rampdown rate value */ | 122 | /* DAC noise gate rampdown rate value */ |
| 124 | static const char * const da7213_dac_ng_rampdown_txt[] = { | 123 | static const char * const da7213_dac_ng_rampdown_txt[] = { |
| 125 | "0.64 ms/dB", "20.48 ms/dB" | 124 | "0.64 ms/dB", "20.48 ms/dB" |
| 126 | }; | 125 | }; |
| 127 | 126 | ||
| 128 | static const struct soc_enum da7213_dac_ng_rampdown_rate = | 127 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate, |
| 129 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 128 | DA7213_DAC_NG_SETUP_TIME, |
| 130 | DA7213_DAC_NG_RAMPDN_RATE_SHIFT, | 129 | DA7213_DAC_NG_RAMPDN_RATE_SHIFT, |
| 131 | DA7213_DAC_NG_RAMP_RATE_MAX, | 130 | da7213_dac_ng_rampdown_txt); |
| 132 | da7213_dac_ng_rampdown_txt); | ||
| 133 | 131 | ||
| 134 | /* DAC soft mute rate value */ | 132 | /* DAC soft mute rate value */ |
| 135 | static const char * const da7213_dac_soft_mute_rate_txt[] = { | 133 | static const char * const da7213_dac_soft_mute_rate_txt[] = { |
| 136 | "1", "2", "4", "8", "16", "32", "64" | 134 | "1", "2", "4", "8", "16", "32", "64" |
| 137 | }; | 135 | }; |
| 138 | 136 | ||
| 139 | static const struct soc_enum da7213_dac_soft_mute_rate = | 137 | static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate, |
| 140 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, | 138 | DA7213_DAC_FILTERS5, |
| 141 | DA7213_DAC_SOFTMUTE_RATE_MAX, | 139 | DA7213_DAC_SOFTMUTE_RATE_SHIFT, |
| 142 | da7213_dac_soft_mute_rate_txt); | 140 | da7213_dac_soft_mute_rate_txt); |
| 143 | 141 | ||
| 144 | /* ALC Attack Rate select */ | 142 | /* ALC Attack Rate select */ |
| 145 | static const char * const da7213_alc_attack_rate_txt[] = { | 143 | static const char * const da7213_alc_attack_rate_txt[] = { |
| @@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = { | |||
| 147 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 145 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
| 148 | }; | 146 | }; |
| 149 | 147 | ||
| 150 | static const struct soc_enum da7213_alc_attack_rate = | 148 | static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate, |
| 151 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, | 149 | DA7213_ALC_CTRL2, |
| 152 | DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); | 150 | DA7213_ALC_ATTACK_SHIFT, |
| 151 | da7213_alc_attack_rate_txt); | ||
| 153 | 152 | ||
| 154 | /* ALC Release Rate select */ | 153 | /* ALC Release Rate select */ |
| 155 | static const char * const da7213_alc_release_rate_txt[] = { | 154 | static const char * const da7213_alc_release_rate_txt[] = { |
| @@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = { | |||
| 157 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 156 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
| 158 | }; | 157 | }; |
| 159 | 158 | ||
| 160 | static const struct soc_enum da7213_alc_release_rate = | 159 | static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate, |
| 161 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, | 160 | DA7213_ALC_CTRL2, |
| 162 | DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); | 161 | DA7213_ALC_RELEASE_SHIFT, |
| 162 | da7213_alc_release_rate_txt); | ||
| 163 | 163 | ||
| 164 | /* ALC Hold Time select */ | 164 | /* ALC Hold Time select */ |
| 165 | static const char * const da7213_alc_hold_time_txt[] = { | 165 | static const char * const da7213_alc_hold_time_txt[] = { |
| @@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = { | |||
| 168 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" | 168 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" |
| 169 | }; | 169 | }; |
| 170 | 170 | ||
| 171 | static const struct soc_enum da7213_alc_hold_time = | 171 | static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time, |
| 172 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, | 172 | DA7213_ALC_CTRL3, |
| 173 | DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); | 173 | DA7213_ALC_HOLD_SHIFT, |
| 174 | da7213_alc_hold_time_txt); | ||
| 174 | 175 | ||
| 175 | /* ALC Input Signal Tracking rate select */ | 176 | /* ALC Input Signal Tracking rate select */ |
| 176 | static const char * const da7213_alc_integ_rate_txt[] = { | 177 | static const char * const da7213_alc_integ_rate_txt[] = { |
| 177 | "1/4", "1/16", "1/256", "1/65536" | 178 | "1/4", "1/16", "1/256", "1/65536" |
| 178 | }; | 179 | }; |
| 179 | 180 | ||
| 180 | static const struct soc_enum da7213_alc_integ_attack_rate = | 181 | static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate, |
| 181 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, | 182 | DA7213_ALC_CTRL3, |
| 182 | DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); | 183 | DA7213_ALC_INTEG_ATTACK_SHIFT, |
| 184 | da7213_alc_integ_rate_txt); | ||
| 183 | 185 | ||
| 184 | static const struct soc_enum da7213_alc_integ_release_rate = | 186 | static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate, |
| 185 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, | 187 | DA7213_ALC_CTRL3, |
| 186 | DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); | 188 | DA7213_ALC_INTEG_RELEASE_SHIFT, |
| 189 | da7213_alc_integ_rate_txt); | ||
| 187 | 190 | ||
| 188 | 191 | ||
| 189 | /* | 192 | /* |
| @@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = { | |||
| 584 | "Differential", "MIC_P", "MIC_N" | 587 | "Differential", "MIC_P", "MIC_N" |
| 585 | }; | 588 | }; |
| 586 | 589 | ||
| 587 | static const struct soc_enum da7213_mic_1_amp_in_sel = | 590 | static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel, |
| 588 | SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, | 591 | DA7213_MIC_1_CTRL, |
| 589 | DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); | 592 | DA7213_MIC_AMP_IN_SEL_SHIFT, |
| 593 | da7213_mic_amp_in_sel_txt); | ||
| 590 | static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = | 594 | static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = |
| 591 | SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); | 595 | SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); |
| 592 | 596 | ||
| 593 | static const struct soc_enum da7213_mic_2_amp_in_sel = | 597 | static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel, |
| 594 | SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, | 598 | DA7213_MIC_2_CTRL, |
| 595 | DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); | 599 | DA7213_MIC_AMP_IN_SEL_SHIFT, |
| 600 | da7213_mic_amp_in_sel_txt); | ||
| 596 | static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = | 601 | static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = |
| 597 | SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); | 602 | SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); |
| 598 | 603 | ||
| @@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = { | |||
| 601 | "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" | 606 | "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" |
| 602 | }; | 607 | }; |
| 603 | 608 | ||
| 604 | static const struct soc_enum da7213_dai_l_src = | 609 | static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src, |
| 605 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, | 610 | DA7213_DIG_ROUTING_DAI, |
| 606 | DA7213_DAI_SRC_MAX, da7213_dai_src_txt); | 611 | DA7213_DAI_L_SRC_SHIFT, |
| 612 | da7213_dai_src_txt); | ||
| 607 | static const struct snd_kcontrol_new da7213_dai_l_src_mux = | 613 | static const struct snd_kcontrol_new da7213_dai_l_src_mux = |
| 608 | SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); | 614 | SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); |
| 609 | 615 | ||
| 610 | static const struct soc_enum da7213_dai_r_src = | 616 | static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src, |
| 611 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, | 617 | DA7213_DIG_ROUTING_DAI, |
| 612 | DA7213_DAI_SRC_MAX, da7213_dai_src_txt); | 618 | DA7213_DAI_R_SRC_SHIFT, |
| 619 | da7213_dai_src_txt); | ||
| 613 | static const struct snd_kcontrol_new da7213_dai_r_src_mux = | 620 | static const struct snd_kcontrol_new da7213_dai_r_src_mux = |
| 614 | SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); | 621 | SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); |
| 615 | 622 | ||
| @@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = { | |||
| 619 | "DAI Input Right" | 626 | "DAI Input Right" |
| 620 | }; | 627 | }; |
| 621 | 628 | ||
| 622 | static const struct soc_enum da7213_dac_l_src = | 629 | static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src, |
| 623 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, | 630 | DA7213_DIG_ROUTING_DAC, |
| 624 | DA7213_DAC_SRC_MAX, da7213_dac_src_txt); | 631 | DA7213_DAC_L_SRC_SHIFT, |
| 632 | da7213_dac_src_txt); | ||
| 625 | static const struct snd_kcontrol_new da7213_dac_l_src_mux = | 633 | static const struct snd_kcontrol_new da7213_dac_l_src_mux = |
| 626 | SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); | 634 | SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); |
| 627 | 635 | ||
| 628 | static const struct soc_enum da7213_dac_r_src = | 636 | static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src, |
| 629 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, | 637 | DA7213_DIG_ROUTING_DAC, |
| 630 | DA7213_DAC_SRC_MAX, da7213_dac_src_txt); | 638 | DA7213_DAC_R_SRC_SHIFT, |
| 639 | da7213_dac_src_txt); | ||
| 631 | static const struct snd_kcontrol_new da7213_dac_r_src_mux = | 640 | static const struct snd_kcontrol_new da7213_dac_r_src_mux = |
| 632 | SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); | 641 | SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); |
| 633 | 642 | ||
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f4d965ebc29e..4d1c302f5a76 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c | |||
| @@ -269,81 +269,65 @@ static const char *da732x_hpf_voice[] = { | |||
| 269 | "150Hz", "200Hz", "300Hz", "400Hz" | 269 | "150Hz", "200Hz", "300Hz", "400Hz" |
| 270 | }; | 270 | }; |
| 271 | 271 | ||
| 272 | static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { | 272 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum, |
| 273 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, | 273 | DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, |
| 274 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 274 | da732x_hpf_mode); |
| 275 | }; | ||
| 276 | |||
| 277 | static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { | ||
| 278 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, | ||
| 279 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
| 280 | }; | ||
| 281 | 275 | ||
| 282 | static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { | 276 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum, |
| 283 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, | 277 | DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, |
| 284 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 278 | da732x_hpf_mode); |
| 285 | }; | ||
| 286 | 279 | ||
| 287 | static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { | 280 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum, |
| 288 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, | 281 | DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, |
| 289 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 282 | da732x_hpf_mode); |
| 290 | }; | ||
| 291 | 283 | ||
| 292 | static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { | 284 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum, |
| 293 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, | 285 | DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, |
| 294 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 286 | da732x_hpf_mode); |
| 295 | }; | ||
| 296 | 287 | ||
| 297 | static const struct soc_enum da732x_dac1_hp_filter_enum[] = { | 288 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum, |
| 298 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, | 289 | DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, |
| 299 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 290 | da732x_hpf_mode); |
| 300 | }; | ||
| 301 | 291 | ||
| 302 | static const struct soc_enum da732x_dac2_hp_filter_enum[] = { | 292 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum, |
| 303 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, | 293 | DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, |
| 304 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 294 | da732x_hpf_music); |
| 305 | }; | ||
| 306 | 295 | ||
| 307 | static const struct soc_enum da732x_dac3_hp_filter_enum[] = { | 296 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum, |
| 308 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, | 297 | DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, |
| 309 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 298 | da732x_hpf_music); |
| 310 | }; | ||
| 311 | 299 | ||
| 312 | static const struct soc_enum da732x_adc1_hp_filter_enum[] = { | 300 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum, |
| 313 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, | 301 | DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, |
| 314 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 302 | da732x_hpf_music); |
| 315 | }; | ||
| 316 | 303 | ||
| 317 | static const struct soc_enum da732x_adc2_hp_filter_enum[] = { | 304 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum, |
| 318 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, | 305 | DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, |
| 319 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 306 | da732x_hpf_music); |
| 320 | }; | ||
| 321 | 307 | ||
| 322 | static const struct soc_enum da732x_dac1_voice_filter_enum[] = { | 308 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum, |
| 323 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, | 309 | DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, |
| 324 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 310 | da732x_hpf_music); |
| 325 | }; | ||
| 326 | 311 | ||
| 327 | static const struct soc_enum da732x_dac2_voice_filter_enum[] = { | 312 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum, |
| 328 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, | 313 | DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, |
| 329 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 314 | da732x_hpf_voice); |
| 330 | }; | ||
| 331 | 315 | ||
| 332 | static const struct soc_enum da732x_dac3_voice_filter_enum[] = { | 316 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum, |
| 333 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, | 317 | DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, |
| 334 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 318 | da732x_hpf_voice); |
| 335 | }; | ||
| 336 | 319 | ||
| 337 | static const struct soc_enum da732x_adc1_voice_filter_enum[] = { | 320 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum, |
| 338 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, | 321 | DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, |
| 339 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 322 | da732x_hpf_voice); |
| 340 | }; | ||
| 341 | 323 | ||
| 342 | static const struct soc_enum da732x_adc2_voice_filter_enum[] = { | 324 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum, |
| 343 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, | 325 | DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, |
| 344 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 326 | da732x_hpf_voice); |
| 345 | }; | ||
| 346 | 327 | ||
| 328 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, | ||
| 329 | DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, | ||
| 330 | da732x_hpf_voice); | ||
| 347 | 331 | ||
| 348 | static int da732x_hpf_set(struct snd_kcontrol *kcontrol, | 332 | static int da732x_hpf_set(struct snd_kcontrol *kcontrol, |
| 349 | struct snd_ctl_elem_value *ucontrol) | 333 | struct snd_ctl_elem_value *ucontrol) |
| @@ -714,65 +698,65 @@ static const char *enable_text[] = { | |||
| 714 | }; | 698 | }; |
| 715 | 699 | ||
| 716 | /* ADC1LMUX */ | 700 | /* ADC1LMUX */ |
| 717 | static const struct soc_enum adc1l_enum = | 701 | static SOC_ENUM_SINGLE_DECL(adc1l_enum, |
| 718 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, | 702 | DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, |
| 719 | DA732X_ADCL_MUX_MAX, adcl_text); | 703 | adcl_text); |
| 720 | static const struct snd_kcontrol_new adc1l_mux = | 704 | static const struct snd_kcontrol_new adc1l_mux = |
| 721 | SOC_DAPM_ENUM("ADC Route", adc1l_enum); | 705 | SOC_DAPM_ENUM("ADC Route", adc1l_enum); |
| 722 | 706 | ||
| 723 | /* ADC1RMUX */ | 707 | /* ADC1RMUX */ |
| 724 | static const struct soc_enum adc1r_enum = | 708 | static SOC_ENUM_SINGLE_DECL(adc1r_enum, |
| 725 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, | 709 | DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, |
| 726 | DA732X_ADCR_MUX_MAX, adcr_text); | 710 | adcr_text); |
| 727 | static const struct snd_kcontrol_new adc1r_mux = | 711 | static const struct snd_kcontrol_new adc1r_mux = |
| 728 | SOC_DAPM_ENUM("ADC Route", adc1r_enum); | 712 | SOC_DAPM_ENUM("ADC Route", adc1r_enum); |
| 729 | 713 | ||
| 730 | /* ADC2LMUX */ | 714 | /* ADC2LMUX */ |
| 731 | static const struct soc_enum adc2l_enum = | 715 | static SOC_ENUM_SINGLE_DECL(adc2l_enum, |
| 732 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, | 716 | DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, |
| 733 | DA732X_ADCL_MUX_MAX, adcl_text); | 717 | adcl_text); |
| 734 | static const struct snd_kcontrol_new adc2l_mux = | 718 | static const struct snd_kcontrol_new adc2l_mux = |
| 735 | SOC_DAPM_ENUM("ADC Route", adc2l_enum); | 719 | SOC_DAPM_ENUM("ADC Route", adc2l_enum); |
| 736 | 720 | ||
| 737 | /* ADC2RMUX */ | 721 | /* ADC2RMUX */ |
| 738 | static const struct soc_enum adc2r_enum = | 722 | static SOC_ENUM_SINGLE_DECL(adc2r_enum, |
| 739 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, | 723 | DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, |
| 740 | DA732X_ADCR_MUX_MAX, adcr_text); | 724 | adcr_text); |
| 741 | 725 | ||
| 742 | static const struct snd_kcontrol_new adc2r_mux = | 726 | static const struct snd_kcontrol_new adc2r_mux = |
| 743 | SOC_DAPM_ENUM("ADC Route", adc2r_enum); | 727 | SOC_DAPM_ENUM("ADC Route", adc2r_enum); |
| 744 | 728 | ||
| 745 | static const struct soc_enum da732x_hp_left_output = | 729 | static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output, |
| 746 | SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, | 730 | DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, |
| 747 | DA732X_DAC_EN_MAX, enable_text); | 731 | enable_text); |
| 748 | 732 | ||
| 749 | static const struct snd_kcontrol_new hpl_mux = | 733 | static const struct snd_kcontrol_new hpl_mux = |
| 750 | SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); | 734 | SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); |
| 751 | 735 | ||
| 752 | static const struct soc_enum da732x_hp_right_output = | 736 | static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output, |
| 753 | SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, | 737 | DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, |
| 754 | DA732X_DAC_EN_MAX, enable_text); | 738 | enable_text); |
| 755 | 739 | ||
| 756 | static const struct snd_kcontrol_new hpr_mux = | 740 | static const struct snd_kcontrol_new hpr_mux = |
| 757 | SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); | 741 | SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); |
| 758 | 742 | ||
| 759 | static const struct soc_enum da732x_speaker_output = | 743 | static SOC_ENUM_SINGLE_DECL(da732x_speaker_output, |
| 760 | SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, | 744 | DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, |
| 761 | DA732X_DAC_EN_MAX, enable_text); | 745 | enable_text); |
| 762 | 746 | ||
| 763 | static const struct snd_kcontrol_new spk_mux = | 747 | static const struct snd_kcontrol_new spk_mux = |
| 764 | SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); | 748 | SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); |
| 765 | 749 | ||
| 766 | static const struct soc_enum da732x_lout4_output = | 750 | static SOC_ENUM_SINGLE_DECL(da732x_lout4_output, |
| 767 | SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, | 751 | DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, |
| 768 | DA732X_DAC_EN_MAX, enable_text); | 752 | enable_text); |
| 769 | 753 | ||
| 770 | static const struct snd_kcontrol_new lout4_mux = | 754 | static const struct snd_kcontrol_new lout4_mux = |
| 771 | SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); | 755 | SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); |
| 772 | 756 | ||
| 773 | static const struct soc_enum da732x_lout2_output = | 757 | static SOC_ENUM_SINGLE_DECL(da732x_lout2_output, |
| 774 | SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, | 758 | DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, |
| 775 | DA732X_DAC_EN_MAX, enable_text); | 759 | enable_text); |
| 776 | 760 | ||
| 777 | static const struct snd_kcontrol_new lout2_mux = | 761 | static const struct snd_kcontrol_new lout2_mux = |
| 778 | SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); | 762 | SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); |
| @@ -1499,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
| 1499 | 1483 | ||
| 1500 | da732x_hp_dc_offset_cancellation(codec); | 1484 | da732x_hp_dc_offset_cancellation(codec); |
| 1501 | 1485 | ||
| 1502 | regcache_cache_only(codec->control_data, false); | 1486 | regcache_cache_only(da732x->regmap, false); |
| 1503 | regcache_sync(codec->control_data); | 1487 | regcache_sync(da732x->regmap); |
| 1504 | } else { | 1488 | } else { |
| 1505 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, | 1489 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, |
| 1506 | DA732X_BIAS_BOOST_MASK, | 1490 | DA732X_BIAS_BOOST_MASK, |
| @@ -1511,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
| 1511 | } | 1495 | } |
| 1512 | break; | 1496 | break; |
| 1513 | case SND_SOC_BIAS_OFF: | 1497 | case SND_SOC_BIAS_OFF: |
| 1514 | regcache_cache_only(codec->control_data, true); | 1498 | regcache_cache_only(da732x->regmap, true); |
| 1515 | da732x_set_charge_pump(codec, DA732X_DISABLE_CP); | 1499 | da732x_set_charge_pump(codec, DA732X_DISABLE_CP); |
| 1516 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, | 1500 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, |
| 1517 | DA732X_BIAS_DIS); | 1501 | DA732X_BIAS_DIS); |
| @@ -1566,7 +1550,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = { | |||
| 1566 | .dapm_routes = da732x_dapm_routes, | 1550 | .dapm_routes = da732x_dapm_routes, |
| 1567 | .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), | 1551 | .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), |
| 1568 | .set_pll = da732x_set_dai_pll, | 1552 | .set_pll = da732x_set_dai_pll, |
| 1569 | .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), | ||
| 1570 | }; | 1553 | }; |
| 1571 | 1554 | ||
| 1572 | static int da732x_i2c_probe(struct i2c_client *i2c, | 1555 | static int da732x_i2c_probe(struct i2c_client *i2c, |
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index c8ce5475de22..1dceafeec415 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h | |||
| @@ -113,9 +113,6 @@ | |||
| 113 | #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 | 113 | #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 |
| 114 | #define DA732X_EQ_OVERALL_VOL_DB_INC 600 | 114 | #define DA732X_EQ_OVERALL_VOL_DB_INC 600 |
| 115 | 115 | ||
| 116 | #define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ | ||
| 117 | {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} | ||
| 118 | |||
| 119 | enum da732x_sysctl { | 116 | enum da732x_sysctl { |
| 120 | DA732X_SR_8KHZ = 0x1, | 117 | DA732X_SR_8KHZ = 0x1, |
| 121 | DA732X_SR_11_025KHZ = 0x2, | 118 | DA732X_SR_11_025KHZ = 0x2, |
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 422812613a28..f118daa91234 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c | |||
| @@ -18,6 +18,8 @@ | |||
| 18 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_device.h> | ||
| 21 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
| 22 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
| 23 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
| @@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = { | |||
| 321 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" | 323 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" |
| 322 | }; | 324 | }; |
| 323 | 325 | ||
| 324 | static const struct soc_enum da9055_dac_hpf_cutoff = | 326 | static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff, |
| 325 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); | 327 | DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt); |
| 326 | 328 | ||
| 327 | static const struct soc_enum da9055_adc_hpf_cutoff = | 329 | static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff, |
| 328 | SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); | 330 | DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt); |
| 329 | 331 | ||
| 330 | /* ADC and DAC voice mode (8kHz) high pass cutoff value */ | 332 | /* ADC and DAC voice mode (8kHz) high pass cutoff value */ |
| 331 | static const char * const da9055_vf_cutoff_txt[] = { | 333 | static const char * const da9055_vf_cutoff_txt[] = { |
| 332 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 334 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
| 333 | }; | 335 | }; |
| 334 | 336 | ||
| 335 | static const struct soc_enum da9055_dac_vf_cutoff = | 337 | static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff, |
| 336 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); | 338 | DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt); |
| 337 | 339 | ||
| 338 | static const struct soc_enum da9055_adc_vf_cutoff = | 340 | static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff, |
| 339 | SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); | 341 | DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt); |
| 340 | 342 | ||
| 341 | /* Gain ramping rate value */ | 343 | /* Gain ramping rate value */ |
| 342 | static const char * const da9055_gain_ramping_txt[] = { | 344 | static const char * const da9055_gain_ramping_txt[] = { |
| @@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = { | |||
| 344 | "nominal rate / 8" | 346 | "nominal rate / 8" |
| 345 | }; | 347 | }; |
| 346 | 348 | ||
| 347 | static const struct soc_enum da9055_gain_ramping_rate = | 349 | static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate, |
| 348 | SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt); | 350 | DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt); |
| 349 | 351 | ||
| 350 | /* DAC noise gate setup time value */ | 352 | /* DAC noise gate setup time value */ |
| 351 | static const char * const da9055_dac_ng_setup_time_txt[] = { | 353 | static const char * const da9055_dac_ng_setup_time_txt[] = { |
| 352 | "256 samples", "512 samples", "1024 samples", "2048 samples" | 354 | "256 samples", "512 samples", "1024 samples", "2048 samples" |
| 353 | }; | 355 | }; |
| 354 | 356 | ||
| 355 | static const struct soc_enum da9055_dac_ng_setup_time = | 357 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time, |
| 356 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4, | 358 | DA9055_DAC_NG_SETUP_TIME, 0, |
| 357 | da9055_dac_ng_setup_time_txt); | 359 | da9055_dac_ng_setup_time_txt); |
| 358 | 360 | ||
| 359 | /* DAC noise gate rampup rate value */ | 361 | /* DAC noise gate rampup rate value */ |
| 360 | static const char * const da9055_dac_ng_rampup_txt[] = { | 362 | static const char * const da9055_dac_ng_rampup_txt[] = { |
| 361 | "0.02 ms/dB", "0.16 ms/dB" | 363 | "0.02 ms/dB", "0.16 ms/dB" |
| 362 | }; | 364 | }; |
| 363 | 365 | ||
| 364 | static const struct soc_enum da9055_dac_ng_rampup_rate = | 366 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate, |
| 365 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2, | 367 | DA9055_DAC_NG_SETUP_TIME, 2, |
| 366 | da9055_dac_ng_rampup_txt); | 368 | da9055_dac_ng_rampup_txt); |
| 367 | 369 | ||
| 368 | /* DAC noise gate rampdown rate value */ | 370 | /* DAC noise gate rampdown rate value */ |
| 369 | static const char * const da9055_dac_ng_rampdown_txt[] = { | 371 | static const char * const da9055_dac_ng_rampdown_txt[] = { |
| 370 | "0.64 ms/dB", "20.48 ms/dB" | 372 | "0.64 ms/dB", "20.48 ms/dB" |
| 371 | }; | 373 | }; |
| 372 | 374 | ||
| 373 | static const struct soc_enum da9055_dac_ng_rampdown_rate = | 375 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate, |
| 374 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2, | 376 | DA9055_DAC_NG_SETUP_TIME, 3, |
| 375 | da9055_dac_ng_rampdown_txt); | 377 | da9055_dac_ng_rampdown_txt); |
| 376 | 378 | ||
| 377 | /* DAC soft mute rate value */ | 379 | /* DAC soft mute rate value */ |
| 378 | static const char * const da9055_dac_soft_mute_rate_txt[] = { | 380 | static const char * const da9055_dac_soft_mute_rate_txt[] = { |
| 379 | "1", "2", "4", "8", "16", "32", "64" | 381 | "1", "2", "4", "8", "16", "32", "64" |
| 380 | }; | 382 | }; |
| 381 | 383 | ||
| 382 | static const struct soc_enum da9055_dac_soft_mute_rate = | 384 | static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate, |
| 383 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7, | 385 | DA9055_DAC_FILTERS5, 4, |
| 384 | da9055_dac_soft_mute_rate_txt); | 386 | da9055_dac_soft_mute_rate_txt); |
| 385 | 387 | ||
| 386 | /* DAC routing select */ | 388 | /* DAC routing select */ |
| 387 | static const char * const da9055_dac_src_txt[] = { | 389 | static const char * const da9055_dac_src_txt[] = { |
| @@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = { | |||
| 389 | "AIF input right" | 391 | "AIF input right" |
| 390 | }; | 392 | }; |
| 391 | 393 | ||
| 392 | static const struct soc_enum da9055_dac_l_src = | 394 | static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src, |
| 393 | SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt); | 395 | DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt); |
| 394 | 396 | ||
| 395 | static const struct soc_enum da9055_dac_r_src = | 397 | static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src, |
| 396 | SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt); | 398 | DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt); |
| 397 | 399 | ||
| 398 | /* MIC PGA Left source select */ | 400 | /* MIC PGA Left source select */ |
| 399 | static const char * const da9055_mic_l_src_txt[] = { | 401 | static const char * const da9055_mic_l_src_txt[] = { |
| 400 | "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" | 402 | "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" |
| 401 | }; | 403 | }; |
| 402 | 404 | ||
| 403 | static const struct soc_enum da9055_mic_l_src = | 405 | static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src, |
| 404 | SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt); | 406 | DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt); |
| 405 | 407 | ||
| 406 | /* MIC PGA Right source select */ | 408 | /* MIC PGA Right source select */ |
| 407 | static const char * const da9055_mic_r_src_txt[] = { | 409 | static const char * const da9055_mic_r_src_txt[] = { |
| 408 | "MIC2_R_L", "MIC2_R", "MIC2_L" | 410 | "MIC2_R_L", "MIC2_R", "MIC2_L" |
| 409 | }; | 411 | }; |
| 410 | 412 | ||
| 411 | static const struct soc_enum da9055_mic_r_src = | 413 | static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src, |
| 412 | SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt); | 414 | DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt); |
| 413 | 415 | ||
| 414 | /* ALC Input Signal Tracking rate select */ | 416 | /* ALC Input Signal Tracking rate select */ |
| 415 | static const char * const da9055_signal_tracking_rate_txt[] = { | 417 | static const char * const da9055_signal_tracking_rate_txt[] = { |
| 416 | "1/4", "1/16", "1/256", "1/65536" | 418 | "1/4", "1/16", "1/256", "1/65536" |
| 417 | }; | 419 | }; |
| 418 | 420 | ||
| 419 | static const struct soc_enum da9055_integ_attack_rate = | 421 | static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate, |
| 420 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4, | 422 | DA9055_ALC_CTRL3, 4, |
| 421 | da9055_signal_tracking_rate_txt); | 423 | da9055_signal_tracking_rate_txt); |
| 422 | 424 | ||
| 423 | static const struct soc_enum da9055_integ_release_rate = | 425 | static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate, |
| 424 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4, | 426 | DA9055_ALC_CTRL3, 6, |
| 425 | da9055_signal_tracking_rate_txt); | 427 | da9055_signal_tracking_rate_txt); |
| 426 | 428 | ||
| 427 | /* ALC Attack Rate select */ | 429 | /* ALC Attack Rate select */ |
| 428 | static const char * const da9055_attack_rate_txt[] = { | 430 | static const char * const da9055_attack_rate_txt[] = { |
| @@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = { | |||
| 430 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 432 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
| 431 | }; | 433 | }; |
| 432 | 434 | ||
| 433 | static const struct soc_enum da9055_attack_rate = | 435 | static SOC_ENUM_SINGLE_DECL(da9055_attack_rate, |
| 434 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt); | 436 | DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt); |
| 435 | 437 | ||
| 436 | /* ALC Release Rate select */ | 438 | /* ALC Release Rate select */ |
| 437 | static const char * const da9055_release_rate_txt[] = { | 439 | static const char * const da9055_release_rate_txt[] = { |
| @@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = { | |||
| 439 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 441 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
| 440 | }; | 442 | }; |
| 441 | 443 | ||
| 442 | static const struct soc_enum da9055_release_rate = | 444 | static SOC_ENUM_SINGLE_DECL(da9055_release_rate, |
| 443 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt); | 445 | DA9055_ALC_CTRL2, 4, da9055_release_rate_txt); |
| 444 | 446 | ||
| 445 | /* ALC Hold Time select */ | 447 | /* ALC Hold Time select */ |
| 446 | static const char * const da9055_hold_time_txt[] = { | 448 | static const char * const da9055_hold_time_txt[] = { |
| @@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = { | |||
| 449 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" | 451 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" |
| 450 | }; | 452 | }; |
| 451 | 453 | ||
| 452 | static const struct soc_enum da9055_hold_time = | 454 | static SOC_ENUM_SINGLE_DECL(da9055_hold_time, |
| 453 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt); | 455 | DA9055_ALC_CTRL3, 0, da9055_hold_time_txt); |
| 454 | 456 | ||
| 455 | static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) | 457 | static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) |
| 456 | { | 458 | { |
| @@ -1536,11 +1538,17 @@ static const struct i2c_device_id da9055_i2c_id[] = { | |||
| 1536 | }; | 1538 | }; |
| 1537 | MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); | 1539 | MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); |
| 1538 | 1540 | ||
| 1541 | static const struct of_device_id da9055_of_match[] = { | ||
| 1542 | { .compatible = "dlg,da9055-codec", }, | ||
| 1543 | { } | ||
| 1544 | }; | ||
| 1545 | |||
| 1539 | /* I2C codec control layer */ | 1546 | /* I2C codec control layer */ |
| 1540 | static struct i2c_driver da9055_i2c_driver = { | 1547 | static struct i2c_driver da9055_i2c_driver = { |
| 1541 | .driver = { | 1548 | .driver = { |
| 1542 | .name = "da9055-codec", | 1549 | .name = "da9055-codec", |
| 1543 | .owner = THIS_MODULE, | 1550 | .owner = THIS_MODULE, |
| 1551 | .of_match_table = of_match_ptr(da9055_of_match), | ||
| 1544 | }, | 1552 | }, |
| 1545 | .probe = da9055_i2c_probe, | 1553 | .probe = da9055_i2c_probe, |
| 1546 | .remove = da9055_remove, | 1554 | .remove = da9055_remove, |
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index e19490cfb3a8..6b7fe5e54881 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
| @@ -195,18 +195,18 @@ struct lm49453_priv { | |||
| 195 | 195 | ||
| 196 | static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; | 196 | static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; |
| 197 | 197 | ||
| 198 | static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, | 198 | static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, |
| 199 | lm49453_mic2mode_text); | 199 | lm49453_mic2mode_text); |
| 200 | 200 | ||
| 201 | static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; | 201 | static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; |
| 202 | 202 | ||
| 203 | static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, | 203 | static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, |
| 204 | LM49453_P0_DIGITAL_MIC1_CONFIG_REG, | 204 | LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7, |
| 205 | 7, lm49453_dmic_cfg_text); | 205 | lm49453_dmic_cfg_text); |
| 206 | 206 | ||
| 207 | static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, | 207 | static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, |
| 208 | LM49453_P0_DIGITAL_MIC2_CONFIG_REG, | 208 | LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7, |
| 209 | 7, lm49453_dmic_cfg_text); | 209 | lm49453_dmic_cfg_text); |
| 210 | 210 | ||
| 211 | /* MUX Controls */ | 211 | /* MUX Controls */ |
| 212 | static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" }; | 212 | static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" }; |
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index ee660e2d3df3..bb1ecfc4459b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
| @@ -1849,7 +1849,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec) | |||
| 1849 | 1849 | ||
| 1850 | /* Now point the soc_enum to .texts array items */ | 1850 | /* Now point the soc_enum to .texts array items */ |
| 1851 | max98088->eq_enum.texts = max98088->eq_texts; | 1851 | max98088->eq_enum.texts = max98088->eq_texts; |
| 1852 | max98088->eq_enum.max = max98088->eq_textcnt; | 1852 | max98088->eq_enum.items = max98088->eq_textcnt; |
| 1853 | 1853 | ||
| 1854 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 1854 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
| 1855 | if (ret != 0) | 1855 | if (ret != 0) |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 9f714ea86613..f363de19be07 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
| @@ -513,65 +513,75 @@ static const char *max98090_perf_pwr_text[] = | |||
| 513 | static const char *max98090_pwr_perf_text[] = | 513 | static const char *max98090_pwr_perf_text[] = |
| 514 | { "Low Power", "High Performance" }; | 514 | { "Low Power", "High Performance" }; |
| 515 | 515 | ||
| 516 | static const struct soc_enum max98090_vcmbandgap_enum = | 516 | static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum, |
| 517 | SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, | 517 | M98090_REG_BIAS_CONTROL, |
| 518 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 518 | M98090_VCM_MODE_SHIFT, |
| 519 | max98090_pwr_perf_text); | ||
| 519 | 520 | ||
| 520 | static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; | 521 | static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; |
| 521 | 522 | ||
| 522 | static const struct soc_enum max98090_osr128_enum = | 523 | static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum, |
| 523 | SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, | 524 | M98090_REG_ADC_CONTROL, |
| 524 | ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text); | 525 | M98090_OSR128_SHIFT, |
| 526 | max98090_osr128_text); | ||
| 525 | 527 | ||
| 526 | static const char *max98090_mode_text[] = { "Voice", "Music" }; | 528 | static const char *max98090_mode_text[] = { "Voice", "Music" }; |
| 527 | 529 | ||
| 528 | static const struct soc_enum max98090_mode_enum = | 530 | static SOC_ENUM_SINGLE_DECL(max98090_mode_enum, |
| 529 | SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT, | 531 | M98090_REG_FILTER_CONFIG, |
| 530 | ARRAY_SIZE(max98090_mode_text), max98090_mode_text); | 532 | M98090_MODE_SHIFT, |
| 533 | max98090_mode_text); | ||
| 531 | 534 | ||
| 532 | static const struct soc_enum max98090_filter_dmic34mode_enum = | 535 | static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum, |
| 533 | SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, | 536 | M98090_REG_FILTER_CONFIG, |
| 534 | M98090_FLT_DMIC34MODE_SHIFT, | 537 | M98090_FLT_DMIC34MODE_SHIFT, |
| 535 | ARRAY_SIZE(max98090_mode_text), max98090_mode_text); | 538 | max98090_mode_text); |
| 536 | 539 | ||
| 537 | static const char *max98090_drcatk_text[] = | 540 | static const char *max98090_drcatk_text[] = |
| 538 | { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; | 541 | { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; |
| 539 | 542 | ||
| 540 | static const struct soc_enum max98090_drcatk_enum = | 543 | static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum, |
| 541 | SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, | 544 | M98090_REG_DRC_TIMING, |
| 542 | ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); | 545 | M98090_DRCATK_SHIFT, |
| 546 | max98090_drcatk_text); | ||
| 543 | 547 | ||
| 544 | static const char *max98090_drcrls_text[] = | 548 | static const char *max98090_drcrls_text[] = |
| 545 | { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; | 549 | { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; |
| 546 | 550 | ||
| 547 | static const struct soc_enum max98090_drcrls_enum = | 551 | static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum, |
| 548 | SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, | 552 | M98090_REG_DRC_TIMING, |
| 549 | ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); | 553 | M98090_DRCRLS_SHIFT, |
| 554 | max98090_drcrls_text); | ||
| 550 | 555 | ||
| 551 | static const char *max98090_alccmp_text[] = | 556 | static const char *max98090_alccmp_text[] = |
| 552 | { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; | 557 | { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; |
| 553 | 558 | ||
| 554 | static const struct soc_enum max98090_alccmp_enum = | 559 | static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum, |
| 555 | SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, | 560 | M98090_REG_DRC_COMPRESSOR, |
| 556 | ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); | 561 | M98090_DRCCMP_SHIFT, |
| 562 | max98090_alccmp_text); | ||
| 557 | 563 | ||
| 558 | static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; | 564 | static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; |
| 559 | 565 | ||
| 560 | static const struct soc_enum max98090_drcexp_enum = | 566 | static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum, |
| 561 | SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, | 567 | M98090_REG_DRC_EXPANDER, |
| 562 | ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text); | 568 | M98090_DRCEXP_SHIFT, |
| 569 | max98090_drcexp_text); | ||
| 563 | 570 | ||
| 564 | static const struct soc_enum max98090_dac_perfmode_enum = | 571 | static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum, |
| 565 | SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT, | 572 | M98090_REG_DAC_CONTROL, |
| 566 | ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text); | 573 | M98090_PERFMODE_SHIFT, |
| 574 | max98090_perf_pwr_text); | ||
| 567 | 575 | ||
| 568 | static const struct soc_enum max98090_dachp_enum = | 576 | static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum, |
| 569 | SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT, | 577 | M98090_REG_DAC_CONTROL, |
| 570 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 578 | M98090_DACHP_SHIFT, |
| 579 | max98090_pwr_perf_text); | ||
| 571 | 580 | ||
| 572 | static const struct soc_enum max98090_adchp_enum = | 581 | static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum, |
| 573 | SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT, | 582 | M98090_REG_ADC_CONTROL, |
| 574 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 583 | M98090_ADCHP_SHIFT, |
| 584 | max98090_pwr_perf_text); | ||
| 575 | 585 | ||
| 576 | static const struct snd_kcontrol_new max98090_snd_controls[] = { | 586 | static const struct snd_kcontrol_new max98090_snd_controls[] = { |
| 577 | SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), | 587 | SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), |
| @@ -842,39 +852,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | |||
| 842 | 852 | ||
| 843 | static const char *mic1_mux_text[] = { "IN12", "IN56" }; | 853 | static const char *mic1_mux_text[] = { "IN12", "IN56" }; |
| 844 | 854 | ||
| 845 | static const struct soc_enum mic1_mux_enum = | 855 | static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, |
| 846 | SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT, | 856 | M98090_REG_INPUT_MODE, |
| 847 | ARRAY_SIZE(mic1_mux_text), mic1_mux_text); | 857 | M98090_EXTMIC1_SHIFT, |
| 858 | mic1_mux_text); | ||
| 848 | 859 | ||
| 849 | static const struct snd_kcontrol_new max98090_mic1_mux = | 860 | static const struct snd_kcontrol_new max98090_mic1_mux = |
| 850 | SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); | 861 | SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); |
| 851 | 862 | ||
| 852 | static const char *mic2_mux_text[] = { "IN34", "IN56" }; | 863 | static const char *mic2_mux_text[] = { "IN34", "IN56" }; |
| 853 | 864 | ||
| 854 | static const struct soc_enum mic2_mux_enum = | 865 | static SOC_ENUM_SINGLE_DECL(mic2_mux_enum, |
| 855 | SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT, | 866 | M98090_REG_INPUT_MODE, |
| 856 | ARRAY_SIZE(mic2_mux_text), mic2_mux_text); | 867 | M98090_EXTMIC2_SHIFT, |
| 868 | mic2_mux_text); | ||
| 857 | 869 | ||
| 858 | static const struct snd_kcontrol_new max98090_mic2_mux = | 870 | static const struct snd_kcontrol_new max98090_mic2_mux = |
| 859 | SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); | 871 | SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); |
| 860 | 872 | ||
| 861 | static const char *dmic_mux_text[] = { "ADC", "DMIC" }; | 873 | static const char *dmic_mux_text[] = { "ADC", "DMIC" }; |
| 862 | 874 | ||
| 863 | static const struct soc_enum dmic_mux_enum = | 875 | static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); |
| 864 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text); | ||
| 865 | 876 | ||
| 866 | static const struct snd_kcontrol_new max98090_dmic_mux = | 877 | static const struct snd_kcontrol_new max98090_dmic_mux = |
| 867 | SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); | 878 | SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); |
| 868 | 879 | ||
| 869 | static const char *max98090_micpre_text[] = { "Off", "On" }; | 880 | static const char *max98090_micpre_text[] = { "Off", "On" }; |
| 870 | 881 | ||
| 871 | static const struct soc_enum max98090_pa1en_enum = | 882 | static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, |
| 872 | SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, | 883 | M98090_REG_MIC1_INPUT_LEVEL, |
| 873 | ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); | 884 | M98090_MIC_PA1EN_SHIFT, |
| 885 | max98090_micpre_text); | ||
| 874 | 886 | ||
| 875 | static const struct soc_enum max98090_pa2en_enum = | 887 | static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, |
| 876 | SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, | 888 | M98090_REG_MIC2_INPUT_LEVEL, |
| 877 | ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); | 889 | M98090_MIC_PA2EN_SHIFT, |
| 890 | max98090_micpre_text); | ||
| 878 | 891 | ||
| 879 | /* LINEA mixer switch */ | 892 | /* LINEA mixer switch */ |
| 880 | static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { | 893 | static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { |
| @@ -938,13 +951,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = { | |||
| 938 | 951 | ||
| 939 | static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; | 952 | static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; |
| 940 | 953 | ||
| 941 | static const struct soc_enum ltenl_mux_enum = | 954 | static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum, |
| 942 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, | 955 | M98090_REG_IO_CONFIGURATION, |
| 943 | ARRAY_SIZE(lten_mux_text), lten_mux_text); | 956 | M98090_LTEN_SHIFT, |
| 957 | lten_mux_text); | ||
| 944 | 958 | ||
| 945 | static const struct soc_enum ltenr_mux_enum = | 959 | static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum, |
| 946 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, | 960 | M98090_REG_IO_CONFIGURATION, |
| 947 | ARRAY_SIZE(lten_mux_text), lten_mux_text); | 961 | M98090_LTEN_SHIFT, |
| 962 | lten_mux_text); | ||
| 948 | 963 | ||
| 949 | static const struct snd_kcontrol_new max98090_ltenl_mux = | 964 | static const struct snd_kcontrol_new max98090_ltenl_mux = |
| 950 | SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); | 965 | SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); |
| @@ -954,13 +969,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux = | |||
| 954 | 969 | ||
| 955 | static const char *lben_mux_text[] = { "Normal", "Loopback" }; | 970 | static const char *lben_mux_text[] = { "Normal", "Loopback" }; |
| 956 | 971 | ||
| 957 | static const struct soc_enum lbenl_mux_enum = | 972 | static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum, |
| 958 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, | 973 | M98090_REG_IO_CONFIGURATION, |
| 959 | ARRAY_SIZE(lben_mux_text), lben_mux_text); | 974 | M98090_LBEN_SHIFT, |
| 975 | lben_mux_text); | ||
| 960 | 976 | ||
| 961 | static const struct soc_enum lbenr_mux_enum = | 977 | static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum, |
| 962 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, | 978 | M98090_REG_IO_CONFIGURATION, |
| 963 | ARRAY_SIZE(lben_mux_text), lben_mux_text); | 979 | M98090_LBEN_SHIFT, |
| 980 | lben_mux_text); | ||
| 964 | 981 | ||
| 965 | static const struct snd_kcontrol_new max98090_lbenl_mux = | 982 | static const struct snd_kcontrol_new max98090_lbenl_mux = |
| 966 | SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); | 983 | SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); |
| @@ -972,13 +989,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" }; | |||
| 972 | 989 | ||
| 973 | static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; | 990 | static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; |
| 974 | 991 | ||
| 975 | static const struct soc_enum stenl_mux_enum = | 992 | static SOC_ENUM_SINGLE_DECL(stenl_mux_enum, |
| 976 | SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT, | 993 | M98090_REG_ADC_SIDETONE, |
| 977 | ARRAY_SIZE(stenl_mux_text), stenl_mux_text); | 994 | M98090_DSTSL_SHIFT, |
| 995 | stenl_mux_text); | ||
| 978 | 996 | ||
| 979 | static const struct soc_enum stenr_mux_enum = | 997 | static SOC_ENUM_SINGLE_DECL(stenr_mux_enum, |
| 980 | SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT, | 998 | M98090_REG_ADC_SIDETONE, |
| 981 | ARRAY_SIZE(stenr_mux_text), stenr_mux_text); | 999 | M98090_DSTSR_SHIFT, |
| 1000 | stenr_mux_text); | ||
| 982 | 1001 | ||
| 983 | static const struct snd_kcontrol_new max98090_stenl_mux = | 1002 | static const struct snd_kcontrol_new max98090_stenl_mux = |
| 984 | SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); | 1003 | SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); |
| @@ -1086,9 +1105,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = { | |||
| 1086 | 1105 | ||
| 1087 | static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; | 1106 | static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; |
| 1088 | 1107 | ||
| 1089 | static const struct soc_enum linmod_mux_enum = | 1108 | static SOC_ENUM_SINGLE_DECL(linmod_mux_enum, |
| 1090 | SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT, | 1109 | M98090_REG_LOUTR_MIXER, |
| 1091 | ARRAY_SIZE(linmod_mux_text), linmod_mux_text); | 1110 | M98090_LINMOD_SHIFT, |
| 1111 | linmod_mux_text); | ||
| 1092 | 1112 | ||
| 1093 | static const struct snd_kcontrol_new max98090_linmod_mux = | 1113 | static const struct snd_kcontrol_new max98090_linmod_mux = |
| 1094 | SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); | 1114 | SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); |
| @@ -1098,16 +1118,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" }; | |||
| 1098 | /* | 1118 | /* |
| 1099 | * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable | 1119 | * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable |
| 1100 | */ | 1120 | */ |
| 1101 | static const struct soc_enum mixhplsel_mux_enum = | 1121 | static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum, |
| 1102 | SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT, | 1122 | M98090_REG_HP_CONTROL, |
| 1103 | ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); | 1123 | M98090_MIXHPLSEL_SHIFT, |
| 1124 | mixhpsel_mux_text); | ||
| 1104 | 1125 | ||
| 1105 | static const struct snd_kcontrol_new max98090_mixhplsel_mux = | 1126 | static const struct snd_kcontrol_new max98090_mixhplsel_mux = |
| 1106 | SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); | 1127 | SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); |
| 1107 | 1128 | ||
| 1108 | static const struct soc_enum mixhprsel_mux_enum = | 1129 | static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum, |
| 1109 | SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT, | 1130 | M98090_REG_HP_CONTROL, |
| 1110 | ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); | 1131 | M98090_MIXHPRSEL_SHIFT, |
| 1132 | mixhpsel_mux_text); | ||
| 1111 | 1133 | ||
| 1112 | static const struct snd_kcontrol_new max98090_mixhprsel_mux = | 1134 | static const struct snd_kcontrol_new max98090_mixhprsel_mux = |
| 1113 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); | 1135 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 3ba1170ebb53..5bce9cde4a6d 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
| @@ -1861,7 +1861,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec) | |||
| 1861 | 1861 | ||
| 1862 | /* Now point the soc_enum to .texts array items */ | 1862 | /* Now point the soc_enum to .texts array items */ |
| 1863 | max98095->eq_enum.texts = max98095->eq_texts; | 1863 | max98095->eq_enum.texts = max98095->eq_texts; |
| 1864 | max98095->eq_enum.max = max98095->eq_textcnt; | 1864 | max98095->eq_enum.items = max98095->eq_textcnt; |
| 1865 | 1865 | ||
| 1866 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 1866 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
| 1867 | if (ret != 0) | 1867 | if (ret != 0) |
| @@ -2016,7 +2016,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec) | |||
| 2016 | 2016 | ||
| 2017 | /* Now point the soc_enum to .texts array items */ | 2017 | /* Now point the soc_enum to .texts array items */ |
| 2018 | max98095->bq_enum.texts = max98095->bq_texts; | 2018 | max98095->bq_enum.texts = max98095->bq_texts; |
| 2019 | max98095->bq_enum.max = max98095->bq_textcnt; | 2019 | max98095->bq_enum.items = max98095->bq_textcnt; |
| 2020 | 2020 | ||
| 2021 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 2021 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
| 2022 | if (ret != 0) | 2022 | if (ret != 0) |
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 582c2bbd42cb..ec89b8f90a64 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c | |||
| @@ -408,8 +408,7 @@ static const char * const adcl_enum_text[] = { | |||
| 408 | "MC1L", "RXINL", | 408 | "MC1L", "RXINL", |
| 409 | }; | 409 | }; |
| 410 | 410 | ||
| 411 | static const struct soc_enum adcl_enum = | 411 | static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text); |
| 412 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text); | ||
| 413 | 412 | ||
| 414 | static const struct snd_kcontrol_new left_input_mux = | 413 | static const struct snd_kcontrol_new left_input_mux = |
| 415 | SOC_DAPM_ENUM_VIRT("Route", adcl_enum); | 414 | SOC_DAPM_ENUM_VIRT("Route", adcl_enum); |
| @@ -418,8 +417,7 @@ static const char * const adcr_enum_text[] = { | |||
| 418 | "MC1R", "MC2", "RXINR", "TXIN", | 417 | "MC1R", "MC2", "RXINR", "TXIN", |
| 419 | }; | 418 | }; |
| 420 | 419 | ||
| 421 | static const struct soc_enum adcr_enum = | 420 | static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text); |
| 422 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text); | ||
| 423 | 421 | ||
| 424 | static const struct snd_kcontrol_new right_input_mux = | 422 | static const struct snd_kcontrol_new right_input_mux = |
| 425 | SOC_DAPM_ENUM_VIRT("Route", adcr_enum); | 423 | SOC_DAPM_ENUM_VIRT("Route", adcr_enum); |
| @@ -430,8 +428,8 @@ static const struct snd_kcontrol_new samp_ctl = | |||
| 430 | static const char * const speaker_amp_source_text[] = { | 428 | static const char * const speaker_amp_source_text[] = { |
| 431 | "CODEC", "Right" | 429 | "CODEC", "Right" |
| 432 | }; | 430 | }; |
| 433 | static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, | 431 | static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, |
| 434 | speaker_amp_source_text); | 432 | speaker_amp_source_text); |
| 435 | static const struct snd_kcontrol_new speaker_amp_source_mux = | 433 | static const struct snd_kcontrol_new speaker_amp_source_mux = |
| 436 | SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); | 434 | SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); |
| 437 | 435 | ||
| @@ -439,8 +437,8 @@ static const char * const headset_amp_source_text[] = { | |||
| 439 | "CODEC", "Mixer" | 437 | "CODEC", "Mixer" |
| 440 | }; | 438 | }; |
| 441 | 439 | ||
| 442 | static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, | 440 | static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, |
| 443 | headset_amp_source_text); | 441 | headset_amp_source_text); |
| 444 | static const struct snd_kcontrol_new headset_amp_source_mux = | 442 | static const struct snd_kcontrol_new headset_amp_source_mux = |
| 445 | SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); | 443 | SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); |
| 446 | 444 | ||
| @@ -580,9 +578,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = { | |||
| 580 | static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", | 578 | static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", |
| 581 | "Mono", "Mono Mix"}; | 579 | "Mono", "Mono Mix"}; |
| 582 | 580 | ||
| 583 | static const struct soc_enum mc13783_enum_3d_mixer = | 581 | static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer, |
| 584 | SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer), | 582 | MC13783_AUDIO_RX1, 16, |
| 585 | mc13783_3d_mixer); | 583 | mc13783_3d_mixer); |
| 586 | 584 | ||
| 587 | static struct snd_kcontrol_new mc13783_control_list[] = { | 585 | static struct snd_kcontrol_new mc13783_control_list[] = { |
| 588 | SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), | 586 | SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), |
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 185fa3bc3052..577fb8776ce7 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c | |||
| @@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); | |||
| 73 | static const char * const ml26124_companding[] = {"16bit PCM", "u-law", | 73 | static const char * const ml26124_companding[] = {"16bit PCM", "u-law", |
| 74 | "A-law"}; | 74 | "A-law"}; |
| 75 | 75 | ||
| 76 | static const struct soc_enum ml26124_adc_companding_enum | 76 | static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum, |
| 77 | = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding); | 77 | ML26124_SAI_TRANS_CTL, 6, ml26124_companding); |
| 78 | 78 | ||
| 79 | static const struct soc_enum ml26124_dac_companding_enum | 79 | static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum, |
| 80 | = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding); | 80 | ML26124_SAI_RCV_CTL, 6, ml26124_companding); |
| 81 | 81 | ||
| 82 | static const struct snd_kcontrol_new ml26124_snd_controls[] = { | 82 | static const struct snd_kcontrol_new ml26124_snd_controls[] = { |
| 83 | SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, | 83 | SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, |
| @@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = { | |||
| 136 | static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in", | 136 | static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in", |
| 137 | "Digital MIC in", "Analog MIC Differential in"}; | 137 | "Digital MIC in", "Analog MIC Differential in"}; |
| 138 | 138 | ||
| 139 | static const struct soc_enum ml26124_insel_enum = | 139 | static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum, |
| 140 | SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select); | 140 | ML26124_MIC_IF_CTL, 0, ml26124_input_select); |
| 141 | 141 | ||
| 142 | static const struct snd_kcontrol_new ml26124_input_mux_controls = | 142 | static const struct snd_kcontrol_new ml26124_input_mux_controls = |
| 143 | SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); | 143 | SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); |
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 73f9c3630e2c..e427544183d7 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c | |||
| @@ -172,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, | |||
| 172 | struct snd_soc_codec *codec = dai->codec; | 172 | struct snd_soc_codec *codec = dai->codec; |
| 173 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | 173 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); |
| 174 | int val = 0, ret; | 174 | int val = 0, ret; |
| 175 | int pcm_format = params_format(params); | ||
| 176 | 175 | ||
| 177 | priv->rate = params_rate(params); | 176 | priv->rate = params_rate(params); |
| 178 | 177 | ||
| 179 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | 178 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 180 | case SND_SOC_DAIFMT_RIGHT_J: | 179 | case SND_SOC_DAIFMT_RIGHT_J: |
| 181 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) | 180 | switch (params_width(params)) { |
| 182 | val = 0x00; | 181 | case 24: |
| 183 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 182 | val = 0; |
| 184 | val = 0x03; | 183 | break; |
| 184 | case 16: | ||
| 185 | val = 3; | ||
| 186 | break; | ||
| 187 | default: | ||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 185 | break; | 190 | break; |
| 186 | case SND_SOC_DAIFMT_I2S: | 191 | case SND_SOC_DAIFMT_I2S: |
| 187 | val = 0x04; | 192 | val = 0x04; |
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 7146653a8e16..3a80ba4452df 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c | |||
| @@ -107,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream, | |||
| 107 | struct snd_soc_codec *codec = dai->codec; | 107 | struct snd_soc_codec *codec = dai->codec; |
| 108 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); | 108 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); |
| 109 | int val = 0, ret; | 109 | int val = 0, ret; |
| 110 | int pcm_format = params_format(params); | ||
| 111 | 110 | ||
| 112 | priv->rate = params_rate(params); | 111 | priv->rate = params_rate(params); |
| 113 | 112 | ||
| 114 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | 113 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 115 | case SND_SOC_DAIFMT_RIGHT_J: | 114 | case SND_SOC_DAIFMT_RIGHT_J: |
| 116 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | 115 | switch (params_width(params)) { |
| 117 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | 116 | case 24: |
| 118 | val = 0x02; | 117 | case 32: |
| 119 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 118 | val = 2; |
| 120 | val = 0x00; | 119 | break; |
| 120 | case 16: | ||
| 121 | val = 0; | ||
| 122 | break; | ||
| 123 | default: | ||
| 124 | return -EINVAL; | ||
| 125 | } | ||
| 121 | break; | 126 | break; |
| 122 | case SND_SOC_DAIFMT_I2S: | 127 | case SND_SOC_DAIFMT_I2S: |
| 123 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | 128 | switch (params_width(params)) { |
| 124 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | 129 | case 24: |
| 125 | val = 0x05; | 130 | case 32: |
| 126 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 131 | val = 5; |
| 127 | val = 0x04; | 132 | break; |
| 133 | case 16: | ||
| 134 | val = 4; | ||
| 135 | break; | ||
| 136 | default: | ||
| 137 | return -EINVAL; | ||
| 138 | } | ||
| 128 | break; | 139 | break; |
| 129 | default: | 140 | default: |
| 130 | dev_err(codec->dev, "Invalid DAI format\n"); | 141 | dev_err(codec->dev, "Invalid DAI format\n"); |
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c new file mode 100644 index 000000000000..4d62230bd378 --- /dev/null +++ b/sound/soc/codecs/pcm512x-i2c.c | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the PCM512x CODECs | ||
| 3 | * | ||
| 4 | * Author: Mark Brown <broonie@linaro.org> | ||
| 5 | * Copyright 2014 Linaro Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/i2c.h> | ||
| 20 | |||
| 21 | #include "pcm512x.h" | ||
| 22 | |||
| 23 | static int pcm512x_i2c_probe(struct i2c_client *i2c, | ||
| 24 | const struct i2c_device_id *id) | ||
| 25 | { | ||
| 26 | struct regmap *regmap; | ||
| 27 | |||
| 28 | regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); | ||
| 29 | if (IS_ERR(regmap)) | ||
| 30 | return PTR_ERR(regmap); | ||
| 31 | |||
| 32 | return pcm512x_probe(&i2c->dev, regmap); | ||
| 33 | } | ||
| 34 | |||
| 35 | static int pcm512x_i2c_remove(struct i2c_client *i2c) | ||
| 36 | { | ||
| 37 | pcm512x_remove(&i2c->dev); | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | static const struct i2c_device_id pcm512x_i2c_id[] = { | ||
| 42 | { "pcm5121", }, | ||
| 43 | { "pcm5122", }, | ||
| 44 | { } | ||
| 45 | }; | ||
| 46 | MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); | ||
| 47 | |||
| 48 | static const struct of_device_id pcm512x_of_match[] = { | ||
| 49 | { .compatible = "ti,pcm5121", }, | ||
| 50 | { .compatible = "ti,pcm5122", }, | ||
| 51 | { } | ||
| 52 | }; | ||
| 53 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
| 54 | |||
| 55 | static struct i2c_driver pcm512x_i2c_driver = { | ||
| 56 | .probe = pcm512x_i2c_probe, | ||
| 57 | .remove = pcm512x_i2c_remove, | ||
| 58 | .id_table = pcm512x_i2c_id, | ||
| 59 | .driver = { | ||
| 60 | .name = "pcm512x", | ||
| 61 | .owner = THIS_MODULE, | ||
| 62 | .of_match_table = pcm512x_of_match, | ||
| 63 | .pm = &pcm512x_pm_ops, | ||
| 64 | }, | ||
| 65 | }; | ||
| 66 | |||
| 67 | module_i2c_driver(pcm512x_i2c_driver); | ||
| 68 | |||
| 69 | MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C"); | ||
| 70 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
| 71 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c new file mode 100644 index 000000000000..f297058c0038 --- /dev/null +++ b/sound/soc/codecs/pcm512x-spi.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the PCM512x CODECs | ||
| 3 | * | ||
| 4 | * Author: Mark Brown <broonie@linaro.org> | ||
| 5 | * Copyright 2014 Linaro Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/spi/spi.h> | ||
| 20 | |||
| 21 | #include "pcm512x.h" | ||
| 22 | |||
| 23 | static int pcm512x_spi_probe(struct spi_device *spi) | ||
| 24 | { | ||
| 25 | struct regmap *regmap; | ||
| 26 | int ret; | ||
| 27 | |||
| 28 | regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); | ||
| 29 | if (IS_ERR(regmap)) { | ||
| 30 | ret = PTR_ERR(regmap); | ||
| 31 | return ret; | ||
| 32 | } | ||
| 33 | |||
| 34 | return pcm512x_probe(&spi->dev, regmap); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int pcm512x_spi_remove(struct spi_device *spi) | ||
| 38 | { | ||
| 39 | pcm512x_remove(&spi->dev); | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | static const struct spi_device_id pcm512x_spi_id[] = { | ||
| 44 | { "pcm5121", }, | ||
| 45 | { "pcm5122", }, | ||
| 46 | { }, | ||
| 47 | }; | ||
| 48 | MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); | ||
| 49 | |||
| 50 | static const struct of_device_id pcm512x_of_match[] = { | ||
| 51 | { .compatible = "ti,pcm5121", }, | ||
| 52 | { .compatible = "ti,pcm5122", }, | ||
| 53 | { } | ||
| 54 | }; | ||
| 55 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
| 56 | |||
| 57 | static struct spi_driver pcm512x_spi_driver = { | ||
| 58 | .probe = pcm512x_spi_probe, | ||
| 59 | .remove = pcm512x_spi_remove, | ||
| 60 | .id_table = pcm512x_spi_id, | ||
| 61 | .driver = { | ||
| 62 | .name = "pcm512x", | ||
| 63 | .owner = THIS_MODULE, | ||
| 64 | .of_match_table = pcm512x_of_match, | ||
| 65 | .pm = &pcm512x_pm_ops, | ||
| 66 | }, | ||
| 67 | }; | ||
| 68 | |||
| 69 | module_spi_driver(pcm512x_spi_driver); | ||
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c new file mode 100644 index 000000000000..4b4c0c7bb918 --- /dev/null +++ b/sound/soc/codecs/pcm512x.c | |||
| @@ -0,0 +1,589 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the PCM512x CODECs | ||
| 3 | * | ||
| 4 | * Author: Mark Brown <broonie@linaro.org> | ||
| 5 | * Copyright 2014 Linaro Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | |||
| 18 | #include <linux/init.h> | ||
| 19 | #include <linux/module.h> | ||
| 20 | #include <linux/clk.h> | ||
| 21 | #include <linux/pm_runtime.h> | ||
| 22 | #include <linux/regmap.h> | ||
| 23 | #include <linux/regulator/consumer.h> | ||
| 24 | #include <sound/soc.h> | ||
| 25 | #include <sound/soc-dapm.h> | ||
| 26 | #include <sound/tlv.h> | ||
| 27 | |||
| 28 | #include "pcm512x.h" | ||
| 29 | |||
| 30 | #define PCM512x_NUM_SUPPLIES 3 | ||
| 31 | static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { | ||
| 32 | "AVDD", | ||
| 33 | "DVDD", | ||
| 34 | "CPVDD", | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct pcm512x_priv { | ||
| 38 | struct regmap *regmap; | ||
| 39 | struct clk *sclk; | ||
| 40 | struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; | ||
| 41 | struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; | ||
| 42 | }; | ||
| 43 | |||
| 44 | /* | ||
| 45 | * We can't use the same notifier block for more than one supply and | ||
| 46 | * there's no way I can see to get from a callback to the caller | ||
| 47 | * except container_of(). | ||
| 48 | */ | ||
| 49 | #define PCM512x_REGULATOR_EVENT(n) \ | ||
| 50 | static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ | ||
| 51 | unsigned long event, void *data) \ | ||
| 52 | { \ | ||
| 53 | struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ | ||
| 54 | supply_nb[n]); \ | ||
| 55 | if (event & REGULATOR_EVENT_DISABLE) { \ | ||
| 56 | regcache_mark_dirty(pcm512x->regmap); \ | ||
| 57 | regcache_cache_only(pcm512x->regmap, true); \ | ||
| 58 | } \ | ||
| 59 | return 0; \ | ||
| 60 | } | ||
| 61 | |||
| 62 | PCM512x_REGULATOR_EVENT(0) | ||
| 63 | PCM512x_REGULATOR_EVENT(1) | ||
| 64 | PCM512x_REGULATOR_EVENT(2) | ||
| 65 | |||
| 66 | static const struct reg_default pcm512x_reg_defaults[] = { | ||
| 67 | { PCM512x_RESET, 0x00 }, | ||
| 68 | { PCM512x_POWER, 0x00 }, | ||
| 69 | { PCM512x_MUTE, 0x00 }, | ||
| 70 | { PCM512x_DSP, 0x00 }, | ||
| 71 | { PCM512x_PLL_REF, 0x00 }, | ||
| 72 | { PCM512x_DAC_ROUTING, 0x11 }, | ||
| 73 | { PCM512x_DSP_PROGRAM, 0x01 }, | ||
| 74 | { PCM512x_CLKDET, 0x00 }, | ||
| 75 | { PCM512x_AUTO_MUTE, 0x00 }, | ||
| 76 | { PCM512x_ERROR_DETECT, 0x00 }, | ||
| 77 | { PCM512x_DIGITAL_VOLUME_1, 0x00 }, | ||
| 78 | { PCM512x_DIGITAL_VOLUME_2, 0x30 }, | ||
| 79 | { PCM512x_DIGITAL_VOLUME_3, 0x30 }, | ||
| 80 | { PCM512x_DIGITAL_MUTE_1, 0x22 }, | ||
| 81 | { PCM512x_DIGITAL_MUTE_2, 0x00 }, | ||
| 82 | { PCM512x_DIGITAL_MUTE_3, 0x07 }, | ||
| 83 | { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, | ||
| 84 | { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, | ||
| 85 | { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, | ||
| 86 | { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, | ||
| 87 | { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, | ||
| 88 | { PCM512x_VCOM_CTRL_1, 0x00 }, | ||
| 89 | { PCM512x_VCOM_CTRL_2, 0x01 }, | ||
| 90 | }; | ||
| 91 | |||
| 92 | static bool pcm512x_readable(struct device *dev, unsigned int reg) | ||
| 93 | { | ||
| 94 | switch (reg) { | ||
| 95 | case PCM512x_RESET: | ||
| 96 | case PCM512x_POWER: | ||
| 97 | case PCM512x_MUTE: | ||
| 98 | case PCM512x_PLL_EN: | ||
| 99 | case PCM512x_SPI_MISO_FUNCTION: | ||
| 100 | case PCM512x_DSP: | ||
| 101 | case PCM512x_GPIO_EN: | ||
| 102 | case PCM512x_BCLK_LRCLK_CFG: | ||
| 103 | case PCM512x_DSP_GPIO_INPUT: | ||
| 104 | case PCM512x_MASTER_MODE: | ||
| 105 | case PCM512x_PLL_REF: | ||
| 106 | case PCM512x_PLL_COEFF_0: | ||
| 107 | case PCM512x_PLL_COEFF_1: | ||
| 108 | case PCM512x_PLL_COEFF_2: | ||
| 109 | case PCM512x_PLL_COEFF_3: | ||
| 110 | case PCM512x_PLL_COEFF_4: | ||
| 111 | case PCM512x_DSP_CLKDIV: | ||
| 112 | case PCM512x_DAC_CLKDIV: | ||
| 113 | case PCM512x_NCP_CLKDIV: | ||
| 114 | case PCM512x_OSR_CLKDIV: | ||
| 115 | case PCM512x_MASTER_CLKDIV_1: | ||
| 116 | case PCM512x_MASTER_CLKDIV_2: | ||
| 117 | case PCM512x_FS_SPEED_MODE: | ||
| 118 | case PCM512x_IDAC_1: | ||
| 119 | case PCM512x_IDAC_2: | ||
| 120 | case PCM512x_ERROR_DETECT: | ||
| 121 | case PCM512x_I2S_1: | ||
| 122 | case PCM512x_I2S_2: | ||
| 123 | case PCM512x_DAC_ROUTING: | ||
| 124 | case PCM512x_DSP_PROGRAM: | ||
| 125 | case PCM512x_CLKDET: | ||
| 126 | case PCM512x_AUTO_MUTE: | ||
| 127 | case PCM512x_DIGITAL_VOLUME_1: | ||
| 128 | case PCM512x_DIGITAL_VOLUME_2: | ||
| 129 | case PCM512x_DIGITAL_VOLUME_3: | ||
| 130 | case PCM512x_DIGITAL_MUTE_1: | ||
| 131 | case PCM512x_DIGITAL_MUTE_2: | ||
| 132 | case PCM512x_DIGITAL_MUTE_3: | ||
| 133 | case PCM512x_GPIO_OUTPUT_1: | ||
| 134 | case PCM512x_GPIO_OUTPUT_2: | ||
| 135 | case PCM512x_GPIO_OUTPUT_3: | ||
| 136 | case PCM512x_GPIO_OUTPUT_4: | ||
| 137 | case PCM512x_GPIO_OUTPUT_5: | ||
| 138 | case PCM512x_GPIO_OUTPUT_6: | ||
| 139 | case PCM512x_GPIO_CONTROL_1: | ||
| 140 | case PCM512x_GPIO_CONTROL_2: | ||
| 141 | case PCM512x_OVERFLOW: | ||
| 142 | case PCM512x_RATE_DET_1: | ||
| 143 | case PCM512x_RATE_DET_2: | ||
| 144 | case PCM512x_RATE_DET_3: | ||
| 145 | case PCM512x_RATE_DET_4: | ||
| 146 | case PCM512x_ANALOG_MUTE_DET: | ||
| 147 | case PCM512x_GPIN: | ||
| 148 | case PCM512x_DIGITAL_MUTE_DET: | ||
| 149 | case PCM512x_OUTPUT_AMPLITUDE: | ||
| 150 | case PCM512x_ANALOG_GAIN_CTRL: | ||
| 151 | case PCM512x_UNDERVOLTAGE_PROT: | ||
| 152 | case PCM512x_ANALOG_MUTE_CTRL: | ||
| 153 | case PCM512x_ANALOG_GAIN_BOOST: | ||
| 154 | case PCM512x_VCOM_CTRL_1: | ||
| 155 | case PCM512x_VCOM_CTRL_2: | ||
| 156 | case PCM512x_CRAM_CTRL: | ||
| 157 | return true; | ||
| 158 | default: | ||
| 159 | /* There are 256 raw register addresses */ | ||
| 160 | return reg < 0xff; | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | static bool pcm512x_volatile(struct device *dev, unsigned int reg) | ||
| 165 | { | ||
| 166 | switch (reg) { | ||
| 167 | case PCM512x_PLL_EN: | ||
| 168 | case PCM512x_OVERFLOW: | ||
| 169 | case PCM512x_RATE_DET_1: | ||
| 170 | case PCM512x_RATE_DET_2: | ||
| 171 | case PCM512x_RATE_DET_3: | ||
| 172 | case PCM512x_RATE_DET_4: | ||
| 173 | case PCM512x_ANALOG_MUTE_DET: | ||
| 174 | case PCM512x_GPIN: | ||
| 175 | case PCM512x_DIGITAL_MUTE_DET: | ||
| 176 | case PCM512x_CRAM_CTRL: | ||
| 177 | return true; | ||
| 178 | default: | ||
| 179 | /* There are 256 raw register addresses */ | ||
| 180 | return reg < 0xff; | ||
| 181 | } | ||
| 182 | } | ||
| 183 | |||
| 184 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); | ||
| 185 | static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); | ||
| 186 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); | ||
| 187 | |||
| 188 | static const char * const pcm512x_dsp_program_texts[] = { | ||
| 189 | "FIR interpolation with de-emphasis", | ||
| 190 | "Low latency IIR with de-emphasis", | ||
| 191 | "Fixed process flow", | ||
| 192 | "High attenuation with de-emphasis", | ||
| 193 | "Ringing-less low latency FIR", | ||
| 194 | }; | ||
| 195 | |||
| 196 | static const unsigned int pcm512x_dsp_program_values[] = { | ||
| 197 | 1, | ||
| 198 | 2, | ||
| 199 | 3, | ||
| 200 | 5, | ||
| 201 | 7, | ||
| 202 | }; | ||
| 203 | |||
| 204 | static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, | ||
| 205 | PCM512x_DSP_PROGRAM, 0, 0x1f, | ||
| 206 | pcm512x_dsp_program_texts, | ||
| 207 | pcm512x_dsp_program_values); | ||
| 208 | |||
| 209 | static const char * const pcm512x_clk_missing_text[] = { | ||
| 210 | "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" | ||
| 211 | }; | ||
| 212 | |||
| 213 | static const struct soc_enum pcm512x_clk_missing = | ||
| 214 | SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); | ||
| 215 | |||
| 216 | static const char * const pcm512x_autom_text[] = { | ||
| 217 | "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" | ||
| 218 | }; | ||
| 219 | |||
| 220 | static const struct soc_enum pcm512x_autom_l = | ||
| 221 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, | ||
| 222 | pcm512x_autom_text); | ||
| 223 | |||
| 224 | static const struct soc_enum pcm512x_autom_r = | ||
| 225 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, | ||
| 226 | pcm512x_autom_text); | ||
| 227 | |||
| 228 | static const char * const pcm512x_ramp_rate_text[] = { | ||
| 229 | "1 sample/update", "2 samples/update", "4 samples/update", | ||
| 230 | "Immediate" | ||
| 231 | }; | ||
| 232 | |||
| 233 | static const struct soc_enum pcm512x_vndf = | ||
| 234 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, | ||
| 235 | pcm512x_ramp_rate_text); | ||
| 236 | |||
| 237 | static const struct soc_enum pcm512x_vnuf = | ||
| 238 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, | ||
| 239 | pcm512x_ramp_rate_text); | ||
| 240 | |||
| 241 | static const struct soc_enum pcm512x_vedf = | ||
| 242 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, | ||
| 243 | pcm512x_ramp_rate_text); | ||
| 244 | |||
| 245 | static const char * const pcm512x_ramp_step_text[] = { | ||
| 246 | "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" | ||
| 247 | }; | ||
| 248 | |||
| 249 | static const struct soc_enum pcm512x_vnds = | ||
| 250 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, | ||
| 251 | pcm512x_ramp_step_text); | ||
| 252 | |||
| 253 | static const struct soc_enum pcm512x_vnus = | ||
| 254 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, | ||
| 255 | pcm512x_ramp_step_text); | ||
| 256 | |||
| 257 | static const struct soc_enum pcm512x_veds = | ||
| 258 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, | ||
| 259 | pcm512x_ramp_step_text); | ||
| 260 | |||
| 261 | static const struct snd_kcontrol_new pcm512x_controls[] = { | ||
| 262 | SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, | ||
| 263 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), | ||
| 264 | SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, | ||
| 265 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), | ||
| 266 | SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, | ||
| 267 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), | ||
| 268 | SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, | ||
| 269 | PCM512x_RQMR_SHIFT, 1, 1), | ||
| 270 | |||
| 271 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), | ||
| 272 | SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), | ||
| 273 | |||
| 274 | SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), | ||
| 275 | SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), | ||
| 276 | SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), | ||
| 277 | SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, | ||
| 278 | PCM512x_ACTL_SHIFT, 1, 0), | ||
| 279 | SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, | ||
| 280 | PCM512x_AMLR_SHIFT, 1, 0), | ||
| 281 | |||
| 282 | SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), | ||
| 283 | SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), | ||
| 284 | SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), | ||
| 285 | SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), | ||
| 286 | SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), | ||
| 287 | SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), | ||
| 288 | }; | ||
| 289 | |||
| 290 | static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { | ||
| 291 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | ||
| 292 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | ||
| 293 | |||
| 294 | SND_SOC_DAPM_OUTPUT("OUTL"), | ||
| 295 | SND_SOC_DAPM_OUTPUT("OUTR"), | ||
| 296 | }; | ||
| 297 | |||
| 298 | static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { | ||
| 299 | { "DACL", NULL, "Playback" }, | ||
| 300 | { "DACR", NULL, "Playback" }, | ||
| 301 | |||
| 302 | { "OUTL", NULL, "DACL" }, | ||
| 303 | { "OUTR", NULL, "DACR" }, | ||
| 304 | }; | ||
| 305 | |||
| 306 | static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | ||
| 307 | enum snd_soc_bias_level level) | ||
| 308 | { | ||
| 309 | struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); | ||
| 310 | int ret; | ||
| 311 | |||
| 312 | switch (level) { | ||
| 313 | case SND_SOC_BIAS_ON: | ||
| 314 | case SND_SOC_BIAS_PREPARE: | ||
| 315 | break; | ||
| 316 | |||
| 317 | case SND_SOC_BIAS_STANDBY: | ||
| 318 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
| 319 | PCM512x_RQST, 0); | ||
| 320 | if (ret != 0) { | ||
| 321 | dev_err(codec->dev, "Failed to remove standby: %d\n", | ||
| 322 | ret); | ||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | break; | ||
| 326 | |||
| 327 | case SND_SOC_BIAS_OFF: | ||
| 328 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
| 329 | PCM512x_RQST, PCM512x_RQST); | ||
| 330 | if (ret != 0) { | ||
| 331 | dev_err(codec->dev, "Failed to request standby: %d\n", | ||
| 332 | ret); | ||
| 333 | return ret; | ||
| 334 | } | ||
| 335 | break; | ||
| 336 | } | ||
| 337 | |||
| 338 | codec->dapm.bias_level = level; | ||
| 339 | |||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | |||
| 343 | static struct snd_soc_dai_driver pcm512x_dai = { | ||
| 344 | .name = "pcm512x-hifi", | ||
| 345 | .playback = { | ||
| 346 | .stream_name = "Playback", | ||
| 347 | .channels_min = 2, | ||
| 348 | .channels_max = 2, | ||
| 349 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 350 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
| 351 | SNDRV_PCM_FMTBIT_S24_LE | | ||
| 352 | SNDRV_PCM_FMTBIT_S32_LE | ||
| 353 | }, | ||
| 354 | }; | ||
| 355 | |||
| 356 | static struct snd_soc_codec_driver pcm512x_codec_driver = { | ||
| 357 | .set_bias_level = pcm512x_set_bias_level, | ||
| 358 | .idle_bias_off = true, | ||
| 359 | |||
| 360 | .controls = pcm512x_controls, | ||
| 361 | .num_controls = ARRAY_SIZE(pcm512x_controls), | ||
| 362 | .dapm_widgets = pcm512x_dapm_widgets, | ||
| 363 | .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), | ||
| 364 | .dapm_routes = pcm512x_dapm_routes, | ||
| 365 | .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), | ||
| 366 | }; | ||
| 367 | |||
| 368 | static const struct regmap_range_cfg pcm512x_range = { | ||
| 369 | .name = "Pages", .range_min = PCM512x_VIRT_BASE, | ||
| 370 | .range_max = PCM512x_MAX_REGISTER, | ||
| 371 | .selector_reg = PCM512x_PAGE, | ||
| 372 | .selector_mask = 0xff, | ||
| 373 | .window_start = 0, .window_len = 0x100, | ||
| 374 | }; | ||
| 375 | |||
| 376 | const struct regmap_config pcm512x_regmap = { | ||
| 377 | .reg_bits = 8, | ||
| 378 | .val_bits = 8, | ||
| 379 | |||
| 380 | .readable_reg = pcm512x_readable, | ||
| 381 | .volatile_reg = pcm512x_volatile, | ||
| 382 | |||
| 383 | .ranges = &pcm512x_range, | ||
| 384 | .num_ranges = 1, | ||
| 385 | |||
| 386 | .max_register = PCM512x_MAX_REGISTER, | ||
| 387 | .reg_defaults = pcm512x_reg_defaults, | ||
| 388 | .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), | ||
| 389 | .cache_type = REGCACHE_RBTREE, | ||
| 390 | }; | ||
| 391 | EXPORT_SYMBOL_GPL(pcm512x_regmap); | ||
| 392 | |||
| 393 | int pcm512x_probe(struct device *dev, struct regmap *regmap) | ||
| 394 | { | ||
| 395 | struct pcm512x_priv *pcm512x; | ||
| 396 | int i, ret; | ||
| 397 | |||
| 398 | pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); | ||
| 399 | if (!pcm512x) | ||
| 400 | return -ENOMEM; | ||
| 401 | |||
| 402 | dev_set_drvdata(dev, pcm512x); | ||
| 403 | pcm512x->regmap = regmap; | ||
| 404 | |||
| 405 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) | ||
| 406 | pcm512x->supplies[i].supply = pcm512x_supply_names[i]; | ||
| 407 | |||
| 408 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), | ||
| 409 | pcm512x->supplies); | ||
| 410 | if (ret != 0) { | ||
| 411 | dev_err(dev, "Failed to get supplies: %d\n", ret); | ||
| 412 | return ret; | ||
| 413 | } | ||
| 414 | |||
| 415 | pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; | ||
| 416 | pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; | ||
| 417 | pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; | ||
| 418 | |||
| 419 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { | ||
| 420 | ret = regulator_register_notifier(pcm512x->supplies[i].consumer, | ||
| 421 | &pcm512x->supply_nb[i]); | ||
| 422 | if (ret != 0) { | ||
| 423 | dev_err(dev, | ||
| 424 | "Failed to register regulator notifier: %d\n", | ||
| 425 | ret); | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
| 430 | pcm512x->supplies); | ||
| 431 | if (ret != 0) { | ||
| 432 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
| 433 | return ret; | ||
| 434 | } | ||
| 435 | |||
| 436 | /* Reset the device, verifying I/O in the process for I2C */ | ||
| 437 | ret = regmap_write(regmap, PCM512x_RESET, | ||
| 438 | PCM512x_RSTM | PCM512x_RSTR); | ||
| 439 | if (ret != 0) { | ||
| 440 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
| 441 | goto err; | ||
| 442 | } | ||
| 443 | |||
| 444 | ret = regmap_write(regmap, PCM512x_RESET, 0); | ||
| 445 | if (ret != 0) { | ||
| 446 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
| 447 | goto err; | ||
| 448 | } | ||
| 449 | |||
| 450 | pcm512x->sclk = devm_clk_get(dev, NULL); | ||
| 451 | if (IS_ERR(pcm512x->sclk)) { | ||
| 452 | if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) | ||
| 453 | return -EPROBE_DEFER; | ||
| 454 | |||
| 455 | dev_info(dev, "No SCLK, using BCLK: %ld\n", | ||
| 456 | PTR_ERR(pcm512x->sclk)); | ||
| 457 | |||
| 458 | /* Disable reporting of missing SCLK as an error */ | ||
| 459 | regmap_update_bits(regmap, PCM512x_ERROR_DETECT, | ||
| 460 | PCM512x_IDCH, PCM512x_IDCH); | ||
| 461 | |||
| 462 | /* Switch PLL input to BCLK */ | ||
| 463 | regmap_update_bits(regmap, PCM512x_PLL_REF, | ||
| 464 | PCM512x_SREF, PCM512x_SREF); | ||
| 465 | } else { | ||
| 466 | ret = clk_prepare_enable(pcm512x->sclk); | ||
| 467 | if (ret != 0) { | ||
| 468 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
| 469 | return ret; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | |||
| 473 | /* Default to standby mode */ | ||
| 474 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
| 475 | PCM512x_RQST, PCM512x_RQST); | ||
| 476 | if (ret != 0) { | ||
| 477 | dev_err(dev, "Failed to request standby: %d\n", | ||
| 478 | ret); | ||
| 479 | goto err_clk; | ||
| 480 | } | ||
| 481 | |||
| 482 | pm_runtime_set_active(dev); | ||
| 483 | pm_runtime_enable(dev); | ||
| 484 | pm_runtime_idle(dev); | ||
| 485 | |||
| 486 | ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, | ||
| 487 | &pcm512x_dai, 1); | ||
| 488 | if (ret != 0) { | ||
| 489 | dev_err(dev, "Failed to register CODEC: %d\n", ret); | ||
| 490 | goto err_pm; | ||
| 491 | } | ||
| 492 | |||
| 493 | return 0; | ||
| 494 | |||
| 495 | err_pm: | ||
| 496 | pm_runtime_disable(dev); | ||
| 497 | err_clk: | ||
| 498 | if (!IS_ERR(pcm512x->sclk)) | ||
| 499 | clk_disable_unprepare(pcm512x->sclk); | ||
| 500 | err: | ||
| 501 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
| 502 | pcm512x->supplies); | ||
| 503 | return ret; | ||
| 504 | } | ||
| 505 | EXPORT_SYMBOL_GPL(pcm512x_probe); | ||
| 506 | |||
| 507 | void pcm512x_remove(struct device *dev) | ||
| 508 | { | ||
| 509 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
| 510 | |||
| 511 | snd_soc_unregister_codec(dev); | ||
| 512 | pm_runtime_disable(dev); | ||
| 513 | if (!IS_ERR(pcm512x->sclk)) | ||
| 514 | clk_disable_unprepare(pcm512x->sclk); | ||
| 515 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
| 516 | pcm512x->supplies); | ||
| 517 | } | ||
| 518 | EXPORT_SYMBOL_GPL(pcm512x_remove); | ||
| 519 | |||
| 520 | static int pcm512x_suspend(struct device *dev) | ||
| 521 | { | ||
| 522 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
| 523 | int ret; | ||
| 524 | |||
| 525 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
| 526 | PCM512x_RQPD, PCM512x_RQPD); | ||
| 527 | if (ret != 0) { | ||
| 528 | dev_err(dev, "Failed to request power down: %d\n", ret); | ||
| 529 | return ret; | ||
| 530 | } | ||
| 531 | |||
| 532 | ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
| 533 | pcm512x->supplies); | ||
| 534 | if (ret != 0) { | ||
| 535 | dev_err(dev, "Failed to disable supplies: %d\n", ret); | ||
| 536 | return ret; | ||
| 537 | } | ||
| 538 | |||
| 539 | if (!IS_ERR(pcm512x->sclk)) | ||
| 540 | clk_disable_unprepare(pcm512x->sclk); | ||
| 541 | |||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 545 | static int pcm512x_resume(struct device *dev) | ||
| 546 | { | ||
| 547 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
| 548 | int ret; | ||
| 549 | |||
| 550 | if (!IS_ERR(pcm512x->sclk)) { | ||
| 551 | ret = clk_prepare_enable(pcm512x->sclk); | ||
| 552 | if (ret != 0) { | ||
| 553 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
| 554 | return ret; | ||
| 555 | } | ||
| 556 | } | ||
| 557 | |||
| 558 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
| 559 | pcm512x->supplies); | ||
| 560 | if (ret != 0) { | ||
| 561 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
| 562 | return ret; | ||
| 563 | } | ||
| 564 | |||
| 565 | regcache_cache_only(pcm512x->regmap, false); | ||
| 566 | ret = regcache_sync(pcm512x->regmap); | ||
| 567 | if (ret != 0) { | ||
| 568 | dev_err(dev, "Failed to sync cache: %d\n", ret); | ||
| 569 | return ret; | ||
| 570 | } | ||
| 571 | |||
| 572 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
| 573 | PCM512x_RQPD, 0); | ||
| 574 | if (ret != 0) { | ||
| 575 | dev_err(dev, "Failed to remove power down: %d\n", ret); | ||
| 576 | return ret; | ||
| 577 | } | ||
| 578 | |||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | |||
| 582 | const struct dev_pm_ops pcm512x_pm_ops = { | ||
| 583 | SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) | ||
| 584 | }; | ||
| 585 | EXPORT_SYMBOL_GPL(pcm512x_pm_ops); | ||
| 586 | |||
| 587 | MODULE_DESCRIPTION("ASoC PCM512x codec driver"); | ||
| 588 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
| 589 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h new file mode 100644 index 000000000000..6ee76aaca09a --- /dev/null +++ b/sound/soc/codecs/pcm512x.h | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the PCM512x CODECs | ||
| 3 | * | ||
| 4 | * Author: Mark Brown <broonie@linaro.org> | ||
| 5 | * Copyright 2014 Linaro Ltd | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * version 2 as published by the Free Software Foundation. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, but | ||
| 12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 14 | * General Public License for more details. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef _SND_SOC_PCM512X | ||
| 18 | #define _SND_SOC_PCM512X | ||
| 19 | |||
| 20 | #include <linux/pm.h> | ||
| 21 | #include <linux/regmap.h> | ||
| 22 | |||
| 23 | #define PCM512x_VIRT_BASE 0x100 | ||
| 24 | #define PCM512x_PAGE_LEN 0x100 | ||
| 25 | #define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) | ||
| 26 | |||
| 27 | #define PCM512x_PAGE 0 | ||
| 28 | |||
| 29 | #define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1) | ||
| 30 | #define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2) | ||
| 31 | #define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3) | ||
| 32 | #define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4) | ||
| 33 | #define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6) | ||
| 34 | #define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7) | ||
| 35 | #define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8) | ||
| 36 | #define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9) | ||
| 37 | #define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) | ||
| 38 | #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) | ||
| 39 | #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) | ||
| 40 | #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) | ||
| 41 | #define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) | ||
| 42 | #define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) | ||
| 43 | #define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23) | ||
| 44 | #define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24) | ||
| 45 | #define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27) | ||
| 46 | #define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28) | ||
| 47 | #define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29) | ||
| 48 | #define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30) | ||
| 49 | #define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32) | ||
| 50 | #define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33) | ||
| 51 | #define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34) | ||
| 52 | #define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35) | ||
| 53 | #define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36) | ||
| 54 | #define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37) | ||
| 55 | #define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40) | ||
| 56 | #define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41) | ||
| 57 | #define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42) | ||
| 58 | #define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43) | ||
| 59 | #define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44) | ||
| 60 | #define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59) | ||
| 61 | #define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60) | ||
| 62 | #define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61) | ||
| 63 | #define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62) | ||
| 64 | #define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63) | ||
| 65 | #define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64) | ||
| 66 | #define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65) | ||
| 67 | #define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80) | ||
| 68 | #define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81) | ||
| 69 | #define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82) | ||
| 70 | #define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83) | ||
| 71 | #define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84) | ||
| 72 | #define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85) | ||
| 73 | #define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86) | ||
| 74 | #define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87) | ||
| 75 | #define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90) | ||
| 76 | #define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91) | ||
| 77 | #define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) | ||
| 78 | #define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) | ||
| 79 | #define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) | ||
| 80 | #define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) | ||
| 81 | #define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) | ||
| 82 | #define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) | ||
| 83 | |||
| 84 | #define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1) | ||
| 85 | #define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2) | ||
| 86 | #define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5) | ||
| 87 | #define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6) | ||
| 88 | #define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7) | ||
| 89 | #define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8) | ||
| 90 | #define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9) | ||
| 91 | |||
| 92 | #define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) | ||
| 93 | |||
| 94 | #define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) | ||
| 95 | |||
| 96 | /* Page 0, Register 1 - reset */ | ||
| 97 | #define PCM512x_RSTR (1 << 0) | ||
| 98 | #define PCM512x_RSTM (1 << 4) | ||
| 99 | |||
| 100 | /* Page 0, Register 2 - power */ | ||
| 101 | #define PCM512x_RQPD (1 << 0) | ||
| 102 | #define PCM512x_RQPD_SHIFT 0 | ||
| 103 | #define PCM512x_RQST (1 << 4) | ||
| 104 | #define PCM512x_RQST_SHIFT 4 | ||
| 105 | |||
| 106 | /* Page 0, Register 3 - mute */ | ||
| 107 | #define PCM512x_RQMR_SHIFT 0 | ||
| 108 | #define PCM512x_RQML_SHIFT 4 | ||
| 109 | |||
| 110 | /* Page 0, Register 4 - PLL */ | ||
| 111 | #define PCM512x_PLCE (1 << 0) | ||
| 112 | #define PCM512x_RLCE_SHIFT 0 | ||
| 113 | #define PCM512x_PLCK (1 << 4) | ||
| 114 | #define PCM512x_PLCK_SHIFT 4 | ||
| 115 | |||
| 116 | /* Page 0, Register 7 - DSP */ | ||
| 117 | #define PCM512x_SDSL (1 << 0) | ||
| 118 | #define PCM512x_SDSL_SHIFT 0 | ||
| 119 | #define PCM512x_DEMP (1 << 4) | ||
| 120 | #define PCM512x_DEMP_SHIFT 4 | ||
| 121 | |||
| 122 | /* Page 0, Register 13 - PLL reference */ | ||
| 123 | #define PCM512x_SREF (1 << 4) | ||
| 124 | |||
| 125 | /* Page 0, Register 37 - Error detection */ | ||
| 126 | #define PCM512x_IPLK (1 << 0) | ||
| 127 | #define PCM512x_DCAS (1 << 1) | ||
| 128 | #define PCM512x_IDCM (1 << 2) | ||
| 129 | #define PCM512x_IDCH (1 << 3) | ||
| 130 | #define PCM512x_IDSK (1 << 4) | ||
| 131 | #define PCM512x_IDBK (1 << 5) | ||
| 132 | #define PCM512x_IDFS (1 << 6) | ||
| 133 | |||
| 134 | /* Page 0, Register 42 - DAC routing */ | ||
| 135 | #define PCM512x_AUPR_SHIFT 0 | ||
| 136 | #define PCM512x_AUPL_SHIFT 4 | ||
| 137 | |||
| 138 | /* Page 0, Register 59 - auto mute */ | ||
| 139 | #define PCM512x_ATMR_SHIFT 0 | ||
| 140 | #define PCM512x_ATML_SHIFT 4 | ||
| 141 | |||
| 142 | /* Page 0, Register 63 - ramp rates */ | ||
| 143 | #define PCM512x_VNDF_SHIFT 6 | ||
| 144 | #define PCM512x_VNDS_SHIFT 4 | ||
| 145 | #define PCM512x_VNUF_SHIFT 2 | ||
| 146 | #define PCM512x_VNUS_SHIFT 0 | ||
| 147 | |||
| 148 | /* Page 0, Register 64 - emergency ramp rates */ | ||
| 149 | #define PCM512x_VEDF_SHIFT 6 | ||
| 150 | #define PCM512x_VEDS_SHIFT 4 | ||
| 151 | |||
| 152 | /* Page 0, Register 65 - Digital mute enables */ | ||
| 153 | #define PCM512x_ACTL_SHIFT 2 | ||
| 154 | #define PCM512x_AMLE_SHIFT 1 | ||
| 155 | #define PCM512x_AMLR_SHIFT 0 | ||
| 156 | |||
| 157 | /* Page 1, Register 2 - analog volume control */ | ||
| 158 | #define PCM512x_RAGN_SHIFT 0 | ||
| 159 | #define PCM512x_LAGN_SHIFT 4 | ||
| 160 | |||
| 161 | /* Page 1, Register 7 - analog boost control */ | ||
| 162 | #define PCM512x_AGBR_SHIFT 0 | ||
| 163 | #define PCM512x_AGBL_SHIFT 4 | ||
| 164 | |||
| 165 | extern const struct dev_pm_ops pcm512x_pm_ops; | ||
| 166 | extern const struct regmap_config pcm512x_regmap; | ||
| 167 | |||
| 168 | int pcm512x_probe(struct device *dev, struct regmap *regmap); | ||
| 169 | void pcm512x_remove(struct device *dev); | ||
| 170 | |||
| 171 | #endif | ||
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 912c9cbc2724..ce199d375209 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c | |||
| @@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, | |||
| 210 | static const char *rt5631_input_mode[] = { | 210 | static const char *rt5631_input_mode[] = { |
| 211 | "Single ended", "Differential"}; | 211 | "Single ended", "Differential"}; |
| 212 | 212 | ||
| 213 | static const SOC_ENUM_SINGLE_DECL( | 213 | static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, |
| 214 | rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, | 214 | RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); |
| 215 | RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
| 216 | 215 | ||
| 217 | static const SOC_ENUM_SINGLE_DECL( | 216 | static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, |
| 218 | rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, | 217 | RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); |
| 219 | RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
| 220 | 218 | ||
| 221 | /* MONO Input Type */ | 219 | /* MONO Input Type */ |
| 222 | static const SOC_ENUM_SINGLE_DECL( | 220 | static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, |
| 223 | rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, | 221 | RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); |
| 224 | RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
| 225 | 222 | ||
| 226 | /* SPK Ratio Gain Control */ | 223 | /* SPK Ratio Gain Control */ |
| 227 | static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", | 224 | static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", |
| 228 | "1.56x", "1.68x", "1.99x", "2.34x"}; | 225 | "1.56x", "1.68x", "1.99x", "2.34x"}; |
| 229 | 226 | ||
| 230 | static const SOC_ENUM_SINGLE_DECL( | 227 | static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, |
| 231 | rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, | 228 | RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); |
| 232 | RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); | ||
| 233 | 229 | ||
| 234 | static const struct snd_kcontrol_new rt5631_snd_controls[] = { | 230 | static const struct snd_kcontrol_new rt5631_snd_controls[] = { |
| 235 | /* MIC */ | 231 | /* MIC */ |
| @@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = { | |||
| 759 | /* Left SPK Volume Input */ | 755 | /* Left SPK Volume Input */ |
| 760 | static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; | 756 | static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; |
| 761 | 757 | ||
| 762 | static const SOC_ENUM_SINGLE_DECL( | 758 | static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, |
| 763 | rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, | 759 | RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); |
| 764 | RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); | ||
| 765 | 760 | ||
| 766 | static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = | 761 | static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = |
| 767 | SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); | 762 | SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); |
| @@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = | |||
| 769 | /* Left HP Volume Input */ | 764 | /* Left HP Volume Input */ |
| 770 | static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; | 765 | static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; |
| 771 | 766 | ||
| 772 | static const SOC_ENUM_SINGLE_DECL( | 767 | static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, |
| 773 | rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, | 768 | RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); |
| 774 | RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); | ||
| 775 | 769 | ||
| 776 | static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = | 770 | static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = |
| 777 | SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); | 771 | SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); |
| @@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = | |||
| 779 | /* Left Out Volume Input */ | 773 | /* Left Out Volume Input */ |
| 780 | static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; | 774 | static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; |
| 781 | 775 | ||
| 782 | static const SOC_ENUM_SINGLE_DECL( | 776 | static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, |
| 783 | rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, | 777 | RT5631_L_EN_SHIFT, rt5631_outvoll_sel); |
| 784 | RT5631_L_EN_SHIFT, rt5631_outvoll_sel); | ||
| 785 | 778 | ||
| 786 | static const struct snd_kcontrol_new rt5631_outvoll_mux_control = | 779 | static const struct snd_kcontrol_new rt5631_outvoll_mux_control = |
| 787 | SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); | 780 | SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); |
| @@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control = | |||
| 789 | /* Right Out Volume Input */ | 782 | /* Right Out Volume Input */ |
| 790 | static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; | 783 | static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; |
| 791 | 784 | ||
| 792 | static const SOC_ENUM_SINGLE_DECL( | 785 | static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, |
| 793 | rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, | 786 | RT5631_R_EN_SHIFT, rt5631_outvolr_sel); |
| 794 | RT5631_R_EN_SHIFT, rt5631_outvolr_sel); | ||
| 795 | 787 | ||
| 796 | static const struct snd_kcontrol_new rt5631_outvolr_mux_control = | 788 | static const struct snd_kcontrol_new rt5631_outvolr_mux_control = |
| 797 | SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); | 789 | SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); |
| @@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control = | |||
| 799 | /* Right HP Volume Input */ | 791 | /* Right HP Volume Input */ |
| 800 | static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; | 792 | static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; |
| 801 | 793 | ||
| 802 | static const SOC_ENUM_SINGLE_DECL( | 794 | static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, |
| 803 | rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, | 795 | RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); |
| 804 | RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); | ||
| 805 | 796 | ||
| 806 | static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = | 797 | static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = |
| 807 | SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); | 798 | SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); |
| @@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = | |||
| 809 | /* Right SPK Volume Input */ | 800 | /* Right SPK Volume Input */ |
| 810 | static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; | 801 | static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; |
| 811 | 802 | ||
| 812 | static const SOC_ENUM_SINGLE_DECL( | 803 | static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, |
| 813 | rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, | 804 | RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); |
| 814 | RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); | ||
| 815 | 805 | ||
| 816 | static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = | 806 | static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = |
| 817 | SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); | 807 | SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); |
| @@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = | |||
| 820 | static const char *rt5631_spol_src_sel[] = { | 810 | static const char *rt5631_spol_src_sel[] = { |
| 821 | "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; | 811 | "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; |
| 822 | 812 | ||
| 823 | static const SOC_ENUM_SINGLE_DECL( | 813 | static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
| 824 | rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 814 | RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); |
| 825 | RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); | ||
| 826 | 815 | ||
| 827 | static const struct snd_kcontrol_new rt5631_spol_mux_control = | 816 | static const struct snd_kcontrol_new rt5631_spol_mux_control = |
| 828 | SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); | 817 | SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); |
| @@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control = | |||
| 831 | static const char *rt5631_spor_src_sel[] = { | 820 | static const char *rt5631_spor_src_sel[] = { |
| 832 | "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; | 821 | "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; |
| 833 | 822 | ||
| 834 | static const SOC_ENUM_SINGLE_DECL( | 823 | static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
| 835 | rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 824 | RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); |
| 836 | RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); | ||
| 837 | 825 | ||
| 838 | static const struct snd_kcontrol_new rt5631_spor_mux_control = | 826 | static const struct snd_kcontrol_new rt5631_spor_mux_control = |
| 839 | SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); | 827 | SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); |
| @@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control = | |||
| 841 | /* MONO Input */ | 829 | /* MONO Input */ |
| 842 | static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; | 830 | static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; |
| 843 | 831 | ||
| 844 | static const SOC_ENUM_SINGLE_DECL( | 832 | static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
| 845 | rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 833 | RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); |
| 846 | RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); | ||
| 847 | 834 | ||
| 848 | static const struct snd_kcontrol_new rt5631_mono_mux_control = | 835 | static const struct snd_kcontrol_new rt5631_mono_mux_control = |
| 849 | SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); | 836 | SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); |
| @@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control = | |||
| 851 | /* Left HPO Input */ | 838 | /* Left HPO Input */ |
| 852 | static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; | 839 | static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; |
| 853 | 840 | ||
| 854 | static const SOC_ENUM_SINGLE_DECL( | 841 | static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
| 855 | rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 842 | RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); |
| 856 | RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); | ||
| 857 | 843 | ||
| 858 | static const struct snd_kcontrol_new rt5631_hpl_mux_control = | 844 | static const struct snd_kcontrol_new rt5631_hpl_mux_control = |
| 859 | SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); | 845 | SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); |
| @@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control = | |||
| 861 | /* Right HPO Input */ | 847 | /* Right HPO Input */ |
| 862 | static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; | 848 | static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; |
| 863 | 849 | ||
| 864 | static const SOC_ENUM_SINGLE_DECL( | 850 | static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
| 865 | rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 851 | RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); |
| 866 | RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); | ||
| 867 | 852 | ||
| 868 | static const struct snd_kcontrol_new rt5631_hpr_mux_control = | 853 | static const struct snd_kcontrol_new rt5631_hpr_mux_control = |
| 869 | SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); | 854 | SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 886924934aa5..1a1e1150237d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
| @@ -361,25 +361,24 @@ static unsigned int bst_tlv[] = { | |||
| 361 | static const char * const rt5640_data_select[] = { | 361 | static const char * const rt5640_data_select[] = { |
| 362 | "Normal", "left copy to right", "right copy to left", "Swap"}; | 362 | "Normal", "left copy to right", "right copy to left", "Swap"}; |
| 363 | 363 | ||
| 364 | static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, | 364 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, |
| 365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); | 365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); |
| 366 | 366 | ||
| 367 | static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, | 367 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, |
| 368 | RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); | 368 | RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); |
| 369 | 369 | ||
| 370 | static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, | 370 | static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, |
| 371 | RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); | 371 | RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); |
| 372 | 372 | ||
| 373 | static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, | 373 | static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, |
| 374 | RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); | 374 | RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); |
| 375 | 375 | ||
| 376 | /* Class D speaker gain ratio */ | 376 | /* Class D speaker gain ratio */ |
| 377 | static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x", | 377 | static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x", |
| 378 | "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; | 378 | "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; |
| 379 | 379 | ||
| 380 | static const SOC_ENUM_SINGLE_DECL( | 380 | static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, |
| 381 | rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, | 381 | RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); |
| 382 | RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); | ||
| 383 | 382 | ||
| 384 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { | 383 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { |
| 385 | /* Speaker Output Volume */ | 384 | /* Speaker Output Volume */ |
| @@ -753,9 +752,8 @@ static const char * const rt5640_stereo_adc1_src[] = { | |||
| 753 | "DIG MIX", "ADC" | 752 | "DIG MIX", "ADC" |
| 754 | }; | 753 | }; |
| 755 | 754 | ||
| 756 | static const SOC_ENUM_SINGLE_DECL( | 755 | static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, |
| 757 | rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, | 756 | RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); |
| 758 | RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); | ||
| 759 | 757 | ||
| 760 | static const struct snd_kcontrol_new rt5640_sto_adc_1_mux = | 758 | static const struct snd_kcontrol_new rt5640_sto_adc_1_mux = |
| 761 | SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); | 759 | SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); |
| @@ -764,9 +762,8 @@ static const char * const rt5640_stereo_adc2_src[] = { | |||
| 764 | "DMIC1", "DMIC2", "DIG MIX" | 762 | "DMIC1", "DMIC2", "DIG MIX" |
| 765 | }; | 763 | }; |
| 766 | 764 | ||
| 767 | static const SOC_ENUM_SINGLE_DECL( | 765 | static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, |
| 768 | rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, | 766 | RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); |
| 769 | RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); | ||
| 770 | 767 | ||
| 771 | static const struct snd_kcontrol_new rt5640_sto_adc_2_mux = | 768 | static const struct snd_kcontrol_new rt5640_sto_adc_2_mux = |
| 772 | SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); | 769 | SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); |
| @@ -776,9 +773,8 @@ static const char * const rt5640_mono_adc_l1_src[] = { | |||
| 776 | "Mono DAC MIXL", "ADCL" | 773 | "Mono DAC MIXL", "ADCL" |
| 777 | }; | 774 | }; |
| 778 | 775 | ||
| 779 | static const SOC_ENUM_SINGLE_DECL( | 776 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, |
| 780 | rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, | 777 | RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); |
| 781 | RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); | ||
| 782 | 778 | ||
| 783 | static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux = | 779 | static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux = |
| 784 | SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); | 780 | SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); |
| @@ -787,9 +783,8 @@ static const char * const rt5640_mono_adc_l2_src[] = { | |||
| 787 | "DMIC L1", "DMIC L2", "Mono DAC MIXL" | 783 | "DMIC L1", "DMIC L2", "Mono DAC MIXL" |
| 788 | }; | 784 | }; |
| 789 | 785 | ||
| 790 | static const SOC_ENUM_SINGLE_DECL( | 786 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, |
| 791 | rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, | 787 | RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); |
| 792 | RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); | ||
| 793 | 788 | ||
| 794 | static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux = | 789 | static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux = |
| 795 | SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); | 790 | SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); |
| @@ -798,9 +793,8 @@ static const char * const rt5640_mono_adc_r1_src[] = { | |||
| 798 | "Mono DAC MIXR", "ADCR" | 793 | "Mono DAC MIXR", "ADCR" |
| 799 | }; | 794 | }; |
| 800 | 795 | ||
| 801 | static const SOC_ENUM_SINGLE_DECL( | 796 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, |
| 802 | rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, | 797 | RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); |
| 803 | RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); | ||
| 804 | 798 | ||
| 805 | static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux = | 799 | static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux = |
| 806 | SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); | 800 | SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); |
| @@ -809,9 +803,8 @@ static const char * const rt5640_mono_adc_r2_src[] = { | |||
| 809 | "DMIC R1", "DMIC R2", "Mono DAC MIXR" | 803 | "DMIC R1", "DMIC R2", "Mono DAC MIXR" |
| 810 | }; | 804 | }; |
| 811 | 805 | ||
| 812 | static const SOC_ENUM_SINGLE_DECL( | 806 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, |
| 813 | rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, | 807 | RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); |
| 814 | RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); | ||
| 815 | 808 | ||
| 816 | static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux = | 809 | static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux = |
| 817 | SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); | 810 | SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); |
| @@ -826,9 +819,9 @@ static int rt5640_dac_l2_values[] = { | |||
| 826 | 3, | 819 | 3, |
| 827 | }; | 820 | }; |
| 828 | 821 | ||
| 829 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 822 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, |
| 830 | rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, | 823 | RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, |
| 831 | 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); | 824 | 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); |
| 832 | 825 | ||
| 833 | static const struct snd_kcontrol_new rt5640_dac_l2_mux = | 826 | static const struct snd_kcontrol_new rt5640_dac_l2_mux = |
| 834 | SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); | 827 | SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); |
| @@ -841,9 +834,9 @@ static int rt5640_dac_r2_values[] = { | |||
| 841 | 0, | 834 | 0, |
| 842 | }; | 835 | }; |
| 843 | 836 | ||
| 844 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 837 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum, |
| 845 | rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, | 838 | RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, |
| 846 | 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); | 839 | 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); |
| 847 | 840 | ||
| 848 | static const struct snd_kcontrol_new rt5640_dac_r2_mux = | 841 | static const struct snd_kcontrol_new rt5640_dac_r2_mux = |
| 849 | SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); | 842 | SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); |
| @@ -860,9 +853,10 @@ static int rt5640_dai_iis_map_values[] = { | |||
| 860 | 7, | 853 | 7, |
| 861 | }; | 854 | }; |
| 862 | 855 | ||
| 863 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 856 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, |
| 864 | rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, | 857 | RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, |
| 865 | 0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values); | 858 | 0x7, rt5640_dai_iis_map, |
| 859 | rt5640_dai_iis_map_values); | ||
| 866 | 860 | ||
| 867 | static const struct snd_kcontrol_new rt5640_dai_mux = | 861 | static const struct snd_kcontrol_new rt5640_dai_mux = |
| 868 | SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); | 862 | SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); |
| @@ -872,9 +866,8 @@ static const char * const rt5640_sdi_sel[] = { | |||
| 872 | "IF1", "IF2" | 866 | "IF1", "IF2" |
| 873 | }; | 867 | }; |
| 874 | 868 | ||
| 875 | static const SOC_ENUM_SINGLE_DECL( | 869 | static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, |
| 876 | rt5640_sdi_sel_enum, RT5640_I2S2_SDP, | 870 | RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); |
| 877 | RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); | ||
| 878 | 871 | ||
| 879 | static const struct snd_kcontrol_new rt5640_sdi_mux = | 872 | static const struct snd_kcontrol_new rt5640_sdi_mux = |
| 880 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); | 873 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 0fcbe90f3ef2..ab4754a7a88c 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
| @@ -187,8 +187,9 @@ static const char *adc_mux_text[] = { | |||
| 187 | "MIC_IN", "LINE_IN" | 187 | "MIC_IN", "LINE_IN" |
| 188 | }; | 188 | }; |
| 189 | 189 | ||
| 190 | static const struct soc_enum adc_enum = | 190 | static SOC_ENUM_SINGLE_DECL(adc_enum, |
| 191 | SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text); | 191 | SGTL5000_CHIP_ANA_CTRL, 2, |
| 192 | adc_mux_text); | ||
| 192 | 193 | ||
| 193 | static const struct snd_kcontrol_new adc_mux = | 194 | static const struct snd_kcontrol_new adc_mux = |
| 194 | SOC_DAPM_ENUM("Capture Mux", adc_enum); | 195 | SOC_DAPM_ENUM("Capture Mux", adc_enum); |
| @@ -198,8 +199,9 @@ static const char *dac_mux_text[] = { | |||
| 198 | "DAC", "LINE_IN" | 199 | "DAC", "LINE_IN" |
| 199 | }; | 200 | }; |
| 200 | 201 | ||
| 201 | static const struct soc_enum dac_enum = | 202 | static SOC_ENUM_SINGLE_DECL(dac_enum, |
| 202 | SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text); | 203 | SGTL5000_CHIP_ANA_CTRL, 6, |
| 204 | dac_mux_text); | ||
| 203 | 205 | ||
| 204 | static const struct snd_kcontrol_new dac_mux = | 206 | static const struct snd_kcontrol_new dac_mux = |
| 205 | SOC_DAPM_ENUM("Headphone Mux", dac_enum); | 207 | SOC_DAPM_ENUM("Headphone Mux", dac_enum); |
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c new file mode 100644 index 000000000000..90e3a228bae4 --- /dev/null +++ b/sound/soc/codecs/sirf-audio-codec.c | |||
| @@ -0,0 +1,533 @@ | |||
| 1 | /* | ||
| 2 | * SiRF audio codec driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/platform_device.h> | ||
| 11 | #include <linux/pm_runtime.h> | ||
| 12 | #include <linux/of.h> | ||
| 13 | #include <linux/of_device.h> | ||
| 14 | #include <linux/clk.h> | ||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <linux/regmap.h> | ||
| 18 | #include <sound/core.h> | ||
| 19 | #include <sound/pcm.h> | ||
| 20 | #include <sound/pcm_params.h> | ||
| 21 | #include <sound/initval.h> | ||
| 22 | #include <sound/tlv.h> | ||
| 23 | #include <sound/soc.h> | ||
| 24 | #include <sound/dmaengine_pcm.h> | ||
| 25 | |||
| 26 | #include "sirf-audio-codec.h" | ||
| 27 | |||
| 28 | struct sirf_audio_codec { | ||
| 29 | struct clk *clk; | ||
| 30 | struct regmap *regmap; | ||
| 31 | u32 reg_ctrl0, reg_ctrl1; | ||
| 32 | }; | ||
| 33 | |||
| 34 | static const char * const input_mode_mux[] = {"Single-ended", | ||
| 35 | "Differential"}; | ||
| 36 | |||
| 37 | static const struct soc_enum input_mode_mux_enum = | ||
| 38 | SOC_ENUM_SINGLE(AUDIO_IC_CODEC_CTRL1, 4, 2, input_mode_mux); | ||
| 39 | |||
| 40 | static const struct snd_kcontrol_new sirf_audio_codec_input_mode_control = | ||
| 41 | SOC_DAPM_ENUM("Route", input_mode_mux_enum); | ||
| 42 | |||
| 43 | static const DECLARE_TLV_DB_SCALE(playback_vol_tlv, -12400, 100, 0); | ||
| 44 | static const DECLARE_TLV_DB_SCALE(capture_vol_tlv_prima2, 500, 100, 0); | ||
| 45 | static const DECLARE_TLV_DB_RANGE(capture_vol_tlv_atlas6, | ||
| 46 | 0, 7, TLV_DB_SCALE_ITEM(-100, 100, 0), | ||
| 47 | 0x22, 0x3F, TLV_DB_SCALE_ITEM(700, 100, 0), | ||
| 48 | ); | ||
| 49 | |||
| 50 | static struct snd_kcontrol_new volume_controls_atlas6[] = { | ||
| 51 | SOC_DOUBLE_TLV("Playback Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, | ||
| 52 | 0x7F, 0, playback_vol_tlv), | ||
| 53 | SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 16, 10, | ||
| 54 | 0x3F, 0, capture_vol_tlv_atlas6), | ||
| 55 | }; | ||
| 56 | |||
| 57 | static struct snd_kcontrol_new volume_controls_prima2[] = { | ||
| 58 | SOC_DOUBLE_TLV("Speaker Volume", AUDIO_IC_CODEC_CTRL0, 21, 14, | ||
| 59 | 0x7F, 0, playback_vol_tlv), | ||
| 60 | SOC_DOUBLE_TLV("Capture Volume", AUDIO_IC_CODEC_CTRL1, 15, 10, | ||
| 61 | 0x1F, 0, capture_vol_tlv_prima2), | ||
| 62 | }; | ||
| 63 | |||
| 64 | static struct snd_kcontrol_new left_input_path_controls[] = { | ||
| 65 | SOC_DAPM_SINGLE("Line Left Switch", AUDIO_IC_CODEC_CTRL1, 6, 1, 0), | ||
| 66 | SOC_DAPM_SINGLE("Mic Left Switch", AUDIO_IC_CODEC_CTRL1, 3, 1, 0), | ||
| 67 | }; | ||
| 68 | |||
| 69 | static struct snd_kcontrol_new right_input_path_controls[] = { | ||
| 70 | SOC_DAPM_SINGLE("Line Right Switch", AUDIO_IC_CODEC_CTRL1, 5, 1, 0), | ||
| 71 | SOC_DAPM_SINGLE("Mic Right Switch", AUDIO_IC_CODEC_CTRL1, 2, 1, 0), | ||
| 72 | }; | ||
| 73 | |||
| 74 | static struct snd_kcontrol_new left_dac_to_hp_left_amp_switch_control = | ||
| 75 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 9, 1, 0); | ||
| 76 | |||
| 77 | static struct snd_kcontrol_new left_dac_to_hp_right_amp_switch_control = | ||
| 78 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 8, 1, 0); | ||
| 79 | |||
| 80 | static struct snd_kcontrol_new right_dac_to_hp_left_amp_switch_control = | ||
| 81 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 7, 1, 0); | ||
| 82 | |||
| 83 | static struct snd_kcontrol_new right_dac_to_hp_right_amp_switch_control = | ||
| 84 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 6, 1, 0); | ||
| 85 | |||
| 86 | static struct snd_kcontrol_new left_dac_to_speaker_lineout_switch_control = | ||
| 87 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 11, 1, 0); | ||
| 88 | |||
| 89 | static struct snd_kcontrol_new right_dac_to_speaker_lineout_switch_control = | ||
| 90 | SOC_DAPM_SINGLE("Switch", AUDIO_IC_CODEC_CTRL0, 10, 1, 0); | ||
| 91 | |||
| 92 | /* After enable adc, Delay 200ms to avoid pop noise */ | ||
| 93 | static int adc_enable_delay_event(struct snd_soc_dapm_widget *w, | ||
| 94 | struct snd_kcontrol *kcontrol, int event) | ||
| 95 | { | ||
| 96 | switch (event) { | ||
| 97 | case SND_SOC_DAPM_POST_PMU: | ||
| 98 | msleep(200); | ||
| 99 | break; | ||
| 100 | default: | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | |||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void enable_and_reset_codec(struct regmap *regmap, | ||
| 108 | u32 codec_enable_bits, u32 codec_reset_bits) | ||
| 109 | { | ||
| 110 | regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, | ||
| 111 | codec_enable_bits | codec_reset_bits, | ||
| 112 | codec_enable_bits | ~codec_reset_bits); | ||
| 113 | msleep(20); | ||
| 114 | regmap_update_bits(regmap, AUDIO_IC_CODEC_CTRL1, | ||
| 115 | codec_reset_bits, codec_reset_bits); | ||
| 116 | } | ||
| 117 | |||
| 118 | static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | ||
| 119 | struct snd_kcontrol *kcontrol, int event) | ||
| 120 | { | ||
| 121 | #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) | ||
| 122 | #define ATLAS6_CODEC_RESET_BITS (1 << 28) | ||
| 123 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | ||
| 124 | switch (event) { | ||
| 125 | case SND_SOC_DAPM_PRE_PMU: | ||
| 126 | enable_and_reset_codec(sirf_audio_codec->regmap, | ||
| 127 | ATLAS6_CODEC_ENABLE_BITS, ATLAS6_CODEC_RESET_BITS); | ||
| 128 | break; | ||
| 129 | case SND_SOC_DAPM_POST_PMD: | ||
| 130 | regmap_update_bits(sirf_audio_codec->regmap, | ||
| 131 | AUDIO_IC_CODEC_CTRL1, ATLAS6_CODEC_ENABLE_BITS, | ||
| 132 | ~ATLAS6_CODEC_ENABLE_BITS); | ||
| 133 | break; | ||
| 134 | default: | ||
| 135 | break; | ||
| 136 | } | ||
| 137 | |||
| 138 | return 0; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | ||
| 142 | struct snd_kcontrol *kcontrol, int event) | ||
| 143 | { | ||
| 144 | #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) | ||
| 145 | #define PRIMA2_CODEC_RESET_BITS (1 << 26) | ||
| 146 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | ||
| 147 | switch (event) { | ||
| 148 | case SND_SOC_DAPM_POST_PMU: | ||
| 149 | enable_and_reset_codec(sirf_audio_codec->regmap, | ||
| 150 | PRIMA2_CODEC_ENABLE_BITS, PRIMA2_CODEC_RESET_BITS); | ||
| 151 | break; | ||
| 152 | case SND_SOC_DAPM_POST_PMD: | ||
| 153 | regmap_update_bits(sirf_audio_codec->regmap, | ||
| 154 | AUDIO_IC_CODEC_CTRL1, PRIMA2_CODEC_ENABLE_BITS, | ||
| 155 | ~PRIMA2_CODEC_ENABLE_BITS); | ||
| 156 | break; | ||
| 157 | default: | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | |||
| 161 | return 0; | ||
| 162 | } | ||
| 163 | |||
| 164 | static const struct snd_soc_dapm_widget atlas6_output_driver_dapm_widgets[] = { | ||
| 165 | SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 166 | 25, 0, NULL, 0), | ||
| 167 | SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 168 | 26, 0, NULL, 0), | ||
| 169 | SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 170 | 27, 0, NULL, 0), | ||
| 171 | }; | ||
| 172 | |||
| 173 | static const struct snd_soc_dapm_widget prima2_output_driver_dapm_widgets[] = { | ||
| 174 | SND_SOC_DAPM_OUT_DRV("HP Left Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 175 | 23, 0, NULL, 0), | ||
| 176 | SND_SOC_DAPM_OUT_DRV("HP Right Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 177 | 24, 0, NULL, 0), | ||
| 178 | SND_SOC_DAPM_OUT_DRV("Speaker Driver", AUDIO_IC_CODEC_CTRL1, | ||
| 179 | 25, 0, NULL, 0), | ||
| 180 | }; | ||
| 181 | |||
| 182 | static const struct snd_soc_dapm_widget atlas6_codec_clock_dapm_widget = | ||
| 183 | SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, | ||
| 184 | atlas6_codec_enable_and_reset_event, | ||
| 185 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); | ||
| 186 | |||
| 187 | static const struct snd_soc_dapm_widget prima2_codec_clock_dapm_widget = | ||
| 188 | SND_SOC_DAPM_SUPPLY("codecclk", SND_SOC_NOPM, 0, 0, | ||
| 189 | prima2_codec_enable_and_reset_event, | ||
| 190 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD); | ||
| 191 | |||
| 192 | static const struct snd_soc_dapm_widget sirf_audio_codec_dapm_widgets[] = { | ||
| 193 | SND_SOC_DAPM_DAC("DAC left", NULL, AUDIO_IC_CODEC_CTRL0, 1, 0), | ||
| 194 | SND_SOC_DAPM_DAC("DAC right", NULL, AUDIO_IC_CODEC_CTRL0, 0, 0), | ||
| 195 | SND_SOC_DAPM_SWITCH("Left dac to hp left amp", SND_SOC_NOPM, 0, 0, | ||
| 196 | &left_dac_to_hp_left_amp_switch_control), | ||
| 197 | SND_SOC_DAPM_SWITCH("Left dac to hp right amp", SND_SOC_NOPM, 0, 0, | ||
| 198 | &left_dac_to_hp_right_amp_switch_control), | ||
| 199 | SND_SOC_DAPM_SWITCH("Right dac to hp left amp", SND_SOC_NOPM, 0, 0, | ||
| 200 | &right_dac_to_hp_left_amp_switch_control), | ||
| 201 | SND_SOC_DAPM_SWITCH("Right dac to hp right amp", SND_SOC_NOPM, 0, 0, | ||
| 202 | &right_dac_to_hp_right_amp_switch_control), | ||
| 203 | SND_SOC_DAPM_OUT_DRV("HP amp left driver", AUDIO_IC_CODEC_CTRL0, 3, 0, | ||
| 204 | NULL, 0), | ||
| 205 | SND_SOC_DAPM_OUT_DRV("HP amp right driver", AUDIO_IC_CODEC_CTRL0, 3, 0, | ||
| 206 | NULL, 0), | ||
| 207 | |||
| 208 | SND_SOC_DAPM_SWITCH("Left dac to speaker lineout", SND_SOC_NOPM, 0, 0, | ||
| 209 | &left_dac_to_speaker_lineout_switch_control), | ||
| 210 | SND_SOC_DAPM_SWITCH("Right dac to speaker lineout", SND_SOC_NOPM, 0, 0, | ||
| 211 | &right_dac_to_speaker_lineout_switch_control), | ||
| 212 | SND_SOC_DAPM_OUT_DRV("Speaker amp driver", AUDIO_IC_CODEC_CTRL0, 4, 0, | ||
| 213 | NULL, 0), | ||
| 214 | |||
| 215 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
| 216 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
| 217 | SND_SOC_DAPM_OUTPUT("SPKOUT"), | ||
| 218 | |||
| 219 | SND_SOC_DAPM_ADC_E("ADC left", NULL, AUDIO_IC_CODEC_CTRL1, 8, 0, | ||
| 220 | adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), | ||
| 221 | SND_SOC_DAPM_ADC_E("ADC right", NULL, AUDIO_IC_CODEC_CTRL1, 7, 0, | ||
| 222 | adc_enable_delay_event, SND_SOC_DAPM_POST_PMU), | ||
| 223 | SND_SOC_DAPM_MIXER("Left PGA mixer", AUDIO_IC_CODEC_CTRL1, 1, 0, | ||
| 224 | &left_input_path_controls[0], | ||
| 225 | ARRAY_SIZE(left_input_path_controls)), | ||
| 226 | SND_SOC_DAPM_MIXER("Right PGA mixer", AUDIO_IC_CODEC_CTRL1, 0, 0, | ||
| 227 | &right_input_path_controls[0], | ||
| 228 | ARRAY_SIZE(right_input_path_controls)), | ||
| 229 | |||
| 230 | SND_SOC_DAPM_MUX("Mic input mode mux", SND_SOC_NOPM, 0, 0, | ||
| 231 | &sirf_audio_codec_input_mode_control), | ||
| 232 | SND_SOC_DAPM_MICBIAS("Mic Bias", AUDIO_IC_CODEC_PWR, 3, 0), | ||
| 233 | SND_SOC_DAPM_INPUT("MICIN1"), | ||
| 234 | SND_SOC_DAPM_INPUT("MICIN2"), | ||
| 235 | SND_SOC_DAPM_INPUT("LINEIN1"), | ||
| 236 | SND_SOC_DAPM_INPUT("LINEIN2"), | ||
| 237 | |||
| 238 | SND_SOC_DAPM_SUPPLY("HSL Phase Opposite", AUDIO_IC_CODEC_CTRL0, | ||
| 239 | 30, 0, NULL, 0), | ||
| 240 | }; | ||
| 241 | |||
| 242 | static const struct snd_soc_dapm_route sirf_audio_codec_map[] = { | ||
| 243 | {"SPKOUT", NULL, "Speaker Driver"}, | ||
| 244 | {"Speaker Driver", NULL, "Speaker amp driver"}, | ||
| 245 | {"Speaker amp driver", NULL, "Left dac to speaker lineout"}, | ||
| 246 | {"Speaker amp driver", NULL, "Right dac to speaker lineout"}, | ||
| 247 | {"Left dac to speaker lineout", "Switch", "DAC left"}, | ||
| 248 | {"Right dac to speaker lineout", "Switch", "DAC right"}, | ||
| 249 | {"HPOUTL", NULL, "HP Left Driver"}, | ||
| 250 | {"HPOUTR", NULL, "HP Right Driver"}, | ||
| 251 | {"HP Left Driver", NULL, "HP amp left driver"}, | ||
| 252 | {"HP Right Driver", NULL, "HP amp right driver"}, | ||
| 253 | {"HP amp left driver", NULL, "Right dac to hp left amp"}, | ||
| 254 | {"HP amp right driver", NULL , "Right dac to hp right amp"}, | ||
| 255 | {"HP amp left driver", NULL, "Left dac to hp left amp"}, | ||
| 256 | {"HP amp right driver", NULL , "Right dac to hp right amp"}, | ||
| 257 | {"Right dac to hp left amp", "Switch", "DAC left"}, | ||
| 258 | {"Right dac to hp right amp", "Switch", "DAC right"}, | ||
| 259 | {"Left dac to hp left amp", "Switch", "DAC left"}, | ||
| 260 | {"Left dac to hp right amp", "Switch", "DAC right"}, | ||
| 261 | {"DAC left", NULL, "codecclk"}, | ||
| 262 | {"DAC right", NULL, "codecclk"}, | ||
| 263 | {"DAC left", NULL, "Playback"}, | ||
| 264 | {"DAC right", NULL, "Playback"}, | ||
| 265 | {"DAC left", NULL, "HSL Phase Opposite"}, | ||
| 266 | {"DAC right", NULL, "HSL Phase Opposite"}, | ||
| 267 | |||
| 268 | {"Capture", NULL, "ADC left"}, | ||
| 269 | {"Capture", NULL, "ADC right"}, | ||
| 270 | {"ADC left", NULL, "codecclk"}, | ||
| 271 | {"ADC right", NULL, "codecclk"}, | ||
| 272 | {"ADC left", NULL, "Left PGA mixer"}, | ||
| 273 | {"ADC right", NULL, "Right PGA mixer"}, | ||
| 274 | {"Left PGA mixer", "Line Left Switch", "LINEIN2"}, | ||
| 275 | {"Right PGA mixer", "Line Right Switch", "LINEIN1"}, | ||
| 276 | {"Left PGA mixer", "Mic Left Switch", "MICIN2"}, | ||
| 277 | {"Right PGA mixer", "Mic Right Switch", "Mic input mode mux"}, | ||
| 278 | {"Mic input mode mux", "Single-ended", "MICIN1"}, | ||
| 279 | {"Mic input mode mux", "Differential", "MICIN1"}, | ||
| 280 | }; | ||
| 281 | |||
| 282 | static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, | ||
| 283 | int cmd, | ||
| 284 | struct snd_soc_dai *dai) | ||
| 285 | { | ||
| 286 | int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
| 287 | struct snd_soc_codec *codec = dai->codec; | ||
| 288 | u32 val = 0; | ||
| 289 | |||
| 290 | /* | ||
| 291 | * This is a workaround, When stop playback, | ||
| 292 | * need disable HP amp, avoid the current noise. | ||
| 293 | */ | ||
| 294 | switch (cmd) { | ||
| 295 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 296 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 297 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 298 | break; | ||
| 299 | case SNDRV_PCM_TRIGGER_START: | ||
| 300 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 301 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 302 | if (playback) | ||
| 303 | val = IC_HSLEN | IC_HSREN; | ||
| 304 | break; | ||
| 305 | default: | ||
| 306 | return -EINVAL; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (playback) | ||
| 310 | snd_soc_update_bits(codec, AUDIO_IC_CODEC_CTRL0, | ||
| 311 | IC_HSLEN | IC_HSREN, val); | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { | ||
| 316 | .trigger = sirf_audio_codec_trigger, | ||
| 317 | }; | ||
| 318 | |||
| 319 | struct snd_soc_dai_driver sirf_audio_codec_dai = { | ||
| 320 | .name = "sirf-audio-codec", | ||
| 321 | .playback = { | ||
| 322 | .stream_name = "Playback", | ||
| 323 | .channels_min = 2, | ||
| 324 | .channels_max = 2, | ||
| 325 | .rates = SNDRV_PCM_RATE_48000, | ||
| 326 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 327 | }, | ||
| 328 | .capture = { | ||
| 329 | .stream_name = "Capture", | ||
| 330 | .channels_min = 1, | ||
| 331 | .channels_max = 2, | ||
| 332 | .rates = SNDRV_PCM_RATE_48000, | ||
| 333 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 334 | }, | ||
| 335 | .ops = &sirf_audio_codec_dai_ops, | ||
| 336 | }; | ||
| 337 | |||
| 338 | static int sirf_audio_codec_probe(struct snd_soc_codec *codec) | ||
| 339 | { | ||
| 340 | int ret; | ||
| 341 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 342 | struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); | ||
| 343 | |||
| 344 | pm_runtime_enable(codec->dev); | ||
| 345 | codec->control_data = sirf_audio_codec->regmap; | ||
| 346 | |||
| 347 | ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); | ||
| 348 | if (ret != 0) { | ||
| 349 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
| 350 | return ret; | ||
| 351 | } | ||
| 352 | |||
| 353 | if (of_device_is_compatible(codec->dev->of_node, "sirf,prima2-audio-codec")) { | ||
| 354 | snd_soc_dapm_new_controls(dapm, | ||
| 355 | prima2_output_driver_dapm_widgets, | ||
| 356 | ARRAY_SIZE(prima2_output_driver_dapm_widgets)); | ||
| 357 | snd_soc_dapm_new_controls(dapm, | ||
| 358 | &prima2_codec_clock_dapm_widget, 1); | ||
| 359 | return snd_soc_add_codec_controls(codec, | ||
| 360 | volume_controls_prima2, | ||
| 361 | ARRAY_SIZE(volume_controls_prima2)); | ||
| 362 | } | ||
| 363 | if (of_device_is_compatible(codec->dev->of_node, "sirf,atlas6-audio-codec")) { | ||
| 364 | snd_soc_dapm_new_controls(dapm, | ||
| 365 | atlas6_output_driver_dapm_widgets, | ||
| 366 | ARRAY_SIZE(atlas6_output_driver_dapm_widgets)); | ||
| 367 | snd_soc_dapm_new_controls(dapm, | ||
| 368 | &atlas6_codec_clock_dapm_widget, 1); | ||
| 369 | return snd_soc_add_codec_controls(codec, | ||
| 370 | volume_controls_atlas6, | ||
| 371 | ARRAY_SIZE(volume_controls_atlas6)); | ||
| 372 | } | ||
| 373 | |||
| 374 | return -EINVAL; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int sirf_audio_codec_remove(struct snd_soc_codec *codec) | ||
| 378 | { | ||
| 379 | pm_runtime_disable(codec->dev); | ||
| 380 | return 0; | ||
| 381 | } | ||
| 382 | |||
| 383 | static struct snd_soc_codec_driver soc_codec_device_sirf_audio_codec = { | ||
| 384 | .probe = sirf_audio_codec_probe, | ||
| 385 | .remove = sirf_audio_codec_remove, | ||
| 386 | .dapm_widgets = sirf_audio_codec_dapm_widgets, | ||
| 387 | .num_dapm_widgets = ARRAY_SIZE(sirf_audio_codec_dapm_widgets), | ||
| 388 | .dapm_routes = sirf_audio_codec_map, | ||
| 389 | .num_dapm_routes = ARRAY_SIZE(sirf_audio_codec_map), | ||
| 390 | .idle_bias_off = true, | ||
| 391 | }; | ||
| 392 | |||
| 393 | static const struct of_device_id sirf_audio_codec_of_match[] = { | ||
| 394 | { .compatible = "sirf,prima2-audio-codec" }, | ||
| 395 | { .compatible = "sirf,atlas6-audio-codec" }, | ||
| 396 | {} | ||
| 397 | }; | ||
| 398 | MODULE_DEVICE_TABLE(of, sirf_audio_codec_of_match); | ||
| 399 | |||
| 400 | static const struct regmap_config sirf_audio_codec_regmap_config = { | ||
| 401 | .reg_bits = 32, | ||
| 402 | .reg_stride = 4, | ||
| 403 | .val_bits = 32, | ||
| 404 | .max_register = AUDIO_IC_CODEC_CTRL3, | ||
| 405 | .cache_type = REGCACHE_NONE, | ||
| 406 | }; | ||
| 407 | |||
| 408 | static int sirf_audio_codec_driver_probe(struct platform_device *pdev) | ||
| 409 | { | ||
| 410 | int ret; | ||
| 411 | struct sirf_audio_codec *sirf_audio_codec; | ||
| 412 | void __iomem *base; | ||
| 413 | struct resource *mem_res; | ||
| 414 | const struct of_device_id *match; | ||
| 415 | |||
| 416 | match = of_match_node(sirf_audio_codec_of_match, pdev->dev.of_node); | ||
| 417 | |||
| 418 | sirf_audio_codec = devm_kzalloc(&pdev->dev, | ||
| 419 | sizeof(struct sirf_audio_codec), GFP_KERNEL); | ||
| 420 | if (!sirf_audio_codec) | ||
| 421 | return -ENOMEM; | ||
| 422 | |||
| 423 | platform_set_drvdata(pdev, sirf_audio_codec); | ||
| 424 | |||
| 425 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 426 | base = devm_ioremap_resource(&pdev->dev, mem_res); | ||
| 427 | if (base == NULL) | ||
| 428 | return -ENOMEM; | ||
| 429 | |||
| 430 | sirf_audio_codec->regmap = devm_regmap_init_mmio(&pdev->dev, base, | ||
| 431 | &sirf_audio_codec_regmap_config); | ||
| 432 | if (IS_ERR(sirf_audio_codec->regmap)) | ||
| 433 | return PTR_ERR(sirf_audio_codec->regmap); | ||
| 434 | |||
| 435 | sirf_audio_codec->clk = devm_clk_get(&pdev->dev, NULL); | ||
| 436 | if (IS_ERR(sirf_audio_codec->clk)) { | ||
| 437 | dev_err(&pdev->dev, "Get clock failed.\n"); | ||
| 438 | return PTR_ERR(sirf_audio_codec->clk); | ||
| 439 | } | ||
| 440 | |||
| 441 | ret = clk_prepare_enable(sirf_audio_codec->clk); | ||
| 442 | if (ret) { | ||
| 443 | dev_err(&pdev->dev, "Enable clock failed.\n"); | ||
| 444 | return ret; | ||
| 445 | } | ||
| 446 | |||
| 447 | ret = snd_soc_register_codec(&(pdev->dev), | ||
| 448 | &soc_codec_device_sirf_audio_codec, | ||
| 449 | &sirf_audio_codec_dai, 1); | ||
| 450 | if (ret) { | ||
| 451 | dev_err(&pdev->dev, "Register Audio Codec dai failed.\n"); | ||
| 452 | goto err_clk_put; | ||
| 453 | } | ||
| 454 | |||
| 455 | /* | ||
| 456 | * Always open charge pump, if not, when the charge pump closed the | ||
| 457 | * adc will not stable | ||
| 458 | */ | ||
| 459 | regmap_update_bits(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, | ||
| 460 | IC_CPFREQ, IC_CPFREQ); | ||
| 461 | |||
| 462 | if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas6-audio-codec")) | ||
| 463 | regmap_update_bits(sirf_audio_codec->regmap, | ||
| 464 | AUDIO_IC_CODEC_CTRL0, IC_CPEN, IC_CPEN); | ||
| 465 | return 0; | ||
| 466 | |||
| 467 | err_clk_put: | ||
| 468 | clk_disable_unprepare(sirf_audio_codec->clk); | ||
| 469 | return ret; | ||
| 470 | } | ||
| 471 | |||
| 472 | static int sirf_audio_codec_driver_remove(struct platform_device *pdev) | ||
| 473 | { | ||
| 474 | struct sirf_audio_codec *sirf_audio_codec = platform_get_drvdata(pdev); | ||
| 475 | |||
| 476 | clk_disable_unprepare(sirf_audio_codec->clk); | ||
| 477 | snd_soc_unregister_codec(&(pdev->dev)); | ||
| 478 | |||
| 479 | return 0; | ||
| 480 | } | ||
| 481 | |||
| 482 | #ifdef CONFIG_PM_SLEEP | ||
| 483 | static int sirf_audio_codec_suspend(struct device *dev) | ||
| 484 | { | ||
| 485 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); | ||
| 486 | |||
| 487 | regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, | ||
| 488 | &sirf_audio_codec->reg_ctrl0); | ||
| 489 | regmap_read(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, | ||
| 490 | &sirf_audio_codec->reg_ctrl1); | ||
| 491 | clk_disable_unprepare(sirf_audio_codec->clk); | ||
| 492 | |||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | static int sirf_audio_codec_resume(struct device *dev) | ||
| 497 | { | ||
| 498 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(dev); | ||
| 499 | int ret; | ||
| 500 | |||
| 501 | ret = clk_prepare_enable(sirf_audio_codec->clk); | ||
| 502 | if (ret) | ||
| 503 | return ret; | ||
| 504 | |||
| 505 | regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL0, | ||
| 506 | sirf_audio_codec->reg_ctrl0); | ||
| 507 | regmap_write(sirf_audio_codec->regmap, AUDIO_IC_CODEC_CTRL1, | ||
| 508 | sirf_audio_codec->reg_ctrl1); | ||
| 509 | |||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | #endif | ||
| 513 | |||
| 514 | static const struct dev_pm_ops sirf_audio_codec_pm_ops = { | ||
| 515 | SET_SYSTEM_SLEEP_PM_OPS(sirf_audio_codec_suspend, sirf_audio_codec_resume) | ||
| 516 | }; | ||
| 517 | |||
| 518 | static struct platform_driver sirf_audio_codec_driver = { | ||
| 519 | .driver = { | ||
| 520 | .name = "sirf-audio-codec", | ||
| 521 | .owner = THIS_MODULE, | ||
| 522 | .of_match_table = sirf_audio_codec_of_match, | ||
| 523 | .pm = &sirf_audio_codec_pm_ops, | ||
| 524 | }, | ||
| 525 | .probe = sirf_audio_codec_driver_probe, | ||
| 526 | .remove = sirf_audio_codec_driver_remove, | ||
| 527 | }; | ||
| 528 | |||
| 529 | module_platform_driver(sirf_audio_codec_driver); | ||
| 530 | |||
| 531 | MODULE_DESCRIPTION("SiRF audio codec driver"); | ||
| 532 | MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); | ||
| 533 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/sirf-audio-codec.h b/sound/soc/codecs/sirf-audio-codec.h new file mode 100644 index 000000000000..d4c187b8e54a --- /dev/null +++ b/sound/soc/codecs/sirf-audio-codec.h | |||
| @@ -0,0 +1,75 @@ | |||
| 1 | /* | ||
| 2 | * SiRF inner codec controllers define | ||
| 3 | * | ||
| 4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef _SIRF_AUDIO_CODEC_H | ||
| 10 | #define _SIRF_AUDIO_CODEC_H | ||
| 11 | |||
| 12 | |||
| 13 | #define AUDIO_IC_CODEC_PWR (0x00E0) | ||
| 14 | #define AUDIO_IC_CODEC_CTRL0 (0x00E4) | ||
| 15 | #define AUDIO_IC_CODEC_CTRL1 (0x00E8) | ||
| 16 | #define AUDIO_IC_CODEC_CTRL2 (0x00EC) | ||
| 17 | #define AUDIO_IC_CODEC_CTRL3 (0x00F0) | ||
| 18 | |||
| 19 | #define MICBIASEN (1 << 3) | ||
| 20 | |||
| 21 | #define IC_RDACEN (1 << 0) | ||
| 22 | #define IC_LDACEN (1 << 1) | ||
| 23 | #define IC_HSREN (1 << 2) | ||
| 24 | #define IC_HSLEN (1 << 3) | ||
| 25 | #define IC_SPEN (1 << 4) | ||
| 26 | #define IC_CPEN (1 << 5) | ||
| 27 | |||
| 28 | #define IC_HPRSELR (1 << 6) | ||
| 29 | #define IC_HPLSELR (1 << 7) | ||
| 30 | #define IC_HPRSELL (1 << 8) | ||
| 31 | #define IC_HPLSELL (1 << 9) | ||
| 32 | #define IC_SPSELR (1 << 10) | ||
| 33 | #define IC_SPSELL (1 << 11) | ||
| 34 | |||
| 35 | #define IC_MONOR (1 << 12) | ||
| 36 | #define IC_MONOL (1 << 13) | ||
| 37 | |||
| 38 | #define IC_RXOSRSEL (1 << 28) | ||
| 39 | #define IC_CPFREQ (1 << 29) | ||
| 40 | #define IC_HSINVEN (1 << 30) | ||
| 41 | |||
| 42 | #define IC_MICINREN (1 << 0) | ||
| 43 | #define IC_MICINLEN (1 << 1) | ||
| 44 | #define IC_MICIN1SEL (1 << 2) | ||
| 45 | #define IC_MICIN2SEL (1 << 3) | ||
| 46 | #define IC_MICDIFSEL (1 << 4) | ||
| 47 | #define IC_LINEIN1SEL (1 << 5) | ||
| 48 | #define IC_LINEIN2SEL (1 << 6) | ||
| 49 | #define IC_RADCEN (1 << 7) | ||
| 50 | #define IC_LADCEN (1 << 8) | ||
| 51 | #define IC_ALM (1 << 9) | ||
| 52 | |||
| 53 | #define IC_DIGMICEN (1 << 22) | ||
| 54 | #define IC_DIGMICFREQ (1 << 23) | ||
| 55 | #define IC_ADC14B_12 (1 << 24) | ||
| 56 | #define IC_FIRDAC_HSL_EN (1 << 25) | ||
| 57 | #define IC_FIRDAC_HSR_EN (1 << 26) | ||
| 58 | #define IC_FIRDAC_LOUT_EN (1 << 27) | ||
| 59 | #define IC_POR (1 << 28) | ||
| 60 | #define IC_CODEC_CLK_EN (1 << 29) | ||
| 61 | #define IC_HP_3DB_BOOST (1 << 30) | ||
| 62 | |||
| 63 | #define IC_ADC_LEFT_GAIN_SHIFT 16 | ||
| 64 | #define IC_ADC_RIGHT_GAIN_SHIFT 10 | ||
| 65 | #define IC_ADC_GAIN_MASK 0x3F | ||
| 66 | #define IC_MIC_MAX_GAIN 0x39 | ||
| 67 | |||
| 68 | #define IC_RXPGAR_MASK 0x3F | ||
| 69 | #define IC_RXPGAR_SHIFT 14 | ||
| 70 | #define IC_RXPGAL_MASK 0x3F | ||
| 71 | #define IC_RXPGAL_SHIFT 21 | ||
| 72 | #define IC_RXPGAR 0x7B | ||
| 73 | #define IC_RXPGAL 0x7B | ||
| 74 | |||
| 75 | #endif /*__SIRF_AUDIO_CODEC_H*/ | ||
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index 13045f2af4d3..bca7d02b362a 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c | |||
| @@ -312,14 +312,14 @@ static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w, | |||
| 312 | /* mux controls */ | 312 | /* mux controls */ |
| 313 | static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" }; | 313 | static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" }; |
| 314 | 314 | ||
| 315 | static const struct soc_enum sn95031_micl_enum = | 315 | static SOC_ENUM_SINGLE_DECL(sn95031_micl_enum, |
| 316 | SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts); | 316 | SN95031_ADCCONFIG, 1, sn95031_mic_texts); |
| 317 | 317 | ||
| 318 | static const struct snd_kcontrol_new sn95031_micl_mux_control = | 318 | static const struct snd_kcontrol_new sn95031_micl_mux_control = |
| 319 | SOC_DAPM_ENUM("Route", sn95031_micl_enum); | 319 | SOC_DAPM_ENUM("Route", sn95031_micl_enum); |
| 320 | 320 | ||
| 321 | static const struct soc_enum sn95031_micr_enum = | 321 | static SOC_ENUM_SINGLE_DECL(sn95031_micr_enum, |
| 322 | SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts); | 322 | SN95031_ADCCONFIG, 3, sn95031_mic_texts); |
| 323 | 323 | ||
| 324 | static const struct snd_kcontrol_new sn95031_micr_mux_control = | 324 | static const struct snd_kcontrol_new sn95031_micr_mux_control = |
| 325 | SOC_DAPM_ENUM("Route", sn95031_micr_enum); | 325 | SOC_DAPM_ENUM("Route", sn95031_micr_enum); |
| @@ -328,26 +328,26 @@ static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3", | |||
| 328 | "DMIC4", "DMIC5", "DMIC6", | 328 | "DMIC4", "DMIC5", "DMIC6", |
| 329 | "ADC Left", "ADC Right" }; | 329 | "ADC Left", "ADC Right" }; |
| 330 | 330 | ||
| 331 | static const struct soc_enum sn95031_input1_enum = | 331 | static SOC_ENUM_SINGLE_DECL(sn95031_input1_enum, |
| 332 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts); | 332 | SN95031_AUDIOMUX12, 0, sn95031_input_texts); |
| 333 | 333 | ||
| 334 | static const struct snd_kcontrol_new sn95031_input1_mux_control = | 334 | static const struct snd_kcontrol_new sn95031_input1_mux_control = |
| 335 | SOC_DAPM_ENUM("Route", sn95031_input1_enum); | 335 | SOC_DAPM_ENUM("Route", sn95031_input1_enum); |
| 336 | 336 | ||
| 337 | static const struct soc_enum sn95031_input2_enum = | 337 | static SOC_ENUM_SINGLE_DECL(sn95031_input2_enum, |
| 338 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts); | 338 | SN95031_AUDIOMUX12, 4, sn95031_input_texts); |
| 339 | 339 | ||
| 340 | static const struct snd_kcontrol_new sn95031_input2_mux_control = | 340 | static const struct snd_kcontrol_new sn95031_input2_mux_control = |
| 341 | SOC_DAPM_ENUM("Route", sn95031_input2_enum); | 341 | SOC_DAPM_ENUM("Route", sn95031_input2_enum); |
| 342 | 342 | ||
| 343 | static const struct soc_enum sn95031_input3_enum = | 343 | static SOC_ENUM_SINGLE_DECL(sn95031_input3_enum, |
| 344 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts); | 344 | SN95031_AUDIOMUX34, 0, sn95031_input_texts); |
| 345 | 345 | ||
| 346 | static const struct snd_kcontrol_new sn95031_input3_mux_control = | 346 | static const struct snd_kcontrol_new sn95031_input3_mux_control = |
| 347 | SOC_DAPM_ENUM("Route", sn95031_input3_enum); | 347 | SOC_DAPM_ENUM("Route", sn95031_input3_enum); |
| 348 | 348 | ||
| 349 | static const struct soc_enum sn95031_input4_enum = | 349 | static SOC_ENUM_SINGLE_DECL(sn95031_input4_enum, |
| 350 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts); | 350 | SN95031_AUDIOMUX34, 4, sn95031_input_texts); |
| 351 | 351 | ||
| 352 | static const struct snd_kcontrol_new sn95031_input4_mux_control = | 352 | static const struct snd_kcontrol_new sn95031_input4_mux_control = |
| 353 | SOC_DAPM_ENUM("Route", sn95031_input4_enum); | 353 | SOC_DAPM_ENUM("Route", sn95031_input4_enum); |
| @@ -359,19 +359,19 @@ static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"}; | |||
| 359 | /* 0dB to 30dB in 10dB steps */ | 359 | /* 0dB to 30dB in 10dB steps */ |
| 360 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0); | 360 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0); |
| 361 | 361 | ||
| 362 | static const struct soc_enum sn95031_micmode1_enum = | 362 | static SOC_ENUM_SINGLE_DECL(sn95031_micmode1_enum, |
| 363 | SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text); | 363 | SN95031_MICAMP1, 1, sn95031_micmode_text); |
| 364 | static const struct soc_enum sn95031_micmode2_enum = | 364 | static SOC_ENUM_SINGLE_DECL(sn95031_micmode2_enum, |
| 365 | SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text); | 365 | SN95031_MICAMP2, 1, sn95031_micmode_text); |
| 366 | 366 | ||
| 367 | static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"}; | 367 | static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"}; |
| 368 | 368 | ||
| 369 | static const struct soc_enum sn95031_dmic12_cfg_enum = | 369 | static SOC_ENUM_SINGLE_DECL(sn95031_dmic12_cfg_enum, |
| 370 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text); | 370 | SN95031_DMICMUX, 0, sn95031_dmic_cfg_text); |
| 371 | static const struct soc_enum sn95031_dmic34_cfg_enum = | 371 | static SOC_ENUM_SINGLE_DECL(sn95031_dmic34_cfg_enum, |
| 372 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text); | 372 | SN95031_DMICMUX, 1, sn95031_dmic_cfg_text); |
| 373 | static const struct soc_enum sn95031_dmic56_cfg_enum = | 373 | static SOC_ENUM_SINGLE_DECL(sn95031_dmic56_cfg_enum, |
| 374 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text); | 374 | SN95031_DMICMUX, 2, sn95031_dmic_cfg_text); |
| 375 | 375 | ||
| 376 | static const struct snd_kcontrol_new sn95031_snd_controls[] = { | 376 | static const struct snd_kcontrol_new sn95031_snd_controls[] = { |
| 377 | SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum), | 377 | SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum), |
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index cc8debce752f..806f3d826ffb 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c | |||
| @@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = { | |||
| 169 | "682.24 ms", "1364 ms", | 169 | "682.24 ms", "1364 ms", |
| 170 | }; | 170 | }; |
| 171 | 171 | ||
| 172 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, | 172 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, |
| 173 | SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); | 173 | SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); |
| 174 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, | 174 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, |
| 175 | SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); | 175 | SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); |
| 176 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, | 176 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, |
| 177 | SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); | 177 | SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); |
| 178 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, | 178 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, |
| 179 | SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); | 179 | SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); |
| 180 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, | 180 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, |
| 181 | SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); | 181 | SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); |
| 182 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, | 182 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, |
| 183 | SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); | 183 | SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); |
| 184 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, | 184 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, |
| 185 | SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); | 185 | SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); |
| 186 | 186 | ||
| 187 | static const struct snd_kcontrol_new ssm2518_snd_controls[] = { | 187 | static const struct snd_kcontrol_new ssm2518_snd_controls[] = { |
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c new file mode 100644 index 000000000000..abd63d537173 --- /dev/null +++ b/sound/soc/codecs/ssm2602-i2c.c | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | /* | ||
| 2 | * SSM2602/SSM2603/SSM2604 I2C audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/i2c.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "ssm2602.h" | ||
| 16 | |||
| 17 | /* | ||
| 18 | * ssm2602 2 wire address is determined by GPIO5 | ||
| 19 | * state during powerup. | ||
| 20 | * low = 0x1a | ||
| 21 | * high = 0x1b | ||
| 22 | */ | ||
| 23 | static int ssm2602_i2c_probe(struct i2c_client *client, | ||
| 24 | const struct i2c_device_id *id) | ||
| 25 | { | ||
| 26 | return ssm2602_probe(&client->dev, id->driver_data, | ||
| 27 | devm_regmap_init_i2c(client, &ssm2602_regmap_config)); | ||
| 28 | } | ||
| 29 | |||
| 30 | static int ssm2602_i2c_remove(struct i2c_client *client) | ||
| 31 | { | ||
| 32 | snd_soc_unregister_codec(&client->dev); | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | |||
| 36 | static const struct i2c_device_id ssm2602_i2c_id[] = { | ||
| 37 | { "ssm2602", SSM2602 }, | ||
| 38 | { "ssm2603", SSM2602 }, | ||
| 39 | { "ssm2604", SSM2604 }, | ||
| 40 | { } | ||
| 41 | }; | ||
| 42 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | ||
| 43 | |||
| 44 | static struct i2c_driver ssm2602_i2c_driver = { | ||
| 45 | .driver = { | ||
| 46 | .name = "ssm2602", | ||
| 47 | .owner = THIS_MODULE, | ||
| 48 | }, | ||
| 49 | .probe = ssm2602_i2c_probe, | ||
| 50 | .remove = ssm2602_i2c_remove, | ||
| 51 | .id_table = ssm2602_i2c_id, | ||
| 52 | }; | ||
| 53 | module_i2c_driver(ssm2602_i2c_driver); | ||
| 54 | |||
| 55 | MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 I2C driver"); | ||
| 56 | MODULE_AUTHOR("Cliff Cai"); | ||
| 57 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c new file mode 100644 index 000000000000..2bf55e24a7bb --- /dev/null +++ b/sound/soc/codecs/ssm2602-spi.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* | ||
| 2 | * SSM2602 SPI audio driver | ||
| 3 | * | ||
| 4 | * Copyright 2014 Analog Devices Inc. | ||
| 5 | * | ||
| 6 | * Licensed under the GPL-2. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/spi/spi.h> | ||
| 11 | #include <linux/regmap.h> | ||
| 12 | |||
| 13 | #include <sound/soc.h> | ||
| 14 | |||
| 15 | #include "ssm2602.h" | ||
| 16 | |||
| 17 | static int ssm2602_spi_probe(struct spi_device *spi) | ||
| 18 | { | ||
| 19 | return ssm2602_probe(&spi->dev, SSM2602, | ||
| 20 | devm_regmap_init_spi(spi, &ssm2602_regmap_config)); | ||
| 21 | } | ||
| 22 | |||
| 23 | static int ssm2602_spi_remove(struct spi_device *spi) | ||
| 24 | { | ||
| 25 | snd_soc_unregister_codec(&spi->dev); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | static struct spi_driver ssm2602_spi_driver = { | ||
| 30 | .driver = { | ||
| 31 | .name = "ssm2602", | ||
| 32 | .owner = THIS_MODULE, | ||
| 33 | }, | ||
| 34 | .probe = ssm2602_spi_probe, | ||
| 35 | .remove = ssm2602_spi_remove, | ||
| 36 | }; | ||
| 37 | module_spi_driver(ssm2602_spi_driver); | ||
| 38 | |||
| 39 | MODULE_DESCRIPTION("ASoC SSM2602 SPI driver"); | ||
| 40 | MODULE_AUTHOR("Cliff Cai"); | ||
| 41 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index af76bbd1b24f..12947096897c 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
| @@ -27,32 +27,20 @@ | |||
| 27 | */ | 27 | */ |
| 28 | 28 | ||
| 29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
| 30 | #include <linux/moduleparam.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/delay.h> | ||
| 33 | #include <linux/pm.h> | ||
| 34 | #include <linux/i2c.h> | ||
| 35 | #include <linux/spi/spi.h> | ||
| 36 | #include <linux/regmap.h> | 30 | #include <linux/regmap.h> |
| 37 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
| 38 | #include <sound/core.h> | 32 | |
| 39 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
| 40 | #include <sound/pcm_params.h> | 34 | #include <sound/pcm_params.h> |
| 41 | #include <sound/soc.h> | 35 | #include <sound/soc.h> |
| 42 | #include <sound/initval.h> | ||
| 43 | #include <sound/tlv.h> | 36 | #include <sound/tlv.h> |
| 44 | 37 | ||
| 45 | #include "ssm2602.h" | 38 | #include "ssm2602.h" |
| 46 | 39 | ||
| 47 | enum ssm2602_type { | ||
| 48 | SSM2602, | ||
| 49 | SSM2604, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* codec private data */ | 40 | /* codec private data */ |
| 53 | struct ssm2602_priv { | 41 | struct ssm2602_priv { |
| 54 | unsigned int sysclk; | 42 | unsigned int sysclk; |
| 55 | struct snd_pcm_hw_constraint_list *sysclk_constraints; | 43 | const struct snd_pcm_hw_constraint_list *sysclk_constraints; |
| 56 | 44 | ||
| 57 | struct regmap *regmap; | 45 | struct regmap *regmap; |
| 58 | 46 | ||
| @@ -75,15 +63,16 @@ static const u16 ssm2602_reg[SSM2602_CACHEREGNUM] = { | |||
| 75 | 63 | ||
| 76 | /*Appending several "None"s just for OSS mixer use*/ | 64 | /*Appending several "None"s just for OSS mixer use*/ |
| 77 | static const char *ssm2602_input_select[] = { | 65 | static const char *ssm2602_input_select[] = { |
| 78 | "Line", "Mic", "None", "None", "None", | 66 | "Line", "Mic", |
| 79 | "None", "None", "None", | ||
| 80 | }; | 67 | }; |
| 81 | 68 | ||
| 82 | static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 69 | static const char *ssm2602_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
| 83 | 70 | ||
| 84 | static const struct soc_enum ssm2602_enum[] = { | 71 | static const struct soc_enum ssm2602_enum[] = { |
| 85 | SOC_ENUM_SINGLE(SSM2602_APANA, 2, 2, ssm2602_input_select), | 72 | SOC_ENUM_SINGLE(SSM2602_APANA, 2, ARRAY_SIZE(ssm2602_input_select), |
| 86 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, 4, ssm2602_deemph), | 73 | ssm2602_input_select), |
| 74 | SOC_ENUM_SINGLE(SSM2602_APDIGI, 1, ARRAY_SIZE(ssm2602_deemph), | ||
| 75 | ssm2602_deemph), | ||
| 87 | }; | 76 | }; |
| 88 | 77 | ||
| 89 | static const unsigned int ssm260x_outmix_tlv[] = { | 78 | static const unsigned int ssm260x_outmix_tlv[] = { |
| @@ -197,7 +186,7 @@ static const unsigned int ssm2602_rates_12288000[] = { | |||
| 197 | 8000, 16000, 32000, 48000, 96000, | 186 | 8000, 16000, 32000, 48000, 96000, |
| 198 | }; | 187 | }; |
| 199 | 188 | ||
| 200 | static struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { | 189 | static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { |
| 201 | .list = ssm2602_rates_12288000, | 190 | .list = ssm2602_rates_12288000, |
| 202 | .count = ARRAY_SIZE(ssm2602_rates_12288000), | 191 | .count = ARRAY_SIZE(ssm2602_rates_12288000), |
| 203 | }; | 192 | }; |
| @@ -206,7 +195,7 @@ static const unsigned int ssm2602_rates_11289600[] = { | |||
| 206 | 8000, 44100, 88200, | 195 | 8000, 44100, 88200, |
| 207 | }; | 196 | }; |
| 208 | 197 | ||
| 209 | static struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { | 198 | static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { |
| 210 | .list = ssm2602_rates_11289600, | 199 | .list = ssm2602_rates_11289600, |
| 211 | .count = ARRAY_SIZE(ssm2602_rates_11289600), | 200 | .count = ARRAY_SIZE(ssm2602_rates_11289600), |
| 212 | }; | 201 | }; |
| @@ -529,7 +518,7 @@ static int ssm2602_resume(struct snd_soc_codec *codec) | |||
| 529 | return 0; | 518 | return 0; |
| 530 | } | 519 | } |
| 531 | 520 | ||
| 532 | static int ssm2602_probe(struct snd_soc_codec *codec) | 521 | static int ssm2602_codec_probe(struct snd_soc_codec *codec) |
| 533 | { | 522 | { |
| 534 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 523 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
| 535 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 524 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| @@ -554,7 +543,7 @@ static int ssm2602_probe(struct snd_soc_codec *codec) | |||
| 554 | ARRAY_SIZE(ssm2602_routes)); | 543 | ARRAY_SIZE(ssm2602_routes)); |
| 555 | } | 544 | } |
| 556 | 545 | ||
| 557 | static int ssm2604_probe(struct snd_soc_codec *codec) | 546 | static int ssm2604_codec_probe(struct snd_soc_codec *codec) |
| 558 | { | 547 | { |
| 559 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 548 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 560 | int ret; | 549 | int ret; |
| @@ -568,7 +557,7 @@ static int ssm2604_probe(struct snd_soc_codec *codec) | |||
| 568 | ARRAY_SIZE(ssm2604_routes)); | 557 | ARRAY_SIZE(ssm2604_routes)); |
| 569 | } | 558 | } |
| 570 | 559 | ||
| 571 | static int ssm260x_probe(struct snd_soc_codec *codec) | 560 | static int ssm260x_codec_probe(struct snd_soc_codec *codec) |
| 572 | { | 561 | { |
| 573 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 562 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
| 574 | int ret; | 563 | int ret; |
| @@ -597,10 +586,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec) | |||
| 597 | 586 | ||
| 598 | switch (ssm2602->type) { | 587 | switch (ssm2602->type) { |
| 599 | case SSM2602: | 588 | case SSM2602: |
| 600 | ret = ssm2602_probe(codec); | 589 | ret = ssm2602_codec_probe(codec); |
| 601 | break; | 590 | break; |
| 602 | case SSM2604: | 591 | case SSM2604: |
| 603 | ret = ssm2604_probe(codec); | 592 | ret = ssm2604_codec_probe(codec); |
| 604 | break; | 593 | break; |
| 605 | } | 594 | } |
| 606 | 595 | ||
| @@ -620,7 +609,7 @@ static int ssm2602_remove(struct snd_soc_codec *codec) | |||
| 620 | } | 609 | } |
| 621 | 610 | ||
| 622 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { | 611 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { |
| 623 | .probe = ssm260x_probe, | 612 | .probe = ssm260x_codec_probe, |
| 624 | .remove = ssm2602_remove, | 613 | .remove = ssm2602_remove, |
| 625 | .suspend = ssm2602_suspend, | 614 | .suspend = ssm2602_suspend, |
| 626 | .resume = ssm2602_resume, | 615 | .resume = ssm2602_resume, |
| @@ -639,7 +628,7 @@ static bool ssm2602_register_volatile(struct device *dev, unsigned int reg) | |||
| 639 | return reg == SSM2602_RESET; | 628 | return reg == SSM2602_RESET; |
| 640 | } | 629 | } |
| 641 | 630 | ||
| 642 | static const struct regmap_config ssm2602_regmap_config = { | 631 | const struct regmap_config ssm2602_regmap_config = { |
| 643 | .val_bits = 9, | 632 | .val_bits = 9, |
| 644 | .reg_bits = 7, | 633 | .reg_bits = 7, |
| 645 | 634 | ||
| @@ -650,134 +639,28 @@ static const struct regmap_config ssm2602_regmap_config = { | |||
| 650 | .reg_defaults_raw = ssm2602_reg, | 639 | .reg_defaults_raw = ssm2602_reg, |
| 651 | .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), | 640 | .num_reg_defaults_raw = ARRAY_SIZE(ssm2602_reg), |
| 652 | }; | 641 | }; |
| 642 | EXPORT_SYMBOL_GPL(ssm2602_regmap_config); | ||
| 653 | 643 | ||
| 654 | #if defined(CONFIG_SPI_MASTER) | 644 | int ssm2602_probe(struct device *dev, enum ssm2602_type type, |
| 655 | static int ssm2602_spi_probe(struct spi_device *spi) | 645 | struct regmap *regmap) |
| 656 | { | 646 | { |
| 657 | struct ssm2602_priv *ssm2602; | 647 | struct ssm2602_priv *ssm2602; |
| 658 | int ret; | ||
| 659 | |||
| 660 | ssm2602 = devm_kzalloc(&spi->dev, sizeof(struct ssm2602_priv), | ||
| 661 | GFP_KERNEL); | ||
| 662 | if (ssm2602 == NULL) | ||
| 663 | return -ENOMEM; | ||
| 664 | |||
| 665 | spi_set_drvdata(spi, ssm2602); | ||
| 666 | ssm2602->type = SSM2602; | ||
| 667 | |||
| 668 | ssm2602->regmap = devm_regmap_init_spi(spi, &ssm2602_regmap_config); | ||
| 669 | if (IS_ERR(ssm2602->regmap)) | ||
| 670 | return PTR_ERR(ssm2602->regmap); | ||
| 671 | |||
| 672 | ret = snd_soc_register_codec(&spi->dev, | ||
| 673 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | ||
| 674 | return ret; | ||
| 675 | } | ||
| 676 | 648 | ||
| 677 | static int ssm2602_spi_remove(struct spi_device *spi) | 649 | if (IS_ERR(regmap)) |
| 678 | { | 650 | return PTR_ERR(regmap); |
| 679 | snd_soc_unregister_codec(&spi->dev); | ||
| 680 | return 0; | ||
| 681 | } | ||
| 682 | |||
| 683 | static struct spi_driver ssm2602_spi_driver = { | ||
| 684 | .driver = { | ||
| 685 | .name = "ssm2602", | ||
| 686 | .owner = THIS_MODULE, | ||
| 687 | }, | ||
| 688 | .probe = ssm2602_spi_probe, | ||
| 689 | .remove = ssm2602_spi_remove, | ||
| 690 | }; | ||
| 691 | #endif | ||
| 692 | |||
| 693 | #if IS_ENABLED(CONFIG_I2C) | ||
| 694 | /* | ||
| 695 | * ssm2602 2 wire address is determined by GPIO5 | ||
| 696 | * state during powerup. | ||
| 697 | * low = 0x1a | ||
| 698 | * high = 0x1b | ||
| 699 | */ | ||
| 700 | static int ssm2602_i2c_probe(struct i2c_client *i2c, | ||
| 701 | const struct i2c_device_id *id) | ||
| 702 | { | ||
| 703 | struct ssm2602_priv *ssm2602; | ||
| 704 | int ret; | ||
| 705 | 651 | ||
| 706 | ssm2602 = devm_kzalloc(&i2c->dev, sizeof(struct ssm2602_priv), | 652 | ssm2602 = devm_kzalloc(dev, sizeof(*ssm2602), GFP_KERNEL); |
| 707 | GFP_KERNEL); | ||
| 708 | if (ssm2602 == NULL) | 653 | if (ssm2602 == NULL) |
| 709 | return -ENOMEM; | 654 | return -ENOMEM; |
| 710 | 655 | ||
| 711 | i2c_set_clientdata(i2c, ssm2602); | 656 | dev_set_drvdata(dev, ssm2602); |
| 712 | ssm2602->type = id->driver_data; | 657 | ssm2602->type = SSM2602; |
| 713 | 658 | ssm2602->regmap = regmap; | |
| 714 | ssm2602->regmap = devm_regmap_init_i2c(i2c, &ssm2602_regmap_config); | ||
| 715 | if (IS_ERR(ssm2602->regmap)) | ||
| 716 | return PTR_ERR(ssm2602->regmap); | ||
| 717 | |||
| 718 | ret = snd_soc_register_codec(&i2c->dev, | ||
| 719 | &soc_codec_dev_ssm2602, &ssm2602_dai, 1); | ||
| 720 | return ret; | ||
| 721 | } | ||
| 722 | |||
| 723 | static int ssm2602_i2c_remove(struct i2c_client *client) | ||
| 724 | { | ||
| 725 | snd_soc_unregister_codec(&client->dev); | ||
| 726 | return 0; | ||
| 727 | } | ||
| 728 | |||
| 729 | static const struct i2c_device_id ssm2602_i2c_id[] = { | ||
| 730 | { "ssm2602", SSM2602 }, | ||
| 731 | { "ssm2603", SSM2602 }, | ||
| 732 | { "ssm2604", SSM2604 }, | ||
| 733 | { } | ||
| 734 | }; | ||
| 735 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | ||
| 736 | |||
| 737 | /* corgi i2c codec control layer */ | ||
| 738 | static struct i2c_driver ssm2602_i2c_driver = { | ||
| 739 | .driver = { | ||
| 740 | .name = "ssm2602", | ||
| 741 | .owner = THIS_MODULE, | ||
| 742 | }, | ||
| 743 | .probe = ssm2602_i2c_probe, | ||
| 744 | .remove = ssm2602_i2c_remove, | ||
| 745 | .id_table = ssm2602_i2c_id, | ||
| 746 | }; | ||
| 747 | #endif | ||
| 748 | |||
| 749 | |||
| 750 | static int __init ssm2602_modinit(void) | ||
| 751 | { | ||
| 752 | int ret = 0; | ||
| 753 | |||
| 754 | #if defined(CONFIG_SPI_MASTER) | ||
| 755 | ret = spi_register_driver(&ssm2602_spi_driver); | ||
| 756 | if (ret) | ||
| 757 | return ret; | ||
| 758 | #endif | ||
| 759 | |||
| 760 | #if IS_ENABLED(CONFIG_I2C) | ||
| 761 | ret = i2c_add_driver(&ssm2602_i2c_driver); | ||
| 762 | if (ret) | ||
| 763 | return ret; | ||
| 764 | #endif | ||
| 765 | |||
| 766 | return ret; | ||
| 767 | } | ||
| 768 | module_init(ssm2602_modinit); | ||
| 769 | |||
| 770 | static void __exit ssm2602_exit(void) | ||
| 771 | { | ||
| 772 | #if defined(CONFIG_SPI_MASTER) | ||
| 773 | spi_unregister_driver(&ssm2602_spi_driver); | ||
| 774 | #endif | ||
| 775 | 659 | ||
| 776 | #if IS_ENABLED(CONFIG_I2C) | 660 | return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, |
| 777 | i2c_del_driver(&ssm2602_i2c_driver); | 661 | &ssm2602_dai, 1); |
| 778 | #endif | ||
| 779 | } | 662 | } |
| 780 | module_exit(ssm2602_exit); | 663 | EXPORT_SYMBOL_GPL(ssm2602_probe); |
| 781 | 664 | ||
| 782 | MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); | 665 | MODULE_DESCRIPTION("ASoC SSM2602/SSM2603/SSM2604 driver"); |
| 783 | MODULE_AUTHOR("Cliff Cai"); | 666 | MODULE_AUTHOR("Cliff Cai"); |
diff --git a/sound/soc/codecs/ssm2602.h b/sound/soc/codecs/ssm2602.h index fbd07d7b73ca..747538847689 100644 --- a/sound/soc/codecs/ssm2602.h +++ b/sound/soc/codecs/ssm2602.h | |||
| @@ -28,6 +28,20 @@ | |||
| 28 | #ifndef _SSM2602_H | 28 | #ifndef _SSM2602_H |
| 29 | #define _SSM2602_H | 29 | #define _SSM2602_H |
| 30 | 30 | ||
| 31 | #include <linux/regmap.h> | ||
| 32 | |||
| 33 | struct device; | ||
| 34 | |||
| 35 | enum ssm2602_type { | ||
| 36 | SSM2602, | ||
| 37 | SSM2604, | ||
| 38 | }; | ||
| 39 | |||
| 40 | extern const struct regmap_config ssm2602_regmap_config; | ||
| 41 | |||
| 42 | int ssm2602_probe(struct device *dev, enum ssm2602_type type, | ||
| 43 | struct regmap *regmap); | ||
| 44 | |||
| 31 | /* SSM2602 Codec Register definitions */ | 45 | /* SSM2602 Codec Register definitions */ |
| 32 | 46 | ||
| 33 | #define SSM2602_LINVOL 0x00 | 47 | #define SSM2602_LINVOL 0x00 |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 40c07be9b581..f15b0e37274c 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
| @@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary", | |||
| 141 | 141 | ||
| 142 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); | 142 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); |
| 143 | static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); | 143 | static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); |
| 144 | static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); | 144 | static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); |
| 145 | 145 | ||
| 146 | static const struct snd_kcontrol_new sta529_snd_controls[] = { | 146 | static const struct snd_kcontrol_new sta529_snd_controls[] = { |
| 147 | SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, | 147 | SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, |
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index a5455c1aea42..53b810d23fea 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
| @@ -62,25 +62,25 @@ static const char *stac9766_boost1[] = {"0dB", "10dB"}; | |||
| 62 | static const char *stac9766_boost2[] = {"0dB", "20dB"}; | 62 | static const char *stac9766_boost2[] = {"0dB", "20dB"}; |
| 63 | static const char *stac9766_stereo_mic[] = {"Off", "On"}; | 63 | static const char *stac9766_stereo_mic[] = {"Off", "On"}; |
| 64 | 64 | ||
| 65 | static const struct soc_enum stac9766_record_enum = | 65 | static SOC_ENUM_DOUBLE_DECL(stac9766_record_enum, |
| 66 | SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 8, stac9766_record_mux); | 66 | AC97_REC_SEL, 8, 0, stac9766_record_mux); |
| 67 | static const struct soc_enum stac9766_mono_enum = | 67 | static SOC_ENUM_SINGLE_DECL(stac9766_mono_enum, |
| 68 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 9, 2, stac9766_mono_mux); | 68 | AC97_GENERAL_PURPOSE, 9, stac9766_mono_mux); |
| 69 | static const struct soc_enum stac9766_mic_enum = | 69 | static SOC_ENUM_SINGLE_DECL(stac9766_mic_enum, |
| 70 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, stac9766_mic_mux); | 70 | AC97_GENERAL_PURPOSE, 8, stac9766_mic_mux); |
| 71 | static const struct soc_enum stac9766_SPDIF_enum = | 71 | static SOC_ENUM_SINGLE_DECL(stac9766_SPDIF_enum, |
| 72 | SOC_ENUM_SINGLE(AC97_STAC_DA_CONTROL, 1, 2, stac9766_SPDIF_mux); | 72 | AC97_STAC_DA_CONTROL, 1, stac9766_SPDIF_mux); |
| 73 | static const struct soc_enum stac9766_popbypass_enum = | 73 | static SOC_ENUM_SINGLE_DECL(stac9766_popbypass_enum, |
| 74 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, stac9766_popbypass_mux); | 74 | AC97_GENERAL_PURPOSE, 15, stac9766_popbypass_mux); |
| 75 | static const struct soc_enum stac9766_record_all_enum = | 75 | static SOC_ENUM_SINGLE_DECL(stac9766_record_all_enum, |
| 76 | SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 12, 2, | 76 | AC97_STAC_ANALOG_SPECIAL, 12, |
| 77 | stac9766_record_all_mux); | 77 | stac9766_record_all_mux); |
| 78 | static const struct soc_enum stac9766_boost1_enum = | 78 | static SOC_ENUM_SINGLE_DECL(stac9766_boost1_enum, |
| 79 | SOC_ENUM_SINGLE(AC97_MIC, 6, 2, stac9766_boost1); /* 0/10dB */ | 79 | AC97_MIC, 6, stac9766_boost1); /* 0/10dB */ |
| 80 | static const struct soc_enum stac9766_boost2_enum = | 80 | static SOC_ENUM_SINGLE_DECL(stac9766_boost2_enum, |
| 81 | SOC_ENUM_SINGLE(AC97_STAC_ANALOG_SPECIAL, 2, 2, stac9766_boost2); /* 0/20dB */ | 81 | AC97_STAC_ANALOG_SPECIAL, 2, stac9766_boost2); /* 0/20dB */ |
| 82 | static const struct soc_enum stac9766_stereo_mic_enum = | 82 | static SOC_ENUM_SINGLE_DECL(stac9766_stereo_mic_enum, |
| 83 | SOC_ENUM_SINGLE(AC97_STAC_STEREO_MIC, 2, 1, stac9766_stereo_mic); | 83 | AC97_STAC_STEREO_MIC, 2, stac9766_stereo_mic); |
| 84 | 84 | ||
| 85 | static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); | 85 | static const DECLARE_TLV_DB_LINEAR(master_tlv, -4600, 0); |
| 86 | static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); | 86 | static const DECLARE_TLV_DB_LINEAR(record_tlv, 0, 2250); |
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c new file mode 100644 index 000000000000..20fc46092c2c --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-i2c.c | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | /* | ||
| 2 | * ALSA SoC TLV320AIC23 codec driver I2C interface | ||
| 3 | * | ||
| 4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
| 5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
| 6 | * | ||
| 7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/i2c.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/regmap.h> | ||
| 17 | #include <sound/soc.h> | ||
| 18 | |||
| 19 | #include "tlv320aic23.h" | ||
| 20 | |||
| 21 | static int tlv320aic23_i2c_probe(struct i2c_client *i2c, | ||
| 22 | const struct i2c_device_id *i2c_id) | ||
| 23 | { | ||
| 24 | struct regmap *regmap; | ||
| 25 | |||
| 26 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
| 27 | return -EINVAL; | ||
| 28 | |||
| 29 | regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); | ||
| 30 | return tlv320aic23_probe(&i2c->dev, regmap); | ||
| 31 | } | ||
| 32 | |||
| 33 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
| 34 | { | ||
| 35 | snd_soc_unregister_codec(&i2c->dev); | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
| 40 | {"tlv320aic23", 0}, | ||
| 41 | {} | ||
| 42 | }; | ||
| 43 | |||
| 44 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
| 45 | |||
| 46 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
| 47 | .driver = { | ||
| 48 | .name = "tlv320aic23-codec", | ||
| 49 | }, | ||
| 50 | .probe = tlv320aic23_i2c_probe, | ||
| 51 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
| 52 | .id_table = tlv320aic23_id, | ||
| 53 | }; | ||
| 54 | |||
| 55 | module_i2c_driver(tlv320aic23_i2c_driver); | ||
| 56 | |||
| 57 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C"); | ||
| 58 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
| 59 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c new file mode 100644 index 000000000000..3b387e41d75d --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-spi.c | |||
| @@ -0,0 +1,56 @@ | |||
| 1 | /* | ||
| 2 | * ALSA SoC TLV320AIC23 codec driver SPI interface | ||
| 3 | * | ||
| 4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
| 5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
| 6 | * | ||
| 7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/module.h> | ||
| 15 | #include <linux/regmap.h> | ||
| 16 | #include <linux/spi/spi.h> | ||
| 17 | #include <sound/soc.h> | ||
| 18 | |||
| 19 | #include "tlv320aic23.h" | ||
| 20 | |||
| 21 | static int aic23_spi_probe(struct spi_device *spi) | ||
| 22 | { | ||
| 23 | int ret; | ||
| 24 | struct regmap *regmap; | ||
| 25 | |||
| 26 | dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n"); | ||
| 27 | |||
| 28 | spi->mode = SPI_MODE_0; | ||
| 29 | ret = spi_setup(spi); | ||
| 30 | if (ret < 0) | ||
| 31 | return ret; | ||
| 32 | |||
| 33 | regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap); | ||
| 34 | return tlv320aic23_probe(&spi->dev, regmap); | ||
| 35 | } | ||
| 36 | |||
| 37 | static int aic23_spi_remove(struct spi_device *spi) | ||
| 38 | { | ||
| 39 | snd_soc_unregister_codec(&spi->dev); | ||
| 40 | return 0; | ||
| 41 | } | ||
| 42 | |||
| 43 | static struct spi_driver aic23_spi = { | ||
| 44 | .driver = { | ||
| 45 | .name = "tlv320aic23", | ||
| 46 | .owner = THIS_MODULE, | ||
| 47 | }, | ||
| 48 | .probe = aic23_spi_probe, | ||
| 49 | .remove = aic23_spi_remove, | ||
| 50 | }; | ||
| 51 | |||
| 52 | module_spi_driver(aic23_spi); | ||
| 53 | |||
| 54 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI"); | ||
| 55 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
| 56 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 5d430cc56f51..dc9a52fcb39a 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
| @@ -23,7 +23,6 @@ | |||
| 23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
| 24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
| 26 | #include <linux/i2c.h> | ||
| 27 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
| 28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
| 29 | #include <sound/core.h> | 28 | #include <sound/core.h> |
| @@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = { | |||
| 51 | { 9, 0x0000 }, | 50 | { 9, 0x0000 }, |
| 52 | }; | 51 | }; |
| 53 | 52 | ||
| 54 | static const struct regmap_config tlv320aic23_regmap = { | 53 | const struct regmap_config tlv320aic23_regmap = { |
| 55 | .reg_bits = 7, | 54 | .reg_bits = 7, |
| 56 | .val_bits = 9, | 55 | .val_bits = 9, |
| 57 | 56 | ||
| @@ -60,20 +59,21 @@ static const struct regmap_config tlv320aic23_regmap = { | |||
| 60 | .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg), | 59 | .num_reg_defaults = ARRAY_SIZE(tlv320aic23_reg), |
| 61 | .cache_type = REGCACHE_RBTREE, | 60 | .cache_type = REGCACHE_RBTREE, |
| 62 | }; | 61 | }; |
| 62 | EXPORT_SYMBOL(tlv320aic23_regmap); | ||
| 63 | 63 | ||
| 64 | static const char *rec_src_text[] = { "Line", "Mic" }; | 64 | static const char *rec_src_text[] = { "Line", "Mic" }; |
| 65 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 65 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
| 66 | 66 | ||
| 67 | static const struct soc_enum rec_src_enum = | 67 | static SOC_ENUM_SINGLE_DECL(rec_src_enum, |
| 68 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | 68 | TLV320AIC23_ANLG, 2, rec_src_text); |
| 69 | 69 | ||
| 70 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = | 70 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = |
| 71 | SOC_DAPM_ENUM("Input Select", rec_src_enum); | 71 | SOC_DAPM_ENUM("Input Select", rec_src_enum); |
| 72 | 72 | ||
| 73 | static const struct soc_enum tlv320aic23_rec_src = | 73 | static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, |
| 74 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | 74 | TLV320AIC23_ANLG, 2, rec_src_text); |
| 75 | static const struct soc_enum tlv320aic23_deemph = | 75 | static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, |
| 76 | SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); | 76 | TLV320AIC23_DIGT, 1, deemph_text); |
| 77 | 77 | ||
| 78 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); | 78 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); |
| 79 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); | 79 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); |
| @@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
| 400 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | 400 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
| 401 | 401 | ||
| 402 | /* deactivate */ | 402 | /* deactivate */ |
| 403 | if (!codec->active) { | 403 | if (!snd_soc_codec_is_active(codec)) { |
| 404 | udelay(50); | 404 | udelay(50); |
| 405 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); | 405 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); |
| 406 | } | 406 | } |
| @@ -557,7 +557,7 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) | |||
| 557 | return 0; | 557 | return 0; |
| 558 | } | 558 | } |
| 559 | 559 | ||
| 560 | static int tlv320aic23_probe(struct snd_soc_codec *codec) | 560 | static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) |
| 561 | { | 561 | { |
| 562 | int ret; | 562 | int ret; |
| 563 | 563 | ||
| @@ -604,7 +604,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) | |||
| 604 | } | 604 | } |
| 605 | 605 | ||
| 606 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | 606 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { |
| 607 | .probe = tlv320aic23_probe, | 607 | .probe = tlv320aic23_codec_probe, |
| 608 | .remove = tlv320aic23_remove, | 608 | .remove = tlv320aic23_remove, |
| 609 | .suspend = tlv320aic23_suspend, | 609 | .suspend = tlv320aic23_suspend, |
| 610 | .resume = tlv320aic23_resume, | 610 | .resume = tlv320aic23_resume, |
| @@ -617,56 +617,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | |||
| 617 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), | 617 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), |
| 618 | }; | 618 | }; |
| 619 | 619 | ||
| 620 | /* | 620 | int tlv320aic23_probe(struct device *dev, struct regmap *regmap) |
| 621 | * If the i2c layer weren't so broken, we could pass this kind of data | ||
| 622 | * around | ||
| 623 | */ | ||
| 624 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | ||
| 625 | const struct i2c_device_id *i2c_id) | ||
| 626 | { | 621 | { |
| 627 | struct aic23 *aic23; | 622 | struct aic23 *aic23; |
| 628 | int ret; | ||
| 629 | 623 | ||
| 630 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 624 | if (IS_ERR(regmap)) |
| 631 | return -EINVAL; | 625 | return PTR_ERR(regmap); |
| 632 | 626 | ||
| 633 | aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL); | 627 | aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL); |
| 634 | if (aic23 == NULL) | 628 | if (aic23 == NULL) |
| 635 | return -ENOMEM; | 629 | return -ENOMEM; |
| 636 | 630 | ||
| 637 | aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); | 631 | aic23->regmap = regmap; |
| 638 | if (IS_ERR(aic23->regmap)) | ||
| 639 | return PTR_ERR(aic23->regmap); | ||
| 640 | 632 | ||
| 641 | i2c_set_clientdata(i2c, aic23); | 633 | dev_set_drvdata(dev, aic23); |
| 642 | 634 | ||
| 643 | ret = snd_soc_register_codec(&i2c->dev, | 635 | return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, |
| 644 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); | 636 | &tlv320aic23_dai, 1); |
| 645 | return ret; | ||
| 646 | } | ||
| 647 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
| 648 | { | ||
| 649 | snd_soc_unregister_codec(&i2c->dev); | ||
| 650 | return 0; | ||
| 651 | } | 637 | } |
| 652 | 638 | EXPORT_SYMBOL(tlv320aic23_probe); | |
| 653 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
| 654 | {"tlv320aic23", 0}, | ||
| 655 | {} | ||
| 656 | }; | ||
| 657 | |||
| 658 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
| 659 | |||
| 660 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
| 661 | .driver = { | ||
| 662 | .name = "tlv320aic23-codec", | ||
| 663 | }, | ||
| 664 | .probe = tlv320aic23_codec_probe, | ||
| 665 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
| 666 | .id_table = tlv320aic23_id, | ||
| 667 | }; | ||
| 668 | |||
| 669 | module_i2c_driver(tlv320aic23_i2c_driver); | ||
| 670 | 639 | ||
| 671 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); | 640 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); |
| 672 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | 641 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); |
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h index e804120bd3da..3a7235a04a89 100644 --- a/sound/soc/codecs/tlv320aic23.h +++ b/sound/soc/codecs/tlv320aic23.h | |||
| @@ -12,6 +12,12 @@ | |||
| 12 | #ifndef _TLV320AIC23_H | 12 | #ifndef _TLV320AIC23_H |
| 13 | #define _TLV320AIC23_H | 13 | #define _TLV320AIC23_H |
| 14 | 14 | ||
| 15 | struct device; | ||
| 16 | struct regmap_config; | ||
| 17 | |||
| 18 | extern const struct regmap_config tlv320aic23_regmap; | ||
| 19 | int tlv320aic23_probe(struct device *dev, struct regmap *regmap); | ||
| 20 | |||
| 15 | /* Codec TLV320AIC23 */ | 21 | /* Codec TLV320AIC23 */ |
| 16 | #define TLV320AIC23_LINVOL 0x00 | 22 | #define TLV320AIC23_LINVOL 0x00 |
| 17 | #define TLV320AIC23_RINVOL 0x01 | 23 | #define TLV320AIC23_RINVOL 0x01 |
diff --git a/sound/soc/codecs/tlv320aic26.c b/sound/soc/codecs/tlv320aic26.c index 94a658fa6d97..ff5f23d482b7 100644 --- a/sound/soc/codecs/tlv320aic26.c +++ b/sound/soc/codecs/tlv320aic26.c | |||
| @@ -238,8 +238,9 @@ static struct snd_soc_dai_driver aic26_dai = { | |||
| 238 | * ALSA controls | 238 | * ALSA controls |
| 239 | */ | 239 | */ |
| 240 | static const char *aic26_capture_src_text[] = {"Mic", "Aux"}; | 240 | static const char *aic26_capture_src_text[] = {"Mic", "Aux"}; |
| 241 | static const struct soc_enum aic26_capture_src_enum = | 241 | static SOC_ENUM_SINGLE_DECL(aic26_capture_src_enum, |
| 242 | SOC_ENUM_SINGLE(AIC26_REG_AUDIO_CTRL1, 12, 2, aic26_capture_src_text); | 242 | AIC26_REG_AUDIO_CTRL1, 12, |
| 243 | aic26_capture_src_text); | ||
| 243 | 244 | ||
| 244 | static const struct snd_kcontrol_new aic26_snd_controls[] = { | 245 | static const struct snd_kcontrol_new aic26_snd_controls[] = { |
| 245 | /* Output */ | 246 | /* Output */ |
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 688151ba309a..c6bd7e75352d 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
| @@ -29,9 +29,12 @@ | |||
| 29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
| 30 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
| 31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
| 32 | #include <linux/of_gpio.h> | ||
| 32 | #include <linux/i2c.h> | 33 | #include <linux/i2c.h> |
| 33 | #include <linux/cdev.h> | 34 | #include <linux/cdev.h> |
| 34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
| 36 | #include <linux/clk.h> | ||
| 37 | #include <linux/regulator/consumer.h> | ||
| 35 | 38 | ||
| 36 | #include <sound/tlv320aic32x4.h> | 39 | #include <sound/tlv320aic32x4.h> |
| 37 | #include <sound/core.h> | 40 | #include <sound/core.h> |
| @@ -66,20 +69,32 @@ struct aic32x4_priv { | |||
| 66 | u32 micpga_routing; | 69 | u32 micpga_routing; |
| 67 | bool swapdacs; | 70 | bool swapdacs; |
| 68 | int rstn_gpio; | 71 | int rstn_gpio; |
| 72 | struct clk *mclk; | ||
| 73 | |||
| 74 | struct regulator *supply_ldo; | ||
| 75 | struct regulator *supply_iov; | ||
| 76 | struct regulator *supply_dv; | ||
| 77 | struct regulator *supply_av; | ||
| 69 | }; | 78 | }; |
| 70 | 79 | ||
| 71 | /* 0dB min, 1dB steps */ | ||
| 72 | static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0); | ||
| 73 | /* 0dB min, 0.5dB steps */ | 80 | /* 0dB min, 0.5dB steps */ |
| 74 | static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0); | 81 | static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0); |
| 82 | /* -63.5dB min, 0.5dB steps */ | ||
| 83 | static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0); | ||
| 84 | /* -6dB min, 1dB steps */ | ||
| 85 | static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0); | ||
| 86 | /* -12dB min, 0.5dB steps */ | ||
| 87 | static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0); | ||
| 75 | 88 | ||
| 76 | static const struct snd_kcontrol_new aic32x4_snd_controls[] = { | 89 | static const struct snd_kcontrol_new aic32x4_snd_controls[] = { |
| 77 | SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL, | 90 | SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, |
| 78 | AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5), | 91 | AIC32X4_RDACVOL, 0, -0x7f, 0x30, 7, 0, tlv_pcm), |
| 79 | SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, | 92 | SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, |
| 80 | AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1), | 93 | AIC32X4_HPRGAIN, 0, -0x6, 0x1d, 5, 0, |
| 81 | SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, | 94 | tlv_driver_gain), |
| 82 | AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1), | 95 | SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, |
| 96 | AIC32X4_LORGAIN, 0, -0x6, 0x1d, 5, 0, | ||
| 97 | tlv_driver_gain), | ||
| 83 | SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, | 98 | SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, |
| 84 | AIC32X4_HPRGAIN, 6, 0x01, 1), | 99 | AIC32X4_HPRGAIN, 6, 0x01, 1), |
| 85 | SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, | 100 | SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, |
| @@ -90,8 +105,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = { | |||
| 90 | SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), | 105 | SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), |
| 91 | SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), | 106 | SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), |
| 92 | 107 | ||
| 93 | SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL, | 108 | SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, |
| 94 | AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5), | 109 | AIC32X4_RADCVOL, 0, -0x18, 0x28, 6, 0, tlv_adc_vol), |
| 95 | SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, | 110 | SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, |
| 96 | AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), | 111 | AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), |
| 97 | 112 | ||
| @@ -480,8 +495,18 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute) | |||
| 480 | static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | 495 | static int aic32x4_set_bias_level(struct snd_soc_codec *codec, |
| 481 | enum snd_soc_bias_level level) | 496 | enum snd_soc_bias_level level) |
| 482 | { | 497 | { |
| 498 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
| 499 | int ret; | ||
| 500 | |||
| 483 | switch (level) { | 501 | switch (level) { |
| 484 | case SND_SOC_BIAS_ON: | 502 | case SND_SOC_BIAS_ON: |
| 503 | /* Switch on master clock */ | ||
| 504 | ret = clk_prepare_enable(aic32x4->mclk); | ||
| 505 | if (ret) { | ||
| 506 | dev_err(codec->dev, "Failed to enable master clock\n"); | ||
| 507 | return ret; | ||
| 508 | } | ||
| 509 | |||
| 485 | /* Switch on PLL */ | 510 | /* Switch on PLL */ |
| 486 | snd_soc_update_bits(codec, AIC32X4_PLLPR, | 511 | snd_soc_update_bits(codec, AIC32X4_PLLPR, |
| 487 | AIC32X4_PLLEN, AIC32X4_PLLEN); | 512 | AIC32X4_PLLEN, AIC32X4_PLLEN); |
| @@ -509,29 +534,32 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | |||
| 509 | case SND_SOC_BIAS_PREPARE: | 534 | case SND_SOC_BIAS_PREPARE: |
| 510 | break; | 535 | break; |
| 511 | case SND_SOC_BIAS_STANDBY: | 536 | case SND_SOC_BIAS_STANDBY: |
| 512 | /* Switch off PLL */ | 537 | /* Switch off BCLK_N Divider */ |
| 513 | snd_soc_update_bits(codec, AIC32X4_PLLPR, | 538 | snd_soc_update_bits(codec, AIC32X4_BCLKN, |
| 514 | AIC32X4_PLLEN, 0); | 539 | AIC32X4_BCLKEN, 0); |
| 515 | 540 | ||
| 516 | /* Switch off NDAC Divider */ | 541 | /* Switch off MADC Divider */ |
| 517 | snd_soc_update_bits(codec, AIC32X4_NDAC, | 542 | snd_soc_update_bits(codec, AIC32X4_MADC, |
| 518 | AIC32X4_NDACEN, 0); | 543 | AIC32X4_MADCEN, 0); |
| 544 | |||
| 545 | /* Switch off NADC Divider */ | ||
| 546 | snd_soc_update_bits(codec, AIC32X4_NADC, | ||
| 547 | AIC32X4_NADCEN, 0); | ||
| 519 | 548 | ||
| 520 | /* Switch off MDAC Divider */ | 549 | /* Switch off MDAC Divider */ |
| 521 | snd_soc_update_bits(codec, AIC32X4_MDAC, | 550 | snd_soc_update_bits(codec, AIC32X4_MDAC, |
| 522 | AIC32X4_MDACEN, 0); | 551 | AIC32X4_MDACEN, 0); |
| 523 | 552 | ||
| 524 | /* Switch off NADC Divider */ | 553 | /* Switch off NDAC Divider */ |
| 525 | snd_soc_update_bits(codec, AIC32X4_NADC, | 554 | snd_soc_update_bits(codec, AIC32X4_NDAC, |
| 526 | AIC32X4_NADCEN, 0); | 555 | AIC32X4_NDACEN, 0); |
| 527 | 556 | ||
| 528 | /* Switch off MADC Divider */ | 557 | /* Switch off PLL */ |
| 529 | snd_soc_update_bits(codec, AIC32X4_MADC, | 558 | snd_soc_update_bits(codec, AIC32X4_PLLPR, |
| 530 | AIC32X4_MADCEN, 0); | 559 | AIC32X4_PLLEN, 0); |
| 531 | 560 | ||
| 532 | /* Switch off BCLK_N Divider */ | 561 | /* Switch off master clock */ |
| 533 | snd_soc_update_bits(codec, AIC32X4_BCLKN, | 562 | clk_disable_unprepare(aic32x4->mclk); |
| 534 | AIC32X4_BCLKEN, 0); | ||
| 535 | break; | 563 | break; |
| 536 | case SND_SOC_BIAS_OFF: | 564 | case SND_SOC_BIAS_OFF: |
| 537 | break; | 565 | break; |
| @@ -588,7 +616,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
| 588 | 616 | ||
| 589 | snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); | 617 | snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
| 590 | 618 | ||
| 591 | if (aic32x4->rstn_gpio >= 0) { | 619 | if (gpio_is_valid(aic32x4->rstn_gpio)) { |
| 592 | ndelay(10); | 620 | ndelay(10); |
| 593 | gpio_set_value(aic32x4->rstn_gpio, 1); | 621 | gpio_set_value(aic32x4->rstn_gpio, 1); |
| 594 | } | 622 | } |
| @@ -663,11 +691,122 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | |||
| 663 | .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), | 691 | .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), |
| 664 | }; | 692 | }; |
| 665 | 693 | ||
| 694 | static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, | ||
| 695 | struct device_node *np) | ||
| 696 | { | ||
| 697 | aic32x4->swapdacs = false; | ||
| 698 | aic32x4->micpga_routing = 0; | ||
| 699 | aic32x4->rstn_gpio = of_get_named_gpio(np, "reset-gpios", 0); | ||
| 700 | |||
| 701 | return 0; | ||
| 702 | } | ||
| 703 | |||
| 704 | static void aic32x4_disable_regulators(struct aic32x4_priv *aic32x4) | ||
| 705 | { | ||
| 706 | regulator_disable(aic32x4->supply_iov); | ||
| 707 | |||
| 708 | if (!IS_ERR(aic32x4->supply_ldo)) | ||
| 709 | regulator_disable(aic32x4->supply_ldo); | ||
| 710 | |||
| 711 | if (!IS_ERR(aic32x4->supply_dv)) | ||
| 712 | regulator_disable(aic32x4->supply_dv); | ||
| 713 | |||
| 714 | if (!IS_ERR(aic32x4->supply_av)) | ||
| 715 | regulator_disable(aic32x4->supply_av); | ||
| 716 | } | ||
| 717 | |||
| 718 | static int aic32x4_setup_regulators(struct device *dev, | ||
| 719 | struct aic32x4_priv *aic32x4) | ||
| 720 | { | ||
| 721 | int ret = 0; | ||
| 722 | |||
| 723 | aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin"); | ||
| 724 | aic32x4->supply_iov = devm_regulator_get(dev, "iov"); | ||
| 725 | aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv"); | ||
| 726 | aic32x4->supply_av = devm_regulator_get_optional(dev, "av"); | ||
| 727 | |||
| 728 | /* Check if the regulator requirements are fulfilled */ | ||
| 729 | |||
| 730 | if (IS_ERR(aic32x4->supply_iov)) { | ||
| 731 | dev_err(dev, "Missing supply 'iov'\n"); | ||
| 732 | return PTR_ERR(aic32x4->supply_iov); | ||
| 733 | } | ||
| 734 | |||
| 735 | if (IS_ERR(aic32x4->supply_ldo)) { | ||
| 736 | if (PTR_ERR(aic32x4->supply_ldo) == -EPROBE_DEFER) | ||
| 737 | return -EPROBE_DEFER; | ||
| 738 | |||
| 739 | if (IS_ERR(aic32x4->supply_dv)) { | ||
| 740 | dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); | ||
| 741 | return PTR_ERR(aic32x4->supply_dv); | ||
| 742 | } | ||
| 743 | if (IS_ERR(aic32x4->supply_av)) { | ||
| 744 | dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); | ||
| 745 | return PTR_ERR(aic32x4->supply_av); | ||
| 746 | } | ||
| 747 | } else { | ||
| 748 | if (IS_ERR(aic32x4->supply_dv) && | ||
| 749 | PTR_ERR(aic32x4->supply_dv) == -EPROBE_DEFER) | ||
| 750 | return -EPROBE_DEFER; | ||
| 751 | if (IS_ERR(aic32x4->supply_av) && | ||
| 752 | PTR_ERR(aic32x4->supply_av) == -EPROBE_DEFER) | ||
| 753 | return -EPROBE_DEFER; | ||
| 754 | } | ||
| 755 | |||
| 756 | ret = regulator_enable(aic32x4->supply_iov); | ||
| 757 | if (ret) { | ||
| 758 | dev_err(dev, "Failed to enable regulator iov\n"); | ||
| 759 | return ret; | ||
| 760 | } | ||
| 761 | |||
| 762 | if (!IS_ERR(aic32x4->supply_ldo)) { | ||
| 763 | ret = regulator_enable(aic32x4->supply_ldo); | ||
| 764 | if (ret) { | ||
| 765 | dev_err(dev, "Failed to enable regulator ldo\n"); | ||
| 766 | goto error_ldo; | ||
| 767 | } | ||
| 768 | } | ||
| 769 | |||
| 770 | if (!IS_ERR(aic32x4->supply_dv)) { | ||
| 771 | ret = regulator_enable(aic32x4->supply_dv); | ||
| 772 | if (ret) { | ||
| 773 | dev_err(dev, "Failed to enable regulator dv\n"); | ||
| 774 | goto error_dv; | ||
| 775 | } | ||
| 776 | } | ||
| 777 | |||
| 778 | if (!IS_ERR(aic32x4->supply_av)) { | ||
| 779 | ret = regulator_enable(aic32x4->supply_av); | ||
| 780 | if (ret) { | ||
| 781 | dev_err(dev, "Failed to enable regulator av\n"); | ||
| 782 | goto error_av; | ||
| 783 | } | ||
| 784 | } | ||
| 785 | |||
| 786 | if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av)) | ||
| 787 | aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE; | ||
| 788 | |||
| 789 | return 0; | ||
| 790 | |||
| 791 | error_av: | ||
| 792 | if (!IS_ERR(aic32x4->supply_dv)) | ||
| 793 | regulator_disable(aic32x4->supply_dv); | ||
| 794 | |||
| 795 | error_dv: | ||
| 796 | if (!IS_ERR(aic32x4->supply_ldo)) | ||
| 797 | regulator_disable(aic32x4->supply_ldo); | ||
| 798 | |||
| 799 | error_ldo: | ||
| 800 | regulator_disable(aic32x4->supply_iov); | ||
| 801 | return ret; | ||
| 802 | } | ||
| 803 | |||
| 666 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | 804 | static int aic32x4_i2c_probe(struct i2c_client *i2c, |
| 667 | const struct i2c_device_id *id) | 805 | const struct i2c_device_id *id) |
| 668 | { | 806 | { |
| 669 | struct aic32x4_pdata *pdata = i2c->dev.platform_data; | 807 | struct aic32x4_pdata *pdata = i2c->dev.platform_data; |
| 670 | struct aic32x4_priv *aic32x4; | 808 | struct aic32x4_priv *aic32x4; |
| 809 | struct device_node *np = i2c->dev.of_node; | ||
| 671 | int ret; | 810 | int ret; |
| 672 | 811 | ||
| 673 | aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), | 812 | aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), |
| @@ -686,6 +825,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
| 686 | aic32x4->swapdacs = pdata->swapdacs; | 825 | aic32x4->swapdacs = pdata->swapdacs; |
| 687 | aic32x4->micpga_routing = pdata->micpga_routing; | 826 | aic32x4->micpga_routing = pdata->micpga_routing; |
| 688 | aic32x4->rstn_gpio = pdata->rstn_gpio; | 827 | aic32x4->rstn_gpio = pdata->rstn_gpio; |
| 828 | } else if (np) { | ||
| 829 | ret = aic32x4_parse_dt(aic32x4, np); | ||
| 830 | if (ret) { | ||
| 831 | dev_err(&i2c->dev, "Failed to parse DT node\n"); | ||
| 832 | return ret; | ||
| 833 | } | ||
| 689 | } else { | 834 | } else { |
| 690 | aic32x4->power_cfg = 0; | 835 | aic32x4->power_cfg = 0; |
| 691 | aic32x4->swapdacs = false; | 836 | aic32x4->swapdacs = false; |
| @@ -693,20 +838,44 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
| 693 | aic32x4->rstn_gpio = -1; | 838 | aic32x4->rstn_gpio = -1; |
| 694 | } | 839 | } |
| 695 | 840 | ||
| 696 | if (aic32x4->rstn_gpio >= 0) { | 841 | aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); |
| 842 | if (IS_ERR(aic32x4->mclk)) { | ||
| 843 | dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); | ||
| 844 | return PTR_ERR(aic32x4->mclk); | ||
| 845 | } | ||
| 846 | |||
| 847 | if (gpio_is_valid(aic32x4->rstn_gpio)) { | ||
| 697 | ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, | 848 | ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, |
| 698 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); | 849 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); |
| 699 | if (ret != 0) | 850 | if (ret != 0) |
| 700 | return ret; | 851 | return ret; |
| 701 | } | 852 | } |
| 702 | 853 | ||
| 854 | ret = aic32x4_setup_regulators(&i2c->dev, aic32x4); | ||
| 855 | if (ret) { | ||
| 856 | dev_err(&i2c->dev, "Failed to setup regulators\n"); | ||
| 857 | return ret; | ||
| 858 | } | ||
| 859 | |||
| 703 | ret = snd_soc_register_codec(&i2c->dev, | 860 | ret = snd_soc_register_codec(&i2c->dev, |
| 704 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); | 861 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); |
| 705 | return ret; | 862 | if (ret) { |
| 863 | dev_err(&i2c->dev, "Failed to register codec\n"); | ||
| 864 | aic32x4_disable_regulators(aic32x4); | ||
| 865 | return ret; | ||
| 866 | } | ||
| 867 | |||
| 868 | i2c_set_clientdata(i2c, aic32x4); | ||
| 869 | |||
| 870 | return 0; | ||
| 706 | } | 871 | } |
| 707 | 872 | ||
| 708 | static int aic32x4_i2c_remove(struct i2c_client *client) | 873 | static int aic32x4_i2c_remove(struct i2c_client *client) |
| 709 | { | 874 | { |
| 875 | struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client); | ||
| 876 | |||
| 877 | aic32x4_disable_regulators(aic32x4); | ||
| 878 | |||
| 710 | snd_soc_unregister_codec(&client->dev); | 879 | snd_soc_unregister_codec(&client->dev); |
| 711 | return 0; | 880 | return 0; |
| 712 | } | 881 | } |
| @@ -717,10 +886,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = { | |||
| 717 | }; | 886 | }; |
| 718 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | 887 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); |
| 719 | 888 | ||
| 889 | static const struct of_device_id aic32x4_of_id[] = { | ||
| 890 | { .compatible = "ti,tlv320aic32x4", }, | ||
| 891 | { /* senitel */ } | ||
| 892 | }; | ||
| 893 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
| 894 | |||
| 720 | static struct i2c_driver aic32x4_i2c_driver = { | 895 | static struct i2c_driver aic32x4_i2c_driver = { |
| 721 | .driver = { | 896 | .driver = { |
| 722 | .name = "tlv320aic32x4", | 897 | .name = "tlv320aic32x4", |
| 723 | .owner = THIS_MODULE, | 898 | .owner = THIS_MODULE, |
| 899 | .of_match_table = aic32x4_of_id, | ||
| 724 | }, | 900 | }, |
| 725 | .probe = aic32x4_i2c_probe, | 901 | .probe = aic32x4_i2c_probe, |
| 726 | .remove = aic32x4_i2c_remove, | 902 | .remove = aic32x4_i2c_remove, |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4f358393d6d6..793516146670 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
| @@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, | |||
| 461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) | 461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) |
| 462 | return 0; | 462 | return 0; |
| 463 | /* Do not allow changes while stream is running*/ | 463 | /* Do not allow changes while stream is running*/ |
| 464 | if (codec->active) | 464 | if (snd_soc_codec_is_active(codec)) |
| 465 | return -EPERM; | 465 | return -EPERM; |
| 466 | 466 | ||
| 467 | if (ucontrol->value.integer.value[0] < 0 || | 467 | if (ucontrol->value.integer.value[0] < 0 || |
| @@ -478,9 +478,7 @@ static const char *dac33_fifo_mode_texts[] = { | |||
| 478 | "Bypass", "Mode 1", "Mode 7" | 478 | "Bypass", "Mode 1", "Mode 7" |
| 479 | }; | 479 | }; |
| 480 | 480 | ||
| 481 | static const struct soc_enum dac33_fifo_mode_enum = | 481 | static SOC_ENUM_SINGLE_EXT_DECL(dac33_fifo_mode_enum, dac33_fifo_mode_texts); |
| 482 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dac33_fifo_mode_texts), | ||
| 483 | dac33_fifo_mode_texts); | ||
| 484 | 482 | ||
| 485 | /* L/R Line Output Gain */ | 483 | /* L/R Line Output Gain */ |
| 486 | static const char *lr_lineout_gain_texts[] = { | 484 | static const char *lr_lineout_gain_texts[] = { |
| @@ -488,15 +486,13 @@ static const char *lr_lineout_gain_texts[] = { | |||
| 488 | "Line 0dB DAC 12dB", "Line 6dB DAC 18dB", | 486 | "Line 0dB DAC 12dB", "Line 6dB DAC 18dB", |
| 489 | }; | 487 | }; |
| 490 | 488 | ||
| 491 | static const struct soc_enum l_lineout_gain_enum = | 489 | static SOC_ENUM_SINGLE_DECL(l_lineout_gain_enum, |
| 492 | SOC_ENUM_SINGLE(DAC33_LDAC_PWR_CTRL, 0, | 490 | DAC33_LDAC_PWR_CTRL, 0, |
| 493 | ARRAY_SIZE(lr_lineout_gain_texts), | 491 | lr_lineout_gain_texts); |
| 494 | lr_lineout_gain_texts); | ||
| 495 | 492 | ||
| 496 | static const struct soc_enum r_lineout_gain_enum = | 493 | static SOC_ENUM_SINGLE_DECL(r_lineout_gain_enum, |
| 497 | SOC_ENUM_SINGLE(DAC33_RDAC_PWR_CTRL, 0, | 494 | DAC33_RDAC_PWR_CTRL, 0, |
| 498 | ARRAY_SIZE(lr_lineout_gain_texts), | 495 | lr_lineout_gain_texts); |
| 499 | lr_lineout_gain_texts); | ||
| 500 | 496 | ||
| 501 | /* | 497 | /* |
| 502 | * DACL/R digital volume control: | 498 | * DACL/R digital volume control: |
| @@ -534,18 +530,16 @@ static const struct snd_kcontrol_new dac33_dapm_abypassr_control = | |||
| 534 | /* LOP L/R invert selection */ | 530 | /* LOP L/R invert selection */ |
| 535 | static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"}; | 531 | static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"}; |
| 536 | 532 | ||
| 537 | static const struct soc_enum dac33_left_lom_enum = | 533 | static SOC_ENUM_SINGLE_DECL(dac33_left_lom_enum, |
| 538 | SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3, | 534 | DAC33_OUT_AMP_CTRL, 3, |
| 539 | ARRAY_SIZE(dac33_lr_lom_texts), | 535 | dac33_lr_lom_texts); |
| 540 | dac33_lr_lom_texts); | ||
| 541 | 536 | ||
| 542 | static const struct snd_kcontrol_new dac33_dapm_left_lom_control = | 537 | static const struct snd_kcontrol_new dac33_dapm_left_lom_control = |
| 543 | SOC_DAPM_ENUM("Route", dac33_left_lom_enum); | 538 | SOC_DAPM_ENUM("Route", dac33_left_lom_enum); |
| 544 | 539 | ||
| 545 | static const struct soc_enum dac33_right_lom_enum = | 540 | static SOC_ENUM_SINGLE_DECL(dac33_right_lom_enum, |
| 546 | SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2, | 541 | DAC33_OUT_AMP_CTRL, 2, |
| 547 | ARRAY_SIZE(dac33_lr_lom_texts), | 542 | dac33_lr_lom_texts); |
| 548 | dac33_lr_lom_texts); | ||
| 549 | 543 | ||
| 550 | static const struct snd_kcontrol_new dac33_dapm_right_lom_control = | 544 | static const struct snd_kcontrol_new dac33_dapm_right_lom_control = |
| 551 | SOC_DAPM_ENUM("Route", dac33_right_lom_enum); | 545 | SOC_DAPM_ENUM("Route", dac33_right_lom_enum); |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 00665ada23e2..975e0f760ac1 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
| @@ -415,10 +415,9 @@ static const struct snd_kcontrol_new twl4030_dapm_carkitr_controls[] = { | |||
| 415 | static const char *twl4030_handsfreel_texts[] = | 415 | static const char *twl4030_handsfreel_texts[] = |
| 416 | {"Voice", "AudioL1", "AudioL2", "AudioR2"}; | 416 | {"Voice", "AudioL1", "AudioL2", "AudioR2"}; |
| 417 | 417 | ||
| 418 | static const struct soc_enum twl4030_handsfreel_enum = | 418 | static SOC_ENUM_SINGLE_DECL(twl4030_handsfreel_enum, |
| 419 | SOC_ENUM_SINGLE(TWL4030_REG_HFL_CTL, 0, | 419 | TWL4030_REG_HFL_CTL, 0, |
| 420 | ARRAY_SIZE(twl4030_handsfreel_texts), | 420 | twl4030_handsfreel_texts); |
| 421 | twl4030_handsfreel_texts); | ||
| 422 | 421 | ||
| 423 | static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = | 422 | static const struct snd_kcontrol_new twl4030_dapm_handsfreel_control = |
| 424 | SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); | 423 | SOC_DAPM_ENUM("Route", twl4030_handsfreel_enum); |
| @@ -431,10 +430,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreelmute_control = | |||
| 431 | static const char *twl4030_handsfreer_texts[] = | 430 | static const char *twl4030_handsfreer_texts[] = |
| 432 | {"Voice", "AudioR1", "AudioR2", "AudioL2"}; | 431 | {"Voice", "AudioR1", "AudioR2", "AudioL2"}; |
| 433 | 432 | ||
| 434 | static const struct soc_enum twl4030_handsfreer_enum = | 433 | static SOC_ENUM_SINGLE_DECL(twl4030_handsfreer_enum, |
| 435 | SOC_ENUM_SINGLE(TWL4030_REG_HFR_CTL, 0, | 434 | TWL4030_REG_HFR_CTL, 0, |
| 436 | ARRAY_SIZE(twl4030_handsfreer_texts), | 435 | twl4030_handsfreer_texts); |
| 437 | twl4030_handsfreer_texts); | ||
| 438 | 436 | ||
| 439 | static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = | 437 | static const struct snd_kcontrol_new twl4030_dapm_handsfreer_control = |
| 440 | SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); | 438 | SOC_DAPM_ENUM("Route", twl4030_handsfreer_enum); |
| @@ -448,10 +446,9 @@ static const struct snd_kcontrol_new twl4030_dapm_handsfreermute_control = | |||
| 448 | static const char *twl4030_vibra_texts[] = | 446 | static const char *twl4030_vibra_texts[] = |
| 449 | {"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; | 447 | {"AudioL1", "AudioR1", "AudioL2", "AudioR2"}; |
| 450 | 448 | ||
| 451 | static const struct soc_enum twl4030_vibra_enum = | 449 | static SOC_ENUM_SINGLE_DECL(twl4030_vibra_enum, |
| 452 | SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 2, | 450 | TWL4030_REG_VIBRA_CTL, 2, |
| 453 | ARRAY_SIZE(twl4030_vibra_texts), | 451 | twl4030_vibra_texts); |
| 454 | twl4030_vibra_texts); | ||
| 455 | 452 | ||
| 456 | static const struct snd_kcontrol_new twl4030_dapm_vibra_control = | 453 | static const struct snd_kcontrol_new twl4030_dapm_vibra_control = |
| 457 | SOC_DAPM_ENUM("Route", twl4030_vibra_enum); | 454 | SOC_DAPM_ENUM("Route", twl4030_vibra_enum); |
| @@ -460,10 +457,9 @@ SOC_DAPM_ENUM("Route", twl4030_vibra_enum); | |||
| 460 | static const char *twl4030_vibrapath_texts[] = | 457 | static const char *twl4030_vibrapath_texts[] = |
| 461 | {"Local vibrator", "Audio"}; | 458 | {"Local vibrator", "Audio"}; |
| 462 | 459 | ||
| 463 | static const struct soc_enum twl4030_vibrapath_enum = | 460 | static SOC_ENUM_SINGLE_DECL(twl4030_vibrapath_enum, |
| 464 | SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 4, | 461 | TWL4030_REG_VIBRA_CTL, 4, |
| 465 | ARRAY_SIZE(twl4030_vibrapath_texts), | 462 | twl4030_vibrapath_texts); |
| 466 | twl4030_vibrapath_texts); | ||
| 467 | 463 | ||
| 468 | static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control = | 464 | static const struct snd_kcontrol_new twl4030_dapm_vibrapath_control = |
| 469 | SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); | 465 | SOC_DAPM_ENUM("Route", twl4030_vibrapath_enum); |
| @@ -490,10 +486,9 @@ static const struct snd_kcontrol_new twl4030_dapm_analogrmic_controls[] = { | |||
| 490 | static const char *twl4030_micpathtx1_texts[] = | 486 | static const char *twl4030_micpathtx1_texts[] = |
| 491 | {"Analog", "Digimic0"}; | 487 | {"Analog", "Digimic0"}; |
| 492 | 488 | ||
| 493 | static const struct soc_enum twl4030_micpathtx1_enum = | 489 | static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx1_enum, |
| 494 | SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 0, | 490 | TWL4030_REG_ADCMICSEL, 0, |
| 495 | ARRAY_SIZE(twl4030_micpathtx1_texts), | 491 | twl4030_micpathtx1_texts); |
| 496 | twl4030_micpathtx1_texts); | ||
| 497 | 492 | ||
| 498 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control = | 493 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx1_control = |
| 499 | SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); | 494 | SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); |
| @@ -502,10 +497,9 @@ SOC_DAPM_ENUM("Route", twl4030_micpathtx1_enum); | |||
| 502 | static const char *twl4030_micpathtx2_texts[] = | 497 | static const char *twl4030_micpathtx2_texts[] = |
| 503 | {"Analog", "Digimic1"}; | 498 | {"Analog", "Digimic1"}; |
| 504 | 499 | ||
| 505 | static const struct soc_enum twl4030_micpathtx2_enum = | 500 | static SOC_ENUM_SINGLE_DECL(twl4030_micpathtx2_enum, |
| 506 | SOC_ENUM_SINGLE(TWL4030_REG_ADCMICSEL, 2, | 501 | TWL4030_REG_ADCMICSEL, 2, |
| 507 | ARRAY_SIZE(twl4030_micpathtx2_texts), | 502 | twl4030_micpathtx2_texts); |
| 508 | twl4030_micpathtx2_texts); | ||
| 509 | 503 | ||
| 510 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = | 504 | static const struct snd_kcontrol_new twl4030_dapm_micpathtx2_control = |
| 511 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); | 505 | SOC_DAPM_ENUM("Route", twl4030_micpathtx2_enum); |
| @@ -955,19 +949,15 @@ static const char *twl4030_op_modes_texts[] = { | |||
| 955 | "Option 2 (voice/audio)", "Option 1 (audio)" | 949 | "Option 2 (voice/audio)", "Option 1 (audio)" |
| 956 | }; | 950 | }; |
| 957 | 951 | ||
| 958 | static const struct soc_enum twl4030_op_modes_enum = | 952 | static SOC_ENUM_SINGLE_DECL(twl4030_op_modes_enum, |
| 959 | SOC_ENUM_SINGLE(TWL4030_REG_CODEC_MODE, 0, | 953 | TWL4030_REG_CODEC_MODE, 0, |
| 960 | ARRAY_SIZE(twl4030_op_modes_texts), | 954 | twl4030_op_modes_texts); |
| 961 | twl4030_op_modes_texts); | ||
| 962 | 955 | ||
| 963 | static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | 956 | static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, |
| 964 | struct snd_ctl_elem_value *ucontrol) | 957 | struct snd_ctl_elem_value *ucontrol) |
| 965 | { | 958 | { |
| 966 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 959 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 967 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 960 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
| 968 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
| 969 | unsigned short val; | ||
| 970 | unsigned short mask; | ||
| 971 | 961 | ||
| 972 | if (twl4030->configured) { | 962 | if (twl4030->configured) { |
| 973 | dev_err(codec->dev, | 963 | dev_err(codec->dev, |
| @@ -975,19 +965,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | |||
| 975 | return -EBUSY; | 965 | return -EBUSY; |
| 976 | } | 966 | } |
| 977 | 967 | ||
| 978 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 968 | return snd_soc_put_enum_double(kcontrol, ucontrol); |
| 979 | return -EINVAL; | ||
| 980 | |||
| 981 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | ||
| 982 | mask = e->mask << e->shift_l; | ||
| 983 | if (e->shift_l != e->shift_r) { | ||
| 984 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
| 985 | return -EINVAL; | ||
| 986 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
| 987 | mask |= e->mask << e->shift_r; | ||
| 988 | } | ||
| 989 | |||
| 990 | return snd_soc_update_bits(codec, e->reg, mask, val); | ||
| 991 | } | 969 | } |
| 992 | 970 | ||
| 993 | /* | 971 | /* |
| @@ -1044,10 +1022,9 @@ static const char *twl4030_avadc_clk_priority_texts[] = { | |||
| 1044 | "Voice high priority", "HiFi high priority" | 1022 | "Voice high priority", "HiFi high priority" |
| 1045 | }; | 1023 | }; |
| 1046 | 1024 | ||
| 1047 | static const struct soc_enum twl4030_avadc_clk_priority_enum = | 1025 | static SOC_ENUM_SINGLE_DECL(twl4030_avadc_clk_priority_enum, |
| 1048 | SOC_ENUM_SINGLE(TWL4030_REG_AVADC_CTL, 2, | 1026 | TWL4030_REG_AVADC_CTL, 2, |
| 1049 | ARRAY_SIZE(twl4030_avadc_clk_priority_texts), | 1027 | twl4030_avadc_clk_priority_texts); |
| 1050 | twl4030_avadc_clk_priority_texts); | ||
| 1051 | 1028 | ||
| 1052 | static const char *twl4030_rampdelay_texts[] = { | 1029 | static const char *twl4030_rampdelay_texts[] = { |
| 1053 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", | 1030 | "27/20/14 ms", "55/40/27 ms", "109/81/55 ms", "218/161/109 ms", |
| @@ -1055,40 +1032,36 @@ static const char *twl4030_rampdelay_texts[] = { | |||
| 1055 | "3495/2581/1748 ms" | 1032 | "3495/2581/1748 ms" |
| 1056 | }; | 1033 | }; |
| 1057 | 1034 | ||
| 1058 | static const struct soc_enum twl4030_rampdelay_enum = | 1035 | static SOC_ENUM_SINGLE_DECL(twl4030_rampdelay_enum, |
| 1059 | SOC_ENUM_SINGLE(TWL4030_REG_HS_POPN_SET, 2, | 1036 | TWL4030_REG_HS_POPN_SET, 2, |
| 1060 | ARRAY_SIZE(twl4030_rampdelay_texts), | 1037 | twl4030_rampdelay_texts); |
| 1061 | twl4030_rampdelay_texts); | ||
| 1062 | 1038 | ||
| 1063 | /* Vibra H-bridge direction mode */ | 1039 | /* Vibra H-bridge direction mode */ |
| 1064 | static const char *twl4030_vibradirmode_texts[] = { | 1040 | static const char *twl4030_vibradirmode_texts[] = { |
| 1065 | "Vibra H-bridge direction", "Audio data MSB", | 1041 | "Vibra H-bridge direction", "Audio data MSB", |
| 1066 | }; | 1042 | }; |
| 1067 | 1043 | ||
| 1068 | static const struct soc_enum twl4030_vibradirmode_enum = | 1044 | static SOC_ENUM_SINGLE_DECL(twl4030_vibradirmode_enum, |
| 1069 | SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 5, | 1045 | TWL4030_REG_VIBRA_CTL, 5, |
| 1070 | ARRAY_SIZE(twl4030_vibradirmode_texts), | 1046 | twl4030_vibradirmode_texts); |
| 1071 | twl4030_vibradirmode_texts); | ||
| 1072 | 1047 | ||
| 1073 | /* Vibra H-bridge direction */ | 1048 | /* Vibra H-bridge direction */ |
| 1074 | static const char *twl4030_vibradir_texts[] = { | 1049 | static const char *twl4030_vibradir_texts[] = { |
| 1075 | "Positive polarity", "Negative polarity", | 1050 | "Positive polarity", "Negative polarity", |
| 1076 | }; | 1051 | }; |
| 1077 | 1052 | ||
| 1078 | static const struct soc_enum twl4030_vibradir_enum = | 1053 | static SOC_ENUM_SINGLE_DECL(twl4030_vibradir_enum, |
| 1079 | SOC_ENUM_SINGLE(TWL4030_REG_VIBRA_CTL, 1, | 1054 | TWL4030_REG_VIBRA_CTL, 1, |
| 1080 | ARRAY_SIZE(twl4030_vibradir_texts), | 1055 | twl4030_vibradir_texts); |
| 1081 | twl4030_vibradir_texts); | ||
| 1082 | 1056 | ||
| 1083 | /* Digimic Left and right swapping */ | 1057 | /* Digimic Left and right swapping */ |
| 1084 | static const char *twl4030_digimicswap_texts[] = { | 1058 | static const char *twl4030_digimicswap_texts[] = { |
| 1085 | "Not swapped", "Swapped", | 1059 | "Not swapped", "Swapped", |
| 1086 | }; | 1060 | }; |
| 1087 | 1061 | ||
| 1088 | static const struct soc_enum twl4030_digimicswap_enum = | 1062 | static SOC_ENUM_SINGLE_DECL(twl4030_digimicswap_enum, |
| 1089 | SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0, | 1063 | TWL4030_REG_MISC_SET_1, 0, |
| 1090 | ARRAY_SIZE(twl4030_digimicswap_texts), | 1064 | twl4030_digimicswap_texts); |
| 1091 | twl4030_digimicswap_texts); | ||
| 1092 | 1065 | ||
| 1093 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { | 1066 | static const struct snd_kcontrol_new twl4030_snd_controls[] = { |
| 1094 | /* Codec operation mode control */ | 1067 | /* Codec operation mode control */ |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 0afe8bef6765..bd3a20647fdf 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
| @@ -81,7 +81,7 @@ struct twl6040_data { | |||
| 81 | }; | 81 | }; |
| 82 | 82 | ||
| 83 | /* set of rates for each pll: low-power and high-performance */ | 83 | /* set of rates for each pll: low-power and high-performance */ |
| 84 | static unsigned int lp_rates[] = { | 84 | static const unsigned int lp_rates[] = { |
| 85 | 8000, | 85 | 8000, |
| 86 | 11250, | 86 | 11250, |
| 87 | 16000, | 87 | 16000, |
| @@ -93,7 +93,7 @@ static unsigned int lp_rates[] = { | |||
| 93 | 96000, | 93 | 96000, |
| 94 | }; | 94 | }; |
| 95 | 95 | ||
| 96 | static unsigned int hp_rates[] = { | 96 | static const unsigned int hp_rates[] = { |
| 97 | 8000, | 97 | 8000, |
| 98 | 16000, | 98 | 16000, |
| 99 | 32000, | 99 | 32000, |
| @@ -101,7 +101,7 @@ static unsigned int hp_rates[] = { | |||
| 101 | 96000, | 101 | 96000, |
| 102 | }; | 102 | }; |
| 103 | 103 | ||
| 104 | static struct snd_pcm_hw_constraint_list sysclk_constraints[] = { | 104 | static const struct snd_pcm_hw_constraint_list sysclk_constraints[] = { |
| 105 | { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, }, | 105 | { .count = ARRAY_SIZE(lp_rates), .list = lp_rates, }, |
| 106 | { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, | 106 | { .count = ARRAY_SIZE(hp_rates), .list = hp_rates, }, |
| 107 | }; | 107 | }; |
| @@ -392,8 +392,10 @@ static const char *twl6040_amicr_texts[] = | |||
| 392 | {"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"}; | 392 | {"Headset Mic", "Sub Mic", "Aux/FM Right", "Off"}; |
| 393 | 393 | ||
| 394 | static const struct soc_enum twl6040_enum[] = { | 394 | static const struct soc_enum twl6040_enum[] = { |
| 395 | SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, 4, twl6040_amicl_texts), | 395 | SOC_ENUM_SINGLE(TWL6040_REG_MICLCTL, 3, |
| 396 | SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, 4, twl6040_amicr_texts), | 396 | ARRAY_SIZE(twl6040_amicl_texts), twl6040_amicl_texts), |
| 397 | SOC_ENUM_SINGLE(TWL6040_REG_MICRCTL, 3, | ||
| 398 | ARRAY_SIZE(twl6040_amicr_texts), twl6040_amicr_texts), | ||
| 397 | }; | 399 | }; |
| 398 | 400 | ||
| 399 | static const char *twl6040_hs_texts[] = { | 401 | static const char *twl6040_hs_texts[] = { |
| @@ -476,9 +478,8 @@ static const char *twl6040_power_mode_texts[] = { | |||
| 476 | "Low-Power", "High-Performance", | 478 | "Low-Power", "High-Performance", |
| 477 | }; | 479 | }; |
| 478 | 480 | ||
| 479 | static const struct soc_enum twl6040_power_mode_enum = | 481 | static SOC_ENUM_SINGLE_EXT_DECL(twl6040_power_mode_enum, |
| 480 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(twl6040_power_mode_texts), | 482 | twl6040_power_mode_texts); |
| 481 | twl6040_power_mode_texts); | ||
| 482 | 483 | ||
| 483 | static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, | 484 | static int twl6040_headset_power_get_enum(struct snd_kcontrol *kcontrol, |
| 484 | struct snd_ctl_elem_value *ucontrol) | 485 | struct snd_ctl_elem_value *ucontrol) |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 726df6d43c2b..4dadaa8ad46c 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
| @@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | |||
| 108 | /* the interpolator & decimator regs must only be written when the | 108 | /* the interpolator & decimator regs must only be written when the |
| 109 | * codec DAI is active. | 109 | * codec DAI is active. |
| 110 | */ | 110 | */ |
| 111 | if (!codec->active && (reg >= UDA1380_MVOL)) | 111 | if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL)) |
| 112 | return 0; | 112 | return 0; |
| 113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | 113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); |
| 114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | 114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { |
| @@ -237,25 +237,27 @@ static const char *uda1380_os_setting[] = { | |||
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | static const struct soc_enum uda1380_deemp_enum[] = { | 239 | static const struct soc_enum uda1380_deemp_enum[] = { |
| 240 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, 5, uda1380_deemp), | 240 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 8, ARRAY_SIZE(uda1380_deemp), |
| 241 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, 5, uda1380_deemp), | 241 | uda1380_deemp), |
| 242 | SOC_ENUM_SINGLE(UDA1380_DEEMP, 0, ARRAY_SIZE(uda1380_deemp), | ||
| 243 | uda1380_deemp), | ||
| 242 | }; | 244 | }; |
| 243 | static const struct soc_enum uda1380_input_sel_enum = | 245 | static SOC_ENUM_SINGLE_DECL(uda1380_input_sel_enum, |
| 244 | SOC_ENUM_SINGLE(UDA1380_ADC, 2, 4, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ | 246 | UDA1380_ADC, 2, uda1380_input_sel); /* SEL_MIC, SEL_LNA */ |
| 245 | static const struct soc_enum uda1380_output_sel_enum = | 247 | static SOC_ENUM_SINGLE_DECL(uda1380_output_sel_enum, |
| 246 | SOC_ENUM_SINGLE(UDA1380_PM, 7, 2, uda1380_output_sel); /* R02_EN_AVC */ | 248 | UDA1380_PM, 7, uda1380_output_sel); /* R02_EN_AVC */ |
| 247 | static const struct soc_enum uda1380_spf_enum = | 249 | static SOC_ENUM_SINGLE_DECL(uda1380_spf_enum, |
| 248 | SOC_ENUM_SINGLE(UDA1380_MODE, 14, 4, uda1380_spf_mode); /* M */ | 250 | UDA1380_MODE, 14, uda1380_spf_mode); /* M */ |
| 249 | static const struct soc_enum uda1380_capture_sel_enum = | 251 | static SOC_ENUM_SINGLE_DECL(uda1380_capture_sel_enum, |
| 250 | SOC_ENUM_SINGLE(UDA1380_IFACE, 6, 2, uda1380_capture_sel); /* SEL_SOURCE */ | 252 | UDA1380_IFACE, 6, uda1380_capture_sel); /* SEL_SOURCE */ |
| 251 | static const struct soc_enum uda1380_sel_ns_enum = | 253 | static SOC_ENUM_SINGLE_DECL(uda1380_sel_ns_enum, |
| 252 | SOC_ENUM_SINGLE(UDA1380_MIXER, 14, 2, uda1380_sel_ns); /* SEL_NS */ | 254 | UDA1380_MIXER, 14, uda1380_sel_ns); /* SEL_NS */ |
| 253 | static const struct soc_enum uda1380_mix_enum = | 255 | static SOC_ENUM_SINGLE_DECL(uda1380_mix_enum, |
| 254 | SOC_ENUM_SINGLE(UDA1380_MIXER, 12, 4, uda1380_mix_control); /* MIX, MIX_POS */ | 256 | UDA1380_MIXER, 12, uda1380_mix_control); /* MIX, MIX_POS */ |
| 255 | static const struct soc_enum uda1380_sdet_enum = | 257 | static SOC_ENUM_SINGLE_DECL(uda1380_sdet_enum, |
| 256 | SOC_ENUM_SINGLE(UDA1380_MIXER, 4, 4, uda1380_sdet_setting); /* SD_VALUE */ | 258 | UDA1380_MIXER, 4, uda1380_sdet_setting); /* SD_VALUE */ |
| 257 | static const struct soc_enum uda1380_os_enum = | 259 | static SOC_ENUM_SINGLE_DECL(uda1380_os_enum, |
| 258 | SOC_ENUM_SINGLE(UDA1380_MIXER, 0, 3, uda1380_os_setting); /* OS */ | 260 | UDA1380_MIXER, 0, uda1380_os_setting); /* OS */ |
| 259 | 261 | ||
| 260 | /* | 262 | /* |
| 261 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) | 263 | * from -48 dB in 1.5 dB steps (mute instead of -49.5 dB) |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index b7ab2ef567c8..6be5f80b65f1 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
| @@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, | |||
| 197 | return 0; | 197 | return 0; |
| 198 | 198 | ||
| 199 | /* Do not allow changes while stream is running */ | 199 | /* Do not allow changes while stream is running */ |
| 200 | if (codec->active) | 200 | if (snd_soc_codec_is_active(codec)) |
| 201 | return -EPERM; | 201 | return -EPERM; |
| 202 | 202 | ||
| 203 | if (ucontrol->value.integer.value[0] < 0 || | 203 | if (ucontrol->value.integer.value[0] < 0 || |
| @@ -209,8 +209,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, | |||
| 209 | return 1; | 209 | return 1; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | static const struct soc_enum wl1273_enum = | 212 | static SOC_ENUM_SINGLE_EXT_DECL(wl1273_enum, wl1273_audio_route); |
| 213 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_route), wl1273_audio_route); | ||
| 214 | 213 | ||
| 215 | static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, | 214 | static int snd_wl1273_fm_audio_get(struct snd_kcontrol *kcontrol, |
| 216 | struct snd_ctl_elem_value *ucontrol) | 215 | struct snd_ctl_elem_value *ucontrol) |
| @@ -247,9 +246,7 @@ static int snd_wl1273_fm_audio_put(struct snd_kcontrol *kcontrol, | |||
| 247 | 246 | ||
| 248 | static const char * const wl1273_audio_strings[] = { "Digital", "Analog" }; | 247 | static const char * const wl1273_audio_strings[] = { "Digital", "Analog" }; |
| 249 | 248 | ||
| 250 | static const struct soc_enum wl1273_audio_enum = | 249 | static SOC_ENUM_SINGLE_EXT_DECL(wl1273_audio_enum, wl1273_audio_strings); |
| 251 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wl1273_audio_strings), | ||
| 252 | wl1273_audio_strings); | ||
| 253 | 250 | ||
| 254 | static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, | 251 | static int snd_wl1273_fm_volume_get(struct snd_kcontrol *kcontrol, |
| 255 | struct snd_ctl_elem_value *ucontrol) | 252 | struct snd_ctl_elem_value *ucontrol) |
diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 57ba315d0c84..1e0a083d8345 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c | |||
| @@ -1113,11 +1113,10 @@ static const char *wm2200_rxanc_input_sel_texts[] = { | |||
| 1113 | "None", "IN1", "IN2", "IN3", | 1113 | "None", "IN1", "IN2", "IN3", |
| 1114 | }; | 1114 | }; |
| 1115 | 1115 | ||
| 1116 | static const struct soc_enum wm2200_rxanc_input_sel = | 1116 | static SOC_ENUM_SINGLE_DECL(wm2200_rxanc_input_sel, |
| 1117 | SOC_ENUM_SINGLE(WM2200_RXANC_SRC, | 1117 | WM2200_RXANC_SRC, |
| 1118 | WM2200_IN_RXANC_SEL_SHIFT, | 1118 | WM2200_IN_RXANC_SEL_SHIFT, |
| 1119 | ARRAY_SIZE(wm2200_rxanc_input_sel_texts), | 1119 | wm2200_rxanc_input_sel_texts); |
| 1120 | wm2200_rxanc_input_sel_texts); | ||
| 1121 | 1120 | ||
| 1122 | static const struct snd_kcontrol_new wm2200_snd_controls[] = { | 1121 | static const struct snd_kcontrol_new wm2200_snd_controls[] = { |
| 1123 | SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, | 1122 | SOC_SINGLE("IN1 High Performance Switch", WM2200_IN1L_CONTROL, |
| @@ -1288,11 +1287,10 @@ static const char *wm2200_aec_loopback_texts[] = { | |||
| 1288 | "OUT1L", "OUT1R", "OUT2L", "OUT2R", | 1287 | "OUT1L", "OUT1R", "OUT2L", "OUT2R", |
| 1289 | }; | 1288 | }; |
| 1290 | 1289 | ||
| 1291 | static const struct soc_enum wm2200_aec_loopback = | 1290 | static SOC_ENUM_SINGLE_DECL(wm2200_aec_loopback, |
| 1292 | SOC_ENUM_SINGLE(WM2200_DAC_AEC_CONTROL_1, | 1291 | WM2200_DAC_AEC_CONTROL_1, |
| 1293 | WM2200_AEC_LOOPBACK_SRC_SHIFT, | 1292 | WM2200_AEC_LOOPBACK_SRC_SHIFT, |
| 1294 | ARRAY_SIZE(wm2200_aec_loopback_texts), | 1293 | wm2200_aec_loopback_texts); |
| 1295 | wm2200_aec_loopback_texts); | ||
| 1296 | 1294 | ||
| 1297 | static const struct snd_kcontrol_new wm2200_aec_loopback_mux = | 1295 | static const struct snd_kcontrol_new wm2200_aec_loopback_mux = |
| 1298 | SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback); | 1296 | SOC_DAPM_ENUM("AEC Loopback", wm2200_aec_loopback); |
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4e3e31aaf509..d3fa65fd9e85 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
| @@ -506,21 +506,21 @@ static const char *wm5100_lhpf_mode_text[] = { | |||
| 506 | "Low-pass", "High-pass" | 506 | "Low-pass", "High-pass" |
| 507 | }; | 507 | }; |
| 508 | 508 | ||
| 509 | static const struct soc_enum wm5100_lhpf1_mode = | 509 | static SOC_ENUM_SINGLE_DECL(wm5100_lhpf1_mode, |
| 510 | SOC_ENUM_SINGLE(WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, 2, | 510 | WM5100_HPLPF1_1, WM5100_LHPF1_MODE_SHIFT, |
| 511 | wm5100_lhpf_mode_text); | 511 | wm5100_lhpf_mode_text); |
| 512 | 512 | ||
| 513 | static const struct soc_enum wm5100_lhpf2_mode = | 513 | static SOC_ENUM_SINGLE_DECL(wm5100_lhpf2_mode, |
| 514 | SOC_ENUM_SINGLE(WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, 2, | 514 | WM5100_HPLPF2_1, WM5100_LHPF2_MODE_SHIFT, |
| 515 | wm5100_lhpf_mode_text); | 515 | wm5100_lhpf_mode_text); |
| 516 | 516 | ||
| 517 | static const struct soc_enum wm5100_lhpf3_mode = | 517 | static SOC_ENUM_SINGLE_DECL(wm5100_lhpf3_mode, |
| 518 | SOC_ENUM_SINGLE(WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, 2, | 518 | WM5100_HPLPF3_1, WM5100_LHPF3_MODE_SHIFT, |
| 519 | wm5100_lhpf_mode_text); | 519 | wm5100_lhpf_mode_text); |
| 520 | 520 | ||
| 521 | static const struct soc_enum wm5100_lhpf4_mode = | 521 | static SOC_ENUM_SINGLE_DECL(wm5100_lhpf4_mode, |
| 522 | SOC_ENUM_SINGLE(WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, 2, | 522 | WM5100_HPLPF4_1, WM5100_LHPF4_MODE_SHIFT, |
| 523 | wm5100_lhpf_mode_text); | 523 | wm5100_lhpf_mode_text); |
| 524 | 524 | ||
| 525 | static const struct snd_kcontrol_new wm5100_snd_controls[] = { | 525 | static const struct snd_kcontrol_new wm5100_snd_controls[] = { |
| 526 | SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL, | 526 | SOC_SINGLE("IN1 High Performance Switch", WM5100_IN1L_CONTROL, |
| @@ -2100,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100) | |||
| 2100 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 2100 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
| 2101 | { | 2101 | { |
| 2102 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | 2102 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); |
| 2103 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 2103 | 2104 | ||
| 2104 | if (jack) { | 2105 | if (jack) { |
| 2105 | wm5100->jack = jack; | 2106 | wm5100->jack = jack; |
| @@ -2117,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
| 2117 | WM5100_ACCDET_RATE_MASK); | 2118 | WM5100_ACCDET_RATE_MASK); |
| 2118 | 2119 | ||
| 2119 | /* We need the charge pump to power MICBIAS */ | 2120 | /* We need the charge pump to power MICBIAS */ |
| 2120 | snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2"); | 2121 | snd_soc_dapm_mutex_lock(dapm); |
| 2121 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 2122 | |
| 2122 | snd_soc_dapm_sync(&codec->dapm); | 2123 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2"); |
| 2124 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); | ||
| 2125 | |||
| 2126 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 2127 | |||
| 2128 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 2123 | 2129 | ||
| 2124 | /* We start off just enabling microphone detection - even a | 2130 | /* We start off just enabling microphone detection - even a |
| 2125 | * plain headphone will trigger detection. | 2131 | * plain headphone will trigger detection. |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index ce9c8e14d4bd..34109050ceed 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
| @@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
| 582 | { | 582 | { |
| 583 | struct snd_soc_codec *codec = w->codec; | 583 | struct snd_soc_codec *codec = w->codec; |
| 584 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 584 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
| 585 | struct regmap *regmap = codec->control_data; | 585 | struct regmap *regmap = arizona->regmap; |
| 586 | const struct reg_default *patch = NULL; | 586 | const struct reg_default *patch = NULL; |
| 587 | int i, patch_size; | 587 | int i, patch_size; |
| 588 | 588 | ||
| @@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = { | |||
| 622 | 622 | ||
| 623 | static const struct soc_enum wm5102_hpout_osr[] = { | 623 | static const struct soc_enum wm5102_hpout_osr[] = { |
| 624 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, | 624 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, |
| 625 | ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, | 625 | ARIZONA_OUT1_OSR_SHIFT, 0x7, |
| 626 | ARRAY_SIZE(wm5102_osr_text), | ||
| 626 | wm5102_osr_text, wm5102_osr_val), | 627 | wm5102_osr_text, wm5102_osr_val), |
| 627 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, | 628 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, |
| 628 | ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, | 629 | ARIZONA_OUT2_OSR_SHIFT, 0x7, |
| 630 | ARRAY_SIZE(wm5102_osr_text), | ||
| 629 | wm5102_osr_text, wm5102_osr_val), | 631 | wm5102_osr_text, wm5102_osr_val), |
| 630 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, | 632 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, |
| 631 | ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, | 633 | ARIZONA_OUT3_OSR_SHIFT, 0x7, |
| 634 | ARRAY_SIZE(wm5102_osr_text), | ||
| 632 | wm5102_osr_text, wm5102_osr_val), | 635 | wm5102_osr_text, wm5102_osr_val), |
| 633 | }; | 636 | }; |
| 634 | 637 | ||
| @@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
| 685 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 688 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
| 686 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 689 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
| 687 | 690 | ||
| 688 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 691 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
| 689 | ARIZONA_EQ1_ENA_MASK), | 692 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
| 690 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
| 691 | ARIZONA_EQ2_ENA_MASK), | ||
| 692 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
| 693 | ARIZONA_EQ3_ENA_MASK), | ||
| 694 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
| 695 | ARIZONA_EQ4_ENA_MASK), | ||
| 696 | |||
| 697 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 693 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
| 698 | 24, 0, eq_tlv), | 694 | 24, 0, eq_tlv), |
| 699 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 695 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
| @@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
| 705 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 701 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
| 706 | 24, 0, eq_tlv), | 702 | 24, 0, eq_tlv), |
| 707 | 703 | ||
| 704 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
| 705 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
| 708 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 706 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
| 709 | 24, 0, eq_tlv), | 707 | 24, 0, eq_tlv), |
| 710 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 708 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
| @@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
| 716 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 714 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
| 717 | 24, 0, eq_tlv), | 715 | 24, 0, eq_tlv), |
| 718 | 716 | ||
| 717 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
| 718 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
| 719 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 719 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
| 720 | 24, 0, eq_tlv), | 720 | 24, 0, eq_tlv), |
| 721 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 721 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
| @@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
| 727 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 727 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
| 728 | 24, 0, eq_tlv), | 728 | 24, 0, eq_tlv), |
| 729 | 729 | ||
| 730 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
| 731 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
| 730 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 732 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
| 731 | 24, 0, eq_tlv), | 733 | 24, 0, eq_tlv), |
| 732 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 734 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2c3c962d9a85..d7bf8848174a 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
| @@ -136,7 +136,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
| 136 | { | 136 | { |
| 137 | struct snd_soc_codec *codec = w->codec; | 137 | struct snd_soc_codec *codec = w->codec; |
| 138 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 138 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
| 139 | struct regmap *regmap = codec->control_data; | 139 | struct regmap *regmap = arizona->regmap; |
| 140 | const struct reg_default *patch = NULL; | 140 | const struct reg_default *patch = NULL; |
| 141 | int i, patch_size; | 141 | int i, patch_size; |
| 142 | 142 | ||
| @@ -247,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
| 247 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 247 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
| 248 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 248 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
| 249 | 249 | ||
| 250 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 250 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
| 251 | ARIZONA_EQ1_ENA_MASK), | 251 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
| 252 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
| 253 | ARIZONA_EQ2_ENA_MASK), | ||
| 254 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
| 255 | ARIZONA_EQ3_ENA_MASK), | ||
| 256 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
| 257 | ARIZONA_EQ4_ENA_MASK), | ||
| 258 | |||
| 259 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 252 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
| 260 | 24, 0, eq_tlv), | 253 | 24, 0, eq_tlv), |
| 261 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 254 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
| @@ -267,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
| 267 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 260 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
| 268 | 24, 0, eq_tlv), | 261 | 24, 0, eq_tlv), |
| 269 | 262 | ||
| 263 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
| 264 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
| 270 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 265 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
| 271 | 24, 0, eq_tlv), | 266 | 24, 0, eq_tlv), |
| 272 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 267 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
| @@ -278,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
| 278 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 273 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
| 279 | 24, 0, eq_tlv), | 274 | 24, 0, eq_tlv), |
| 280 | 275 | ||
| 276 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
| 277 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
| 281 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 278 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
| 282 | 24, 0, eq_tlv), | 279 | 24, 0, eq_tlv), |
| 283 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 280 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
| @@ -289,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
| 289 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 286 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
| 290 | 24, 0, eq_tlv), | 287 | 24, 0, eq_tlv), |
| 291 | 288 | ||
| 289 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
| 290 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
| 292 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 291 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
| 293 | 24, 0, eq_tlv), | 292 | 24, 0, eq_tlv), |
| 294 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 293 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 74d106dc7667..5dfd571b1a03 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
| @@ -75,8 +75,8 @@ static const char *wm8523_zd_count_text[] = { | |||
| 75 | "2048", | 75 | "2048", |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | static const struct soc_enum wm8523_zc_count = | 78 | static SOC_ENUM_SINGLE_DECL(wm8523_zc_count, WM8523_ZERO_DETECT, 0, |
| 79 | SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text); | 79 | wm8523_zd_count_text); |
| 80 | 80 | ||
| 81 | static const struct snd_kcontrol_new wm8523_controls[] = { | 81 | static const struct snd_kcontrol_new wm8523_controls[] = { |
| 82 | SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, | 82 | SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR, |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index d99f948c513c..6efcc40a7cb3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
| @@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream, | |||
| 201 | struct snd_soc_codec *codec = dai->codec; | 201 | struct snd_soc_codec *codec = dai->codec; |
| 202 | 202 | ||
| 203 | /* deactivate */ | 203 | /* deactivate */ |
| 204 | if (!codec->active) { | 204 | if (!snd_soc_codec_is_active(codec)) { |
| 205 | udelay(50); | 205 | udelay(50); |
| 206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | 206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); |
| 207 | } | 207 | } |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 029720366ff8..d9655f981df1 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
| @@ -83,8 +83,8 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg) | |||
| 83 | 83 | ||
| 84 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; | 84 | static const char *wm8731_input_select[] = {"Line In", "Mic"}; |
| 85 | 85 | ||
| 86 | static const struct soc_enum wm8731_insel_enum = | 86 | static SOC_ENUM_SINGLE_DECL(wm8731_insel_enum, |
| 87 | SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select); | 87 | WM8731_APANA, 2, wm8731_input_select); |
| 88 | 88 | ||
| 89 | static int wm8731_deemph[] = { 0, 32000, 44100, 48000 }; | 89 | static int wm8731_deemph[] = { 0, 32000, 44100, 48000 }; |
| 90 | 90 | ||
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 2f167a8ca01b..ecc4e8725d5b 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c | |||
| @@ -99,29 +99,29 @@ static const char *micbias_enum_text[] = { | |||
| 99 | "100%", | 99 | "100%", |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| 102 | static const struct soc_enum micbias_enum = | 102 | static SOC_ENUM_SINGLE_DECL(micbias_enum, |
| 103 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text); | 103 | WM8737_MIC_PREAMP_CONTROL, 0, micbias_enum_text); |
| 104 | 104 | ||
| 105 | static const char *low_cutoff_text[] = { | 105 | static const char *low_cutoff_text[] = { |
| 106 | "Low", "High" | 106 | "Low", "High" |
| 107 | }; | 107 | }; |
| 108 | 108 | ||
| 109 | static const struct soc_enum low_3d = | 109 | static SOC_ENUM_SINGLE_DECL(low_3d, |
| 110 | SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text); | 110 | WM8737_3D_ENHANCE, 6, low_cutoff_text); |
| 111 | 111 | ||
| 112 | static const char *high_cutoff_text[] = { | 112 | static const char *high_cutoff_text[] = { |
| 113 | "High", "Low" | 113 | "High", "Low" |
| 114 | }; | 114 | }; |
| 115 | 115 | ||
| 116 | static const struct soc_enum high_3d = | 116 | static SOC_ENUM_SINGLE_DECL(high_3d, |
| 117 | SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text); | 117 | WM8737_3D_ENHANCE, 5, high_cutoff_text); |
| 118 | 118 | ||
| 119 | static const char *alc_fn_text[] = { | 119 | static const char *alc_fn_text[] = { |
| 120 | "Disabled", "Right", "Left", "Stereo" | 120 | "Disabled", "Right", "Left", "Stereo" |
| 121 | }; | 121 | }; |
| 122 | 122 | ||
| 123 | static const struct soc_enum alc_fn = | 123 | static SOC_ENUM_SINGLE_DECL(alc_fn, |
| 124 | SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text); | 124 | WM8737_ALC1, 7, alc_fn_text); |
| 125 | 125 | ||
| 126 | static const char *alc_hold_text[] = { | 126 | static const char *alc_hold_text[] = { |
| 127 | "0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms", | 127 | "0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms", |
| @@ -129,24 +129,24 @@ static const char *alc_hold_text[] = { | |||
| 129 | "10.916s", "21.832s", "43.691s" | 129 | "10.916s", "21.832s", "43.691s" |
| 130 | }; | 130 | }; |
| 131 | 131 | ||
| 132 | static const struct soc_enum alc_hold = | 132 | static SOC_ENUM_SINGLE_DECL(alc_hold, |
| 133 | SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text); | 133 | WM8737_ALC2, 0, alc_hold_text); |
| 134 | 134 | ||
| 135 | static const char *alc_atk_text[] = { | 135 | static const char *alc_atk_text[] = { |
| 136 | "8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", | 136 | "8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", |
| 137 | "1.075s", "2.15s", "4.3s", "8.6s" | 137 | "1.075s", "2.15s", "4.3s", "8.6s" |
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | static const struct soc_enum alc_atk = | 140 | static SOC_ENUM_SINGLE_DECL(alc_atk, |
| 141 | SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text); | 141 | WM8737_ALC3, 0, alc_atk_text); |
| 142 | 142 | ||
| 143 | static const char *alc_dcy_text[] = { | 143 | static const char *alc_dcy_text[] = { |
| 144 | "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s", | 144 | "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s", |
| 145 | "4.3s", "8.6s", "17.2s", "34.41s" | 145 | "4.3s", "8.6s", "17.2s", "34.41s" |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| 148 | static const struct soc_enum alc_dcy = | 148 | static SOC_ENUM_SINGLE_DECL(alc_dcy, |
| 149 | SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text); | 149 | WM8737_ALC3, 4, alc_dcy_text); |
| 150 | 150 | ||
| 151 | static const struct snd_kcontrol_new wm8737_snd_controls[] = { | 151 | static const struct snd_kcontrol_new wm8737_snd_controls[] = { |
| 152 | SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, | 152 | SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R, |
| @@ -191,8 +191,8 @@ static const char *linsel_text[] = { | |||
| 191 | "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC", | 191 | "LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC", |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| 194 | static const struct soc_enum linsel_enum = | 194 | static SOC_ENUM_SINGLE_DECL(linsel_enum, |
| 195 | SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text); | 195 | WM8737_AUDIO_PATH_L, 7, linsel_text); |
| 196 | 196 | ||
| 197 | static const struct snd_kcontrol_new linsel_mux = | 197 | static const struct snd_kcontrol_new linsel_mux = |
| 198 | SOC_DAPM_ENUM("LINSEL", linsel_enum); | 198 | SOC_DAPM_ENUM("LINSEL", linsel_enum); |
| @@ -202,8 +202,8 @@ static const char *rinsel_text[] = { | |||
| 202 | "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC", | 202 | "RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC", |
| 203 | }; | 203 | }; |
| 204 | 204 | ||
| 205 | static const struct soc_enum rinsel_enum = | 205 | static SOC_ENUM_SINGLE_DECL(rinsel_enum, |
| 206 | SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text); | 206 | WM8737_AUDIO_PATH_R, 7, rinsel_text); |
| 207 | 207 | ||
| 208 | static const struct snd_kcontrol_new rinsel_mux = | 208 | static const struct snd_kcontrol_new rinsel_mux = |
| 209 | SOC_DAPM_ENUM("RINSEL", rinsel_enum); | 209 | SOC_DAPM_ENUM("RINSEL", rinsel_enum); |
| @@ -212,15 +212,15 @@ static const char *bypass_text[] = { | |||
| 212 | "Direct", "Preamp" | 212 | "Direct", "Preamp" |
| 213 | }; | 213 | }; |
| 214 | 214 | ||
| 215 | static const struct soc_enum lbypass_enum = | 215 | static SOC_ENUM_SINGLE_DECL(lbypass_enum, |
| 216 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text); | 216 | WM8737_MIC_PREAMP_CONTROL, 2, bypass_text); |
| 217 | 217 | ||
| 218 | static const struct snd_kcontrol_new lbypass_mux = | 218 | static const struct snd_kcontrol_new lbypass_mux = |
| 219 | SOC_DAPM_ENUM("Left Bypass", lbypass_enum); | 219 | SOC_DAPM_ENUM("Left Bypass", lbypass_enum); |
| 220 | 220 | ||
| 221 | 221 | ||
| 222 | static const struct soc_enum rbypass_enum = | 222 | static SOC_ENUM_SINGLE_DECL(rbypass_enum, |
| 223 | SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text); | 223 | WM8737_MIC_PREAMP_CONTROL, 3, bypass_text); |
| 224 | 224 | ||
| 225 | static const struct snd_kcontrol_new rbypass_mux = | 225 | static const struct snd_kcontrol_new rbypass_mux = |
| 226 | SOC_DAPM_ENUM("Left Bypass", rbypass_enum); | 226 | SOC_DAPM_ENUM("Left Bypass", rbypass_enum); |
| @@ -644,7 +644,7 @@ static const struct regmap_config wm8737_regmap = { | |||
| 644 | .volatile_reg = wm8737_volatile, | 644 | .volatile_reg = wm8737_volatile, |
| 645 | }; | 645 | }; |
| 646 | 646 | ||
| 647 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 647 | #if IS_ENABLED(CONFIG_I2C) |
| 648 | static int wm8737_i2c_probe(struct i2c_client *i2c, | 648 | static int wm8737_i2c_probe(struct i2c_client *i2c, |
| 649 | const struct i2c_device_id *id) | 649 | const struct i2c_device_id *id) |
| 650 | { | 650 | { |
| @@ -758,7 +758,7 @@ static struct spi_driver wm8737_spi_driver = { | |||
| 758 | static int __init wm8737_modinit(void) | 758 | static int __init wm8737_modinit(void) |
| 759 | { | 759 | { |
| 760 | int ret; | 760 | int ret; |
| 761 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 761 | #if IS_ENABLED(CONFIG_I2C) |
| 762 | ret = i2c_add_driver(&wm8737_i2c_driver); | 762 | ret = i2c_add_driver(&wm8737_i2c_driver); |
| 763 | if (ret != 0) { | 763 | if (ret != 0) { |
| 764 | printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n", | 764 | printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n", |
| @@ -781,7 +781,7 @@ static void __exit wm8737_exit(void) | |||
| 781 | #if defined(CONFIG_SPI_MASTER) | 781 | #if defined(CONFIG_SPI_MASTER) |
| 782 | spi_unregister_driver(&wm8737_spi_driver); | 782 | spi_unregister_driver(&wm8737_spi_driver); |
| 783 | #endif | 783 | #endif |
| 784 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 784 | #if IS_ENABLED(CONFIG_I2C) |
| 785 | i2c_del_driver(&wm8737_i2c_driver); | 785 | i2c_del_driver(&wm8737_i2c_driver); |
| 786 | #endif | 786 | #endif |
| 787 | } | 787 | } |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 2895c8d3b5e4..dd02ebf88015 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
| @@ -44,7 +44,7 @@ struct wm8741_priv { | |||
| 44 | struct regmap *regmap; | 44 | struct regmap *regmap; |
| 45 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | 45 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; |
| 46 | unsigned int sysclk; | 46 | unsigned int sysclk; |
| 47 | struct snd_pcm_hw_constraint_list *sysclk_constraints; | 47 | const struct snd_pcm_hw_constraint_list *sysclk_constraints; |
| 48 | }; | 48 | }; |
| 49 | 49 | ||
| 50 | static const struct reg_default wm8741_reg_defaults[] = { | 50 | static const struct reg_default wm8741_reg_defaults[] = { |
| @@ -122,74 +122,74 @@ static struct { | |||
| 122 | { 6, 768 }, | 122 | { 6, 768 }, |
| 123 | }; | 123 | }; |
| 124 | 124 | ||
| 125 | static unsigned int rates_11289[] = { | 125 | static const unsigned int rates_11289[] = { |
| 126 | 44100, 88235, | 126 | 44100, 88235, |
| 127 | }; | 127 | }; |
| 128 | 128 | ||
| 129 | static struct snd_pcm_hw_constraint_list constraints_11289 = { | 129 | static const struct snd_pcm_hw_constraint_list constraints_11289 = { |
| 130 | .count = ARRAY_SIZE(rates_11289), | 130 | .count = ARRAY_SIZE(rates_11289), |
| 131 | .list = rates_11289, | 131 | .list = rates_11289, |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | static unsigned int rates_12288[] = { | 134 | static const unsigned int rates_12288[] = { |
| 135 | 32000, 48000, 96000, | 135 | 32000, 48000, 96000, |
| 136 | }; | 136 | }; |
| 137 | 137 | ||
| 138 | static struct snd_pcm_hw_constraint_list constraints_12288 = { | 138 | static const struct snd_pcm_hw_constraint_list constraints_12288 = { |
| 139 | .count = ARRAY_SIZE(rates_12288), | 139 | .count = ARRAY_SIZE(rates_12288), |
| 140 | .list = rates_12288, | 140 | .list = rates_12288, |
| 141 | }; | 141 | }; |
| 142 | 142 | ||
| 143 | static unsigned int rates_16384[] = { | 143 | static const unsigned int rates_16384[] = { |
| 144 | 32000, | 144 | 32000, |
| 145 | }; | 145 | }; |
| 146 | 146 | ||
| 147 | static struct snd_pcm_hw_constraint_list constraints_16384 = { | 147 | static const struct snd_pcm_hw_constraint_list constraints_16384 = { |
| 148 | .count = ARRAY_SIZE(rates_16384), | 148 | .count = ARRAY_SIZE(rates_16384), |
| 149 | .list = rates_16384, | 149 | .list = rates_16384, |
| 150 | }; | 150 | }; |
| 151 | 151 | ||
| 152 | static unsigned int rates_16934[] = { | 152 | static const unsigned int rates_16934[] = { |
| 153 | 44100, 88235, | 153 | 44100, 88235, |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | static struct snd_pcm_hw_constraint_list constraints_16934 = { | 156 | static const struct snd_pcm_hw_constraint_list constraints_16934 = { |
| 157 | .count = ARRAY_SIZE(rates_16934), | 157 | .count = ARRAY_SIZE(rates_16934), |
| 158 | .list = rates_16934, | 158 | .list = rates_16934, |
| 159 | }; | 159 | }; |
| 160 | 160 | ||
| 161 | static unsigned int rates_18432[] = { | 161 | static const unsigned int rates_18432[] = { |
| 162 | 48000, 96000, | 162 | 48000, 96000, |
| 163 | }; | 163 | }; |
| 164 | 164 | ||
| 165 | static struct snd_pcm_hw_constraint_list constraints_18432 = { | 165 | static const struct snd_pcm_hw_constraint_list constraints_18432 = { |
| 166 | .count = ARRAY_SIZE(rates_18432), | 166 | .count = ARRAY_SIZE(rates_18432), |
| 167 | .list = rates_18432, | 167 | .list = rates_18432, |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
| 170 | static unsigned int rates_22579[] = { | 170 | static const unsigned int rates_22579[] = { |
| 171 | 44100, 88235, 1764000 | 171 | 44100, 88235, 1764000 |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | static struct snd_pcm_hw_constraint_list constraints_22579 = { | 174 | static const struct snd_pcm_hw_constraint_list constraints_22579 = { |
| 175 | .count = ARRAY_SIZE(rates_22579), | 175 | .count = ARRAY_SIZE(rates_22579), |
| 176 | .list = rates_22579, | 176 | .list = rates_22579, |
| 177 | }; | 177 | }; |
| 178 | 178 | ||
| 179 | static unsigned int rates_24576[] = { | 179 | static const unsigned int rates_24576[] = { |
| 180 | 32000, 48000, 96000, 192000 | 180 | 32000, 48000, 96000, 192000 |
| 181 | }; | 181 | }; |
| 182 | 182 | ||
| 183 | static struct snd_pcm_hw_constraint_list constraints_24576 = { | 183 | static const struct snd_pcm_hw_constraint_list constraints_24576 = { |
| 184 | .count = ARRAY_SIZE(rates_24576), | 184 | .count = ARRAY_SIZE(rates_24576), |
| 185 | .list = rates_24576, | 185 | .list = rates_24576, |
| 186 | }; | 186 | }; |
| 187 | 187 | ||
| 188 | static unsigned int rates_36864[] = { | 188 | static const unsigned int rates_36864[] = { |
| 189 | 48000, 96000, 19200 | 189 | 48000, 96000, 19200 |
| 190 | }; | 190 | }; |
| 191 | 191 | ||
| 192 | static struct snd_pcm_hw_constraint_list constraints_36864 = { | 192 | static const struct snd_pcm_hw_constraint_list constraints_36864 = { |
| 193 | .count = ARRAY_SIZE(rates_36864), | 193 | .count = ARRAY_SIZE(rates_36864), |
| 194 | .list = rates_36864, | 194 | .list = rates_36864, |
| 195 | }; | 195 | }; |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index be85da93a268..6a6855d8b8ea 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
| @@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
| 251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) | 251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) |
| 252 | return 0; | 252 | return 0; |
| 253 | 253 | ||
| 254 | if (codec->active) | 254 | if (snd_soc_codec_is_active(codec)) |
| 255 | return -EBUSY; | 255 | return -EBUSY; |
| 256 | 256 | ||
| 257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); | 257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); |
| @@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) | |||
| 1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. |
| 1315 | * make sure we check if they are not both active when we mute */ | 1315 | * make sure we check if they are not both active when we mute */ |
| 1316 | if (mute && wm8753->dai_func == 1) { | 1316 | if (mute && wm8753->dai_func == 1) { |
| 1317 | if (!codec->active) | 1317 | if (!snd_soc_codec_is_active(codec)) |
| 1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); | 1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); |
| 1319 | } else { | 1319 | } else { |
| 1320 | if (mute) | 1320 | if (mute) |
| @@ -1440,7 +1440,6 @@ static void wm8753_work(struct work_struct *work) | |||
| 1440 | static int wm8753_suspend(struct snd_soc_codec *codec) | 1440 | static int wm8753_suspend(struct snd_soc_codec *codec) |
| 1441 | { | 1441 | { |
| 1442 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1442 | wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1443 | codec->cache_sync = 1; | ||
| 1444 | return 0; | 1443 | return 0; |
| 1445 | } | 1444 | } |
| 1446 | 1445 | ||
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 9bc8206a6807..72d12bbe1a56 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
| @@ -92,7 +92,7 @@ WM8804_REGULATOR_EVENT(0) | |||
| 92 | WM8804_REGULATOR_EVENT(1) | 92 | WM8804_REGULATOR_EVENT(1) |
| 93 | 93 | ||
| 94 | static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; | 94 | static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; |
| 95 | static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); | 95 | static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); |
| 96 | 96 | ||
| 97 | static const struct snd_kcontrol_new wm8804_snd_controls[] = { | 97 | static const struct snd_kcontrol_new wm8804_snd_controls[] = { |
| 98 | SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), | 98 | SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index eebcb1da3b7b..b82b70a3b3d3 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
| @@ -489,28 +489,28 @@ static const char *hpf_mode_text[] = { | |||
| 489 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3" | 489 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3" |
| 490 | }; | 490 | }; |
| 491 | 491 | ||
| 492 | static const struct soc_enum hpf_mode = | 492 | static SOC_ENUM_SINGLE_DECL(hpf_mode, |
| 493 | SOC_ENUM_SINGLE(WM8903_ADC_DIGITAL_0, 5, 4, hpf_mode_text); | 493 | WM8903_ADC_DIGITAL_0, 5, hpf_mode_text); |
| 494 | 494 | ||
| 495 | static const char *osr_text[] = { | 495 | static const char *osr_text[] = { |
| 496 | "Low power", "High performance" | 496 | "Low power", "High performance" |
| 497 | }; | 497 | }; |
| 498 | 498 | ||
| 499 | static const struct soc_enum adc_osr = | 499 | static SOC_ENUM_SINGLE_DECL(adc_osr, |
| 500 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_ADC_0, 0, 2, osr_text); | 500 | WM8903_ANALOGUE_ADC_0, 0, osr_text); |
| 501 | 501 | ||
| 502 | static const struct soc_enum dac_osr = | 502 | static SOC_ENUM_SINGLE_DECL(dac_osr, |
| 503 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 0, 2, osr_text); | 503 | WM8903_DAC_DIGITAL_1, 0, osr_text); |
| 504 | 504 | ||
| 505 | static const char *drc_slope_text[] = { | 505 | static const char *drc_slope_text[] = { |
| 506 | "1", "1/2", "1/4", "1/8", "1/16", "0" | 506 | "1", "1/2", "1/4", "1/8", "1/16", "0" |
| 507 | }; | 507 | }; |
| 508 | 508 | ||
| 509 | static const struct soc_enum drc_slope_r0 = | 509 | static SOC_ENUM_SINGLE_DECL(drc_slope_r0, |
| 510 | SOC_ENUM_SINGLE(WM8903_DRC_2, 3, 6, drc_slope_text); | 510 | WM8903_DRC_2, 3, drc_slope_text); |
| 511 | 511 | ||
| 512 | static const struct soc_enum drc_slope_r1 = | 512 | static SOC_ENUM_SINGLE_DECL(drc_slope_r1, |
| 513 | SOC_ENUM_SINGLE(WM8903_DRC_2, 0, 6, drc_slope_text); | 513 | WM8903_DRC_2, 0, drc_slope_text); |
| 514 | 514 | ||
| 515 | static const char *drc_attack_text[] = { | 515 | static const char *drc_attack_text[] = { |
| 516 | "instantaneous", | 516 | "instantaneous", |
| @@ -518,125 +518,125 @@ static const char *drc_attack_text[] = { | |||
| 518 | "46.4ms", "92.8ms", "185.6ms" | 518 | "46.4ms", "92.8ms", "185.6ms" |
| 519 | }; | 519 | }; |
| 520 | 520 | ||
| 521 | static const struct soc_enum drc_attack = | 521 | static SOC_ENUM_SINGLE_DECL(drc_attack, |
| 522 | SOC_ENUM_SINGLE(WM8903_DRC_1, 12, 11, drc_attack_text); | 522 | WM8903_DRC_1, 12, drc_attack_text); |
| 523 | 523 | ||
| 524 | static const char *drc_decay_text[] = { | 524 | static const char *drc_decay_text[] = { |
| 525 | "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s", | 525 | "186ms", "372ms", "743ms", "1.49s", "2.97s", "5.94s", "11.89s", |
| 526 | "23.87s", "47.56s" | 526 | "23.87s", "47.56s" |
| 527 | }; | 527 | }; |
| 528 | 528 | ||
| 529 | static const struct soc_enum drc_decay = | 529 | static SOC_ENUM_SINGLE_DECL(drc_decay, |
| 530 | SOC_ENUM_SINGLE(WM8903_DRC_1, 8, 9, drc_decay_text); | 530 | WM8903_DRC_1, 8, drc_decay_text); |
| 531 | 531 | ||
| 532 | static const char *drc_ff_delay_text[] = { | 532 | static const char *drc_ff_delay_text[] = { |
| 533 | "5 samples", "9 samples" | 533 | "5 samples", "9 samples" |
| 534 | }; | 534 | }; |
| 535 | 535 | ||
| 536 | static const struct soc_enum drc_ff_delay = | 536 | static SOC_ENUM_SINGLE_DECL(drc_ff_delay, |
| 537 | SOC_ENUM_SINGLE(WM8903_DRC_0, 5, 2, drc_ff_delay_text); | 537 | WM8903_DRC_0, 5, drc_ff_delay_text); |
| 538 | 538 | ||
| 539 | static const char *drc_qr_decay_text[] = { | 539 | static const char *drc_qr_decay_text[] = { |
| 540 | "0.725ms", "1.45ms", "5.8ms" | 540 | "0.725ms", "1.45ms", "5.8ms" |
| 541 | }; | 541 | }; |
| 542 | 542 | ||
| 543 | static const struct soc_enum drc_qr_decay = | 543 | static SOC_ENUM_SINGLE_DECL(drc_qr_decay, |
| 544 | SOC_ENUM_SINGLE(WM8903_DRC_1, 4, 3, drc_qr_decay_text); | 544 | WM8903_DRC_1, 4, drc_qr_decay_text); |
| 545 | 545 | ||
| 546 | static const char *drc_smoothing_text[] = { | 546 | static const char *drc_smoothing_text[] = { |
| 547 | "Low", "Medium", "High" | 547 | "Low", "Medium", "High" |
| 548 | }; | 548 | }; |
| 549 | 549 | ||
| 550 | static const struct soc_enum drc_smoothing = | 550 | static SOC_ENUM_SINGLE_DECL(drc_smoothing, |
| 551 | SOC_ENUM_SINGLE(WM8903_DRC_0, 11, 3, drc_smoothing_text); | 551 | WM8903_DRC_0, 11, drc_smoothing_text); |
| 552 | 552 | ||
| 553 | static const char *soft_mute_text[] = { | 553 | static const char *soft_mute_text[] = { |
| 554 | "Fast (fs/2)", "Slow (fs/32)" | 554 | "Fast (fs/2)", "Slow (fs/32)" |
| 555 | }; | 555 | }; |
| 556 | 556 | ||
| 557 | static const struct soc_enum soft_mute = | 557 | static SOC_ENUM_SINGLE_DECL(soft_mute, |
| 558 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 10, 2, soft_mute_text); | 558 | WM8903_DAC_DIGITAL_1, 10, soft_mute_text); |
| 559 | 559 | ||
| 560 | static const char *mute_mode_text[] = { | 560 | static const char *mute_mode_text[] = { |
| 561 | "Hard", "Soft" | 561 | "Hard", "Soft" |
| 562 | }; | 562 | }; |
| 563 | 563 | ||
| 564 | static const struct soc_enum mute_mode = | 564 | static SOC_ENUM_SINGLE_DECL(mute_mode, |
| 565 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_1, 9, 2, mute_mode_text); | 565 | WM8903_DAC_DIGITAL_1, 9, mute_mode_text); |
| 566 | 566 | ||
| 567 | static const char *companding_text[] = { | 567 | static const char *companding_text[] = { |
| 568 | "ulaw", "alaw" | 568 | "ulaw", "alaw" |
| 569 | }; | 569 | }; |
| 570 | 570 | ||
| 571 | static const struct soc_enum dac_companding = | 571 | static SOC_ENUM_SINGLE_DECL(dac_companding, |
| 572 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 0, 2, companding_text); | 572 | WM8903_AUDIO_INTERFACE_0, 0, companding_text); |
| 573 | 573 | ||
| 574 | static const struct soc_enum adc_companding = | 574 | static SOC_ENUM_SINGLE_DECL(adc_companding, |
| 575 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 2, 2, companding_text); | 575 | WM8903_AUDIO_INTERFACE_0, 2, companding_text); |
| 576 | 576 | ||
| 577 | static const char *input_mode_text[] = { | 577 | static const char *input_mode_text[] = { |
| 578 | "Single-Ended", "Differential Line", "Differential Mic" | 578 | "Single-Ended", "Differential Line", "Differential Mic" |
| 579 | }; | 579 | }; |
| 580 | 580 | ||
| 581 | static const struct soc_enum linput_mode_enum = | 581 | static SOC_ENUM_SINGLE_DECL(linput_mode_enum, |
| 582 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); | 582 | WM8903_ANALOGUE_LEFT_INPUT_1, 0, input_mode_text); |
| 583 | 583 | ||
| 584 | static const struct soc_enum rinput_mode_enum = | 584 | static SOC_ENUM_SINGLE_DECL(rinput_mode_enum, |
| 585 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); | 585 | WM8903_ANALOGUE_RIGHT_INPUT_1, 0, input_mode_text); |
| 586 | 586 | ||
| 587 | static const char *linput_mux_text[] = { | 587 | static const char *linput_mux_text[] = { |
| 588 | "IN1L", "IN2L", "IN3L" | 588 | "IN1L", "IN2L", "IN3L" |
| 589 | }; | 589 | }; |
| 590 | 590 | ||
| 591 | static const struct soc_enum linput_enum = | 591 | static SOC_ENUM_SINGLE_DECL(linput_enum, |
| 592 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 2, 3, linput_mux_text); | 592 | WM8903_ANALOGUE_LEFT_INPUT_1, 2, linput_mux_text); |
| 593 | 593 | ||
| 594 | static const struct soc_enum linput_inv_enum = | 594 | static SOC_ENUM_SINGLE_DECL(linput_inv_enum, |
| 595 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_LEFT_INPUT_1, 4, 3, linput_mux_text); | 595 | WM8903_ANALOGUE_LEFT_INPUT_1, 4, linput_mux_text); |
| 596 | 596 | ||
| 597 | static const char *rinput_mux_text[] = { | 597 | static const char *rinput_mux_text[] = { |
| 598 | "IN1R", "IN2R", "IN3R" | 598 | "IN1R", "IN2R", "IN3R" |
| 599 | }; | 599 | }; |
| 600 | 600 | ||
| 601 | static const struct soc_enum rinput_enum = | 601 | static SOC_ENUM_SINGLE_DECL(rinput_enum, |
| 602 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 2, 3, rinput_mux_text); | 602 | WM8903_ANALOGUE_RIGHT_INPUT_1, 2, rinput_mux_text); |
| 603 | 603 | ||
| 604 | static const struct soc_enum rinput_inv_enum = | 604 | static SOC_ENUM_SINGLE_DECL(rinput_inv_enum, |
| 605 | SOC_ENUM_SINGLE(WM8903_ANALOGUE_RIGHT_INPUT_1, 4, 3, rinput_mux_text); | 605 | WM8903_ANALOGUE_RIGHT_INPUT_1, 4, rinput_mux_text); |
| 606 | 606 | ||
| 607 | 607 | ||
| 608 | static const char *sidetone_text[] = { | 608 | static const char *sidetone_text[] = { |
| 609 | "None", "Left", "Right" | 609 | "None", "Left", "Right" |
| 610 | }; | 610 | }; |
| 611 | 611 | ||
| 612 | static const struct soc_enum lsidetone_enum = | 612 | static SOC_ENUM_SINGLE_DECL(lsidetone_enum, |
| 613 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 2, 3, sidetone_text); | 613 | WM8903_DAC_DIGITAL_0, 2, sidetone_text); |
| 614 | 614 | ||
| 615 | static const struct soc_enum rsidetone_enum = | 615 | static SOC_ENUM_SINGLE_DECL(rsidetone_enum, |
| 616 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); | 616 | WM8903_DAC_DIGITAL_0, 0, sidetone_text); |
| 617 | 617 | ||
| 618 | static const char *adcinput_text[] = { | 618 | static const char *adcinput_text[] = { |
| 619 | "ADC", "DMIC" | 619 | "ADC", "DMIC" |
| 620 | }; | 620 | }; |
| 621 | 621 | ||
| 622 | static const struct soc_enum adcinput_enum = | 622 | static SOC_ENUM_SINGLE_DECL(adcinput_enum, |
| 623 | SOC_ENUM_SINGLE(WM8903_CLOCK_RATE_TEST_4, 9, 2, adcinput_text); | 623 | WM8903_CLOCK_RATE_TEST_4, 9, adcinput_text); |
| 624 | 624 | ||
| 625 | static const char *aif_text[] = { | 625 | static const char *aif_text[] = { |
| 626 | "Left", "Right" | 626 | "Left", "Right" |
| 627 | }; | 627 | }; |
| 628 | 628 | ||
| 629 | static const struct soc_enum lcapture_enum = | 629 | static SOC_ENUM_SINGLE_DECL(lcapture_enum, |
| 630 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text); | 630 | WM8903_AUDIO_INTERFACE_0, 7, aif_text); |
| 631 | 631 | ||
| 632 | static const struct soc_enum rcapture_enum = | 632 | static SOC_ENUM_SINGLE_DECL(rcapture_enum, |
| 633 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text); | 633 | WM8903_AUDIO_INTERFACE_0, 6, aif_text); |
| 634 | 634 | ||
| 635 | static const struct soc_enum lplay_enum = | 635 | static SOC_ENUM_SINGLE_DECL(lplay_enum, |
| 636 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text); | 636 | WM8903_AUDIO_INTERFACE_0, 5, aif_text); |
| 637 | 637 | ||
| 638 | static const struct soc_enum rplay_enum = | 638 | static SOC_ENUM_SINGLE_DECL(rplay_enum, |
| 639 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text); | 639 | WM8903_AUDIO_INTERFACE_0, 4, aif_text); |
| 640 | 640 | ||
| 641 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { | 641 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { |
| 642 | 642 | ||
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 53bbfac6a83a..27299cda0e99 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
| @@ -552,18 +552,20 @@ static const char *input_mode_text[] = { | |||
| 552 | "Single-Ended", "Differential Line", "Differential Mic" | 552 | "Single-Ended", "Differential Line", "Differential Mic" |
| 553 | }; | 553 | }; |
| 554 | 554 | ||
| 555 | static const struct soc_enum lin_mode = | 555 | static SOC_ENUM_SINGLE_DECL(lin_mode, |
| 556 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 0, 3, input_mode_text); | 556 | WM8904_ANALOGUE_LEFT_INPUT_1, 0, |
| 557 | input_mode_text); | ||
| 557 | 558 | ||
| 558 | static const struct soc_enum rin_mode = | 559 | static SOC_ENUM_SINGLE_DECL(rin_mode, |
| 559 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 0, 3, input_mode_text); | 560 | WM8904_ANALOGUE_RIGHT_INPUT_1, 0, |
| 561 | input_mode_text); | ||
| 560 | 562 | ||
| 561 | static const char *hpf_mode_text[] = { | 563 | static const char *hpf_mode_text[] = { |
| 562 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3" | 564 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3" |
| 563 | }; | 565 | }; |
| 564 | 566 | ||
| 565 | static const struct soc_enum hpf_mode = | 567 | static SOC_ENUM_SINGLE_DECL(hpf_mode, WM8904_ADC_DIGITAL_0, 5, |
| 566 | SOC_ENUM_SINGLE(WM8904_ADC_DIGITAL_0, 5, 4, hpf_mode_text); | 568 | hpf_mode_text); |
| 567 | 569 | ||
| 568 | static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, | 570 | static int wm8904_adc_osr_put(struct snd_kcontrol *kcontrol, |
| 569 | struct snd_ctl_elem_value *ucontrol) | 571 | struct snd_ctl_elem_value *ucontrol) |
| @@ -611,8 +613,7 @@ static const char *drc_path_text[] = { | |||
| 611 | "ADC", "DAC" | 613 | "ADC", "DAC" |
| 612 | }; | 614 | }; |
| 613 | 615 | ||
| 614 | static const struct soc_enum drc_path = | 616 | static SOC_ENUM_SINGLE_DECL(drc_path, WM8904_DRC_0, 14, drc_path_text); |
| 615 | SOC_ENUM_SINGLE(WM8904_DRC_0, 14, 2, drc_path_text); | ||
| 616 | 617 | ||
| 617 | static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { | 618 | static const struct snd_kcontrol_new wm8904_dac_snd_controls[] = { |
| 618 | SOC_SINGLE_TLV("Digital Playback Boost Volume", | 619 | SOC_SINGLE_TLV("Digital Playback Boost Volume", |
| @@ -858,14 +859,14 @@ static const char *lin_text[] = { | |||
| 858 | "IN1L", "IN2L", "IN3L" | 859 | "IN1L", "IN2L", "IN3L" |
| 859 | }; | 860 | }; |
| 860 | 861 | ||
| 861 | static const struct soc_enum lin_enum = | 862 | static SOC_ENUM_SINGLE_DECL(lin_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 2, |
| 862 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 2, 3, lin_text); | 863 | lin_text); |
| 863 | 864 | ||
| 864 | static const struct snd_kcontrol_new lin_mux = | 865 | static const struct snd_kcontrol_new lin_mux = |
| 865 | SOC_DAPM_ENUM("Left Capture Mux", lin_enum); | 866 | SOC_DAPM_ENUM("Left Capture Mux", lin_enum); |
| 866 | 867 | ||
| 867 | static const struct soc_enum lin_inv_enum = | 868 | static SOC_ENUM_SINGLE_DECL(lin_inv_enum, WM8904_ANALOGUE_LEFT_INPUT_1, 4, |
| 868 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_LEFT_INPUT_1, 4, 3, lin_text); | 869 | lin_text); |
| 869 | 870 | ||
| 870 | static const struct snd_kcontrol_new lin_inv_mux = | 871 | static const struct snd_kcontrol_new lin_inv_mux = |
| 871 | SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); | 872 | SOC_DAPM_ENUM("Left Capture Inveting Mux", lin_inv_enum); |
| @@ -874,14 +875,14 @@ static const char *rin_text[] = { | |||
| 874 | "IN1R", "IN2R", "IN3R" | 875 | "IN1R", "IN2R", "IN3R" |
| 875 | }; | 876 | }; |
| 876 | 877 | ||
| 877 | static const struct soc_enum rin_enum = | 878 | static SOC_ENUM_SINGLE_DECL(rin_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 2, |
| 878 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 2, 3, rin_text); | 879 | rin_text); |
| 879 | 880 | ||
| 880 | static const struct snd_kcontrol_new rin_mux = | 881 | static const struct snd_kcontrol_new rin_mux = |
| 881 | SOC_DAPM_ENUM("Right Capture Mux", rin_enum); | 882 | SOC_DAPM_ENUM("Right Capture Mux", rin_enum); |
| 882 | 883 | ||
| 883 | static const struct soc_enum rin_inv_enum = | 884 | static SOC_ENUM_SINGLE_DECL(rin_inv_enum, WM8904_ANALOGUE_RIGHT_INPUT_1, 4, |
| 884 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_RIGHT_INPUT_1, 4, 3, rin_text); | 885 | rin_text); |
| 885 | 886 | ||
| 886 | static const struct snd_kcontrol_new rin_inv_mux = | 887 | static const struct snd_kcontrol_new rin_inv_mux = |
| 887 | SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); | 888 | SOC_DAPM_ENUM("Right Capture Inveting Mux", rin_inv_enum); |
| @@ -890,26 +891,26 @@ static const char *aif_text[] = { | |||
| 890 | "Left", "Right" | 891 | "Left", "Right" |
| 891 | }; | 892 | }; |
| 892 | 893 | ||
| 893 | static const struct soc_enum aifoutl_enum = | 894 | static SOC_ENUM_SINGLE_DECL(aifoutl_enum, WM8904_AUDIO_INTERFACE_0, 7, |
| 894 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 7, 2, aif_text); | 895 | aif_text); |
| 895 | 896 | ||
| 896 | static const struct snd_kcontrol_new aifoutl_mux = | 897 | static const struct snd_kcontrol_new aifoutl_mux = |
| 897 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); | 898 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); |
| 898 | 899 | ||
| 899 | static const struct soc_enum aifoutr_enum = | 900 | static SOC_ENUM_SINGLE_DECL(aifoutr_enum, WM8904_AUDIO_INTERFACE_0, 6, |
| 900 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 6, 2, aif_text); | 901 | aif_text); |
| 901 | 902 | ||
| 902 | static const struct snd_kcontrol_new aifoutr_mux = | 903 | static const struct snd_kcontrol_new aifoutr_mux = |
| 903 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); | 904 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); |
| 904 | 905 | ||
| 905 | static const struct soc_enum aifinl_enum = | 906 | static SOC_ENUM_SINGLE_DECL(aifinl_enum, WM8904_AUDIO_INTERFACE_0, 5, |
| 906 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 5, 2, aif_text); | 907 | aif_text); |
| 907 | 908 | ||
| 908 | static const struct snd_kcontrol_new aifinl_mux = | 909 | static const struct snd_kcontrol_new aifinl_mux = |
| 909 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); | 910 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); |
| 910 | 911 | ||
| 911 | static const struct soc_enum aifinr_enum = | 912 | static SOC_ENUM_SINGLE_DECL(aifinr_enum, WM8904_AUDIO_INTERFACE_0, 4, |
| 912 | SOC_ENUM_SINGLE(WM8904_AUDIO_INTERFACE_0, 4, 2, aif_text); | 913 | aif_text); |
| 913 | 914 | ||
| 914 | static const struct snd_kcontrol_new aifinr_mux = | 915 | static const struct snd_kcontrol_new aifinr_mux = |
| 915 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); | 916 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); |
| @@ -991,26 +992,26 @@ static const char *out_mux_text[] = { | |||
| 991 | "DAC", "Bypass" | 992 | "DAC", "Bypass" |
| 992 | }; | 993 | }; |
| 993 | 994 | ||
| 994 | static const struct soc_enum hpl_enum = | 995 | static SOC_ENUM_SINGLE_DECL(hpl_enum, WM8904_ANALOGUE_OUT12_ZC, 3, |
| 995 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 3, 2, out_mux_text); | 996 | out_mux_text); |
| 996 | 997 | ||
| 997 | static const struct snd_kcontrol_new hpl_mux = | 998 | static const struct snd_kcontrol_new hpl_mux = |
| 998 | SOC_DAPM_ENUM("HPL Mux", hpl_enum); | 999 | SOC_DAPM_ENUM("HPL Mux", hpl_enum); |
| 999 | 1000 | ||
| 1000 | static const struct soc_enum hpr_enum = | 1001 | static SOC_ENUM_SINGLE_DECL(hpr_enum, WM8904_ANALOGUE_OUT12_ZC, 2, |
| 1001 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 2, 2, out_mux_text); | 1002 | out_mux_text); |
| 1002 | 1003 | ||
| 1003 | static const struct snd_kcontrol_new hpr_mux = | 1004 | static const struct snd_kcontrol_new hpr_mux = |
| 1004 | SOC_DAPM_ENUM("HPR Mux", hpr_enum); | 1005 | SOC_DAPM_ENUM("HPR Mux", hpr_enum); |
| 1005 | 1006 | ||
| 1006 | static const struct soc_enum linel_enum = | 1007 | static SOC_ENUM_SINGLE_DECL(linel_enum, WM8904_ANALOGUE_OUT12_ZC, 1, |
| 1007 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 1, 2, out_mux_text); | 1008 | out_mux_text); |
| 1008 | 1009 | ||
| 1009 | static const struct snd_kcontrol_new linel_mux = | 1010 | static const struct snd_kcontrol_new linel_mux = |
| 1010 | SOC_DAPM_ENUM("LINEL Mux", linel_enum); | 1011 | SOC_DAPM_ENUM("LINEL Mux", linel_enum); |
| 1011 | 1012 | ||
| 1012 | static const struct soc_enum liner_enum = | 1013 | static SOC_ENUM_SINGLE_DECL(liner_enum, WM8904_ANALOGUE_OUT12_ZC, 0, |
| 1013 | SOC_ENUM_SINGLE(WM8904_ANALOGUE_OUT12_ZC, 0, 2, out_mux_text); | 1014 | out_mux_text); |
| 1014 | 1015 | ||
| 1015 | static const struct snd_kcontrol_new liner_mux = | 1016 | static const struct snd_kcontrol_new liner_mux = |
| 1016 | SOC_DAPM_ENUM("LINER Mux", liner_enum); | 1017 | SOC_DAPM_ENUM("LINER Mux", liner_enum); |
| @@ -1019,14 +1020,14 @@ static const char *sidetone_text[] = { | |||
| 1019 | "None", "Left", "Right" | 1020 | "None", "Left", "Right" |
| 1020 | }; | 1021 | }; |
| 1021 | 1022 | ||
| 1022 | static const struct soc_enum dacl_sidetone_enum = | 1023 | static SOC_ENUM_SINGLE_DECL(dacl_sidetone_enum, WM8904_DAC_DIGITAL_0, 2, |
| 1023 | SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 2, 3, sidetone_text); | 1024 | sidetone_text); |
| 1024 | 1025 | ||
| 1025 | static const struct snd_kcontrol_new dacl_sidetone_mux = | 1026 | static const struct snd_kcontrol_new dacl_sidetone_mux = |
| 1026 | SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); | 1027 | SOC_DAPM_ENUM("Left Sidetone Mux", dacl_sidetone_enum); |
| 1027 | 1028 | ||
| 1028 | static const struct soc_enum dacr_sidetone_enum = | 1029 | static SOC_ENUM_SINGLE_DECL(dacr_sidetone_enum, WM8904_DAC_DIGITAL_0, 0, |
| 1029 | SOC_ENUM_SINGLE(WM8904_DAC_DIGITAL_0, 0, 3, sidetone_text); | 1030 | sidetone_text); |
| 1030 | 1031 | ||
| 1031 | static const struct snd_kcontrol_new dacr_sidetone_mux = | 1032 | static const struct snd_kcontrol_new dacr_sidetone_mux = |
| 1032 | SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); | 1033 | SOC_DAPM_ENUM("Right Sidetone Mux", dacr_sidetone_enum); |
| @@ -1981,7 +1982,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) | |||
| 1981 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 1982 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
| 1982 | wm8904->num_retune_mobile_texts); | 1983 | wm8904->num_retune_mobile_texts); |
| 1983 | 1984 | ||
| 1984 | wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; | 1985 | wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts; |
| 1985 | wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; | 1986 | wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; |
| 1986 | 1987 | ||
| 1987 | ret = snd_soc_add_codec_controls(codec, &control, 1); | 1988 | ret = snd_soc_add_codec_controls(codec, &control, 1); |
| @@ -2022,7 +2023,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) | |||
| 2022 | for (i = 0; i < pdata->num_drc_cfgs; i++) | 2023 | for (i = 0; i < pdata->num_drc_cfgs; i++) |
| 2023 | wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; | 2024 | wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; |
| 2024 | 2025 | ||
| 2025 | wm8904->drc_enum.max = pdata->num_drc_cfgs; | 2026 | wm8904->drc_enum.items = pdata->num_drc_cfgs; |
| 2026 | wm8904->drc_enum.texts = wm8904->drc_texts; | 2027 | wm8904->drc_enum.texts = wm8904->drc_texts; |
| 2027 | 2028 | ||
| 2028 | ret = snd_soc_add_codec_controls(codec, &control, 1); | 2029 | ret = snd_soc_add_codec_controls(codec, &control, 1); |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index b404c26c1753..87f032d0d19f 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
| @@ -154,22 +154,22 @@ static const struct reg_default wm8940_reg_defaults[] = { | |||
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; | 156 | static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; |
| 157 | static const struct soc_enum wm8940_adc_companding_enum | 157 | static SOC_ENUM_SINGLE_DECL(wm8940_adc_companding_enum, |
| 158 | = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); | 158 | WM8940_COMPANDINGCTL, 1, wm8940_companding); |
| 159 | static const struct soc_enum wm8940_dac_companding_enum | 159 | static SOC_ENUM_SINGLE_DECL(wm8940_dac_companding_enum, |
| 160 | = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 3, 4, wm8940_companding); | 160 | WM8940_COMPANDINGCTL, 3, wm8940_companding); |
| 161 | 161 | ||
| 162 | static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; | 162 | static const char *wm8940_alc_mode_text[] = {"ALC", "Limiter"}; |
| 163 | static const struct soc_enum wm8940_alc_mode_enum | 163 | static SOC_ENUM_SINGLE_DECL(wm8940_alc_mode_enum, |
| 164 | = SOC_ENUM_SINGLE(WM8940_ALC3, 8, 2, wm8940_alc_mode_text); | 164 | WM8940_ALC3, 8, wm8940_alc_mode_text); |
| 165 | 165 | ||
| 166 | static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; | 166 | static const char *wm8940_mic_bias_level_text[] = {"0.9", "0.65"}; |
| 167 | static const struct soc_enum wm8940_mic_bias_level_enum | 167 | static SOC_ENUM_SINGLE_DECL(wm8940_mic_bias_level_enum, |
| 168 | = SOC_ENUM_SINGLE(WM8940_INPUTCTL, 8, 2, wm8940_mic_bias_level_text); | 168 | WM8940_INPUTCTL, 8, wm8940_mic_bias_level_text); |
| 169 | 169 | ||
| 170 | static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; | 170 | static const char *wm8940_filter_mode_text[] = {"Audio", "Application"}; |
| 171 | static const struct soc_enum wm8940_filter_mode_enum | 171 | static SOC_ENUM_SINGLE_DECL(wm8940_filter_mode_enum, |
| 172 | = SOC_ENUM_SINGLE(WM8940_ADC, 7, 2, wm8940_filter_mode_text); | 172 | WM8940_ADC, 7, wm8940_filter_mode_text); |
| 173 | 173 | ||
| 174 | static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1); | 174 | static DECLARE_TLV_DB_SCALE(wm8940_spk_vol_tlv, -5700, 100, 1); |
| 175 | static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); | 175 | static DECLARE_TLV_DB_SCALE(wm8940_att_tlv, -1000, 1000, 0); |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 82c8ba975720..d4dcaecc8a5f 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
| @@ -416,22 +416,21 @@ static const char *bass_mode_text[] = { | |||
| 416 | "Linear", "Adaptive", | 416 | "Linear", "Adaptive", |
| 417 | }; | 417 | }; |
| 418 | 418 | ||
| 419 | static const struct soc_enum bass_mode = | 419 | static SOC_ENUM_SINGLE_DECL(bass_mode, WM8955_BASS_CONTROL, 7, bass_mode_text); |
| 420 | SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 7, 2, bass_mode_text); | ||
| 421 | 420 | ||
| 422 | static const char *bass_cutoff_text[] = { | 421 | static const char *bass_cutoff_text[] = { |
| 423 | "Low", "High" | 422 | "Low", "High" |
| 424 | }; | 423 | }; |
| 425 | 424 | ||
| 426 | static const struct soc_enum bass_cutoff = | 425 | static SOC_ENUM_SINGLE_DECL(bass_cutoff, WM8955_BASS_CONTROL, 6, |
| 427 | SOC_ENUM_SINGLE(WM8955_BASS_CONTROL, 6, 2, bass_cutoff_text); | 426 | bass_cutoff_text); |
| 428 | 427 | ||
| 429 | static const char *treble_cutoff_text[] = { | 428 | static const char *treble_cutoff_text[] = { |
| 430 | "High", "Low" | 429 | "High", "Low" |
| 431 | }; | 430 | }; |
| 432 | 431 | ||
| 433 | static const struct soc_enum treble_cutoff = | 432 | static SOC_ENUM_SINGLE_DECL(treble_cutoff, WM8955_TREBLE_CONTROL, 2, |
| 434 | SOC_ENUM_SINGLE(WM8955_TREBLE_CONTROL, 6, 2, treble_cutoff_text); | 433 | treble_cutoff_text); |
| 435 | 434 | ||
| 436 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | 435 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
| 437 | static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0); | 436 | static const DECLARE_TLV_DB_SCALE(atten_tlv, -600, 600, 0); |
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index d4248e00160e..7ac2e511403c 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c | |||
| @@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
| 944 | for (i = 0; i < pdata->num_mbc_cfgs; i++) | 944 | for (i = 0; i < pdata->num_mbc_cfgs; i++) |
| 945 | wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; | 945 | wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; |
| 946 | 946 | ||
| 947 | wm8994->mbc_enum.max = pdata->num_mbc_cfgs; | 947 | wm8994->mbc_enum.items = pdata->num_mbc_cfgs; |
| 948 | wm8994->mbc_enum.texts = wm8994->mbc_texts; | 948 | wm8994->mbc_enum.texts = wm8994->mbc_texts; |
| 949 | 949 | ||
| 950 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 950 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
| @@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
| 973 | for (i = 0; i < pdata->num_vss_cfgs; i++) | 973 | for (i = 0; i < pdata->num_vss_cfgs; i++) |
| 974 | wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; | 974 | wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; |
| 975 | 975 | ||
| 976 | wm8994->vss_enum.max = pdata->num_vss_cfgs; | 976 | wm8994->vss_enum.items = pdata->num_vss_cfgs; |
| 977 | wm8994->vss_enum.texts = wm8994->vss_texts; | 977 | wm8994->vss_enum.texts = wm8994->vss_texts; |
| 978 | 978 | ||
| 979 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 979 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
| @@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
| 1003 | for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) | 1003 | for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) |
| 1004 | wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; | 1004 | wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; |
| 1005 | 1005 | ||
| 1006 | wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; | 1006 | wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs; |
| 1007 | wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; | 1007 | wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; |
| 1008 | 1008 | ||
| 1009 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 1009 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
| @@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
| 1034 | for (i = 0; i < pdata->num_enh_eq_cfgs; i++) | 1034 | for (i = 0; i < pdata->num_enh_eq_cfgs; i++) |
| 1035 | wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; | 1035 | wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; |
| 1036 | 1036 | ||
| 1037 | wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; | 1037 | wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs; |
| 1038 | wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; | 1038 | wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; |
| 1039 | 1039 | ||
| 1040 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 1040 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 900328e28a15..ce8fa6e01cb4 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
| @@ -317,15 +317,15 @@ static const char *adc_hpf_text[] = { | |||
| 317 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3", | 317 | "Hi-fi", "Voice 1", "Voice 2", "Voice 3", |
| 318 | }; | 318 | }; |
| 319 | 319 | ||
| 320 | static const struct soc_enum adc_hpf = | 320 | static SOC_ENUM_SINGLE_DECL(adc_hpf, |
| 321 | SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_2, 7, 4, adc_hpf_text); | 321 | WM8961_ADC_DAC_CONTROL_2, 7, adc_hpf_text); |
| 322 | 322 | ||
| 323 | static const char *dac_deemph_text[] = { | 323 | static const char *dac_deemph_text[] = { |
| 324 | "None", "32kHz", "44.1kHz", "48kHz", | 324 | "None", "32kHz", "44.1kHz", "48kHz", |
| 325 | }; | 325 | }; |
| 326 | 326 | ||
| 327 | static const struct soc_enum dac_deemph = | 327 | static SOC_ENUM_SINGLE_DECL(dac_deemph, |
| 328 | SOC_ENUM_SINGLE(WM8961_ADC_DAC_CONTROL_1, 1, 4, dac_deemph_text); | 328 | WM8961_ADC_DAC_CONTROL_1, 1, dac_deemph_text); |
| 329 | 329 | ||
| 330 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); | 330 | static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1); |
| 331 | static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); | 331 | static const DECLARE_TLV_DB_SCALE(hp_sec_tlv, -700, 100, 0); |
| @@ -385,11 +385,11 @@ static const char *sidetone_text[] = { | |||
| 385 | "None", "Left", "Right" | 385 | "None", "Left", "Right" |
| 386 | }; | 386 | }; |
| 387 | 387 | ||
| 388 | static const struct soc_enum dacl_sidetone = | 388 | static SOC_ENUM_SINGLE_DECL(dacl_sidetone, |
| 389 | SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_0, 2, 3, sidetone_text); | 389 | WM8961_DSP_SIDETONE_0, 2, sidetone_text); |
| 390 | 390 | ||
| 391 | static const struct soc_enum dacr_sidetone = | 391 | static SOC_ENUM_SINGLE_DECL(dacr_sidetone, |
| 392 | SOC_ENUM_SINGLE(WM8961_DSP_SIDETONE_1, 2, 3, sidetone_text); | 392 | WM8961_DSP_SIDETONE_1, 2, sidetone_text); |
| 393 | 393 | ||
| 394 | static const struct snd_kcontrol_new dacl_mux = | 394 | static const struct snd_kcontrol_new dacl_mux = |
| 395 | SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone); | 395 | SOC_DAPM_ENUM("DACL Sidetone", dacl_sidetone); |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 97db3b45b411..62af9dc59fc5 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
| @@ -1479,7 +1479,9 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | |||
| 1479 | 1479 | ||
| 1480 | static int wm8962_dsp2_write_config(struct snd_soc_codec *codec) | 1480 | static int wm8962_dsp2_write_config(struct snd_soc_codec *codec) |
| 1481 | { | 1481 | { |
| 1482 | return regcache_sync_region(codec->control_data, | 1482 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
| 1483 | |||
| 1484 | return regcache_sync_region(wm8962->regmap, | ||
| 1483 | WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER); | 1485 | WM8962_HDBASS_AI_1, WM8962_MAX_REGISTER); |
| 1484 | } | 1486 | } |
| 1485 | 1487 | ||
| @@ -1658,16 +1660,16 @@ static const char *cap_hpf_mode_text[] = { | |||
| 1658 | "Hi-fi", "Application" | 1660 | "Hi-fi", "Application" |
| 1659 | }; | 1661 | }; |
| 1660 | 1662 | ||
| 1661 | static const struct soc_enum cap_hpf_mode = | 1663 | static SOC_ENUM_SINGLE_DECL(cap_hpf_mode, |
| 1662 | SOC_ENUM_SINGLE(WM8962_ADC_DAC_CONTROL_2, 10, 2, cap_hpf_mode_text); | 1664 | WM8962_ADC_DAC_CONTROL_2, 10, cap_hpf_mode_text); |
| 1663 | 1665 | ||
| 1664 | 1666 | ||
| 1665 | static const char *cap_lhpf_mode_text[] = { | 1667 | static const char *cap_lhpf_mode_text[] = { |
| 1666 | "LPF", "HPF" | 1668 | "LPF", "HPF" |
| 1667 | }; | 1669 | }; |
| 1668 | 1670 | ||
| 1669 | static const struct soc_enum cap_lhpf_mode = | 1671 | static SOC_ENUM_SINGLE_DECL(cap_lhpf_mode, |
| 1670 | SOC_ENUM_SINGLE(WM8962_LHPF1, 1, 2, cap_lhpf_mode_text); | 1672 | WM8962_LHPF1, 1, cap_lhpf_mode_text); |
| 1671 | 1673 | ||
| 1672 | static const struct snd_kcontrol_new wm8962_snd_controls[] = { | 1674 | static const struct snd_kcontrol_new wm8962_snd_controls[] = { |
| 1673 | SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1), | 1675 | SOC_DOUBLE("Input Mixer Switch", WM8962_INPUT_MIXER_CONTROL_1, 3, 2, 1, 1), |
| @@ -2014,40 +2016,40 @@ static int dsp2_event(struct snd_soc_dapm_widget *w, | |||
| 2014 | 2016 | ||
| 2015 | static const char *st_text[] = { "None", "Left", "Right" }; | 2017 | static const char *st_text[] = { "None", "Left", "Right" }; |
| 2016 | 2018 | ||
| 2017 | static const struct soc_enum str_enum = | 2019 | static SOC_ENUM_SINGLE_DECL(str_enum, |
| 2018 | SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_1, 2, 3, st_text); | 2020 | WM8962_DAC_DSP_MIXING_1, 2, st_text); |
| 2019 | 2021 | ||
| 2020 | static const struct snd_kcontrol_new str_mux = | 2022 | static const struct snd_kcontrol_new str_mux = |
| 2021 | SOC_DAPM_ENUM("Right Sidetone", str_enum); | 2023 | SOC_DAPM_ENUM("Right Sidetone", str_enum); |
| 2022 | 2024 | ||
| 2023 | static const struct soc_enum stl_enum = | 2025 | static SOC_ENUM_SINGLE_DECL(stl_enum, |
| 2024 | SOC_ENUM_SINGLE(WM8962_DAC_DSP_MIXING_2, 2, 3, st_text); | 2026 | WM8962_DAC_DSP_MIXING_2, 2, st_text); |
| 2025 | 2027 | ||
| 2026 | static const struct snd_kcontrol_new stl_mux = | 2028 | static const struct snd_kcontrol_new stl_mux = |
| 2027 | SOC_DAPM_ENUM("Left Sidetone", stl_enum); | 2029 | SOC_DAPM_ENUM("Left Sidetone", stl_enum); |
| 2028 | 2030 | ||
| 2029 | static const char *outmux_text[] = { "DAC", "Mixer" }; | 2031 | static const char *outmux_text[] = { "DAC", "Mixer" }; |
| 2030 | 2032 | ||
| 2031 | static const struct soc_enum spkoutr_enum = | 2033 | static SOC_ENUM_SINGLE_DECL(spkoutr_enum, |
| 2032 | SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_2, 7, 2, outmux_text); | 2034 | WM8962_SPEAKER_MIXER_2, 7, outmux_text); |
| 2033 | 2035 | ||
| 2034 | static const struct snd_kcontrol_new spkoutr_mux = | 2036 | static const struct snd_kcontrol_new spkoutr_mux = |
| 2035 | SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum); | 2037 | SOC_DAPM_ENUM("SPKOUTR Mux", spkoutr_enum); |
| 2036 | 2038 | ||
| 2037 | static const struct soc_enum spkoutl_enum = | 2039 | static SOC_ENUM_SINGLE_DECL(spkoutl_enum, |
| 2038 | SOC_ENUM_SINGLE(WM8962_SPEAKER_MIXER_1, 7, 2, outmux_text); | 2040 | WM8962_SPEAKER_MIXER_1, 7, outmux_text); |
| 2039 | 2041 | ||
| 2040 | static const struct snd_kcontrol_new spkoutl_mux = | 2042 | static const struct snd_kcontrol_new spkoutl_mux = |
| 2041 | SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum); | 2043 | SOC_DAPM_ENUM("SPKOUTL Mux", spkoutl_enum); |
| 2042 | 2044 | ||
| 2043 | static const struct soc_enum hpoutr_enum = | 2045 | static SOC_ENUM_SINGLE_DECL(hpoutr_enum, |
| 2044 | SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_2, 7, 2, outmux_text); | 2046 | WM8962_HEADPHONE_MIXER_2, 7, outmux_text); |
| 2045 | 2047 | ||
| 2046 | static const struct snd_kcontrol_new hpoutr_mux = | 2048 | static const struct snd_kcontrol_new hpoutr_mux = |
| 2047 | SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum); | 2049 | SOC_DAPM_ENUM("HPOUTR Mux", hpoutr_enum); |
| 2048 | 2050 | ||
| 2049 | static const struct soc_enum hpoutl_enum = | 2051 | static SOC_ENUM_SINGLE_DECL(hpoutl_enum, |
| 2050 | SOC_ENUM_SINGLE(WM8962_HEADPHONE_MIXER_1, 7, 2, outmux_text); | 2052 | WM8962_HEADPHONE_MIXER_1, 7, outmux_text); |
| 2051 | 2053 | ||
| 2052 | static const struct snd_kcontrol_new hpoutl_mux = | 2054 | static const struct snd_kcontrol_new hpoutl_mux = |
| 2053 | SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum); | 2055 | SOC_DAPM_ENUM("HPOUTL Mux", hpoutl_enum); |
| @@ -2884,9 +2886,13 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
| 2884 | snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda); | 2886 | snd_soc_write(codec, WM8962_FLL_CONTROL_7, fll_div.lambda); |
| 2885 | snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n); | 2887 | snd_soc_write(codec, WM8962_FLL_CONTROL_8, fll_div.n); |
| 2886 | 2888 | ||
| 2887 | try_wait_for_completion(&wm8962->fll_lock); | 2889 | reinit_completion(&wm8962->fll_lock); |
| 2888 | 2890 | ||
| 2889 | pm_runtime_get_sync(codec->dev); | 2891 | ret = pm_runtime_get_sync(codec->dev); |
| 2892 | if (ret < 0) { | ||
| 2893 | dev_err(codec->dev, "Failed to resume device: %d\n", ret); | ||
| 2894 | return ret; | ||
| 2895 | } | ||
| 2890 | 2896 | ||
| 2891 | snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, | 2897 | snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, |
| 2892 | WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | | 2898 | WM8962_FLL_FRAC | WM8962_FLL_REFCLK_SRC_MASK | |
| @@ -2894,8 +2900,6 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
| 2894 | 2900 | ||
| 2895 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); | 2901 | dev_dbg(codec->dev, "FLL configured for %dHz->%dHz\n", Fref, Fout); |
| 2896 | 2902 | ||
| 2897 | ret = 0; | ||
| 2898 | |||
| 2899 | /* This should be a massive overestimate but go even | 2903 | /* This should be a massive overestimate but go even |
| 2900 | * higher if we'll error out | 2904 | * higher if we'll error out |
| 2901 | */ | 2905 | */ |
| @@ -2909,14 +2913,17 @@ static int wm8962_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | |||
| 2909 | 2913 | ||
| 2910 | if (timeout == 0 && wm8962->irq) { | 2914 | if (timeout == 0 && wm8962->irq) { |
| 2911 | dev_err(codec->dev, "FLL lock timed out"); | 2915 | dev_err(codec->dev, "FLL lock timed out"); |
| 2912 | ret = -ETIMEDOUT; | 2916 | snd_soc_update_bits(codec, WM8962_FLL_CONTROL_1, |
| 2917 | WM8962_FLL_ENA, 0); | ||
| 2918 | pm_runtime_put(codec->dev); | ||
| 2919 | return -ETIMEDOUT; | ||
| 2913 | } | 2920 | } |
| 2914 | 2921 | ||
| 2915 | wm8962->fll_fref = Fref; | 2922 | wm8962->fll_fref = Fref; |
| 2916 | wm8962->fll_fout = Fout; | 2923 | wm8962->fll_fout = Fout; |
| 2917 | wm8962->fll_src = source; | 2924 | wm8962->fll_src = source; |
| 2918 | 2925 | ||
| 2919 | return ret; | 2926 | return 0; |
| 2920 | } | 2927 | } |
| 2921 | 2928 | ||
| 2922 | static int wm8962_mute(struct snd_soc_dai *dai, int mute) | 2929 | static int wm8962_mute(struct snd_soc_dai *dai, int mute) |
| @@ -3003,9 +3010,16 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3003 | unsigned int active; | 3010 | unsigned int active; |
| 3004 | int reg, ret; | 3011 | int reg, ret; |
| 3005 | 3012 | ||
| 3013 | ret = pm_runtime_get_sync(dev); | ||
| 3014 | if (ret < 0) { | ||
| 3015 | dev_err(dev, "Failed to resume: %d\n", ret); | ||
| 3016 | return IRQ_NONE; | ||
| 3017 | } | ||
| 3018 | |||
| 3006 | ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK, | 3019 | ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2_MASK, |
| 3007 | &mask); | 3020 | &mask); |
| 3008 | if (ret != 0) { | 3021 | if (ret != 0) { |
| 3022 | pm_runtime_put(dev); | ||
| 3009 | dev_err(dev, "Failed to read interrupt mask: %d\n", | 3023 | dev_err(dev, "Failed to read interrupt mask: %d\n", |
| 3010 | ret); | 3024 | ret); |
| 3011 | return IRQ_NONE; | 3025 | return IRQ_NONE; |
| @@ -3013,14 +3027,17 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3013 | 3027 | ||
| 3014 | ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active); | 3028 | ret = regmap_read(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, &active); |
| 3015 | if (ret != 0) { | 3029 | if (ret != 0) { |
| 3030 | pm_runtime_put(dev); | ||
| 3016 | dev_err(dev, "Failed to read interrupt: %d\n", ret); | 3031 | dev_err(dev, "Failed to read interrupt: %d\n", ret); |
| 3017 | return IRQ_NONE; | 3032 | return IRQ_NONE; |
| 3018 | } | 3033 | } |
| 3019 | 3034 | ||
| 3020 | active &= ~mask; | 3035 | active &= ~mask; |
| 3021 | 3036 | ||
| 3022 | if (!active) | 3037 | if (!active) { |
| 3038 | pm_runtime_put(dev); | ||
| 3023 | return IRQ_NONE; | 3039 | return IRQ_NONE; |
| 3040 | } | ||
| 3024 | 3041 | ||
| 3025 | /* Acknowledge the interrupts */ | 3042 | /* Acknowledge the interrupts */ |
| 3026 | ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active); | 3043 | ret = regmap_write(wm8962->regmap, WM8962_INTERRUPT_STATUS_2, active); |
| @@ -3070,6 +3087,8 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3070 | msecs_to_jiffies(250)); | 3087 | msecs_to_jiffies(250)); |
| 3071 | } | 3088 | } |
| 3072 | 3089 | ||
| 3090 | pm_runtime_put(dev); | ||
| 3091 | |||
| 3073 | return IRQ_HANDLED; | 3092 | return IRQ_HANDLED; |
| 3074 | } | 3093 | } |
| 3075 | 3094 | ||
| @@ -3089,6 +3108,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
| 3089 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 3108 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
| 3090 | { | 3109 | { |
| 3091 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3110 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
| 3111 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 3092 | int irq_mask, enable; | 3112 | int irq_mask, enable; |
| 3093 | 3113 | ||
| 3094 | wm8962->jack = jack; | 3114 | wm8962->jack = jack; |
| @@ -3109,14 +3129,18 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
| 3109 | snd_soc_jack_report(wm8962->jack, 0, | 3129 | snd_soc_jack_report(wm8962->jack, 0, |
| 3110 | SND_JACK_MICROPHONE | SND_JACK_BTN_0); | 3130 | SND_JACK_MICROPHONE | SND_JACK_BTN_0); |
| 3111 | 3131 | ||
| 3132 | snd_soc_dapm_mutex_lock(dapm); | ||
| 3133 | |||
| 3112 | if (jack) { | 3134 | if (jack) { |
| 3113 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 3135 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); |
| 3114 | snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); | 3136 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); |
| 3115 | } else { | 3137 | } else { |
| 3116 | snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK"); | 3138 | snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK"); |
| 3117 | snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); | 3139 | snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); |
| 3118 | } | 3140 | } |
| 3119 | 3141 | ||
| 3142 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 3143 | |||
| 3120 | return 0; | 3144 | return 0; |
| 3121 | } | 3145 | } |
| 3122 | EXPORT_SYMBOL_GPL(wm8962_mic_detect); | 3146 | EXPORT_SYMBOL_GPL(wm8962_mic_detect); |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 15f45c7bd833..6e16c4306461 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
| @@ -84,8 +84,8 @@ static const struct soc_enum wm8974_enum[] = { | |||
| 84 | 84 | ||
| 85 | static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" }; | 85 | static const char *wm8974_auxmode_text[] = { "Buffer", "Mixer" }; |
| 86 | 86 | ||
| 87 | static const struct soc_enum wm8974_auxmode = | 87 | static SOC_ENUM_SINGLE_DECL(wm8974_auxmode, |
| 88 | SOC_ENUM_SINGLE(WM8974_INPUT, 3, 2, wm8974_auxmode_text); | 88 | WM8974_INPUT, 3, wm8974_auxmode_text); |
| 89 | 89 | ||
| 90 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | 90 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
| 91 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 91 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d8fc531c0e59..a9e2f465c331 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
| @@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"}; | |||
| 117 | static const char *wm8978_alc3[] = {"ALC", "Limiter"}; | 117 | static const char *wm8978_alc3[] = {"ALC", "Limiter"}; |
| 118 | static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; | 118 | static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; |
| 119 | 119 | ||
| 120 | static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, | 120 | static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, |
| 121 | wm8978_companding); | 121 | wm8978_companding); |
| 122 | static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, | 122 | static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, |
| 123 | wm8978_companding); | 123 | wm8978_companding); |
| 124 | static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); | 124 | static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); |
| 125 | static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); | 125 | static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); |
| 126 | static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); | 126 | static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); |
| 127 | static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); | 127 | static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); |
| 128 | static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); | 128 | static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); |
| 129 | static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); | 129 | static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); |
| 130 | static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); | 130 | static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); |
| 131 | static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); | 131 | static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); |
| 132 | static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); | 132 | static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); |
| 133 | static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); | 133 | static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); |
| 134 | static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); | 134 | static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); |
| 135 | 135 | ||
| 136 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | 136 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
| 137 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 137 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index aa41ba0dfff4..58f0551eed2d 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c | |||
| @@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | |||
| 205 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); | 205 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); |
| 206 | 206 | ||
| 207 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; | 207 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; |
| 208 | static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, | 208 | static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text); |
| 209 | alc_sel_text); | ||
| 210 | 209 | ||
| 211 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; | 210 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; |
| 212 | static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, | 211 | static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text); |
| 213 | alc_mode_text); | ||
| 214 | 212 | ||
| 215 | static const char *filter_mode_text[] = { "Audio", "Application" }; | 213 | static const char *filter_mode_text[] = { "Audio", "Application" }; |
| 216 | static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, | 214 | static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, |
| 217 | filter_mode_text); | 215 | filter_mode_text); |
| 218 | 216 | ||
| 219 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; | 217 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; |
| 220 | static const char *eqmode_text[] = { "Capture", "Playback" }; | 218 | static const char *eqmode_text[] = { "Capture", "Playback" }; |
| 221 | static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); | 219 | static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); |
| 222 | 220 | ||
| 223 | static const char *eq1_cutoff_text[] = { | 221 | static const char *eq1_cutoff_text[] = { |
| 224 | "80Hz", "105Hz", "135Hz", "175Hz" | 222 | "80Hz", "105Hz", "135Hz", "175Hz" |
| 225 | }; | 223 | }; |
| 226 | static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, | 224 | static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, |
| 227 | eq1_cutoff_text); | 225 | eq1_cutoff_text); |
| 228 | static const char *eq2_cutoff_text[] = { | 226 | static const char *eq2_cutoff_text[] = { |
| 229 | "230Hz", "300Hz", "385Hz", "500Hz" | 227 | "230Hz", "300Hz", "385Hz", "500Hz" |
| 230 | }; | 228 | }; |
| 231 | static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); | 229 | static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); |
| 232 | static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, | 230 | static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text); |
| 233 | eq2_cutoff_text); | ||
| 234 | static const char *eq3_cutoff_text[] = { | 231 | static const char *eq3_cutoff_text[] = { |
| 235 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" | 232 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" |
| 236 | }; | 233 | }; |
| 237 | static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); | 234 | static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); |
| 238 | static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, | 235 | static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text); |
| 239 | eq3_cutoff_text); | ||
| 240 | static const char *eq4_cutoff_text[] = { | 236 | static const char *eq4_cutoff_text[] = { |
| 241 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" | 237 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" |
| 242 | }; | 238 | }; |
| 243 | static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); | 239 | static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); |
| 244 | static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, | 240 | static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text); |
| 245 | eq4_cutoff_text); | ||
| 246 | static const char *eq5_cutoff_text[] = { | 241 | static const char *eq5_cutoff_text[] = { |
| 247 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" | 242 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" |
| 248 | }; | 243 | }; |
| 249 | static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, | 244 | static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, |
| 250 | eq5_cutoff_text); | 245 | eq5_cutoff_text); |
| 251 | 246 | ||
| 252 | static const char *depth_3d_text[] = { | 247 | static const char *depth_3d_text[] = { |
| 253 | "Off", | 248 | "Off", |
| @@ -267,8 +262,8 @@ static const char *depth_3d_text[] = { | |||
| 267 | "93.3%", | 262 | "93.3%", |
| 268 | "100%" | 263 | "100%" |
| 269 | }; | 264 | }; |
| 270 | static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, | 265 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, |
| 271 | depth_3d_text); | 266 | depth_3d_text); |
| 272 | 267 | ||
| 273 | static const struct snd_kcontrol_new wm8983_snd_controls[] = { | 268 | static const struct snd_kcontrol_new wm8983_snd_controls[] = { |
| 274 | SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, | 269 | SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, |
| @@ -1129,7 +1124,7 @@ static struct spi_driver wm8983_spi_driver = { | |||
| 1129 | }; | 1124 | }; |
| 1130 | #endif | 1125 | #endif |
| 1131 | 1126 | ||
| 1132 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1127 | #if IS_ENABLED(CONFIG_I2C) |
| 1133 | static int wm8983_i2c_probe(struct i2c_client *i2c, | 1128 | static int wm8983_i2c_probe(struct i2c_client *i2c, |
| 1134 | const struct i2c_device_id *id) | 1129 | const struct i2c_device_id *id) |
| 1135 | { | 1130 | { |
| @@ -1182,7 +1177,7 @@ static int __init wm8983_modinit(void) | |||
| 1182 | { | 1177 | { |
| 1183 | int ret = 0; | 1178 | int ret = 0; |
| 1184 | 1179 | ||
| 1185 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1180 | #if IS_ENABLED(CONFIG_I2C) |
| 1186 | ret = i2c_add_driver(&wm8983_i2c_driver); | 1181 | ret = i2c_add_driver(&wm8983_i2c_driver); |
| 1187 | if (ret) { | 1182 | if (ret) { |
| 1188 | printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n", | 1183 | printk(KERN_ERR "Failed to register wm8983 I2C driver: %d\n", |
| @@ -1202,7 +1197,7 @@ module_init(wm8983_modinit); | |||
| 1202 | 1197 | ||
| 1203 | static void __exit wm8983_exit(void) | 1198 | static void __exit wm8983_exit(void) |
| 1204 | { | 1199 | { |
| 1205 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1200 | #if IS_ENABLED(CONFIG_I2C) |
| 1206 | i2c_del_driver(&wm8983_i2c_driver); | 1201 | i2c_del_driver(&wm8983_i2c_driver); |
| 1207 | #endif | 1202 | #endif |
| 1208 | #if defined(CONFIG_SPI_MASTER) | 1203 | #if defined(CONFIG_SPI_MASTER) |
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 271b517911a4..d786f2b39764 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
| @@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | |||
| 226 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); | 226 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); |
| 227 | 227 | ||
| 228 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; | 228 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; |
| 229 | static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, | 229 | static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text); |
| 230 | alc_sel_text); | ||
| 231 | 230 | ||
| 232 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; | 231 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; |
| 233 | static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, | 232 | static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text); |
| 234 | alc_mode_text); | ||
| 235 | 233 | ||
| 236 | static const char *filter_mode_text[] = { "Audio", "Application" }; | 234 | static const char *filter_mode_text[] = { "Audio", "Application" }; |
| 237 | static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, | 235 | static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, |
| 238 | filter_mode_text); | 236 | filter_mode_text); |
| 239 | 237 | ||
| 240 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; | 238 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; |
| 241 | static const char *eqmode_text[] = { "Capture", "Playback" }; | 239 | static const char *eqmode_text[] = { "Capture", "Playback" }; |
| 242 | static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); | 240 | static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); |
| 243 | 241 | ||
| 244 | static const char *eq1_cutoff_text[] = { | 242 | static const char *eq1_cutoff_text[] = { |
| 245 | "80Hz", "105Hz", "135Hz", "175Hz" | 243 | "80Hz", "105Hz", "135Hz", "175Hz" |
| 246 | }; | 244 | }; |
| 247 | static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, | 245 | static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, |
| 248 | eq1_cutoff_text); | 246 | eq1_cutoff_text); |
| 249 | static const char *eq2_cutoff_text[] = { | 247 | static const char *eq2_cutoff_text[] = { |
| 250 | "230Hz", "300Hz", "385Hz", "500Hz" | 248 | "230Hz", "300Hz", "385Hz", "500Hz" |
| 251 | }; | 249 | }; |
| 252 | static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); | 250 | static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); |
| 253 | static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, | 251 | static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text); |
| 254 | eq2_cutoff_text); | ||
| 255 | static const char *eq3_cutoff_text[] = { | 252 | static const char *eq3_cutoff_text[] = { |
| 256 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" | 253 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" |
| 257 | }; | 254 | }; |
| 258 | static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); | 255 | static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); |
| 259 | static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, | 256 | static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, |
| 260 | eq3_cutoff_text); | 257 | eq3_cutoff_text); |
| 261 | static const char *eq4_cutoff_text[] = { | 258 | static const char *eq4_cutoff_text[] = { |
| 262 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" | 259 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" |
| 263 | }; | 260 | }; |
| 264 | static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); | 261 | static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); |
| 265 | static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, | 262 | static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text); |
| 266 | eq4_cutoff_text); | ||
| 267 | static const char *eq5_cutoff_text[] = { | 263 | static const char *eq5_cutoff_text[] = { |
| 268 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" | 264 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" |
| 269 | }; | 265 | }; |
| 270 | static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, | 266 | static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, |
| 271 | eq5_cutoff_text); | 267 | eq5_cutoff_text); |
| 272 | 268 | ||
| 273 | static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; | 269 | static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; |
| 274 | static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); | 270 | static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); |
| 275 | 271 | ||
| 276 | static const char *depth_3d_text[] = { | 272 | static const char *depth_3d_text[] = { |
| 277 | "Off", | 273 | "Off", |
| @@ -291,8 +287,7 @@ static const char *depth_3d_text[] = { | |||
| 291 | "93.3%", | 287 | "93.3%", |
| 292 | "100%" | 288 | "100%" |
| 293 | }; | 289 | }; |
| 294 | static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, | 290 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text); |
| 295 | depth_3d_text); | ||
| 296 | 291 | ||
| 297 | static const struct snd_kcontrol_new wm8985_snd_controls[] = { | 292 | static const struct snd_kcontrol_new wm8985_snd_controls[] = { |
| 298 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, | 293 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, |
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index a55e1c2c382e..0277a76c6bef 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
| @@ -116,7 +116,7 @@ static bool wm8988_writeable(struct device *dev, unsigned int reg) | |||
| 116 | struct wm8988_priv { | 116 | struct wm8988_priv { |
| 117 | struct regmap *regmap; | 117 | struct regmap *regmap; |
| 118 | unsigned int sysclk; | 118 | unsigned int sysclk; |
| 119 | struct snd_pcm_hw_constraint_list *sysclk_constraints; | 119 | const struct snd_pcm_hw_constraint_list *sysclk_constraints; |
| 120 | }; | 120 | }; |
| 121 | 121 | ||
| 122 | #define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) | 122 | #define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) |
| @@ -126,46 +126,46 @@ struct wm8988_priv { | |||
| 126 | */ | 126 | */ |
| 127 | 127 | ||
| 128 | static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; | 128 | static const char *bass_boost_txt[] = {"Linear Control", "Adaptive Boost"}; |
| 129 | static const struct soc_enum bass_boost = | 129 | static SOC_ENUM_SINGLE_DECL(bass_boost, |
| 130 | SOC_ENUM_SINGLE(WM8988_BASS, 7, 2, bass_boost_txt); | 130 | WM8988_BASS, 7, bass_boost_txt); |
| 131 | 131 | ||
| 132 | static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; | 132 | static const char *bass_filter_txt[] = { "130Hz @ 48kHz", "200Hz @ 48kHz" }; |
| 133 | static const struct soc_enum bass_filter = | 133 | static SOC_ENUM_SINGLE_DECL(bass_filter, |
| 134 | SOC_ENUM_SINGLE(WM8988_BASS, 6, 2, bass_filter_txt); | 134 | WM8988_BASS, 6, bass_filter_txt); |
| 135 | 135 | ||
| 136 | static const char *treble_txt[] = {"8kHz", "4kHz"}; | 136 | static const char *treble_txt[] = {"8kHz", "4kHz"}; |
| 137 | static const struct soc_enum treble = | 137 | static SOC_ENUM_SINGLE_DECL(treble, |
| 138 | SOC_ENUM_SINGLE(WM8988_TREBLE, 6, 2, treble_txt); | 138 | WM8988_TREBLE, 6, treble_txt); |
| 139 | 139 | ||
| 140 | static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; | 140 | static const char *stereo_3d_lc_txt[] = {"200Hz", "500Hz"}; |
| 141 | static const struct soc_enum stereo_3d_lc = | 141 | static SOC_ENUM_SINGLE_DECL(stereo_3d_lc, |
| 142 | SOC_ENUM_SINGLE(WM8988_3D, 5, 2, stereo_3d_lc_txt); | 142 | WM8988_3D, 5, stereo_3d_lc_txt); |
| 143 | 143 | ||
| 144 | static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; | 144 | static const char *stereo_3d_uc_txt[] = {"2.2kHz", "1.5kHz"}; |
| 145 | static const struct soc_enum stereo_3d_uc = | 145 | static SOC_ENUM_SINGLE_DECL(stereo_3d_uc, |
| 146 | SOC_ENUM_SINGLE(WM8988_3D, 6, 2, stereo_3d_uc_txt); | 146 | WM8988_3D, 6, stereo_3d_uc_txt); |
| 147 | 147 | ||
| 148 | static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; | 148 | static const char *stereo_3d_func_txt[] = {"Capture", "Playback"}; |
| 149 | static const struct soc_enum stereo_3d_func = | 149 | static SOC_ENUM_SINGLE_DECL(stereo_3d_func, |
| 150 | SOC_ENUM_SINGLE(WM8988_3D, 7, 2, stereo_3d_func_txt); | 150 | WM8988_3D, 7, stereo_3d_func_txt); |
| 151 | 151 | ||
| 152 | static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; | 152 | static const char *alc_func_txt[] = {"Off", "Right", "Left", "Stereo"}; |
| 153 | static const struct soc_enum alc_func = | 153 | static SOC_ENUM_SINGLE_DECL(alc_func, |
| 154 | SOC_ENUM_SINGLE(WM8988_ALC1, 7, 4, alc_func_txt); | 154 | WM8988_ALC1, 7, alc_func_txt); |
| 155 | 155 | ||
| 156 | static const char *ng_type_txt[] = {"Constant PGA Gain", | 156 | static const char *ng_type_txt[] = {"Constant PGA Gain", |
| 157 | "Mute ADC Output"}; | 157 | "Mute ADC Output"}; |
| 158 | static const struct soc_enum ng_type = | 158 | static SOC_ENUM_SINGLE_DECL(ng_type, |
| 159 | SOC_ENUM_SINGLE(WM8988_NGATE, 1, 2, ng_type_txt); | 159 | WM8988_NGATE, 1, ng_type_txt); |
| 160 | 160 | ||
| 161 | static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 161 | static const char *deemph_txt[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
| 162 | static const struct soc_enum deemph = | 162 | static SOC_ENUM_SINGLE_DECL(deemph, |
| 163 | SOC_ENUM_SINGLE(WM8988_ADCDAC, 1, 4, deemph_txt); | 163 | WM8988_ADCDAC, 1, deemph_txt); |
| 164 | 164 | ||
| 165 | static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert", | 165 | static const char *adcpol_txt[] = {"Normal", "L Invert", "R Invert", |
| 166 | "L + R Invert"}; | 166 | "L + R Invert"}; |
| 167 | static const struct soc_enum adcpol = | 167 | static SOC_ENUM_SINGLE_DECL(adcpol, |
| 168 | SOC_ENUM_SINGLE(WM8988_ADCDAC, 5, 4, adcpol_txt); | 168 | WM8988_ADCDAC, 5, adcpol_txt); |
| 169 | 169 | ||
| 170 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); | 170 | static const DECLARE_TLV_DB_SCALE(pga_tlv, -1725, 75, 0); |
| 171 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); | 171 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9750, 50, 1); |
| @@ -317,16 +317,16 @@ static const struct snd_kcontrol_new wm8988_right_pga_controls = | |||
| 317 | 317 | ||
| 318 | /* Differential Mux */ | 318 | /* Differential Mux */ |
| 319 | static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; | 319 | static const char *wm8988_diff_sel[] = {"Line 1", "Line 2"}; |
| 320 | static const struct soc_enum diffmux = | 320 | static SOC_ENUM_SINGLE_DECL(diffmux, |
| 321 | SOC_ENUM_SINGLE(WM8988_ADCIN, 8, 2, wm8988_diff_sel); | 321 | WM8988_ADCIN, 8, wm8988_diff_sel); |
| 322 | static const struct snd_kcontrol_new wm8988_diffmux_controls = | 322 | static const struct snd_kcontrol_new wm8988_diffmux_controls = |
| 323 | SOC_DAPM_ENUM("Route", diffmux); | 323 | SOC_DAPM_ENUM("Route", diffmux); |
| 324 | 324 | ||
| 325 | /* Mono ADC Mux */ | 325 | /* Mono ADC Mux */ |
| 326 | static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)", | 326 | static const char *wm8988_mono_mux[] = {"Stereo", "Mono (Left)", |
| 327 | "Mono (Right)", "Digital Mono"}; | 327 | "Mono (Right)", "Digital Mono"}; |
| 328 | static const struct soc_enum monomux = | 328 | static SOC_ENUM_SINGLE_DECL(monomux, |
| 329 | SOC_ENUM_SINGLE(WM8988_ADCIN, 6, 4, wm8988_mono_mux); | 329 | WM8988_ADCIN, 6, wm8988_mono_mux); |
| 330 | static const struct snd_kcontrol_new wm8988_monomux_controls = | 330 | static const struct snd_kcontrol_new wm8988_monomux_controls = |
| 331 | SOC_DAPM_ENUM("Route", monomux); | 331 | SOC_DAPM_ENUM("Route", monomux); |
| 332 | 332 | ||
| @@ -521,30 +521,30 @@ static inline int get_coeff(int mclk, int rate) | |||
| 521 | 521 | ||
| 522 | /* The set of rates we can generate from the above for each SYSCLK */ | 522 | /* The set of rates we can generate from the above for each SYSCLK */ |
| 523 | 523 | ||
| 524 | static unsigned int rates_12288[] = { | 524 | static const unsigned int rates_12288[] = { |
| 525 | 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, | 525 | 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000, |
| 526 | }; | 526 | }; |
| 527 | 527 | ||
| 528 | static struct snd_pcm_hw_constraint_list constraints_12288 = { | 528 | static const struct snd_pcm_hw_constraint_list constraints_12288 = { |
| 529 | .count = ARRAY_SIZE(rates_12288), | 529 | .count = ARRAY_SIZE(rates_12288), |
| 530 | .list = rates_12288, | 530 | .list = rates_12288, |
| 531 | }; | 531 | }; |
| 532 | 532 | ||
| 533 | static unsigned int rates_112896[] = { | 533 | static const unsigned int rates_112896[] = { |
| 534 | 8000, 11025, 22050, 44100, | 534 | 8000, 11025, 22050, 44100, |
| 535 | }; | 535 | }; |
| 536 | 536 | ||
| 537 | static struct snd_pcm_hw_constraint_list constraints_112896 = { | 537 | static const struct snd_pcm_hw_constraint_list constraints_112896 = { |
| 538 | .count = ARRAY_SIZE(rates_112896), | 538 | .count = ARRAY_SIZE(rates_112896), |
| 539 | .list = rates_112896, | 539 | .list = rates_112896, |
| 540 | }; | 540 | }; |
| 541 | 541 | ||
| 542 | static unsigned int rates_12[] = { | 542 | static const unsigned int rates_12[] = { |
| 543 | 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000, | 543 | 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000, |
| 544 | 48000, 88235, 96000, | 544 | 48000, 88235, 96000, |
| 545 | }; | 545 | }; |
| 546 | 546 | ||
| 547 | static struct snd_pcm_hw_constraint_list constraints_12 = { | 547 | static const struct snd_pcm_hw_constraint_list constraints_12 = { |
| 548 | .count = ARRAY_SIZE(rates_12), | 548 | .count = ARRAY_SIZE(rates_12), |
| 549 | .list = rates_12, | 549 | .list = rates_12, |
| 550 | }; | 550 | }; |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 0ccd4d8d043b..33f53ab1e7b0 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
| @@ -157,26 +157,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | |||
| 157 | static const char *wm8990_digital_sidetone[] = | 157 | static const char *wm8990_digital_sidetone[] = |
| 158 | {"None", "Left ADC", "Right ADC", "Reserved"}; | 158 | {"None", "Left ADC", "Right ADC", "Reserved"}; |
| 159 | 159 | ||
| 160 | static const struct soc_enum wm8990_left_digital_sidetone_enum = | 160 | static SOC_ENUM_SINGLE_DECL(wm8990_left_digital_sidetone_enum, |
| 161 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | 161 | WM8990_DIGITAL_SIDE_TONE, |
| 162 | WM8990_ADC_TO_DACL_SHIFT, | 162 | WM8990_ADC_TO_DACL_SHIFT, |
| 163 | WM8990_ADC_TO_DACL_MASK, | 163 | wm8990_digital_sidetone); |
| 164 | wm8990_digital_sidetone); | 164 | |
| 165 | 165 | static SOC_ENUM_SINGLE_DECL(wm8990_right_digital_sidetone_enum, | |
| 166 | static const struct soc_enum wm8990_right_digital_sidetone_enum = | 166 | WM8990_DIGITAL_SIDE_TONE, |
| 167 | SOC_ENUM_SINGLE(WM8990_DIGITAL_SIDE_TONE, | 167 | WM8990_ADC_TO_DACR_SHIFT, |
| 168 | WM8990_ADC_TO_DACR_SHIFT, | 168 | wm8990_digital_sidetone); |
| 169 | WM8990_ADC_TO_DACR_MASK, | ||
| 170 | wm8990_digital_sidetone); | ||
| 171 | 169 | ||
| 172 | static const char *wm8990_adcmode[] = | 170 | static const char *wm8990_adcmode[] = |
| 173 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | 171 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; |
| 174 | 172 | ||
| 175 | static const struct soc_enum wm8990_right_adcmode_enum = | 173 | static SOC_ENUM_SINGLE_DECL(wm8990_right_adcmode_enum, |
| 176 | SOC_ENUM_SINGLE(WM8990_ADC_CTRL, | 174 | WM8990_ADC_CTRL, |
| 177 | WM8990_ADC_HPF_CUT_SHIFT, | 175 | WM8990_ADC_HPF_CUT_SHIFT, |
| 178 | WM8990_ADC_HPF_CUT_MASK, | 176 | wm8990_adcmode); |
| 179 | wm8990_adcmode); | ||
| 180 | 177 | ||
| 181 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { | 178 | static const struct snd_kcontrol_new wm8990_snd_controls[] = { |
| 182 | /* INMIXL */ | 179 | /* INMIXL */ |
| @@ -475,9 +472,9 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8990_INPUT_MIXER3, WM8990_L34MNB_BIT, | |||
| 475 | static const char *wm8990_ainlmux[] = | 472 | static const char *wm8990_ainlmux[] = |
| 476 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | 473 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; |
| 477 | 474 | ||
| 478 | static const struct soc_enum wm8990_ainlmux_enum = | 475 | static SOC_ENUM_SINGLE_DECL(wm8990_ainlmux_enum, |
| 479 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, | 476 | WM8990_INPUT_MIXER1, WM8990_AINLMODE_SHIFT, |
| 480 | ARRAY_SIZE(wm8990_ainlmux), wm8990_ainlmux); | 477 | wm8990_ainlmux); |
| 481 | 478 | ||
| 482 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = | 479 | static const struct snd_kcontrol_new wm8990_dapm_ainlmux_controls = |
| 483 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | 480 | SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); |
| @@ -488,9 +485,9 @@ SOC_DAPM_ENUM("Route", wm8990_ainlmux_enum); | |||
| 488 | static const char *wm8990_ainrmux[] = | 485 | static const char *wm8990_ainrmux[] = |
| 489 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | 486 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; |
| 490 | 487 | ||
| 491 | static const struct soc_enum wm8990_ainrmux_enum = | 488 | static SOC_ENUM_SINGLE_DECL(wm8990_ainrmux_enum, |
| 492 | SOC_ENUM_SINGLE(WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, | 489 | WM8990_INPUT_MIXER1, WM8990_AINRMODE_SHIFT, |
| 493 | ARRAY_SIZE(wm8990_ainrmux), wm8990_ainrmux); | 490 | wm8990_ainrmux); |
| 494 | 491 | ||
| 495 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = | 492 | static const struct snd_kcontrol_new wm8990_dapm_ainrmux_controls = |
| 496 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); | 493 | SOC_DAPM_ENUM("Route", wm8990_ainrmux_enum); |
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index dba0306c42a5..32d219570cca 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c | |||
| @@ -171,26 +171,23 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | |||
| 171 | static const char *wm8991_digital_sidetone[] = | 171 | static const char *wm8991_digital_sidetone[] = |
| 172 | {"None", "Left ADC", "Right ADC", "Reserved"}; | 172 | {"None", "Left ADC", "Right ADC", "Reserved"}; |
| 173 | 173 | ||
| 174 | static const struct soc_enum wm8991_left_digital_sidetone_enum = | 174 | static SOC_ENUM_SINGLE_DECL(wm8991_left_digital_sidetone_enum, |
| 175 | SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, | 175 | WM8991_DIGITAL_SIDE_TONE, |
| 176 | WM8991_ADC_TO_DACL_SHIFT, | 176 | WM8991_ADC_TO_DACL_SHIFT, |
| 177 | WM8991_ADC_TO_DACL_MASK, | 177 | wm8991_digital_sidetone); |
| 178 | wm8991_digital_sidetone); | 178 | |
| 179 | 179 | static SOC_ENUM_SINGLE_DECL(wm8991_right_digital_sidetone_enum, | |
| 180 | static const struct soc_enum wm8991_right_digital_sidetone_enum = | 180 | WM8991_DIGITAL_SIDE_TONE, |
| 181 | SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, | 181 | WM8991_ADC_TO_DACR_SHIFT, |
| 182 | WM8991_ADC_TO_DACR_SHIFT, | 182 | wm8991_digital_sidetone); |
| 183 | WM8991_ADC_TO_DACR_MASK, | ||
| 184 | wm8991_digital_sidetone); | ||
| 185 | 183 | ||
| 186 | static const char *wm8991_adcmode[] = | 184 | static const char *wm8991_adcmode[] = |
| 187 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | 185 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; |
| 188 | 186 | ||
| 189 | static const struct soc_enum wm8991_right_adcmode_enum = | 187 | static SOC_ENUM_SINGLE_DECL(wm8991_right_adcmode_enum, |
| 190 | SOC_ENUM_SINGLE(WM8991_ADC_CTRL, | 188 | WM8991_ADC_CTRL, |
| 191 | WM8991_ADC_HPF_CUT_SHIFT, | 189 | WM8991_ADC_HPF_CUT_SHIFT, |
| 192 | WM8991_ADC_HPF_CUT_MASK, | 190 | wm8991_adcmode); |
| 193 | wm8991_adcmode); | ||
| 194 | 191 | ||
| 195 | static const struct snd_kcontrol_new wm8991_snd_controls[] = { | 192 | static const struct snd_kcontrol_new wm8991_snd_controls[] = { |
| 196 | /* INMIXL */ | 193 | /* INMIXL */ |
| @@ -486,9 +483,9 @@ static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = { | |||
| 486 | static const char *wm8991_ainlmux[] = | 483 | static const char *wm8991_ainlmux[] = |
| 487 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | 484 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; |
| 488 | 485 | ||
| 489 | static const struct soc_enum wm8991_ainlmux_enum = | 486 | static SOC_ENUM_SINGLE_DECL(wm8991_ainlmux_enum, |
| 490 | SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT, | 487 | WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT, |
| 491 | ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux); | 488 | wm8991_ainlmux); |
| 492 | 489 | ||
| 493 | static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls = | 490 | static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls = |
| 494 | SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum); | 491 | SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum); |
| @@ -499,9 +496,9 @@ static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls = | |||
| 499 | static const char *wm8991_ainrmux[] = | 496 | static const char *wm8991_ainrmux[] = |
| 500 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | 497 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; |
| 501 | 498 | ||
| 502 | static const struct soc_enum wm8991_ainrmux_enum = | 499 | static SOC_ENUM_SINGLE_DECL(wm8991_ainrmux_enum, |
| 503 | SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT, | 500 | WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT, |
| 504 | ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux); | 501 | wm8991_ainrmux); |
| 505 | 502 | ||
| 506 | static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls = | 503 | static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls = |
| 507 | SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum); | 504 | SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum); |
| @@ -1251,11 +1248,8 @@ static int wm8991_remove(struct snd_soc_codec *codec) | |||
| 1251 | 1248 | ||
| 1252 | static int wm8991_probe(struct snd_soc_codec *codec) | 1249 | static int wm8991_probe(struct snd_soc_codec *codec) |
| 1253 | { | 1250 | { |
| 1254 | struct wm8991_priv *wm8991; | ||
| 1255 | int ret; | 1251 | int ret; |
| 1256 | 1252 | ||
| 1257 | wm8991 = snd_soc_codec_get_drvdata(codec); | ||
| 1258 | |||
| 1259 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); | 1253 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); |
| 1260 | if (ret < 0) { | 1254 | if (ret < 0) { |
| 1261 | dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); | 1255 | dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 2ee23a39622c..7b0630a076fa 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
| @@ -646,8 +646,8 @@ static const char *dac_deemph_text[] = { | |||
| 646 | "48kHz", | 646 | "48kHz", |
| 647 | }; | 647 | }; |
| 648 | 648 | ||
| 649 | static const struct soc_enum dac_deemph = | 649 | static SOC_ENUM_SINGLE_DECL(dac_deemph, |
| 650 | SOC_ENUM_SINGLE(WM8993_DAC_CTRL, 4, 4, dac_deemph_text); | 650 | WM8993_DAC_CTRL, 4, dac_deemph_text); |
| 651 | 651 | ||
| 652 | static const char *adc_hpf_text[] = { | 652 | static const char *adc_hpf_text[] = { |
| 653 | "Hi-Fi", | 653 | "Hi-Fi", |
| @@ -656,16 +656,16 @@ static const char *adc_hpf_text[] = { | |||
| 656 | "Voice 3", | 656 | "Voice 3", |
| 657 | }; | 657 | }; |
| 658 | 658 | ||
| 659 | static const struct soc_enum adc_hpf = | 659 | static SOC_ENUM_SINGLE_DECL(adc_hpf, |
| 660 | SOC_ENUM_SINGLE(WM8993_ADC_CTRL, 5, 4, adc_hpf_text); | 660 | WM8993_ADC_CTRL, 5, adc_hpf_text); |
| 661 | 661 | ||
| 662 | static const char *drc_path_text[] = { | 662 | static const char *drc_path_text[] = { |
| 663 | "ADC", | 663 | "ADC", |
| 664 | "DAC" | 664 | "DAC" |
| 665 | }; | 665 | }; |
| 666 | 666 | ||
| 667 | static const struct soc_enum drc_path = | 667 | static SOC_ENUM_SINGLE_DECL(drc_path, |
| 668 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 14, 2, drc_path_text); | 668 | WM8993_DRC_CONTROL_1, 14, drc_path_text); |
| 669 | 669 | ||
| 670 | static const char *drc_r0_text[] = { | 670 | static const char *drc_r0_text[] = { |
| 671 | "1", | 671 | "1", |
| @@ -676,8 +676,8 @@ static const char *drc_r0_text[] = { | |||
| 676 | "0", | 676 | "0", |
| 677 | }; | 677 | }; |
| 678 | 678 | ||
| 679 | static const struct soc_enum drc_r0 = | 679 | static SOC_ENUM_SINGLE_DECL(drc_r0, |
| 680 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 8, 6, drc_r0_text); | 680 | WM8993_DRC_CONTROL_3, 8, drc_r0_text); |
| 681 | 681 | ||
| 682 | static const char *drc_r1_text[] = { | 682 | static const char *drc_r1_text[] = { |
| 683 | "1", | 683 | "1", |
| @@ -687,8 +687,8 @@ static const char *drc_r1_text[] = { | |||
| 687 | "0", | 687 | "0", |
| 688 | }; | 688 | }; |
| 689 | 689 | ||
| 690 | static const struct soc_enum drc_r1 = | 690 | static SOC_ENUM_SINGLE_DECL(drc_r1, |
| 691 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_4, 13, 5, drc_r1_text); | 691 | WM8993_DRC_CONTROL_4, 13, drc_r1_text); |
| 692 | 692 | ||
| 693 | static const char *drc_attack_text[] = { | 693 | static const char *drc_attack_text[] = { |
| 694 | "Reserved", | 694 | "Reserved", |
| @@ -705,8 +705,8 @@ static const char *drc_attack_text[] = { | |||
| 705 | "185.6ms", | 705 | "185.6ms", |
| 706 | }; | 706 | }; |
| 707 | 707 | ||
| 708 | static const struct soc_enum drc_attack = | 708 | static SOC_ENUM_SINGLE_DECL(drc_attack, |
| 709 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 12, 12, drc_attack_text); | 709 | WM8993_DRC_CONTROL_2, 12, drc_attack_text); |
| 710 | 710 | ||
| 711 | static const char *drc_decay_text[] = { | 711 | static const char *drc_decay_text[] = { |
| 712 | "186ms", | 712 | "186ms", |
| @@ -720,16 +720,16 @@ static const char *drc_decay_text[] = { | |||
| 720 | "47.56ms", | 720 | "47.56ms", |
| 721 | }; | 721 | }; |
| 722 | 722 | ||
| 723 | static const struct soc_enum drc_decay = | 723 | static SOC_ENUM_SINGLE_DECL(drc_decay, |
| 724 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_2, 8, 9, drc_decay_text); | 724 | WM8993_DRC_CONTROL_2, 8, drc_decay_text); |
| 725 | 725 | ||
| 726 | static const char *drc_ff_text[] = { | 726 | static const char *drc_ff_text[] = { |
| 727 | "5 samples", | 727 | "5 samples", |
| 728 | "9 samples", | 728 | "9 samples", |
| 729 | }; | 729 | }; |
| 730 | 730 | ||
| 731 | static const struct soc_enum drc_ff = | 731 | static SOC_ENUM_SINGLE_DECL(drc_ff, |
| 732 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 7, 2, drc_ff_text); | 732 | WM8993_DRC_CONTROL_3, 7, drc_ff_text); |
| 733 | 733 | ||
| 734 | static const char *drc_qr_rate_text[] = { | 734 | static const char *drc_qr_rate_text[] = { |
| 735 | "0.725ms", | 735 | "0.725ms", |
| @@ -737,8 +737,8 @@ static const char *drc_qr_rate_text[] = { | |||
| 737 | "5.8ms", | 737 | "5.8ms", |
| 738 | }; | 738 | }; |
| 739 | 739 | ||
| 740 | static const struct soc_enum drc_qr_rate = | 740 | static SOC_ENUM_SINGLE_DECL(drc_qr_rate, |
| 741 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_3, 0, 3, drc_qr_rate_text); | 741 | WM8993_DRC_CONTROL_3, 0, drc_qr_rate_text); |
| 742 | 742 | ||
| 743 | static const char *drc_smooth_text[] = { | 743 | static const char *drc_smooth_text[] = { |
| 744 | "Low", | 744 | "Low", |
| @@ -746,8 +746,8 @@ static const char *drc_smooth_text[] = { | |||
| 746 | "High", | 746 | "High", |
| 747 | }; | 747 | }; |
| 748 | 748 | ||
| 749 | static const struct soc_enum drc_smooth = | 749 | static SOC_ENUM_SINGLE_DECL(drc_smooth, |
| 750 | SOC_ENUM_SINGLE(WM8993_DRC_CONTROL_1, 4, 3, drc_smooth_text); | 750 | WM8993_DRC_CONTROL_1, 4, drc_smooth_text); |
| 751 | 751 | ||
| 752 | static const struct snd_kcontrol_new wm8993_snd_controls[] = { | 752 | static const struct snd_kcontrol_new wm8993_snd_controls[] = { |
| 753 | SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, | 753 | SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, |
| @@ -841,26 +841,26 @@ static const char *aif_text[] = { | |||
| 841 | "Left", "Right" | 841 | "Left", "Right" |
| 842 | }; | 842 | }; |
| 843 | 843 | ||
| 844 | static const struct soc_enum aifoutl_enum = | 844 | static SOC_ENUM_SINGLE_DECL(aifoutl_enum, |
| 845 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text); | 845 | WM8993_AUDIO_INTERFACE_1, 15, aif_text); |
| 846 | 846 | ||
| 847 | static const struct snd_kcontrol_new aifoutl_mux = | 847 | static const struct snd_kcontrol_new aifoutl_mux = |
| 848 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); | 848 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); |
| 849 | 849 | ||
| 850 | static const struct soc_enum aifoutr_enum = | 850 | static SOC_ENUM_SINGLE_DECL(aifoutr_enum, |
| 851 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text); | 851 | WM8993_AUDIO_INTERFACE_1, 14, aif_text); |
| 852 | 852 | ||
| 853 | static const struct snd_kcontrol_new aifoutr_mux = | 853 | static const struct snd_kcontrol_new aifoutr_mux = |
| 854 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); | 854 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); |
| 855 | 855 | ||
| 856 | static const struct soc_enum aifinl_enum = | 856 | static SOC_ENUM_SINGLE_DECL(aifinl_enum, |
| 857 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text); | 857 | WM8993_AUDIO_INTERFACE_2, 15, aif_text); |
| 858 | 858 | ||
| 859 | static const struct snd_kcontrol_new aifinl_mux = | 859 | static const struct snd_kcontrol_new aifinl_mux = |
| 860 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); | 860 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); |
| 861 | 861 | ||
| 862 | static const struct soc_enum aifinr_enum = | 862 | static SOC_ENUM_SINGLE_DECL(aifinr_enum, |
| 863 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text); | 863 | WM8993_AUDIO_INTERFACE_2, 14, aif_text); |
| 864 | 864 | ||
| 865 | static const struct snd_kcontrol_new aifinr_mux = | 865 | static const struct snd_kcontrol_new aifinr_mux = |
| 866 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); | 866 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); |
| @@ -869,14 +869,14 @@ static const char *sidetone_text[] = { | |||
| 869 | "None", "Left", "Right" | 869 | "None", "Left", "Right" |
| 870 | }; | 870 | }; |
| 871 | 871 | ||
| 872 | static const struct soc_enum sidetonel_enum = | 872 | static SOC_ENUM_SINGLE_DECL(sidetonel_enum, |
| 873 | SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text); | 873 | WM8993_DIGITAL_SIDE_TONE, 2, sidetone_text); |
| 874 | 874 | ||
| 875 | static const struct snd_kcontrol_new sidetonel_mux = | 875 | static const struct snd_kcontrol_new sidetonel_mux = |
| 876 | SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); | 876 | SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); |
| 877 | 877 | ||
| 878 | static const struct soc_enum sidetoner_enum = | 878 | static SOC_ENUM_SINGLE_DECL(sidetoner_enum, |
| 879 | SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text); | 879 | WM8993_DIGITAL_SIDE_TONE, 0, sidetone_text); |
| 880 | 880 | ||
| 881 | static const struct snd_kcontrol_new sidetoner_mux = | 881 | static const struct snd_kcontrol_new sidetoner_mux = |
| 882 | SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); | 882 | SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); |
| @@ -1559,8 +1559,6 @@ static int wm8993_probe(struct snd_soc_codec *codec) | |||
| 1559 | 1559 | ||
| 1560 | static int wm8993_remove(struct snd_soc_codec *codec) | 1560 | static int wm8993_remove(struct snd_soc_codec *codec) |
| 1561 | { | 1561 | { |
| 1562 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | ||
| 1563 | |||
| 1564 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1562 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 1565 | return 0; | 1563 | return 0; |
| 1566 | } | 1564 | } |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index adb72063d44e..79854cb7feb6 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
| @@ -1344,8 +1344,7 @@ static const char *adc_mux_text[] = { | |||
| 1344 | "DMIC", | 1344 | "DMIC", |
| 1345 | }; | 1345 | }; |
| 1346 | 1346 | ||
| 1347 | static SOC_ENUM_SINGLE_DECL(adc_enum, | 1347 | static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); |
| 1348 | 0, 0, adc_mux_text); | ||
| 1349 | 1348 | ||
| 1350 | static const struct snd_kcontrol_new adcl_mux = | 1349 | static const struct snd_kcontrol_new adcl_mux = |
| 1351 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); | 1350 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); |
| @@ -2554,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
| 2554 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) | 2553 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) |
| 2555 | { | 2554 | { |
| 2556 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2555 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
| 2556 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 2557 | 2557 | ||
| 2558 | switch (mode) { | 2558 | switch (mode) { |
| 2559 | case WM8994_VMID_NORMAL: | 2559 | case WM8994_VMID_NORMAL: |
| 2560 | snd_soc_dapm_mutex_lock(dapm); | ||
| 2561 | |||
| 2560 | if (wm8994->hubs.lineout1_se) { | 2562 | if (wm8994->hubs.lineout1_se) { |
| 2561 | snd_soc_dapm_disable_pin(&codec->dapm, | 2563 | snd_soc_dapm_disable_pin_unlocked(dapm, |
| 2562 | "LINEOUT1N Driver"); | 2564 | "LINEOUT1N Driver"); |
| 2563 | snd_soc_dapm_disable_pin(&codec->dapm, | 2565 | snd_soc_dapm_disable_pin_unlocked(dapm, |
| 2564 | "LINEOUT1P Driver"); | 2566 | "LINEOUT1P Driver"); |
| 2565 | } | 2567 | } |
| 2566 | if (wm8994->hubs.lineout2_se) { | 2568 | if (wm8994->hubs.lineout2_se) { |
| 2567 | snd_soc_dapm_disable_pin(&codec->dapm, | 2569 | snd_soc_dapm_disable_pin_unlocked(dapm, |
| 2568 | "LINEOUT2N Driver"); | 2570 | "LINEOUT2N Driver"); |
| 2569 | snd_soc_dapm_disable_pin(&codec->dapm, | 2571 | snd_soc_dapm_disable_pin_unlocked(dapm, |
| 2570 | "LINEOUT2P Driver"); | 2572 | "LINEOUT2P Driver"); |
| 2571 | } | 2573 | } |
| 2572 | 2574 | ||
| 2573 | /* Do the sync with the old mode to allow it to clean up */ | 2575 | /* Do the sync with the old mode to allow it to clean up */ |
| 2574 | snd_soc_dapm_sync(&codec->dapm); | 2576 | snd_soc_dapm_sync_unlocked(dapm); |
| 2575 | wm8994->vmid_mode = mode; | 2577 | wm8994->vmid_mode = mode; |
| 2578 | |||
| 2579 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 2576 | break; | 2580 | break; |
| 2577 | 2581 | ||
| 2578 | case WM8994_VMID_FORCE: | 2582 | case WM8994_VMID_FORCE: |
| 2583 | snd_soc_dapm_mutex_lock(dapm); | ||
| 2584 | |||
| 2579 | if (wm8994->hubs.lineout1_se) { | 2585 | if (wm8994->hubs.lineout1_se) { |
| 2580 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2586 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
| 2581 | "LINEOUT1N Driver"); | 2587 | "LINEOUT1N Driver"); |
| 2582 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2588 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
| 2583 | "LINEOUT1P Driver"); | 2589 | "LINEOUT1P Driver"); |
| 2584 | } | 2590 | } |
| 2585 | if (wm8994->hubs.lineout2_se) { | 2591 | if (wm8994->hubs.lineout2_se) { |
| 2586 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2592 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
| 2587 | "LINEOUT2N Driver"); | 2593 | "LINEOUT2N Driver"); |
| 2588 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2594 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
| 2589 | "LINEOUT2P Driver"); | 2595 | "LINEOUT2P Driver"); |
| 2590 | } | 2596 | } |
| 2591 | 2597 | ||
| 2592 | wm8994->vmid_mode = mode; | 2598 | wm8994->vmid_mode = mode; |
| 2593 | snd_soc_dapm_sync(&codec->dapm); | 2599 | snd_soc_dapm_sync_unlocked(dapm); |
| 2600 | |||
| 2601 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 2594 | break; | 2602 | break; |
| 2595 | 2603 | ||
| 2596 | default: | 2604 | default: |
| @@ -3242,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) | |||
| 3242 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 3250 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
| 3243 | wm8994->num_retune_mobile_texts); | 3251 | wm8994->num_retune_mobile_texts); |
| 3244 | 3252 | ||
| 3245 | wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; | 3253 | wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts; |
| 3246 | wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; | 3254 | wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; |
| 3247 | 3255 | ||
| 3248 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, | 3256 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, |
| @@ -3298,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | |||
| 3298 | for (i = 0; i < pdata->num_drc_cfgs; i++) | 3306 | for (i = 0; i < pdata->num_drc_cfgs; i++) |
| 3299 | wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; | 3307 | wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; |
| 3300 | 3308 | ||
| 3301 | wm8994->drc_enum.max = pdata->num_drc_cfgs; | 3309 | wm8994->drc_enum.items = pdata->num_drc_cfgs; |
| 3302 | wm8994->drc_enum.texts = wm8994->drc_texts; | 3310 | wm8994->drc_enum.texts = wm8994->drc_texts; |
| 3303 | 3311 | ||
| 3304 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, | 3312 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 4300caff1783..ddb197dc1d53 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
| @@ -423,24 +423,24 @@ static const char *in1l_text[] = { | |||
| 423 | "Differential", "Single-ended IN1LN", "Single-ended IN1LP" | 423 | "Differential", "Single-ended IN1LN", "Single-ended IN1LP" |
| 424 | }; | 424 | }; |
| 425 | 425 | ||
| 426 | static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, | 426 | static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, |
| 427 | 2, in1l_text); | 427 | 2, in1l_text); |
| 428 | 428 | ||
| 429 | static const char *in1r_text[] = { | 429 | static const char *in1r_text[] = { |
| 430 | "Differential", "Single-ended IN1RN", "Single-ended IN1RP" | 430 | "Differential", "Single-ended IN1RN", "Single-ended IN1RP" |
| 431 | }; | 431 | }; |
| 432 | 432 | ||
| 433 | static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, | 433 | static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, |
| 434 | 0, in1r_text); | 434 | 0, in1r_text); |
| 435 | 435 | ||
| 436 | static const char *dmic_src_text[] = { | 436 | static const char *dmic_src_text[] = { |
| 437 | "DMICDAT1", "DMICDAT2", "DMICDAT3" | 437 | "DMICDAT1", "DMICDAT2", "DMICDAT3" |
| 438 | }; | 438 | }; |
| 439 | 439 | ||
| 440 | static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, | 440 | static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, |
| 441 | 8, dmic_src_text); | 441 | 8, dmic_src_text); |
| 442 | static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, | 442 | static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, |
| 443 | 6, dmic_src_text); | 443 | 6, dmic_src_text); |
| 444 | 444 | ||
| 445 | static const struct snd_kcontrol_new wm8995_snd_controls[] = { | 445 | static const struct snd_kcontrol_new wm8995_snd_controls[] = { |
| 446 | SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, | 446 | SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, |
| @@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w, | |||
| 561 | struct snd_kcontrol *kcontrol, int event) | 561 | struct snd_kcontrol *kcontrol, int event) |
| 562 | { | 562 | { |
| 563 | struct snd_soc_codec *codec; | 563 | struct snd_soc_codec *codec; |
| 564 | struct wm8995_priv *wm8995; | ||
| 565 | 564 | ||
| 566 | codec = w->codec; | 565 | codec = w->codec; |
| 567 | wm8995 = snd_soc_codec_get_drvdata(codec); | ||
| 568 | 566 | ||
| 569 | switch (event) { | 567 | switch (event) { |
| 570 | case SND_SOC_DAPM_PRE_PMU: | 568 | case SND_SOC_DAPM_PRE_PMU: |
| @@ -783,14 +781,12 @@ static const char *sidetone_text[] = { | |||
| 783 | "ADC/DMIC1", "DMIC2", | 781 | "ADC/DMIC1", "DMIC2", |
| 784 | }; | 782 | }; |
| 785 | 783 | ||
| 786 | static const struct soc_enum sidetone1_enum = | 784 | static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text); |
| 787 | SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text); | ||
| 788 | 785 | ||
| 789 | static const struct snd_kcontrol_new sidetone1_mux = | 786 | static const struct snd_kcontrol_new sidetone1_mux = |
| 790 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); | 787 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); |
| 791 | 788 | ||
| 792 | static const struct soc_enum sidetone2_enum = | 789 | static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text); |
| 793 | SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text); | ||
| 794 | 790 | ||
| 795 | static const struct snd_kcontrol_new sidetone2_mux = | 791 | static const struct snd_kcontrol_new sidetone2_mux = |
| 796 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); | 792 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); |
| @@ -886,8 +882,7 @@ static const char *adc_mux_text[] = { | |||
| 886 | "DMIC", | 882 | "DMIC", |
| 887 | }; | 883 | }; |
| 888 | 884 | ||
| 889 | static const struct soc_enum adc_enum = | 885 | static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); |
| 890 | SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); | ||
| 891 | 886 | ||
| 892 | static const struct snd_kcontrol_new adcl_mux = | 887 | static const struct snd_kcontrol_new adcl_mux = |
| 893 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); | 888 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); |
| @@ -899,14 +894,14 @@ static const char *spk_src_text[] = { | |||
| 899 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" | 894 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" |
| 900 | }; | 895 | }; |
| 901 | 896 | ||
| 902 | static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, | 897 | static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, |
| 903 | 0, spk_src_text); | 898 | 0, spk_src_text); |
| 904 | static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, | 899 | static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, |
| 905 | 0, spk_src_text); | 900 | 0, spk_src_text); |
| 906 | static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, | 901 | static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, |
| 907 | 0, spk_src_text); | 902 | 0, spk_src_text); |
| 908 | static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, | 903 | static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, |
| 909 | 0, spk_src_text); | 904 | 0, spk_src_text); |
| 910 | 905 | ||
| 911 | static const struct snd_kcontrol_new spk1l_mux = | 906 | static const struct snd_kcontrol_new spk1l_mux = |
| 912 | SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); | 907 | SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); |
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 1a7655b0aa22..c8244af7d56a 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
| @@ -311,28 +311,28 @@ static const char *sidetone_hpf_text[] = { | |||
| 311 | "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz" | 311 | "2.9kHz", "1.5kHz", "735Hz", "403Hz", "196Hz", "98Hz", "49Hz" |
| 312 | }; | 312 | }; |
| 313 | 313 | ||
| 314 | static const struct soc_enum sidetone_hpf = | 314 | static SOC_ENUM_SINGLE_DECL(sidetone_hpf, |
| 315 | SOC_ENUM_SINGLE(WM8996_SIDETONE, 7, 7, sidetone_hpf_text); | 315 | WM8996_SIDETONE, 7, sidetone_hpf_text); |
| 316 | 316 | ||
| 317 | static const char *hpf_mode_text[] = { | 317 | static const char *hpf_mode_text[] = { |
| 318 | "HiFi", "Custom", "Voice" | 318 | "HiFi", "Custom", "Voice" |
| 319 | }; | 319 | }; |
| 320 | 320 | ||
| 321 | static const struct soc_enum dsp1tx_hpf_mode = | 321 | static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_mode, |
| 322 | SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 3, 3, hpf_mode_text); | 322 | WM8996_DSP1_TX_FILTERS, 3, hpf_mode_text); |
| 323 | 323 | ||
| 324 | static const struct soc_enum dsp2tx_hpf_mode = | 324 | static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_mode, |
| 325 | SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 3, 3, hpf_mode_text); | 325 | WM8996_DSP2_TX_FILTERS, 3, hpf_mode_text); |
| 326 | 326 | ||
| 327 | static const char *hpf_cutoff_text[] = { | 327 | static const char *hpf_cutoff_text[] = { |
| 328 | "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 328 | "50Hz", "75Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
| 329 | }; | 329 | }; |
| 330 | 330 | ||
| 331 | static const struct soc_enum dsp1tx_hpf_cutoff = | 331 | static SOC_ENUM_SINGLE_DECL(dsp1tx_hpf_cutoff, |
| 332 | SOC_ENUM_SINGLE(WM8996_DSP1_TX_FILTERS, 0, 7, hpf_cutoff_text); | 332 | WM8996_DSP1_TX_FILTERS, 0, hpf_cutoff_text); |
| 333 | 333 | ||
| 334 | static const struct soc_enum dsp2tx_hpf_cutoff = | 334 | static SOC_ENUM_SINGLE_DECL(dsp2tx_hpf_cutoff, |
| 335 | SOC_ENUM_SINGLE(WM8996_DSP2_TX_FILTERS, 0, 7, hpf_cutoff_text); | 335 | WM8996_DSP2_TX_FILTERS, 0, hpf_cutoff_text); |
| 336 | 336 | ||
| 337 | static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block) | 337 | static void wm8996_set_retune_mobile(struct snd_soc_codec *codec, int block) |
| 338 | { | 338 | { |
| @@ -780,14 +780,14 @@ static const char *sidetone_text[] = { | |||
| 780 | "IN1", "IN2", | 780 | "IN1", "IN2", |
| 781 | }; | 781 | }; |
| 782 | 782 | ||
| 783 | static const struct soc_enum left_sidetone_enum = | 783 | static SOC_ENUM_SINGLE_DECL(left_sidetone_enum, |
| 784 | SOC_ENUM_SINGLE(WM8996_SIDETONE, 0, 2, sidetone_text); | 784 | WM8996_SIDETONE, 0, sidetone_text); |
| 785 | 785 | ||
| 786 | static const struct snd_kcontrol_new left_sidetone = | 786 | static const struct snd_kcontrol_new left_sidetone = |
| 787 | SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum); | 787 | SOC_DAPM_ENUM("Left Sidetone", left_sidetone_enum); |
| 788 | 788 | ||
| 789 | static const struct soc_enum right_sidetone_enum = | 789 | static SOC_ENUM_SINGLE_DECL(right_sidetone_enum, |
| 790 | SOC_ENUM_SINGLE(WM8996_SIDETONE, 1, 2, sidetone_text); | 790 | WM8996_SIDETONE, 1, sidetone_text); |
| 791 | 791 | ||
| 792 | static const struct snd_kcontrol_new right_sidetone = | 792 | static const struct snd_kcontrol_new right_sidetone = |
| 793 | SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum); | 793 | SOC_DAPM_ENUM("Right Sidetone", right_sidetone_enum); |
| @@ -796,14 +796,14 @@ static const char *spk_text[] = { | |||
| 796 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" | 796 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" |
| 797 | }; | 797 | }; |
| 798 | 798 | ||
| 799 | static const struct soc_enum spkl_enum = | 799 | static SOC_ENUM_SINGLE_DECL(spkl_enum, |
| 800 | SOC_ENUM_SINGLE(WM8996_LEFT_PDM_SPEAKER, 0, 4, spk_text); | 800 | WM8996_LEFT_PDM_SPEAKER, 0, spk_text); |
| 801 | 801 | ||
| 802 | static const struct snd_kcontrol_new spkl_mux = | 802 | static const struct snd_kcontrol_new spkl_mux = |
| 803 | SOC_DAPM_ENUM("SPKL", spkl_enum); | 803 | SOC_DAPM_ENUM("SPKL", spkl_enum); |
| 804 | 804 | ||
| 805 | static const struct soc_enum spkr_enum = | 805 | static SOC_ENUM_SINGLE_DECL(spkr_enum, |
| 806 | SOC_ENUM_SINGLE(WM8996_RIGHT_PDM_SPEAKER, 0, 4, spk_text); | 806 | WM8996_RIGHT_PDM_SPEAKER, 0, spk_text); |
| 807 | 807 | ||
| 808 | static const struct snd_kcontrol_new spkr_mux = | 808 | static const struct snd_kcontrol_new spkr_mux = |
| 809 | SOC_DAPM_ENUM("SPKR", spkr_enum); | 809 | SOC_DAPM_ENUM("SPKR", spkr_enum); |
| @@ -812,8 +812,8 @@ static const char *dsp1rx_text[] = { | |||
| 812 | "AIF1", "AIF2" | 812 | "AIF1", "AIF2" |
| 813 | }; | 813 | }; |
| 814 | 814 | ||
| 815 | static const struct soc_enum dsp1rx_enum = | 815 | static SOC_ENUM_SINGLE_DECL(dsp1rx_enum, |
| 816 | SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 0, 2, dsp1rx_text); | 816 | WM8996_POWER_MANAGEMENT_8, 0, dsp1rx_text); |
| 817 | 817 | ||
| 818 | static const struct snd_kcontrol_new dsp1rx = | 818 | static const struct snd_kcontrol_new dsp1rx = |
| 819 | SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum); | 819 | SOC_DAPM_ENUM("DSP1RX", dsp1rx_enum); |
| @@ -822,8 +822,8 @@ static const char *dsp2rx_text[] = { | |||
| 822 | "AIF2", "AIF1" | 822 | "AIF2", "AIF1" |
| 823 | }; | 823 | }; |
| 824 | 824 | ||
| 825 | static const struct soc_enum dsp2rx_enum = | 825 | static SOC_ENUM_SINGLE_DECL(dsp2rx_enum, |
| 826 | SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 4, 2, dsp2rx_text); | 826 | WM8996_POWER_MANAGEMENT_8, 4, dsp2rx_text); |
| 827 | 827 | ||
| 828 | static const struct snd_kcontrol_new dsp2rx = | 828 | static const struct snd_kcontrol_new dsp2rx = |
| 829 | SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum); | 829 | SOC_DAPM_ENUM("DSP2RX", dsp2rx_enum); |
| @@ -832,8 +832,8 @@ static const char *aif2tx_text[] = { | |||
| 832 | "DSP2", "DSP1", "AIF1" | 832 | "DSP2", "DSP1", "AIF1" |
| 833 | }; | 833 | }; |
| 834 | 834 | ||
| 835 | static const struct soc_enum aif2tx_enum = | 835 | static SOC_ENUM_SINGLE_DECL(aif2tx_enum, |
| 836 | SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_8, 6, 3, aif2tx_text); | 836 | WM8996_POWER_MANAGEMENT_8, 6, aif2tx_text); |
| 837 | 837 | ||
| 838 | static const struct snd_kcontrol_new aif2tx = | 838 | static const struct snd_kcontrol_new aif2tx = |
| 839 | SOC_DAPM_ENUM("AIF2TX", aif2tx_enum); | 839 | SOC_DAPM_ENUM("AIF2TX", aif2tx_enum); |
| @@ -842,14 +842,14 @@ static const char *inmux_text[] = { | |||
| 842 | "ADC", "DMIC1", "DMIC2" | 842 | "ADC", "DMIC1", "DMIC2" |
| 843 | }; | 843 | }; |
| 844 | 844 | ||
| 845 | static const struct soc_enum in1_enum = | 845 | static SOC_ENUM_SINGLE_DECL(in1_enum, |
| 846 | SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 0, 3, inmux_text); | 846 | WM8996_POWER_MANAGEMENT_7, 0, inmux_text); |
| 847 | 847 | ||
| 848 | static const struct snd_kcontrol_new in1_mux = | 848 | static const struct snd_kcontrol_new in1_mux = |
| 849 | SOC_DAPM_ENUM("IN1 Mux", in1_enum); | 849 | SOC_DAPM_ENUM("IN1 Mux", in1_enum); |
| 850 | 850 | ||
| 851 | static const struct soc_enum in2_enum = | 851 | static SOC_ENUM_SINGLE_DECL(in2_enum, |
| 852 | SOC_ENUM_SINGLE(WM8996_POWER_MANAGEMENT_7, 4, 3, inmux_text); | 852 | WM8996_POWER_MANAGEMENT_7, 4, inmux_text); |
| 853 | 853 | ||
| 854 | static const struct snd_kcontrol_new in2_mux = | 854 | static const struct snd_kcontrol_new in2_mux = |
| 855 | SOC_DAPM_ENUM("IN2 Mux", in2_enum); | 855 | SOC_DAPM_ENUM("IN2 Mux", in2_enum); |
| @@ -1608,8 +1608,8 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec, | |||
| 1608 | msleep(5); | 1608 | msleep(5); |
| 1609 | } | 1609 | } |
| 1610 | 1610 | ||
| 1611 | regcache_cache_only(codec->control_data, false); | 1611 | regcache_cache_only(wm8996->regmap, false); |
| 1612 | regcache_sync(codec->control_data); | 1612 | regcache_sync(wm8996->regmap); |
| 1613 | } | 1613 | } |
| 1614 | 1614 | ||
| 1615 | /* Bypass the MICBIASes for lowest power */ | 1615 | /* Bypass the MICBIASes for lowest power */ |
| @@ -1620,10 +1620,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec, | |||
| 1620 | break; | 1620 | break; |
| 1621 | 1621 | ||
| 1622 | case SND_SOC_BIAS_OFF: | 1622 | case SND_SOC_BIAS_OFF: |
| 1623 | regcache_cache_only(codec->control_data, true); | 1623 | regcache_cache_only(wm8996->regmap, true); |
| 1624 | if (wm8996->pdata.ldo_ena >= 0) { | 1624 | if (wm8996->pdata.ldo_ena >= 0) { |
| 1625 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); | 1625 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); |
| 1626 | regcache_cache_only(codec->control_data, true); | 1626 | regcache_cache_only(wm8996->regmap, true); |
| 1627 | } | 1627 | } |
| 1628 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), | 1628 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), |
| 1629 | wm8996->supplies); | 1629 | wm8996->supplies); |
| @@ -2251,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
| 2251 | wm8996_polarity_fn polarity_cb) | 2251 | wm8996_polarity_fn polarity_cb) |
| 2252 | { | 2252 | { |
| 2253 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 2253 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
| 2254 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 2254 | 2255 | ||
| 2255 | wm8996->jack = jack; | 2256 | wm8996->jack = jack; |
| 2256 | wm8996->detecting = true; | 2257 | wm8996->detecting = true; |
| @@ -2267,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
| 2267 | WM8996_MICB2_DISCH, 0); | 2268 | WM8996_MICB2_DISCH, 0); |
| 2268 | 2269 | ||
| 2269 | /* LDO2 powers the microphones, SYSCLK clocks detection */ | 2270 | /* LDO2 powers the microphones, SYSCLK clocks detection */ |
| 2270 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | 2271 | snd_soc_dapm_mutex_lock(dapm); |
| 2271 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 2272 | |
| 2273 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); | ||
| 2274 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); | ||
| 2275 | |||
| 2276 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 2272 | 2277 | ||
| 2273 | /* We start off just enabling microphone detection - even a | 2278 | /* We start off just enabling microphone detection - even a |
| 2274 | * plain headphone will trigger detection. | 2279 | * plain headphone will trigger detection. |
| @@ -2595,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec) | |||
| 2595 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 2600 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
| 2596 | wm8996->num_retune_mobile_texts); | 2601 | wm8996->num_retune_mobile_texts); |
| 2597 | 2602 | ||
| 2598 | wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts; | 2603 | wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts; |
| 2599 | wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; | 2604 | wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; |
| 2600 | 2605 | ||
| 2601 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 2606 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 555115ee2159..e10f44d7fdb7 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c | |||
| @@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
| 86 | { | 86 | { |
| 87 | struct snd_soc_codec *codec = w->codec; | 87 | struct snd_soc_codec *codec = w->codec; |
| 88 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 88 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
| 89 | struct regmap *regmap = codec->control_data; | 89 | struct regmap *regmap = arizona->regmap; |
| 90 | const struct reg_default *patch = NULL; | 90 | const struct reg_default *patch = NULL; |
| 91 | int i, patch_size; | 91 | int i, patch_size; |
| 92 | 92 | ||
| @@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = { | |||
| 123 | 123 | ||
| 124 | static const struct soc_enum wm8997_hpout_osr[] = { | 124 | static const struct soc_enum wm8997_hpout_osr[] = { |
| 125 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, | 125 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, |
| 126 | ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, | 126 | ARIZONA_OUT1_OSR_SHIFT, 0x7, |
| 127 | ARRAY_SIZE(wm8997_osr_text), | ||
| 127 | wm8997_osr_text, wm8997_osr_val), | 128 | wm8997_osr_text, wm8997_osr_val), |
| 128 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, | 129 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, |
| 129 | ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, | 130 | ARIZONA_OUT3_OSR_SHIFT, 0x7, |
| 131 | ARRAY_SIZE(wm8997_osr_text), | ||
| 130 | wm8997_osr_text, wm8997_osr_val), | 132 | wm8997_osr_text, wm8997_osr_val), |
| 131 | }; | 133 | }; |
| 132 | 134 | ||
| @@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
| 170 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 172 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
| 171 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 173 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
| 172 | 174 | ||
| 173 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 175 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
| 174 | ARIZONA_EQ1_ENA_MASK), | 176 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
| 175 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
| 176 | ARIZONA_EQ2_ENA_MASK), | ||
| 177 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
| 178 | ARIZONA_EQ3_ENA_MASK), | ||
| 179 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
| 180 | ARIZONA_EQ4_ENA_MASK), | ||
| 181 | |||
| 182 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 177 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
| 183 | 24, 0, eq_tlv), | 178 | 24, 0, eq_tlv), |
| 184 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 179 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
| @@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
| 190 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 185 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
| 191 | 24, 0, eq_tlv), | 186 | 24, 0, eq_tlv), |
| 192 | 187 | ||
| 188 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
| 189 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
| 193 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 190 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
| 194 | 24, 0, eq_tlv), | 191 | 24, 0, eq_tlv), |
| 195 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 192 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
| @@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
| 201 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 198 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
| 202 | 24, 0, eq_tlv), | 199 | 24, 0, eq_tlv), |
| 203 | 200 | ||
| 201 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
| 202 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
| 204 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 203 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
| 205 | 24, 0, eq_tlv), | 204 | 24, 0, eq_tlv), |
| 206 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 205 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
| @@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
| 212 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 211 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
| 213 | 24, 0, eq_tlv), | 212 | 24, 0, eq_tlv), |
| 214 | 213 | ||
| 214 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
| 215 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
| 215 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 216 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
| 216 | 24, 0, eq_tlv), | 217 | 24, 0, eq_tlv), |
| 217 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 218 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 0982c1d38ec4..721cee71d5fc 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
| @@ -268,8 +268,7 @@ static const char *drc_high_text[] = { | |||
| 268 | "0", | 268 | "0", |
| 269 | }; | 269 | }; |
| 270 | 270 | ||
| 271 | static const struct soc_enum drc_high = | 271 | static SOC_ENUM_SINGLE_DECL(drc_high, WM9081_DRC_3, 3, drc_high_text); |
| 272 | SOC_ENUM_SINGLE(WM9081_DRC_3, 3, 6, drc_high_text); | ||
| 273 | 272 | ||
| 274 | static const char *drc_low_text[] = { | 273 | static const char *drc_low_text[] = { |
| 275 | "1", | 274 | "1", |
| @@ -279,8 +278,7 @@ static const char *drc_low_text[] = { | |||
| 279 | "0", | 278 | "0", |
| 280 | }; | 279 | }; |
| 281 | 280 | ||
| 282 | static const struct soc_enum drc_low = | 281 | static SOC_ENUM_SINGLE_DECL(drc_low, WM9081_DRC_3, 0, drc_low_text); |
| 283 | SOC_ENUM_SINGLE(WM9081_DRC_3, 0, 5, drc_low_text); | ||
| 284 | 282 | ||
| 285 | static const char *drc_atk_text[] = { | 283 | static const char *drc_atk_text[] = { |
| 286 | "181us", | 284 | "181us", |
| @@ -297,8 +295,7 @@ static const char *drc_atk_text[] = { | |||
| 297 | "185.6ms", | 295 | "185.6ms", |
| 298 | }; | 296 | }; |
| 299 | 297 | ||
| 300 | static const struct soc_enum drc_atk = | 298 | static SOC_ENUM_SINGLE_DECL(drc_atk, WM9081_DRC_2, 12, drc_atk_text); |
| 301 | SOC_ENUM_SINGLE(WM9081_DRC_2, 12, 12, drc_atk_text); | ||
| 302 | 299 | ||
| 303 | static const char *drc_dcy_text[] = { | 300 | static const char *drc_dcy_text[] = { |
| 304 | "186ms", | 301 | "186ms", |
| @@ -312,8 +309,7 @@ static const char *drc_dcy_text[] = { | |||
| 312 | "47.56s", | 309 | "47.56s", |
| 313 | }; | 310 | }; |
| 314 | 311 | ||
| 315 | static const struct soc_enum drc_dcy = | 312 | static SOC_ENUM_SINGLE_DECL(drc_dcy, WM9081_DRC_2, 8, drc_dcy_text); |
| 316 | SOC_ENUM_SINGLE(WM9081_DRC_2, 8, 9, drc_dcy_text); | ||
| 317 | 313 | ||
| 318 | static const char *drc_qr_dcy_text[] = { | 314 | static const char *drc_qr_dcy_text[] = { |
| 319 | "0.725ms", | 315 | "0.725ms", |
| @@ -321,8 +317,7 @@ static const char *drc_qr_dcy_text[] = { | |||
| 321 | "5.8ms", | 317 | "5.8ms", |
| 322 | }; | 318 | }; |
| 323 | 319 | ||
| 324 | static const struct soc_enum drc_qr_dcy = | 320 | static SOC_ENUM_SINGLE_DECL(drc_qr_dcy, WM9081_DRC_2, 4, drc_qr_dcy_text); |
| 325 | SOC_ENUM_SINGLE(WM9081_DRC_2, 4, 3, drc_qr_dcy_text); | ||
| 326 | 321 | ||
| 327 | static const char *dac_deemph_text[] = { | 322 | static const char *dac_deemph_text[] = { |
| 328 | "None", | 323 | "None", |
| @@ -331,16 +326,16 @@ static const char *dac_deemph_text[] = { | |||
| 331 | "48kHz", | 326 | "48kHz", |
| 332 | }; | 327 | }; |
| 333 | 328 | ||
| 334 | static const struct soc_enum dac_deemph = | 329 | static SOC_ENUM_SINGLE_DECL(dac_deemph, WM9081_DAC_DIGITAL_2, 1, |
| 335 | SOC_ENUM_SINGLE(WM9081_DAC_DIGITAL_2, 1, 4, dac_deemph_text); | 330 | dac_deemph_text); |
| 336 | 331 | ||
| 337 | static const char *speaker_mode_text[] = { | 332 | static const char *speaker_mode_text[] = { |
| 338 | "Class D", | 333 | "Class D", |
| 339 | "Class AB", | 334 | "Class AB", |
| 340 | }; | 335 | }; |
| 341 | 336 | ||
| 342 | static const struct soc_enum speaker_mode = | 337 | static SOC_ENUM_SINGLE_DECL(speaker_mode, WM9081_ANALOGUE_SPEAKER_2, 6, |
| 343 | SOC_ENUM_SINGLE(WM9081_ANALOGUE_SPEAKER_2, 6, 2, speaker_mode_text); | 338 | speaker_mode_text); |
| 344 | 339 | ||
| 345 | static int speaker_mode_get(struct snd_kcontrol *kcontrol, | 340 | static int speaker_mode_get(struct snd_kcontrol *kcontrol, |
| 346 | struct snd_ctl_elem_value *ucontrol) | 341 | struct snd_ctl_elem_value *ucontrol) |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 70ce6793c5bd..c0b7f45dfa37 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
| @@ -67,12 +67,12 @@ static const char *wm9705_mic[] = {"Mic 1", "Mic 2"}; | |||
| 67 | static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC", | 67 | static const char *wm9705_rec_sel[] = {"Mic", "CD", "NC", "NC", |
| 68 | "Line", "Stereo Mix", "Mono Mix", "Phone"}; | 68 | "Line", "Stereo Mix", "Mono Mix", "Phone"}; |
| 69 | 69 | ||
| 70 | static const struct soc_enum wm9705_enum_mic = | 70 | static SOC_ENUM_SINGLE_DECL(wm9705_enum_mic, |
| 71 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 8, 2, wm9705_mic); | 71 | AC97_GENERAL_PURPOSE, 8, wm9705_mic); |
| 72 | static const struct soc_enum wm9705_enum_rec_l = | 72 | static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_l, |
| 73 | SOC_ENUM_SINGLE(AC97_REC_SEL, 8, 8, wm9705_rec_sel); | 73 | AC97_REC_SEL, 8, wm9705_rec_sel); |
| 74 | static const struct soc_enum wm9705_enum_rec_r = | 74 | static SOC_ENUM_SINGLE_DECL(wm9705_enum_rec_r, |
| 75 | SOC_ENUM_SINGLE(AC97_REC_SEL, 0, 8, wm9705_rec_sel); | 75 | AC97_REC_SEL, 0, wm9705_rec_sel); |
| 76 | 76 | ||
| 77 | /* Headphone Mixer */ | 77 | /* Headphone Mixer */ |
| 78 | static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = { | 78 | static const struct snd_kcontrol_new wm9705_hp_mixer_controls[] = { |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 444626fcab40..bb5f7b4e3ebb 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
| @@ -684,24 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
| 684 | } | 684 | } |
| 685 | 685 | ||
| 686 | if (reg) { | 686 | if (reg) { |
| 687 | buf = wm_adsp_buf_alloc(region->data, | 687 | size_t to_write = PAGE_SIZE; |
| 688 | le32_to_cpu(region->len), | 688 | size_t remain = le32_to_cpu(region->len); |
| 689 | &buf_list); | 689 | const u8 *data = region->data; |
| 690 | if (!buf) { | 690 | |
| 691 | adsp_err(dsp, "Out of memory\n"); | 691 | while (remain > 0) { |
| 692 | ret = -ENOMEM; | 692 | if (remain < PAGE_SIZE) |
| 693 | goto out_fw; | 693 | to_write = remain; |
| 694 | } | 694 | |
| 695 | buf = wm_adsp_buf_alloc(data, | ||
| 696 | to_write, | ||
| 697 | &buf_list); | ||
| 698 | if (!buf) { | ||
| 699 | adsp_err(dsp, "Out of memory\n"); | ||
| 700 | ret = -ENOMEM; | ||
| 701 | goto out_fw; | ||
| 702 | } | ||
| 695 | 703 | ||
| 696 | ret = regmap_raw_write_async(regmap, reg, buf->buf, | 704 | ret = regmap_raw_write_async(regmap, reg, |
| 697 | le32_to_cpu(region->len)); | 705 | buf->buf, |
| 698 | if (ret != 0) { | 706 | to_write); |
| 699 | adsp_err(dsp, | 707 | if (ret != 0) { |
| 700 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | 708 | adsp_err(dsp, |
| 701 | file, regions, | 709 | "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", |
| 702 | le32_to_cpu(region->len), offset, | 710 | file, regions, |
| 703 | region_name, ret); | 711 | to_write, offset, |
| 704 | goto out_fw; | 712 | region_name, ret); |
| 713 | goto out_fw; | ||
| 714 | } | ||
| 715 | |||
| 716 | data += to_write; | ||
| 717 | reg += to_write / 2; | ||
| 718 | remain -= to_write; | ||
| 705 | } | 719 | } |
| 706 | } | 720 | } |
| 707 | 721 | ||
| @@ -1679,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
| 1679 | list_del(&alg_region->list); | 1693 | list_del(&alg_region->list); |
| 1680 | kfree(alg_region); | 1694 | kfree(alg_region); |
| 1681 | } | 1695 | } |
| 1696 | |||
| 1697 | adsp_dbg(dsp, "Shutdown complete\n"); | ||
| 1682 | break; | 1698 | break; |
| 1683 | 1699 | ||
| 1684 | default: | 1700 | default: |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index b371066dd5bc..b6209662ab13 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
| @@ -50,16 +50,16 @@ static const char *speaker_ref_text[] = { | |||
| 50 | "VMID", | 50 | "VMID", |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
| 53 | static const struct soc_enum speaker_ref = | 53 | static SOC_ENUM_SINGLE_DECL(speaker_ref, |
| 54 | SOC_ENUM_SINGLE(WM8993_SPEAKER_MIXER, 8, 2, speaker_ref_text); | 54 | WM8993_SPEAKER_MIXER, 8, speaker_ref_text); |
| 55 | 55 | ||
| 56 | static const char *speaker_mode_text[] = { | 56 | static const char *speaker_mode_text[] = { |
| 57 | "Class D", | 57 | "Class D", |
| 58 | "Class AB", | 58 | "Class AB", |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | static const struct soc_enum speaker_mode = | 61 | static SOC_ENUM_SINGLE_DECL(speaker_mode, |
| 62 | SOC_ENUM_SINGLE(WM8993_SPKMIXR_ATTENUATION, 8, 2, speaker_mode_text); | 62 | WM8993_SPKMIXR_ATTENUATION, 8, speaker_mode_text); |
| 63 | 63 | ||
| 64 | static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) | 64 | static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) |
| 65 | { | 65 | { |
| @@ -735,15 +735,15 @@ static const char *hp_mux_text[] = { | |||
| 735 | "DAC", | 735 | "DAC", |
| 736 | }; | 736 | }; |
| 737 | 737 | ||
| 738 | static const struct soc_enum hpl_enum = | 738 | static SOC_ENUM_SINGLE_DECL(hpl_enum, |
| 739 | SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER1, 8, 2, hp_mux_text); | 739 | WM8993_OUTPUT_MIXER1, 8, hp_mux_text); |
| 740 | 740 | ||
| 741 | const struct snd_kcontrol_new wm_hubs_hpl_mux = | 741 | const struct snd_kcontrol_new wm_hubs_hpl_mux = |
| 742 | WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum); | 742 | WM_HUBS_ENUM_W("Left Headphone Mux", hpl_enum); |
| 743 | EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux); | 743 | EXPORT_SYMBOL_GPL(wm_hubs_hpl_mux); |
| 744 | 744 | ||
| 745 | static const struct soc_enum hpr_enum = | 745 | static SOC_ENUM_SINGLE_DECL(hpr_enum, |
| 746 | SOC_ENUM_SINGLE(WM8993_OUTPUT_MIXER2, 8, 2, hp_mux_text); | 746 | WM8993_OUTPUT_MIXER2, 8, hp_mux_text); |
| 747 | 747 | ||
| 748 | const struct snd_kcontrol_new wm_hubs_hpr_mux = | 748 | const struct snd_kcontrol_new wm_hubs_hpr_mux = |
| 749 | WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum); | 749 | WM_HUBS_ENUM_W("Right Headphone Mux", hpr_enum); |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 5e3bc3c6801a..621e9a997d4c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #include <linux/platform_data/edma.h> | 17 | #include <linux/platform_data/edma.h> |
| 18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
| 19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
| 20 | #include <linux/clk.h> | ||
| 20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
| 21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
| 22 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
| @@ -30,9 +31,34 @@ | |||
| 30 | #include "davinci-i2s.h" | 31 | #include "davinci-i2s.h" |
| 31 | 32 | ||
| 32 | struct snd_soc_card_drvdata_davinci { | 33 | struct snd_soc_card_drvdata_davinci { |
| 34 | struct clk *mclk; | ||
| 33 | unsigned sysclk; | 35 | unsigned sysclk; |
| 34 | }; | 36 | }; |
| 35 | 37 | ||
| 38 | static int evm_startup(struct snd_pcm_substream *substream) | ||
| 39 | { | ||
| 40 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 41 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
| 42 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
| 43 | snd_soc_card_get_drvdata(soc_card); | ||
| 44 | |||
| 45 | if (drvdata->mclk) | ||
| 46 | return clk_prepare_enable(drvdata->mclk); | ||
| 47 | |||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | static void evm_shutdown(struct snd_pcm_substream *substream) | ||
| 52 | { | ||
| 53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 54 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
| 55 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
| 56 | snd_soc_card_get_drvdata(soc_card); | ||
| 57 | |||
| 58 | if (drvdata->mclk) | ||
| 59 | clk_disable_unprepare(drvdata->mclk); | ||
| 60 | } | ||
| 61 | |||
| 36 | static int evm_hw_params(struct snd_pcm_substream *substream, | 62 | static int evm_hw_params(struct snd_pcm_substream *substream, |
| 37 | struct snd_pcm_hw_params *params) | 63 | struct snd_pcm_hw_params *params) |
| 38 | { | 64 | { |
| @@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
| 59 | } | 85 | } |
| 60 | 86 | ||
| 61 | static struct snd_soc_ops evm_ops = { | 87 | static struct snd_soc_ops evm_ops = { |
| 88 | .startup = evm_startup, | ||
| 89 | .shutdown = evm_shutdown, | ||
| 62 | .hw_params = evm_hw_params, | 90 | .hw_params = evm_hw_params, |
| 63 | }; | 91 | }; |
| 64 | 92 | ||
| @@ -348,6 +376,7 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
| 348 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); | 376 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); |
| 349 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; | 377 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; |
| 350 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; | 378 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; |
| 379 | struct clk *mclk; | ||
| 351 | int ret = 0; | 380 | int ret = 0; |
| 352 | 381 | ||
| 353 | evm_soc_card.dai_link = dai; | 382 | evm_soc_card.dai_link = dai; |
| @@ -367,13 +396,38 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
| 367 | if (ret) | 396 | if (ret) |
| 368 | return ret; | 397 | return ret; |
| 369 | 398 | ||
| 399 | mclk = devm_clk_get(&pdev->dev, "mclk"); | ||
| 400 | if (PTR_ERR(mclk) == -EPROBE_DEFER) { | ||
| 401 | return -EPROBE_DEFER; | ||
| 402 | } else if (IS_ERR(mclk)) { | ||
| 403 | dev_dbg(&pdev->dev, "mclk not found.\n"); | ||
| 404 | mclk = NULL; | ||
| 405 | } | ||
| 406 | |||
| 370 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | 407 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); |
| 371 | if (!drvdata) | 408 | if (!drvdata) |
| 372 | return -ENOMEM; | 409 | return -ENOMEM; |
| 373 | 410 | ||
| 411 | drvdata->mclk = mclk; | ||
| 412 | |||
| 374 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); | 413 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); |
| 375 | if (ret < 0) | 414 | |
| 376 | return -EINVAL; | 415 | if (ret < 0) { |
| 416 | if (!drvdata->mclk) { | ||
| 417 | dev_err(&pdev->dev, | ||
| 418 | "No clock or clock rate defined.\n"); | ||
| 419 | return -EINVAL; | ||
| 420 | } | ||
| 421 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
| 422 | } else if (drvdata->mclk) { | ||
| 423 | unsigned int requestd_rate = drvdata->sysclk; | ||
| 424 | clk_set_rate(drvdata->mclk, drvdata->sysclk); | ||
| 425 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
| 426 | if (drvdata->sysclk != requestd_rate) | ||
| 427 | dev_warn(&pdev->dev, | ||
| 428 | "Could not get requested rate %u using %u.\n", | ||
| 429 | requestd_rate, drvdata->sysclk); | ||
| 430 | } | ||
| 377 | 431 | ||
| 378 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); | 432 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); |
| 379 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); | 433 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 670afa29e30d..b0ae0677f023 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
| @@ -37,6 +37,16 @@ | |||
| 37 | #include "davinci-pcm.h" | 37 | #include "davinci-pcm.h" |
| 38 | #include "davinci-mcasp.h" | 38 | #include "davinci-mcasp.h" |
| 39 | 39 | ||
| 40 | struct davinci_mcasp_context { | ||
| 41 | u32 txfmtctl; | ||
| 42 | u32 rxfmtctl; | ||
| 43 | u32 txfmt; | ||
| 44 | u32 rxfmt; | ||
| 45 | u32 aclkxctl; | ||
| 46 | u32 aclkrctl; | ||
| 47 | u32 pdir; | ||
| 48 | }; | ||
| 49 | |||
| 40 | struct davinci_mcasp { | 50 | struct davinci_mcasp { |
| 41 | struct davinci_pcm_dma_params dma_params[2]; | 51 | struct davinci_pcm_dma_params dma_params[2]; |
| 42 | struct snd_dmaengine_dai_dma_data dma_data[2]; | 52 | struct snd_dmaengine_dai_dma_data dma_data[2]; |
| @@ -53,6 +63,9 @@ struct davinci_mcasp { | |||
| 53 | u16 bclk_lrclk_ratio; | 63 | u16 bclk_lrclk_ratio; |
| 54 | int streams; | 64 | int streams; |
| 55 | 65 | ||
| 66 | int sysclk_freq; | ||
| 67 | bool bclk_master; | ||
| 68 | |||
| 56 | /* McASP FIFO related */ | 69 | /* McASP FIFO related */ |
| 57 | u8 txnumevt; | 70 | u8 txnumevt; |
| 58 | u8 rxnumevt; | 71 | u8 rxnumevt; |
| @@ -60,15 +73,7 @@ struct davinci_mcasp { | |||
| 60 | bool dat_port; | 73 | bool dat_port; |
| 61 | 74 | ||
| 62 | #ifdef CONFIG_PM_SLEEP | 75 | #ifdef CONFIG_PM_SLEEP |
| 63 | struct { | 76 | struct davinci_mcasp_context context; |
| 64 | u32 txfmtctl; | ||
| 65 | u32 rxfmtctl; | ||
| 66 | u32 txfmt; | ||
| 67 | u32 rxfmt; | ||
| 68 | u32 aclkxctl; | ||
| 69 | u32 aclkrctl; | ||
| 70 | u32 pdir; | ||
| 71 | } context; | ||
| 72 | #endif | 77 | #endif |
| 73 | }; | 78 | }; |
| 74 | 79 | ||
| @@ -294,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
| 294 | 299 | ||
| 295 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 300 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); |
| 296 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 301 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); |
| 302 | mcasp->bclk_master = 1; | ||
| 297 | break; | 303 | break; |
| 298 | case SND_SOC_DAIFMT_CBM_CFS: | 304 | case SND_SOC_DAIFMT_CBM_CFS: |
| 299 | /* codec is clock master and frame slave */ | 305 | /* codec is clock master and frame slave */ |
| @@ -305,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
| 305 | 311 | ||
| 306 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 312 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); |
| 307 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 313 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); |
| 314 | mcasp->bclk_master = 0; | ||
| 308 | break; | 315 | break; |
| 309 | case SND_SOC_DAIFMT_CBM_CFM: | 316 | case SND_SOC_DAIFMT_CBM_CFM: |
| 310 | /* codec is clock and frame master */ | 317 | /* codec is clock and frame master */ |
| @@ -316,6 +323,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
| 316 | 323 | ||
| 317 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, | 324 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, |
| 318 | ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); | 325 | ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); |
| 326 | mcasp->bclk_master = 0; | ||
| 319 | break; | 327 | break; |
| 320 | 328 | ||
| 321 | default: | 329 | default: |
| @@ -410,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
| 410 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 418 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); |
| 411 | } | 419 | } |
| 412 | 420 | ||
| 421 | mcasp->sysclk_freq = freq; | ||
| 422 | |||
| 413 | return 0; | 423 | return 0; |
| 414 | } | 424 | } |
| 415 | 425 | ||
| @@ -603,20 +613,23 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
| 603 | u8 fifo_level; | 613 | u8 fifo_level; |
| 604 | u8 slots = mcasp->tdm_slots; | 614 | u8 slots = mcasp->tdm_slots; |
| 605 | u8 active_serializers; | 615 | u8 active_serializers; |
| 606 | int channels; | 616 | int channels = params_channels(params); |
| 607 | int ret; | 617 | int ret; |
| 608 | struct snd_interval *pcm_channels = hw_param_interval(params, | ||
| 609 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 610 | channels = pcm_channels->min; | ||
| 611 | 618 | ||
| 612 | active_serializers = (channels + slots - 1) / slots; | 619 | /* If mcasp is BCLK master we need to set BCLK divider */ |
| 620 | if (mcasp->bclk_master) { | ||
| 621 | unsigned int bclk_freq = snd_soc_params_to_bclk(params); | ||
| 622 | if (mcasp->sysclk_freq % bclk_freq != 0) { | ||
| 623 | dev_err(mcasp->dev, "Can't produce requred BCLK\n"); | ||
| 624 | return -EINVAL; | ||
| 625 | } | ||
| 626 | davinci_mcasp_set_clkdiv( | ||
| 627 | cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); | ||
| 628 | } | ||
| 613 | 629 | ||
| 614 | if (mcasp_common_hw_param(mcasp, substream->stream, channels) == -EINVAL) | 630 | ret = mcasp_common_hw_param(mcasp, substream->stream, channels); |
| 615 | return -EINVAL; | 631 | if (ret) |
| 616 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 632 | return ret; |
| 617 | fifo_level = mcasp->txnumevt * active_serializers; | ||
| 618 | else | ||
| 619 | fifo_level = mcasp->rxnumevt * active_serializers; | ||
| 620 | 633 | ||
| 621 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 634 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
| 622 | ret = mcasp_dit_hw_param(mcasp); | 635 | ret = mcasp_dit_hw_param(mcasp); |
| @@ -658,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
| 658 | return -EINVAL; | 671 | return -EINVAL; |
| 659 | } | 672 | } |
| 660 | 673 | ||
| 674 | /* Calculate FIFO level */ | ||
| 675 | active_serializers = (channels + slots - 1) / slots; | ||
| 676 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 677 | fifo_level = mcasp->txnumevt * active_serializers; | ||
| 678 | else | ||
| 679 | fifo_level = mcasp->rxnumevt * active_serializers; | ||
| 680 | |||
| 661 | if (mcasp->version == MCASP_VERSION_2 && !fifo_level) | 681 | if (mcasp->version == MCASP_VERSION_2 && !fifo_level) |
| 662 | dma_params->acnt = 4; | 682 | dma_params->acnt = 4; |
| 663 | else | 683 | else |
| @@ -719,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | |||
| 719 | .set_sysclk = davinci_mcasp_set_sysclk, | 739 | .set_sysclk = davinci_mcasp_set_sysclk, |
| 720 | }; | 740 | }; |
| 721 | 741 | ||
| 742 | #ifdef CONFIG_PM_SLEEP | ||
| 743 | static int davinci_mcasp_suspend(struct snd_soc_dai *dai) | ||
| 744 | { | ||
| 745 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
| 746 | struct davinci_mcasp_context *context = &mcasp->context; | ||
| 747 | |||
| 748 | context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | ||
| 749 | context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | ||
| 750 | context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | ||
| 751 | context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | ||
| 752 | context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | ||
| 753 | context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | ||
| 754 | context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | ||
| 755 | |||
| 756 | return 0; | ||
| 757 | } | ||
| 758 | |||
| 759 | static int davinci_mcasp_resume(struct snd_soc_dai *dai) | ||
| 760 | { | ||
| 761 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
| 762 | struct davinci_mcasp_context *context = &mcasp->context; | ||
| 763 | |||
| 764 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); | ||
| 765 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); | ||
| 766 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); | ||
| 767 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); | ||
| 768 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); | ||
| 769 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); | ||
| 770 | mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); | ||
| 771 | |||
| 772 | return 0; | ||
| 773 | } | ||
| 774 | #else | ||
| 775 | #define davinci_mcasp_suspend NULL | ||
| 776 | #define davinci_mcasp_resume NULL | ||
| 777 | #endif | ||
| 778 | |||
| 722 | #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 | 779 | #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 |
| 723 | 780 | ||
| 724 | #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ | 781 | #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ |
| @@ -735,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | |||
| 735 | static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | 792 | static struct snd_soc_dai_driver davinci_mcasp_dai[] = { |
| 736 | { | 793 | { |
| 737 | .name = "davinci-mcasp.0", | 794 | .name = "davinci-mcasp.0", |
| 795 | .suspend = davinci_mcasp_suspend, | ||
| 796 | .resume = davinci_mcasp_resume, | ||
| 738 | .playback = { | 797 | .playback = { |
| 739 | .channels_min = 2, | 798 | .channels_min = 2, |
| 740 | .channels_max = 32 * 16, | 799 | .channels_max = 32 * 16, |
| @@ -768,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { | |||
| 768 | }; | 827 | }; |
| 769 | 828 | ||
| 770 | /* Some HW specific values and defaults. The rest is filled in from DT. */ | 829 | /* Some HW specific values and defaults. The rest is filled in from DT. */ |
| 771 | static struct snd_platform_data dm646x_mcasp_pdata = { | 830 | static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { |
| 772 | .tx_dma_offset = 0x400, | 831 | .tx_dma_offset = 0x400, |
| 773 | .rx_dma_offset = 0x400, | 832 | .rx_dma_offset = 0x400, |
| 774 | .asp_chan_q = EVENTQ_0, | 833 | .asp_chan_q = EVENTQ_0, |
| 775 | .version = MCASP_VERSION_1, | 834 | .version = MCASP_VERSION_1, |
| 776 | }; | 835 | }; |
| 777 | 836 | ||
| 778 | static struct snd_platform_data da830_mcasp_pdata = { | 837 | static struct davinci_mcasp_pdata da830_mcasp_pdata = { |
| 779 | .tx_dma_offset = 0x2000, | 838 | .tx_dma_offset = 0x2000, |
| 780 | .rx_dma_offset = 0x2000, | 839 | .rx_dma_offset = 0x2000, |
| 781 | .asp_chan_q = EVENTQ_0, | 840 | .asp_chan_q = EVENTQ_0, |
| 782 | .version = MCASP_VERSION_2, | 841 | .version = MCASP_VERSION_2, |
| 783 | }; | 842 | }; |
| 784 | 843 | ||
| 785 | static struct snd_platform_data am33xx_mcasp_pdata = { | 844 | static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { |
| 786 | .tx_dma_offset = 0, | 845 | .tx_dma_offset = 0, |
| 787 | .rx_dma_offset = 0, | 846 | .rx_dma_offset = 0, |
| 788 | .asp_chan_q = EVENTQ_0, | 847 | .asp_chan_q = EVENTQ_0, |
| 789 | .version = MCASP_VERSION_3, | 848 | .version = MCASP_VERSION_3, |
| 790 | }; | 849 | }; |
| 791 | 850 | ||
| 792 | static struct snd_platform_data dra7_mcasp_pdata = { | 851 | static struct davinci_mcasp_pdata dra7_mcasp_pdata = { |
| 793 | .tx_dma_offset = 0x200, | 852 | .tx_dma_offset = 0x200, |
| 794 | .rx_dma_offset = 0x284, | 853 | .rx_dma_offset = 0x284, |
| 795 | .asp_chan_q = EVENTQ_0, | 854 | .asp_chan_q = EVENTQ_0, |
| @@ -857,11 +916,11 @@ err1: | |||
| 857 | return ret; | 916 | return ret; |
| 858 | } | 917 | } |
| 859 | 918 | ||
| 860 | static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( | 919 | static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( |
| 861 | struct platform_device *pdev) | 920 | struct platform_device *pdev) |
| 862 | { | 921 | { |
| 863 | struct device_node *np = pdev->dev.of_node; | 922 | struct device_node *np = pdev->dev.of_node; |
| 864 | struct snd_platform_data *pdata = NULL; | 923 | struct davinci_mcasp_pdata *pdata = NULL; |
| 865 | const struct of_device_id *match = | 924 | const struct of_device_id *match = |
| 866 | of_match_device(mcasp_dt_ids, &pdev->dev); | 925 | of_match_device(mcasp_dt_ids, &pdev->dev); |
| 867 | struct of_phandle_args dma_spec; | 926 | struct of_phandle_args dma_spec; |
| @@ -874,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( | |||
| 874 | pdata = pdev->dev.platform_data; | 933 | pdata = pdev->dev.platform_data; |
| 875 | return pdata; | 934 | return pdata; |
| 876 | } else if (match) { | 935 | } else if (match) { |
| 877 | pdata = (struct snd_platform_data *) match->data; | 936 | pdata = (struct davinci_mcasp_pdata*) match->data; |
| 878 | } else { | 937 | } else { |
| 879 | /* control shouldn't reach here. something is wrong */ | 938 | /* control shouldn't reach here. something is wrong */ |
| 880 | ret = -EINVAL; | 939 | ret = -EINVAL; |
| @@ -966,9 +1025,9 @@ nodata: | |||
| 966 | 1025 | ||
| 967 | static int davinci_mcasp_probe(struct platform_device *pdev) | 1026 | static int davinci_mcasp_probe(struct platform_device *pdev) |
| 968 | { | 1027 | { |
| 969 | struct davinci_pcm_dma_params *dma_data; | 1028 | struct davinci_pcm_dma_params *dma_params; |
| 970 | struct resource *mem, *ioarea, *res, *dat; | 1029 | struct resource *mem, *ioarea, *res, *dat; |
| 971 | struct snd_platform_data *pdata; | 1030 | struct davinci_mcasp_pdata *pdata; |
| 972 | struct davinci_mcasp *mcasp; | 1031 | struct davinci_mcasp *mcasp; |
| 973 | int ret; | 1032 | int ret; |
| 974 | 1033 | ||
| @@ -1035,41 +1094,41 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
| 1035 | if (dat) | 1094 | if (dat) |
| 1036 | mcasp->dat_port = true; | 1095 | mcasp->dat_port = true; |
| 1037 | 1096 | ||
| 1038 | dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; | 1097 | dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; |
| 1039 | dma_data->asp_chan_q = pdata->asp_chan_q; | 1098 | dma_params->asp_chan_q = pdata->asp_chan_q; |
| 1040 | dma_data->ram_chan_q = pdata->ram_chan_q; | 1099 | dma_params->ram_chan_q = pdata->ram_chan_q; |
| 1041 | dma_data->sram_pool = pdata->sram_pool; | 1100 | dma_params->sram_pool = pdata->sram_pool; |
| 1042 | dma_data->sram_size = pdata->sram_size_playback; | 1101 | dma_params->sram_size = pdata->sram_size_playback; |
| 1043 | if (dat) | 1102 | if (dat) |
| 1044 | dma_data->dma_addr = dat->start; | 1103 | dma_params->dma_addr = dat->start; |
| 1045 | else | 1104 | else |
| 1046 | dma_data->dma_addr = mem->start + pdata->tx_dma_offset; | 1105 | dma_params->dma_addr = mem->start + pdata->tx_dma_offset; |
| 1047 | 1106 | ||
| 1048 | /* Unconditional dmaengine stuff */ | 1107 | /* Unconditional dmaengine stuff */ |
| 1049 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; | 1108 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr; |
| 1050 | 1109 | ||
| 1051 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 1110 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
| 1052 | if (res) | 1111 | if (res) |
| 1053 | dma_data->channel = res->start; | 1112 | dma_params->channel = res->start; |
| 1054 | else | 1113 | else |
| 1055 | dma_data->channel = pdata->tx_dma_channel; | 1114 | dma_params->channel = pdata->tx_dma_channel; |
| 1056 | 1115 | ||
| 1057 | dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; | 1116 | dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; |
| 1058 | dma_data->asp_chan_q = pdata->asp_chan_q; | 1117 | dma_params->asp_chan_q = pdata->asp_chan_q; |
| 1059 | dma_data->ram_chan_q = pdata->ram_chan_q; | 1118 | dma_params->ram_chan_q = pdata->ram_chan_q; |
| 1060 | dma_data->sram_pool = pdata->sram_pool; | 1119 | dma_params->sram_pool = pdata->sram_pool; |
| 1061 | dma_data->sram_size = pdata->sram_size_capture; | 1120 | dma_params->sram_size = pdata->sram_size_capture; |
| 1062 | if (dat) | 1121 | if (dat) |
| 1063 | dma_data->dma_addr = dat->start; | 1122 | dma_params->dma_addr = dat->start; |
| 1064 | else | 1123 | else |
| 1065 | dma_data->dma_addr = mem->start + pdata->rx_dma_offset; | 1124 | dma_params->dma_addr = mem->start + pdata->rx_dma_offset; |
| 1066 | 1125 | ||
| 1067 | /* Unconditional dmaengine stuff */ | 1126 | /* Unconditional dmaengine stuff */ |
| 1068 | mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; | 1127 | mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr; |
| 1069 | 1128 | ||
| 1070 | if (mcasp->version < MCASP_VERSION_3) { | 1129 | if (mcasp->version < MCASP_VERSION_3) { |
| 1071 | mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; | 1130 | mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; |
| 1072 | /* dma_data->dma_addr is pointing to the data port address */ | 1131 | /* dma_params->dma_addr is pointing to the data port address */ |
| 1073 | mcasp->dat_port = true; | 1132 | mcasp->dat_port = true; |
| 1074 | } else { | 1133 | } else { |
| 1075 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; | 1134 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; |
| @@ -1077,9 +1136,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
| 1077 | 1136 | ||
| 1078 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 1137 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
| 1079 | if (res) | 1138 | if (res) |
| 1080 | dma_data->channel = res->start; | 1139 | dma_params->channel = res->start; |
| 1081 | else | 1140 | else |
| 1082 | dma_data->channel = pdata->rx_dma_channel; | 1141 | dma_params->channel = pdata->rx_dma_channel; |
| 1083 | 1142 | ||
| 1084 | /* Unconditional dmaengine stuff */ | 1143 | /* Unconditional dmaengine stuff */ |
| 1085 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; | 1144 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; |
| @@ -1127,49 +1186,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev) | |||
| 1127 | return 0; | 1186 | return 0; |
| 1128 | } | 1187 | } |
| 1129 | 1188 | ||
| 1130 | #ifdef CONFIG_PM_SLEEP | ||
| 1131 | static int davinci_mcasp_suspend(struct device *dev) | ||
| 1132 | { | ||
| 1133 | struct davinci_mcasp *mcasp = dev_get_drvdata(dev); | ||
| 1134 | |||
| 1135 | mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | ||
| 1136 | mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | ||
| 1137 | mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | ||
| 1138 | mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | ||
| 1139 | mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | ||
| 1140 | mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | ||
| 1141 | mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | ||
| 1142 | |||
| 1143 | return 0; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static int davinci_mcasp_resume(struct device *dev) | ||
| 1147 | { | ||
| 1148 | struct davinci_mcasp *mcasp = dev_get_drvdata(dev); | ||
| 1149 | |||
| 1150 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl); | ||
| 1151 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl); | ||
| 1152 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt); | ||
| 1153 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt); | ||
| 1154 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl); | ||
| 1155 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl); | ||
| 1156 | mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir); | ||
| 1157 | |||
| 1158 | return 0; | ||
| 1159 | } | ||
| 1160 | #endif | ||
| 1161 | |||
| 1162 | SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops, | ||
| 1163 | davinci_mcasp_suspend, | ||
| 1164 | davinci_mcasp_resume); | ||
| 1165 | |||
| 1166 | static struct platform_driver davinci_mcasp_driver = { | 1189 | static struct platform_driver davinci_mcasp_driver = { |
| 1167 | .probe = davinci_mcasp_probe, | 1190 | .probe = davinci_mcasp_probe, |
| 1168 | .remove = davinci_mcasp_remove, | 1191 | .remove = davinci_mcasp_remove, |
| 1169 | .driver = { | 1192 | .driver = { |
| 1170 | .name = "davinci-mcasp", | 1193 | .name = "davinci-mcasp", |
| 1171 | .owner = THIS_MODULE, | 1194 | .owner = THIS_MODULE, |
| 1172 | .pm = &davinci_mcasp_pm_ops, | ||
| 1173 | .of_match_table = mcasp_dt_ids, | 1195 | .of_match_table = mcasp_dt_ids, |
| 1174 | }, | 1196 | }, |
| 1175 | }; | 1197 | }; |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 07f8f141727d..597962ec28fa 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | config SND_SOC_FSL_SAI | 1 | config SND_SOC_FSL_SAI |
| 2 | tristate | 2 | tristate |
| 3 | select REGMAP_MMIO | ||
| 3 | select SND_SOC_GENERIC_DMAENGINE_PCM | 4 | select SND_SOC_GENERIC_DMAENGINE_PCM |
| 4 | 5 | ||
| 5 | config SND_SOC_FSL_SSI | 6 | config SND_SOC_FSL_SSI |
| @@ -7,9 +8,11 @@ config SND_SOC_FSL_SSI | |||
| 7 | 8 | ||
| 8 | config SND_SOC_FSL_SPDIF | 9 | config SND_SOC_FSL_SPDIF |
| 9 | tristate | 10 | tristate |
| 11 | select REGMAP_MMIO | ||
| 10 | 12 | ||
| 11 | config SND_SOC_FSL_ESAI | 13 | config SND_SOC_FSL_ESAI |
| 12 | tristate | 14 | tristate |
| 15 | select REGMAP_MMIO | ||
| 13 | 16 | ||
| 14 | config SND_SOC_FSL_UTILS | 17 | config SND_SOC_FSL_UTILS |
| 15 | tristate | 18 | tristate |
| @@ -168,12 +171,14 @@ config SND_SOC_EUKREA_TLV320 | |||
| 168 | depends on MACH_EUKREA_MBIMX27_BASEBOARD \ | 171 | depends on MACH_EUKREA_MBIMX27_BASEBOARD \ |
| 169 | || MACH_EUKREA_MBIMXSD25_BASEBOARD \ | 172 | || MACH_EUKREA_MBIMXSD25_BASEBOARD \ |
| 170 | || MACH_EUKREA_MBIMXSD35_BASEBOARD \ | 173 | || MACH_EUKREA_MBIMXSD35_BASEBOARD \ |
| 171 | || MACH_EUKREA_MBIMXSD51_BASEBOARD | 174 | || MACH_EUKREA_MBIMXSD51_BASEBOARD \ |
| 175 | || (OF && ARM) | ||
| 172 | depends on I2C | 176 | depends on I2C |
| 173 | select SND_SOC_TLV320AIC23 | 177 | select SND_SOC_TLV320AIC23_I2C |
| 174 | select SND_SOC_IMX_PCM_FIQ | ||
| 175 | select SND_SOC_IMX_AUDMUX | 178 | select SND_SOC_IMX_AUDMUX |
| 176 | select SND_SOC_IMX_SSI | 179 | select SND_SOC_IMX_SSI |
| 180 | select SND_SOC_FSL_SSI | ||
| 181 | select SND_SOC_IMX_PCM_DMA | ||
| 177 | help | 182 | help |
| 178 | Enable I2S based access to the TLV320AIC23B codec attached | 183 | Enable I2S based access to the TLV320AIC23B codec attached |
| 179 | to the SSI interface | 184 | to the SSI interface |
| @@ -204,7 +209,6 @@ config SND_SOC_IMX_SPDIF | |||
| 204 | tristate "SoC Audio support for i.MX boards with S/PDIF" | 209 | tristate "SoC Audio support for i.MX boards with S/PDIF" |
| 205 | select SND_SOC_IMX_PCM_DMA | 210 | select SND_SOC_IMX_PCM_DMA |
| 206 | select SND_SOC_FSL_SPDIF | 211 | select SND_SOC_FSL_SPDIF |
| 207 | select REGMAP_MMIO | ||
| 208 | help | 212 | help |
| 209 | SoC Audio support for i.MX boards with S/PDIF | 213 | SoC Audio support for i.MX boards with S/PDIF |
| 210 | Say Y if you want to add support for SoC audio on an i.MX board with | 214 | Say Y if you want to add support for SoC audio on an i.MX board with |
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 5983740be123..eb093d5b85c4 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c | |||
| @@ -15,8 +15,11 @@ | |||
| 15 | * | 15 | * |
| 16 | */ | 16 | */ |
| 17 | 17 | ||
| 18 | #include <linux/errno.h> | ||
| 18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 19 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_platform.h> | ||
| 20 | #include <linux/device.h> | 23 | #include <linux/device.h> |
| 21 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
| 22 | #include <sound/core.h> | 25 | #include <sound/core.h> |
| @@ -26,6 +29,7 @@ | |||
| 26 | 29 | ||
| 27 | #include "../codecs/tlv320aic23.h" | 30 | #include "../codecs/tlv320aic23.h" |
| 28 | #include "imx-ssi.h" | 31 | #include "imx-ssi.h" |
| 32 | #include "fsl_ssi.h" | ||
| 29 | #include "imx-audmux.h" | 33 | #include "imx-audmux.h" |
| 30 | 34 | ||
| 31 | #define CODEC_CLOCK 12000000 | 35 | #define CODEC_CLOCK 12000000 |
| @@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, | |||
| 41 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 45 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
| 42 | SND_SOC_DAIFMT_NB_NF | | 46 | SND_SOC_DAIFMT_NB_NF | |
| 43 | SND_SOC_DAIFMT_CBM_CFM); | 47 | SND_SOC_DAIFMT_CBM_CFM); |
| 44 | if (ret) { | 48 | /* fsl_ssi lacks the set_fmt ops. */ |
| 49 | if (ret && ret != -ENOTSUPP) { | ||
| 45 | dev_err(cpu_dai->dev, | 50 | dev_err(cpu_dai->dev, |
| 46 | "Failed to set the cpu dai format.\n"); | 51 | "Failed to set the cpu dai format.\n"); |
| 47 | return ret; | 52 | return ret; |
| @@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, | |||
| 63 | "Failed to set the codec sysclk.\n"); | 68 | "Failed to set the codec sysclk.\n"); |
| 64 | return ret; | 69 | return ret; |
| 65 | } | 70 | } |
| 71 | |||
| 66 | snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); | 72 | snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); |
| 67 | 73 | ||
| 68 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, | 74 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, |
| 69 | SND_SOC_CLOCK_IN); | 75 | SND_SOC_CLOCK_IN); |
| 70 | if (ret) { | 76 | /* fsl_ssi lacks the set_sysclk ops */ |
| 77 | if (ret && ret != -EINVAL) { | ||
| 71 | dev_err(cpu_dai->dev, | 78 | dev_err(cpu_dai->dev, |
| 72 | "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); | 79 | "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); |
| 73 | return ret; | 80 | return ret; |
| @@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = { | |||
| 84 | .name = "tlv320aic23", | 91 | .name = "tlv320aic23", |
| 85 | .stream_name = "TLV320AIC23", | 92 | .stream_name = "TLV320AIC23", |
| 86 | .codec_dai_name = "tlv320aic23-hifi", | 93 | .codec_dai_name = "tlv320aic23-hifi", |
| 87 | .platform_name = "imx-ssi.0", | ||
| 88 | .codec_name = "tlv320aic23-codec.0-001a", | ||
| 89 | .cpu_dai_name = "imx-ssi.0", | ||
| 90 | .ops = &eukrea_tlv320_snd_ops, | 94 | .ops = &eukrea_tlv320_snd_ops, |
| 91 | }; | 95 | }; |
| 92 | 96 | ||
| 93 | static struct snd_soc_card eukrea_tlv320 = { | 97 | static struct snd_soc_card eukrea_tlv320 = { |
| 94 | .name = "cpuimx-audio", | ||
| 95 | .owner = THIS_MODULE, | 98 | .owner = THIS_MODULE, |
| 96 | .dai_link = &eukrea_tlv320_dai, | 99 | .dai_link = &eukrea_tlv320_dai, |
| 97 | .num_links = 1, | 100 | .num_links = 1, |
| @@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
| 101 | { | 104 | { |
| 102 | int ret; | 105 | int ret; |
| 103 | int int_port = 0, ext_port; | 106 | int int_port = 0, ext_port; |
| 107 | struct device_node *np = pdev->dev.of_node; | ||
| 108 | struct device_node *ssi_np, *codec_np; | ||
| 104 | 109 | ||
| 105 | if (machine_is_eukrea_cpuimx27()) { | 110 | eukrea_tlv320.dev = &pdev->dev; |
| 111 | if (np) { | ||
| 112 | ret = snd_soc_of_parse_card_name(&eukrea_tlv320, | ||
| 113 | "eukrea,model"); | ||
| 114 | if (ret) { | ||
| 115 | dev_err(&pdev->dev, | ||
| 116 | "eukrea,model node missing or invalid.\n"); | ||
| 117 | goto err; | ||
| 118 | } | ||
| 119 | |||
| 120 | ssi_np = of_parse_phandle(pdev->dev.of_node, | ||
| 121 | "ssi-controller", 0); | ||
| 122 | if (!ssi_np) { | ||
| 123 | dev_err(&pdev->dev, | ||
| 124 | "ssi-controller missing or invalid.\n"); | ||
| 125 | ret = -ENODEV; | ||
| 126 | goto err; | ||
| 127 | } | ||
| 128 | |||
| 129 | codec_np = of_parse_phandle(ssi_np, "codec-handle", 0); | ||
| 130 | if (codec_np) | ||
| 131 | eukrea_tlv320_dai.codec_of_node = codec_np; | ||
| 132 | else | ||
| 133 | dev_err(&pdev->dev, "codec-handle node missing or invalid.\n"); | ||
| 134 | |||
| 135 | ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port); | ||
| 136 | if (ret) { | ||
| 137 | dev_err(&pdev->dev, | ||
| 138 | "fsl,mux-int-port node missing or invalid.\n"); | ||
| 139 | return ret; | ||
| 140 | } | ||
| 141 | ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port); | ||
| 142 | if (ret) { | ||
| 143 | dev_err(&pdev->dev, | ||
| 144 | "fsl,mux-ext-port node missing or invalid.\n"); | ||
| 145 | return ret; | ||
| 146 | } | ||
| 147 | |||
| 148 | /* | ||
| 149 | * The port numbering in the hardware manual starts at 1, while | ||
| 150 | * the audmux API expects it starts at 0. | ||
| 151 | */ | ||
| 152 | int_port--; | ||
| 153 | ext_port--; | ||
| 154 | |||
| 155 | eukrea_tlv320_dai.cpu_of_node = ssi_np; | ||
| 156 | eukrea_tlv320_dai.platform_of_node = ssi_np; | ||
| 157 | } else { | ||
| 158 | eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0"; | ||
| 159 | eukrea_tlv320_dai.platform_name = "imx-ssi.0"; | ||
| 160 | eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a"; | ||
| 161 | eukrea_tlv320.name = "cpuimx-audio"; | ||
| 162 | } | ||
| 163 | |||
| 164 | if (machine_is_eukrea_cpuimx27() || | ||
| 165 | of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) { | ||
| 106 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, | 166 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, |
| 107 | IMX_AUDMUX_V1_PCR_SYN | | 167 | IMX_AUDMUX_V1_PCR_SYN | |
| 108 | IMX_AUDMUX_V1_PCR_TFSDIR | | 168 | IMX_AUDMUX_V1_PCR_TFSDIR | |
| @@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
| 119 | ); | 179 | ); |
| 120 | } else if (machine_is_eukrea_cpuimx25sd() || | 180 | } else if (machine_is_eukrea_cpuimx25sd() || |
| 121 | machine_is_eukrea_cpuimx35sd() || | 181 | machine_is_eukrea_cpuimx35sd() || |
| 122 | machine_is_eukrea_cpuimx51sd()) { | 182 | machine_is_eukrea_cpuimx51sd() || |
| 123 | ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; | 183 | of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) { |
| 184 | if (!np) | ||
| 185 | ext_port = machine_is_eukrea_cpuimx25sd() ? | ||
| 186 | 4 : 3; | ||
| 187 | |||
| 124 | imx_audmux_v2_configure_port(int_port, | 188 | imx_audmux_v2_configure_port(int_port, |
| 125 | IMX_AUDMUX_V2_PTCR_SYN | | 189 | IMX_AUDMUX_V2_PTCR_SYN | |
| 126 | IMX_AUDMUX_V2_PTCR_TFSDIR | | 190 | IMX_AUDMUX_V2_PTCR_TFSDIR | |
| @@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
| 134 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) | 198 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) |
| 135 | ); | 199 | ); |
| 136 | } else { | 200 | } else { |
| 137 | /* return happy. We might run on a totally different machine */ | 201 | if (np) { |
| 138 | return 0; | 202 | /* The eukrea,asoc-tlv320 driver was explicitely |
| 203 | * requested (through the device tree). | ||
| 204 | */ | ||
| 205 | dev_err(&pdev->dev, | ||
| 206 | "Missing or invalid audmux DT node.\n"); | ||
| 207 | return -ENODEV; | ||
| 208 | } else { | ||
| 209 | /* Return happy. | ||
| 210 | * We might run on a totally different machine. | ||
| 211 | */ | ||
| 212 | return 0; | ||
| 213 | } | ||
| 139 | } | 214 | } |
| 140 | 215 | ||
| 141 | eukrea_tlv320.dev = &pdev->dev; | ||
| 142 | ret = snd_soc_register_card(&eukrea_tlv320); | 216 | ret = snd_soc_register_card(&eukrea_tlv320); |
| 217 | err: | ||
| 143 | if (ret) | 218 | if (ret) |
| 144 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | 219 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); |
| 220 | if (np) | ||
| 221 | of_node_put(ssi_np); | ||
| 145 | 222 | ||
| 146 | return ret; | 223 | return ret; |
| 147 | } | 224 | } |
| @@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev) | |||
| 153 | return 0; | 230 | return 0; |
| 154 | } | 231 | } |
| 155 | 232 | ||
| 233 | static const struct of_device_id imx_tlv320_dt_ids[] = { | ||
| 234 | { .compatible = "eukrea,asoc-tlv320"}, | ||
| 235 | { /* sentinel */ } | ||
| 236 | }; | ||
| 237 | MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids); | ||
| 238 | |||
| 156 | static struct platform_driver eukrea_tlv320_driver = { | 239 | static struct platform_driver eukrea_tlv320_driver = { |
| 157 | .driver = { | 240 | .driver = { |
| 158 | .name = "eukrea_tlv320", | 241 | .name = "eukrea_tlv320", |
| 159 | .owner = THIS_MODULE, | 242 | .owner = THIS_MODULE, |
| 243 | .of_match_table = imx_tlv320_dt_ids, | ||
| 160 | }, | 244 | }, |
| 161 | .probe = eukrea_tlv320_probe, | 245 | .probe = eukrea_tlv320_probe, |
| 162 | .remove = eukrea_tlv320_remove, | 246 | .remove = eukrea_tlv320_remove, |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index c84026c99134..0ba37005ab04 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
| @@ -431,17 +431,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
| 431 | static int fsl_esai_startup(struct snd_pcm_substream *substream, | 431 | static int fsl_esai_startup(struct snd_pcm_substream *substream, |
| 432 | struct snd_soc_dai *dai) | 432 | struct snd_soc_dai *dai) |
| 433 | { | 433 | { |
| 434 | int ret; | ||
| 434 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); | 435 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); |
| 435 | 436 | ||
| 436 | /* | 437 | /* |
| 437 | * Some platforms might use the same bit to gate all three or two of | 438 | * Some platforms might use the same bit to gate all three or two of |
| 438 | * clocks, so keep all clocks open/close at the same time for safety | 439 | * clocks, so keep all clocks open/close at the same time for safety |
| 439 | */ | 440 | */ |
| 440 | clk_prepare_enable(esai_priv->coreclk); | 441 | ret = clk_prepare_enable(esai_priv->coreclk); |
| 441 | if (!IS_ERR(esai_priv->extalclk)) | 442 | if (ret) |
| 442 | clk_prepare_enable(esai_priv->extalclk); | 443 | return ret; |
| 443 | if (!IS_ERR(esai_priv->fsysclk)) | 444 | if (!IS_ERR(esai_priv->extalclk)) { |
| 444 | clk_prepare_enable(esai_priv->fsysclk); | 445 | ret = clk_prepare_enable(esai_priv->extalclk); |
| 446 | if (ret) | ||
| 447 | goto err_extalck; | ||
| 448 | } | ||
| 449 | if (!IS_ERR(esai_priv->fsysclk)) { | ||
| 450 | ret = clk_prepare_enable(esai_priv->fsysclk); | ||
| 451 | if (ret) | ||
| 452 | goto err_fsysclk; | ||
| 453 | } | ||
| 445 | 454 | ||
| 446 | if (!dai->active) { | 455 | if (!dai->active) { |
| 447 | /* Reset Port C */ | 456 | /* Reset Port C */ |
| @@ -463,6 +472,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, | |||
| 463 | } | 472 | } |
| 464 | 473 | ||
| 465 | return 0; | 474 | return 0; |
| 475 | |||
| 476 | err_fsysclk: | ||
| 477 | if (!IS_ERR(esai_priv->extalclk)) | ||
| 478 | clk_disable_unprepare(esai_priv->extalclk); | ||
| 479 | err_extalck: | ||
| 480 | clk_disable_unprepare(esai_priv->coreclk); | ||
| 481 | |||
| 482 | return ret; | ||
| 466 | } | 483 | } |
| 467 | 484 | ||
| 468 | static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | 485 | static int fsl_esai_hw_params(struct snd_pcm_substream *substream, |
| @@ -661,7 +678,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) | |||
| 661 | } | 678 | } |
| 662 | } | 679 | } |
| 663 | 680 | ||
| 664 | static const struct regmap_config fsl_esai_regmap_config = { | 681 | static struct regmap_config fsl_esai_regmap_config = { |
| 665 | .reg_bits = 32, | 682 | .reg_bits = 32, |
| 666 | .reg_stride = 4, | 683 | .reg_stride = 4, |
| 667 | .val_bits = 32, | 684 | .val_bits = 32, |
| @@ -687,6 +704,9 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
| 687 | esai_priv->pdev = pdev; | 704 | esai_priv->pdev = pdev; |
| 688 | strcpy(esai_priv->name, np->name); | 705 | strcpy(esai_priv->name, np->name); |
| 689 | 706 | ||
| 707 | if (of_property_read_bool(np, "big-endian")) | ||
| 708 | fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
| 709 | |||
| 690 | /* Get the addresses and IRQ */ | 710 | /* Get the addresses and IRQ */ |
| 691 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 711 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 692 | regs = devm_ioremap_resource(&pdev->dev, res); | 712 | regs = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cdd3fa830704..c4a423111673 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/dmaengine.h> | 15 | #include <linux/dmaengine.h> |
| 16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 17 | #include <linux/of_address.h> | 17 | #include <linux/of_address.h> |
| 18 | #include <linux/regmap.h> | ||
| 18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 19 | #include <sound/core.h> | 20 | #include <sound/core.h> |
| 20 | #include <sound/dmaengine_pcm.h> | 21 | #include <sound/dmaengine_pcm.h> |
| @@ -22,34 +23,6 @@ | |||
| 22 | 23 | ||
| 23 | #include "fsl_sai.h" | 24 | #include "fsl_sai.h" |
| 24 | 25 | ||
| 25 | static inline u32 sai_readl(struct fsl_sai *sai, | ||
| 26 | const void __iomem *addr) | ||
| 27 | { | ||
| 28 | u32 val; | ||
| 29 | |||
| 30 | val = __raw_readl(addr); | ||
| 31 | |||
| 32 | if (likely(sai->big_endian_regs)) | ||
| 33 | val = be32_to_cpu(val); | ||
| 34 | else | ||
| 35 | val = le32_to_cpu(val); | ||
| 36 | rmb(); | ||
| 37 | |||
| 38 | return val; | ||
| 39 | } | ||
| 40 | |||
| 41 | static inline void sai_writel(struct fsl_sai *sai, | ||
| 42 | u32 val, void __iomem *addr) | ||
| 43 | { | ||
| 44 | wmb(); | ||
| 45 | if (likely(sai->big_endian_regs)) | ||
| 46 | val = cpu_to_be32(val); | ||
| 47 | else | ||
| 48 | val = cpu_to_le32(val); | ||
| 49 | |||
| 50 | __raw_writel(val, addr); | ||
| 51 | } | ||
| 52 | |||
| 53 | static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | 26 | static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, |
| 54 | int clk_id, unsigned int freq, int fsl_dir) | 27 | int clk_id, unsigned int freq, int fsl_dir) |
| 55 | { | 28 | { |
| @@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
| 61 | else | 34 | else |
| 62 | reg_cr2 = FSL_SAI_RCR2; | 35 | reg_cr2 = FSL_SAI_RCR2; |
| 63 | 36 | ||
| 64 | val_cr2 = sai_readl(sai, sai->base + reg_cr2); | 37 | regmap_read(sai->regmap, reg_cr2, &val_cr2); |
| 38 | |||
| 65 | val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; | 39 | val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; |
| 66 | 40 | ||
| 67 | switch (clk_id) { | 41 | switch (clk_id) { |
| @@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
| 81 | return -EINVAL; | 55 | return -EINVAL; |
| 82 | } | 56 | } |
| 83 | 57 | ||
| 84 | sai_writel(sai, val_cr2, sai->base + reg_cr2); | 58 | regmap_write(sai->regmap, reg_cr2, val_cr2); |
| 85 | 59 | ||
| 86 | return 0; | 60 | return 0; |
| 87 | } | 61 | } |
| @@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
| 89 | static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | 63 | static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
| 90 | int clk_id, unsigned int freq, int dir) | 64 | int clk_id, unsigned int freq, int dir) |
| 91 | { | 65 | { |
| 92 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | ||
| 93 | int ret; | 66 | int ret; |
| 94 | 67 | ||
| 95 | if (dir == SND_SOC_CLOCK_IN) | 68 | if (dir == SND_SOC_CLOCK_IN) |
| 96 | return 0; | 69 | return 0; |
| 97 | 70 | ||
| 98 | ret = clk_prepare_enable(sai->clk); | ||
| 99 | if (ret) | ||
| 100 | return ret; | ||
| 101 | |||
| 102 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, | 71 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, |
| 103 | FSL_FMT_TRANSMITTER); | 72 | FSL_FMT_TRANSMITTER); |
| 104 | if (ret) { | 73 | if (ret) { |
| 105 | dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); | 74 | dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); |
| 106 | goto err_clk; | 75 | return ret; |
| 107 | } | 76 | } |
| 108 | 77 | ||
| 109 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, | 78 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, |
| 110 | FSL_FMT_RECEIVER); | 79 | FSL_FMT_RECEIVER); |
| 111 | if (ret) { | 80 | if (ret) |
| 112 | dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); | 81 | dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); |
| 113 | goto err_clk; | ||
| 114 | } | ||
| 115 | |||
| 116 | err_clk: | ||
| 117 | clk_disable_unprepare(sai->clk); | ||
| 118 | 82 | ||
| 119 | return ret; | 83 | return ret; |
| 120 | } | 84 | } |
| @@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
| 133 | reg_cr4 = FSL_SAI_RCR4; | 97 | reg_cr4 = FSL_SAI_RCR4; |
| 134 | } | 98 | } |
| 135 | 99 | ||
| 136 | val_cr2 = sai_readl(sai, sai->base + reg_cr2); | 100 | regmap_read(sai->regmap, reg_cr2, &val_cr2); |
| 137 | val_cr4 = sai_readl(sai, sai->base + reg_cr4); | 101 | regmap_read(sai->regmap, reg_cr4, &val_cr4); |
| 138 | 102 | ||
| 139 | if (sai->big_endian_data) | 103 | if (sai->big_endian_data) |
| 140 | val_cr4 &= ~FSL_SAI_CR4_MF; | 104 | val_cr4 &= ~FSL_SAI_CR4_MF; |
| 141 | else | 105 | else |
| 142 | val_cr4 |= FSL_SAI_CR4_MF; | 106 | val_cr4 |= FSL_SAI_CR4_MF; |
| 143 | 107 | ||
| 108 | /* DAI mode */ | ||
| 144 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 109 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
| 145 | case SND_SOC_DAIFMT_I2S: | 110 | case SND_SOC_DAIFMT_I2S: |
| 111 | /* | ||
| 112 | * Frame low, 1clk before data, one word length for frame sync, | ||
| 113 | * frame sync starts one serial clock cycle earlier, | ||
| 114 | * that is, together with the last bit of the previous | ||
| 115 | * data word. | ||
| 116 | */ | ||
| 117 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
| 118 | val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; | ||
| 119 | break; | ||
| 120 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 121 | /* | ||
| 122 | * Frame high, one word length for frame sync, | ||
| 123 | * frame sync asserts with the first bit of the frame. | ||
| 124 | */ | ||
| 125 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
| 126 | val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); | ||
| 127 | break; | ||
| 128 | case SND_SOC_DAIFMT_DSP_A: | ||
| 129 | /* | ||
| 130 | * Frame high, 1clk before data, one bit for frame sync, | ||
| 131 | * frame sync starts one serial clock cycle earlier, | ||
| 132 | * that is, together with the last bit of the previous | ||
| 133 | * data word. | ||
| 134 | */ | ||
| 135 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
| 136 | val_cr4 &= ~FSL_SAI_CR4_FSP; | ||
| 146 | val_cr4 |= FSL_SAI_CR4_FSE; | 137 | val_cr4 |= FSL_SAI_CR4_FSE; |
| 138 | sai->is_dsp_mode = true; | ||
| 139 | break; | ||
| 140 | case SND_SOC_DAIFMT_DSP_B: | ||
| 141 | /* | ||
| 142 | * Frame high, one bit for frame sync, | ||
| 143 | * frame sync asserts with the first bit of the frame. | ||
| 144 | */ | ||
| 145 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
| 146 | val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); | ||
| 147 | sai->is_dsp_mode = true; | ||
| 147 | break; | 148 | break; |
| 149 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 150 | /* To be done */ | ||
| 148 | default: | 151 | default: |
| 149 | return -EINVAL; | 152 | return -EINVAL; |
| 150 | } | 153 | } |
| 151 | 154 | ||
| 155 | /* DAI clock inversion */ | ||
| 152 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 156 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
| 153 | case SND_SOC_DAIFMT_IB_IF: | 157 | case SND_SOC_DAIFMT_IB_IF: |
| 154 | val_cr4 |= FSL_SAI_CR4_FSP; | 158 | /* Invert both clocks */ |
| 155 | val_cr2 &= ~FSL_SAI_CR2_BCP; | 159 | val_cr2 ^= FSL_SAI_CR2_BCP; |
| 160 | val_cr4 ^= FSL_SAI_CR4_FSP; | ||
| 156 | break; | 161 | break; |
| 157 | case SND_SOC_DAIFMT_IB_NF: | 162 | case SND_SOC_DAIFMT_IB_NF: |
| 158 | val_cr4 &= ~FSL_SAI_CR4_FSP; | 163 | /* Invert bit clock */ |
| 159 | val_cr2 &= ~FSL_SAI_CR2_BCP; | 164 | val_cr2 ^= FSL_SAI_CR2_BCP; |
| 160 | break; | 165 | break; |
| 161 | case SND_SOC_DAIFMT_NB_IF: | 166 | case SND_SOC_DAIFMT_NB_IF: |
| 162 | val_cr4 |= FSL_SAI_CR4_FSP; | 167 | /* Invert frame clock */ |
| 163 | val_cr2 |= FSL_SAI_CR2_BCP; | 168 | val_cr4 ^= FSL_SAI_CR4_FSP; |
| 164 | break; | 169 | break; |
| 165 | case SND_SOC_DAIFMT_NB_NF: | 170 | case SND_SOC_DAIFMT_NB_NF: |
| 166 | val_cr4 &= ~FSL_SAI_CR4_FSP; | 171 | /* Nothing to do for both normal cases */ |
| 167 | val_cr2 |= FSL_SAI_CR2_BCP; | ||
| 168 | break; | 172 | break; |
| 169 | default: | 173 | default: |
| 170 | return -EINVAL; | 174 | return -EINVAL; |
| 171 | } | 175 | } |
| 172 | 176 | ||
| 177 | /* DAI clock master masks */ | ||
| 173 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 178 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
| 174 | case SND_SOC_DAIFMT_CBS_CFS: | 179 | case SND_SOC_DAIFMT_CBS_CFS: |
| 175 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; | 180 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; |
| @@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
| 179 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; | 184 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; |
| 180 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; | 185 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; |
| 181 | break; | 186 | break; |
| 187 | case SND_SOC_DAIFMT_CBS_CFM: | ||
| 188 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; | ||
| 189 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; | ||
| 190 | break; | ||
| 191 | case SND_SOC_DAIFMT_CBM_CFS: | ||
| 192 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; | ||
| 193 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; | ||
| 194 | break; | ||
| 182 | default: | 195 | default: |
| 183 | return -EINVAL; | 196 | return -EINVAL; |
| 184 | } | 197 | } |
| 185 | 198 | ||
| 186 | sai_writel(sai, val_cr2, sai->base + reg_cr2); | 199 | regmap_write(sai->regmap, reg_cr2, val_cr2); |
| 187 | sai_writel(sai, val_cr4, sai->base + reg_cr4); | 200 | regmap_write(sai->regmap, reg_cr4, val_cr4); |
| 188 | 201 | ||
| 189 | return 0; | 202 | return 0; |
| 190 | } | 203 | } |
| 191 | 204 | ||
| 192 | static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | 205 | static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) |
| 193 | { | 206 | { |
| 194 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | ||
| 195 | int ret; | 207 | int ret; |
| 196 | 208 | ||
| 197 | ret = clk_prepare_enable(sai->clk); | ||
| 198 | if (ret) | ||
| 199 | return ret; | ||
| 200 | |||
| 201 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); | 209 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); |
| 202 | if (ret) { | 210 | if (ret) { |
| 203 | dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); | 211 | dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); |
| 204 | goto err_clk; | 212 | return ret; |
| 205 | } | 213 | } |
| 206 | 214 | ||
| 207 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); | 215 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); |
| 208 | if (ret) { | 216 | if (ret) |
| 209 | dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); | 217 | dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); |
| 210 | goto err_clk; | ||
| 211 | } | ||
| 212 | |||
| 213 | err_clk: | ||
| 214 | clk_disable_unprepare(sai->clk); | ||
| 215 | 218 | ||
| 216 | return ret; | 219 | return ret; |
| 217 | } | 220 | } |
| @@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
| 235 | reg_mr = FSL_SAI_RMR; | 238 | reg_mr = FSL_SAI_RMR; |
| 236 | } | 239 | } |
| 237 | 240 | ||
| 238 | val_cr4 = sai_readl(sai, sai->base + reg_cr4); | 241 | regmap_read(sai->regmap, reg_cr4, &val_cr4); |
| 242 | regmap_read(sai->regmap, reg_cr4, &val_cr5); | ||
| 243 | |||
| 239 | val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; | 244 | val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; |
| 240 | val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; | 245 | val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; |
| 241 | 246 | ||
| 242 | val_cr5 = sai_readl(sai, sai->base + reg_cr5); | ||
| 243 | val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; | 247 | val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; |
| 244 | val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; | 248 | val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; |
| 245 | val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; | 249 | val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; |
| 246 | 250 | ||
| 247 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); | 251 | if (!sai->is_dsp_mode) |
| 252 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); | ||
| 253 | |||
| 248 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); | 254 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); |
| 249 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); | 255 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); |
| 250 | 256 | ||
| @@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
| 257 | val_cr4 |= FSL_SAI_CR4_FRSZ(channels); | 263 | val_cr4 |= FSL_SAI_CR4_FRSZ(channels); |
| 258 | val_mr = ~0UL - ((1 << channels) - 1); | 264 | val_mr = ~0UL - ((1 << channels) - 1); |
| 259 | 265 | ||
| 260 | sai_writel(sai, val_cr4, sai->base + reg_cr4); | 266 | regmap_write(sai->regmap, reg_cr4, val_cr4); |
| 261 | sai_writel(sai, val_cr5, sai->base + reg_cr5); | 267 | regmap_write(sai->regmap, reg_cr5, val_cr5); |
| 262 | sai_writel(sai, val_mr, sai->base + reg_mr); | 268 | regmap_write(sai->regmap, reg_mr, val_mr); |
| 263 | 269 | ||
| 264 | return 0; | 270 | return 0; |
| 265 | } | 271 | } |
| @@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 268 | struct snd_soc_dai *cpu_dai) | 274 | struct snd_soc_dai *cpu_dai) |
| 269 | { | 275 | { |
| 270 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 276 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
| 271 | u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3; | 277 | u32 tcsr, rcsr; |
| 272 | |||
| 273 | val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2); | ||
| 274 | val_cr2 &= ~FSL_SAI_CR2_SYNC; | ||
| 275 | sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2); | ||
| 276 | 278 | ||
| 277 | val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2); | 279 | /* |
| 278 | val_cr2 |= FSL_SAI_CR2_SYNC; | 280 | * The transmitter bit clock and frame sync are to be |
| 279 | sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2); | 281 | * used by both the transmitter and receiver. |
| 282 | */ | ||
| 283 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, | ||
| 284 | ~FSL_SAI_CR2_SYNC); | ||
| 285 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, | ||
| 286 | FSL_SAI_CR2_SYNC); | ||
| 280 | 287 | ||
| 281 | tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR); | 288 | regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); |
| 282 | rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR); | 289 | regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); |
| 283 | 290 | ||
| 284 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 291 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 285 | tcsr |= FSL_SAI_CSR_FRDE; | 292 | tcsr |= FSL_SAI_CSR_FRDE; |
| 286 | rcsr &= ~FSL_SAI_CSR_FRDE; | 293 | rcsr &= ~FSL_SAI_CSR_FRDE; |
| 287 | reg_cr3 = FSL_SAI_TCR3; | ||
| 288 | } else { | 294 | } else { |
| 289 | rcsr |= FSL_SAI_CSR_FRDE; | 295 | rcsr |= FSL_SAI_CSR_FRDE; |
| 290 | tcsr &= ~FSL_SAI_CSR_FRDE; | 296 | tcsr &= ~FSL_SAI_CSR_FRDE; |
| 291 | reg_cr3 = FSL_SAI_RCR3; | ||
| 292 | } | 297 | } |
| 293 | 298 | ||
| 294 | val_cr3 = sai_readl(sai, sai->base + reg_cr3); | 299 | /* |
| 295 | 300 | * It is recommended that the transmitter is the last enabled | |
| 301 | * and the first disabled. | ||
| 302 | */ | ||
| 296 | switch (cmd) { | 303 | switch (cmd) { |
| 297 | case SNDRV_PCM_TRIGGER_START: | 304 | case SNDRV_PCM_TRIGGER_START: |
| 298 | case SNDRV_PCM_TRIGGER_RESUME: | 305 | case SNDRV_PCM_TRIGGER_RESUME: |
| 299 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 306 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 300 | tcsr |= FSL_SAI_CSR_TERE; | 307 | tcsr |= FSL_SAI_CSR_TERE; |
| 301 | rcsr |= FSL_SAI_CSR_TERE; | 308 | rcsr |= FSL_SAI_CSR_TERE; |
| 302 | val_cr3 |= FSL_SAI_CR3_TRCE; | ||
| 303 | 309 | ||
| 304 | sai_writel(sai, val_cr3, sai->base + reg_cr3); | 310 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); |
| 305 | sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); | 311 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); |
| 306 | sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); | ||
| 307 | break; | 312 | break; |
| 308 | |||
| 309 | case SNDRV_PCM_TRIGGER_STOP: | 313 | case SNDRV_PCM_TRIGGER_STOP: |
| 310 | case SNDRV_PCM_TRIGGER_SUSPEND: | 314 | case SNDRV_PCM_TRIGGER_SUSPEND: |
| 311 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 315 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| @@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 314 | rcsr &= ~FSL_SAI_CSR_TERE; | 318 | rcsr &= ~FSL_SAI_CSR_TERE; |
| 315 | } | 319 | } |
| 316 | 320 | ||
| 317 | val_cr3 &= ~FSL_SAI_CR3_TRCE; | 321 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); |
| 318 | 322 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); | |
| 319 | sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); | ||
| 320 | sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); | ||
| 321 | sai_writel(sai, val_cr3, sai->base + reg_cr3); | ||
| 322 | break; | 323 | break; |
| 323 | default: | 324 | default: |
| 324 | return -EINVAL; | 325 | return -EINVAL; |
| @@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, | |||
| 331 | struct snd_soc_dai *cpu_dai) | 332 | struct snd_soc_dai *cpu_dai) |
| 332 | { | 333 | { |
| 333 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 334 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
| 335 | u32 reg; | ||
| 336 | |||
| 337 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 338 | reg = FSL_SAI_TCR3; | ||
| 339 | else | ||
| 340 | reg = FSL_SAI_RCR3; | ||
| 341 | |||
| 342 | regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, | ||
| 343 | FSL_SAI_CR3_TRCE); | ||
| 334 | 344 | ||
| 335 | return clk_prepare_enable(sai->clk); | 345 | return 0; |
| 336 | } | 346 | } |
| 337 | 347 | ||
| 338 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, | 348 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, |
| 339 | struct snd_soc_dai *cpu_dai) | 349 | struct snd_soc_dai *cpu_dai) |
| 340 | { | 350 | { |
| 341 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 351 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
| 352 | u32 reg; | ||
| 353 | |||
| 354 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 355 | reg = FSL_SAI_TCR3; | ||
| 356 | else | ||
| 357 | reg = FSL_SAI_RCR3; | ||
| 342 | 358 | ||
| 343 | clk_disable_unprepare(sai->clk); | 359 | regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, |
| 360 | ~FSL_SAI_CR3_TRCE); | ||
| 344 | } | 361 | } |
| 345 | 362 | ||
| 346 | static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { | 363 | static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { |
| @@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { | |||
| 355 | static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) | 372 | static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) |
| 356 | { | 373 | { |
| 357 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); | 374 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); |
| 358 | int ret; | ||
| 359 | 375 | ||
| 360 | ret = clk_prepare_enable(sai->clk); | 376 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); |
| 361 | if (ret) | 377 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); |
| 362 | return ret; | 378 | regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, |
| 363 | 379 | FSL_SAI_MAXBURST_TX * 2); | |
| 364 | sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR); | 380 | regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, |
| 365 | sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR); | 381 | FSL_SAI_MAXBURST_RX - 1); |
| 366 | sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1); | ||
| 367 | sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1); | ||
| 368 | |||
| 369 | clk_disable_unprepare(sai->clk); | ||
| 370 | 382 | ||
| 371 | snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, | 383 | snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, |
| 372 | &sai->dma_params_rx); | 384 | &sai->dma_params_rx); |
| @@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = { | |||
| 397 | .name = "fsl-sai", | 409 | .name = "fsl-sai", |
| 398 | }; | 410 | }; |
| 399 | 411 | ||
| 412 | static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) | ||
| 413 | { | ||
| 414 | switch (reg) { | ||
| 415 | case FSL_SAI_TCSR: | ||
| 416 | case FSL_SAI_TCR1: | ||
| 417 | case FSL_SAI_TCR2: | ||
| 418 | case FSL_SAI_TCR3: | ||
| 419 | case FSL_SAI_TCR4: | ||
| 420 | case FSL_SAI_TCR5: | ||
| 421 | case FSL_SAI_TFR: | ||
| 422 | case FSL_SAI_TMR: | ||
| 423 | case FSL_SAI_RCSR: | ||
| 424 | case FSL_SAI_RCR1: | ||
| 425 | case FSL_SAI_RCR2: | ||
| 426 | case FSL_SAI_RCR3: | ||
| 427 | case FSL_SAI_RCR4: | ||
| 428 | case FSL_SAI_RCR5: | ||
| 429 | case FSL_SAI_RDR: | ||
| 430 | case FSL_SAI_RFR: | ||
| 431 | case FSL_SAI_RMR: | ||
| 432 | return true; | ||
| 433 | default: | ||
| 434 | return false; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) | ||
| 439 | { | ||
| 440 | switch (reg) { | ||
| 441 | case FSL_SAI_TFR: | ||
| 442 | case FSL_SAI_RFR: | ||
| 443 | case FSL_SAI_TDR: | ||
| 444 | case FSL_SAI_RDR: | ||
| 445 | return true; | ||
| 446 | default: | ||
| 447 | return false; | ||
| 448 | } | ||
| 449 | |||
| 450 | } | ||
| 451 | |||
| 452 | static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) | ||
| 453 | { | ||
| 454 | switch (reg) { | ||
| 455 | case FSL_SAI_TCSR: | ||
| 456 | case FSL_SAI_TCR1: | ||
| 457 | case FSL_SAI_TCR2: | ||
| 458 | case FSL_SAI_TCR3: | ||
| 459 | case FSL_SAI_TCR4: | ||
| 460 | case FSL_SAI_TCR5: | ||
| 461 | case FSL_SAI_TDR: | ||
| 462 | case FSL_SAI_TMR: | ||
| 463 | case FSL_SAI_RCSR: | ||
| 464 | case FSL_SAI_RCR1: | ||
| 465 | case FSL_SAI_RCR2: | ||
| 466 | case FSL_SAI_RCR3: | ||
| 467 | case FSL_SAI_RCR4: | ||
| 468 | case FSL_SAI_RCR5: | ||
| 469 | case FSL_SAI_RMR: | ||
| 470 | return true; | ||
| 471 | default: | ||
| 472 | return false; | ||
| 473 | } | ||
| 474 | } | ||
| 475 | |||
| 476 | static struct regmap_config fsl_sai_regmap_config = { | ||
| 477 | .reg_bits = 32, | ||
| 478 | .reg_stride = 4, | ||
| 479 | .val_bits = 32, | ||
| 480 | |||
| 481 | .max_register = FSL_SAI_RMR, | ||
| 482 | .readable_reg = fsl_sai_readable_reg, | ||
| 483 | .volatile_reg = fsl_sai_volatile_reg, | ||
| 484 | .writeable_reg = fsl_sai_writeable_reg, | ||
| 485 | }; | ||
| 486 | |||
| 400 | static int fsl_sai_probe(struct platform_device *pdev) | 487 | static int fsl_sai_probe(struct platform_device *pdev) |
| 401 | { | 488 | { |
| 402 | struct device_node *np = pdev->dev.of_node; | 489 | struct device_node *np = pdev->dev.of_node; |
| 403 | struct fsl_sai *sai; | 490 | struct fsl_sai *sai; |
| 404 | struct resource *res; | 491 | struct resource *res; |
| 492 | void __iomem *base; | ||
| 405 | int ret; | 493 | int ret; |
| 406 | 494 | ||
| 407 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); | 495 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); |
| 408 | if (!sai) | 496 | if (!sai) |
| 409 | return -ENOMEM; | 497 | return -ENOMEM; |
| 410 | 498 | ||
| 499 | sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); | ||
| 500 | if (sai->big_endian_regs) | ||
| 501 | fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
| 502 | |||
| 503 | sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); | ||
| 504 | |||
| 411 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 505 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 412 | sai->base = devm_ioremap_resource(&pdev->dev, res); | 506 | base = devm_ioremap_resource(&pdev->dev, res); |
| 413 | if (IS_ERR(sai->base)) | 507 | if (IS_ERR(base)) |
| 414 | return PTR_ERR(sai->base); | 508 | return PTR_ERR(base); |
| 415 | 509 | ||
| 416 | sai->clk = devm_clk_get(&pdev->dev, "sai"); | 510 | sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, |
| 417 | if (IS_ERR(sai->clk)) { | 511 | "sai", base, &fsl_sai_regmap_config); |
| 418 | dev_err(&pdev->dev, "Cannot get SAI's clock\n"); | 512 | if (IS_ERR(sai->regmap)) { |
| 419 | return PTR_ERR(sai->clk); | 513 | dev_err(&pdev->dev, "regmap init failed\n"); |
| 514 | return PTR_ERR(sai->regmap); | ||
| 420 | } | 515 | } |
| 421 | 516 | ||
| 422 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; | 517 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; |
| @@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
| 424 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; | 519 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; |
| 425 | sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; | 520 | sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; |
| 426 | 521 | ||
| 427 | sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); | ||
| 428 | sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); | ||
| 429 | |||
| 430 | platform_set_drvdata(pdev, sai); | 522 | platform_set_drvdata(pdev, sai); |
| 431 | 523 | ||
| 432 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, | 524 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, |
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 41bb62e69361..e432260be598 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h | |||
| @@ -15,31 +15,36 @@ | |||
| 15 | SNDRV_PCM_FMTBIT_S20_3LE |\ | 15 | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 16 | SNDRV_PCM_FMTBIT_S24_LE) | 16 | SNDRV_PCM_FMTBIT_S24_LE) |
| 17 | 17 | ||
| 18 | /* SAI Register Map Register */ | ||
| 19 | #define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ | ||
| 20 | #define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */ | ||
| 21 | #define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */ | ||
| 22 | #define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ | ||
| 23 | #define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ | ||
| 24 | #define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ | ||
| 25 | #define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ | ||
| 26 | #define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ | ||
| 27 | #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ | ||
| 28 | #define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ | ||
| 29 | #define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ | ||
| 30 | #define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */ | ||
| 31 | #define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ | ||
| 32 | #define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ | ||
| 33 | #define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ | ||
| 34 | #define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ | ||
| 35 | #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ | ||
| 36 | #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ | ||
| 37 | |||
| 18 | /* SAI Transmit/Recieve Control Register */ | 38 | /* SAI Transmit/Recieve Control Register */ |
| 19 | #define FSL_SAI_TCSR 0x00 | ||
| 20 | #define FSL_SAI_RCSR 0x80 | ||
| 21 | #define FSL_SAI_CSR_TERE BIT(31) | 39 | #define FSL_SAI_CSR_TERE BIT(31) |
| 22 | #define FSL_SAI_CSR_FWF BIT(17) | 40 | #define FSL_SAI_CSR_FWF BIT(17) |
| 23 | #define FSL_SAI_CSR_FRIE BIT(8) | 41 | #define FSL_SAI_CSR_FRIE BIT(8) |
| 24 | #define FSL_SAI_CSR_FRDE BIT(0) | 42 | #define FSL_SAI_CSR_FRDE BIT(0) |
| 25 | 43 | ||
| 26 | /* SAI Transmit Data/FIFO/MASK Register */ | ||
| 27 | #define FSL_SAI_TDR 0x20 | ||
| 28 | #define FSL_SAI_TFR 0x40 | ||
| 29 | #define FSL_SAI_TMR 0x60 | ||
| 30 | |||
| 31 | /* SAI Recieve Data/FIFO/MASK Register */ | ||
| 32 | #define FSL_SAI_RDR 0xa0 | ||
| 33 | #define FSL_SAI_RFR 0xc0 | ||
| 34 | #define FSL_SAI_RMR 0xe0 | ||
| 35 | |||
| 36 | /* SAI Transmit and Recieve Configuration 1 Register */ | 44 | /* SAI Transmit and Recieve Configuration 1 Register */ |
| 37 | #define FSL_SAI_TCR1 0x04 | 45 | #define FSL_SAI_CR1_RFW_MASK 0x1f |
| 38 | #define FSL_SAI_RCR1 0x84 | ||
| 39 | 46 | ||
| 40 | /* SAI Transmit and Recieve Configuration 2 Register */ | 47 | /* SAI Transmit and Recieve Configuration 2 Register */ |
| 41 | #define FSL_SAI_TCR2 0x08 | ||
| 42 | #define FSL_SAI_RCR2 0x88 | ||
| 43 | #define FSL_SAI_CR2_SYNC BIT(30) | 48 | #define FSL_SAI_CR2_SYNC BIT(30) |
| 44 | #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) | 49 | #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) |
| 45 | #define FSL_SAI_CR2_MSEL_BUS 0 | 50 | #define FSL_SAI_CR2_MSEL_BUS 0 |
| @@ -50,15 +55,11 @@ | |||
| 50 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) | 55 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) |
| 51 | 56 | ||
| 52 | /* SAI Transmit and Recieve Configuration 3 Register */ | 57 | /* SAI Transmit and Recieve Configuration 3 Register */ |
| 53 | #define FSL_SAI_TCR3 0x0c | ||
| 54 | #define FSL_SAI_RCR3 0x8c | ||
| 55 | #define FSL_SAI_CR3_TRCE BIT(16) | 58 | #define FSL_SAI_CR3_TRCE BIT(16) |
| 56 | #define FSL_SAI_CR3_WDFL(x) (x) | 59 | #define FSL_SAI_CR3_WDFL(x) (x) |
| 57 | #define FSL_SAI_CR3_WDFL_MASK 0x1f | 60 | #define FSL_SAI_CR3_WDFL_MASK 0x1f |
| 58 | 61 | ||
| 59 | /* SAI Transmit and Recieve Configuration 4 Register */ | 62 | /* SAI Transmit and Recieve Configuration 4 Register */ |
| 60 | #define FSL_SAI_TCR4 0x10 | ||
| 61 | #define FSL_SAI_RCR4 0x90 | ||
| 62 | #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) | 63 | #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) |
| 63 | #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) | 64 | #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) |
| 64 | #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) | 65 | #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) |
| @@ -69,8 +70,6 @@ | |||
| 69 | #define FSL_SAI_CR4_FSD_MSTR BIT(0) | 70 | #define FSL_SAI_CR4_FSD_MSTR BIT(0) |
| 70 | 71 | ||
| 71 | /* SAI Transmit and Recieve Configuration 5 Register */ | 72 | /* SAI Transmit and Recieve Configuration 5 Register */ |
| 72 | #define FSL_SAI_TCR5 0x14 | ||
| 73 | #define FSL_SAI_RCR5 0x94 | ||
| 74 | #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) | 73 | #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) |
| 75 | #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) | 74 | #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) |
| 76 | #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) | 75 | #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) |
| @@ -100,12 +99,11 @@ | |||
| 100 | #define FSL_SAI_MAXBURST_RX 6 | 99 | #define FSL_SAI_MAXBURST_RX 6 |
| 101 | 100 | ||
| 102 | struct fsl_sai { | 101 | struct fsl_sai { |
| 103 | struct clk *clk; | 102 | struct regmap *regmap; |
| 104 | |||
| 105 | void __iomem *base; | ||
| 106 | 103 | ||
| 107 | bool big_endian_regs; | 104 | bool big_endian_regs; |
| 108 | bool big_endian_data; | 105 | bool big_endian_data; |
| 106 | bool is_dsp_mode; | ||
| 109 | 107 | ||
| 110 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 108 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
| 111 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 109 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 4d075f1abe78..6452ca83d889 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
| @@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | |||
| 911 | { | 911 | { |
| 912 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | 912 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); |
| 913 | 913 | ||
| 914 | dai->playback_dma_data = &spdif_private->dma_params_tx; | 914 | snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx, |
| 915 | dai->capture_dma_data = &spdif_private->dma_params_rx; | 915 | &spdif_private->dma_params_rx); |
| 916 | 916 | ||
| 917 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | 917 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); |
| 918 | 918 | ||
| @@ -985,7 +985,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | |||
| 985 | } | 985 | } |
| 986 | } | 986 | } |
| 987 | 987 | ||
| 988 | static const struct regmap_config fsl_spdif_regmap_config = { | 988 | static struct regmap_config fsl_spdif_regmap_config = { |
| 989 | .reg_bits = 32, | 989 | .reg_bits = 32, |
| 990 | .reg_stride = 4, | 990 | .reg_stride = 4, |
| 991 | .val_bits = 32, | 991 | .val_bits = 32, |
| @@ -1105,6 +1105,9 @@ static int fsl_spdif_probe(struct platform_device *pdev) | |||
| 1105 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | 1105 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); |
| 1106 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | 1106 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; |
| 1107 | 1107 | ||
| 1108 | if (of_property_read_bool(np, "big-endian")) | ||
| 1109 | fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
| 1110 | |||
| 1108 | /* Get the addresses and IRQ */ | 1111 | /* Get the addresses and IRQ */ |
| 1109 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1112 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| 1110 | regs = devm_ioremap_resource(&pdev->dev, res); | 1113 | regs = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 6553202dd48c..7abf6a079574 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c | |||
| @@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
| 270 | ret = imx_pcm_preallocate_dma_buffer(pcm, | 270 | ret = imx_pcm_preallocate_dma_buffer(pcm, |
| 271 | SNDRV_PCM_STREAM_PLAYBACK); | 271 | SNDRV_PCM_STREAM_PLAYBACK); |
| 272 | if (ret) | 272 | if (ret) |
| 273 | goto out; | 273 | return ret; |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | 276 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
| 277 | ret = imx_pcm_preallocate_dma_buffer(pcm, | 277 | ret = imx_pcm_preallocate_dma_buffer(pcm, |
| 278 | SNDRV_PCM_STREAM_CAPTURE); | 278 | SNDRV_PCM_STREAM_CAPTURE); |
| 279 | if (ret) | 279 | if (ret) |
| 280 | goto out; | 280 | return ret; |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | out: | 283 | return 0; |
| 284 | return ret; | ||
| 285 | } | 284 | } |
| 286 | 285 | ||
| 287 | static int ssi_irq = 0; | 286 | static int ssi_irq = 0; |
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index fce63252bdbb..804749a6c61e 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c | |||
| @@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) | |||
| 214 | struct snd_soc_codec *codec = rtd->codec; | 214 | struct snd_soc_codec *codec = rtd->codec; |
| 215 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 215 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 216 | 216 | ||
| 217 | snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets, | ||
| 218 | ARRAY_SIZE(wm1133_ev1_widgets)); | ||
| 219 | |||
| 220 | snd_soc_dapm_add_routes(dapm, wm1133_ev1_map, | ||
| 221 | ARRAY_SIZE(wm1133_ev1_map)); | ||
| 222 | |||
| 223 | /* Headphone jack detection */ | 217 | /* Headphone jack detection */ |
| 224 | snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); | 218 | snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); |
| 225 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), | 219 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), |
| @@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = { | |||
| 257 | .owner = THIS_MODULE, | 251 | .owner = THIS_MODULE, |
| 258 | .dai_link = &wm1133_ev1_dai, | 252 | .dai_link = &wm1133_ev1_dai, |
| 259 | .num_links = 1, | 253 | .num_links = 1, |
| 254 | |||
| 255 | .dapm_widgets = wm1133_ev1_widgets, | ||
| 256 | .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets), | ||
| 257 | .dapm_routes = wm1133_ev1_map, | ||
| 258 | .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map), | ||
| 260 | }; | 259 | }; |
| 261 | 260 | ||
| 262 | static struct platform_device *wm1133_ev1_snd_device; | 261 | static struct platform_device *wm1133_ev1_snd_device; |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2a1b1b5b5221..5dd47691ba41 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
| @@ -9,48 +9,73 @@ | |||
| 9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
| 10 | */ | 10 | */ |
| 11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
| 12 | #include <linux/device.h> | ||
| 12 | #include <linux/module.h> | 13 | #include <linux/module.h> |
| 13 | #include <linux/of.h> | 14 | #include <linux/of.h> |
| 14 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
| 15 | #include <linux/string.h> | 16 | #include <linux/string.h> |
| 16 | #include <sound/simple_card.h> | 17 | #include <sound/simple_card.h> |
| 18 | #include <sound/soc-dai.h> | ||
| 19 | #include <sound/soc.h> | ||
| 20 | |||
| 21 | struct simple_card_data { | ||
| 22 | struct snd_soc_card snd_card; | ||
| 23 | unsigned int daifmt; | ||
| 24 | struct asoc_simple_dai cpu_dai; | ||
| 25 | struct asoc_simple_dai codec_dai; | ||
| 26 | struct snd_soc_dai_link snd_link; | ||
| 27 | }; | ||
| 17 | 28 | ||
| 18 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, | 29 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, |
| 19 | struct asoc_simple_dai *set, | 30 | struct asoc_simple_dai *set) |
| 20 | unsigned int daifmt) | ||
| 21 | { | 31 | { |
| 22 | int ret = 0; | 32 | int ret; |
| 23 | 33 | ||
| 24 | daifmt |= set->fmt; | 34 | if (set->fmt) { |
| 35 | ret = snd_soc_dai_set_fmt(dai, set->fmt); | ||
| 36 | if (ret && ret != -ENOTSUPP) { | ||
| 37 | dev_err(dai->dev, "simple-card: set_fmt error\n"); | ||
| 38 | goto err; | ||
| 39 | } | ||
| 40 | } | ||
| 25 | 41 | ||
| 26 | if (daifmt) | 42 | if (set->sysclk) { |
| 27 | ret = snd_soc_dai_set_fmt(dai, daifmt); | 43 | ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); |
| 44 | if (ret && ret != -ENOTSUPP) { | ||
| 45 | dev_err(dai->dev, "simple-card: set_sysclk error\n"); | ||
| 46 | goto err; | ||
| 47 | } | ||
| 48 | } | ||
| 28 | 49 | ||
| 29 | if (ret == -ENOTSUPP) { | 50 | if (set->slots) { |
| 30 | dev_dbg(dai->dev, "ASoC: set_fmt is not supported\n"); | 51 | ret = snd_soc_dai_set_tdm_slot(dai, 0, 0, |
| 31 | ret = 0; | 52 | set->slots, |
| 53 | set->slot_width); | ||
| 54 | if (ret && ret != -ENOTSUPP) { | ||
| 55 | dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); | ||
| 56 | goto err; | ||
| 57 | } | ||
| 32 | } | 58 | } |
| 33 | 59 | ||
| 34 | if (!ret && set->sysclk) | 60 | ret = 0; |
| 35 | ret = snd_soc_dai_set_sysclk(dai, 0, set->sysclk, 0); | ||
| 36 | 61 | ||
| 62 | err: | ||
| 37 | return ret; | 63 | return ret; |
| 38 | } | 64 | } |
| 39 | 65 | ||
| 40 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | 66 | static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) |
| 41 | { | 67 | { |
| 42 | struct asoc_simple_card_info *info = | 68 | struct simple_card_data *priv = |
| 43 | snd_soc_card_get_drvdata(rtd->card); | 69 | snd_soc_card_get_drvdata(rtd->card); |
| 44 | struct snd_soc_dai *codec = rtd->codec_dai; | 70 | struct snd_soc_dai *codec = rtd->codec_dai; |
| 45 | struct snd_soc_dai *cpu = rtd->cpu_dai; | 71 | struct snd_soc_dai *cpu = rtd->cpu_dai; |
| 46 | unsigned int daifmt = info->daifmt; | ||
| 47 | int ret; | 72 | int ret; |
| 48 | 73 | ||
| 49 | ret = __asoc_simple_card_dai_init(codec, &info->codec_dai, daifmt); | 74 | ret = __asoc_simple_card_dai_init(codec, &priv->codec_dai); |
| 50 | if (ret < 0) | 75 | if (ret < 0) |
| 51 | return ret; | 76 | return ret; |
| 52 | 77 | ||
| 53 | ret = __asoc_simple_card_dai_init(cpu, &info->cpu_dai, daifmt); | 78 | ret = __asoc_simple_card_dai_init(cpu, &priv->cpu_dai); |
| 54 | if (ret < 0) | 79 | if (ret < 0) |
| 55 | return ret; | 80 | return ret; |
| 56 | 81 | ||
| @@ -59,9 +84,12 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
| 59 | 84 | ||
| 60 | static int | 85 | static int |
| 61 | asoc_simple_card_sub_parse_of(struct device_node *np, | 86 | asoc_simple_card_sub_parse_of(struct device_node *np, |
| 87 | unsigned int daifmt, | ||
| 62 | struct asoc_simple_dai *dai, | 88 | struct asoc_simple_dai *dai, |
| 63 | struct device_node **node) | 89 | const struct device_node **p_node, |
| 90 | const char **name) | ||
| 64 | { | 91 | { |
| 92 | struct device_node *node; | ||
| 65 | struct clk *clk; | 93 | struct clk *clk; |
| 66 | int ret; | 94 | int ret; |
| 67 | 95 | ||
| @@ -69,21 +97,28 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
| 69 | * get node via "sound-dai = <&phandle port>" | 97 | * get node via "sound-dai = <&phandle port>" |
| 70 | * it will be used as xxx_of_node on soc_bind_dai_link() | 98 | * it will be used as xxx_of_node on soc_bind_dai_link() |
| 71 | */ | 99 | */ |
| 72 | *node = of_parse_phandle(np, "sound-dai", 0); | 100 | node = of_parse_phandle(np, "sound-dai", 0); |
| 73 | if (!*node) | 101 | if (!node) |
| 74 | return -ENODEV; | 102 | return -ENODEV; |
| 103 | *p_node = node; | ||
| 75 | 104 | ||
| 76 | /* get dai->name */ | 105 | /* get dai->name */ |
| 77 | ret = snd_soc_of_get_dai_name(np, &dai->name); | 106 | ret = snd_soc_of_get_dai_name(np, name); |
| 78 | if (ret < 0) | 107 | if (ret < 0) |
| 79 | goto parse_error; | 108 | goto parse_error; |
| 80 | 109 | ||
| 110 | /* parse TDM slot */ | ||
| 111 | ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); | ||
| 112 | if (ret) | ||
| 113 | goto parse_error; | ||
| 114 | |||
| 81 | /* | 115 | /* |
| 82 | * bitclock-inversion, frame-inversion | 116 | * bitclock-inversion, frame-inversion |
| 83 | * bitclock-master, frame-master | 117 | * bitclock-master, frame-master |
| 84 | * and specific "format" if it has | 118 | * and specific "format" if it has |
| 85 | */ | 119 | */ |
| 86 | dai->fmt = snd_soc_of_parse_daifmt(np, NULL); | 120 | dai->fmt = snd_soc_of_parse_daifmt(np, NULL); |
| 121 | dai->fmt |= daifmt; | ||
| 87 | 122 | ||
| 88 | /* | 123 | /* |
| 89 | * dai->sysclk come from | 124 | * dai->sysclk come from |
| @@ -104,7 +139,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
| 104 | "system-clock-frequency", | 139 | "system-clock-frequency", |
| 105 | &dai->sysclk); | 140 | &dai->sysclk); |
| 106 | } else { | 141 | } else { |
| 107 | clk = of_clk_get(*node, 0); | 142 | clk = of_clk_get(node, 0); |
| 108 | if (!IS_ERR(clk)) | 143 | if (!IS_ERR(clk)) |
| 109 | dai->sysclk = clk_get_rate(clk); | 144 | dai->sysclk = clk_get_rate(clk); |
| 110 | } | 145 | } |
| @@ -112,29 +147,38 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
| 112 | ret = 0; | 147 | ret = 0; |
| 113 | 148 | ||
| 114 | parse_error: | 149 | parse_error: |
| 115 | of_node_put(*node); | 150 | of_node_put(node); |
| 116 | 151 | ||
| 117 | return ret; | 152 | return ret; |
| 118 | } | 153 | } |
| 119 | 154 | ||
| 120 | static int asoc_simple_card_parse_of(struct device_node *node, | 155 | static int asoc_simple_card_parse_of(struct device_node *node, |
| 121 | struct asoc_simple_card_info *info, | 156 | struct simple_card_data *priv, |
| 122 | struct device *dev, | 157 | struct device *dev) |
| 123 | struct device_node **of_cpu, | ||
| 124 | struct device_node **of_codec, | ||
| 125 | struct device_node **of_platform) | ||
| 126 | { | 158 | { |
| 159 | struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; | ||
| 127 | struct device_node *np; | 160 | struct device_node *np; |
| 128 | char *name; | 161 | char *name; |
| 129 | int ret; | 162 | int ret; |
| 130 | 163 | ||
| 164 | /* parsing the card name from DT */ | ||
| 165 | snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); | ||
| 166 | |||
| 131 | /* get CPU/CODEC common format via simple-audio-card,format */ | 167 | /* get CPU/CODEC common format via simple-audio-card,format */ |
| 132 | info->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & | 168 | priv->daifmt = snd_soc_of_parse_daifmt(node, "simple-audio-card,") & |
| 133 | (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); | 169 | (SND_SOC_DAIFMT_FORMAT_MASK | SND_SOC_DAIFMT_INV_MASK); |
| 134 | 170 | ||
| 171 | /* off-codec widgets */ | ||
| 172 | if (of_property_read_bool(node, "simple-audio-card,widgets")) { | ||
| 173 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, | ||
| 174 | "simple-audio-card,widgets"); | ||
| 175 | if (ret) | ||
| 176 | return ret; | ||
| 177 | } | ||
| 178 | |||
| 135 | /* DAPM routes */ | 179 | /* DAPM routes */ |
| 136 | if (of_property_read_bool(node, "simple-audio-card,routing")) { | 180 | if (of_property_read_bool(node, "simple-audio-card,routing")) { |
| 137 | ret = snd_soc_of_parse_audio_routing(&info->snd_card, | 181 | ret = snd_soc_of_parse_audio_routing(&priv->snd_card, |
| 138 | "simple-audio-card,routing"); | 182 | "simple-audio-card,routing"); |
| 139 | if (ret) | 183 | if (ret) |
| 140 | return ret; | 184 | return ret; |
| @@ -144,9 +188,10 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
| 144 | ret = -EINVAL; | 188 | ret = -EINVAL; |
| 145 | np = of_get_child_by_name(node, "simple-audio-card,cpu"); | 189 | np = of_get_child_by_name(node, "simple-audio-card,cpu"); |
| 146 | if (np) | 190 | if (np) |
| 147 | ret = asoc_simple_card_sub_parse_of(np, | 191 | ret = asoc_simple_card_sub_parse_of(np, priv->daifmt, |
| 148 | &info->cpu_dai, | 192 | &priv->cpu_dai, |
| 149 | of_cpu); | 193 | &dai_link->cpu_of_node, |
| 194 | &dai_link->cpu_dai_name); | ||
| 150 | if (ret < 0) | 195 | if (ret < 0) |
| 151 | return ret; | 196 | return ret; |
| 152 | 197 | ||
| @@ -154,114 +199,126 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
| 154 | ret = -EINVAL; | 199 | ret = -EINVAL; |
| 155 | np = of_get_child_by_name(node, "simple-audio-card,codec"); | 200 | np = of_get_child_by_name(node, "simple-audio-card,codec"); |
| 156 | if (np) | 201 | if (np) |
| 157 | ret = asoc_simple_card_sub_parse_of(np, | 202 | ret = asoc_simple_card_sub_parse_of(np, priv->daifmt, |
| 158 | &info->codec_dai, | 203 | &priv->codec_dai, |
| 159 | of_codec); | 204 | &dai_link->codec_of_node, |
| 205 | &dai_link->codec_dai_name); | ||
| 160 | if (ret < 0) | 206 | if (ret < 0) |
| 161 | return ret; | 207 | return ret; |
| 162 | 208 | ||
| 163 | if (!info->cpu_dai.name || !info->codec_dai.name) | 209 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) |
| 164 | return -EINVAL; | 210 | return -EINVAL; |
| 165 | 211 | ||
| 166 | /* card name is created from CPU/CODEC dai name */ | 212 | /* card name is created from CPU/CODEC dai name */ |
| 167 | name = devm_kzalloc(dev, | 213 | name = devm_kzalloc(dev, |
| 168 | strlen(info->cpu_dai.name) + | 214 | strlen(dai_link->cpu_dai_name) + |
| 169 | strlen(info->codec_dai.name) + 2, | 215 | strlen(dai_link->codec_dai_name) + 2, |
| 170 | GFP_KERNEL); | 216 | GFP_KERNEL); |
| 171 | sprintf(name, "%s-%s", info->cpu_dai.name, info->codec_dai.name); | 217 | sprintf(name, "%s-%s", dai_link->cpu_dai_name, |
| 172 | info->name = info->card = name; | 218 | dai_link->codec_dai_name); |
| 219 | if (!priv->snd_card.name) | ||
| 220 | priv->snd_card.name = name; | ||
| 221 | dai_link->name = dai_link->stream_name = name; | ||
| 173 | 222 | ||
| 174 | /* simple-card assumes platform == cpu */ | 223 | /* simple-card assumes platform == cpu */ |
| 175 | *of_platform = *of_cpu; | 224 | dai_link->platform_of_node = dai_link->cpu_of_node; |
| 176 | 225 | ||
| 177 | dev_dbg(dev, "card-name : %s\n", info->card); | 226 | dev_dbg(dev, "card-name : %s\n", name); |
| 178 | dev_dbg(dev, "platform : %04x\n", info->daifmt); | 227 | dev_dbg(dev, "platform : %04x\n", priv->daifmt); |
| 179 | dev_dbg(dev, "cpu : %s / %04x / %d\n", | 228 | dev_dbg(dev, "cpu : %s / %04x / %d\n", |
| 180 | info->cpu_dai.name, | 229 | dai_link->cpu_dai_name, |
| 181 | info->cpu_dai.fmt, | 230 | priv->cpu_dai.fmt, |
| 182 | info->cpu_dai.sysclk); | 231 | priv->cpu_dai.sysclk); |
| 183 | dev_dbg(dev, "codec : %s / %04x / %d\n", | 232 | dev_dbg(dev, "codec : %s / %04x / %d\n", |
| 184 | info->codec_dai.name, | 233 | dai_link->codec_dai_name, |
| 185 | info->codec_dai.fmt, | 234 | priv->codec_dai.fmt, |
| 186 | info->codec_dai.sysclk); | 235 | priv->codec_dai.sysclk); |
| 236 | |||
| 237 | /* | ||
| 238 | * soc_bind_dai_link() will check cpu name | ||
| 239 | * after of_node matching if dai_link has cpu_dai_name. | ||
| 240 | * but, it will never match if name was created by fmt_single_name() | ||
| 241 | * remove cpu_dai_name to escape name matching. | ||
| 242 | * see | ||
| 243 | * fmt_single_name() | ||
| 244 | * fmt_multiple_name() | ||
| 245 | */ | ||
| 246 | dai_link->cpu_dai_name = NULL; | ||
| 187 | 247 | ||
| 188 | return 0; | 248 | return 0; |
| 189 | } | 249 | } |
| 190 | 250 | ||
| 191 | static int asoc_simple_card_probe(struct platform_device *pdev) | 251 | static int asoc_simple_card_probe(struct platform_device *pdev) |
| 192 | { | 252 | { |
| 193 | struct asoc_simple_card_info *cinfo; | 253 | struct simple_card_data *priv; |
| 254 | struct snd_soc_dai_link *dai_link; | ||
| 194 | struct device_node *np = pdev->dev.of_node; | 255 | struct device_node *np = pdev->dev.of_node; |
| 195 | struct device_node *of_cpu, *of_codec, *of_platform; | ||
| 196 | struct device *dev = &pdev->dev; | 256 | struct device *dev = &pdev->dev; |
| 197 | int ret; | 257 | int ret; |
| 198 | 258 | ||
| 199 | cinfo = NULL; | 259 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
| 200 | of_cpu = NULL; | 260 | if (!priv) |
| 201 | of_codec = NULL; | ||
| 202 | of_platform = NULL; | ||
| 203 | |||
| 204 | cinfo = devm_kzalloc(dev, sizeof(*cinfo), GFP_KERNEL); | ||
| 205 | if (!cinfo) | ||
| 206 | return -ENOMEM; | 261 | return -ENOMEM; |
| 207 | 262 | ||
| 263 | /* | ||
| 264 | * init snd_soc_card | ||
| 265 | */ | ||
| 266 | priv->snd_card.owner = THIS_MODULE; | ||
| 267 | priv->snd_card.dev = dev; | ||
| 268 | dai_link = &priv->snd_link; | ||
| 269 | priv->snd_card.dai_link = dai_link; | ||
| 270 | priv->snd_card.num_links = 1; | ||
| 271 | |||
| 208 | if (np && of_device_is_available(np)) { | 272 | if (np && of_device_is_available(np)) { |
| 209 | cinfo->snd_card.dev = dev; | ||
| 210 | 273 | ||
| 211 | ret = asoc_simple_card_parse_of(np, cinfo, dev, | 274 | ret = asoc_simple_card_parse_of(np, priv, dev); |
| 212 | &of_cpu, | ||
| 213 | &of_codec, | ||
| 214 | &of_platform); | ||
| 215 | if (ret < 0) { | 275 | if (ret < 0) { |
| 216 | if (ret != -EPROBE_DEFER) | 276 | if (ret != -EPROBE_DEFER) |
| 217 | dev_err(dev, "parse error %d\n", ret); | 277 | dev_err(dev, "parse error %d\n", ret); |
| 218 | return ret; | 278 | return ret; |
| 219 | } | 279 | } |
| 220 | } else { | 280 | } else { |
| 221 | if (!dev->platform_data) { | 281 | struct asoc_simple_card_info *cinfo; |
| 282 | |||
| 283 | cinfo = dev->platform_data; | ||
| 284 | if (!cinfo) { | ||
| 222 | dev_err(dev, "no info for asoc-simple-card\n"); | 285 | dev_err(dev, "no info for asoc-simple-card\n"); |
| 223 | return -EINVAL; | 286 | return -EINVAL; |
| 224 | } | 287 | } |
| 225 | 288 | ||
| 226 | memcpy(cinfo, dev->platform_data, sizeof(*cinfo)); | 289 | if (!cinfo->name || |
| 227 | cinfo->snd_card.dev = dev; | 290 | !cinfo->codec_dai.name || |
| 228 | } | 291 | !cinfo->codec || |
| 292 | !cinfo->platform || | ||
| 293 | !cinfo->cpu_dai.name) { | ||
| 294 | dev_err(dev, "insufficient asoc_simple_card_info settings\n"); | ||
| 295 | return -EINVAL; | ||
| 296 | } | ||
| 229 | 297 | ||
| 230 | if (!cinfo->name || | 298 | priv->snd_card.name = (cinfo->card) ? cinfo->card : cinfo->name; |
| 231 | !cinfo->card || | 299 | dai_link->name = cinfo->name; |
| 232 | !cinfo->codec_dai.name || | 300 | dai_link->stream_name = cinfo->name; |
| 233 | !(cinfo->codec || of_codec) || | 301 | dai_link->platform_name = cinfo->platform; |
| 234 | !(cinfo->platform || of_platform) || | 302 | dai_link->codec_name = cinfo->codec; |
| 235 | !(cinfo->cpu_dai.name || of_cpu)) { | 303 | dai_link->cpu_dai_name = cinfo->cpu_dai.name; |
| 236 | dev_err(dev, "insufficient asoc_simple_card_info settings\n"); | 304 | dai_link->codec_dai_name = cinfo->codec_dai.name; |
| 237 | return -EINVAL; | 305 | memcpy(&priv->cpu_dai, &cinfo->cpu_dai, |
| 306 | sizeof(priv->cpu_dai)); | ||
| 307 | memcpy(&priv->codec_dai, &cinfo->codec_dai, | ||
| 308 | sizeof(priv->codec_dai)); | ||
| 309 | |||
| 310 | priv->cpu_dai.fmt |= cinfo->daifmt; | ||
| 311 | priv->codec_dai.fmt |= cinfo->daifmt; | ||
| 238 | } | 312 | } |
| 239 | 313 | ||
| 240 | /* | 314 | /* |
| 241 | * init snd_soc_dai_link | 315 | * init snd_soc_dai_link |
| 242 | */ | 316 | */ |
| 243 | cinfo->snd_link.name = cinfo->name; | 317 | dai_link->init = asoc_simple_card_dai_init; |
| 244 | cinfo->snd_link.stream_name = cinfo->name; | ||
| 245 | cinfo->snd_link.cpu_dai_name = cinfo->cpu_dai.name; | ||
| 246 | cinfo->snd_link.platform_name = cinfo->platform; | ||
| 247 | cinfo->snd_link.codec_name = cinfo->codec; | ||
| 248 | cinfo->snd_link.codec_dai_name = cinfo->codec_dai.name; | ||
| 249 | cinfo->snd_link.cpu_of_node = of_cpu; | ||
| 250 | cinfo->snd_link.codec_of_node = of_codec; | ||
| 251 | cinfo->snd_link.platform_of_node = of_platform; | ||
| 252 | cinfo->snd_link.init = asoc_simple_card_dai_init; | ||
| 253 | |||
| 254 | /* | ||
| 255 | * init snd_soc_card | ||
| 256 | */ | ||
| 257 | cinfo->snd_card.name = cinfo->card; | ||
| 258 | cinfo->snd_card.owner = THIS_MODULE; | ||
| 259 | cinfo->snd_card.dai_link = &cinfo->snd_link; | ||
| 260 | cinfo->snd_card.num_links = 1; | ||
| 261 | 318 | ||
| 262 | snd_soc_card_set_drvdata(&cinfo->snd_card, cinfo); | 319 | snd_soc_card_set_drvdata(&priv->snd_card, priv); |
| 263 | 320 | ||
| 264 | return devm_snd_soc_register_card(&pdev->dev, &cinfo->snd_card); | 321 | return devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); |
| 265 | } | 322 | } |
| 266 | 323 | ||
| 267 | static const struct of_device_id asoc_simple_of_match[] = { | 324 | static const struct of_device_id asoc_simple_of_match[] = { |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 61c10bf503d2..4577b69fcf2c 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
| @@ -2,12 +2,50 @@ config SND_MFLD_MACHINE | |||
| 2 | tristate "SOC Machine Audio driver for Intel Medfield MID platform" | 2 | tristate "SOC Machine Audio driver for Intel Medfield MID platform" |
| 3 | depends on INTEL_SCU_IPC | 3 | depends on INTEL_SCU_IPC |
| 4 | select SND_SOC_SN95031 | 4 | select SND_SOC_SN95031 |
| 5 | select SND_SST_PLATFORM | 5 | select SND_SST_MFLD_PLATFORM |
| 6 | help | 6 | help |
| 7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform | 7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform |
| 8 | used as alsa device in audio substem in Intel(R) MID devices | 8 | used as alsa device in audio substem in Intel(R) MID devices |
| 9 | Say Y if you have such a device | 9 | Say Y if you have such a device |
| 10 | If unsure select "N". | 10 | If unsure select "N". |
| 11 | 11 | ||
| 12 | config SND_SST_PLATFORM | 12 | config SND_SST_MFLD_PLATFORM |
| 13 | tristate | 13 | tristate |
| 14 | |||
| 15 | config SND_SOC_INTEL_SST | ||
| 16 | tristate "ASoC support for Intel(R) Smart Sound Technology" | ||
| 17 | select SND_SOC_INTEL_SST_ACPI if ACPI | ||
| 18 | depends on (X86 || COMPILE_TEST) | ||
| 19 | help | ||
| 20 | This adds support for Intel(R) Smart Sound Technology (SST). | ||
| 21 | Say Y if you have such a device | ||
| 22 | If unsure select "N". | ||
| 23 | |||
| 24 | config SND_SOC_INTEL_SST_ACPI | ||
| 25 | tristate | ||
| 26 | |||
| 27 | config SND_SOC_INTEL_HASWELL | ||
| 28 | tristate | ||
| 29 | |||
| 30 | config SND_SOC_INTEL_BAYTRAIL | ||
| 31 | tristate | ||
| 32 | |||
| 33 | config SND_SOC_INTEL_HASWELL_MACH | ||
| 34 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | ||
| 35 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS | ||
| 36 | select SND_SOC_INTEL_HASWELL | ||
| 37 | select SND_SOC_RT5640 | ||
| 38 | help | ||
| 39 | This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell | ||
| 40 | Ultrabook platforms. | ||
| 41 | Say Y if you have such a device | ||
| 42 | If unsure select "N". | ||
| 43 | |||
| 44 | config SND_SOC_INTEL_BYT_RT5640_MACH | ||
| 45 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" | ||
| 46 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS | ||
| 47 | select SND_SOC_INTEL_BAYTRAIL | ||
| 48 | select SND_SOC_RT5640 | ||
| 49 | help | ||
| 50 | This adds audio driver for Intel Baytrail platform based boards | ||
| 51 | with the RT5640 audio codec. | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 639883339465..edeb79ae3dff 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
| @@ -1,5 +1,28 @@ | |||
| 1 | snd-soc-sst-platform-objs := sst_platform.o | 1 | # Core support |
| 2 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o | ||
| 3 | snd-soc-sst-acpi-objs := sst-acpi.o | ||
| 4 | |||
| 5 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o | ||
| 2 | snd-soc-mfld-machine-objs := mfld_machine.o | 6 | snd-soc-mfld-machine-objs := mfld_machine.o |
| 3 | 7 | ||
| 4 | obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o | 8 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o |
| 5 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o | 9 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o |
| 10 | |||
| 11 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o | ||
| 12 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o | ||
| 13 | |||
| 14 | # Platform Support | ||
| 15 | snd-soc-sst-haswell-pcm-objs := \ | ||
| 16 | sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o | ||
| 17 | snd-soc-sst-baytrail-pcm-objs := \ | ||
| 18 | sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o | ||
| 19 | |||
| 20 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o | ||
| 21 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | ||
| 22 | |||
| 23 | # Machine support | ||
| 24 | snd-soc-sst-haswell-objs := haswell.o | ||
| 25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | ||
| 26 | |||
| 27 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | ||
| 28 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | ||
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c new file mode 100644 index 000000000000..eff97c8e5218 --- /dev/null +++ b/sound/soc/intel/byt-rt5640.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Intel Baytrail SST RT5640 machine driver | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/init.h> | ||
| 16 | #include <linux/module.h> | ||
| 17 | #include <linux/platform_device.h> | ||
| 18 | #include <linux/acpi.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <sound/pcm.h> | ||
| 22 | #include <sound/pcm_params.h> | ||
| 23 | #include <sound/soc.h> | ||
| 24 | #include <sound/jack.h> | ||
| 25 | #include "../codecs/rt5640.h" | ||
| 26 | |||
| 27 | #include "sst-dsp.h" | ||
| 28 | |||
| 29 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | ||
| 30 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
| 31 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
| 32 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | ||
| 33 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
| 34 | }; | ||
| 35 | |||
| 36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | ||
| 37 | {"IN2P", NULL, "Headset Mic"}, | ||
| 38 | {"IN2N", NULL, "Headset Mic"}, | ||
| 39 | {"DMIC1", NULL, "Internal Mic"}, | ||
| 40 | {"Headphone", NULL, "HPOL"}, | ||
| 41 | {"Headphone", NULL, "HPOR"}, | ||
| 42 | {"Speaker", NULL, "SPOLP"}, | ||
| 43 | {"Speaker", NULL, "SPOLN"}, | ||
| 44 | {"Speaker", NULL, "SPORP"}, | ||
| 45 | {"Speaker", NULL, "SPORN"}, | ||
| 46 | }; | ||
| 47 | |||
| 48 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { | ||
| 49 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
| 50 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
| 51 | SOC_DAPM_PIN_SWITCH("Internal Mic"), | ||
| 52 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
| 53 | }; | ||
| 54 | |||
| 55 | static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, | ||
| 56 | struct snd_pcm_hw_params *params) | ||
| 57 | { | ||
| 58 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 59 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 60 | int ret; | ||
| 61 | |||
| 62 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | ||
| 63 | params_rate(params) * 256, | ||
| 64 | SND_SOC_CLOCK_IN); | ||
| 65 | if (ret < 0) { | ||
| 66 | dev_err(codec_dai->dev, "can't set codec clock %d\n", ret); | ||
| 67 | return ret; | ||
| 68 | } | ||
| 69 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, | ||
| 70 | params_rate(params) * 64, | ||
| 71 | params_rate(params) * 256); | ||
| 72 | if (ret < 0) { | ||
| 73 | dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); | ||
| 74 | return ret; | ||
| 75 | } | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | ||
| 80 | { | ||
| 81 | int ret; | ||
| 82 | struct snd_soc_codec *codec = runtime->codec; | ||
| 83 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 84 | struct snd_soc_card *card = runtime->card; | ||
| 85 | |||
| 86 | card->dapm.idle_bias_off = true; | ||
| 87 | |||
| 88 | ret = snd_soc_add_card_controls(card, byt_rt5640_controls, | ||
| 89 | ARRAY_SIZE(byt_rt5640_controls)); | ||
| 90 | if (ret) { | ||
| 91 | dev_err(card->dev, "unable to add card controls\n"); | ||
| 92 | return ret; | ||
| 93 | } | ||
| 94 | |||
| 95 | snd_soc_dapm_ignore_suspend(dapm, "HPOL"); | ||
| 96 | snd_soc_dapm_ignore_suspend(dapm, "HPOR"); | ||
| 97 | |||
| 98 | snd_soc_dapm_ignore_suspend(dapm, "SPOLP"); | ||
| 99 | snd_soc_dapm_ignore_suspend(dapm, "SPOLN"); | ||
| 100 | snd_soc_dapm_ignore_suspend(dapm, "SPORP"); | ||
| 101 | snd_soc_dapm_ignore_suspend(dapm, "SPORN"); | ||
| 102 | |||
| 103 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | ||
| 104 | snd_soc_dapm_enable_pin(dapm, "Headphone"); | ||
| 105 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | ||
| 106 | snd_soc_dapm_enable_pin(dapm, "Internal Mic"); | ||
| 107 | |||
| 108 | snd_soc_dapm_sync(dapm); | ||
| 109 | return ret; | ||
| 110 | } | ||
| 111 | |||
| 112 | static struct snd_soc_ops byt_rt5640_ops = { | ||
| 113 | .hw_params = byt_rt5640_hw_params, | ||
| 114 | }; | ||
| 115 | |||
| 116 | static struct snd_soc_dai_link byt_rt5640_dais[] = { | ||
| 117 | { | ||
| 118 | .name = "Baytrail Audio", | ||
| 119 | .stream_name = "Audio", | ||
| 120 | .cpu_dai_name = "Front-cpu-dai", | ||
| 121 | .codec_dai_name = "rt5640-aif1", | ||
| 122 | .codec_name = "i2c-10EC5640:00", | ||
| 123 | .platform_name = "baytrail-pcm-audio", | ||
| 124 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
| 125 | SND_SOC_DAIFMT_CBS_CFS, | ||
| 126 | .init = byt_rt5640_init, | ||
| 127 | .ignore_suspend = 1, | ||
| 128 | .ops = &byt_rt5640_ops, | ||
| 129 | }, | ||
| 130 | { | ||
| 131 | .name = "Baytrail Voice", | ||
| 132 | .stream_name = "Voice", | ||
| 133 | .cpu_dai_name = "Mic1-cpu-dai", | ||
| 134 | .codec_dai_name = "rt5640-aif1", | ||
| 135 | .codec_name = "i2c-10EC5640:00", | ||
| 136 | .platform_name = "baytrail-pcm-audio", | ||
| 137 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
| 138 | SND_SOC_DAIFMT_CBS_CFS, | ||
| 139 | .init = NULL, | ||
| 140 | .ignore_suspend = 1, | ||
| 141 | .ops = &byt_rt5640_ops, | ||
| 142 | }, | ||
| 143 | }; | ||
| 144 | |||
| 145 | static struct snd_soc_card byt_rt5640_card = { | ||
| 146 | .name = "byt-rt5640", | ||
| 147 | .dai_link = byt_rt5640_dais, | ||
| 148 | .num_links = ARRAY_SIZE(byt_rt5640_dais), | ||
| 149 | .dapm_widgets = byt_rt5640_widgets, | ||
| 150 | .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), | ||
| 151 | .dapm_routes = byt_rt5640_audio_map, | ||
| 152 | .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), | ||
| 153 | }; | ||
| 154 | |||
| 155 | static int byt_rt5640_probe(struct platform_device *pdev) | ||
| 156 | { | ||
| 157 | struct snd_soc_card *card = &byt_rt5640_card; | ||
| 158 | struct device *dev = &pdev->dev; | ||
| 159 | |||
| 160 | card->dev = &pdev->dev; | ||
| 161 | dev_set_drvdata(dev, card); | ||
| 162 | return snd_soc_register_card(card); | ||
| 163 | } | ||
| 164 | |||
| 165 | static int byt_rt5640_remove(struct platform_device *pdev) | ||
| 166 | { | ||
| 167 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
| 168 | |||
| 169 | snd_soc_unregister_card(card); | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static struct platform_driver byt_rt5640_audio = { | ||
| 175 | .probe = byt_rt5640_probe, | ||
| 176 | .remove = byt_rt5640_remove, | ||
| 177 | .driver = { | ||
| 178 | .name = "byt-rt5640", | ||
| 179 | .owner = THIS_MODULE, | ||
| 180 | }, | ||
| 181 | }; | ||
| 182 | module_platform_driver(byt_rt5640_audio) | ||
| 183 | |||
| 184 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver"); | ||
| 185 | MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula"); | ||
| 186 | MODULE_LICENSE("GPL v2"); | ||
| 187 | MODULE_ALIAS("platform:byt-rt5640"); | ||
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c new file mode 100644 index 000000000000..54345a2a7386 --- /dev/null +++ b/sound/soc/intel/haswell.c | |||
| @@ -0,0 +1,235 @@ | |||
| 1 | /* | ||
| 2 | * Intel Haswell Lynxpoint SST Audio | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/platform_device.h> | ||
| 19 | #include <sound/core.h> | ||
| 20 | #include <sound/pcm.h> | ||
| 21 | #include <sound/soc.h> | ||
| 22 | #include <sound/pcm_params.h> | ||
| 23 | |||
| 24 | #include "sst-dsp.h" | ||
| 25 | #include "sst-haswell-ipc.h" | ||
| 26 | |||
| 27 | #include "../codecs/rt5640.h" | ||
| 28 | |||
| 29 | /* Haswell ULT platforms have a Headphone and Mic jack */ | ||
| 30 | static const struct snd_soc_dapm_widget haswell_widgets[] = { | ||
| 31 | SND_SOC_DAPM_HP("Headphones", NULL), | ||
| 32 | SND_SOC_DAPM_MIC("Mic", NULL), | ||
| 33 | }; | ||
| 34 | |||
| 35 | static const struct snd_soc_dapm_route haswell_rt5640_map[] = { | ||
| 36 | |||
| 37 | {"Headphones", NULL, "HPOR"}, | ||
| 38 | {"Headphones", NULL, "HPOL"}, | ||
| 39 | {"IN2P", NULL, "Mic"}, | ||
| 40 | |||
| 41 | /* CODEC BE connections */ | ||
| 42 | {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, | ||
| 43 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
| 47 | struct snd_pcm_hw_params *params) | ||
| 48 | { | ||
| 49 | struct snd_interval *rate = hw_param_interval(params, | ||
| 50 | SNDRV_PCM_HW_PARAM_RATE); | ||
| 51 | struct snd_interval *channels = hw_param_interval(params, | ||
| 52 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
| 53 | |||
| 54 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
| 55 | rate->min = rate->max = 48000; | ||
| 56 | channels->min = channels->max = 2; | ||
| 57 | |||
| 58 | /* set SSP0 to 16 bit */ | ||
| 59 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
| 60 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
| 61 | SNDRV_PCM_FORMAT_S16_LE); | ||
| 62 | return 0; | ||
| 63 | } | ||
| 64 | |||
| 65 | static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, | ||
| 66 | struct snd_pcm_hw_params *params) | ||
| 67 | { | ||
| 68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 69 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 70 | int ret; | ||
| 71 | |||
| 72 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, | ||
| 73 | SND_SOC_CLOCK_IN); | ||
| 74 | |||
| 75 | if (ret < 0) { | ||
| 76 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
| 77 | return ret; | ||
| 78 | } | ||
| 79 | |||
| 80 | /* set correct codec filter for DAI format and clock config */ | ||
| 81 | snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000); | ||
| 82 | |||
| 83 | return ret; | ||
| 84 | } | ||
| 85 | |||
| 86 | static struct snd_soc_ops haswell_rt5640_ops = { | ||
| 87 | .hw_params = haswell_rt5640_hw_params, | ||
| 88 | }; | ||
| 89 | |||
| 90 | static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) | ||
| 91 | { | ||
| 92 | struct snd_soc_codec *codec = rtd->codec; | ||
| 93 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 94 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | ||
| 95 | struct sst_hsw *haswell = pdata->dsp; | ||
| 96 | int ret; | ||
| 97 | |||
| 98 | /* Set ADSP SSP port settings */ | ||
| 99 | ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0, | ||
| 100 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
| 101 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
| 102 | if (ret < 0) { | ||
| 103 | dev_err(rtd->dev, "failed to set device config\n"); | ||
| 104 | return ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | /* always connected */ | ||
| 108 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | ||
| 109 | snd_soc_dapm_enable_pin(dapm, "Mic"); | ||
| 110 | |||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | static struct snd_soc_dai_link haswell_rt5640_dais[] = { | ||
| 115 | /* Front End DAI links */ | ||
| 116 | { | ||
| 117 | .name = "System", | ||
| 118 | .stream_name = "System Playback", | ||
| 119 | .cpu_dai_name = "System Pin", | ||
| 120 | .platform_name = "haswell-pcm-audio", | ||
| 121 | .dynamic = 1, | ||
| 122 | .codec_name = "snd-soc-dummy", | ||
| 123 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 124 | .init = haswell_rtd_init, | ||
| 125 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 126 | .dpcm_playback = 1, | ||
| 127 | }, | ||
| 128 | { | ||
| 129 | .name = "Offload0", | ||
| 130 | .stream_name = "Offload0 Playback", | ||
| 131 | .cpu_dai_name = "Offload0 Pin", | ||
| 132 | .platform_name = "haswell-pcm-audio", | ||
| 133 | .dynamic = 1, | ||
| 134 | .codec_name = "snd-soc-dummy", | ||
| 135 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 136 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 137 | .dpcm_playback = 1, | ||
| 138 | }, | ||
| 139 | { | ||
| 140 | .name = "Offload1", | ||
| 141 | .stream_name = "Offload1 Playback", | ||
| 142 | .cpu_dai_name = "Offload1 Pin", | ||
| 143 | .platform_name = "haswell-pcm-audio", | ||
| 144 | .dynamic = 1, | ||
| 145 | .codec_name = "snd-soc-dummy", | ||
| 146 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 147 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 148 | .dpcm_playback = 1, | ||
| 149 | }, | ||
| 150 | { | ||
| 151 | .name = "Loopback", | ||
| 152 | .stream_name = "Loopback", | ||
| 153 | .cpu_dai_name = "Loopback Pin", | ||
| 154 | .platform_name = "haswell-pcm-audio", | ||
| 155 | .dynamic = 0, | ||
| 156 | .codec_name = "snd-soc-dummy", | ||
| 157 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 158 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 159 | .dpcm_capture = 1, | ||
| 160 | }, | ||
| 161 | { | ||
| 162 | .name = "Capture", | ||
| 163 | .stream_name = "Capture", | ||
| 164 | .cpu_dai_name = "Capture Pin", | ||
| 165 | .platform_name = "haswell-pcm-audio", | ||
| 166 | .dynamic = 1, | ||
| 167 | .codec_name = "snd-soc-dummy", | ||
| 168 | .codec_dai_name = "snd-soc-dummy-dai", | ||
| 169 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
| 170 | .dpcm_capture = 1, | ||
| 171 | }, | ||
| 172 | |||
| 173 | /* Back End DAI links */ | ||
| 174 | { | ||
| 175 | /* SSP0 - Codec */ | ||
| 176 | .name = "Codec", | ||
| 177 | .be_id = 0, | ||
| 178 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
| 179 | .platform_name = "snd-soc-dummy", | ||
| 180 | .no_pcm = 1, | ||
| 181 | .codec_name = "i2c-INT33CA:00", | ||
| 182 | .codec_dai_name = "rt5640-aif1", | ||
| 183 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
| 184 | SND_SOC_DAIFMT_CBS_CFS, | ||
| 185 | .ignore_suspend = 1, | ||
| 186 | .ignore_pmdown_time = 1, | ||
| 187 | .be_hw_params_fixup = haswell_ssp0_fixup, | ||
| 188 | .ops = &haswell_rt5640_ops, | ||
| 189 | .dpcm_playback = 1, | ||
| 190 | .dpcm_capture = 1, | ||
| 191 | }, | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* audio machine driver for Haswell Lynxpoint DSP + RT5640 */ | ||
| 195 | static struct snd_soc_card haswell_rt5640 = { | ||
| 196 | .name = "haswell-rt5640", | ||
| 197 | .owner = THIS_MODULE, | ||
| 198 | .dai_link = haswell_rt5640_dais, | ||
| 199 | .num_links = ARRAY_SIZE(haswell_rt5640_dais), | ||
| 200 | .dapm_widgets = haswell_widgets, | ||
| 201 | .num_dapm_widgets = ARRAY_SIZE(haswell_widgets), | ||
| 202 | .dapm_routes = haswell_rt5640_map, | ||
| 203 | .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map), | ||
| 204 | .fully_routed = true, | ||
| 205 | }; | ||
| 206 | |||
| 207 | static int haswell_audio_probe(struct platform_device *pdev) | ||
| 208 | { | ||
| 209 | haswell_rt5640.dev = &pdev->dev; | ||
| 210 | |||
| 211 | return snd_soc_register_card(&haswell_rt5640); | ||
| 212 | } | ||
| 213 | |||
| 214 | static int haswell_audio_remove(struct platform_device *pdev) | ||
| 215 | { | ||
| 216 | snd_soc_unregister_card(&haswell_rt5640); | ||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static struct platform_driver haswell_audio = { | ||
| 221 | .probe = haswell_audio_probe, | ||
| 222 | .remove = haswell_audio_remove, | ||
| 223 | .driver = { | ||
| 224 | .name = "haswell-audio", | ||
| 225 | .owner = THIS_MODULE, | ||
| 226 | }, | ||
| 227 | }; | ||
| 228 | |||
| 229 | module_platform_driver(haswell_audio) | ||
| 230 | |||
| 231 | /* Module information */ | ||
| 232 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
| 233 | MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint"); | ||
| 234 | MODULE_LICENSE("GPL v2"); | ||
| 235 | MODULE_ALIAS("platform:haswell-audio"); | ||
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index d3d4c32434f7..0cef32e9d402 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c | |||
| @@ -101,20 +101,27 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, | |||
| 101 | struct snd_ctl_elem_value *ucontrol) | 101 | struct snd_ctl_elem_value *ucontrol) |
| 102 | { | 102 | { |
| 103 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 103 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 104 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 104 | 105 | ||
| 105 | if (ucontrol->value.integer.value[0] == hs_switch) | 106 | if (ucontrol->value.integer.value[0] == hs_switch) |
| 106 | return 0; | 107 | return 0; |
| 107 | 108 | ||
| 109 | snd_soc_dapm_mutex_lock(dapm); | ||
| 110 | |||
| 108 | if (ucontrol->value.integer.value[0]) { | 111 | if (ucontrol->value.integer.value[0]) { |
| 109 | pr_debug("hs_set HS path\n"); | 112 | pr_debug("hs_set HS path\n"); |
| 110 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 113 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); |
| 111 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 114 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
| 112 | } else { | 115 | } else { |
| 113 | pr_debug("hs_set EP path\n"); | 116 | pr_debug("hs_set EP path\n"); |
| 114 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 117 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
| 115 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 118 | snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); |
| 116 | } | 119 | } |
| 117 | snd_soc_dapm_sync(&codec->dapm); | 120 | |
| 121 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 122 | |||
| 123 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 124 | |||
| 118 | hs_switch = ucontrol->value.integer.value[0]; | 125 | hs_switch = ucontrol->value.integer.value[0]; |
| 119 | 126 | ||
| 120 | return 0; | 127 | return 0; |
| @@ -122,18 +129,20 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, | |||
| 122 | 129 | ||
| 123 | static void lo_enable_out_pins(struct snd_soc_codec *codec) | 130 | static void lo_enable_out_pins(struct snd_soc_codec *codec) |
| 124 | { | 131 | { |
| 125 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); | 132 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 126 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); | 133 | |
| 127 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); | 134 | snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL"); |
| 128 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); | 135 | snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR"); |
| 129 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); | 136 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL"); |
| 130 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); | 137 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR"); |
| 138 | snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT"); | ||
| 139 | snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT"); | ||
| 131 | if (hs_switch) { | 140 | if (hs_switch) { |
| 132 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 141 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); |
| 133 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 142 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
| 134 | } else { | 143 | } else { |
| 135 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 144 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
| 136 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 145 | snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); |
| 137 | } | 146 | } |
| 138 | } | 147 | } |
| 139 | 148 | ||
| @@ -148,44 +157,52 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol, | |||
| 148 | struct snd_ctl_elem_value *ucontrol) | 157 | struct snd_ctl_elem_value *ucontrol) |
| 149 | { | 158 | { |
| 150 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 159 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 160 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 151 | 161 | ||
| 152 | if (ucontrol->value.integer.value[0] == lo_dac) | 162 | if (ucontrol->value.integer.value[0] == lo_dac) |
| 153 | return 0; | 163 | return 0; |
| 154 | 164 | ||
| 165 | snd_soc_dapm_mutex_lock(dapm); | ||
| 166 | |||
| 155 | /* we dont want to work with last state of lineout so just enable all | 167 | /* we dont want to work with last state of lineout so just enable all |
| 156 | * pins and then disable pins not required | 168 | * pins and then disable pins not required |
| 157 | */ | 169 | */ |
| 158 | lo_enable_out_pins(codec); | 170 | lo_enable_out_pins(codec); |
| 171 | |||
| 159 | switch (ucontrol->value.integer.value[0]) { | 172 | switch (ucontrol->value.integer.value[0]) { |
| 160 | case 0: | 173 | case 0: |
| 161 | pr_debug("set vibra path\n"); | 174 | pr_debug("set vibra path\n"); |
| 162 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); | 175 | snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT"); |
| 163 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); | 176 | snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT"); |
| 164 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); | 177 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); |
| 165 | break; | 178 | break; |
| 166 | 179 | ||
| 167 | case 1: | 180 | case 1: |
| 168 | pr_debug("set hs path\n"); | 181 | pr_debug("set hs path\n"); |
| 169 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 182 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
| 170 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 183 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
| 171 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); | 184 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); |
| 172 | break; | 185 | break; |
| 173 | 186 | ||
| 174 | case 2: | 187 | case 2: |
| 175 | pr_debug("set spkr path\n"); | 188 | pr_debug("set spkr path\n"); |
| 176 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); | 189 | snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL"); |
| 177 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); | 190 | snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR"); |
| 178 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); | 191 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); |
| 179 | break; | 192 | break; |
| 180 | 193 | ||
| 181 | case 3: | 194 | case 3: |
| 182 | pr_debug("set null path\n"); | 195 | pr_debug("set null path\n"); |
| 183 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); | 196 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL"); |
| 184 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); | 197 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR"); |
| 185 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); | 198 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); |
| 186 | break; | 199 | break; |
| 187 | } | 200 | } |
| 188 | snd_soc_dapm_sync(&codec->dapm); | 201 | |
| 202 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 203 | |||
| 204 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 205 | |||
| 189 | lo_dac = ucontrol->value.integer.value[0]; | 206 | lo_dac = ucontrol->value.integer.value[0]; |
| 190 | return 0; | 207 | return 0; |
| 191 | } | 208 | } |
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c new file mode 100644 index 000000000000..5d06eecb6198 --- /dev/null +++ b/sound/soc/intel/sst-acpi.c | |||
| @@ -0,0 +1,284 @@ | |||
| 1 | /* | ||
| 2 | * Intel SST loader on ACPI systems | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/acpi.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/firmware.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | |||
| 23 | #include "sst-dsp.h" | ||
| 24 | |||
| 25 | #define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000 | ||
| 26 | #define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000 | ||
| 27 | #define SST_LPT_DSP_DMA_SIZE (1024 - 1) | ||
| 28 | |||
| 29 | /* Descriptor for SST ASoC machine driver */ | ||
| 30 | struct sst_acpi_mach { | ||
| 31 | /* ACPI ID for the matching machine driver. Audio codec for instance */ | ||
| 32 | const u8 id[ACPI_ID_LEN]; | ||
| 33 | /* machine driver name */ | ||
| 34 | const char *drv_name; | ||
| 35 | /* firmware file name */ | ||
| 36 | const char *fw_filename; | ||
| 37 | }; | ||
| 38 | |||
| 39 | /* Descriptor for setting up SST platform data */ | ||
| 40 | struct sst_acpi_desc { | ||
| 41 | const char *drv_name; | ||
| 42 | struct sst_acpi_mach *machines; | ||
| 43 | /* Platform resource indexes. Must set to -1 if not used */ | ||
| 44 | int resindex_lpe_base; | ||
| 45 | int resindex_pcicfg_base; | ||
| 46 | int resindex_fw_base; | ||
| 47 | int irqindex_host_ipc; | ||
| 48 | int resindex_dma_base; | ||
| 49 | /* Unique number identifying the SST core on platform */ | ||
| 50 | int sst_id; | ||
| 51 | /* DMA only valid when resindex_dma_base != -1*/ | ||
| 52 | int dma_engine; | ||
| 53 | int dma_size; | ||
| 54 | }; | ||
| 55 | |||
| 56 | struct sst_acpi_priv { | ||
| 57 | struct platform_device *pdev_mach; | ||
| 58 | struct platform_device *pdev_pcm; | ||
| 59 | struct sst_pdata sst_pdata; | ||
| 60 | struct sst_acpi_desc *desc; | ||
| 61 | struct sst_acpi_mach *mach; | ||
| 62 | }; | ||
| 63 | |||
| 64 | static void sst_acpi_fw_cb(const struct firmware *fw, void *context) | ||
| 65 | { | ||
| 66 | struct platform_device *pdev = context; | ||
| 67 | struct device *dev = &pdev->dev; | ||
| 68 | struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev); | ||
| 69 | struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata; | ||
| 70 | struct sst_acpi_desc *desc = sst_acpi->desc; | ||
| 71 | struct sst_acpi_mach *mach = sst_acpi->mach; | ||
| 72 | |||
| 73 | sst_pdata->fw = fw; | ||
| 74 | if (!fw) { | ||
| 75 | dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename); | ||
| 76 | return; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* register PCM and DAI driver */ | ||
| 80 | sst_acpi->pdev_pcm = | ||
| 81 | platform_device_register_data(dev, desc->drv_name, -1, | ||
| 82 | sst_pdata, sizeof(*sst_pdata)); | ||
| 83 | if (IS_ERR(sst_acpi->pdev_pcm)) { | ||
| 84 | dev_err(dev, "Cannot register device %s. Error %d\n", | ||
| 85 | desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm)); | ||
| 86 | } | ||
| 87 | |||
| 88 | return; | ||
| 89 | } | ||
| 90 | |||
| 91 | static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, | ||
| 92 | void *context, void **ret) | ||
| 93 | { | ||
| 94 | *(bool *)context = true; | ||
| 95 | return AE_OK; | ||
| 96 | } | ||
| 97 | |||
| 98 | static struct sst_acpi_mach *sst_acpi_find_machine( | ||
| 99 | struct sst_acpi_mach *machines) | ||
| 100 | { | ||
| 101 | struct sst_acpi_mach *mach; | ||
| 102 | bool found = false; | ||
| 103 | |||
| 104 | for (mach = machines; mach->id[0]; mach++) | ||
| 105 | if (ACPI_SUCCESS(acpi_get_devices(mach->id, | ||
| 106 | sst_acpi_mach_match, | ||
| 107 | &found, NULL)) && found) | ||
| 108 | return mach; | ||
| 109 | |||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | |||
| 113 | static int sst_acpi_probe(struct platform_device *pdev) | ||
| 114 | { | ||
| 115 | const struct acpi_device_id *id; | ||
| 116 | struct device *dev = &pdev->dev; | ||
| 117 | struct sst_acpi_priv *sst_acpi; | ||
| 118 | struct sst_pdata *sst_pdata; | ||
| 119 | struct sst_acpi_mach *mach; | ||
| 120 | struct sst_acpi_desc *desc; | ||
| 121 | struct resource *mmio; | ||
| 122 | int ret = 0; | ||
| 123 | |||
| 124 | sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL); | ||
| 125 | if (sst_acpi == NULL) | ||
| 126 | return -ENOMEM; | ||
| 127 | |||
| 128 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
| 129 | if (!id) | ||
| 130 | return -ENODEV; | ||
| 131 | |||
| 132 | desc = (struct sst_acpi_desc *)id->driver_data; | ||
| 133 | mach = sst_acpi_find_machine(desc->machines); | ||
| 134 | if (mach == NULL) { | ||
| 135 | dev_err(dev, "No matching ASoC machine driver found\n"); | ||
| 136 | return -ENODEV; | ||
| 137 | } | ||
| 138 | |||
| 139 | sst_pdata = &sst_acpi->sst_pdata; | ||
| 140 | sst_pdata->id = desc->sst_id; | ||
| 141 | sst_acpi->desc = desc; | ||
| 142 | sst_acpi->mach = mach; | ||
| 143 | |||
| 144 | if (desc->resindex_dma_base >= 0) { | ||
| 145 | sst_pdata->dma_engine = desc->dma_engine; | ||
| 146 | sst_pdata->dma_base = desc->resindex_dma_base; | ||
| 147 | sst_pdata->dma_size = desc->dma_size; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (desc->irqindex_host_ipc >= 0) | ||
| 151 | sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc); | ||
| 152 | |||
| 153 | if (desc->resindex_lpe_base >= 0) { | ||
| 154 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 155 | desc->resindex_lpe_base); | ||
| 156 | if (mmio) { | ||
| 157 | sst_pdata->lpe_base = mmio->start; | ||
| 158 | sst_pdata->lpe_size = resource_size(mmio); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | if (desc->resindex_pcicfg_base >= 0) { | ||
| 163 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 164 | desc->resindex_pcicfg_base); | ||
| 165 | if (mmio) { | ||
| 166 | sst_pdata->pcicfg_base = mmio->start; | ||
| 167 | sst_pdata->pcicfg_size = resource_size(mmio); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | if (desc->resindex_fw_base >= 0) { | ||
| 172 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
| 173 | desc->resindex_fw_base); | ||
| 174 | if (mmio) { | ||
| 175 | sst_pdata->fw_base = mmio->start; | ||
| 176 | sst_pdata->fw_size = resource_size(mmio); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | platform_set_drvdata(pdev, sst_acpi); | ||
| 181 | |||
| 182 | /* register machine driver */ | ||
| 183 | sst_acpi->pdev_mach = | ||
| 184 | platform_device_register_data(dev, mach->drv_name, -1, | ||
| 185 | sst_pdata, sizeof(*sst_pdata)); | ||
| 186 | if (IS_ERR(sst_acpi->pdev_mach)) | ||
| 187 | return PTR_ERR(sst_acpi->pdev_mach); | ||
| 188 | |||
| 189 | /* continue SST probing after firmware is loaded */ | ||
| 190 | ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename, | ||
| 191 | dev, GFP_KERNEL, pdev, sst_acpi_fw_cb); | ||
| 192 | if (ret) | ||
| 193 | platform_device_unregister(sst_acpi->pdev_mach); | ||
| 194 | |||
| 195 | return ret; | ||
| 196 | } | ||
| 197 | |||
| 198 | static int sst_acpi_remove(struct platform_device *pdev) | ||
| 199 | { | ||
| 200 | struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev); | ||
| 201 | struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata; | ||
| 202 | |||
| 203 | platform_device_unregister(sst_acpi->pdev_mach); | ||
| 204 | if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm)) | ||
| 205 | platform_device_unregister(sst_acpi->pdev_pcm); | ||
| 206 | release_firmware(sst_pdata->fw); | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | static struct sst_acpi_mach haswell_machines[] = { | ||
| 212 | { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" }, | ||
| 213 | {} | ||
| 214 | }; | ||
| 215 | |||
| 216 | static struct sst_acpi_desc sst_acpi_haswell_desc = { | ||
| 217 | .drv_name = "haswell-pcm-audio", | ||
| 218 | .machines = haswell_machines, | ||
| 219 | .resindex_lpe_base = 0, | ||
| 220 | .resindex_pcicfg_base = 1, | ||
| 221 | .resindex_fw_base = -1, | ||
| 222 | .irqindex_host_ipc = 0, | ||
| 223 | .sst_id = SST_DEV_ID_LYNX_POINT, | ||
| 224 | .dma_engine = SST_DMA_TYPE_DW, | ||
| 225 | .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET, | ||
| 226 | .dma_size = SST_LPT_DSP_DMA_SIZE, | ||
| 227 | }; | ||
| 228 | |||
| 229 | static struct sst_acpi_mach broadwell_machines[] = { | ||
| 230 | { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" }, | ||
| 231 | {} | ||
| 232 | }; | ||
| 233 | |||
| 234 | static struct sst_acpi_desc sst_acpi_broadwell_desc = { | ||
| 235 | .drv_name = "haswell-pcm-audio", | ||
| 236 | .machines = broadwell_machines, | ||
| 237 | .resindex_lpe_base = 0, | ||
| 238 | .resindex_pcicfg_base = 1, | ||
| 239 | .resindex_fw_base = -1, | ||
| 240 | .irqindex_host_ipc = 0, | ||
| 241 | .sst_id = SST_DEV_ID_WILDCAT_POINT, | ||
| 242 | .dma_engine = SST_DMA_TYPE_DW, | ||
| 243 | .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET, | ||
| 244 | .dma_size = SST_LPT_DSP_DMA_SIZE, | ||
| 245 | }; | ||
| 246 | |||
| 247 | static struct sst_acpi_mach baytrail_machines[] = { | ||
| 248 | { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, | ||
| 249 | {} | ||
| 250 | }; | ||
| 251 | |||
| 252 | static struct sst_acpi_desc sst_acpi_baytrail_desc = { | ||
| 253 | .drv_name = "baytrail-pcm-audio", | ||
| 254 | .machines = baytrail_machines, | ||
| 255 | .resindex_lpe_base = 0, | ||
| 256 | .resindex_pcicfg_base = 1, | ||
| 257 | .resindex_fw_base = 2, | ||
| 258 | .irqindex_host_ipc = 5, | ||
| 259 | .sst_id = SST_DEV_ID_BYT, | ||
| 260 | .resindex_dma_base = -1, | ||
| 261 | }; | ||
| 262 | |||
| 263 | static struct acpi_device_id sst_acpi_match[] = { | ||
| 264 | { "INT33C8", (unsigned long)&sst_acpi_haswell_desc }, | ||
| 265 | { "INT3438", (unsigned long)&sst_acpi_broadwell_desc }, | ||
| 266 | { "80860F28", (unsigned long)&sst_acpi_baytrail_desc }, | ||
| 267 | { } | ||
| 268 | }; | ||
| 269 | MODULE_DEVICE_TABLE(acpi, sst_acpi_match); | ||
| 270 | |||
| 271 | static struct platform_driver sst_acpi_driver = { | ||
| 272 | .probe = sst_acpi_probe, | ||
| 273 | .remove = sst_acpi_remove, | ||
| 274 | .driver = { | ||
| 275 | .name = "sst-acpi", | ||
| 276 | .owner = THIS_MODULE, | ||
| 277 | .acpi_match_table = ACPI_PTR(sst_acpi_match), | ||
| 278 | }, | ||
| 279 | }; | ||
| 280 | module_platform_driver(sst_acpi_driver); | ||
| 281 | |||
| 282 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); | ||
| 283 | MODULE_DESCRIPTION("Intel SST loader on ACPI systems"); | ||
| 284 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c new file mode 100644 index 000000000000..a50bf7fc0e3a --- /dev/null +++ b/sound/soc/intel/sst-baytrail-dsp.c | |||
| @@ -0,0 +1,372 @@ | |||
| 1 | /* | ||
| 2 | * Intel Baytrail SST DSP driver | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/delay.h> | ||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/dma-mapping.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/firmware.h> | ||
| 24 | |||
| 25 | #include "sst-dsp.h" | ||
| 26 | #include "sst-dsp-priv.h" | ||
| 27 | #include "sst-baytrail-ipc.h" | ||
| 28 | |||
| 29 | #define SST_BYT_FW_SIGNATURE_SIZE 4 | ||
| 30 | #define SST_BYT_FW_SIGN "$SST" | ||
| 31 | |||
| 32 | #define SST_BYT_IRAM_OFFSET 0xC0000 | ||
| 33 | #define SST_BYT_DRAM_OFFSET 0x100000 | ||
| 34 | #define SST_BYT_SHIM_OFFSET 0x140000 | ||
| 35 | |||
| 36 | enum sst_ram_type { | ||
| 37 | SST_BYT_IRAM = 1, | ||
| 38 | SST_BYT_DRAM = 2, | ||
| 39 | SST_BYT_CACHE = 3, | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct dma_block_info { | ||
| 43 | enum sst_ram_type type; /* IRAM/DRAM */ | ||
| 44 | u32 size; /* Bytes */ | ||
| 45 | u32 ram_offset; /* Offset in I/DRAM */ | ||
| 46 | u32 rsvd; /* Reserved field */ | ||
| 47 | }; | ||
| 48 | |||
| 49 | struct fw_header { | ||
| 50 | unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE]; | ||
| 51 | u32 file_size; /* size of fw minus this header */ | ||
| 52 | u32 modules; /* # of modules */ | ||
| 53 | u32 file_format; /* version of header format */ | ||
| 54 | u32 reserved[4]; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct sst_byt_fw_module_header { | ||
| 58 | unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE]; | ||
| 59 | u32 mod_size; /* size of module */ | ||
| 60 | u32 blocks; /* # of blocks */ | ||
| 61 | u32 type; /* codec type, pp lib */ | ||
| 62 | u32 entry_point; | ||
| 63 | }; | ||
| 64 | |||
| 65 | static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | ||
| 66 | struct sst_byt_fw_module_header *module) | ||
| 67 | { | ||
| 68 | struct dma_block_info *block; | ||
| 69 | struct sst_module *mod; | ||
| 70 | struct sst_module_data block_data; | ||
| 71 | struct sst_module_template template; | ||
| 72 | int count; | ||
| 73 | |||
| 74 | memset(&template, 0, sizeof(template)); | ||
| 75 | template.id = module->type; | ||
| 76 | template.entry = module->entry_point; | ||
| 77 | template.p.type = SST_MEM_DRAM; | ||
| 78 | template.p.data_type = SST_DATA_P; | ||
| 79 | template.s.type = SST_MEM_DRAM; | ||
| 80 | template.s.data_type = SST_DATA_S; | ||
| 81 | |||
| 82 | mod = sst_module_new(fw, &template, NULL); | ||
| 83 | if (mod == NULL) | ||
| 84 | return -ENOMEM; | ||
| 85 | |||
| 86 | block = (void *)module + sizeof(*module); | ||
| 87 | |||
| 88 | for (count = 0; count < module->blocks; count++) { | ||
| 89 | |||
| 90 | if (block->size <= 0) { | ||
| 91 | dev_err(dsp->dev, "block %d size invalid\n", count); | ||
| 92 | return -EINVAL; | ||
| 93 | } | ||
| 94 | |||
| 95 | switch (block->type) { | ||
| 96 | case SST_BYT_IRAM: | ||
| 97 | block_data.offset = block->ram_offset + | ||
| 98 | dsp->addr.iram_offset; | ||
| 99 | block_data.type = SST_MEM_IRAM; | ||
| 100 | break; | ||
| 101 | case SST_BYT_DRAM: | ||
| 102 | block_data.offset = block->ram_offset + | ||
| 103 | dsp->addr.dram_offset; | ||
| 104 | block_data.type = SST_MEM_DRAM; | ||
| 105 | break; | ||
| 106 | case SST_BYT_CACHE: | ||
| 107 | block_data.offset = block->ram_offset + | ||
| 108 | (dsp->addr.fw_ext - dsp->addr.lpe); | ||
| 109 | block_data.type = SST_MEM_CACHE; | ||
| 110 | break; | ||
| 111 | default: | ||
| 112 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", | ||
| 113 | block->type, count); | ||
| 114 | return -EINVAL; | ||
| 115 | } | ||
| 116 | |||
| 117 | block_data.size = block->size; | ||
| 118 | block_data.data_type = SST_DATA_M; | ||
| 119 | block_data.data = (void *)block + sizeof(*block); | ||
| 120 | |||
| 121 | sst_module_insert_fixed_block(mod, &block_data); | ||
| 122 | |||
| 123 | block = (void *)block + sizeof(*block) + block->size; | ||
| 124 | } | ||
| 125 | return 0; | ||
| 126 | } | ||
| 127 | |||
| 128 | static int sst_byt_parse_fw_image(struct sst_fw *sst_fw) | ||
| 129 | { | ||
| 130 | struct fw_header *header; | ||
| 131 | struct sst_byt_fw_module_header *module; | ||
| 132 | struct sst_dsp *dsp = sst_fw->dsp; | ||
| 133 | int ret, count; | ||
| 134 | |||
| 135 | /* Read the header information from the data pointer */ | ||
| 136 | header = (struct fw_header *)sst_fw->dma_buf; | ||
| 137 | |||
| 138 | /* verify FW */ | ||
| 139 | if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) || | ||
| 140 | (sst_fw->size != header->file_size + sizeof(*header))) { | ||
| 141 | /* Invalid FW signature */ | ||
| 142 | dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n"); | ||
| 143 | return -EINVAL; | ||
| 144 | } | ||
| 145 | |||
| 146 | dev_dbg(dsp->dev, | ||
| 147 | "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n", | ||
| 148 | header->signature, header->file_size, header->modules, | ||
| 149 | header->file_format, sizeof(*header)); | ||
| 150 | |||
| 151 | module = (void *)sst_fw->dma_buf + sizeof(*header); | ||
| 152 | for (count = 0; count < header->modules; count++) { | ||
| 153 | /* module */ | ||
| 154 | ret = sst_byt_parse_module(dsp, sst_fw, module); | ||
| 155 | if (ret < 0) { | ||
| 156 | dev_err(dsp->dev, "invalid module %d\n", count); | ||
| 157 | return ret; | ||
| 158 | } | ||
| 159 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
| 160 | } | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | static void sst_byt_dump_shim(struct sst_dsp *sst) | ||
| 166 | { | ||
| 167 | int i; | ||
| 168 | u64 reg; | ||
| 169 | |||
| 170 | for (i = 0; i <= 0xF0; i += 8) { | ||
| 171 | reg = sst_dsp_shim_read64_unlocked(sst, i); | ||
| 172 | if (reg) | ||
| 173 | dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n", | ||
| 174 | i, reg); | ||
| 175 | } | ||
| 176 | |||
| 177 | for (i = 0x00; i <= 0xff; i += 4) { | ||
| 178 | reg = readl(sst->addr.pci_cfg + i); | ||
| 179 | if (reg) | ||
| 180 | dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n", | ||
| 181 | i, (u32)reg); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | static irqreturn_t sst_byt_irq(int irq, void *context) | ||
| 186 | { | ||
| 187 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
| 188 | u64 isrx; | ||
| 189 | irqreturn_t ret = IRQ_NONE; | ||
| 190 | |||
| 191 | spin_lock(&sst->spinlock); | ||
| 192 | |||
| 193 | isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
| 194 | if (isrx & SST_ISRX_DONE) { | ||
| 195 | /* ADSP has processed the message request from IA */ | ||
| 196 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX, | ||
| 197 | SST_BYT_IPCX_DONE, 0); | ||
| 198 | ret = IRQ_WAKE_THREAD; | ||
| 199 | } | ||
| 200 | if (isrx & SST_BYT_ISRX_REQUEST) { | ||
| 201 | /* mask message request from ADSP and do processing later */ | ||
| 202 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX, | ||
| 203 | SST_BYT_IMRX_REQUEST, | ||
| 204 | SST_BYT_IMRX_REQUEST); | ||
| 205 | ret = IRQ_WAKE_THREAD; | ||
| 206 | } | ||
| 207 | |||
| 208 | spin_unlock(&sst->spinlock); | ||
| 209 | |||
| 210 | return ret; | ||
| 211 | } | ||
| 212 | |||
| 213 | static void sst_byt_boot(struct sst_dsp *sst) | ||
| 214 | { | ||
| 215 | int tries = 10; | ||
| 216 | |||
| 217 | /* release stall and wait to unstall */ | ||
| 218 | sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0); | ||
| 219 | while (tries--) { | ||
| 220 | if (!(sst_dsp_shim_read64(sst, SST_CSR) & | ||
| 221 | SST_BYT_CSR_PWAITMODE)) | ||
| 222 | break; | ||
| 223 | msleep(100); | ||
| 224 | } | ||
| 225 | if (tries < 0) { | ||
| 226 | dev_err(sst->dev, "unable to start DSP\n"); | ||
| 227 | sst_byt_dump_shim(sst); | ||
| 228 | } | ||
| 229 | } | ||
| 230 | |||
| 231 | static void sst_byt_reset(struct sst_dsp *sst) | ||
| 232 | { | ||
| 233 | /* put DSP into reset, set reset vector and stall */ | ||
| 234 | sst_dsp_shim_update_bits64(sst, SST_CSR, | ||
| 235 | SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL, | ||
| 236 | SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL); | ||
| 237 | |||
| 238 | udelay(10); | ||
| 239 | |||
| 240 | /* take DSP out of reset and keep stalled for FW loading */ | ||
| 241 | sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0); | ||
| 242 | } | ||
| 243 | |||
| 244 | struct sst_adsp_memregion { | ||
| 245 | u32 start; | ||
| 246 | u32 end; | ||
| 247 | int blocks; | ||
| 248 | enum sst_mem_type type; | ||
| 249 | }; | ||
| 250 | |||
| 251 | /* BYT test stuff */ | ||
| 252 | static const struct sst_adsp_memregion byt_region[] = { | ||
| 253 | {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */ | ||
| 254 | {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
| 255 | }; | ||
| 256 | |||
| 257 | static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
| 258 | { | ||
| 259 | sst->addr.lpe_base = pdata->lpe_base; | ||
| 260 | sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size); | ||
| 261 | if (!sst->addr.lpe) | ||
| 262 | return -ENODEV; | ||
| 263 | |||
| 264 | /* ADSP PCI MMIO config space */ | ||
| 265 | sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size); | ||
| 266 | if (!sst->addr.pci_cfg) { | ||
| 267 | iounmap(sst->addr.lpe); | ||
| 268 | return -ENODEV; | ||
| 269 | } | ||
| 270 | |||
| 271 | /* SST Extended FW allocation */ | ||
| 272 | sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size); | ||
| 273 | if (!sst->addr.fw_ext) { | ||
| 274 | iounmap(sst->addr.pci_cfg); | ||
| 275 | iounmap(sst->addr.lpe); | ||
| 276 | return -ENODEV; | ||
| 277 | } | ||
| 278 | |||
| 279 | /* SST Shim */ | ||
| 280 | sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset; | ||
| 281 | |||
| 282 | sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204, | ||
| 283 | SST_BYT_IPC_MAX_PAYLOAD_SIZE, | ||
| 284 | SST_BYT_MAILBOX_OFFSET, | ||
| 285 | SST_BYT_IPC_MAX_PAYLOAD_SIZE); | ||
| 286 | |||
| 287 | sst->irq = pdata->irq; | ||
| 288 | |||
| 289 | return 0; | ||
| 290 | } | ||
| 291 | |||
| 292 | static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
| 293 | { | ||
| 294 | const struct sst_adsp_memregion *region; | ||
| 295 | struct device *dev; | ||
| 296 | int ret = -ENODEV, i, j, region_count; | ||
| 297 | u32 offset, size; | ||
| 298 | |||
| 299 | dev = sst->dev; | ||
| 300 | |||
| 301 | switch (sst->id) { | ||
| 302 | case SST_DEV_ID_BYT: | ||
| 303 | region = byt_region; | ||
| 304 | region_count = ARRAY_SIZE(byt_region); | ||
| 305 | sst->addr.iram_offset = SST_BYT_IRAM_OFFSET; | ||
| 306 | sst->addr.dram_offset = SST_BYT_DRAM_OFFSET; | ||
| 307 | sst->addr.shim_offset = SST_BYT_SHIM_OFFSET; | ||
| 308 | break; | ||
| 309 | default: | ||
| 310 | dev_err(dev, "failed to get mem resources\n"); | ||
| 311 | return ret; | ||
| 312 | } | ||
| 313 | |||
| 314 | ret = sst_byt_resource_map(sst, pdata); | ||
| 315 | if (ret < 0) { | ||
| 316 | dev_err(dev, "failed to map resources\n"); | ||
| 317 | return ret; | ||
| 318 | } | ||
| 319 | |||
| 320 | /* | ||
| 321 | * save the physical address of extended firmware block in the first | ||
| 322 | * 4 bytes of the mailbox | ||
| 323 | */ | ||
| 324 | memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET, | ||
| 325 | &pdata->fw_base, sizeof(u32)); | ||
| 326 | |||
| 327 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
| 328 | if (ret) | ||
| 329 | return ret; | ||
| 330 | |||
| 331 | /* enable Interrupt from both sides */ | ||
| 332 | sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0); | ||
| 333 | sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0); | ||
| 334 | |||
| 335 | /* register DSP memory blocks - ideally we should get this from ACPI */ | ||
| 336 | for (i = 0; i < region_count; i++) { | ||
| 337 | offset = region[i].start; | ||
| 338 | size = (region[i].end - region[i].start) / region[i].blocks; | ||
| 339 | |||
| 340 | /* register individual memory blocks */ | ||
| 341 | for (j = 0; j < region[i].blocks; j++) { | ||
| 342 | sst_mem_block_register(sst, offset, size, | ||
| 343 | region[i].type, NULL, j, sst); | ||
| 344 | offset += size; | ||
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | return 0; | ||
| 349 | } | ||
| 350 | |||
| 351 | static void sst_byt_free(struct sst_dsp *sst) | ||
| 352 | { | ||
| 353 | sst_mem_block_unregister_all(sst); | ||
| 354 | iounmap(sst->addr.lpe); | ||
| 355 | iounmap(sst->addr.pci_cfg); | ||
| 356 | iounmap(sst->addr.fw_ext); | ||
| 357 | } | ||
| 358 | |||
| 359 | struct sst_ops sst_byt_ops = { | ||
| 360 | .reset = sst_byt_reset, | ||
| 361 | .boot = sst_byt_boot, | ||
| 362 | .write = sst_shim32_write, | ||
| 363 | .read = sst_shim32_read, | ||
| 364 | .write64 = sst_shim32_write64, | ||
| 365 | .read64 = sst_shim32_read64, | ||
| 366 | .ram_read = sst_memcpy_fromio_32, | ||
| 367 | .ram_write = sst_memcpy_toio_32, | ||
| 368 | .irq_handler = sst_byt_irq, | ||
| 369 | .init = sst_byt_init, | ||
| 370 | .free = sst_byt_free, | ||
| 371 | .parse_fw = sst_byt_parse_fw_image, | ||
| 372 | }; | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c new file mode 100644 index 000000000000..d0eaeee21be4 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
| @@ -0,0 +1,867 @@ | |||
| 1 | /* | ||
| 2 | * Intel Baytrail SST IPC Support | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/types.h> | ||
| 16 | #include <linux/kernel.h> | ||
| 17 | #include <linux/list.h> | ||
| 18 | #include <linux/device.h> | ||
| 19 | #include <linux/wait.h> | ||
| 20 | #include <linux/spinlock.h> | ||
| 21 | #include <linux/workqueue.h> | ||
| 22 | #include <linux/export.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/delay.h> | ||
| 25 | #include <linux/list.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/kthread.h> | ||
| 28 | #include <linux/firmware.h> | ||
| 29 | #include <linux/io.h> | ||
| 30 | #include <asm/div64.h> | ||
| 31 | |||
| 32 | #include "sst-baytrail-ipc.h" | ||
| 33 | #include "sst-dsp.h" | ||
| 34 | #include "sst-dsp-priv.h" | ||
| 35 | |||
| 36 | /* IPC message timeout */ | ||
| 37 | #define IPC_TIMEOUT_MSECS 300 | ||
| 38 | #define IPC_BOOT_MSECS 200 | ||
| 39 | |||
| 40 | #define IPC_EMPTY_LIST_SIZE 8 | ||
| 41 | |||
| 42 | /* IPC header bits */ | ||
| 43 | #define IPC_HEADER_MSG_ID_MASK 0xff | ||
| 44 | #define IPC_HEADER_MSG_ID(x) ((x) & IPC_HEADER_MSG_ID_MASK) | ||
| 45 | #define IPC_HEADER_STR_ID_SHIFT 8 | ||
| 46 | #define IPC_HEADER_STR_ID_MASK 0x1f | ||
| 47 | #define IPC_HEADER_STR_ID(x) (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT) | ||
| 48 | #define IPC_HEADER_LARGE_SHIFT 13 | ||
| 49 | #define IPC_HEADER_LARGE(x) (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT) | ||
| 50 | #define IPC_HEADER_DATA_SHIFT 16 | ||
| 51 | #define IPC_HEADER_DATA_MASK 0x3fff | ||
| 52 | #define IPC_HEADER_DATA(x) (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT) | ||
| 53 | |||
| 54 | /* mask for differentiating between notification and reply message */ | ||
| 55 | #define IPC_NOTIFICATION (0x1 << 7) | ||
| 56 | |||
| 57 | /* I2L Stream config/control msgs */ | ||
| 58 | #define IPC_IA_ALLOC_STREAM 0x20 | ||
| 59 | #define IPC_IA_FREE_STREAM 0x21 | ||
| 60 | #define IPC_IA_PAUSE_STREAM 0x24 | ||
| 61 | #define IPC_IA_RESUME_STREAM 0x25 | ||
| 62 | #define IPC_IA_DROP_STREAM 0x26 | ||
| 63 | #define IPC_IA_START_STREAM 0x30 | ||
| 64 | |||
| 65 | /* notification messages */ | ||
| 66 | #define IPC_IA_FW_INIT_CMPLT 0x81 | ||
| 67 | #define IPC_SST_PERIOD_ELAPSED 0x97 | ||
| 68 | |||
| 69 | /* IPC messages between host and ADSP */ | ||
| 70 | struct sst_byt_address_info { | ||
| 71 | u32 addr; | ||
| 72 | u32 size; | ||
| 73 | } __packed; | ||
| 74 | |||
| 75 | struct sst_byt_str_type { | ||
| 76 | u8 codec_type; | ||
| 77 | u8 str_type; | ||
| 78 | u8 operation; | ||
| 79 | u8 protected_str; | ||
| 80 | u8 time_slots; | ||
| 81 | u8 reserved; | ||
| 82 | u16 result; | ||
| 83 | } __packed; | ||
| 84 | |||
| 85 | struct sst_byt_pcm_params { | ||
| 86 | u8 num_chan; | ||
| 87 | u8 pcm_wd_sz; | ||
| 88 | u8 use_offload_path; | ||
| 89 | u8 reserved; | ||
| 90 | u32 sfreq; | ||
| 91 | u8 channel_map[8]; | ||
| 92 | } __packed; | ||
| 93 | |||
| 94 | struct sst_byt_frames_info { | ||
| 95 | u16 num_entries; | ||
| 96 | u16 rsrvd; | ||
| 97 | u32 frag_size; | ||
| 98 | struct sst_byt_address_info ring_buf_info[8]; | ||
| 99 | } __packed; | ||
| 100 | |||
| 101 | struct sst_byt_alloc_params { | ||
| 102 | struct sst_byt_str_type str_type; | ||
| 103 | struct sst_byt_pcm_params pcm_params; | ||
| 104 | struct sst_byt_frames_info frame_info; | ||
| 105 | } __packed; | ||
| 106 | |||
| 107 | struct sst_byt_alloc_response { | ||
| 108 | struct sst_byt_str_type str_type; | ||
| 109 | u8 reserved[88]; | ||
| 110 | } __packed; | ||
| 111 | |||
| 112 | struct sst_byt_start_stream_params { | ||
| 113 | u32 byte_offset; | ||
| 114 | } __packed; | ||
| 115 | |||
| 116 | struct sst_byt_tstamp { | ||
| 117 | u64 ring_buffer_counter; | ||
| 118 | u64 hardware_counter; | ||
| 119 | u64 frames_decoded; | ||
| 120 | u64 bytes_decoded; | ||
| 121 | u64 bytes_copied; | ||
| 122 | u32 sampling_frequency; | ||
| 123 | u32 channel_peak[8]; | ||
| 124 | } __packed; | ||
| 125 | |||
| 126 | /* driver internal IPC message structure */ | ||
| 127 | struct ipc_message { | ||
| 128 | struct list_head list; | ||
| 129 | u64 header; | ||
| 130 | |||
| 131 | /* direction wrt host CPU */ | ||
| 132 | char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
| 133 | size_t tx_size; | ||
| 134 | char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
| 135 | size_t rx_size; | ||
| 136 | |||
| 137 | wait_queue_head_t waitq; | ||
| 138 | bool complete; | ||
| 139 | bool wait; | ||
| 140 | int errno; | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct sst_byt_stream; | ||
| 144 | struct sst_byt; | ||
| 145 | |||
| 146 | /* stream infomation */ | ||
| 147 | struct sst_byt_stream { | ||
| 148 | struct list_head node; | ||
| 149 | |||
| 150 | /* configuration */ | ||
| 151 | struct sst_byt_alloc_params request; | ||
| 152 | struct sst_byt_alloc_response reply; | ||
| 153 | |||
| 154 | /* runtime info */ | ||
| 155 | struct sst_byt *byt; | ||
| 156 | int str_id; | ||
| 157 | bool commited; | ||
| 158 | bool running; | ||
| 159 | |||
| 160 | /* driver callback */ | ||
| 161 | u32 (*notify_position)(struct sst_byt_stream *stream, void *data); | ||
| 162 | void *pdata; | ||
| 163 | }; | ||
| 164 | |||
| 165 | /* SST Baytrail IPC data */ | ||
| 166 | struct sst_byt { | ||
| 167 | struct device *dev; | ||
| 168 | struct sst_dsp *dsp; | ||
| 169 | |||
| 170 | /* stream */ | ||
| 171 | struct list_head stream_list; | ||
| 172 | |||
| 173 | /* boot */ | ||
| 174 | wait_queue_head_t boot_wait; | ||
| 175 | bool boot_complete; | ||
| 176 | |||
| 177 | /* IPC messaging */ | ||
| 178 | struct list_head tx_list; | ||
| 179 | struct list_head rx_list; | ||
| 180 | struct list_head empty_list; | ||
| 181 | wait_queue_head_t wait_txq; | ||
| 182 | struct task_struct *tx_thread; | ||
| 183 | struct kthread_worker kworker; | ||
| 184 | struct kthread_work kwork; | ||
| 185 | struct ipc_message *msg; | ||
| 186 | }; | ||
| 187 | |||
| 188 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) | ||
| 189 | { | ||
| 190 | u64 header; | ||
| 191 | |||
| 192 | header = IPC_HEADER_MSG_ID(msg_id) | | ||
| 193 | IPC_HEADER_STR_ID(str_id) | | ||
| 194 | IPC_HEADER_LARGE(large) | | ||
| 195 | IPC_HEADER_DATA(data) | | ||
| 196 | SST_BYT_IPCX_BUSY; | ||
| 197 | |||
| 198 | return header; | ||
| 199 | } | ||
| 200 | |||
| 201 | static inline u16 sst_byt_header_msg_id(u64 header) | ||
| 202 | { | ||
| 203 | return header & IPC_HEADER_MSG_ID_MASK; | ||
| 204 | } | ||
| 205 | |||
| 206 | static inline u8 sst_byt_header_str_id(u64 header) | ||
| 207 | { | ||
| 208 | return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK; | ||
| 209 | } | ||
| 210 | |||
| 211 | static inline u16 sst_byt_header_data(u64 header) | ||
| 212 | { | ||
| 213 | return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK; | ||
| 214 | } | ||
| 215 | |||
| 216 | static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, | ||
| 217 | int stream_id) | ||
| 218 | { | ||
| 219 | struct sst_byt_stream *stream; | ||
| 220 | |||
| 221 | list_for_each_entry(stream, &byt->stream_list, node) { | ||
| 222 | if (stream->str_id == stream_id) | ||
| 223 | return stream; | ||
| 224 | } | ||
| 225 | |||
| 226 | return NULL; | ||
| 227 | } | ||
| 228 | |||
| 229 | static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text) | ||
| 230 | { | ||
| 231 | struct sst_dsp *sst = byt->dsp; | ||
| 232 | u64 isr, ipcd, imrx, ipcx; | ||
| 233 | |||
| 234 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
| 235 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
| 236 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
| 237 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
| 238 | |||
| 239 | dev_err(byt->dev, | ||
| 240 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
| 241 | text, ipcx, isr, ipcd, imrx); | ||
| 242 | } | ||
| 243 | |||
| 244 | /* locks held by caller */ | ||
| 245 | static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt) | ||
| 246 | { | ||
| 247 | struct ipc_message *msg = NULL; | ||
| 248 | |||
| 249 | if (!list_empty(&byt->empty_list)) { | ||
| 250 | msg = list_first_entry(&byt->empty_list, | ||
| 251 | struct ipc_message, list); | ||
| 252 | list_del(&msg->list); | ||
| 253 | } | ||
| 254 | |||
| 255 | return msg; | ||
| 256 | } | ||
| 257 | |||
| 258 | static void sst_byt_ipc_tx_msgs(struct kthread_work *work) | ||
| 259 | { | ||
| 260 | struct sst_byt *byt = | ||
| 261 | container_of(work, struct sst_byt, kwork); | ||
| 262 | struct ipc_message *msg; | ||
| 263 | u64 ipcx; | ||
| 264 | unsigned long flags; | ||
| 265 | |||
| 266 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 267 | if (list_empty(&byt->tx_list)) { | ||
| 268 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 269 | return; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* if the DSP is busy we will TX messages after IRQ */ | ||
| 273 | ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX); | ||
| 274 | if (ipcx & SST_BYT_IPCX_BUSY) { | ||
| 275 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 276 | return; | ||
| 277 | } | ||
| 278 | |||
| 279 | msg = list_first_entry(&byt->tx_list, struct ipc_message, list); | ||
| 280 | |||
| 281 | list_move(&msg->list, &byt->rx_list); | ||
| 282 | |||
| 283 | /* send the message */ | ||
| 284 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
| 285 | sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size); | ||
| 286 | sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header); | ||
| 287 | |||
| 288 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 289 | } | ||
| 290 | |||
| 291 | static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, | ||
| 292 | struct ipc_message *msg) | ||
| 293 | { | ||
| 294 | msg->complete = true; | ||
| 295 | |||
| 296 | if (!msg->wait) | ||
| 297 | list_add_tail(&msg->list, &byt->empty_list); | ||
| 298 | else | ||
| 299 | wake_up(&msg->waitq); | ||
| 300 | } | ||
| 301 | |||
| 302 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, | ||
| 303 | void *rx_data) | ||
| 304 | { | ||
| 305 | unsigned long flags; | ||
| 306 | int ret; | ||
| 307 | |||
| 308 | /* wait for DSP completion */ | ||
| 309 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
| 310 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
| 311 | |||
| 312 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 313 | if (ret == 0) { | ||
| 314 | list_del(&msg->list); | ||
| 315 | sst_byt_ipc_shim_dbg(byt, "message timeout"); | ||
| 316 | |||
| 317 | ret = -ETIMEDOUT; | ||
| 318 | } else { | ||
| 319 | |||
| 320 | /* copy the data returned from DSP */ | ||
| 321 | if (msg->rx_size) | ||
| 322 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
| 323 | ret = msg->errno; | ||
| 324 | } | ||
| 325 | |||
| 326 | list_add_tail(&msg->list, &byt->empty_list); | ||
| 327 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 328 | return ret; | ||
| 329 | } | ||
| 330 | |||
| 331 | static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header, | ||
| 332 | void *tx_data, size_t tx_bytes, | ||
| 333 | void *rx_data, size_t rx_bytes, int wait) | ||
| 334 | { | ||
| 335 | unsigned long flags; | ||
| 336 | struct ipc_message *msg; | ||
| 337 | |||
| 338 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
| 339 | |||
| 340 | msg = sst_byt_msg_get_empty(byt); | ||
| 341 | if (msg == NULL) { | ||
| 342 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 343 | return -EBUSY; | ||
| 344 | } | ||
| 345 | |||
| 346 | msg->header = header; | ||
| 347 | msg->tx_size = tx_bytes; | ||
| 348 | msg->rx_size = rx_bytes; | ||
| 349 | msg->wait = wait; | ||
| 350 | msg->errno = 0; | ||
| 351 | msg->complete = false; | ||
| 352 | |||
| 353 | if (tx_bytes) { | ||
| 354 | /* msg content = lower 32-bit of the header + data */ | ||
| 355 | *(u32 *)msg->tx_data = (u32)(header & (u32)-1); | ||
| 356 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes); | ||
| 357 | msg->tx_size += sizeof(u32); | ||
| 358 | } | ||
| 359 | |||
| 360 | list_add_tail(&msg->list, &byt->tx_list); | ||
| 361 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
| 362 | |||
| 363 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
| 364 | |||
| 365 | if (wait) | ||
| 366 | return sst_byt_tx_wait_done(byt, msg, rx_data); | ||
| 367 | else | ||
| 368 | return 0; | ||
| 369 | } | ||
| 370 | |||
| 371 | static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header, | ||
| 372 | void *tx_data, size_t tx_bytes, | ||
| 373 | void *rx_data, size_t rx_bytes) | ||
| 374 | { | ||
| 375 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
| 376 | rx_data, rx_bytes, 1); | ||
| 377 | } | ||
| 378 | |||
| 379 | static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header, | ||
| 380 | void *tx_data, size_t tx_bytes) | ||
| 381 | { | ||
| 382 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
| 383 | NULL, 0, 0); | ||
| 384 | } | ||
| 385 | |||
| 386 | static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt, | ||
| 387 | u64 header) | ||
| 388 | { | ||
| 389 | struct ipc_message *msg = NULL, *_msg; | ||
| 390 | u64 mask; | ||
| 391 | |||
| 392 | /* match reply to message sent based on msg and stream IDs */ | ||
| 393 | mask = IPC_HEADER_MSG_ID_MASK | | ||
| 394 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
| 395 | header &= mask; | ||
| 396 | |||
| 397 | if (list_empty(&byt->rx_list)) { | ||
| 398 | dev_err(byt->dev, | ||
| 399 | "ipc: rx list is empty but received 0x%llx\n", header); | ||
| 400 | goto out; | ||
| 401 | } | ||
| 402 | |||
| 403 | list_for_each_entry(_msg, &byt->rx_list, list) { | ||
| 404 | if ((_msg->header & mask) == header) { | ||
| 405 | msg = _msg; | ||
| 406 | break; | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | out: | ||
| 411 | return msg; | ||
| 412 | } | ||
| 413 | |||
| 414 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) | ||
| 415 | { | ||
| 416 | struct sst_byt_stream *stream; | ||
| 417 | u64 header = msg->header; | ||
| 418 | u8 stream_id = sst_byt_header_str_id(header); | ||
| 419 | u8 stream_msg = sst_byt_header_msg_id(header); | ||
| 420 | |||
| 421 | stream = sst_byt_get_stream(byt, stream_id); | ||
| 422 | if (stream == NULL) | ||
| 423 | return; | ||
| 424 | |||
| 425 | switch (stream_msg) { | ||
| 426 | case IPC_IA_DROP_STREAM: | ||
| 427 | case IPC_IA_PAUSE_STREAM: | ||
| 428 | case IPC_IA_FREE_STREAM: | ||
| 429 | stream->running = false; | ||
| 430 | break; | ||
| 431 | case IPC_IA_START_STREAM: | ||
| 432 | case IPC_IA_RESUME_STREAM: | ||
| 433 | stream->running = true; | ||
| 434 | break; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | ||
| 439 | { | ||
| 440 | struct ipc_message *msg; | ||
| 441 | |||
| 442 | msg = sst_byt_reply_find_msg(byt, header); | ||
| 443 | if (msg == NULL) | ||
| 444 | return 1; | ||
| 445 | |||
| 446 | if (header & IPC_HEADER_LARGE(true)) { | ||
| 447 | msg->rx_size = sst_byt_header_data(header); | ||
| 448 | sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size); | ||
| 449 | } | ||
| 450 | |||
| 451 | /* update any stream states */ | ||
| 452 | sst_byt_stream_update(byt, msg); | ||
| 453 | |||
| 454 | list_del(&msg->list); | ||
| 455 | /* wake up */ | ||
| 456 | sst_byt_tx_msg_reply_complete(byt, msg); | ||
| 457 | |||
| 458 | return 1; | ||
| 459 | } | ||
| 460 | |||
| 461 | static void sst_byt_fw_ready(struct sst_byt *byt, u64 header) | ||
| 462 | { | ||
| 463 | dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header); | ||
| 464 | |||
| 465 | byt->boot_complete = true; | ||
| 466 | wake_up(&byt->boot_wait); | ||
| 467 | } | ||
| 468 | |||
| 469 | static int sst_byt_process_notification(struct sst_byt *byt, | ||
| 470 | unsigned long *flags) | ||
| 471 | { | ||
| 472 | struct sst_dsp *sst = byt->dsp; | ||
| 473 | struct sst_byt_stream *stream; | ||
| 474 | u64 header; | ||
| 475 | u8 msg_id, stream_id; | ||
| 476 | int handled = 1; | ||
| 477 | |||
| 478 | header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
| 479 | msg_id = sst_byt_header_msg_id(header); | ||
| 480 | |||
| 481 | switch (msg_id) { | ||
| 482 | case IPC_SST_PERIOD_ELAPSED: | ||
| 483 | stream_id = sst_byt_header_str_id(header); | ||
| 484 | stream = sst_byt_get_stream(byt, stream_id); | ||
| 485 | if (stream && stream->running && stream->notify_position) { | ||
| 486 | spin_unlock_irqrestore(&sst->spinlock, *flags); | ||
| 487 | stream->notify_position(stream, stream->pdata); | ||
| 488 | spin_lock_irqsave(&sst->spinlock, *flags); | ||
| 489 | } | ||
| 490 | break; | ||
| 491 | case IPC_IA_FW_INIT_CMPLT: | ||
| 492 | sst_byt_fw_ready(byt, header); | ||
| 493 | break; | ||
| 494 | } | ||
| 495 | |||
| 496 | return handled; | ||
| 497 | } | ||
| 498 | |||
| 499 | static irqreturn_t sst_byt_irq_thread(int irq, void *context) | ||
| 500 | { | ||
| 501 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
| 502 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); | ||
| 503 | u64 header; | ||
| 504 | unsigned long flags; | ||
| 505 | |||
| 506 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 507 | |||
| 508 | header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
| 509 | if (header & SST_BYT_IPCD_BUSY) { | ||
| 510 | if (header & IPC_NOTIFICATION) { | ||
| 511 | /* message from ADSP */ | ||
| 512 | sst_byt_process_notification(byt, &flags); | ||
| 513 | } else { | ||
| 514 | /* reply from ADSP */ | ||
| 515 | sst_byt_process_reply(byt, header); | ||
| 516 | } | ||
| 517 | /* | ||
| 518 | * clear IPCD BUSY bit and set DONE bit. Tell DSP we have | ||
| 519 | * processed the message and can accept new. Clear data part | ||
| 520 | * of the header | ||
| 521 | */ | ||
| 522 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD, | ||
| 523 | SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY | | ||
| 524 | IPC_HEADER_DATA(IPC_HEADER_DATA_MASK), | ||
| 525 | SST_BYT_IPCD_DONE); | ||
| 526 | /* unmask message request interrupts */ | ||
| 527 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX, | ||
| 528 | SST_BYT_IMRX_REQUEST, 0); | ||
| 529 | } | ||
| 530 | |||
| 531 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 532 | |||
| 533 | /* continue to send any remaining messages... */ | ||
| 534 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
| 535 | |||
| 536 | return IRQ_HANDLED; | ||
| 537 | } | ||
| 538 | |||
| 539 | /* stream API */ | ||
| 540 | struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | ||
| 541 | u32 (*notify_position)(struct sst_byt_stream *stream, void *data), | ||
| 542 | void *data) | ||
| 543 | { | ||
| 544 | struct sst_byt_stream *stream; | ||
| 545 | |||
| 546 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
| 547 | if (stream == NULL) | ||
| 548 | return NULL; | ||
| 549 | |||
| 550 | list_add(&stream->node, &byt->stream_list); | ||
| 551 | stream->notify_position = notify_position; | ||
| 552 | stream->pdata = data; | ||
| 553 | stream->byt = byt; | ||
| 554 | stream->str_id = id; | ||
| 555 | |||
| 556 | return stream; | ||
| 557 | } | ||
| 558 | |||
| 559 | int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 560 | int bits) | ||
| 561 | { | ||
| 562 | stream->request.pcm_params.pcm_wd_sz = bits; | ||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | int sst_byt_stream_set_channels(struct sst_byt *byt, | ||
| 567 | struct sst_byt_stream *stream, u8 channels) | ||
| 568 | { | ||
| 569 | stream->request.pcm_params.num_chan = channels; | ||
| 570 | return 0; | ||
| 571 | } | ||
| 572 | |||
| 573 | int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 574 | unsigned int rate) | ||
| 575 | { | ||
| 576 | stream->request.pcm_params.sfreq = rate; | ||
| 577 | return 0; | ||
| 578 | } | ||
| 579 | |||
| 580 | /* stream sonfiguration */ | ||
| 581 | int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 582 | int codec_type, int stream_type, int operation) | ||
| 583 | { | ||
| 584 | stream->request.str_type.codec_type = codec_type; | ||
| 585 | stream->request.str_type.str_type = stream_type; | ||
| 586 | stream->request.str_type.operation = operation; | ||
| 587 | stream->request.str_type.time_slots = 0xc; | ||
| 588 | |||
| 589 | return 0; | ||
| 590 | } | ||
| 591 | |||
| 592 | int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 593 | uint32_t buffer_addr, uint32_t buffer_size) | ||
| 594 | { | ||
| 595 | stream->request.frame_info.num_entries = 1; | ||
| 596 | stream->request.frame_info.ring_buf_info[0].addr = buffer_addr; | ||
| 597 | stream->request.frame_info.ring_buf_info[0].size = buffer_size; | ||
| 598 | /* calculate bytes per 4 ms fragment */ | ||
| 599 | stream->request.frame_info.frag_size = | ||
| 600 | stream->request.pcm_params.sfreq * | ||
| 601 | stream->request.pcm_params.num_chan * | ||
| 602 | stream->request.pcm_params.pcm_wd_sz / 8 * | ||
| 603 | 4 / 1000; | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 608 | { | ||
| 609 | struct sst_byt_alloc_params *str_req = &stream->request; | ||
| 610 | struct sst_byt_alloc_response *reply = &stream->reply; | ||
| 611 | u64 header; | ||
| 612 | int ret; | ||
| 613 | |||
| 614 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, | ||
| 615 | sizeof(*str_req) + sizeof(u32), | ||
| 616 | true, stream->str_id); | ||
| 617 | ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req), | ||
| 618 | reply, sizeof(*reply)); | ||
| 619 | if (ret < 0) { | ||
| 620 | dev_err(byt->dev, "ipc: error stream commit failed\n"); | ||
| 621 | return ret; | ||
| 622 | } | ||
| 623 | |||
| 624 | stream->commited = true; | ||
| 625 | |||
| 626 | return 0; | ||
| 627 | } | ||
| 628 | |||
| 629 | int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 630 | { | ||
| 631 | u64 header; | ||
| 632 | int ret = 0; | ||
| 633 | |||
| 634 | if (!stream->commited) | ||
| 635 | goto out; | ||
| 636 | |||
| 637 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); | ||
| 638 | ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | ||
| 639 | if (ret < 0) { | ||
| 640 | dev_err(byt->dev, "ipc: free stream %d failed\n", | ||
| 641 | stream->str_id); | ||
| 642 | return -EAGAIN; | ||
| 643 | } | ||
| 644 | |||
| 645 | stream->commited = false; | ||
| 646 | out: | ||
| 647 | list_del(&stream->node); | ||
| 648 | kfree(stream); | ||
| 649 | |||
| 650 | return ret; | ||
| 651 | } | ||
| 652 | |||
| 653 | static int sst_byt_stream_operations(struct sst_byt *byt, int type, | ||
| 654 | int stream_id, int wait) | ||
| 655 | { | ||
| 656 | struct sst_byt_start_stream_params start_stream; | ||
| 657 | u64 header; | ||
| 658 | void *tx_msg = NULL; | ||
| 659 | size_t size = 0; | ||
| 660 | |||
| 661 | if (type != IPC_IA_START_STREAM) { | ||
| 662 | header = sst_byt_header(type, 0, false, stream_id); | ||
| 663 | } else { | ||
| 664 | start_stream.byte_offset = 0; | ||
| 665 | header = sst_byt_header(IPC_IA_START_STREAM, | ||
| 666 | sizeof(start_stream) + sizeof(u32), | ||
| 667 | true, stream_id); | ||
| 668 | tx_msg = &start_stream; | ||
| 669 | size = sizeof(start_stream); | ||
| 670 | } | ||
| 671 | |||
| 672 | if (wait) | ||
| 673 | return sst_byt_ipc_tx_msg_wait(byt, header, | ||
| 674 | tx_msg, size, NULL, 0); | ||
| 675 | else | ||
| 676 | return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | ||
| 677 | } | ||
| 678 | |||
| 679 | /* stream ALSA trigger operations */ | ||
| 680 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 681 | { | ||
| 682 | int ret; | ||
| 683 | |||
| 684 | ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM, | ||
| 685 | stream->str_id, 0); | ||
| 686 | if (ret < 0) | ||
| 687 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", | ||
| 688 | stream->str_id); | ||
| 689 | |||
| 690 | return ret; | ||
| 691 | } | ||
| 692 | |||
| 693 | int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 694 | { | ||
| 695 | int ret; | ||
| 696 | |||
| 697 | /* don't stop streams that are not commited */ | ||
| 698 | if (!stream->commited) | ||
| 699 | return 0; | ||
| 700 | |||
| 701 | ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM, | ||
| 702 | stream->str_id, 0); | ||
| 703 | if (ret < 0) | ||
| 704 | dev_err(byt->dev, "ipc: error failed to stop stream %d\n", | ||
| 705 | stream->str_id); | ||
| 706 | return ret; | ||
| 707 | } | ||
| 708 | |||
| 709 | int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 710 | { | ||
| 711 | int ret; | ||
| 712 | |||
| 713 | ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM, | ||
| 714 | stream->str_id, 0); | ||
| 715 | if (ret < 0) | ||
| 716 | dev_err(byt->dev, "ipc: error failed to pause stream %d\n", | ||
| 717 | stream->str_id); | ||
| 718 | |||
| 719 | return ret; | ||
| 720 | } | ||
| 721 | |||
| 722 | int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
| 723 | { | ||
| 724 | int ret; | ||
| 725 | |||
| 726 | ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM, | ||
| 727 | stream->str_id, 0); | ||
| 728 | if (ret < 0) | ||
| 729 | dev_err(byt->dev, "ipc: error failed to resume stream %d\n", | ||
| 730 | stream->str_id); | ||
| 731 | |||
| 732 | return ret; | ||
| 733 | } | ||
| 734 | |||
| 735 | int sst_byt_get_dsp_position(struct sst_byt *byt, | ||
| 736 | struct sst_byt_stream *stream, int buffer_size) | ||
| 737 | { | ||
| 738 | struct sst_dsp *sst = byt->dsp; | ||
| 739 | struct sst_byt_tstamp fw_tstamp; | ||
| 740 | u8 str_id = stream->str_id; | ||
| 741 | u32 tstamp_offset; | ||
| 742 | |||
| 743 | tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp); | ||
| 744 | memcpy_fromio(&fw_tstamp, | ||
| 745 | sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp)); | ||
| 746 | |||
| 747 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); | ||
| 748 | } | ||
| 749 | |||
| 750 | static int msg_empty_list_init(struct sst_byt *byt) | ||
| 751 | { | ||
| 752 | struct ipc_message *msg; | ||
| 753 | int i; | ||
| 754 | |||
| 755 | byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
| 756 | if (byt->msg == NULL) | ||
| 757 | return -ENOMEM; | ||
| 758 | |||
| 759 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
| 760 | init_waitqueue_head(&byt->msg[i].waitq); | ||
| 761 | list_add(&byt->msg[i].list, &byt->empty_list); | ||
| 762 | } | ||
| 763 | |||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) | ||
| 768 | { | ||
| 769 | return byt->dsp; | ||
| 770 | } | ||
| 771 | |||
| 772 | static struct sst_dsp_device byt_dev = { | ||
| 773 | .thread = sst_byt_irq_thread, | ||
| 774 | .ops = &sst_byt_ops, | ||
| 775 | }; | ||
| 776 | |||
| 777 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | ||
| 778 | { | ||
| 779 | struct sst_byt *byt; | ||
| 780 | struct sst_fw *byt_sst_fw; | ||
| 781 | int err; | ||
| 782 | |||
| 783 | dev_dbg(dev, "initialising Byt DSP IPC\n"); | ||
| 784 | |||
| 785 | byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL); | ||
| 786 | if (byt == NULL) | ||
| 787 | return -ENOMEM; | ||
| 788 | |||
| 789 | byt->dev = dev; | ||
| 790 | INIT_LIST_HEAD(&byt->stream_list); | ||
| 791 | INIT_LIST_HEAD(&byt->tx_list); | ||
| 792 | INIT_LIST_HEAD(&byt->rx_list); | ||
| 793 | INIT_LIST_HEAD(&byt->empty_list); | ||
| 794 | init_waitqueue_head(&byt->boot_wait); | ||
| 795 | init_waitqueue_head(&byt->wait_txq); | ||
| 796 | |||
| 797 | err = msg_empty_list_init(byt); | ||
| 798 | if (err < 0) | ||
| 799 | return -ENOMEM; | ||
| 800 | |||
| 801 | /* start the IPC message thread */ | ||
| 802 | init_kthread_worker(&byt->kworker); | ||
| 803 | byt->tx_thread = kthread_run(kthread_worker_fn, | ||
| 804 | &byt->kworker, | ||
| 805 | dev_name(byt->dev)); | ||
| 806 | if (IS_ERR(byt->tx_thread)) { | ||
| 807 | err = PTR_ERR(byt->tx_thread); | ||
| 808 | dev_err(byt->dev, "error failed to create message TX task\n"); | ||
| 809 | goto err_free_msg; | ||
| 810 | } | ||
| 811 | init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs); | ||
| 812 | |||
| 813 | byt_dev.thread_context = byt; | ||
| 814 | |||
| 815 | /* init SST shim */ | ||
| 816 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); | ||
| 817 | if (byt->dsp == NULL) { | ||
| 818 | err = -ENODEV; | ||
| 819 | goto err_free_msg; | ||
| 820 | } | ||
| 821 | |||
| 822 | /* keep the DSP in reset state for base FW loading */ | ||
| 823 | sst_dsp_reset(byt->dsp); | ||
| 824 | |||
| 825 | byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt); | ||
| 826 | if (byt_sst_fw == NULL) { | ||
| 827 | err = -ENODEV; | ||
| 828 | dev_err(dev, "error: failed to load firmware\n"); | ||
| 829 | goto fw_err; | ||
| 830 | } | ||
| 831 | |||
| 832 | /* wait for DSP boot completion */ | ||
| 833 | sst_dsp_boot(byt->dsp); | ||
| 834 | err = wait_event_timeout(byt->boot_wait, byt->boot_complete, | ||
| 835 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
| 836 | if (err == 0) { | ||
| 837 | err = -EIO; | ||
| 838 | dev_err(byt->dev, "ipc: error DSP boot timeout\n"); | ||
| 839 | goto boot_err; | ||
| 840 | } | ||
| 841 | |||
| 842 | pdata->dsp = byt; | ||
| 843 | |||
| 844 | return 0; | ||
| 845 | |||
| 846 | boot_err: | ||
| 847 | sst_dsp_reset(byt->dsp); | ||
| 848 | sst_fw_free(byt_sst_fw); | ||
| 849 | fw_err: | ||
| 850 | sst_dsp_free(byt->dsp); | ||
| 851 | err_free_msg: | ||
| 852 | kfree(byt->msg); | ||
| 853 | |||
| 854 | return err; | ||
| 855 | } | ||
| 856 | EXPORT_SYMBOL_GPL(sst_byt_dsp_init); | ||
| 857 | |||
| 858 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) | ||
| 859 | { | ||
| 860 | struct sst_byt *byt = pdata->dsp; | ||
| 861 | |||
| 862 | sst_dsp_reset(byt->dsp); | ||
| 863 | sst_fw_free_all(byt->dsp); | ||
| 864 | sst_dsp_free(byt->dsp); | ||
| 865 | kfree(byt->msg); | ||
| 866 | } | ||
| 867 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h new file mode 100644 index 000000000000..f172b6440fa9 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-ipc.h | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 2 | * Intel Baytrail SST IPC Support | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #ifndef __SST_BYT_IPC_H | ||
| 16 | #define __SST_BYT_IPC_H | ||
| 17 | |||
| 18 | #include <linux/types.h> | ||
| 19 | |||
| 20 | struct sst_byt; | ||
| 21 | struct sst_byt_stream; | ||
| 22 | struct sst_pdata; | ||
| 23 | extern struct sst_ops sst_byt_ops; | ||
| 24 | |||
| 25 | |||
| 26 | #define SST_BYT_MAILBOX_OFFSET 0x144000 | ||
| 27 | #define SST_BYT_TIMESTAMP_OFFSET (SST_BYT_MAILBOX_OFFSET + 0x800) | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Upfront defined maximum message size that is | ||
| 31 | * expected by the in/out communication pipes in FW. | ||
| 32 | */ | ||
| 33 | #define SST_BYT_IPC_MAX_PAYLOAD_SIZE 200 | ||
| 34 | |||
| 35 | /* stream API */ | ||
| 36 | struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | ||
| 37 | uint32_t (*get_write_position)(struct sst_byt_stream *stream, | ||
| 38 | void *data), | ||
| 39 | void *data); | ||
| 40 | |||
| 41 | /* stream configuration */ | ||
| 42 | int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 43 | int bits); | ||
| 44 | int sst_byt_stream_set_channels(struct sst_byt *byt, | ||
| 45 | struct sst_byt_stream *stream, u8 channels); | ||
| 46 | int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 47 | unsigned int rate); | ||
| 48 | int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 49 | int codec_type, int stream_type, int operation); | ||
| 50 | int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
| 51 | uint32_t buffer_addr, uint32_t buffer_size); | ||
| 52 | int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 53 | int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 54 | |||
| 55 | /* stream ALSA trigger operations */ | ||
| 56 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 57 | int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 58 | int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 59 | int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
| 60 | |||
| 61 | int sst_byt_get_dsp_position(struct sst_byt *byt, | ||
| 62 | struct sst_byt_stream *stream, int buffer_size); | ||
| 63 | |||
| 64 | /* init */ | ||
| 65 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); | ||
| 66 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); | ||
| 67 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); | ||
| 68 | |||
| 69 | #endif | ||
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c new file mode 100644 index 000000000000..6d101f3813b4 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-pcm.c | |||
| @@ -0,0 +1,422 @@ | |||
| 1 | /* | ||
| 2 | * Intel Baytrail SST PCM Support | ||
| 3 | * Copyright (c) 2014, Intel Corporation. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms and conditions of the GNU General Public License, | ||
| 7 | * version 2, as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 12 | * more details. | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/dma-mapping.h> | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <sound/core.h> | ||
| 19 | #include <sound/pcm.h> | ||
| 20 | #include <sound/pcm_params.h> | ||
| 21 | #include <sound/soc.h> | ||
| 22 | #include "sst-baytrail-ipc.h" | ||
| 23 | #include "sst-dsp-priv.h" | ||
| 24 | #include "sst-dsp.h" | ||
| 25 | |||
| 26 | #define BYT_PCM_COUNT 2 | ||
| 27 | |||
| 28 | static const struct snd_pcm_hardware sst_byt_pcm_hardware = { | ||
| 29 | .info = SNDRV_PCM_INFO_MMAP | | ||
| 30 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 31 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 32 | SNDRV_PCM_INFO_PAUSE | | ||
| 33 | SNDRV_PCM_INFO_RESUME, | ||
| 34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
| 35 | SNDRV_PCM_FORMAT_S24_LE, | ||
| 36 | .period_bytes_min = 384, | ||
| 37 | .period_bytes_max = 48000, | ||
| 38 | .periods_min = 2, | ||
| 39 | .periods_max = 250, | ||
| 40 | .buffer_bytes_max = 96000, | ||
| 41 | }; | ||
| 42 | |||
| 43 | /* private data for each PCM DSP stream */ | ||
| 44 | struct sst_byt_pcm_data { | ||
| 45 | struct sst_byt_stream *stream; | ||
| 46 | struct snd_pcm_substream *substream; | ||
| 47 | struct mutex mutex; | ||
| 48 | }; | ||
| 49 | |||
| 50 | /* private data for the driver */ | ||
| 51 | struct sst_byt_priv_data { | ||
| 52 | /* runtime DSP */ | ||
| 53 | struct sst_byt *byt; | ||
| 54 | |||
| 55 | /* DAI data */ | ||
| 56 | struct sst_byt_pcm_data pcm[BYT_PCM_COUNT]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* this may get called several times by oss emulation */ | ||
| 60 | static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 61 | struct snd_pcm_hw_params *params) | ||
| 62 | { | ||
| 63 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 64 | struct sst_byt_priv_data *pdata = | ||
| 65 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 66 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 67 | struct sst_byt *byt = pdata->byt; | ||
| 68 | u32 rate, bits; | ||
| 69 | u8 channels; | ||
| 70 | int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
| 71 | |||
| 72 | dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data); | ||
| 73 | |||
| 74 | ret = sst_byt_stream_type(byt, pcm_data->stream, | ||
| 75 | 1, 1, !playback); | ||
| 76 | if (ret < 0) { | ||
| 77 | dev_err(rtd->dev, "failed to set stream format %d\n", ret); | ||
| 78 | return ret; | ||
| 79 | } | ||
| 80 | |||
| 81 | rate = params_rate(params); | ||
| 82 | ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate); | ||
| 83 | if (ret < 0) { | ||
| 84 | dev_err(rtd->dev, "could not set rate %d\n", rate); | ||
| 85 | return ret; | ||
| 86 | } | ||
| 87 | |||
| 88 | bits = snd_pcm_format_width(params_format(params)); | ||
| 89 | ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits); | ||
| 90 | if (ret < 0) { | ||
| 91 | dev_err(rtd->dev, "could not set formats %d\n", | ||
| 92 | params_rate(params)); | ||
| 93 | return ret; | ||
| 94 | } | ||
| 95 | |||
| 96 | channels = (u8)(params_channels(params) & 0xF); | ||
| 97 | ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels); | ||
| 98 | if (ret < 0) { | ||
| 99 | dev_err(rtd->dev, "could not set channels %d\n", | ||
| 100 | params_rate(params)); | ||
| 101 | return ret; | ||
| 102 | } | ||
| 103 | |||
| 104 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 105 | |||
| 106 | ret = sst_byt_stream_buffer(byt, pcm_data->stream, | ||
| 107 | substream->dma_buffer.addr, | ||
| 108 | params_buffer_bytes(params)); | ||
| 109 | if (ret < 0) { | ||
| 110 | dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret); | ||
| 111 | return ret; | ||
| 112 | } | ||
| 113 | |||
| 114 | ret = sst_byt_stream_commit(byt, pcm_data->stream); | ||
| 115 | if (ret < 0) { | ||
| 116 | dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret); | ||
| 117 | return ret; | ||
| 118 | } | ||
| 119 | |||
| 120 | return 0; | ||
| 121 | } | ||
| 122 | |||
| 123 | static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 124 | { | ||
| 125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 126 | |||
| 127 | dev_dbg(rtd->dev, "PCM: hw_free\n"); | ||
| 128 | snd_pcm_lib_free_pages(substream); | ||
| 129 | |||
| 130 | return 0; | ||
| 131 | } | ||
| 132 | |||
| 133 | static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 134 | { | ||
| 135 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 136 | struct sst_byt_priv_data *pdata = | ||
| 137 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 138 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 139 | struct sst_byt *byt = pdata->byt; | ||
| 140 | |||
| 141 | dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd); | ||
| 142 | |||
| 143 | switch (cmd) { | ||
| 144 | case SNDRV_PCM_TRIGGER_START: | ||
| 145 | sst_byt_stream_start(byt, pcm_data->stream); | ||
| 146 | break; | ||
| 147 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 148 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 149 | sst_byt_stream_resume(byt, pcm_data->stream); | ||
| 150 | break; | ||
| 151 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 152 | sst_byt_stream_stop(byt, pcm_data->stream); | ||
| 153 | break; | ||
| 154 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 155 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 156 | sst_byt_stream_pause(byt, pcm_data->stream); | ||
| 157 | break; | ||
| 158 | default: | ||
| 159 | break; | ||
| 160 | } | ||
| 161 | |||
| 162 | return 0; | ||
| 163 | } | ||
| 164 | |||
| 165 | static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data) | ||
| 166 | { | ||
| 167 | struct sst_byt_pcm_data *pcm_data = data; | ||
| 168 | struct snd_pcm_substream *substream = pcm_data->substream; | ||
| 169 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 170 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 171 | u32 pos; | ||
| 172 | |||
| 173 | pos = frames_to_bytes(runtime, | ||
| 174 | (runtime->control->appl_ptr % | ||
| 175 | runtime->buffer_size)); | ||
| 176 | |||
| 177 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | ||
| 178 | |||
| 179 | snd_pcm_period_elapsed(substream); | ||
| 180 | return pos; | ||
| 181 | } | ||
| 182 | |||
| 183 | static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 184 | { | ||
| 185 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 187 | struct sst_byt_priv_data *pdata = | ||
| 188 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 189 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 190 | struct sst_byt *byt = pdata->byt; | ||
| 191 | snd_pcm_uframes_t offset; | ||
| 192 | int pos; | ||
| 193 | |||
| 194 | pos = sst_byt_get_dsp_position(byt, pcm_data->stream, | ||
| 195 | snd_pcm_lib_buffer_bytes(substream)); | ||
| 196 | offset = bytes_to_frames(runtime, pos); | ||
| 197 | |||
| 198 | dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", | ||
| 199 | frames_to_bytes(runtime, (u32)offset)); | ||
| 200 | return offset; | ||
| 201 | } | ||
| 202 | |||
| 203 | static int sst_byt_pcm_open(struct snd_pcm_substream *substream) | ||
| 204 | { | ||
| 205 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 206 | struct sst_byt_priv_data *pdata = | ||
| 207 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 208 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 209 | struct sst_byt *byt = pdata->byt; | ||
| 210 | |||
| 211 | dev_dbg(rtd->dev, "PCM: open\n"); | ||
| 212 | |||
| 213 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | ||
| 214 | mutex_lock(&pcm_data->mutex); | ||
| 215 | |||
| 216 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | ||
| 217 | pcm_data->substream = substream; | ||
| 218 | |||
| 219 | snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware); | ||
| 220 | |||
| 221 | pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1, | ||
| 222 | byt_notify_pointer, pcm_data); | ||
| 223 | if (pcm_data->stream == NULL) { | ||
| 224 | dev_err(rtd->dev, "failed to create stream\n"); | ||
| 225 | mutex_unlock(&pcm_data->mutex); | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | |||
| 229 | mutex_unlock(&pcm_data->mutex); | ||
| 230 | return 0; | ||
| 231 | } | ||
| 232 | |||
| 233 | static int sst_byt_pcm_close(struct snd_pcm_substream *substream) | ||
| 234 | { | ||
| 235 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 236 | struct sst_byt_priv_data *pdata = | ||
| 237 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 238 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 239 | struct sst_byt *byt = pdata->byt; | ||
| 240 | int ret; | ||
| 241 | |||
| 242 | dev_dbg(rtd->dev, "PCM: close\n"); | ||
| 243 | |||
| 244 | mutex_lock(&pcm_data->mutex); | ||
| 245 | ret = sst_byt_stream_free(byt, pcm_data->stream); | ||
| 246 | if (ret < 0) { | ||
| 247 | dev_dbg(rtd->dev, "Free stream fail\n"); | ||
| 248 | goto out; | ||
| 249 | } | ||
| 250 | pcm_data->stream = NULL; | ||
| 251 | |||
| 252 | out: | ||
| 253 | mutex_unlock(&pcm_data->mutex); | ||
| 254 | return ret; | ||
| 255 | } | ||
| 256 | |||
| 257 | static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream, | ||
| 258 | struct vm_area_struct *vma) | ||
| 259 | { | ||
| 260 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 261 | |||
| 262 | dev_dbg(rtd->dev, "PCM: mmap\n"); | ||
| 263 | return snd_pcm_lib_default_mmap(substream, vma); | ||
| 264 | } | ||
| 265 | |||
| 266 | static struct snd_pcm_ops sst_byt_pcm_ops = { | ||
| 267 | .open = sst_byt_pcm_open, | ||
| 268 | .close = sst_byt_pcm_close, | ||
| 269 | .ioctl = snd_pcm_lib_ioctl, | ||
| 270 | .hw_params = sst_byt_pcm_hw_params, | ||
| 271 | .hw_free = sst_byt_pcm_hw_free, | ||
| 272 | .trigger = sst_byt_pcm_trigger, | ||
| 273 | .pointer = sst_byt_pcm_pointer, | ||
| 274 | .mmap = sst_byt_pcm_mmap, | ||
| 275 | }; | ||
| 276 | |||
| 277 | static void sst_byt_pcm_free(struct snd_pcm *pcm) | ||
| 278 | { | ||
| 279 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
| 280 | } | ||
| 281 | |||
| 282 | static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
| 283 | { | ||
| 284 | struct snd_pcm *pcm = rtd->pcm; | ||
| 285 | size_t size; | ||
| 286 | int ret = 0; | ||
| 287 | |||
| 288 | ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); | ||
| 289 | if (ret) | ||
| 290 | return ret; | ||
| 291 | |||
| 292 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | ||
| 293 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
| 294 | size = sst_byt_pcm_hardware.buffer_bytes_max; | ||
| 295 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
| 296 | SNDRV_DMA_TYPE_DEV, | ||
| 297 | rtd->card->dev, | ||
| 298 | size, size); | ||
| 299 | if (ret) { | ||
| 300 | dev_err(rtd->dev, "dma buffer allocation failed %d\n", | ||
| 301 | ret); | ||
| 302 | return ret; | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | return ret; | ||
| 307 | } | ||
| 308 | |||
| 309 | static struct snd_soc_dai_driver byt_dais[] = { | ||
| 310 | { | ||
| 311 | .name = "Front-cpu-dai", | ||
| 312 | .playback = { | ||
| 313 | .stream_name = "System Playback", | ||
| 314 | .channels_min = 2, | ||
| 315 | .channels_max = 2, | ||
| 316 | .rates = SNDRV_PCM_RATE_48000, | ||
| 317 | .formats = SNDRV_PCM_FMTBIT_S24_3LE | | ||
| 318 | SNDRV_PCM_FMTBIT_S16_LE, | ||
| 319 | }, | ||
| 320 | }, | ||
| 321 | { | ||
| 322 | .name = "Mic1-cpu-dai", | ||
| 323 | .capture = { | ||
| 324 | .stream_name = "Analog Capture", | ||
| 325 | .channels_min = 2, | ||
| 326 | .channels_max = 2, | ||
| 327 | .rates = SNDRV_PCM_RATE_48000, | ||
| 328 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 329 | }, | ||
| 330 | }, | ||
| 331 | }; | ||
| 332 | |||
| 333 | static int sst_byt_pcm_probe(struct snd_soc_platform *platform) | ||
| 334 | { | ||
| 335 | struct sst_pdata *plat_data = dev_get_platdata(platform->dev); | ||
| 336 | struct sst_byt_priv_data *priv_data; | ||
| 337 | int i; | ||
| 338 | |||
| 339 | if (!plat_data) | ||
| 340 | return -ENODEV; | ||
| 341 | |||
| 342 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), | ||
| 343 | GFP_KERNEL); | ||
| 344 | priv_data->byt = plat_data->dsp; | ||
| 345 | snd_soc_platform_set_drvdata(platform, priv_data); | ||
| 346 | |||
| 347 | for (i = 0; i < ARRAY_SIZE(byt_dais); i++) | ||
| 348 | mutex_init(&priv_data->pcm[i].mutex); | ||
| 349 | |||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int sst_byt_pcm_remove(struct snd_soc_platform *platform) | ||
| 354 | { | ||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | static struct snd_soc_platform_driver byt_soc_platform = { | ||
| 359 | .probe = sst_byt_pcm_probe, | ||
| 360 | .remove = sst_byt_pcm_remove, | ||
| 361 | .ops = &sst_byt_pcm_ops, | ||
| 362 | .pcm_new = sst_byt_pcm_new, | ||
| 363 | .pcm_free = sst_byt_pcm_free, | ||
| 364 | }; | ||
| 365 | |||
| 366 | static const struct snd_soc_component_driver byt_dai_component = { | ||
| 367 | .name = "byt-dai", | ||
| 368 | }; | ||
| 369 | |||
| 370 | static int sst_byt_pcm_dev_probe(struct platform_device *pdev) | ||
| 371 | { | ||
| 372 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
| 373 | int ret; | ||
| 374 | |||
| 375 | ret = sst_byt_dsp_init(&pdev->dev, sst_pdata); | ||
| 376 | if (ret < 0) | ||
| 377 | return -ENODEV; | ||
| 378 | |||
| 379 | ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform); | ||
| 380 | if (ret < 0) | ||
| 381 | goto err_plat; | ||
| 382 | |||
| 383 | ret = snd_soc_register_component(&pdev->dev, &byt_dai_component, | ||
| 384 | byt_dais, ARRAY_SIZE(byt_dais)); | ||
| 385 | if (ret < 0) | ||
| 386 | goto err_comp; | ||
| 387 | |||
| 388 | return 0; | ||
| 389 | |||
| 390 | err_comp: | ||
| 391 | snd_soc_unregister_platform(&pdev->dev); | ||
| 392 | err_plat: | ||
| 393 | sst_byt_dsp_free(&pdev->dev, sst_pdata); | ||
| 394 | return ret; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int sst_byt_pcm_dev_remove(struct platform_device *pdev) | ||
| 398 | { | ||
| 399 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
| 400 | |||
| 401 | snd_soc_unregister_platform(&pdev->dev); | ||
| 402 | snd_soc_unregister_component(&pdev->dev); | ||
| 403 | sst_byt_dsp_free(&pdev->dev, sst_pdata); | ||
| 404 | |||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | static struct platform_driver sst_byt_pcm_driver = { | ||
| 409 | .driver = { | ||
| 410 | .name = "baytrail-pcm-audio", | ||
| 411 | .owner = THIS_MODULE, | ||
| 412 | }, | ||
| 413 | |||
| 414 | .probe = sst_byt_pcm_dev_probe, | ||
| 415 | .remove = sst_byt_pcm_dev_remove, | ||
| 416 | }; | ||
| 417 | module_platform_driver(sst_byt_pcm_driver); | ||
| 418 | |||
| 419 | MODULE_AUTHOR("Jarkko Nikula"); | ||
| 420 | MODULE_DESCRIPTION("Baytrail PCM"); | ||
| 421 | MODULE_LICENSE("GPL v2"); | ||
| 422 | MODULE_ALIAS("platform:baytrail-pcm-audio"); | ||
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h new file mode 100644 index 000000000000..fe8e81aad646 --- /dev/null +++ b/sound/soc/intel/sst-dsp-priv.h | |||
| @@ -0,0 +1,309 @@ | |||
| 1 | /* | ||
| 2 | * Intel Smart Sound Technology | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __SOUND_SOC_SST_DSP_PRIV_H | ||
| 18 | #define __SOUND_SOC_SST_DSP_PRIV_H | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | #include <linux/firmware.h> | ||
| 24 | |||
| 25 | struct sst_mem_block; | ||
| 26 | struct sst_module; | ||
| 27 | struct sst_fw; | ||
| 28 | |||
| 29 | /* | ||
| 30 | * DSP Operations exported by platform Audio DSP driver. | ||
| 31 | */ | ||
| 32 | struct sst_ops { | ||
| 33 | /* DSP core boot / reset */ | ||
| 34 | void (*boot)(struct sst_dsp *); | ||
| 35 | void (*reset)(struct sst_dsp *); | ||
| 36 | |||
| 37 | /* Shim IO */ | ||
| 38 | void (*write)(void __iomem *addr, u32 offset, u32 value); | ||
| 39 | u32 (*read)(void __iomem *addr, u32 offset); | ||
| 40 | void (*write64)(void __iomem *addr, u32 offset, u64 value); | ||
| 41 | u64 (*read64)(void __iomem *addr, u32 offset); | ||
| 42 | |||
| 43 | /* DSP I/DRAM IO */ | ||
| 44 | void (*ram_read)(struct sst_dsp *sst, void *dest, void __iomem *src, | ||
| 45 | size_t bytes); | ||
| 46 | void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src, | ||
| 47 | size_t bytes); | ||
| 48 | |||
| 49 | void (*dump)(struct sst_dsp *); | ||
| 50 | |||
| 51 | /* IRQ handlers */ | ||
| 52 | irqreturn_t (*irq_handler)(int irq, void *context); | ||
| 53 | |||
| 54 | /* SST init and free */ | ||
| 55 | int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata); | ||
| 56 | void (*free)(struct sst_dsp *sst); | ||
| 57 | |||
| 58 | /* FW module parser/loader */ | ||
| 59 | int (*parse_fw)(struct sst_fw *sst_fw); | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Audio DSP memory offsets and addresses. | ||
| 64 | */ | ||
| 65 | struct sst_addr { | ||
| 66 | u32 lpe_base; | ||
| 67 | u32 shim_offset; | ||
| 68 | u32 iram_offset; | ||
| 69 | u32 dram_offset; | ||
| 70 | void __iomem *lpe; | ||
| 71 | void __iomem *shim; | ||
| 72 | void __iomem *pci_cfg; | ||
| 73 | void __iomem *fw_ext; | ||
| 74 | }; | ||
| 75 | |||
| 76 | /* | ||
| 77 | * Audio DSP Mailbox configuration. | ||
| 78 | */ | ||
| 79 | struct sst_mailbox { | ||
| 80 | void __iomem *in_base; | ||
| 81 | void __iomem *out_base; | ||
| 82 | size_t in_size; | ||
| 83 | size_t out_size; | ||
| 84 | }; | ||
| 85 | |||
| 86 | /* | ||
| 87 | * Audio DSP Firmware data types. | ||
| 88 | */ | ||
| 89 | enum sst_data_type { | ||
| 90 | SST_DATA_M = 0, /* module block data */ | ||
| 91 | SST_DATA_P = 1, /* peristant data (text, data) */ | ||
| 92 | SST_DATA_S = 2, /* scratch data (usually buffers) */ | ||
| 93 | }; | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Audio DSP memory block types. | ||
| 97 | */ | ||
| 98 | enum sst_mem_type { | ||
| 99 | SST_MEM_IRAM = 0, | ||
| 100 | SST_MEM_DRAM = 1, | ||
| 101 | SST_MEM_ANY = 2, | ||
| 102 | SST_MEM_CACHE= 3, | ||
| 103 | }; | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Audio DSP Generic Firmware File. | ||
| 107 | * | ||
| 108 | * SST Firmware files can consist of 1..N modules. This generic structure is | ||
| 109 | * used to manage each firmware file and it's modules regardless of SST firmware | ||
| 110 | * type. A SST driver may load multiple FW files. | ||
| 111 | */ | ||
| 112 | struct sst_fw { | ||
| 113 | struct sst_dsp *dsp; | ||
| 114 | |||
| 115 | /* base addresses of FW file data */ | ||
| 116 | dma_addr_t dmable_fw_paddr; /* physical address of fw data */ | ||
| 117 | void *dma_buf; /* virtual address of fw data */ | ||
| 118 | u32 size; /* size of fw data */ | ||
| 119 | |||
| 120 | /* lists */ | ||
| 121 | struct list_head list; /* DSP list of FW */ | ||
| 122 | struct list_head module_list; /* FW list of modules */ | ||
| 123 | |||
| 124 | void *private; /* core doesn't touch this */ | ||
| 125 | }; | ||
| 126 | |||
| 127 | /* | ||
| 128 | * Audio DSP Generic Module data. | ||
| 129 | * | ||
| 130 | * This is used to dsecribe any sections of persistent (text and data) and | ||
| 131 | * scratch (buffers) of module data in ADSP memory space. | ||
| 132 | */ | ||
| 133 | struct sst_module_data { | ||
| 134 | |||
| 135 | enum sst_mem_type type; /* destination memory type */ | ||
| 136 | enum sst_data_type data_type; /* type of module data */ | ||
| 137 | |||
| 138 | u32 size; /* size in bytes */ | ||
| 139 | u32 offset; /* offset in FW file */ | ||
| 140 | u32 data_offset; /* offset in ADSP memory space */ | ||
| 141 | void *data; /* module data */ | ||
| 142 | }; | ||
| 143 | |||
| 144 | /* | ||
| 145 | * Audio DSP Generic Module Template. | ||
| 146 | * | ||
| 147 | * Used to define and register a new FW module. This data is extracted from | ||
| 148 | * FW module header information. | ||
| 149 | */ | ||
| 150 | struct sst_module_template { | ||
| 151 | u32 id; | ||
| 152 | u32 entry; /* entry point */ | ||
| 153 | struct sst_module_data s; /* scratch data */ | ||
| 154 | struct sst_module_data p; /* peristant data */ | ||
| 155 | }; | ||
| 156 | |||
| 157 | /* | ||
| 158 | * Audio DSP Generic Module. | ||
| 159 | * | ||
| 160 | * Each Firmware file can consist of 1..N modules. A module can span multiple | ||
| 161 | * ADSP memory blocks. The simplest FW will be a file with 1 module. | ||
| 162 | */ | ||
| 163 | struct sst_module { | ||
| 164 | struct sst_dsp *dsp; | ||
| 165 | struct sst_fw *sst_fw; /* parent FW we belong too */ | ||
| 166 | |||
| 167 | /* module configuration */ | ||
| 168 | u32 id; | ||
| 169 | u32 entry; /* module entry point */ | ||
| 170 | u32 offset; /* module offset in firmware file */ | ||
| 171 | u32 size; /* module size */ | ||
| 172 | struct sst_module_data s; /* scratch data */ | ||
| 173 | struct sst_module_data p; /* peristant data */ | ||
| 174 | |||
| 175 | /* runtime */ | ||
| 176 | u32 usage_count; /* can be unloaded if count == 0 */ | ||
| 177 | void *private; /* core doesn't touch this */ | ||
| 178 | |||
| 179 | /* lists */ | ||
| 180 | struct list_head block_list; /* Module list of blocks in use */ | ||
| 181 | struct list_head list; /* DSP list of modules */ | ||
| 182 | struct list_head list_fw; /* FW list of modules */ | ||
| 183 | }; | ||
| 184 | |||
| 185 | /* | ||
| 186 | * SST Memory Block operations. | ||
| 187 | */ | ||
| 188 | struct sst_block_ops { | ||
| 189 | int (*enable)(struct sst_mem_block *block); | ||
| 190 | int (*disable)(struct sst_mem_block *block); | ||
| 191 | }; | ||
| 192 | |||
| 193 | /* | ||
| 194 | * SST Generic Memory Block. | ||
| 195 | * | ||
| 196 | * SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be | ||
| 197 | * power gated. | ||
| 198 | */ | ||
| 199 | struct sst_mem_block { | ||
| 200 | struct sst_dsp *dsp; | ||
| 201 | struct sst_module *module; /* module that uses this block */ | ||
| 202 | |||
| 203 | /* block config */ | ||
| 204 | u32 offset; /* offset from base */ | ||
| 205 | u32 size; /* block size */ | ||
| 206 | u32 index; /* block index 0..N */ | ||
| 207 | enum sst_mem_type type; /* block memory type IRAM/DRAM */ | ||
| 208 | struct sst_block_ops *ops; /* block operations, if any */ | ||
| 209 | |||
| 210 | /* block status */ | ||
| 211 | enum sst_data_type data_type; /* data type held in this block */ | ||
| 212 | u32 bytes_used; /* bytes in use by modules */ | ||
| 213 | void *private; /* generic core does not touch this */ | ||
| 214 | int users; /* number of modules using this block */ | ||
| 215 | |||
| 216 | /* block lists */ | ||
| 217 | struct list_head module_list; /* Module list of blocks */ | ||
| 218 | struct list_head list; /* Map list of free/used blocks */ | ||
| 219 | }; | ||
| 220 | |||
| 221 | /* | ||
| 222 | * Generic SST Shim Interface. | ||
| 223 | */ | ||
| 224 | struct sst_dsp { | ||
| 225 | |||
| 226 | /* runtime */ | ||
| 227 | struct sst_dsp_device *sst_dev; | ||
| 228 | spinlock_t spinlock; /* IPC locking */ | ||
| 229 | struct mutex mutex; /* DSP FW lock */ | ||
| 230 | struct device *dev; | ||
| 231 | void *thread_context; | ||
| 232 | int irq; | ||
| 233 | u32 id; | ||
| 234 | |||
| 235 | /* list of free and used ADSP memory blocks */ | ||
| 236 | struct list_head used_block_list; | ||
| 237 | struct list_head free_block_list; | ||
| 238 | |||
| 239 | /* operations */ | ||
| 240 | struct sst_ops *ops; | ||
| 241 | |||
| 242 | /* debug FS */ | ||
| 243 | struct dentry *debugfs_root; | ||
| 244 | |||
| 245 | /* base addresses */ | ||
| 246 | struct sst_addr addr; | ||
| 247 | |||
| 248 | /* mailbox */ | ||
| 249 | struct sst_mailbox mailbox; | ||
| 250 | |||
| 251 | /* SST FW files loaded and their modules */ | ||
| 252 | struct list_head module_list; | ||
| 253 | struct list_head fw_list; | ||
| 254 | |||
| 255 | /* platform data */ | ||
| 256 | struct sst_pdata *pdata; | ||
| 257 | |||
| 258 | /* DMA FW loading */ | ||
| 259 | struct sst_dma *dma; | ||
| 260 | bool fw_use_dma; | ||
| 261 | }; | ||
| 262 | |||
| 263 | /* Size optimised DRAM/IRAM memcpy */ | ||
| 264 | static inline void sst_dsp_write(struct sst_dsp *sst, void *src, | ||
| 265 | u32 dest_offset, size_t bytes) | ||
| 266 | { | ||
| 267 | sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes); | ||
| 268 | } | ||
| 269 | |||
| 270 | static inline void sst_dsp_read(struct sst_dsp *sst, void *dest, | ||
| 271 | u32 src_offset, size_t bytes) | ||
| 272 | { | ||
| 273 | sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes); | ||
| 274 | } | ||
| 275 | |||
| 276 | static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst) | ||
| 277 | { | ||
| 278 | return sst->thread_context; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* Create/Free FW files - can contain multiple modules */ | ||
| 282 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | ||
| 283 | const struct firmware *fw, void *private); | ||
| 284 | void sst_fw_free(struct sst_fw *sst_fw); | ||
| 285 | void sst_fw_free_all(struct sst_dsp *dsp); | ||
| 286 | |||
| 287 | /* Create/Free firmware modules */ | ||
| 288 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | ||
| 289 | struct sst_module_template *template, void *private); | ||
| 290 | void sst_module_free(struct sst_module *sst_module); | ||
| 291 | int sst_module_insert(struct sst_module *sst_module); | ||
| 292 | int sst_module_remove(struct sst_module *sst_module); | ||
| 293 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
| 294 | struct sst_module_data *data); | ||
| 295 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); | ||
| 296 | |||
| 297 | /* allocate/free pesistent/scratch memory regions managed by drv */ | ||
| 298 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp); | ||
| 299 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | ||
| 300 | struct sst_module *scratch); | ||
| 301 | int sst_block_module_remove(struct sst_module *module); | ||
| 302 | |||
| 303 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ | ||
| 304 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | ||
| 305 | u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, | ||
| 306 | void *private); | ||
| 307 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); | ||
| 308 | |||
| 309 | #endif | ||
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c new file mode 100644 index 000000000000..0c129fd85ecf --- /dev/null +++ b/sound/soc/intel/sst-dsp.c | |||
| @@ -0,0 +1,385 @@ | |||
| 1 | /* | ||
| 2 | * Intel Smart Sound Technology (SST) DSP Core Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/export.h> | ||
| 19 | #include <linux/interrupt.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #include "sst-dsp.h" | ||
| 25 | #include "sst-dsp-priv.h" | ||
| 26 | |||
| 27 | #define CREATE_TRACE_POINTS | ||
| 28 | #include <trace/events/intel-sst.h> | ||
| 29 | |||
| 30 | /* Internal generic low-level SST IO functions - can be overidden */ | ||
| 31 | void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) | ||
| 32 | { | ||
| 33 | writel(value, addr + offset); | ||
| 34 | } | ||
| 35 | EXPORT_SYMBOL_GPL(sst_shim32_write); | ||
| 36 | |||
| 37 | u32 sst_shim32_read(void __iomem *addr, u32 offset) | ||
| 38 | { | ||
| 39 | return readl(addr + offset); | ||
| 40 | } | ||
| 41 | EXPORT_SYMBOL_GPL(sst_shim32_read); | ||
| 42 | |||
| 43 | void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) | ||
| 44 | { | ||
| 45 | memcpy_toio(addr + offset, &value, sizeof(value)); | ||
| 46 | } | ||
| 47 | EXPORT_SYMBOL_GPL(sst_shim32_write64); | ||
| 48 | |||
| 49 | u64 sst_shim32_read64(void __iomem *addr, u32 offset) | ||
| 50 | { | ||
| 51 | u64 val; | ||
| 52 | |||
| 53 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
| 54 | return val; | ||
| 55 | } | ||
| 56 | EXPORT_SYMBOL_GPL(sst_shim32_read64); | ||
| 57 | |||
| 58 | static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest, | ||
| 59 | u32 *src, size_t bytes) | ||
| 60 | { | ||
| 61 | int i, words = bytes >> 2; | ||
| 62 | |||
| 63 | for (i = 0; i < words; i++) | ||
| 64 | writel(src[i], dest + i); | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline void _sst_memcpy_fromio_32(u32 *dest, | ||
| 68 | const volatile __iomem u32 *src, size_t bytes) | ||
| 69 | { | ||
| 70 | int i, words = bytes >> 2; | ||
| 71 | |||
| 72 | for (i = 0; i < words; i++) | ||
| 73 | dest[i] = readl(src + i); | ||
| 74 | } | ||
| 75 | |||
| 76 | void sst_memcpy_toio_32(struct sst_dsp *sst, | ||
| 77 | void __iomem *dest, void *src, size_t bytes) | ||
| 78 | { | ||
| 79 | _sst_memcpy_toio_32(dest, src, bytes); | ||
| 80 | } | ||
| 81 | EXPORT_SYMBOL_GPL(sst_memcpy_toio_32); | ||
| 82 | |||
| 83 | void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest, | ||
| 84 | void __iomem *src, size_t bytes) | ||
| 85 | { | ||
| 86 | _sst_memcpy_fromio_32(dest, src, bytes); | ||
| 87 | } | ||
| 88 | EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32); | ||
| 89 | |||
| 90 | /* Public API */ | ||
| 91 | void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) | ||
| 92 | { | ||
| 93 | unsigned long flags; | ||
| 94 | |||
| 95 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 96 | sst->ops->write(sst->addr.shim, offset, value); | ||
| 97 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 98 | } | ||
| 99 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write); | ||
| 100 | |||
| 101 | u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) | ||
| 102 | { | ||
| 103 | unsigned long flags; | ||
| 104 | u32 val; | ||
| 105 | |||
| 106 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 107 | val = sst->ops->read(sst->addr.shim, offset); | ||
| 108 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 109 | |||
| 110 | return val; | ||
| 111 | } | ||
| 112 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read); | ||
| 113 | |||
| 114 | void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value) | ||
| 115 | { | ||
| 116 | unsigned long flags; | ||
| 117 | |||
| 118 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 119 | sst->ops->write64(sst->addr.shim, offset, value); | ||
| 120 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 121 | } | ||
| 122 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write64); | ||
| 123 | |||
| 124 | u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset) | ||
| 125 | { | ||
| 126 | unsigned long flags; | ||
| 127 | u64 val; | ||
| 128 | |||
| 129 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 130 | val = sst->ops->read64(sst->addr.shim, offset); | ||
| 131 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 132 | |||
| 133 | return val; | ||
| 134 | } | ||
| 135 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read64); | ||
| 136 | |||
| 137 | void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) | ||
| 138 | { | ||
| 139 | sst->ops->write(sst->addr.shim, offset, value); | ||
| 140 | } | ||
| 141 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); | ||
| 142 | |||
| 143 | u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) | ||
| 144 | { | ||
| 145 | return sst->ops->read(sst->addr.shim, offset); | ||
| 146 | } | ||
| 147 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); | ||
| 148 | |||
| 149 | void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value) | ||
| 150 | { | ||
| 151 | sst->ops->write64(sst->addr.shim, offset, value); | ||
| 152 | } | ||
| 153 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked); | ||
| 154 | |||
| 155 | u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset) | ||
| 156 | { | ||
| 157 | return sst->ops->read64(sst->addr.shim, offset); | ||
| 158 | } | ||
| 159 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked); | ||
| 160 | |||
| 161 | int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, | ||
| 162 | u32 mask, u32 value) | ||
| 163 | { | ||
| 164 | bool change; | ||
| 165 | unsigned int old, new; | ||
| 166 | u32 ret; | ||
| 167 | |||
| 168 | ret = sst_dsp_shim_read_unlocked(sst, offset); | ||
| 169 | |||
| 170 | old = ret; | ||
| 171 | new = (old & (~mask)) | (value & mask); | ||
| 172 | |||
| 173 | change = (old != new); | ||
| 174 | if (change) | ||
| 175 | sst_dsp_shim_write_unlocked(sst, offset, new); | ||
| 176 | |||
| 177 | return change; | ||
| 178 | } | ||
| 179 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); | ||
| 180 | |||
| 181 | int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, | ||
| 182 | u64 mask, u64 value) | ||
| 183 | { | ||
| 184 | bool change; | ||
| 185 | u64 old, new; | ||
| 186 | |||
| 187 | old = sst_dsp_shim_read64_unlocked(sst, offset); | ||
| 188 | |||
| 189 | new = (old & (~mask)) | (value & mask); | ||
| 190 | |||
| 191 | change = (old != new); | ||
| 192 | if (change) | ||
| 193 | sst_dsp_shim_write64_unlocked(sst, offset, new); | ||
| 194 | |||
| 195 | return change; | ||
| 196 | } | ||
| 197 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked); | ||
| 198 | |||
| 199 | int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, | ||
| 200 | u32 mask, u32 value) | ||
| 201 | { | ||
| 202 | unsigned long flags; | ||
| 203 | bool change; | ||
| 204 | |||
| 205 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 206 | change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); | ||
| 207 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 208 | return change; | ||
| 209 | } | ||
| 210 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); | ||
| 211 | |||
| 212 | int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, | ||
| 213 | u64 mask, u64 value) | ||
| 214 | { | ||
| 215 | unsigned long flags; | ||
| 216 | bool change; | ||
| 217 | |||
| 218 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 219 | change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value); | ||
| 220 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 221 | return change; | ||
| 222 | } | ||
| 223 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); | ||
| 224 | |||
| 225 | void sst_dsp_dump(struct sst_dsp *sst) | ||
| 226 | { | ||
| 227 | sst->ops->dump(sst); | ||
| 228 | } | ||
| 229 | EXPORT_SYMBOL_GPL(sst_dsp_dump); | ||
| 230 | |||
| 231 | void sst_dsp_reset(struct sst_dsp *sst) | ||
| 232 | { | ||
| 233 | sst->ops->reset(sst); | ||
| 234 | } | ||
| 235 | EXPORT_SYMBOL_GPL(sst_dsp_reset); | ||
| 236 | |||
| 237 | int sst_dsp_boot(struct sst_dsp *sst) | ||
| 238 | { | ||
| 239 | sst->ops->boot(sst); | ||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | ||
| 243 | |||
| 244 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) | ||
| 245 | { | ||
| 246 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); | ||
| 247 | trace_sst_ipc_msg_tx(msg); | ||
| 248 | } | ||
| 249 | EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx); | ||
| 250 | |||
| 251 | u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp) | ||
| 252 | { | ||
| 253 | u32 msg; | ||
| 254 | |||
| 255 | msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); | ||
| 256 | trace_sst_ipc_msg_rx(msg); | ||
| 257 | |||
| 258 | return msg; | ||
| 259 | } | ||
| 260 | EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx); | ||
| 261 | |||
| 262 | int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, | ||
| 263 | u32 outbox_offset, size_t outbox_size) | ||
| 264 | { | ||
| 265 | sst->mailbox.in_base = sst->addr.lpe + inbox_offset; | ||
| 266 | sst->mailbox.out_base = sst->addr.lpe + outbox_offset; | ||
| 267 | sst->mailbox.in_size = inbox_size; | ||
| 268 | sst->mailbox.out_size = outbox_size; | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); | ||
| 272 | |||
| 273 | void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) | ||
| 274 | { | ||
| 275 | u32 i; | ||
| 276 | |||
| 277 | trace_sst_ipc_outbox_write(bytes); | ||
| 278 | |||
| 279 | memcpy_toio(sst->mailbox.out_base, message, bytes); | ||
| 280 | |||
| 281 | for (i = 0; i < bytes; i += 4) | ||
| 282 | trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); | ||
| 283 | } | ||
| 284 | EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); | ||
| 285 | |||
| 286 | void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) | ||
| 287 | { | ||
| 288 | u32 i; | ||
| 289 | |||
| 290 | trace_sst_ipc_outbox_read(bytes); | ||
| 291 | |||
| 292 | memcpy_fromio(message, sst->mailbox.out_base, bytes); | ||
| 293 | |||
| 294 | for (i = 0; i < bytes; i += 4) | ||
| 295 | trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); | ||
| 296 | } | ||
| 297 | EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); | ||
| 298 | |||
| 299 | void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) | ||
| 300 | { | ||
| 301 | u32 i; | ||
| 302 | |||
| 303 | trace_sst_ipc_inbox_write(bytes); | ||
| 304 | |||
| 305 | memcpy_toio(sst->mailbox.in_base, message, bytes); | ||
| 306 | |||
| 307 | for (i = 0; i < bytes; i += 4) | ||
| 308 | trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); | ||
| 309 | } | ||
| 310 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); | ||
| 311 | |||
| 312 | void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) | ||
| 313 | { | ||
| 314 | u32 i; | ||
| 315 | |||
| 316 | trace_sst_ipc_inbox_read(bytes); | ||
| 317 | |||
| 318 | memcpy_fromio(message, sst->mailbox.in_base, bytes); | ||
| 319 | |||
| 320 | for (i = 0; i < bytes; i += 4) | ||
| 321 | trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); | ||
| 322 | } | ||
| 323 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); | ||
| 324 | |||
| 325 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
| 326 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) | ||
| 327 | { | ||
| 328 | struct sst_dsp *sst; | ||
| 329 | int err; | ||
| 330 | |||
| 331 | dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id); | ||
| 332 | |||
| 333 | sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); | ||
| 334 | if (sst == NULL) | ||
| 335 | return NULL; | ||
| 336 | |||
| 337 | spin_lock_init(&sst->spinlock); | ||
| 338 | mutex_init(&sst->mutex); | ||
| 339 | sst->dev = dev; | ||
| 340 | sst->thread_context = sst_dev->thread_context; | ||
| 341 | sst->sst_dev = sst_dev; | ||
| 342 | sst->id = pdata->id; | ||
| 343 | sst->irq = pdata->irq; | ||
| 344 | sst->ops = sst_dev->ops; | ||
| 345 | sst->pdata = pdata; | ||
| 346 | INIT_LIST_HEAD(&sst->used_block_list); | ||
| 347 | INIT_LIST_HEAD(&sst->free_block_list); | ||
| 348 | INIT_LIST_HEAD(&sst->module_list); | ||
| 349 | INIT_LIST_HEAD(&sst->fw_list); | ||
| 350 | |||
| 351 | /* Initialise SST Audio DSP */ | ||
| 352 | if (sst->ops->init) { | ||
| 353 | err = sst->ops->init(sst, pdata); | ||
| 354 | if (err < 0) | ||
| 355 | return NULL; | ||
| 356 | } | ||
| 357 | |||
| 358 | /* Register the ISR */ | ||
| 359 | err = request_threaded_irq(sst->irq, sst->ops->irq_handler, | ||
| 360 | sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); | ||
| 361 | if (err) | ||
| 362 | goto irq_err; | ||
| 363 | |||
| 364 | return sst; | ||
| 365 | |||
| 366 | irq_err: | ||
| 367 | if (sst->ops->free) | ||
| 368 | sst->ops->free(sst); | ||
| 369 | |||
| 370 | return NULL; | ||
| 371 | } | ||
| 372 | EXPORT_SYMBOL_GPL(sst_dsp_new); | ||
| 373 | |||
| 374 | void sst_dsp_free(struct sst_dsp *sst) | ||
| 375 | { | ||
| 376 | free_irq(sst->irq, sst); | ||
| 377 | if (sst->ops->free) | ||
| 378 | sst->ops->free(sst); | ||
| 379 | } | ||
| 380 | EXPORT_SYMBOL_GPL(sst_dsp_free); | ||
| 381 | |||
| 382 | /* Module information */ | ||
| 383 | MODULE_AUTHOR("Liam Girdwood"); | ||
| 384 | MODULE_DESCRIPTION("Intel SST Core"); | ||
| 385 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h new file mode 100644 index 000000000000..74052b59485c --- /dev/null +++ b/sound/soc/intel/sst-dsp.h | |||
| @@ -0,0 +1,233 @@ | |||
| 1 | /* | ||
| 2 | * Intel Smart Sound Technology (SST) Core | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __SOUND_SOC_SST_DSP_H | ||
| 18 | #define __SOUND_SOC_SST_DSP_H | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/types.h> | ||
| 22 | #include <linux/interrupt.h> | ||
| 23 | |||
| 24 | /* SST Device IDs */ | ||
| 25 | #define SST_DEV_ID_LYNX_POINT 0x33C8 | ||
| 26 | #define SST_DEV_ID_WILDCAT_POINT 0x3438 | ||
| 27 | #define SST_DEV_ID_BYT 0x0F28 | ||
| 28 | |||
| 29 | /* Supported SST DMA Devices */ | ||
| 30 | #define SST_DMA_TYPE_DW 1 | ||
| 31 | #define SST_DMA_TYPE_MID 2 | ||
| 32 | |||
| 33 | /* SST Shim register map | ||
| 34 | * The register naming can differ between products. Some products also | ||
| 35 | * contain extra functionality. | ||
| 36 | */ | ||
| 37 | #define SST_CSR 0x00 | ||
| 38 | #define SST_PISR 0x08 | ||
| 39 | #define SST_PIMR 0x10 | ||
| 40 | #define SST_ISRX 0x18 | ||
| 41 | #define SST_ISRD 0x20 | ||
| 42 | #define SST_IMRX 0x28 | ||
| 43 | #define SST_IMRD 0x30 | ||
| 44 | #define SST_IPCX 0x38 /* IPC IA -> SST */ | ||
| 45 | #define SST_IPCD 0x40 /* IPC SST -> IA */ | ||
| 46 | #define SST_ISRSC 0x48 | ||
| 47 | #define SST_ISRLPESC 0x50 | ||
| 48 | #define SST_IMRSC 0x58 | ||
| 49 | #define SST_IMRLPESC 0x60 | ||
| 50 | #define SST_IPCSC 0x68 | ||
| 51 | #define SST_IPCLPESC 0x70 | ||
| 52 | #define SST_CLKCTL 0x78 | ||
| 53 | #define SST_CSR2 0x80 | ||
| 54 | #define SST_LTRC 0xE0 | ||
| 55 | #define SST_HDMC 0xE8 | ||
| 56 | #define SST_DBGO 0xF0 | ||
| 57 | |||
| 58 | #define SST_SHIM_SIZE 0x100 | ||
| 59 | #define SST_PWMCTRL 0x1000 | ||
| 60 | |||
| 61 | /* SST Shim Register bits | ||
| 62 | * The register bit naming can differ between products. Some products also | ||
| 63 | * contain extra functionality. | ||
| 64 | */ | ||
| 65 | |||
| 66 | /* CSR / CS */ | ||
| 67 | #define SST_CSR_RST (0x1 << 1) | ||
| 68 | #define SST_CSR_SBCS0 (0x1 << 2) | ||
| 69 | #define SST_CSR_SBCS1 (0x1 << 3) | ||
| 70 | #define SST_CSR_DCS(x) (x << 4) | ||
| 71 | #define SST_CSR_DCS_MASK (0x7 << 4) | ||
| 72 | #define SST_CSR_STALL (0x1 << 10) | ||
| 73 | #define SST_CSR_S0IOCS (0x1 << 21) | ||
| 74 | #define SST_CSR_S1IOCS (0x1 << 23) | ||
| 75 | #define SST_CSR_LPCS (0x1 << 31) | ||
| 76 | #define SST_BYT_CSR_RST (0x1 << 0) | ||
| 77 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) | ||
| 78 | #define SST_BYT_CSR_STALL (0x1 << 2) | ||
| 79 | #define SST_BYT_CSR_PWAITMODE (0x1 << 3) | ||
| 80 | |||
| 81 | /* ISRX / ISC */ | ||
| 82 | #define SST_ISRX_BUSY (0x1 << 1) | ||
| 83 | #define SST_ISRX_DONE (0x1 << 0) | ||
| 84 | #define SST_BYT_ISRX_REQUEST (0x1 << 1) | ||
| 85 | |||
| 86 | /* ISRD / ISD */ | ||
| 87 | #define SST_ISRD_BUSY (0x1 << 1) | ||
| 88 | #define SST_ISRD_DONE (0x1 << 0) | ||
| 89 | |||
| 90 | /* IMRX / IMC */ | ||
| 91 | #define SST_IMRX_BUSY (0x1 << 1) | ||
| 92 | #define SST_IMRX_DONE (0x1 << 0) | ||
| 93 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) | ||
| 94 | |||
| 95 | /* IPCX / IPCC */ | ||
| 96 | #define SST_IPCX_DONE (0x1 << 30) | ||
| 97 | #define SST_IPCX_BUSY (0x1 << 31) | ||
| 98 | #define SST_BYT_IPCX_DONE ((u64)0x1 << 62) | ||
| 99 | #define SST_BYT_IPCX_BUSY ((u64)0x1 << 63) | ||
| 100 | |||
| 101 | /* IPCD */ | ||
| 102 | #define SST_IPCD_DONE (0x1 << 30) | ||
| 103 | #define SST_IPCD_BUSY (0x1 << 31) | ||
| 104 | #define SST_BYT_IPCD_DONE ((u64)0x1 << 62) | ||
| 105 | #define SST_BYT_IPCD_BUSY ((u64)0x1 << 63) | ||
| 106 | |||
| 107 | /* CLKCTL */ | ||
| 108 | #define SST_CLKCTL_SMOS(x) (x << 24) | ||
| 109 | #define SST_CLKCTL_MASK (3 << 24) | ||
| 110 | #define SST_CLKCTL_DCPLCG (1 << 18) | ||
| 111 | #define SST_CLKCTL_SCOE1 (1 << 17) | ||
| 112 | #define SST_CLKCTL_SCOE0 (1 << 16) | ||
| 113 | |||
| 114 | /* CSR2 / CS2 */ | ||
| 115 | #define SST_CSR2_SDFD_SSP0 (1 << 1) | ||
| 116 | #define SST_CSR2_SDFD_SSP1 (1 << 2) | ||
| 117 | |||
| 118 | /* LTRC */ | ||
| 119 | #define SST_LTRC_VAL(x) (x << 0) | ||
| 120 | |||
| 121 | /* HDMC */ | ||
| 122 | #define SST_HDMC_HDDA0(x) (x << 0) | ||
| 123 | #define SST_HDMC_HDDA1(x) (x << 7) | ||
| 124 | |||
| 125 | |||
| 126 | /* SST Vendor Defined Registers and bits */ | ||
| 127 | #define SST_VDRTCTL0 0xa0 | ||
| 128 | #define SST_VDRTCTL1 0xa4 | ||
| 129 | #define SST_VDRTCTL2 0xa8 | ||
| 130 | #define SST_VDRTCTL3 0xaC | ||
| 131 | |||
| 132 | /* VDRTCTL0 */ | ||
| 133 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | ||
| 134 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | ||
| 135 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | ||
| 136 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | ||
| 137 | |||
| 138 | struct sst_dsp; | ||
| 139 | |||
| 140 | /* | ||
| 141 | * SST Device. | ||
| 142 | * | ||
| 143 | * This structure is populated by the SST core driver. | ||
| 144 | */ | ||
| 145 | struct sst_dsp_device { | ||
| 146 | /* Mandatory fields */ | ||
| 147 | struct sst_ops *ops; | ||
| 148 | irqreturn_t (*thread)(int irq, void *context); | ||
| 149 | void *thread_context; | ||
| 150 | }; | ||
| 151 | |||
| 152 | /* | ||
| 153 | * SST Platform Data. | ||
| 154 | */ | ||
| 155 | struct sst_pdata { | ||
| 156 | /* ACPI data */ | ||
| 157 | u32 lpe_base; | ||
| 158 | u32 lpe_size; | ||
| 159 | u32 pcicfg_base; | ||
| 160 | u32 pcicfg_size; | ||
| 161 | u32 fw_base; | ||
| 162 | u32 fw_size; | ||
| 163 | int irq; | ||
| 164 | |||
| 165 | /* Firmware */ | ||
| 166 | const struct firmware *fw; | ||
| 167 | |||
| 168 | /* DMA */ | ||
| 169 | u32 dma_base; | ||
| 170 | u32 dma_size; | ||
| 171 | int dma_engine; | ||
| 172 | |||
| 173 | /* DSP */ | ||
| 174 | u32 id; | ||
| 175 | void *dsp; | ||
| 176 | }; | ||
| 177 | |||
| 178 | /* Initialization */ | ||
| 179 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
| 180 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); | ||
| 181 | void sst_dsp_free(struct sst_dsp *sst); | ||
| 182 | |||
| 183 | /* SHIM Read / Write */ | ||
| 184 | void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); | ||
| 185 | u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); | ||
| 186 | int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, | ||
| 187 | u32 mask, u32 value); | ||
| 188 | void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value); | ||
| 189 | u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset); | ||
| 190 | int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, | ||
| 191 | u64 mask, u64 value); | ||
| 192 | |||
| 193 | /* SHIM Read / Write Unlocked for callers already holding sst lock */ | ||
| 194 | void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); | ||
| 195 | u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); | ||
| 196 | int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, | ||
| 197 | u32 mask, u32 value); | ||
| 198 | void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value); | ||
| 199 | u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset); | ||
| 200 | int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, | ||
| 201 | u64 mask, u64 value); | ||
| 202 | |||
| 203 | /* Internal generic low-level SST IO functions - can be overidden */ | ||
| 204 | void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); | ||
| 205 | u32 sst_shim32_read(void __iomem *addr, u32 offset); | ||
| 206 | void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value); | ||
| 207 | u64 sst_shim32_read64(void __iomem *addr, u32 offset); | ||
| 208 | void sst_memcpy_toio_32(struct sst_dsp *sst, | ||
| 209 | void __iomem *dest, void *src, size_t bytes); | ||
| 210 | void sst_memcpy_fromio_32(struct sst_dsp *sst, | ||
| 211 | void *dest, void __iomem *src, size_t bytes); | ||
| 212 | |||
| 213 | /* DSP reset & boot */ | ||
| 214 | void sst_dsp_reset(struct sst_dsp *sst); | ||
| 215 | int sst_dsp_boot(struct sst_dsp *sst); | ||
| 216 | |||
| 217 | /* Msg IO */ | ||
| 218 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); | ||
| 219 | u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp); | ||
| 220 | |||
| 221 | /* Mailbox management */ | ||
| 222 | int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset, | ||
| 223 | size_t inbox_size, u32 outbox_offset, size_t outbox_size); | ||
| 224 | void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes); | ||
| 225 | void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); | ||
| 226 | void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); | ||
| 227 | void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); | ||
| 228 | void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); | ||
| 229 | |||
| 230 | /* Debug */ | ||
| 231 | void sst_dsp_dump(struct sst_dsp *sst); | ||
| 232 | |||
| 233 | #endif | ||
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c new file mode 100644 index 000000000000..f7687107cf7f --- /dev/null +++ b/sound/soc/intel/sst-firmware.c | |||
| @@ -0,0 +1,587 @@ | |||
| 1 | /* | ||
| 2 | * Intel SST Firmware Loader | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/kernel.h> | ||
| 18 | #include <linux/slab.h> | ||
| 19 | #include <linux/sched.h> | ||
| 20 | #include <linux/firmware.h> | ||
| 21 | #include <linux/export.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | #include <linux/dma-mapping.h> | ||
| 24 | #include <linux/dmaengine.h> | ||
| 25 | #include <linux/pci.h> | ||
| 26 | |||
| 27 | #include <asm/page.h> | ||
| 28 | #include <asm/pgtable.h> | ||
| 29 | |||
| 30 | #include "sst-dsp.h" | ||
| 31 | #include "sst-dsp-priv.h" | ||
| 32 | |||
| 33 | static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | ||
| 34 | { | ||
| 35 | u32 i; | ||
| 36 | |||
| 37 | /* copy one 32 bit word at a time as 64 bit access is not supported */ | ||
| 38 | for (i = 0; i < bytes; i += 4) | ||
| 39 | memcpy_toio(dest + i, src + i, 4); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* create new generic firmware object */ | ||
| 43 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | ||
| 44 | const struct firmware *fw, void *private) | ||
| 45 | { | ||
| 46 | struct sst_fw *sst_fw; | ||
| 47 | int err; | ||
| 48 | |||
| 49 | if (!dsp->ops->parse_fw) | ||
| 50 | return NULL; | ||
| 51 | |||
| 52 | sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL); | ||
| 53 | if (sst_fw == NULL) | ||
| 54 | return NULL; | ||
| 55 | |||
| 56 | sst_fw->dsp = dsp; | ||
| 57 | sst_fw->private = private; | ||
| 58 | sst_fw->size = fw->size; | ||
| 59 | |||
| 60 | err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); | ||
| 61 | if (err < 0) { | ||
| 62 | kfree(sst_fw); | ||
| 63 | return NULL; | ||
| 64 | } | ||
| 65 | |||
| 66 | /* allocate DMA buffer to store FW data */ | ||
| 67 | sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, | ||
| 68 | &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); | ||
| 69 | if (!sst_fw->dma_buf) { | ||
| 70 | dev_err(dsp->dev, "error: DMA alloc failed\n"); | ||
| 71 | kfree(sst_fw); | ||
| 72 | return NULL; | ||
| 73 | } | ||
| 74 | |||
| 75 | /* copy FW data to DMA-able memory */ | ||
| 76 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); | ||
| 77 | |||
| 78 | /* call core specific FW paser to load FW data into DSP */ | ||
| 79 | err = dsp->ops->parse_fw(sst_fw); | ||
| 80 | if (err < 0) { | ||
| 81 | dev_err(dsp->dev, "error: parse fw failed %d\n", err); | ||
| 82 | goto parse_err; | ||
| 83 | } | ||
| 84 | |||
| 85 | mutex_lock(&dsp->mutex); | ||
| 86 | list_add(&sst_fw->list, &dsp->fw_list); | ||
| 87 | mutex_unlock(&dsp->mutex); | ||
| 88 | |||
| 89 | return sst_fw; | ||
| 90 | |||
| 91 | parse_err: | ||
| 92 | dma_free_coherent(dsp->dev, sst_fw->size, | ||
| 93 | sst_fw->dma_buf, | ||
| 94 | sst_fw->dmable_fw_paddr); | ||
| 95 | kfree(sst_fw); | ||
| 96 | return NULL; | ||
| 97 | } | ||
| 98 | EXPORT_SYMBOL_GPL(sst_fw_new); | ||
| 99 | |||
| 100 | /* free single firmware object */ | ||
| 101 | void sst_fw_free(struct sst_fw *sst_fw) | ||
| 102 | { | ||
| 103 | struct sst_dsp *dsp = sst_fw->dsp; | ||
| 104 | |||
| 105 | mutex_lock(&dsp->mutex); | ||
| 106 | list_del(&sst_fw->list); | ||
| 107 | mutex_unlock(&dsp->mutex); | ||
| 108 | |||
| 109 | dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, | ||
| 110 | sst_fw->dmable_fw_paddr); | ||
| 111 | kfree(sst_fw); | ||
| 112 | } | ||
| 113 | EXPORT_SYMBOL_GPL(sst_fw_free); | ||
| 114 | |||
| 115 | /* free all firmware objects */ | ||
| 116 | void sst_fw_free_all(struct sst_dsp *dsp) | ||
| 117 | { | ||
| 118 | struct sst_fw *sst_fw, *t; | ||
| 119 | |||
| 120 | mutex_lock(&dsp->mutex); | ||
| 121 | list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) { | ||
| 122 | |||
| 123 | list_del(&sst_fw->list); | ||
| 124 | dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, | ||
| 125 | sst_fw->dmable_fw_paddr); | ||
| 126 | kfree(sst_fw); | ||
| 127 | } | ||
| 128 | mutex_unlock(&dsp->mutex); | ||
| 129 | } | ||
| 130 | EXPORT_SYMBOL_GPL(sst_fw_free_all); | ||
| 131 | |||
| 132 | /* create a new SST generic module from FW template */ | ||
| 133 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | ||
| 134 | struct sst_module_template *template, void *private) | ||
| 135 | { | ||
| 136 | struct sst_dsp *dsp = sst_fw->dsp; | ||
| 137 | struct sst_module *sst_module; | ||
| 138 | |||
| 139 | sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL); | ||
| 140 | if (sst_module == NULL) | ||
| 141 | return NULL; | ||
| 142 | |||
| 143 | sst_module->id = template->id; | ||
| 144 | sst_module->dsp = dsp; | ||
| 145 | sst_module->sst_fw = sst_fw; | ||
| 146 | |||
| 147 | memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data)); | ||
| 148 | memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data)); | ||
| 149 | |||
| 150 | INIT_LIST_HEAD(&sst_module->block_list); | ||
| 151 | |||
| 152 | mutex_lock(&dsp->mutex); | ||
| 153 | list_add(&sst_module->list, &dsp->module_list); | ||
| 154 | mutex_unlock(&dsp->mutex); | ||
| 155 | |||
| 156 | return sst_module; | ||
| 157 | } | ||
| 158 | EXPORT_SYMBOL_GPL(sst_module_new); | ||
| 159 | |||
| 160 | /* free firmware module and remove from available list */ | ||
| 161 | void sst_module_free(struct sst_module *sst_module) | ||
| 162 | { | ||
| 163 | struct sst_dsp *dsp = sst_module->dsp; | ||
| 164 | |||
| 165 | mutex_lock(&dsp->mutex); | ||
| 166 | list_del(&sst_module->list); | ||
| 167 | mutex_unlock(&dsp->mutex); | ||
| 168 | |||
| 169 | kfree(sst_module); | ||
| 170 | } | ||
| 171 | EXPORT_SYMBOL_GPL(sst_module_free); | ||
| 172 | |||
| 173 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type, | ||
| 174 | u32 offset) | ||
| 175 | { | ||
| 176 | struct sst_mem_block *block; | ||
| 177 | |||
| 178 | list_for_each_entry(block, &dsp->free_block_list, list) { | ||
| 179 | if (block->type == type && block->offset == offset) | ||
| 180 | return block; | ||
| 181 | } | ||
| 182 | |||
| 183 | return NULL; | ||
| 184 | } | ||
| 185 | |||
| 186 | static int block_alloc_contiguous(struct sst_module *module, | ||
| 187 | struct sst_module_data *data, u32 offset, int size) | ||
| 188 | { | ||
| 189 | struct list_head tmp = LIST_HEAD_INIT(tmp); | ||
| 190 | struct sst_dsp *dsp = module->dsp; | ||
| 191 | struct sst_mem_block *block; | ||
| 192 | |||
| 193 | while (size > 0) { | ||
| 194 | block = find_block(dsp, data->type, offset); | ||
| 195 | if (!block) { | ||
| 196 | list_splice(&tmp, &dsp->free_block_list); | ||
| 197 | return -ENOMEM; | ||
| 198 | } | ||
| 199 | |||
| 200 | list_move_tail(&block->list, &tmp); | ||
| 201 | offset += block->size; | ||
| 202 | size -= block->size; | ||
| 203 | } | ||
| 204 | |||
| 205 | list_splice(&tmp, &dsp->used_block_list); | ||
| 206 | return 0; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* allocate free DSP blocks for module data - callers hold locks */ | ||
| 210 | static int block_alloc(struct sst_module *module, | ||
| 211 | struct sst_module_data *data) | ||
| 212 | { | ||
| 213 | struct sst_dsp *dsp = module->dsp; | ||
| 214 | struct sst_mem_block *block, *tmp; | ||
| 215 | int ret = 0; | ||
| 216 | |||
| 217 | if (data->size == 0) | ||
| 218 | return 0; | ||
| 219 | |||
| 220 | /* find first free whole blocks that can hold module */ | ||
| 221 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
| 222 | |||
| 223 | /* ignore blocks with wrong type */ | ||
| 224 | if (block->type != data->type) | ||
| 225 | continue; | ||
| 226 | |||
| 227 | if (data->size > block->size) | ||
| 228 | continue; | ||
| 229 | |||
| 230 | data->offset = block->offset; | ||
| 231 | block->data_type = data->data_type; | ||
| 232 | block->bytes_used = data->size % block->size; | ||
| 233 | list_add(&block->module_list, &module->block_list); | ||
| 234 | list_move(&block->list, &dsp->used_block_list); | ||
| 235 | dev_dbg(dsp->dev, " *module %d added block %d:%d\n", | ||
| 236 | module->id, block->type, block->index); | ||
| 237 | return 0; | ||
| 238 | } | ||
| 239 | |||
| 240 | /* then find free multiple blocks that can hold module */ | ||
| 241 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
| 242 | |||
| 243 | /* ignore blocks with wrong type */ | ||
| 244 | if (block->type != data->type) | ||
| 245 | continue; | ||
| 246 | |||
| 247 | /* do we span > 1 blocks */ | ||
| 248 | if (data->size > block->size) { | ||
| 249 | ret = block_alloc_contiguous(module, data, | ||
| 250 | block->offset + block->size, | ||
| 251 | data->size - block->size); | ||
| 252 | if (ret == 0) | ||
| 253 | return ret; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | |||
| 257 | /* not enough free block space */ | ||
| 258 | return -ENOMEM; | ||
| 259 | } | ||
| 260 | |||
| 261 | /* remove module from memory - callers hold locks */ | ||
| 262 | static void block_module_remove(struct sst_module *module) | ||
| 263 | { | ||
| 264 | struct sst_mem_block *block, *tmp; | ||
| 265 | struct sst_dsp *dsp = module->dsp; | ||
| 266 | int err; | ||
| 267 | |||
| 268 | /* disable each block */ | ||
| 269 | list_for_each_entry(block, &module->block_list, module_list) { | ||
| 270 | |||
| 271 | if (block->ops && block->ops->disable) { | ||
| 272 | err = block->ops->disable(block); | ||
| 273 | if (err < 0) | ||
| 274 | dev_err(dsp->dev, | ||
| 275 | "error: cant disable block %d:%d\n", | ||
| 276 | block->type, block->index); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | |||
| 280 | /* mark each block as free */ | ||
| 281 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | ||
| 282 | list_del(&block->module_list); | ||
| 283 | list_move(&block->list, &dsp->free_block_list); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
| 288 | static int block_module_prepare(struct sst_module *module) | ||
| 289 | { | ||
| 290 | struct sst_mem_block *block; | ||
| 291 | int ret = 0; | ||
| 292 | |||
| 293 | /* enable each block so that's it'e ready for module P/S data */ | ||
| 294 | list_for_each_entry(block, &module->block_list, module_list) { | ||
| 295 | |||
| 296 | if (block->ops && block->ops->enable) { | ||
| 297 | ret = block->ops->enable(block); | ||
| 298 | if (ret < 0) { | ||
| 299 | dev_err(module->dsp->dev, | ||
| 300 | "error: cant disable block %d:%d\n", | ||
| 301 | block->type, block->index); | ||
| 302 | goto err; | ||
| 303 | } | ||
| 304 | } | ||
| 305 | } | ||
| 306 | return ret; | ||
| 307 | |||
| 308 | err: | ||
| 309 | list_for_each_entry(block, &module->block_list, module_list) { | ||
| 310 | if (block->ops && block->ops->disable) | ||
| 311 | block->ops->disable(block); | ||
| 312 | } | ||
| 313 | return ret; | ||
| 314 | } | ||
| 315 | |||
| 316 | /* allocate memory blocks for static module addresses - callers hold locks */ | ||
| 317 | static int block_alloc_fixed(struct sst_module *module, | ||
| 318 | struct sst_module_data *data) | ||
| 319 | { | ||
| 320 | struct sst_dsp *dsp = module->dsp; | ||
| 321 | struct sst_mem_block *block, *tmp; | ||
| 322 | u32 end = data->offset + data->size, block_end; | ||
| 323 | int err; | ||
| 324 | |||
| 325 | /* only IRAM/DRAM blocks are managed */ | ||
| 326 | if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM) | ||
| 327 | return 0; | ||
| 328 | |||
| 329 | /* are blocks already attached to this module */ | ||
| 330 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | ||
| 331 | |||
| 332 | /* force compacting mem blocks of the same data_type */ | ||
| 333 | if (block->data_type != data->data_type) | ||
| 334 | continue; | ||
| 335 | |||
| 336 | block_end = block->offset + block->size; | ||
| 337 | |||
| 338 | /* find block that holds section */ | ||
| 339 | if (data->offset >= block->offset && end < block_end) | ||
| 340 | return 0; | ||
| 341 | |||
| 342 | /* does block span more than 1 section */ | ||
| 343 | if (data->offset >= block->offset && data->offset < block_end) { | ||
| 344 | |||
| 345 | err = block_alloc_contiguous(module, data, | ||
| 346 | block->offset + block->size, | ||
| 347 | data->size - block->size + data->offset - block->offset); | ||
| 348 | if (err < 0) | ||
| 349 | return -ENOMEM; | ||
| 350 | |||
| 351 | /* module already owns blocks */ | ||
| 352 | return 0; | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | /* find first free blocks that can hold section in free list */ | ||
| 357 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
| 358 | block_end = block->offset + block->size; | ||
| 359 | |||
| 360 | /* find block that holds section */ | ||
| 361 | if (data->offset >= block->offset && end < block_end) { | ||
| 362 | |||
| 363 | /* add block */ | ||
| 364 | block->data_type = data->data_type; | ||
| 365 | list_move(&block->list, &dsp->used_block_list); | ||
| 366 | list_add(&block->module_list, &module->block_list); | ||
| 367 | return 0; | ||
| 368 | } | ||
| 369 | |||
| 370 | /* does block span more than 1 section */ | ||
| 371 | if (data->offset >= block->offset && data->offset < block_end) { | ||
| 372 | |||
| 373 | err = block_alloc_contiguous(module, data, | ||
| 374 | block->offset + block->size, | ||
| 375 | data->size - block->size); | ||
| 376 | if (err < 0) | ||
| 377 | return -ENOMEM; | ||
| 378 | |||
| 379 | /* add block */ | ||
| 380 | block->data_type = data->data_type; | ||
| 381 | list_move(&block->list, &dsp->used_block_list); | ||
| 382 | list_add(&block->module_list, &module->block_list); | ||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | } | ||
| 387 | |||
| 388 | return -ENOMEM; | ||
| 389 | } | ||
| 390 | |||
| 391 | /* Load fixed module data into DSP memory blocks */ | ||
| 392 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
| 393 | struct sst_module_data *data) | ||
| 394 | { | ||
| 395 | struct sst_dsp *dsp = module->dsp; | ||
| 396 | int ret; | ||
| 397 | |||
| 398 | mutex_lock(&dsp->mutex); | ||
| 399 | |||
| 400 | /* alloc blocks that includes this section */ | ||
| 401 | ret = block_alloc_fixed(module, data); | ||
| 402 | if (ret < 0) { | ||
| 403 | dev_err(dsp->dev, | ||
| 404 | "error: no free blocks for section at offset 0x%x size 0x%x\n", | ||
| 405 | data->offset, data->size); | ||
| 406 | mutex_unlock(&dsp->mutex); | ||
| 407 | return -ENOMEM; | ||
| 408 | } | ||
| 409 | |||
| 410 | /* prepare DSP blocks for module copy */ | ||
| 411 | ret = block_module_prepare(module); | ||
| 412 | if (ret < 0) { | ||
| 413 | dev_err(dsp->dev, "error: fw module prepare failed\n"); | ||
| 414 | goto err; | ||
| 415 | } | ||
| 416 | |||
| 417 | /* copy partial module data to blocks */ | ||
| 418 | sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size); | ||
| 419 | |||
| 420 | mutex_unlock(&dsp->mutex); | ||
| 421 | return ret; | ||
| 422 | |||
| 423 | err: | ||
| 424 | block_module_remove(module); | ||
| 425 | mutex_unlock(&dsp->mutex); | ||
| 426 | return ret; | ||
| 427 | } | ||
| 428 | EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block); | ||
| 429 | |||
| 430 | /* Unload entire module from DSP memory */ | ||
| 431 | int sst_block_module_remove(struct sst_module *module) | ||
| 432 | { | ||
| 433 | struct sst_dsp *dsp = module->dsp; | ||
| 434 | |||
| 435 | mutex_lock(&dsp->mutex); | ||
| 436 | block_module_remove(module); | ||
| 437 | mutex_unlock(&dsp->mutex); | ||
| 438 | return 0; | ||
| 439 | } | ||
| 440 | EXPORT_SYMBOL_GPL(sst_block_module_remove); | ||
| 441 | |||
| 442 | /* register a DSP memory block for use with FW based modules */ | ||
| 443 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | ||
| 444 | u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, | ||
| 445 | void *private) | ||
| 446 | { | ||
| 447 | struct sst_mem_block *block; | ||
| 448 | |||
| 449 | block = kzalloc(sizeof(*block), GFP_KERNEL); | ||
| 450 | if (block == NULL) | ||
| 451 | return NULL; | ||
| 452 | |||
| 453 | block->offset = offset; | ||
| 454 | block->size = size; | ||
| 455 | block->index = index; | ||
| 456 | block->type = type; | ||
| 457 | block->dsp = dsp; | ||
| 458 | block->private = private; | ||
| 459 | block->ops = ops; | ||
| 460 | |||
| 461 | mutex_lock(&dsp->mutex); | ||
| 462 | list_add(&block->list, &dsp->free_block_list); | ||
| 463 | mutex_unlock(&dsp->mutex); | ||
| 464 | |||
| 465 | return block; | ||
| 466 | } | ||
| 467 | EXPORT_SYMBOL_GPL(sst_mem_block_register); | ||
| 468 | |||
| 469 | /* unregister all DSP memory blocks */ | ||
| 470 | void sst_mem_block_unregister_all(struct sst_dsp *dsp) | ||
| 471 | { | ||
| 472 | struct sst_mem_block *block, *tmp; | ||
| 473 | |||
| 474 | mutex_lock(&dsp->mutex); | ||
| 475 | |||
| 476 | /* unregister used blocks */ | ||
| 477 | list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) { | ||
| 478 | list_del(&block->list); | ||
| 479 | kfree(block); | ||
| 480 | } | ||
| 481 | |||
| 482 | /* unregister free blocks */ | ||
| 483 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
| 484 | list_del(&block->list); | ||
| 485 | kfree(block); | ||
| 486 | } | ||
| 487 | |||
| 488 | mutex_unlock(&dsp->mutex); | ||
| 489 | } | ||
| 490 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); | ||
| 491 | |||
| 492 | /* allocate scratch buffer blocks */ | ||
| 493 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp) | ||
| 494 | { | ||
| 495 | struct sst_module *sst_module, *scratch; | ||
| 496 | struct sst_mem_block *block, *tmp; | ||
| 497 | u32 block_size; | ||
| 498 | int ret = 0; | ||
| 499 | |||
| 500 | scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL); | ||
| 501 | if (scratch == NULL) | ||
| 502 | return NULL; | ||
| 503 | |||
| 504 | mutex_lock(&dsp->mutex); | ||
| 505 | |||
| 506 | /* calculate required scratch size */ | ||
| 507 | list_for_each_entry(sst_module, &dsp->module_list, list) { | ||
| 508 | if (scratch->s.size > sst_module->s.size) | ||
| 509 | scratch->s.size = scratch->s.size; | ||
| 510 | else | ||
| 511 | scratch->s.size = sst_module->s.size; | ||
| 512 | } | ||
| 513 | |||
| 514 | dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n", | ||
| 515 | scratch->s.size); | ||
| 516 | |||
| 517 | /* init scratch module */ | ||
| 518 | scratch->dsp = dsp; | ||
| 519 | scratch->s.type = SST_MEM_DRAM; | ||
| 520 | scratch->s.data_type = SST_DATA_S; | ||
| 521 | INIT_LIST_HEAD(&scratch->block_list); | ||
| 522 | |||
| 523 | /* check free blocks before looking at used blocks for space */ | ||
| 524 | if (!list_empty(&dsp->free_block_list)) | ||
| 525 | block = list_first_entry(&dsp->free_block_list, | ||
| 526 | struct sst_mem_block, list); | ||
| 527 | else | ||
| 528 | block = list_first_entry(&dsp->used_block_list, | ||
| 529 | struct sst_mem_block, list); | ||
| 530 | block_size = block->size; | ||
| 531 | |||
| 532 | /* allocate blocks for module scratch buffers */ | ||
| 533 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); | ||
| 534 | ret = block_alloc(scratch, &scratch->s); | ||
| 535 | if (ret < 0) { | ||
| 536 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); | ||
| 537 | goto err; | ||
| 538 | } | ||
| 539 | |||
| 540 | /* assign the same offset of scratch to each module */ | ||
| 541 | list_for_each_entry(sst_module, &dsp->module_list, list) | ||
| 542 | sst_module->s.offset = scratch->s.offset; | ||
| 543 | |||
| 544 | mutex_unlock(&dsp->mutex); | ||
| 545 | return scratch; | ||
| 546 | |||
| 547 | err: | ||
| 548 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
| 549 | list_del(&block->module_list); | ||
| 550 | mutex_unlock(&dsp->mutex); | ||
| 551 | return NULL; | ||
| 552 | } | ||
| 553 | EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch); | ||
| 554 | |||
| 555 | /* free all scratch blocks */ | ||
| 556 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | ||
| 557 | struct sst_module *scratch) | ||
| 558 | { | ||
| 559 | struct sst_mem_block *block, *tmp; | ||
| 560 | |||
| 561 | mutex_lock(&dsp->mutex); | ||
| 562 | |||
| 563 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
| 564 | list_del(&block->module_list); | ||
| 565 | |||
| 566 | mutex_unlock(&dsp->mutex); | ||
| 567 | } | ||
| 568 | EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch); | ||
| 569 | |||
| 570 | /* get a module from it's unique ID */ | ||
| 571 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | ||
| 572 | { | ||
| 573 | struct sst_module *module; | ||
| 574 | |||
| 575 | mutex_lock(&dsp->mutex); | ||
| 576 | |||
| 577 | list_for_each_entry(module, &dsp->module_list, list) { | ||
| 578 | if (module->id == id) { | ||
| 579 | mutex_unlock(&dsp->mutex); | ||
| 580 | return module; | ||
| 581 | } | ||
| 582 | } | ||
| 583 | |||
| 584 | mutex_unlock(&dsp->mutex); | ||
| 585 | return NULL; | ||
| 586 | } | ||
| 587 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c new file mode 100644 index 000000000000..f5ebf36af889 --- /dev/null +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
| @@ -0,0 +1,517 @@ | |||
| 1 | /* | ||
| 2 | * Intel Haswell SST DSP driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/delay.h> | ||
| 18 | #include <linux/fs.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/sched.h> | ||
| 22 | #include <linux/export.h> | ||
| 23 | #include <linux/interrupt.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/dma-mapping.h> | ||
| 26 | #include <linux/platform_device.h> | ||
| 27 | #include <linux/pci.h> | ||
| 28 | #include <linux/firmware.h> | ||
| 29 | #include <linux/pm_runtime.h> | ||
| 30 | |||
| 31 | #include <linux/acpi.h> | ||
| 32 | #include <acpi/acpi_bus.h> | ||
| 33 | |||
| 34 | #include "sst-dsp.h" | ||
| 35 | #include "sst-dsp-priv.h" | ||
| 36 | #include "sst-haswell-ipc.h" | ||
| 37 | |||
| 38 | #include <trace/events/hswadsp.h> | ||
| 39 | |||
| 40 | #define SST_HSW_FW_SIGNATURE_SIZE 4 | ||
| 41 | #define SST_HSW_FW_SIGN "$SST" | ||
| 42 | #define SST_HSW_FW_LIB_SIGN "$LIB" | ||
| 43 | |||
| 44 | #define SST_WPT_SHIM_OFFSET 0xFB000 | ||
| 45 | #define SST_LP_SHIM_OFFSET 0xE7000 | ||
| 46 | #define SST_WPT_IRAM_OFFSET 0xA0000 | ||
| 47 | #define SST_LP_IRAM_OFFSET 0x80000 | ||
| 48 | |||
| 49 | #define SST_SHIM_PM_REG 0x84 | ||
| 50 | |||
| 51 | #define SST_HSW_IRAM 1 | ||
| 52 | #define SST_HSW_DRAM 2 | ||
| 53 | #define SST_HSW_REGS 3 | ||
| 54 | |||
| 55 | struct dma_block_info { | ||
| 56 | __le32 type; /* IRAM/DRAM */ | ||
| 57 | __le32 size; /* Bytes */ | ||
| 58 | __le32 ram_offset; /* Offset in I/DRAM */ | ||
| 59 | __le32 rsvd; /* Reserved field */ | ||
| 60 | } __attribute__((packed)); | ||
| 61 | |||
| 62 | struct fw_module_info { | ||
| 63 | __le32 persistent_size; | ||
| 64 | __le32 scratch_size; | ||
| 65 | } __attribute__((packed)); | ||
| 66 | |||
| 67 | struct fw_header { | ||
| 68 | unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */ | ||
| 69 | __le32 file_size; /* size of fw minus this header */ | ||
| 70 | __le32 modules; /* # of modules */ | ||
| 71 | __le32 file_format; /* version of header format */ | ||
| 72 | __le32 reserved[4]; | ||
| 73 | } __attribute__((packed)); | ||
| 74 | |||
| 75 | struct fw_module_header { | ||
| 76 | unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */ | ||
| 77 | __le32 mod_size; /* size of module */ | ||
| 78 | __le32 blocks; /* # of blocks */ | ||
| 79 | __le16 padding; | ||
| 80 | __le16 type; /* codec type, pp lib */ | ||
| 81 | __le32 entry_point; | ||
| 82 | struct fw_module_info info; | ||
| 83 | } __attribute__((packed)); | ||
| 84 | |||
| 85 | static void hsw_free(struct sst_dsp *sst); | ||
| 86 | |||
| 87 | static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | ||
| 88 | struct fw_module_header *module) | ||
| 89 | { | ||
| 90 | struct dma_block_info *block; | ||
| 91 | struct sst_module *mod; | ||
| 92 | struct sst_module_data block_data; | ||
| 93 | struct sst_module_template template; | ||
| 94 | int count; | ||
| 95 | void __iomem *ram; | ||
| 96 | |||
| 97 | /* TODO: allowed module types need to be configurable */ | ||
| 98 | if (module->type != SST_HSW_MODULE_BASE_FW | ||
| 99 | && module->type != SST_HSW_MODULE_PCM_SYSTEM | ||
| 100 | && module->type != SST_HSW_MODULE_PCM | ||
| 101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE | ||
| 102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE | ||
| 103 | && module->type != SST_HSW_MODULE_LPAL) | ||
| 104 | return 0; | ||
| 105 | |||
| 106 | dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n", | ||
| 107 | module->signature, module->mod_size, | ||
| 108 | module->blocks, module->type); | ||
| 109 | dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point); | ||
| 110 | dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n", | ||
| 111 | module->info.persistent_size, module->info.scratch_size); | ||
| 112 | |||
| 113 | memset(&template, 0, sizeof(template)); | ||
| 114 | template.id = module->type; | ||
| 115 | template.entry = module->entry_point; | ||
| 116 | template.p.size = module->info.persistent_size; | ||
| 117 | template.p.type = SST_MEM_DRAM; | ||
| 118 | template.p.data_type = SST_DATA_P; | ||
| 119 | template.s.size = module->info.scratch_size; | ||
| 120 | template.s.type = SST_MEM_DRAM; | ||
| 121 | template.s.data_type = SST_DATA_S; | ||
| 122 | |||
| 123 | mod = sst_module_new(fw, &template, NULL); | ||
| 124 | if (mod == NULL) | ||
| 125 | return -ENOMEM; | ||
| 126 | |||
| 127 | block = (void *)module + sizeof(*module); | ||
| 128 | |||
| 129 | for (count = 0; count < module->blocks; count++) { | ||
| 130 | |||
| 131 | if (block->size <= 0) { | ||
| 132 | dev_err(dsp->dev, | ||
| 133 | "error: block %d size invalid\n", count); | ||
| 134 | sst_module_free(mod); | ||
| 135 | return -EINVAL; | ||
| 136 | } | ||
| 137 | |||
| 138 | switch (block->type) { | ||
| 139 | case SST_HSW_IRAM: | ||
| 140 | ram = dsp->addr.lpe; | ||
| 141 | block_data.offset = | ||
| 142 | block->ram_offset + dsp->addr.iram_offset; | ||
| 143 | block_data.type = SST_MEM_IRAM; | ||
| 144 | break; | ||
| 145 | case SST_HSW_DRAM: | ||
| 146 | ram = dsp->addr.lpe; | ||
| 147 | block_data.offset = block->ram_offset; | ||
| 148 | block_data.type = SST_MEM_DRAM; | ||
| 149 | break; | ||
| 150 | default: | ||
| 151 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", | ||
| 152 | block->type, count); | ||
| 153 | sst_module_free(mod); | ||
| 154 | return -EINVAL; | ||
| 155 | } | ||
| 156 | |||
| 157 | block_data.size = block->size; | ||
| 158 | block_data.data_type = SST_DATA_M; | ||
| 159 | block_data.data = (void *)block + sizeof(*block); | ||
| 160 | block_data.data_offset = block_data.data - fw->dma_buf; | ||
| 161 | |||
| 162 | dev_dbg(dsp->dev, "copy firmware block %d type 0x%x " | ||
| 163 | "size 0x%x ==> ram %p offset 0x%x\n", | ||
| 164 | count, block->type, block->size, ram, | ||
| 165 | block->ram_offset); | ||
| 166 | |||
| 167 | sst_module_insert_fixed_block(mod, &block_data); | ||
| 168 | |||
| 169 | block = (void *)block + sizeof(*block) + block->size; | ||
| 170 | } | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) | ||
| 175 | { | ||
| 176 | struct fw_header *header; | ||
| 177 | struct sst_module *scratch; | ||
| 178 | struct fw_module_header *module; | ||
| 179 | struct sst_dsp *dsp = sst_fw->dsp; | ||
| 180 | struct sst_hsw *hsw = sst_fw->private; | ||
| 181 | int ret, count; | ||
| 182 | |||
| 183 | /* Read the header information from the data pointer */ | ||
| 184 | header = (struct fw_header *)sst_fw->dma_buf; | ||
| 185 | |||
| 186 | /* verify FW */ | ||
| 187 | if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) || | ||
| 188 | (sst_fw->size != header->file_size + sizeof(*header))) { | ||
| 189 | dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n"); | ||
| 190 | return -EINVAL; | ||
| 191 | } | ||
| 192 | |||
| 193 | dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n", | ||
| 194 | header->file_size, header->modules, | ||
| 195 | header->file_format, sizeof(*header)); | ||
| 196 | |||
| 197 | /* parse each module */ | ||
| 198 | module = (void *)sst_fw->dma_buf + sizeof(*header); | ||
| 199 | for (count = 0; count < header->modules; count++) { | ||
| 200 | |||
| 201 | /* module */ | ||
| 202 | ret = hsw_parse_module(dsp, sst_fw, module); | ||
| 203 | if (ret < 0) { | ||
| 204 | dev_err(dsp->dev, "error: invalid module %d\n", count); | ||
| 205 | return ret; | ||
| 206 | } | ||
| 207 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
| 208 | } | ||
| 209 | |||
| 210 | /* allocate persistent/scratch mem regions */ | ||
| 211 | scratch = sst_mem_block_alloc_scratch(dsp); | ||
| 212 | if (scratch == NULL) | ||
| 213 | return -ENOMEM; | ||
| 214 | |||
| 215 | sst_hsw_set_scratch_module(hsw, scratch); | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static irqreturn_t hsw_irq(int irq, void *context) | ||
| 221 | { | ||
| 222 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
| 223 | u32 isr; | ||
| 224 | int ret = IRQ_NONE; | ||
| 225 | |||
| 226 | spin_lock(&sst->spinlock); | ||
| 227 | |||
| 228 | /* Interrupt arrived, check src */ | ||
| 229 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
| 230 | if (isr & SST_ISRX_DONE) { | ||
| 231 | trace_sst_irq_done(isr, | ||
| 232 | sst_dsp_shim_read_unlocked(sst, SST_IMRX)); | ||
| 233 | |||
| 234 | /* Mask Done interrupt before return */ | ||
| 235 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
| 236 | SST_IMRX_DONE, SST_IMRX_DONE); | ||
| 237 | ret = IRQ_WAKE_THREAD; | ||
| 238 | } | ||
| 239 | |||
| 240 | if (isr & SST_ISRX_BUSY) { | ||
| 241 | trace_sst_irq_busy(isr, | ||
| 242 | sst_dsp_shim_read_unlocked(sst, SST_IMRX)); | ||
| 243 | |||
| 244 | /* Mask Busy interrupt before return */ | ||
| 245 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
| 246 | SST_IMRX_BUSY, SST_IMRX_BUSY); | ||
| 247 | ret = IRQ_WAKE_THREAD; | ||
| 248 | } | ||
| 249 | |||
| 250 | spin_unlock(&sst->spinlock); | ||
| 251 | return ret; | ||
| 252 | } | ||
| 253 | |||
| 254 | static void hsw_boot(struct sst_dsp *sst) | ||
| 255 | { | ||
| 256 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ | ||
| 257 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
| 258 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); | ||
| 259 | |||
| 260 | /* stall DSP core, set clk to 192/96Mhz */ | ||
| 261 | sst_dsp_shim_update_bits_unlocked(sst, | ||
| 262 | SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK, | ||
| 263 | SST_CSR_STALL | SST_CSR_DCS(4)); | ||
| 264 | |||
| 265 | /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ | ||
| 266 | sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, | ||
| 267 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, | ||
| 268 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); | ||
| 269 | |||
| 270 | /* disable DMA finish function for SSP0 & SSP1 */ | ||
| 271 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, | ||
| 272 | SST_CSR2_SDFD_SSP1); | ||
| 273 | |||
| 274 | /* enable DMA engine 0,1 all channels to access host memory */ | ||
| 275 | sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC, | ||
| 276 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff), | ||
| 277 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff)); | ||
| 278 | |||
| 279 | /* disable all clock gating */ | ||
| 280 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
| 281 | |||
| 282 | /* set DSP to RUN */ | ||
| 283 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); | ||
| 284 | } | ||
| 285 | |||
| 286 | static void hsw_reset(struct sst_dsp *sst) | ||
| 287 | { | ||
| 288 | /* put DSP into reset and stall */ | ||
| 289 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
| 290 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL); | ||
| 291 | |||
| 292 | /* keep in reset for 10ms */ | ||
| 293 | mdelay(10); | ||
| 294 | |||
| 295 | /* take DSP out of reset and keep stalled for FW loading */ | ||
| 296 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
| 297 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | ||
| 298 | } | ||
| 299 | |||
| 300 | struct sst_adsp_memregion { | ||
| 301 | u32 start; | ||
| 302 | u32 end; | ||
| 303 | int blocks; | ||
| 304 | enum sst_mem_type type; | ||
| 305 | }; | ||
| 306 | |||
| 307 | /* lynx point ADSP mem regions */ | ||
| 308 | static const struct sst_adsp_memregion lp_region[] = { | ||
| 309 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
| 310 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
| 311 | {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */ | ||
| 312 | }; | ||
| 313 | |||
| 314 | /* wild cat point ADSP mem regions */ | ||
| 315 | static const struct sst_adsp_memregion wpt_region[] = { | ||
| 316 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
| 317 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
| 318 | {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */ | ||
| 319 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ | ||
| 320 | }; | ||
| 321 | |||
| 322 | static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
| 323 | { | ||
| 324 | /* ADSP DRAM & IRAM */ | ||
| 325 | sst->addr.lpe_base = pdata->lpe_base; | ||
| 326 | sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size); | ||
| 327 | if (!sst->addr.lpe) | ||
| 328 | return -ENODEV; | ||
| 329 | |||
| 330 | /* ADSP PCI MMIO config space */ | ||
| 331 | sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size); | ||
| 332 | if (!sst->addr.pci_cfg) { | ||
| 333 | iounmap(sst->addr.lpe); | ||
| 334 | return -ENODEV; | ||
| 335 | } | ||
| 336 | |||
| 337 | /* SST Shim */ | ||
| 338 | sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset; | ||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static u32 hsw_block_get_bit(struct sst_mem_block *block) | ||
| 343 | { | ||
| 344 | u32 bit = 0, shift = 0; | ||
| 345 | |||
| 346 | switch (block->type) { | ||
| 347 | case SST_MEM_DRAM: | ||
| 348 | shift = 16; | ||
| 349 | break; | ||
| 350 | case SST_MEM_IRAM: | ||
| 351 | shift = 6; | ||
| 352 | break; | ||
| 353 | default: | ||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | bit = 1 << (block->index + shift); | ||
| 358 | |||
| 359 | return bit; | ||
| 360 | } | ||
| 361 | |||
| 362 | /* enable 32kB memory block - locks held by caller */ | ||
| 363 | static int hsw_block_enable(struct sst_mem_block *block) | ||
| 364 | { | ||
| 365 | struct sst_dsp *sst = block->dsp; | ||
| 366 | u32 bit, val; | ||
| 367 | |||
| 368 | if (block->users++ > 0) | ||
| 369 | return 0; | ||
| 370 | |||
| 371 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", | ||
| 372 | block->type, block->index, block->offset); | ||
| 373 | |||
| 374 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 375 | bit = hsw_block_get_bit(block); | ||
| 376 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 377 | |||
| 378 | /* wait 18 DSP clock ticks */ | ||
| 379 | udelay(10); | ||
| 380 | |||
| 381 | return 0; | ||
| 382 | } | ||
| 383 | |||
| 384 | /* disable 32kB memory block - locks held by caller */ | ||
| 385 | static int hsw_block_disable(struct sst_mem_block *block) | ||
| 386 | { | ||
| 387 | struct sst_dsp *sst = block->dsp; | ||
| 388 | u32 bit, val; | ||
| 389 | |||
| 390 | if (--block->users > 0) | ||
| 391 | return 0; | ||
| 392 | |||
| 393 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", | ||
| 394 | block->type, block->index, block->offset); | ||
| 395 | |||
| 396 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 397 | bit = hsw_block_get_bit(block); | ||
| 398 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 399 | |||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | |||
| 403 | static struct sst_block_ops sst_hsw_ops = { | ||
| 404 | .enable = hsw_block_enable, | ||
| 405 | .disable = hsw_block_disable, | ||
| 406 | }; | ||
| 407 | |||
| 408 | static int hsw_enable_shim(struct sst_dsp *sst) | ||
| 409 | { | ||
| 410 | int tries = 10; | ||
| 411 | u32 reg; | ||
| 412 | |||
| 413 | /* enable shim */ | ||
| 414 | reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
| 415 | writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
| 416 | |||
| 417 | /* check that ADSP shim is enabled */ | ||
| 418 | while (tries--) { | ||
| 419 | reg = sst_dsp_shim_read_unlocked(sst, SST_CSR); | ||
| 420 | if (reg != 0xffffffff) | ||
| 421 | return 0; | ||
| 422 | |||
| 423 | msleep(1); | ||
| 424 | } | ||
| 425 | |||
| 426 | return -ENODEV; | ||
| 427 | } | ||
| 428 | |||
| 429 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
| 430 | { | ||
| 431 | const struct sst_adsp_memregion *region; | ||
| 432 | struct device *dev; | ||
| 433 | int ret = -ENODEV, i, j, region_count; | ||
| 434 | u32 offset, size; | ||
| 435 | |||
| 436 | dev = sst->dev; | ||
| 437 | |||
| 438 | switch (sst->id) { | ||
| 439 | case SST_DEV_ID_LYNX_POINT: | ||
| 440 | region = lp_region; | ||
| 441 | region_count = ARRAY_SIZE(lp_region); | ||
| 442 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; | ||
| 443 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; | ||
| 444 | break; | ||
| 445 | case SST_DEV_ID_WILDCAT_POINT: | ||
| 446 | region = wpt_region; | ||
| 447 | region_count = ARRAY_SIZE(wpt_region); | ||
| 448 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; | ||
| 449 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; | ||
| 450 | break; | ||
| 451 | default: | ||
| 452 | dev_err(dev, "error: failed to get mem resources\n"); | ||
| 453 | return ret; | ||
| 454 | } | ||
| 455 | |||
| 456 | ret = hsw_acpi_resource_map(sst, pdata); | ||
| 457 | if (ret < 0) { | ||
| 458 | dev_err(dev, "error: failed to map resources\n"); | ||
| 459 | return ret; | ||
| 460 | } | ||
| 461 | |||
| 462 | /* enable the DSP SHIM */ | ||
| 463 | ret = hsw_enable_shim(sst); | ||
| 464 | if (ret < 0) { | ||
| 465 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); | ||
| 466 | return ret; | ||
| 467 | } | ||
| 468 | |||
| 469 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
| 470 | if (ret) | ||
| 471 | return ret; | ||
| 472 | |||
| 473 | /* Enable Interrupt from both sides */ | ||
| 474 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0); | ||
| 475 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD, | ||
| 476 | (0x3 | 0x1 << 16 | 0x3 << 21), 0x0); | ||
| 477 | |||
| 478 | /* register DSP memory blocks - ideally we should get this from ACPI */ | ||
| 479 | for (i = 0; i < region_count; i++) { | ||
| 480 | offset = region[i].start; | ||
| 481 | size = (region[i].end - region[i].start) / region[i].blocks; | ||
| 482 | |||
| 483 | /* register individual memory blocks */ | ||
| 484 | for (j = 0; j < region[i].blocks; j++) { | ||
| 485 | sst_mem_block_register(sst, offset, size, | ||
| 486 | region[i].type, &sst_hsw_ops, j, sst); | ||
| 487 | offset += size; | ||
| 488 | } | ||
| 489 | } | ||
| 490 | |||
| 491 | /* set default power gating mask */ | ||
| 492 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
| 493 | |||
| 494 | return 0; | ||
| 495 | } | ||
| 496 | |||
| 497 | static void hsw_free(struct sst_dsp *sst) | ||
| 498 | { | ||
| 499 | sst_mem_block_unregister_all(sst); | ||
| 500 | iounmap(sst->addr.lpe); | ||
| 501 | iounmap(sst->addr.pci_cfg); | ||
| 502 | } | ||
| 503 | |||
| 504 | struct sst_ops haswell_ops = { | ||
| 505 | .reset = hsw_reset, | ||
| 506 | .boot = hsw_boot, | ||
| 507 | .write = sst_shim32_write, | ||
| 508 | .read = sst_shim32_read, | ||
| 509 | .write64 = sst_shim32_write64, | ||
| 510 | .read64 = sst_shim32_read64, | ||
| 511 | .ram_read = sst_memcpy_fromio_32, | ||
| 512 | .ram_write = sst_memcpy_toio_32, | ||
| 513 | .irq_handler = hsw_irq, | ||
| 514 | .init = hsw_init, | ||
| 515 | .free = hsw_free, | ||
| 516 | .parse_fw = hsw_parse_fw_image, | ||
| 517 | }; | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c new file mode 100644 index 000000000000..f46bb4ddde6f --- /dev/null +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
| @@ -0,0 +1,1785 @@ | |||
| 1 | /* | ||
| 2 | * Intel SST Haswell/Broadwell IPC Support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/types.h> | ||
| 18 | #include <linux/kernel.h> | ||
| 19 | #include <linux/list.h> | ||
| 20 | #include <linux/device.h> | ||
| 21 | #include <linux/wait.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/workqueue.h> | ||
| 24 | #include <linux/export.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/sched.h> | ||
| 28 | #include <linux/list.h> | ||
| 29 | #include <linux/platform_device.h> | ||
| 30 | #include <linux/kthread.h> | ||
| 31 | #include <linux/firmware.h> | ||
| 32 | #include <linux/dma-mapping.h> | ||
| 33 | #include <linux/debugfs.h> | ||
| 34 | |||
| 35 | #include "sst-haswell-ipc.h" | ||
| 36 | #include "sst-dsp.h" | ||
| 37 | #include "sst-dsp-priv.h" | ||
| 38 | |||
| 39 | /* Global Message - Generic */ | ||
| 40 | #define IPC_GLB_TYPE_SHIFT 24 | ||
| 41 | #define IPC_GLB_TYPE_MASK (0x1f << IPC_GLB_TYPE_SHIFT) | ||
| 42 | #define IPC_GLB_TYPE(x) (x << IPC_GLB_TYPE_SHIFT) | ||
| 43 | |||
| 44 | /* Global Message - Reply */ | ||
| 45 | #define IPC_GLB_REPLY_SHIFT 0 | ||
| 46 | #define IPC_GLB_REPLY_MASK (0x1f << IPC_GLB_REPLY_SHIFT) | ||
| 47 | #define IPC_GLB_REPLY_TYPE(x) (x << IPC_GLB_REPLY_TYPE_SHIFT) | ||
| 48 | |||
| 49 | /* Stream Message - Generic */ | ||
| 50 | #define IPC_STR_TYPE_SHIFT 20 | ||
| 51 | #define IPC_STR_TYPE_MASK (0xf << IPC_STR_TYPE_SHIFT) | ||
| 52 | #define IPC_STR_TYPE(x) (x << IPC_STR_TYPE_SHIFT) | ||
| 53 | #define IPC_STR_ID_SHIFT 16 | ||
| 54 | #define IPC_STR_ID_MASK (0xf << IPC_STR_ID_SHIFT) | ||
| 55 | #define IPC_STR_ID(x) (x << IPC_STR_ID_SHIFT) | ||
| 56 | |||
| 57 | /* Stream Message - Reply */ | ||
| 58 | #define IPC_STR_REPLY_SHIFT 0 | ||
| 59 | #define IPC_STR_REPLY_MASK (0x1f << IPC_STR_REPLY_SHIFT) | ||
| 60 | |||
| 61 | /* Stream Stage Message - Generic */ | ||
| 62 | #define IPC_STG_TYPE_SHIFT 12 | ||
| 63 | #define IPC_STG_TYPE_MASK (0xf << IPC_STG_TYPE_SHIFT) | ||
| 64 | #define IPC_STG_TYPE(x) (x << IPC_STG_TYPE_SHIFT) | ||
| 65 | #define IPC_STG_ID_SHIFT 10 | ||
| 66 | #define IPC_STG_ID_MASK (0x3 << IPC_STG_ID_SHIFT) | ||
| 67 | #define IPC_STG_ID(x) (x << IPC_STG_ID_SHIFT) | ||
| 68 | |||
| 69 | /* Stream Stage Message - Reply */ | ||
| 70 | #define IPC_STG_REPLY_SHIFT 0 | ||
| 71 | #define IPC_STG_REPLY_MASK (0x1f << IPC_STG_REPLY_SHIFT) | ||
| 72 | |||
| 73 | /* Debug Log Message - Generic */ | ||
| 74 | #define IPC_LOG_OP_SHIFT 20 | ||
| 75 | #define IPC_LOG_OP_MASK (0xf << IPC_LOG_OP_SHIFT) | ||
| 76 | #define IPC_LOG_OP_TYPE(x) (x << IPC_LOG_OP_SHIFT) | ||
| 77 | #define IPC_LOG_ID_SHIFT 16 | ||
| 78 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) | ||
| 79 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) | ||
| 80 | |||
| 81 | /* IPC message timeout (msecs) */ | ||
| 82 | #define IPC_TIMEOUT_MSECS 300 | ||
| 83 | #define IPC_BOOT_MSECS 200 | ||
| 84 | #define IPC_MSG_WAIT 0 | ||
| 85 | #define IPC_MSG_NOWAIT 1 | ||
| 86 | |||
| 87 | /* Firmware Ready Message */ | ||
| 88 | #define IPC_FW_READY (0x1 << 29) | ||
| 89 | #define IPC_STATUS_MASK (0x3 << 30) | ||
| 90 | |||
| 91 | #define IPC_EMPTY_LIST_SIZE 8 | ||
| 92 | #define IPC_MAX_STREAMS 4 | ||
| 93 | |||
| 94 | /* Mailbox */ | ||
| 95 | #define IPC_MAX_MAILBOX_BYTES 256 | ||
| 96 | |||
| 97 | /* Global Message - Types and Replies */ | ||
| 98 | enum ipc_glb_type { | ||
| 99 | IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ | ||
| 100 | IPC_GLB_PERFORMANCE_MONITOR = 1, /* Performance monitoring actions */ | ||
| 101 | IPC_GLB_ALLOCATE_STREAM = 3, /* Request to allocate new stream */ | ||
| 102 | IPC_GLB_FREE_STREAM = 4, /* Request to free stream */ | ||
| 103 | IPC_GLB_GET_FW_CAPABILITIES = 5, /* Retrieves firmware capabilities */ | ||
| 104 | IPC_GLB_STREAM_MESSAGE = 6, /* Message directed to stream or its stages */ | ||
| 105 | /* Request to store firmware context during D0->D3 transition */ | ||
| 106 | IPC_GLB_REQUEST_DUMP = 7, | ||
| 107 | /* Request to restore firmware context during D3->D0 transition */ | ||
| 108 | IPC_GLB_RESTORE_CONTEXT = 8, | ||
| 109 | IPC_GLB_GET_DEVICE_FORMATS = 9, /* Set device format */ | ||
| 110 | IPC_GLB_SET_DEVICE_FORMATS = 10, /* Get device format */ | ||
| 111 | IPC_GLB_SHORT_REPLY = 11, | ||
| 112 | IPC_GLB_ENTER_DX_STATE = 12, | ||
| 113 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ | ||
| 114 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ | ||
| 115 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ | ||
| 116 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ | ||
| 117 | }; | ||
| 118 | |||
| 119 | enum ipc_glb_reply { | ||
| 120 | IPC_GLB_REPLY_SUCCESS = 0, /* The operation was successful. */ | ||
| 121 | IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1, /* Invalid parameter was passed. */ | ||
| 122 | IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */ | ||
| 123 | IPC_GLB_REPLY_OUT_OF_RESOURCES = 3, /* No resources to satisfy the request. */ | ||
| 124 | IPC_GLB_REPLY_BUSY = 4, /* The system or resource is busy. */ | ||
| 125 | IPC_GLB_REPLY_PENDING = 5, /* The action was scheduled for processing. */ | ||
| 126 | IPC_GLB_REPLY_FAILURE = 6, /* Critical error happened. */ | ||
| 127 | IPC_GLB_REPLY_INVALID_REQUEST = 7, /* Request can not be completed. */ | ||
| 128 | IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8, /* Processing stage was uninitialized. */ | ||
| 129 | IPC_GLB_REPLY_NOT_FOUND = 9, /* Required resource can not be found. */ | ||
| 130 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ | ||
| 131 | }; | ||
| 132 | |||
| 133 | /* Stream Message - Types */ | ||
| 134 | enum ipc_str_operation { | ||
| 135 | IPC_STR_RESET = 0, | ||
| 136 | IPC_STR_PAUSE = 1, | ||
| 137 | IPC_STR_RESUME = 2, | ||
| 138 | IPC_STR_STAGE_MESSAGE = 3, | ||
| 139 | IPC_STR_NOTIFICATION = 4, | ||
| 140 | IPC_STR_MAX_MESSAGE | ||
| 141 | }; | ||
| 142 | |||
| 143 | /* Stream Stage Message Types */ | ||
| 144 | enum ipc_stg_operation { | ||
| 145 | IPC_STG_GET_VOLUME = 0, | ||
| 146 | IPC_STG_SET_VOLUME, | ||
| 147 | IPC_STG_SET_WRITE_POSITION, | ||
| 148 | IPC_STG_SET_FX_ENABLE, | ||
| 149 | IPC_STG_SET_FX_DISABLE, | ||
| 150 | IPC_STG_SET_FX_GET_PARAM, | ||
| 151 | IPC_STG_SET_FX_SET_PARAM, | ||
| 152 | IPC_STG_SET_FX_GET_INFO, | ||
| 153 | IPC_STG_MUTE_LOOPBACK, | ||
| 154 | IPC_STG_MAX_MESSAGE | ||
| 155 | }; | ||
| 156 | |||
| 157 | /* Stream Stage Message Types For Notification*/ | ||
| 158 | enum ipc_stg_operation_notify { | ||
| 159 | IPC_POSITION_CHANGED = 0, | ||
| 160 | IPC_STG_GLITCH, | ||
| 161 | IPC_STG_MAX_NOTIFY | ||
| 162 | }; | ||
| 163 | |||
| 164 | enum ipc_glitch_type { | ||
| 165 | IPC_GLITCH_UNDERRUN = 1, | ||
| 166 | IPC_GLITCH_DECODER_ERROR, | ||
| 167 | IPC_GLITCH_DOUBLED_WRITE_POS, | ||
| 168 | IPC_GLITCH_MAX | ||
| 169 | }; | ||
| 170 | |||
| 171 | /* Debug Control */ | ||
| 172 | enum ipc_debug_operation { | ||
| 173 | IPC_DEBUG_ENABLE_LOG = 0, | ||
| 174 | IPC_DEBUG_DISABLE_LOG = 1, | ||
| 175 | IPC_DEBUG_REQUEST_LOG_DUMP = 2, | ||
| 176 | IPC_DEBUG_NOTIFY_LOG_DUMP = 3, | ||
| 177 | IPC_DEBUG_MAX_DEBUG_LOG | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* Firmware Ready */ | ||
| 181 | struct sst_hsw_ipc_fw_ready { | ||
| 182 | u32 inbox_offset; | ||
| 183 | u32 outbox_offset; | ||
| 184 | u32 inbox_size; | ||
| 185 | u32 outbox_size; | ||
| 186 | u32 fw_info_size; | ||
| 187 | u8 fw_info[1]; | ||
| 188 | } __attribute__((packed)); | ||
| 189 | |||
| 190 | struct ipc_message { | ||
| 191 | struct list_head list; | ||
| 192 | u32 header; | ||
| 193 | |||
| 194 | /* direction wrt host CPU */ | ||
| 195 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | ||
| 196 | size_t tx_size; | ||
| 197 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | ||
| 198 | size_t rx_size; | ||
| 199 | |||
| 200 | wait_queue_head_t waitq; | ||
| 201 | bool pending; | ||
| 202 | bool complete; | ||
| 203 | bool wait; | ||
| 204 | int errno; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct sst_hsw_stream; | ||
| 208 | struct sst_hsw; | ||
| 209 | |||
| 210 | /* Stream infomation */ | ||
| 211 | struct sst_hsw_stream { | ||
| 212 | /* configuration */ | ||
| 213 | struct sst_hsw_ipc_stream_alloc_req request; | ||
| 214 | struct sst_hsw_ipc_stream_alloc_reply reply; | ||
| 215 | struct sst_hsw_ipc_stream_free_req free_req; | ||
| 216 | |||
| 217 | /* Mixer info */ | ||
| 218 | u32 mute_volume[SST_HSW_NO_CHANNELS]; | ||
| 219 | u32 mute[SST_HSW_NO_CHANNELS]; | ||
| 220 | |||
| 221 | /* runtime info */ | ||
| 222 | struct sst_hsw *hsw; | ||
| 223 | int host_id; | ||
| 224 | bool commited; | ||
| 225 | bool running; | ||
| 226 | |||
| 227 | /* Notification work */ | ||
| 228 | struct work_struct notify_work; | ||
| 229 | u32 header; | ||
| 230 | |||
| 231 | /* Position info from DSP */ | ||
| 232 | struct sst_hsw_ipc_stream_set_position wpos; | ||
| 233 | struct sst_hsw_ipc_stream_get_position rpos; | ||
| 234 | struct sst_hsw_ipc_stream_glitch_position glitch; | ||
| 235 | |||
| 236 | /* Volume info */ | ||
| 237 | struct sst_hsw_ipc_volume_req vol_req; | ||
| 238 | |||
| 239 | /* driver callback */ | ||
| 240 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data); | ||
| 241 | void *pdata; | ||
| 242 | |||
| 243 | struct list_head node; | ||
| 244 | }; | ||
| 245 | |||
| 246 | /* FW log ring information */ | ||
| 247 | struct sst_hsw_log_stream { | ||
| 248 | dma_addr_t dma_addr; | ||
| 249 | unsigned char *dma_area; | ||
| 250 | unsigned char *ring_descr; | ||
| 251 | int pages; | ||
| 252 | int size; | ||
| 253 | |||
| 254 | /* Notification work */ | ||
| 255 | struct work_struct notify_work; | ||
| 256 | wait_queue_head_t readers_wait_q; | ||
| 257 | struct mutex rw_mutex; | ||
| 258 | |||
| 259 | u32 last_pos; | ||
| 260 | u32 curr_pos; | ||
| 261 | u32 reader_pos; | ||
| 262 | |||
| 263 | /* fw log config */ | ||
| 264 | u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS]; | ||
| 265 | |||
| 266 | struct sst_hsw *hsw; | ||
| 267 | }; | ||
| 268 | |||
| 269 | /* SST Haswell IPC data */ | ||
| 270 | struct sst_hsw { | ||
| 271 | struct device *dev; | ||
| 272 | struct sst_dsp *dsp; | ||
| 273 | struct platform_device *pdev_pcm; | ||
| 274 | |||
| 275 | /* FW config */ | ||
| 276 | struct sst_hsw_ipc_fw_ready fw_ready; | ||
| 277 | struct sst_hsw_ipc_fw_version version; | ||
| 278 | struct sst_module *scratch; | ||
| 279 | bool fw_done; | ||
| 280 | |||
| 281 | /* stream */ | ||
| 282 | struct list_head stream_list; | ||
| 283 | |||
| 284 | /* global mixer */ | ||
| 285 | struct sst_hsw_ipc_stream_info_reply mixer_info; | ||
| 286 | enum sst_hsw_volume_curve curve_type; | ||
| 287 | u32 curve_duration; | ||
| 288 | u32 mute[SST_HSW_NO_CHANNELS]; | ||
| 289 | u32 mute_volume[SST_HSW_NO_CHANNELS]; | ||
| 290 | |||
| 291 | /* DX */ | ||
| 292 | struct sst_hsw_ipc_dx_reply dx; | ||
| 293 | |||
| 294 | /* boot */ | ||
| 295 | wait_queue_head_t boot_wait; | ||
| 296 | bool boot_complete; | ||
| 297 | bool shutdown; | ||
| 298 | |||
| 299 | /* IPC messaging */ | ||
| 300 | struct list_head tx_list; | ||
| 301 | struct list_head rx_list; | ||
| 302 | struct list_head empty_list; | ||
| 303 | wait_queue_head_t wait_txq; | ||
| 304 | struct task_struct *tx_thread; | ||
| 305 | struct kthread_worker kworker; | ||
| 306 | struct kthread_work kwork; | ||
| 307 | bool pending; | ||
| 308 | struct ipc_message *msg; | ||
| 309 | |||
| 310 | /* FW log stream */ | ||
| 311 | struct sst_hsw_log_stream log_stream; | ||
| 312 | }; | ||
| 313 | |||
| 314 | #define CREATE_TRACE_POINTS | ||
| 315 | #include <trace/events/hswadsp.h> | ||
| 316 | |||
| 317 | static inline u32 msg_get_global_type(u32 msg) | ||
| 318 | { | ||
| 319 | return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT; | ||
| 320 | } | ||
| 321 | |||
| 322 | static inline u32 msg_get_global_reply(u32 msg) | ||
| 323 | { | ||
| 324 | return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT; | ||
| 325 | } | ||
| 326 | |||
| 327 | static inline u32 msg_get_stream_type(u32 msg) | ||
| 328 | { | ||
| 329 | return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT; | ||
| 330 | } | ||
| 331 | |||
| 332 | static inline u32 msg_get_stage_type(u32 msg) | ||
| 333 | { | ||
| 334 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | ||
| 335 | } | ||
| 336 | |||
| 337 | static inline u32 msg_set_stage_type(u32 msg, u32 type) | ||
| 338 | { | ||
| 339 | return (msg & ~IPC_STG_TYPE_MASK) + | ||
| 340 | (type << IPC_STG_TYPE_SHIFT); | ||
| 341 | } | ||
| 342 | |||
| 343 | static inline u32 msg_get_stream_id(u32 msg) | ||
| 344 | { | ||
| 345 | return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; | ||
| 346 | } | ||
| 347 | |||
| 348 | static inline u32 msg_get_notify_reason(u32 msg) | ||
| 349 | { | ||
| 350 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | ||
| 351 | } | ||
| 352 | |||
| 353 | u32 create_channel_map(enum sst_hsw_channel_config config) | ||
| 354 | { | ||
| 355 | switch (config) { | ||
| 356 | case SST_HSW_CHANNEL_CONFIG_MONO: | ||
| 357 | return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER); | ||
| 358 | case SST_HSW_CHANNEL_CONFIG_STEREO: | ||
| 359 | return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT | ||
| 360 | | (SST_HSW_CHANNEL_RIGHT << 4)); | ||
| 361 | case SST_HSW_CHANNEL_CONFIG_2_POINT_1: | ||
| 362 | return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT | ||
| 363 | | (SST_HSW_CHANNEL_RIGHT << 4) | ||
| 364 | | (SST_HSW_CHANNEL_LFE << 8 )); | ||
| 365 | case SST_HSW_CHANNEL_CONFIG_3_POINT_0: | ||
| 366 | return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT | ||
| 367 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
| 368 | | (SST_HSW_CHANNEL_RIGHT << 8)); | ||
| 369 | case SST_HSW_CHANNEL_CONFIG_3_POINT_1: | ||
| 370 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
| 371 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
| 372 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
| 373 | | (SST_HSW_CHANNEL_LFE << 12)); | ||
| 374 | case SST_HSW_CHANNEL_CONFIG_QUATRO: | ||
| 375 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
| 376 | | (SST_HSW_CHANNEL_RIGHT << 4) | ||
| 377 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 8) | ||
| 378 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12)); | ||
| 379 | case SST_HSW_CHANNEL_CONFIG_4_POINT_0: | ||
| 380 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
| 381 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
| 382 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
| 383 | | (SST_HSW_CHANNEL_CENTER_SURROUND << 12)); | ||
| 384 | case SST_HSW_CHANNEL_CONFIG_5_POINT_0: | ||
| 385 | return (0xFFF00000 | SST_HSW_CHANNEL_LEFT | ||
| 386 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
| 387 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
| 388 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 12) | ||
| 389 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)); | ||
| 390 | case SST_HSW_CHANNEL_CONFIG_5_POINT_1: | ||
| 391 | return (0xFF000000 | SST_HSW_CHANNEL_CENTER | ||
| 392 | | (SST_HSW_CHANNEL_LEFT << 4) | ||
| 393 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
| 394 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 12) | ||
| 395 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16) | ||
| 396 | | (SST_HSW_CHANNEL_LFE << 20)); | ||
| 397 | case SST_HSW_CHANNEL_CONFIG_DUAL_MONO: | ||
| 398 | return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT | ||
| 399 | | (SST_HSW_CHANNEL_LEFT << 4)); | ||
| 400 | default: | ||
| 401 | return 0xFFFFFFFF; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw, | ||
| 406 | int stream_id) | ||
| 407 | { | ||
| 408 | struct sst_hsw_stream *stream; | ||
| 409 | |||
| 410 | list_for_each_entry(stream, &hsw->stream_list, node) { | ||
| 411 | if (stream->reply.stream_hw_id == stream_id) | ||
| 412 | return stream; | ||
| 413 | } | ||
| 414 | |||
| 415 | return NULL; | ||
| 416 | } | ||
| 417 | |||
| 418 | static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text) | ||
| 419 | { | ||
| 420 | struct sst_dsp *sst = hsw->dsp; | ||
| 421 | u32 isr, ipcd, imrx, ipcx; | ||
| 422 | |||
| 423 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
| 424 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
| 425 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
| 426 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
| 427 | |||
| 428 | dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
| 429 | text, ipcx, isr, ipcd, imrx); | ||
| 430 | } | ||
| 431 | |||
| 432 | /* locks held by caller */ | ||
| 433 | static struct ipc_message *msg_get_empty(struct sst_hsw *hsw) | ||
| 434 | { | ||
| 435 | struct ipc_message *msg = NULL; | ||
| 436 | |||
| 437 | if (!list_empty(&hsw->empty_list)) { | ||
| 438 | msg = list_first_entry(&hsw->empty_list, struct ipc_message, | ||
| 439 | list); | ||
| 440 | list_del(&msg->list); | ||
| 441 | } | ||
| 442 | |||
| 443 | return msg; | ||
| 444 | } | ||
| 445 | |||
| 446 | static void ipc_tx_msgs(struct kthread_work *work) | ||
| 447 | { | ||
| 448 | struct sst_hsw *hsw = | ||
| 449 | container_of(work, struct sst_hsw, kwork); | ||
| 450 | struct ipc_message *msg; | ||
| 451 | unsigned long flags; | ||
| 452 | u32 ipcx; | ||
| 453 | |||
| 454 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
| 455 | |||
| 456 | if (list_empty(&hsw->tx_list) || hsw->pending) { | ||
| 457 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 458 | return; | ||
| 459 | } | ||
| 460 | |||
| 461 | /* if the DSP is busy we will TX messages after IRQ */ | ||
| 462 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | ||
| 463 | if (ipcx & SST_IPCX_BUSY) { | ||
| 464 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 465 | return; | ||
| 466 | } | ||
| 467 | |||
| 468 | msg = list_first_entry(&hsw->tx_list, struct ipc_message, list); | ||
| 469 | |||
| 470 | list_move(&msg->list, &hsw->rx_list); | ||
| 471 | |||
| 472 | /* send the message */ | ||
| 473 | sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size); | ||
| 474 | sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY); | ||
| 475 | |||
| 476 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 477 | } | ||
| 478 | |||
| 479 | /* locks held by caller */ | ||
| 480 | static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg) | ||
| 481 | { | ||
| 482 | msg->complete = true; | ||
| 483 | trace_ipc_reply("completed", msg->header); | ||
| 484 | |||
| 485 | if (!msg->wait) | ||
| 486 | list_add_tail(&msg->list, &hsw->empty_list); | ||
| 487 | else | ||
| 488 | wake_up(&msg->waitq); | ||
| 489 | } | ||
| 490 | |||
| 491 | static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | ||
| 492 | void *rx_data) | ||
| 493 | { | ||
| 494 | unsigned long flags; | ||
| 495 | int ret; | ||
| 496 | |||
| 497 | /* wait for DSP completion (in all cases atm inc pending) */ | ||
| 498 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
| 499 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
| 500 | |||
| 501 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
| 502 | if (ret == 0) { | ||
| 503 | ipc_shim_dbg(hsw, "message timeout"); | ||
| 504 | |||
| 505 | trace_ipc_error("error message timeout for", msg->header); | ||
| 506 | ret = -ETIMEDOUT; | ||
| 507 | } else { | ||
| 508 | |||
| 509 | /* copy the data returned from DSP */ | ||
| 510 | if (msg->rx_size) | ||
| 511 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
| 512 | ret = msg->errno; | ||
| 513 | } | ||
| 514 | |||
| 515 | list_add_tail(&msg->list, &hsw->empty_list); | ||
| 516 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 517 | return ret; | ||
| 518 | } | ||
| 519 | |||
| 520 | static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data, | ||
| 521 | size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait) | ||
| 522 | { | ||
| 523 | struct ipc_message *msg; | ||
| 524 | unsigned long flags; | ||
| 525 | |||
| 526 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
| 527 | |||
| 528 | msg = msg_get_empty(hsw); | ||
| 529 | if (msg == NULL) { | ||
| 530 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 531 | return -EBUSY; | ||
| 532 | } | ||
| 533 | |||
| 534 | if (tx_bytes) | ||
| 535 | memcpy(msg->tx_data, tx_data, tx_bytes); | ||
| 536 | |||
| 537 | msg->header = header; | ||
| 538 | msg->tx_size = tx_bytes; | ||
| 539 | msg->rx_size = rx_bytes; | ||
| 540 | msg->wait = wait; | ||
| 541 | msg->errno = 0; | ||
| 542 | msg->pending = false; | ||
| 543 | msg->complete = false; | ||
| 544 | |||
| 545 | list_add_tail(&msg->list, &hsw->tx_list); | ||
| 546 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
| 547 | |||
| 548 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
| 549 | |||
| 550 | if (wait) | ||
| 551 | return tx_wait_done(hsw, msg, rx_data); | ||
| 552 | else | ||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header, | ||
| 557 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) | ||
| 558 | { | ||
| 559 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data, | ||
| 560 | rx_bytes, 1); | ||
| 561 | } | ||
| 562 | |||
| 563 | static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header, | ||
| 564 | void *tx_data, size_t tx_bytes) | ||
| 565 | { | ||
| 566 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0); | ||
| 567 | } | ||
| 568 | |||
| 569 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | ||
| 570 | { | ||
| 571 | struct sst_hsw_ipc_fw_ready fw_ready; | ||
| 572 | u32 offset; | ||
| 573 | |||
| 574 | offset = (header & 0x1FFFFFFF) << 3; | ||
| 575 | |||
| 576 | dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", | ||
| 577 | header, offset); | ||
| 578 | |||
| 579 | /* copy data from the DSP FW ready offset */ | ||
| 580 | sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready)); | ||
| 581 | |||
| 582 | sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset, | ||
| 583 | fw_ready.inbox_size, fw_ready.outbox_offset, | ||
| 584 | fw_ready.outbox_size); | ||
| 585 | |||
| 586 | hsw->boot_complete = true; | ||
| 587 | wake_up(&hsw->boot_wait); | ||
| 588 | |||
| 589 | dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n", | ||
| 590 | fw_ready.inbox_offset, fw_ready.inbox_size); | ||
| 591 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", | ||
| 592 | fw_ready.outbox_offset, fw_ready.outbox_size); | ||
| 593 | } | ||
| 594 | |||
| 595 | static void hsw_notification_work(struct work_struct *work) | ||
| 596 | { | ||
| 597 | struct sst_hsw_stream *stream = container_of(work, | ||
| 598 | struct sst_hsw_stream, notify_work); | ||
| 599 | struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch; | ||
| 600 | struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos; | ||
| 601 | struct sst_hsw *hsw = stream->hsw; | ||
| 602 | u32 reason; | ||
| 603 | |||
| 604 | reason = msg_get_notify_reason(stream->header); | ||
| 605 | |||
| 606 | switch (reason) { | ||
| 607 | case IPC_STG_GLITCH: | ||
| 608 | trace_ipc_notification("DSP stream under/overrun", | ||
| 609 | stream->reply.stream_hw_id); | ||
| 610 | sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch)); | ||
| 611 | |||
| 612 | dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n", | ||
| 613 | glitch->glitch_type, glitch->present_pos, | ||
| 614 | glitch->write_pos); | ||
| 615 | break; | ||
| 616 | |||
| 617 | case IPC_POSITION_CHANGED: | ||
| 618 | trace_ipc_notification("DSP stream position changed for", | ||
| 619 | stream->reply.stream_hw_id); | ||
| 620 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); | ||
| 621 | |||
| 622 | if (stream->notify_position) | ||
| 623 | stream->notify_position(stream, stream->pdata); | ||
| 624 | |||
| 625 | break; | ||
| 626 | default: | ||
| 627 | dev_err(hsw->dev, "error: unknown notification 0x%x\n", | ||
| 628 | stream->header); | ||
| 629 | break; | ||
| 630 | } | ||
| 631 | |||
| 632 | /* tell DSP that notification has been handled */ | ||
| 633 | sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD, | ||
| 634 | SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); | ||
| 635 | |||
| 636 | /* unmask busy interrupt */ | ||
| 637 | sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); | ||
| 638 | } | ||
| 639 | |||
| 640 | static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header) | ||
| 641 | { | ||
| 642 | struct ipc_message *msg; | ||
| 643 | |||
| 644 | /* clear reply bits & status bits */ | ||
| 645 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
| 646 | |||
| 647 | if (list_empty(&hsw->rx_list)) { | ||
| 648 | dev_err(hsw->dev, "error: rx list empty but received 0x%x\n", | ||
| 649 | header); | ||
| 650 | return NULL; | ||
| 651 | } | ||
| 652 | |||
| 653 | list_for_each_entry(msg, &hsw->rx_list, list) { | ||
| 654 | if (msg->header == header) | ||
| 655 | return msg; | ||
| 656 | } | ||
| 657 | |||
| 658 | return NULL; | ||
| 659 | } | ||
| 660 | |||
| 661 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | ||
| 662 | { | ||
| 663 | struct sst_hsw_stream *stream; | ||
| 664 | u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
| 665 | u32 stream_id = msg_get_stream_id(header); | ||
| 666 | u32 stream_msg = msg_get_stream_type(header); | ||
| 667 | |||
| 668 | stream = get_stream_by_id(hsw, stream_id); | ||
| 669 | if (stream == NULL) | ||
| 670 | return; | ||
| 671 | |||
| 672 | switch (stream_msg) { | ||
| 673 | case IPC_STR_STAGE_MESSAGE: | ||
| 674 | case IPC_STR_NOTIFICATION: | ||
| 675 | case IPC_STR_RESET: | ||
| 676 | break; | ||
| 677 | case IPC_STR_PAUSE: | ||
| 678 | stream->running = false; | ||
| 679 | trace_ipc_notification("stream paused", | ||
| 680 | stream->reply.stream_hw_id); | ||
| 681 | break; | ||
| 682 | case IPC_STR_RESUME: | ||
| 683 | stream->running = true; | ||
| 684 | trace_ipc_notification("stream running", | ||
| 685 | stream->reply.stream_hw_id); | ||
| 686 | break; | ||
| 687 | } | ||
| 688 | } | ||
| 689 | |||
| 690 | static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | ||
| 691 | { | ||
| 692 | struct ipc_message *msg; | ||
| 693 | u32 reply = msg_get_global_reply(header); | ||
| 694 | |||
| 695 | trace_ipc_reply("processing -->", header); | ||
| 696 | |||
| 697 | msg = reply_find_msg(hsw, header); | ||
| 698 | if (msg == NULL) { | ||
| 699 | trace_ipc_error("error: can't find message header", header); | ||
| 700 | return -EIO; | ||
| 701 | } | ||
| 702 | |||
| 703 | /* first process the header */ | ||
| 704 | switch (reply) { | ||
| 705 | case IPC_GLB_REPLY_PENDING: | ||
| 706 | trace_ipc_pending_reply("received", header); | ||
| 707 | msg->pending = true; | ||
| 708 | hsw->pending = true; | ||
| 709 | return 1; | ||
| 710 | case IPC_GLB_REPLY_SUCCESS: | ||
| 711 | if (msg->pending) { | ||
| 712 | trace_ipc_pending_reply("completed", header); | ||
| 713 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, | ||
| 714 | msg->rx_size); | ||
| 715 | hsw->pending = false; | ||
| 716 | } else { | ||
| 717 | /* copy data from the DSP */ | ||
| 718 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, | ||
| 719 | msg->rx_size); | ||
| 720 | } | ||
| 721 | break; | ||
| 722 | /* these will be rare - but useful for debug */ | ||
| 723 | case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE: | ||
| 724 | trace_ipc_error("error: unknown message type", header); | ||
| 725 | msg->errno = -EBADMSG; | ||
| 726 | break; | ||
| 727 | case IPC_GLB_REPLY_OUT_OF_RESOURCES: | ||
| 728 | trace_ipc_error("error: out of resources", header); | ||
| 729 | msg->errno = -ENOMEM; | ||
| 730 | break; | ||
| 731 | case IPC_GLB_REPLY_BUSY: | ||
| 732 | trace_ipc_error("error: reply busy", header); | ||
| 733 | msg->errno = -EBUSY; | ||
| 734 | break; | ||
| 735 | case IPC_GLB_REPLY_FAILURE: | ||
| 736 | trace_ipc_error("error: reply failure", header); | ||
| 737 | msg->errno = -EINVAL; | ||
| 738 | break; | ||
| 739 | case IPC_GLB_REPLY_STAGE_UNINITIALIZED: | ||
| 740 | trace_ipc_error("error: stage uninitialized", header); | ||
| 741 | msg->errno = -EINVAL; | ||
| 742 | break; | ||
| 743 | case IPC_GLB_REPLY_NOT_FOUND: | ||
| 744 | trace_ipc_error("error: reply not found", header); | ||
| 745 | msg->errno = -EINVAL; | ||
| 746 | break; | ||
| 747 | case IPC_GLB_REPLY_SOURCE_NOT_STARTED: | ||
| 748 | trace_ipc_error("error: source not started", header); | ||
| 749 | msg->errno = -EINVAL; | ||
| 750 | break; | ||
| 751 | case IPC_GLB_REPLY_INVALID_REQUEST: | ||
| 752 | trace_ipc_error("error: invalid request", header); | ||
| 753 | msg->errno = -EINVAL; | ||
| 754 | break; | ||
| 755 | case IPC_GLB_REPLY_ERROR_INVALID_PARAM: | ||
| 756 | trace_ipc_error("error: invalid parameter", header); | ||
| 757 | msg->errno = -EINVAL; | ||
| 758 | break; | ||
| 759 | default: | ||
| 760 | trace_ipc_error("error: unknown reply", header); | ||
| 761 | msg->errno = -EINVAL; | ||
| 762 | break; | ||
| 763 | } | ||
| 764 | |||
| 765 | /* update any stream states */ | ||
| 766 | hsw_stream_update(hsw, msg); | ||
| 767 | |||
| 768 | /* wake up and return the error if we have waiters on this message ? */ | ||
| 769 | list_del(&msg->list); | ||
| 770 | tx_msg_reply_complete(hsw, msg); | ||
| 771 | |||
| 772 | return 1; | ||
| 773 | } | ||
| 774 | |||
| 775 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) | ||
| 776 | { | ||
| 777 | u32 stream_msg, stream_id, stage_type; | ||
| 778 | struct sst_hsw_stream *stream; | ||
| 779 | int handled = 0; | ||
| 780 | |||
| 781 | stream_msg = msg_get_stream_type(header); | ||
| 782 | stream_id = msg_get_stream_id(header); | ||
| 783 | stage_type = msg_get_stage_type(header); | ||
| 784 | |||
| 785 | stream = get_stream_by_id(hsw, stream_id); | ||
| 786 | if (stream == NULL) | ||
| 787 | return handled; | ||
| 788 | |||
| 789 | stream->header = header; | ||
| 790 | |||
| 791 | switch (stream_msg) { | ||
| 792 | case IPC_STR_STAGE_MESSAGE: | ||
| 793 | dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n", | ||
| 794 | header); | ||
| 795 | break; | ||
| 796 | case IPC_STR_NOTIFICATION: | ||
| 797 | schedule_work(&stream->notify_work); | ||
| 798 | break; | ||
| 799 | default: | ||
| 800 | /* handle pending message complete request */ | ||
| 801 | handled = hsw_process_reply(hsw, header); | ||
| 802 | break; | ||
| 803 | } | ||
| 804 | |||
| 805 | return handled; | ||
| 806 | } | ||
| 807 | |||
| 808 | static int hsw_log_message(struct sst_hsw *hsw, u32 header) | ||
| 809 | { | ||
| 810 | u32 operation = (header & IPC_LOG_OP_MASK) >> IPC_LOG_OP_SHIFT; | ||
| 811 | struct sst_hsw_log_stream *stream = &hsw->log_stream; | ||
| 812 | int ret = 1; | ||
| 813 | |||
| 814 | if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) { | ||
| 815 | dev_err(hsw->dev, | ||
| 816 | "error: log msg not implemented 0x%8.8x\n", header); | ||
| 817 | return 0; | ||
| 818 | } | ||
| 819 | |||
| 820 | mutex_lock(&stream->rw_mutex); | ||
| 821 | stream->last_pos = stream->curr_pos; | ||
| 822 | sst_dsp_inbox_read( | ||
| 823 | hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos)); | ||
| 824 | mutex_unlock(&stream->rw_mutex); | ||
| 825 | |||
| 826 | schedule_work(&stream->notify_work); | ||
| 827 | |||
| 828 | return ret; | ||
| 829 | } | ||
| 830 | |||
| 831 | static int hsw_process_notification(struct sst_hsw *hsw) | ||
| 832 | { | ||
| 833 | struct sst_dsp *sst = hsw->dsp; | ||
| 834 | u32 type, header; | ||
| 835 | int handled = 1; | ||
| 836 | |||
| 837 | header = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
| 838 | type = msg_get_global_type(header); | ||
| 839 | |||
| 840 | trace_ipc_request("processing -->", header); | ||
| 841 | |||
| 842 | /* FW Ready is a special case */ | ||
| 843 | if (!hsw->boot_complete && header & IPC_FW_READY) { | ||
| 844 | hsw_fw_ready(hsw, header); | ||
| 845 | return handled; | ||
| 846 | } | ||
| 847 | |||
| 848 | switch (type) { | ||
| 849 | case IPC_GLB_GET_FW_VERSION: | ||
| 850 | case IPC_GLB_ALLOCATE_STREAM: | ||
| 851 | case IPC_GLB_FREE_STREAM: | ||
| 852 | case IPC_GLB_GET_FW_CAPABILITIES: | ||
| 853 | case IPC_GLB_REQUEST_DUMP: | ||
| 854 | case IPC_GLB_GET_DEVICE_FORMATS: | ||
| 855 | case IPC_GLB_SET_DEVICE_FORMATS: | ||
| 856 | case IPC_GLB_ENTER_DX_STATE: | ||
| 857 | case IPC_GLB_GET_MIXER_STREAM_INFO: | ||
| 858 | case IPC_GLB_MAX_IPC_MESSAGE_TYPE: | ||
| 859 | case IPC_GLB_RESTORE_CONTEXT: | ||
| 860 | case IPC_GLB_SHORT_REPLY: | ||
| 861 | dev_err(hsw->dev, "error: message type %d header 0x%x\n", | ||
| 862 | type, header); | ||
| 863 | break; | ||
| 864 | case IPC_GLB_STREAM_MESSAGE: | ||
| 865 | handled = hsw_stream_message(hsw, header); | ||
| 866 | break; | ||
| 867 | case IPC_GLB_DEBUG_LOG_MESSAGE: | ||
| 868 | handled = hsw_log_message(hsw, header); | ||
| 869 | break; | ||
| 870 | default: | ||
| 871 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", | ||
| 872 | type, header); | ||
| 873 | break; | ||
| 874 | } | ||
| 875 | |||
| 876 | return handled; | ||
| 877 | } | ||
| 878 | |||
| 879 | static irqreturn_t hsw_irq_thread(int irq, void *context) | ||
| 880 | { | ||
| 881 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
| 882 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); | ||
| 883 | u32 ipcx, ipcd; | ||
| 884 | int handled; | ||
| 885 | unsigned long flags; | ||
| 886 | |||
| 887 | spin_lock_irqsave(&sst->spinlock, flags); | ||
| 888 | |||
| 889 | ipcx = sst_dsp_ipc_msg_rx(hsw->dsp); | ||
| 890 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
| 891 | |||
| 892 | /* reply message from DSP */ | ||
| 893 | if (ipcx & SST_IPCX_DONE) { | ||
| 894 | |||
| 895 | /* Handle Immediate reply from DSP Core */ | ||
| 896 | handled = hsw_process_reply(hsw, ipcx); | ||
| 897 | |||
| 898 | if (handled > 0) { | ||
| 899 | /* clear DONE bit - tell DSP we have completed */ | ||
| 900 | sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, | ||
| 901 | SST_IPCX_DONE, 0); | ||
| 902 | |||
| 903 | /* unmask Done interrupt */ | ||
| 904 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
| 905 | SST_IMRX_DONE, 0); | ||
| 906 | } | ||
| 907 | } | ||
| 908 | |||
| 909 | /* new message from DSP */ | ||
| 910 | if (ipcd & SST_IPCD_BUSY) { | ||
| 911 | |||
| 912 | /* Handle Notification and Delayed reply from DSP Core */ | ||
| 913 | handled = hsw_process_notification(hsw); | ||
| 914 | |||
| 915 | /* clear BUSY bit and set DONE bit - accept new messages */ | ||
| 916 | if (handled > 0) { | ||
| 917 | sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, | ||
| 918 | SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); | ||
| 919 | |||
| 920 | /* unmask busy interrupt */ | ||
| 921 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
| 922 | SST_IMRX_BUSY, 0); | ||
| 923 | } | ||
| 924 | } | ||
| 925 | |||
| 926 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
| 927 | |||
| 928 | /* continue to send any remaining messages... */ | ||
| 929 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
| 930 | |||
| 931 | return IRQ_HANDLED; | ||
| 932 | } | ||
| 933 | |||
| 934 | int sst_hsw_fw_get_version(struct sst_hsw *hsw, | ||
| 935 | struct sst_hsw_ipc_fw_version *version) | ||
| 936 | { | ||
| 937 | int ret; | ||
| 938 | |||
| 939 | ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | ||
| 940 | NULL, 0, version, sizeof(*version)); | ||
| 941 | if (ret < 0) | ||
| 942 | dev_err(hsw->dev, "error: get version failed\n"); | ||
| 943 | |||
| 944 | return ret; | ||
| 945 | } | ||
| 946 | |||
| 947 | /* Mixer Controls */ | ||
| 948 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 949 | u32 stage_id, u32 channel) | ||
| 950 | { | ||
| 951 | int ret; | ||
| 952 | |||
| 953 | ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel, | ||
| 954 | &stream->mute_volume[channel]); | ||
| 955 | if (ret < 0) | ||
| 956 | return ret; | ||
| 957 | |||
| 958 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0); | ||
| 959 | if (ret < 0) { | ||
| 960 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
| 961 | stream->reply.stream_hw_id, channel); | ||
| 962 | return ret; | ||
| 963 | } | ||
| 964 | |||
| 965 | stream->mute[channel] = 1; | ||
| 966 | return 0; | ||
| 967 | } | ||
| 968 | |||
| 969 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 970 | u32 stage_id, u32 channel) | ||
| 971 | |||
| 972 | { | ||
| 973 | int ret; | ||
| 974 | |||
| 975 | stream->mute[channel] = 0; | ||
| 976 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, | ||
| 977 | stream->mute_volume[channel]); | ||
| 978 | if (ret < 0) { | ||
| 979 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
| 980 | stream->reply.stream_hw_id, channel); | ||
| 981 | return ret; | ||
| 982 | } | ||
| 983 | |||
| 984 | return 0; | ||
| 985 | } | ||
| 986 | |||
| 987 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 988 | u32 stage_id, u32 channel, u32 *volume) | ||
| 989 | { | ||
| 990 | if (channel > 1) | ||
| 991 | return -EINVAL; | ||
| 992 | |||
| 993 | sst_dsp_read(hsw->dsp, volume, | ||
| 994 | stream->reply.volume_register_address[channel], sizeof(volume)); | ||
| 995 | |||
| 996 | return 0; | ||
| 997 | } | ||
| 998 | |||
| 999 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
| 1000 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
| 1001 | enum sst_hsw_volume_curve curve) | ||
| 1002 | { | ||
| 1003 | /* curve duration in steps of 100ns */ | ||
| 1004 | stream->vol_req.curve_duration = curve_duration; | ||
| 1005 | stream->vol_req.curve_type = curve; | ||
| 1006 | |||
| 1007 | return 0; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | /* stream volume */ | ||
| 1011 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | ||
| 1012 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) | ||
| 1013 | { | ||
| 1014 | struct sst_hsw_ipc_volume_req *req; | ||
| 1015 | u32 header; | ||
| 1016 | int ret; | ||
| 1017 | |||
| 1018 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); | ||
| 1019 | |||
| 1020 | if (channel > 1) | ||
| 1021 | return -EINVAL; | ||
| 1022 | |||
| 1023 | if (stream->mute[channel]) { | ||
| 1024 | stream->mute_volume[channel] = volume; | ||
| 1025 | return 0; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
| 1029 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
| 1030 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | ||
| 1031 | header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); | ||
| 1032 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
| 1033 | |||
| 1034 | req = &stream->vol_req; | ||
| 1035 | req->channel = channel; | ||
| 1036 | req->target_volume = volume; | ||
| 1037 | |||
| 1038 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | ||
| 1039 | if (ret < 0) { | ||
| 1040 | dev_err(hsw->dev, "error: set stream volume failed\n"); | ||
| 1041 | return ret; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | return 0; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
| 1048 | { | ||
| 1049 | int ret; | ||
| 1050 | |||
| 1051 | ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel, | ||
| 1052 | &hsw->mute_volume[channel]); | ||
| 1053 | if (ret < 0) | ||
| 1054 | return ret; | ||
| 1055 | |||
| 1056 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0); | ||
| 1057 | if (ret < 0) { | ||
| 1058 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
| 1059 | channel); | ||
| 1060 | return ret; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | hsw->mute[channel] = 1; | ||
| 1064 | return 0; | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
| 1068 | { | ||
| 1069 | int ret; | ||
| 1070 | |||
| 1071 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, | ||
| 1072 | hsw->mixer_info.volume_register_address[channel]); | ||
| 1073 | if (ret < 0) { | ||
| 1074 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
| 1075 | channel); | ||
| 1076 | return ret; | ||
| 1077 | } | ||
| 1078 | |||
| 1079 | hsw->mute[channel] = 0; | ||
| 1080 | return 0; | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
| 1084 | u32 *volume) | ||
| 1085 | { | ||
| 1086 | if (channel > 1) | ||
| 1087 | return -EINVAL; | ||
| 1088 | |||
| 1089 | sst_dsp_read(hsw->dsp, volume, | ||
| 1090 | hsw->mixer_info.volume_register_address[channel], | ||
| 1091 | sizeof(*volume)); | ||
| 1092 | |||
| 1093 | return 0; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
| 1097 | u64 curve_duration, enum sst_hsw_volume_curve curve) | ||
| 1098 | { | ||
| 1099 | /* curve duration in steps of 100ns */ | ||
| 1100 | hsw->curve_duration = curve_duration; | ||
| 1101 | hsw->curve_type = curve; | ||
| 1102 | |||
| 1103 | return 0; | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | /* global mixer volume */ | ||
| 1107 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
| 1108 | u32 volume) | ||
| 1109 | { | ||
| 1110 | struct sst_hsw_ipc_volume_req req; | ||
| 1111 | u32 header; | ||
| 1112 | int ret; | ||
| 1113 | |||
| 1114 | trace_ipc_request("set mixer volume", volume); | ||
| 1115 | |||
| 1116 | /* set both at same time ? */ | ||
| 1117 | if (channel == 2) { | ||
| 1118 | if (hsw->mute[0] && hsw->mute[1]) { | ||
| 1119 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | ||
| 1120 | return 0; | ||
| 1121 | } else if (hsw->mute[0]) | ||
| 1122 | req.channel = 1; | ||
| 1123 | else if (hsw->mute[1]) | ||
| 1124 | req.channel = 0; | ||
| 1125 | else | ||
| 1126 | req.channel = 0xffffffff; | ||
| 1127 | } else { | ||
| 1128 | /* set only 1 channel */ | ||
| 1129 | if (hsw->mute[channel]) { | ||
| 1130 | hsw->mute_volume[channel] = volume; | ||
| 1131 | return 0; | ||
| 1132 | } | ||
| 1133 | req.channel = channel; | ||
| 1134 | } | ||
| 1135 | |||
| 1136 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
| 1137 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
| 1138 | header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); | ||
| 1139 | header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); | ||
| 1140 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
| 1141 | |||
| 1142 | req.curve_duration = hsw->curve_duration; | ||
| 1143 | req.curve_type = hsw->curve_type; | ||
| 1144 | req.target_volume = volume; | ||
| 1145 | |||
| 1146 | ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0); | ||
| 1147 | if (ret < 0) { | ||
| 1148 | dev_err(hsw->dev, "error: set mixer volume failed\n"); | ||
| 1149 | return ret; | ||
| 1150 | } | ||
| 1151 | |||
| 1152 | return 0; | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | /* Stream API */ | ||
| 1156 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | ||
| 1157 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data), | ||
| 1158 | void *data) | ||
| 1159 | { | ||
| 1160 | struct sst_hsw_stream *stream; | ||
| 1161 | |||
| 1162 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
| 1163 | if (stream == NULL) | ||
| 1164 | return NULL; | ||
| 1165 | |||
| 1166 | list_add(&stream->node, &hsw->stream_list); | ||
| 1167 | stream->notify_position = notify_position; | ||
| 1168 | stream->pdata = data; | ||
| 1169 | stream->hsw = hsw; | ||
| 1170 | stream->host_id = id; | ||
| 1171 | |||
| 1172 | /* work to process notification messages */ | ||
| 1173 | INIT_WORK(&stream->notify_work, hsw_notification_work); | ||
| 1174 | |||
| 1175 | return stream; | ||
| 1176 | } | ||
| 1177 | |||
| 1178 | int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
| 1179 | { | ||
| 1180 | u32 header; | ||
| 1181 | int ret = 0; | ||
| 1182 | |||
| 1183 | /* dont free DSP streams that are not commited */ | ||
| 1184 | if (!stream->commited) | ||
| 1185 | goto out; | ||
| 1186 | |||
| 1187 | trace_ipc_request("stream free", stream->host_id); | ||
| 1188 | |||
| 1189 | stream->free_req.stream_id = stream->reply.stream_hw_id; | ||
| 1190 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); | ||
| 1191 | |||
| 1192 | ret = ipc_tx_message_wait(hsw, header, &stream->free_req, | ||
| 1193 | sizeof(stream->free_req), NULL, 0); | ||
| 1194 | if (ret < 0) { | ||
| 1195 | dev_err(hsw->dev, "error: free stream %d failed\n", | ||
| 1196 | stream->free_req.stream_id); | ||
| 1197 | return -EAGAIN; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | trace_hsw_stream_free_req(stream, &stream->free_req); | ||
| 1201 | |||
| 1202 | out: | ||
| 1203 | list_del(&stream->node); | ||
| 1204 | kfree(stream); | ||
| 1205 | |||
| 1206 | return ret; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | int sst_hsw_stream_set_bits(struct sst_hsw *hsw, | ||
| 1210 | struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits) | ||
| 1211 | { | ||
| 1212 | if (stream->commited) { | ||
| 1213 | dev_err(hsw->dev, "error: stream committed for set bits\n"); | ||
| 1214 | return -EINVAL; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | stream->request.format.bitdepth = bits; | ||
| 1218 | return 0; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | ||
| 1222 | struct sst_hsw_stream *stream, int channels) | ||
| 1223 | { | ||
| 1224 | if (stream->commited) { | ||
| 1225 | dev_err(hsw->dev, "error: stream committed for set channels\n"); | ||
| 1226 | return -EINVAL; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* stereo is only supported atm */ | ||
| 1230 | if (channels != 2) | ||
| 1231 | return -EINVAL; | ||
| 1232 | |||
| 1233 | stream->request.format.ch_num = channels; | ||
| 1234 | return 0; | ||
| 1235 | } | ||
| 1236 | |||
| 1237 | int sst_hsw_stream_set_rate(struct sst_hsw *hsw, | ||
| 1238 | struct sst_hsw_stream *stream, int rate) | ||
| 1239 | { | ||
| 1240 | if (stream->commited) { | ||
| 1241 | dev_err(hsw->dev, "error: stream committed for set rate\n"); | ||
| 1242 | return -EINVAL; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | stream->request.format.frequency = rate; | ||
| 1246 | return 0; | ||
| 1247 | } | ||
| 1248 | |||
| 1249 | int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | ||
| 1250 | struct sst_hsw_stream *stream, u32 map, | ||
| 1251 | enum sst_hsw_channel_config config) | ||
| 1252 | { | ||
| 1253 | if (stream->commited) { | ||
| 1254 | dev_err(hsw->dev, "error: stream committed for set map\n"); | ||
| 1255 | return -EINVAL; | ||
| 1256 | } | ||
| 1257 | |||
| 1258 | stream->request.format.map = map; | ||
| 1259 | stream->request.format.config = config; | ||
| 1260 | return 0; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, | ||
| 1264 | struct sst_hsw_stream *stream, enum sst_hsw_interleaving style) | ||
| 1265 | { | ||
| 1266 | if (stream->commited) { | ||
| 1267 | dev_err(hsw->dev, "error: stream committed for set style\n"); | ||
| 1268 | return -EINVAL; | ||
| 1269 | } | ||
| 1270 | |||
| 1271 | stream->request.format.style = style; | ||
| 1272 | return 0; | ||
| 1273 | } | ||
| 1274 | |||
| 1275 | int sst_hsw_stream_set_valid(struct sst_hsw *hsw, | ||
| 1276 | struct sst_hsw_stream *stream, u32 bits) | ||
| 1277 | { | ||
| 1278 | if (stream->commited) { | ||
| 1279 | dev_err(hsw->dev, "error: stream committed for set valid bits\n"); | ||
| 1280 | return -EINVAL; | ||
| 1281 | } | ||
| 1282 | |||
| 1283 | stream->request.format.valid_bit = bits; | ||
| 1284 | return 0; | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | /* Stream Configuration */ | ||
| 1288 | int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 1289 | enum sst_hsw_stream_path_id path_id, | ||
| 1290 | enum sst_hsw_stream_type stream_type, | ||
| 1291 | enum sst_hsw_stream_format format_id) | ||
| 1292 | { | ||
| 1293 | if (stream->commited) { | ||
| 1294 | dev_err(hsw->dev, "error: stream committed for set format\n"); | ||
| 1295 | return -EINVAL; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | stream->request.path_id = path_id; | ||
| 1299 | stream->request.stream_type = stream_type; | ||
| 1300 | stream->request.format_id = format_id; | ||
| 1301 | |||
| 1302 | trace_hsw_stream_alloc_request(stream, &stream->request); | ||
| 1303 | |||
| 1304 | return 0; | ||
| 1305 | } | ||
| 1306 | |||
| 1307 | int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 1308 | u32 ring_pt_address, u32 num_pages, | ||
| 1309 | u32 ring_size, u32 ring_offset, u32 ring_first_pfn) | ||
| 1310 | { | ||
| 1311 | if (stream->commited) { | ||
| 1312 | dev_err(hsw->dev, "error: stream committed for buffer\n"); | ||
| 1313 | return -EINVAL; | ||
| 1314 | } | ||
| 1315 | |||
| 1316 | stream->request.ringinfo.ring_pt_address = ring_pt_address; | ||
| 1317 | stream->request.ringinfo.num_pages = num_pages; | ||
| 1318 | stream->request.ringinfo.ring_size = ring_size; | ||
| 1319 | stream->request.ringinfo.ring_offset = ring_offset; | ||
| 1320 | stream->request.ringinfo.ring_first_pfn = ring_first_pfn; | ||
| 1321 | |||
| 1322 | trace_hsw_stream_buffer(stream); | ||
| 1323 | |||
| 1324 | return 0; | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | ||
| 1328 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | ||
| 1329 | u32 entry_point) | ||
| 1330 | { | ||
| 1331 | struct sst_hsw_module_map *map = &stream->request.map; | ||
| 1332 | |||
| 1333 | if (stream->commited) { | ||
| 1334 | dev_err(hsw->dev, "error: stream committed for set module\n"); | ||
| 1335 | return -EINVAL; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | /* only support initial module atm */ | ||
| 1339 | map->module_entries_count = 1; | ||
| 1340 | map->module_entries[0].module_id = module_id; | ||
| 1341 | map->module_entries[0].entry_point = entry_point; | ||
| 1342 | |||
| 1343 | return 0; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | ||
| 1347 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
| 1348 | { | ||
| 1349 | if (stream->commited) { | ||
| 1350 | dev_err(hsw->dev, "error: stream committed for set pmem\n"); | ||
| 1351 | return -EINVAL; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | stream->request.persistent_mem.offset = offset; | ||
| 1355 | stream->request.persistent_mem.size = size; | ||
| 1356 | |||
| 1357 | return 0; | ||
| 1358 | } | ||
| 1359 | |||
| 1360 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
| 1361 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
| 1362 | { | ||
| 1363 | if (stream->commited) { | ||
| 1364 | dev_err(hsw->dev, "error: stream committed for set smem\n"); | ||
| 1365 | return -EINVAL; | ||
| 1366 | } | ||
| 1367 | |||
| 1368 | stream->request.scratch_mem.offset = offset; | ||
| 1369 | stream->request.scratch_mem.size = size; | ||
| 1370 | |||
| 1371 | return 0; | ||
| 1372 | } | ||
| 1373 | |||
| 1374 | int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
| 1375 | { | ||
| 1376 | struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request; | ||
| 1377 | struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply; | ||
| 1378 | u32 header; | ||
| 1379 | int ret; | ||
| 1380 | |||
| 1381 | trace_ipc_request("stream alloc", stream->host_id); | ||
| 1382 | |||
| 1383 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); | ||
| 1384 | |||
| 1385 | ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req), | ||
| 1386 | reply, sizeof(*reply)); | ||
| 1387 | if (ret < 0) { | ||
| 1388 | dev_err(hsw->dev, "error: stream commit failed\n"); | ||
| 1389 | return ret; | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | stream->commited = 1; | ||
| 1393 | trace_hsw_stream_alloc_reply(stream); | ||
| 1394 | |||
| 1395 | return 0; | ||
| 1396 | } | ||
| 1397 | |||
| 1398 | /* Stream Information - these calls could be inline but we want the IPC | ||
| 1399 | ABI to be opaque to client PCM drivers to cope with any future ABI changes */ | ||
| 1400 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | ||
| 1401 | struct sst_hsw_stream *stream) | ||
| 1402 | { | ||
| 1403 | return stream->reply.stream_hw_id; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | ||
| 1407 | struct sst_hsw_stream *stream) | ||
| 1408 | { | ||
| 1409 | return stream->reply.mixer_hw_id; | ||
| 1410 | } | ||
| 1411 | |||
| 1412 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | ||
| 1413 | struct sst_hsw_stream *stream) | ||
| 1414 | { | ||
| 1415 | return stream->reply.read_position_register_address; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | ||
| 1419 | struct sst_hsw_stream *stream) | ||
| 1420 | { | ||
| 1421 | return stream->reply.presentation_position_register_address; | ||
| 1422 | } | ||
| 1423 | |||
| 1424 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | ||
| 1425 | struct sst_hsw_stream *stream, u32 channel) | ||
| 1426 | { | ||
| 1427 | if (channel >= 2) | ||
| 1428 | return 0; | ||
| 1429 | |||
| 1430 | return stream->reply.peak_meter_register_address[channel]; | ||
| 1431 | } | ||
| 1432 | |||
| 1433 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | ||
| 1434 | struct sst_hsw_stream *stream, u32 channel) | ||
| 1435 | { | ||
| 1436 | if (channel >= 2) | ||
| 1437 | return 0; | ||
| 1438 | |||
| 1439 | return stream->reply.volume_register_address[channel]; | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw) | ||
| 1443 | { | ||
| 1444 | struct sst_hsw_ipc_stream_info_reply *reply; | ||
| 1445 | u32 header; | ||
| 1446 | int ret; | ||
| 1447 | |||
| 1448 | reply = &hsw->mixer_info; | ||
| 1449 | header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); | ||
| 1450 | |||
| 1451 | trace_ipc_request("get global mixer info", 0); | ||
| 1452 | |||
| 1453 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply)); | ||
| 1454 | if (ret < 0) { | ||
| 1455 | dev_err(hsw->dev, "error: get stream info failed\n"); | ||
| 1456 | return ret; | ||
| 1457 | } | ||
| 1458 | |||
| 1459 | trace_hsw_mixer_info_reply(reply); | ||
| 1460 | |||
| 1461 | return 0; | ||
| 1462 | } | ||
| 1463 | |||
| 1464 | /* Send stream command */ | ||
| 1465 | static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, | ||
| 1466 | int stream_id, int wait) | ||
| 1467 | { | ||
| 1468 | u32 header; | ||
| 1469 | |||
| 1470 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type); | ||
| 1471 | header |= (stream_id << IPC_STR_ID_SHIFT); | ||
| 1472 | |||
| 1473 | if (wait) | ||
| 1474 | return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | ||
| 1475 | else | ||
| 1476 | return ipc_tx_message_nowait(hsw, header, NULL, 0); | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | /* Stream ALSA trigger operations */ | ||
| 1480 | int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 1481 | int wait) | ||
| 1482 | { | ||
| 1483 | int ret; | ||
| 1484 | |||
| 1485 | trace_ipc_request("stream pause", stream->reply.stream_hw_id); | ||
| 1486 | |||
| 1487 | ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE, | ||
| 1488 | stream->reply.stream_hw_id, wait); | ||
| 1489 | if (ret < 0) | ||
| 1490 | dev_err(hsw->dev, "error: failed to pause stream %d\n", | ||
| 1491 | stream->reply.stream_hw_id); | ||
| 1492 | |||
| 1493 | return ret; | ||
| 1494 | } | ||
| 1495 | |||
| 1496 | int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 1497 | int wait) | ||
| 1498 | { | ||
| 1499 | int ret; | ||
| 1500 | |||
| 1501 | trace_ipc_request("stream resume", stream->reply.stream_hw_id); | ||
| 1502 | |||
| 1503 | ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME, | ||
| 1504 | stream->reply.stream_hw_id, wait); | ||
| 1505 | if (ret < 0) | ||
| 1506 | dev_err(hsw->dev, "error: failed to resume stream %d\n", | ||
| 1507 | stream->reply.stream_hw_id); | ||
| 1508 | |||
| 1509 | return ret; | ||
| 1510 | } | ||
| 1511 | |||
| 1512 | int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
| 1513 | { | ||
| 1514 | int ret, tries = 10; | ||
| 1515 | |||
| 1516 | /* dont reset streams that are not commited */ | ||
| 1517 | if (!stream->commited) | ||
| 1518 | return 0; | ||
| 1519 | |||
| 1520 | /* wait for pause to complete before we reset the stream */ | ||
| 1521 | while (stream->running && tries--) | ||
| 1522 | msleep(1); | ||
| 1523 | if (!tries) { | ||
| 1524 | dev_err(hsw->dev, "error: reset stream %d still running\n", | ||
| 1525 | stream->reply.stream_hw_id); | ||
| 1526 | return -EINVAL; | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | trace_ipc_request("stream reset", stream->reply.stream_hw_id); | ||
| 1530 | |||
| 1531 | ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET, | ||
| 1532 | stream->reply.stream_hw_id, 1); | ||
| 1533 | if (ret < 0) | ||
| 1534 | dev_err(hsw->dev, "error: failed to reset stream %d\n", | ||
| 1535 | stream->reply.stream_hw_id); | ||
| 1536 | return ret; | ||
| 1537 | } | ||
| 1538 | |||
| 1539 | /* Stream pointer positions */ | ||
| 1540 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | ||
| 1541 | struct sst_hsw_stream *stream) | ||
| 1542 | { | ||
| 1543 | return stream->rpos.position; | ||
| 1544 | } | ||
| 1545 | |||
| 1546 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
| 1547 | struct sst_hsw_stream *stream, u32 stage_id, u32 position) | ||
| 1548 | { | ||
| 1549 | u32 header; | ||
| 1550 | int ret; | ||
| 1551 | |||
| 1552 | trace_stream_write_position(stream->reply.stream_hw_id, position); | ||
| 1553 | |||
| 1554 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
| 1555 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
| 1556 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | ||
| 1557 | header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT); | ||
| 1558 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
| 1559 | stream->wpos.position = position; | ||
| 1560 | |||
| 1561 | ret = ipc_tx_message_nowait(hsw, header, &stream->wpos, | ||
| 1562 | sizeof(stream->wpos)); | ||
| 1563 | if (ret < 0) | ||
| 1564 | dev_err(hsw->dev, "error: stream %d set position %d failed\n", | ||
| 1565 | stream->reply.stream_hw_id, position); | ||
| 1566 | |||
| 1567 | return ret; | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | /* physical BE config */ | ||
| 1571 | int sst_hsw_device_set_config(struct sst_hsw *hsw, | ||
| 1572 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, | ||
| 1573 | enum sst_hsw_device_mode mode, u32 clock_divider) | ||
| 1574 | { | ||
| 1575 | struct sst_hsw_ipc_device_config_req config; | ||
| 1576 | u32 header; | ||
| 1577 | int ret; | ||
| 1578 | |||
| 1579 | trace_ipc_request("set device config", dev); | ||
| 1580 | |||
| 1581 | config.ssp_interface = dev; | ||
| 1582 | config.clock_frequency = mclk; | ||
| 1583 | config.mode = mode; | ||
| 1584 | config.clock_divider = clock_divider; | ||
| 1585 | |||
| 1586 | trace_hsw_device_config_req(&config); | ||
| 1587 | |||
| 1588 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); | ||
| 1589 | |||
| 1590 | ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config), | ||
| 1591 | NULL, 0); | ||
| 1592 | if (ret < 0) | ||
| 1593 | dev_err(hsw->dev, "error: set device formats failed\n"); | ||
| 1594 | |||
| 1595 | return ret; | ||
| 1596 | } | ||
| 1597 | EXPORT_SYMBOL_GPL(sst_hsw_device_set_config); | ||
| 1598 | |||
| 1599 | /* DX Config */ | ||
| 1600 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, | ||
| 1601 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) | ||
| 1602 | { | ||
| 1603 | u32 header, state_; | ||
| 1604 | int ret; | ||
| 1605 | |||
| 1606 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); | ||
| 1607 | state_ = state; | ||
| 1608 | |||
| 1609 | trace_ipc_request("PM enter Dx state", state); | ||
| 1610 | |||
| 1611 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | ||
| 1612 | dx, sizeof(dx)); | ||
| 1613 | if (ret < 0) { | ||
| 1614 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | ||
| 1615 | return ret; | ||
| 1616 | } | ||
| 1617 | |||
| 1618 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | ||
| 1619 | dx->entries_no, state); | ||
| 1620 | |||
| 1621 | memcpy(&hsw->dx, dx, sizeof(*dx)); | ||
| 1622 | return 0; | ||
| 1623 | } | ||
| 1624 | |||
| 1625 | /* Used to save state into hsw->dx_reply */ | ||
| 1626 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | ||
| 1627 | u32 *offset, u32 *size, u32 *source) | ||
| 1628 | { | ||
| 1629 | struct sst_hsw_ipc_dx_memory_item *dx_mem; | ||
| 1630 | struct sst_hsw_ipc_dx_reply *dx_reply; | ||
| 1631 | int entry_no; | ||
| 1632 | |||
| 1633 | dx_reply = &hsw->dx; | ||
| 1634 | entry_no = dx_reply->entries_no; | ||
| 1635 | |||
| 1636 | trace_ipc_request("PM get Dx state", entry_no); | ||
| 1637 | |||
| 1638 | if (item >= entry_no) | ||
| 1639 | return -EINVAL; | ||
| 1640 | |||
| 1641 | dx_mem = &dx_reply->mem_info[item]; | ||
| 1642 | *offset = dx_mem->offset; | ||
| 1643 | *size = dx_mem->size; | ||
| 1644 | *source = dx_mem->source; | ||
| 1645 | |||
| 1646 | return 0; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | static int msg_empty_list_init(struct sst_hsw *hsw) | ||
| 1650 | { | ||
| 1651 | int i; | ||
| 1652 | |||
| 1653 | hsw->msg = kzalloc(sizeof(struct ipc_message) * | ||
| 1654 | IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
| 1655 | if (hsw->msg == NULL) | ||
| 1656 | return -ENOMEM; | ||
| 1657 | |||
| 1658 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
| 1659 | init_waitqueue_head(&hsw->msg[i].waitq); | ||
| 1660 | list_add(&hsw->msg[i].list, &hsw->empty_list); | ||
| 1661 | } | ||
| 1662 | |||
| 1663 | return 0; | ||
| 1664 | } | ||
| 1665 | |||
| 1666 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
| 1667 | struct sst_module *scratch) | ||
| 1668 | { | ||
| 1669 | hsw->scratch = scratch; | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | ||
| 1673 | { | ||
| 1674 | return hsw->dsp; | ||
| 1675 | } | ||
| 1676 | |||
| 1677 | static struct sst_dsp_device hsw_dev = { | ||
| 1678 | .thread = hsw_irq_thread, | ||
| 1679 | .ops = &haswell_ops, | ||
| 1680 | }; | ||
| 1681 | |||
| 1682 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | ||
| 1683 | { | ||
| 1684 | struct sst_hsw_ipc_fw_version version; | ||
| 1685 | struct sst_hsw *hsw; | ||
| 1686 | struct sst_fw *hsw_sst_fw; | ||
| 1687 | int ret; | ||
| 1688 | |||
| 1689 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | ||
| 1690 | |||
| 1691 | hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL); | ||
| 1692 | if (hsw == NULL) | ||
| 1693 | return -ENOMEM; | ||
| 1694 | |||
| 1695 | hsw->dev = dev; | ||
| 1696 | INIT_LIST_HEAD(&hsw->stream_list); | ||
| 1697 | INIT_LIST_HEAD(&hsw->tx_list); | ||
| 1698 | INIT_LIST_HEAD(&hsw->rx_list); | ||
| 1699 | INIT_LIST_HEAD(&hsw->empty_list); | ||
| 1700 | init_waitqueue_head(&hsw->boot_wait); | ||
| 1701 | init_waitqueue_head(&hsw->wait_txq); | ||
| 1702 | |||
| 1703 | ret = msg_empty_list_init(hsw); | ||
| 1704 | if (ret < 0) | ||
| 1705 | goto list_err; | ||
| 1706 | |||
| 1707 | /* start the IPC message thread */ | ||
| 1708 | init_kthread_worker(&hsw->kworker); | ||
| 1709 | hsw->tx_thread = kthread_run(kthread_worker_fn, | ||
| 1710 | &hsw->kworker, | ||
| 1711 | dev_name(hsw->dev)); | ||
| 1712 | if (IS_ERR(hsw->tx_thread)) { | ||
| 1713 | ret = PTR_ERR(hsw->tx_thread); | ||
| 1714 | dev_err(hsw->dev, "error: failed to create message TX task\n"); | ||
| 1715 | goto list_err; | ||
| 1716 | } | ||
| 1717 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); | ||
| 1718 | |||
| 1719 | hsw_dev.thread_context = hsw; | ||
| 1720 | |||
| 1721 | /* init SST shim */ | ||
| 1722 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); | ||
| 1723 | if (hsw->dsp == NULL) { | ||
| 1724 | ret = -ENODEV; | ||
| 1725 | goto list_err; | ||
| 1726 | } | ||
| 1727 | |||
| 1728 | /* keep the DSP in reset state for base FW loading */ | ||
| 1729 | sst_dsp_reset(hsw->dsp); | ||
| 1730 | |||
| 1731 | hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | ||
| 1732 | |||
| 1733 | if (hsw_sst_fw == NULL) { | ||
| 1734 | ret = -ENODEV; | ||
| 1735 | dev_err(dev, "error: failed to load firmware\n"); | ||
| 1736 | goto fw_err; | ||
| 1737 | } | ||
| 1738 | |||
| 1739 | /* wait for DSP boot completion */ | ||
| 1740 | sst_dsp_boot(hsw->dsp); | ||
| 1741 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | ||
| 1742 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
| 1743 | if (ret == 0) { | ||
| 1744 | ret = -EIO; | ||
| 1745 | dev_err(hsw->dev, "error: ADSP boot timeout\n"); | ||
| 1746 | goto boot_err; | ||
| 1747 | } | ||
| 1748 | |||
| 1749 | /* get the FW version */ | ||
| 1750 | sst_hsw_fw_get_version(hsw, &version); | ||
| 1751 | dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n", | ||
| 1752 | version.type, version.major, version.minor, version.build); | ||
| 1753 | |||
| 1754 | /* get the globalmixer */ | ||
| 1755 | ret = sst_hsw_mixer_get_info(hsw); | ||
| 1756 | if (ret < 0) { | ||
| 1757 | dev_err(hsw->dev, "error: failed to get stream info\n"); | ||
| 1758 | goto boot_err; | ||
| 1759 | } | ||
| 1760 | |||
| 1761 | pdata->dsp = hsw; | ||
| 1762 | return 0; | ||
| 1763 | |||
| 1764 | boot_err: | ||
| 1765 | sst_dsp_reset(hsw->dsp); | ||
| 1766 | sst_fw_free(hsw_sst_fw); | ||
| 1767 | fw_err: | ||
| 1768 | sst_dsp_free(hsw->dsp); | ||
| 1769 | kfree(hsw->msg); | ||
| 1770 | list_err: | ||
| 1771 | return ret; | ||
| 1772 | } | ||
| 1773 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | ||
| 1774 | |||
| 1775 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | ||
| 1776 | { | ||
| 1777 | struct sst_hsw *hsw = pdata->dsp; | ||
| 1778 | |||
| 1779 | sst_dsp_reset(hsw->dsp); | ||
| 1780 | sst_fw_free_all(hsw->dsp); | ||
| 1781 | sst_dsp_free(hsw->dsp); | ||
| 1782 | kfree(hsw->scratch); | ||
| 1783 | kfree(hsw->msg); | ||
| 1784 | } | ||
| 1785 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h new file mode 100644 index 000000000000..d517929ccc38 --- /dev/null +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
| @@ -0,0 +1,488 @@ | |||
| 1 | /* | ||
| 2 | * Intel SST Haswell/Broadwell IPC Support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #ifndef __SST_HASWELL_IPC_H | ||
| 18 | #define __SST_HASWELL_IPC_H | ||
| 19 | |||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | |||
| 24 | #define SST_HSW_NO_CHANNELS 2 | ||
| 25 | #define SST_HSW_MAX_DX_REGIONS 14 | ||
| 26 | |||
| 27 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 | ||
| 28 | #define SST_HSW_GLOBAL_LOG 15 | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Upfront defined maximum message size that is | ||
| 32 | * expected by the in/out communication pipes in FW. | ||
| 33 | */ | ||
| 34 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 | ||
| 35 | #define SST_HSW_MAX_INFO_SIZE 64 | ||
| 36 | #define SST_HSW_BUILD_HASH_LENGTH 40 | ||
| 37 | |||
| 38 | struct sst_hsw; | ||
| 39 | struct sst_hsw_stream; | ||
| 40 | struct sst_hsw_log_stream; | ||
| 41 | struct sst_pdata; | ||
| 42 | struct sst_module; | ||
| 43 | extern struct sst_ops haswell_ops; | ||
| 44 | |||
| 45 | /* Stream Allocate Path ID */ | ||
| 46 | enum sst_hsw_stream_path_id { | ||
| 47 | SST_HSW_STREAM_PATH_SSP0_OUT = 0, | ||
| 48 | SST_HSW_STREAM_PATH_SSP0_IN = 1, | ||
| 49 | SST_HSW_STREAM_PATH_MAX_PATH_ID = 2, | ||
| 50 | }; | ||
| 51 | |||
| 52 | /* Stream Allocate Stream Type */ | ||
| 53 | enum sst_hsw_stream_type { | ||
| 54 | SST_HSW_STREAM_TYPE_RENDER = 0, | ||
| 55 | SST_HSW_STREAM_TYPE_SYSTEM = 1, | ||
| 56 | SST_HSW_STREAM_TYPE_CAPTURE = 2, | ||
| 57 | SST_HSW_STREAM_TYPE_LOOPBACK = 3, | ||
| 58 | SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4, | ||
| 59 | }; | ||
| 60 | |||
| 61 | /* Stream Allocate Stream Format */ | ||
| 62 | enum sst_hsw_stream_format { | ||
| 63 | SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0, | ||
| 64 | SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1, | ||
| 65 | SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2, | ||
| 66 | SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3, | ||
| 67 | }; | ||
| 68 | |||
| 69 | /* Device ID */ | ||
| 70 | enum sst_hsw_device_id { | ||
| 71 | SST_HSW_DEVICE_SSP_0 = 0, | ||
| 72 | SST_HSW_DEVICE_SSP_1 = 1, | ||
| 73 | }; | ||
| 74 | |||
| 75 | /* Device Master Clock Frequency */ | ||
| 76 | enum sst_hsw_device_mclk { | ||
| 77 | SST_HSW_DEVICE_MCLK_OFF = 0, | ||
| 78 | SST_HSW_DEVICE_MCLK_FREQ_6_MHZ = 1, | ||
| 79 | SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2, | ||
| 80 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3, | ||
| 81 | }; | ||
| 82 | |||
| 83 | /* Device Clock Master */ | ||
| 84 | enum sst_hsw_device_mode { | ||
| 85 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, | ||
| 86 | SST_HSW_DEVICE_CLOCK_MASTER = 1, | ||
| 87 | }; | ||
| 88 | |||
| 89 | /* DX Power State */ | ||
| 90 | enum sst_hsw_dx_state { | ||
| 91 | SST_HSW_DX_STATE_D0 = 0, | ||
| 92 | SST_HSW_DX_STATE_D1 = 1, | ||
| 93 | SST_HSW_DX_STATE_D3 = 3, | ||
| 94 | SST_HSW_DX_STATE_MAX = 3, | ||
| 95 | }; | ||
| 96 | |||
| 97 | /* Audio stream stage IDs */ | ||
| 98 | enum sst_hsw_fx_stage_id { | ||
| 99 | SST_HSW_STAGE_ID_WAVES = 0, | ||
| 100 | SST_HSW_STAGE_ID_DTS = 1, | ||
| 101 | SST_HSW_STAGE_ID_DOLBY = 2, | ||
| 102 | SST_HSW_STAGE_ID_BOOST = 3, | ||
| 103 | SST_HSW_STAGE_ID_MAX_FX_ID | ||
| 104 | }; | ||
| 105 | |||
| 106 | /* DX State Type */ | ||
| 107 | enum sst_hsw_dx_type { | ||
| 108 | SST_HSW_DX_TYPE_FW_IMAGE = 0, | ||
| 109 | SST_HSW_DX_TYPE_MEMORY_DUMP = 1 | ||
| 110 | }; | ||
| 111 | |||
| 112 | /* Volume Curve Type*/ | ||
| 113 | enum sst_hsw_volume_curve { | ||
| 114 | SST_HSW_VOLUME_CURVE_NONE = 0, | ||
| 115 | SST_HSW_VOLUME_CURVE_FADE = 1 | ||
| 116 | }; | ||
| 117 | |||
| 118 | /* Sample ordering */ | ||
| 119 | enum sst_hsw_interleaving { | ||
| 120 | SST_HSW_INTERLEAVING_PER_CHANNEL = 0, | ||
| 121 | SST_HSW_INTERLEAVING_PER_SAMPLE = 1, | ||
| 122 | }; | ||
| 123 | |||
| 124 | /* Channel indices */ | ||
| 125 | enum sst_hsw_channel_index { | ||
| 126 | SST_HSW_CHANNEL_LEFT = 0, | ||
| 127 | SST_HSW_CHANNEL_CENTER = 1, | ||
| 128 | SST_HSW_CHANNEL_RIGHT = 2, | ||
| 129 | SST_HSW_CHANNEL_LEFT_SURROUND = 3, | ||
| 130 | SST_HSW_CHANNEL_CENTER_SURROUND = 3, | ||
| 131 | SST_HSW_CHANNEL_RIGHT_SURROUND = 4, | ||
| 132 | SST_HSW_CHANNEL_LFE = 7, | ||
| 133 | SST_HSW_CHANNEL_INVALID = 0xF, | ||
| 134 | }; | ||
| 135 | |||
| 136 | /* List of supported channel maps. */ | ||
| 137 | enum sst_hsw_channel_config { | ||
| 138 | SST_HSW_CHANNEL_CONFIG_MONO = 0, /* mono only. */ | ||
| 139 | SST_HSW_CHANNEL_CONFIG_STEREO = 1, /* L & R. */ | ||
| 140 | SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */ | ||
| 141 | SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */ | ||
| 142 | SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */ | ||
| 143 | SST_HSW_CHANNEL_CONFIG_QUATRO = 5, /* L, R, Ls & Rs; PCM only. */ | ||
| 144 | SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */ | ||
| 145 | SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */ | ||
| 146 | SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */ | ||
| 147 | SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */ | ||
| 148 | SST_HSW_CHANNEL_CONFIG_INVALID, | ||
| 149 | }; | ||
| 150 | |||
| 151 | /* List of supported bit depths. */ | ||
| 152 | enum sst_hsw_bitdepth { | ||
| 153 | SST_HSW_DEPTH_8BIT = 8, | ||
| 154 | SST_HSW_DEPTH_16BIT = 16, | ||
| 155 | SST_HSW_DEPTH_24BIT = 24, /* Default. */ | ||
| 156 | SST_HSW_DEPTH_32BIT = 32, | ||
| 157 | SST_HSW_DEPTH_INVALID = 33, | ||
| 158 | }; | ||
| 159 | |||
| 160 | enum sst_hsw_module_id { | ||
| 161 | SST_HSW_MODULE_BASE_FW = 0x0, | ||
| 162 | SST_HSW_MODULE_MP3 = 0x1, | ||
| 163 | SST_HSW_MODULE_AAC_5_1 = 0x2, | ||
| 164 | SST_HSW_MODULE_AAC_2_0 = 0x3, | ||
| 165 | SST_HSW_MODULE_SRC = 0x4, | ||
| 166 | SST_HSW_MODULE_WAVES = 0x5, | ||
| 167 | SST_HSW_MODULE_DOLBY = 0x6, | ||
| 168 | SST_HSW_MODULE_BOOST = 0x7, | ||
| 169 | SST_HSW_MODULE_LPAL = 0x8, | ||
| 170 | SST_HSW_MODULE_DTS = 0x9, | ||
| 171 | SST_HSW_MODULE_PCM_CAPTURE = 0xA, | ||
| 172 | SST_HSW_MODULE_PCM_SYSTEM = 0xB, | ||
| 173 | SST_HSW_MODULE_PCM_REFERENCE = 0xC, | ||
| 174 | SST_HSW_MODULE_PCM = 0xD, | ||
| 175 | SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE, | ||
| 176 | SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF, | ||
| 177 | SST_HSW_MAX_MODULE_ID, | ||
| 178 | }; | ||
| 179 | |||
| 180 | enum sst_hsw_performance_action { | ||
| 181 | SST_HSW_PERF_START = 0, | ||
| 182 | SST_HSW_PERF_STOP = 1, | ||
| 183 | }; | ||
| 184 | |||
| 185 | /* SST firmware module info */ | ||
| 186 | struct sst_hsw_module_info { | ||
| 187 | u8 name[SST_HSW_MAX_INFO_SIZE]; | ||
| 188 | u8 version[SST_HSW_MAX_INFO_SIZE]; | ||
| 189 | } __attribute__((packed)); | ||
| 190 | |||
| 191 | /* Module entry point */ | ||
| 192 | struct sst_hsw_module_entry { | ||
| 193 | enum sst_hsw_module_id module_id; | ||
| 194 | u32 entry_point; | ||
| 195 | } __attribute__((packed)); | ||
| 196 | |||
| 197 | /* Module map - alignement matches DSP */ | ||
| 198 | struct sst_hsw_module_map { | ||
| 199 | u8 module_entries_count; | ||
| 200 | struct sst_hsw_module_entry module_entries[1]; | ||
| 201 | } __attribute__((packed)); | ||
| 202 | |||
| 203 | struct sst_hsw_memory_info { | ||
| 204 | u32 offset; | ||
| 205 | u32 size; | ||
| 206 | } __attribute__((packed)); | ||
| 207 | |||
| 208 | struct sst_hsw_fx_enable { | ||
| 209 | struct sst_hsw_module_map module_map; | ||
| 210 | struct sst_hsw_memory_info persistent_mem; | ||
| 211 | } __attribute__((packed)); | ||
| 212 | |||
| 213 | struct sst_hsw_get_fx_param { | ||
| 214 | u32 parameter_id; | ||
| 215 | u32 param_size; | ||
| 216 | } __attribute__((packed)); | ||
| 217 | |||
| 218 | struct sst_hsw_perf_action { | ||
| 219 | u32 action; | ||
| 220 | } __attribute__((packed)); | ||
| 221 | |||
| 222 | struct sst_hsw_perf_data { | ||
| 223 | u64 timestamp; | ||
| 224 | u64 cycles; | ||
| 225 | u64 datatime; | ||
| 226 | } __attribute__((packed)); | ||
| 227 | |||
| 228 | /* FW version */ | ||
| 229 | struct sst_hsw_ipc_fw_version { | ||
| 230 | u8 build; | ||
| 231 | u8 minor; | ||
| 232 | u8 major; | ||
| 233 | u8 type; | ||
| 234 | u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH]; | ||
| 235 | u32 fw_log_providers_hash; | ||
| 236 | } __attribute__((packed)); | ||
| 237 | |||
| 238 | /* Stream ring info */ | ||
| 239 | struct sst_hsw_ipc_stream_ring { | ||
| 240 | u32 ring_pt_address; | ||
| 241 | u32 num_pages; | ||
| 242 | u32 ring_size; | ||
| 243 | u32 ring_offset; | ||
| 244 | u32 ring_first_pfn; | ||
| 245 | } __attribute__((packed)); | ||
| 246 | |||
| 247 | /* Debug Dump Log Enable Request */ | ||
| 248 | struct sst_hsw_ipc_debug_log_enable_req { | ||
| 249 | struct sst_hsw_ipc_stream_ring ringinfo; | ||
| 250 | u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS]; | ||
| 251 | } __attribute__((packed)); | ||
| 252 | |||
| 253 | /* Debug Dump Log Reply */ | ||
| 254 | struct sst_hsw_ipc_debug_log_reply { | ||
| 255 | u32 log_buffer_begining; | ||
| 256 | u32 log_buffer_size; | ||
| 257 | } __attribute__((packed)); | ||
| 258 | |||
| 259 | /* Stream glitch position */ | ||
| 260 | struct sst_hsw_ipc_stream_glitch_position { | ||
| 261 | u32 glitch_type; | ||
| 262 | u32 present_pos; | ||
| 263 | u32 write_pos; | ||
| 264 | } __attribute__((packed)); | ||
| 265 | |||
| 266 | /* Stream get position */ | ||
| 267 | struct sst_hsw_ipc_stream_get_position { | ||
| 268 | u32 position; | ||
| 269 | u32 fw_cycle_count; | ||
| 270 | } __attribute__((packed)); | ||
| 271 | |||
| 272 | /* Stream set position */ | ||
| 273 | struct sst_hsw_ipc_stream_set_position { | ||
| 274 | u32 position; | ||
| 275 | u32 end_of_buffer; | ||
| 276 | } __attribute__((packed)); | ||
| 277 | |||
| 278 | /* Stream Free Request */ | ||
| 279 | struct sst_hsw_ipc_stream_free_req { | ||
| 280 | u8 stream_id; | ||
| 281 | u8 reserved[3]; | ||
| 282 | } __attribute__((packed)); | ||
| 283 | |||
| 284 | /* Set Volume Request */ | ||
| 285 | struct sst_hsw_ipc_volume_req { | ||
| 286 | u32 channel; | ||
| 287 | u32 target_volume; | ||
| 288 | u64 curve_duration; | ||
| 289 | u32 curve_type; | ||
| 290 | } __attribute__((packed)); | ||
| 291 | |||
| 292 | /* Device Configuration Request */ | ||
| 293 | struct sst_hsw_ipc_device_config_req { | ||
| 294 | u32 ssp_interface; | ||
| 295 | u32 clock_frequency; | ||
| 296 | u32 mode; | ||
| 297 | u16 clock_divider; | ||
| 298 | u16 reserved; | ||
| 299 | } __attribute__((packed)); | ||
| 300 | |||
| 301 | /* Audio Data formats */ | ||
| 302 | struct sst_hsw_audio_data_format_ipc { | ||
| 303 | u32 frequency; | ||
| 304 | u32 bitdepth; | ||
| 305 | u32 map; | ||
| 306 | u32 config; | ||
| 307 | u32 style; | ||
| 308 | u8 ch_num; | ||
| 309 | u8 valid_bit; | ||
| 310 | u8 reserved[2]; | ||
| 311 | } __attribute__((packed)); | ||
| 312 | |||
| 313 | /* Stream Allocate Request */ | ||
| 314 | struct sst_hsw_ipc_stream_alloc_req { | ||
| 315 | u8 path_id; | ||
| 316 | u8 stream_type; | ||
| 317 | u8 format_id; | ||
| 318 | u8 reserved; | ||
| 319 | struct sst_hsw_audio_data_format_ipc format; | ||
| 320 | struct sst_hsw_ipc_stream_ring ringinfo; | ||
| 321 | struct sst_hsw_module_map map; | ||
| 322 | struct sst_hsw_memory_info persistent_mem; | ||
| 323 | struct sst_hsw_memory_info scratch_mem; | ||
| 324 | u32 number_of_notifications; | ||
| 325 | } __attribute__((packed)); | ||
| 326 | |||
| 327 | /* Stream Allocate Reply */ | ||
| 328 | struct sst_hsw_ipc_stream_alloc_reply { | ||
| 329 | u32 stream_hw_id; | ||
| 330 | u32 mixer_hw_id; // returns rate ???? | ||
| 331 | u32 read_position_register_address; | ||
| 332 | u32 presentation_position_register_address; | ||
| 333 | u32 peak_meter_register_address[SST_HSW_NO_CHANNELS]; | ||
| 334 | u32 volume_register_address[SST_HSW_NO_CHANNELS]; | ||
| 335 | } __attribute__((packed)); | ||
| 336 | |||
| 337 | /* Get Mixer Stream Info */ | ||
| 338 | struct sst_hsw_ipc_stream_info_reply { | ||
| 339 | u32 mixer_hw_id; | ||
| 340 | u32 peak_meter_register_address[SST_HSW_NO_CHANNELS]; | ||
| 341 | u32 volume_register_address[SST_HSW_NO_CHANNELS]; | ||
| 342 | } __attribute__((packed)); | ||
| 343 | |||
| 344 | /* DX State Request */ | ||
| 345 | struct sst_hsw_ipc_dx_req { | ||
| 346 | u8 state; | ||
| 347 | u8 reserved[3]; | ||
| 348 | } __attribute__((packed)); | ||
| 349 | |||
| 350 | /* DX State Reply Memory Info Item */ | ||
| 351 | struct sst_hsw_ipc_dx_memory_item { | ||
| 352 | u32 offset; | ||
| 353 | u32 size; | ||
| 354 | u32 source; | ||
| 355 | } __attribute__((packed)); | ||
| 356 | |||
| 357 | /* DX State Reply */ | ||
| 358 | struct sst_hsw_ipc_dx_reply { | ||
| 359 | u32 entries_no; | ||
| 360 | struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS]; | ||
| 361 | } __attribute__((packed)); | ||
| 362 | |||
| 363 | struct sst_hsw_ipc_fw_version; | ||
| 364 | |||
| 365 | /* SST Init & Free */ | ||
| 366 | struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length, | ||
| 367 | u32 fw_offset); | ||
| 368 | void sst_hsw_free(struct sst_hsw *hsw); | ||
| 369 | int sst_hsw_fw_get_version(struct sst_hsw *hsw, | ||
| 370 | struct sst_hsw_ipc_fw_version *version); | ||
| 371 | u32 create_channel_map(enum sst_hsw_channel_config config); | ||
| 372 | |||
| 373 | /* Stream Mixer Controls - */ | ||
| 374 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 375 | u32 stage_id, u32 channel); | ||
| 376 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 377 | u32 stage_id, u32 channel); | ||
| 378 | |||
| 379 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | ||
| 380 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); | ||
| 381 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, | ||
| 382 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); | ||
| 383 | |||
| 384 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
| 385 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
| 386 | enum sst_hsw_volume_curve curve); | ||
| 387 | |||
| 388 | /* Global Mixer Controls - */ | ||
| 389 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
| 390 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
| 391 | |||
| 392 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
| 393 | u32 volume); | ||
| 394 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
| 395 | u32 *volume); | ||
| 396 | |||
| 397 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
| 398 | u64 curve_duration, enum sst_hsw_volume_curve curve); | ||
| 399 | |||
| 400 | /* Stream API */ | ||
| 401 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | ||
| 402 | u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), | ||
| 403 | void *data); | ||
| 404 | |||
| 405 | int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
| 406 | |||
| 407 | /* Stream Configuration */ | ||
| 408 | int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 409 | enum sst_hsw_stream_path_id path_id, | ||
| 410 | enum sst_hsw_stream_type stream_type, | ||
| 411 | enum sst_hsw_stream_format format_id); | ||
| 412 | |||
| 413 | int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 414 | u32 ring_pt_address, u32 num_pages, | ||
| 415 | u32 ring_size, u32 ring_offset, u32 ring_first_pfn); | ||
| 416 | |||
| 417 | int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
| 418 | |||
| 419 | int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 420 | u32 bits); | ||
| 421 | int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 422 | int rate); | ||
| 423 | int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 424 | enum sst_hsw_bitdepth bits); | ||
| 425 | int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | ||
| 426 | struct sst_hsw_stream *stream, int channels); | ||
| 427 | int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | ||
| 428 | struct sst_hsw_stream *stream, u32 map, | ||
| 429 | enum sst_hsw_channel_config config); | ||
| 430 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 431 | enum sst_hsw_interleaving style); | ||
| 432 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | ||
| 433 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | ||
| 434 | u32 entry_point); | ||
| 435 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | ||
| 436 | struct sst_hsw_stream *stream, u32 offset, u32 size); | ||
| 437 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
| 438 | struct sst_hsw_stream *stream, u32 offset, u32 size); | ||
| 439 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | ||
| 440 | struct sst_hsw_stream *stream); | ||
| 441 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | ||
| 442 | struct sst_hsw_stream *stream); | ||
| 443 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | ||
| 444 | struct sst_hsw_stream *stream); | ||
| 445 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | ||
| 446 | struct sst_hsw_stream *stream); | ||
| 447 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | ||
| 448 | struct sst_hsw_stream *stream, u32 channel); | ||
| 449 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | ||
| 450 | struct sst_hsw_stream *stream, u32 channel); | ||
| 451 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw); | ||
| 452 | |||
| 453 | /* Stream ALSA trigger operations */ | ||
| 454 | int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 455 | int wait); | ||
| 456 | int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
| 457 | int wait); | ||
| 458 | int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
| 459 | |||
| 460 | /* Stream pointer positions */ | ||
| 461 | int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw, | ||
| 462 | struct sst_hsw_stream *stream, u32 *position); | ||
| 463 | int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, | ||
| 464 | struct sst_hsw_stream *stream, u32 *position); | ||
| 465 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
| 466 | struct sst_hsw_stream *stream, u32 stage_id, u32 position); | ||
| 467 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | ||
| 468 | struct sst_hsw_stream *stream); | ||
| 469 | |||
| 470 | /* HW port config */ | ||
| 471 | int sst_hsw_device_set_config(struct sst_hsw *hsw, | ||
| 472 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, | ||
| 473 | enum sst_hsw_device_mode mode, u32 clock_divider); | ||
| 474 | |||
| 475 | /* DX Config */ | ||
| 476 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, | ||
| 477 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); | ||
| 478 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | ||
| 479 | u32 *offset, u32 *size, u32 *source); | ||
| 480 | |||
| 481 | /* init */ | ||
| 482 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | ||
| 483 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | ||
| 484 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | ||
| 485 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
| 486 | struct sst_module *scratch); | ||
| 487 | |||
| 488 | #endif | ||
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c new file mode 100644 index 000000000000..0a32dd13a23d --- /dev/null +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
| @@ -0,0 +1,872 @@ | |||
| 1 | /* | ||
| 2 | * Intel SST Haswell/Broadwell PCM Support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU General Public License version | ||
| 8 | * 2 as published by the Free Software Foundation. | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | #include <linux/dma-mapping.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/delay.h> | ||
| 22 | #include <asm/page.h> | ||
| 23 | #include <asm/pgtable.h> | ||
| 24 | #include <sound/core.h> | ||
| 25 | #include <sound/pcm.h> | ||
| 26 | #include <sound/pcm_params.h> | ||
| 27 | #include <sound/dmaengine_pcm.h> | ||
| 28 | #include <sound/soc.h> | ||
| 29 | #include <sound/tlv.h> | ||
| 30 | #include <sound/compress_driver.h> | ||
| 31 | |||
| 32 | #include "sst-haswell-ipc.h" | ||
| 33 | #include "sst-dsp-priv.h" | ||
| 34 | #include "sst-dsp.h" | ||
| 35 | |||
| 36 | #define HSW_PCM_COUNT 6 | ||
| 37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ | ||
| 38 | |||
| 39 | /* simple volume table */ | ||
| 40 | static const u32 volume_map[] = { | ||
| 41 | HSW_VOLUME_MAX >> 30, | ||
| 42 | HSW_VOLUME_MAX >> 29, | ||
| 43 | HSW_VOLUME_MAX >> 28, | ||
| 44 | HSW_VOLUME_MAX >> 27, | ||
| 45 | HSW_VOLUME_MAX >> 26, | ||
| 46 | HSW_VOLUME_MAX >> 25, | ||
| 47 | HSW_VOLUME_MAX >> 24, | ||
| 48 | HSW_VOLUME_MAX >> 23, | ||
| 49 | HSW_VOLUME_MAX >> 22, | ||
| 50 | HSW_VOLUME_MAX >> 21, | ||
| 51 | HSW_VOLUME_MAX >> 20, | ||
| 52 | HSW_VOLUME_MAX >> 19, | ||
| 53 | HSW_VOLUME_MAX >> 18, | ||
| 54 | HSW_VOLUME_MAX >> 17, | ||
| 55 | HSW_VOLUME_MAX >> 16, | ||
| 56 | HSW_VOLUME_MAX >> 15, | ||
| 57 | HSW_VOLUME_MAX >> 14, | ||
| 58 | HSW_VOLUME_MAX >> 13, | ||
| 59 | HSW_VOLUME_MAX >> 12, | ||
| 60 | HSW_VOLUME_MAX >> 11, | ||
| 61 | HSW_VOLUME_MAX >> 10, | ||
| 62 | HSW_VOLUME_MAX >> 9, | ||
| 63 | HSW_VOLUME_MAX >> 8, | ||
| 64 | HSW_VOLUME_MAX >> 7, | ||
| 65 | HSW_VOLUME_MAX >> 6, | ||
| 66 | HSW_VOLUME_MAX >> 5, | ||
| 67 | HSW_VOLUME_MAX >> 4, | ||
| 68 | HSW_VOLUME_MAX >> 3, | ||
| 69 | HSW_VOLUME_MAX >> 2, | ||
| 70 | HSW_VOLUME_MAX >> 1, | ||
| 71 | HSW_VOLUME_MAX >> 0, | ||
| 72 | }; | ||
| 73 | |||
| 74 | #define HSW_PCM_PERIODS_MAX 64 | ||
| 75 | #define HSW_PCM_PERIODS_MIN 2 | ||
| 76 | |||
| 77 | static const struct snd_pcm_hardware hsw_pcm_hardware = { | ||
| 78 | .info = SNDRV_PCM_INFO_MMAP | | ||
| 79 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 80 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 81 | SNDRV_PCM_INFO_PAUSE | | ||
| 82 | SNDRV_PCM_INFO_RESUME | | ||
| 83 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
| 84 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE | | ||
| 85 | SNDRV_PCM_FMTBIT_S32_LE, | ||
| 86 | .period_bytes_min = PAGE_SIZE, | ||
| 87 | .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE, | ||
| 88 | .periods_min = HSW_PCM_PERIODS_MIN, | ||
| 89 | .periods_max = HSW_PCM_PERIODS_MAX, | ||
| 90 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, | ||
| 91 | }; | ||
| 92 | |||
| 93 | /* private data for each PCM DSP stream */ | ||
| 94 | struct hsw_pcm_data { | ||
| 95 | int dai_id; | ||
| 96 | struct sst_hsw_stream *stream; | ||
| 97 | u32 volume[2]; | ||
| 98 | struct snd_pcm_substream *substream; | ||
| 99 | struct snd_compr_stream *cstream; | ||
| 100 | unsigned int wpos; | ||
| 101 | struct mutex mutex; | ||
| 102 | }; | ||
| 103 | |||
| 104 | /* private data for the driver */ | ||
| 105 | struct hsw_priv_data { | ||
| 106 | /* runtime DSP */ | ||
| 107 | struct sst_hsw *hsw; | ||
| 108 | |||
| 109 | /* page tables */ | ||
| 110 | unsigned char *pcm_pg[HSW_PCM_COUNT][2]; | ||
| 111 | |||
| 112 | /* DAI data */ | ||
| 113 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; | ||
| 114 | }; | ||
| 115 | |||
| 116 | static inline u32 hsw_mixer_to_ipc(unsigned int value) | ||
| 117 | { | ||
| 118 | if (value >= ARRAY_SIZE(volume_map)) | ||
| 119 | return volume_map[0]; | ||
| 120 | else | ||
| 121 | return volume_map[value]; | ||
| 122 | } | ||
| 123 | |||
| 124 | static inline unsigned int hsw_ipc_to_mixer(u32 value) | ||
| 125 | { | ||
| 126 | int i; | ||
| 127 | |||
| 128 | for (i = 0; i < ARRAY_SIZE(volume_map); i++) { | ||
| 129 | if (volume_map[i] >= value) | ||
| 130 | return i; | ||
| 131 | } | ||
| 132 | |||
| 133 | return i - 1; | ||
| 134 | } | ||
| 135 | |||
| 136 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | ||
| 137 | struct snd_ctl_elem_value *ucontrol) | ||
| 138 | { | ||
| 139 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
| 140 | struct soc_mixer_control *mc = | ||
| 141 | (struct soc_mixer_control *)kcontrol->private_value; | ||
| 142 | struct hsw_priv_data *pdata = | ||
| 143 | snd_soc_platform_get_drvdata(platform); | ||
| 144 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | ||
| 145 | struct sst_hsw *hsw = pdata->hsw; | ||
| 146 | u32 volume; | ||
| 147 | |||
| 148 | mutex_lock(&pcm_data->mutex); | ||
| 149 | |||
| 150 | if (!pcm_data->stream) { | ||
| 151 | pcm_data->volume[0] = | ||
| 152 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
| 153 | pcm_data->volume[1] = | ||
| 154 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
| 155 | mutex_unlock(&pcm_data->mutex); | ||
| 156 | return 0; | ||
| 157 | } | ||
| 158 | |||
| 159 | if (ucontrol->value.integer.value[0] == | ||
| 160 | ucontrol->value.integer.value[1]) { | ||
| 161 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
| 162 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume); | ||
| 163 | } else { | ||
| 164 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
| 165 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); | ||
| 166 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
| 167 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); | ||
| 168 | } | ||
| 169 | |||
| 170 | mutex_unlock(&pcm_data->mutex); | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | ||
| 175 | struct snd_ctl_elem_value *ucontrol) | ||
| 176 | { | ||
| 177 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
| 178 | struct soc_mixer_control *mc = | ||
| 179 | (struct soc_mixer_control *)kcontrol->private_value; | ||
| 180 | struct hsw_priv_data *pdata = | ||
| 181 | snd_soc_platform_get_drvdata(platform); | ||
| 182 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | ||
| 183 | struct sst_hsw *hsw = pdata->hsw; | ||
| 184 | u32 volume; | ||
| 185 | |||
| 186 | mutex_lock(&pcm_data->mutex); | ||
| 187 | |||
| 188 | if (!pcm_data->stream) { | ||
| 189 | ucontrol->value.integer.value[0] = | ||
| 190 | hsw_ipc_to_mixer(pcm_data->volume[0]); | ||
| 191 | ucontrol->value.integer.value[1] = | ||
| 192 | hsw_ipc_to_mixer(pcm_data->volume[1]); | ||
| 193 | mutex_unlock(&pcm_data->mutex); | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume); | ||
| 198 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | ||
| 199 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); | ||
| 200 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | ||
| 201 | mutex_unlock(&pcm_data->mutex); | ||
| 202 | |||
| 203 | return 0; | ||
| 204 | } | ||
| 205 | |||
| 206 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, | ||
| 207 | struct snd_ctl_elem_value *ucontrol) | ||
| 208 | { | ||
| 209 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
| 210 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 211 | struct sst_hsw *hsw = pdata->hsw; | ||
| 212 | u32 volume; | ||
| 213 | |||
| 214 | if (ucontrol->value.integer.value[0] == | ||
| 215 | ucontrol->value.integer.value[1]) { | ||
| 216 | |||
| 217 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
| 218 | sst_hsw_mixer_set_volume(hsw, 0, 2, volume); | ||
| 219 | |||
| 220 | } else { | ||
| 221 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
| 222 | sst_hsw_mixer_set_volume(hsw, 0, 0, volume); | ||
| 223 | |||
| 224 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
| 225 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); | ||
| 226 | } | ||
| 227 | |||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, | ||
| 232 | struct snd_ctl_elem_value *ucontrol) | ||
| 233 | { | ||
| 234 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
| 235 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
| 236 | struct sst_hsw *hsw = pdata->hsw; | ||
| 237 | unsigned int volume = 0; | ||
| 238 | |||
| 239 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); | ||
| 240 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | ||
| 241 | |||
| 242 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); | ||
| 243 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | /* TLV used by both global and stream volumes */ | ||
| 249 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | ||
| 250 | |||
| 251 | /* System Pin has no volume control */ | ||
| 252 | static const struct snd_kcontrol_new hsw_volume_controls[] = { | ||
| 253 | /* Global DSP volume */ | ||
| 254 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, | ||
| 255 | ARRAY_SIZE(volume_map) -1, 0, | ||
| 256 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), | ||
| 257 | /* Offload 0 volume */ | ||
| 258 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, | ||
| 259 | ARRAY_SIZE(volume_map), 0, | ||
| 260 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
| 261 | /* Offload 1 volume */ | ||
| 262 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, | ||
| 263 | ARRAY_SIZE(volume_map), 0, | ||
| 264 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
| 265 | /* Loopback volume */ | ||
| 266 | SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8, | ||
| 267 | ARRAY_SIZE(volume_map), 0, | ||
| 268 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
| 269 | /* Mic Capture volume */ | ||
| 270 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | ||
| 271 | ARRAY_SIZE(volume_map), 0, | ||
| 272 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
| 273 | }; | ||
| 274 | |||
| 275 | /* Create DMA buffer page table for DSP */ | ||
| 276 | static int create_adsp_page_table(struct hsw_priv_data *pdata, | ||
| 277 | struct snd_soc_pcm_runtime *rtd, | ||
| 278 | unsigned char *dma_area, size_t size, int pcm, int stream) | ||
| 279 | { | ||
| 280 | int i, pages; | ||
| 281 | |||
| 282 | if (size % PAGE_SIZE) | ||
| 283 | pages = (size / PAGE_SIZE) + 1; | ||
| 284 | else | ||
| 285 | pages = size / PAGE_SIZE; | ||
| 286 | |||
| 287 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", | ||
| 288 | dma_area, size, pages); | ||
| 289 | |||
| 290 | for (i = 0; i < pages; i++) { | ||
| 291 | u32 idx = (((i << 2) + i)) >> 1; | ||
| 292 | u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; | ||
| 293 | u32 *pg_table; | ||
| 294 | |||
| 295 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); | ||
| 296 | |||
| 297 | pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); | ||
| 298 | |||
| 299 | if (i & 1) | ||
| 300 | *pg_table |= (pfn << 4); | ||
| 301 | else | ||
| 302 | *pg_table |= pfn; | ||
| 303 | } | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | /* this may get called several times by oss emulation */ | ||
| 309 | static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 310 | struct snd_pcm_hw_params *params) | ||
| 311 | { | ||
| 312 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 313 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 314 | struct hsw_priv_data *pdata = | ||
| 315 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 316 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 317 | struct sst_hsw *hsw = pdata->hsw; | ||
| 318 | struct sst_module *module_data; | ||
| 319 | struct sst_dsp *dsp; | ||
| 320 | enum sst_hsw_stream_type stream_type; | ||
| 321 | enum sst_hsw_stream_path_id path_id; | ||
| 322 | u32 rate, bits, map, pages, module_id; | ||
| 323 | u8 channels; | ||
| 324 | int ret; | ||
| 325 | |||
| 326 | /* stream direction */ | ||
| 327 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 328 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | ||
| 329 | else | ||
| 330 | path_id = SST_HSW_STREAM_PATH_SSP0_IN; | ||
| 331 | |||
| 332 | /* DSP stream type depends on DAI ID */ | ||
| 333 | switch (rtd->cpu_dai->id) { | ||
| 334 | case 0: | ||
| 335 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; | ||
| 336 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | ||
| 337 | break; | ||
| 338 | case 1: | ||
| 339 | case 2: | ||
| 340 | stream_type = SST_HSW_STREAM_TYPE_RENDER; | ||
| 341 | module_id = SST_HSW_MODULE_PCM; | ||
| 342 | break; | ||
| 343 | case 3: | ||
| 344 | /* path ID needs to be OUT for loopback */ | ||
| 345 | stream_type = SST_HSW_STREAM_TYPE_LOOPBACK; | ||
| 346 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | ||
| 347 | module_id = SST_HSW_MODULE_PCM_REFERENCE; | ||
| 348 | break; | ||
| 349 | case 4: | ||
| 350 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
| 351 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
| 352 | break; | ||
| 353 | default: | ||
| 354 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", | ||
| 355 | rtd->cpu_dai->id); | ||
| 356 | return -EINVAL; | ||
| 357 | }; | ||
| 358 | |||
| 359 | ret = sst_hsw_stream_format(hsw, pcm_data->stream, | ||
| 360 | path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); | ||
| 361 | if (ret < 0) { | ||
| 362 | dev_err(rtd->dev, "error: failed to set format %d\n", ret); | ||
| 363 | return ret; | ||
| 364 | } | ||
| 365 | |||
| 366 | rate = params_rate(params); | ||
| 367 | ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate); | ||
| 368 | if (ret < 0) { | ||
| 369 | dev_err(rtd->dev, "error: could not set rate %d\n", rate); | ||
| 370 | return ret; | ||
| 371 | } | ||
| 372 | |||
| 373 | switch (params_format(params)) { | ||
| 374 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 375 | bits = SST_HSW_DEPTH_16BIT; | ||
| 376 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16); | ||
| 377 | break; | ||
| 378 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 379 | bits = SST_HSW_DEPTH_24BIT; | ||
| 380 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32); | ||
| 381 | break; | ||
| 382 | default: | ||
| 383 | dev_err(rtd->dev, "error: invalid format %d\n", | ||
| 384 | params_format(params)); | ||
| 385 | return -EINVAL; | ||
| 386 | } | ||
| 387 | |||
| 388 | ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits); | ||
| 389 | if (ret < 0) { | ||
| 390 | dev_err(rtd->dev, "error: could not set bits %d\n", bits); | ||
| 391 | return ret; | ||
| 392 | } | ||
| 393 | |||
| 394 | /* we only support stereo atm */ | ||
| 395 | channels = params_channels(params); | ||
| 396 | if (channels != 2) { | ||
| 397 | dev_err(rtd->dev, "error: invalid channels %d\n", channels); | ||
| 398 | return -EINVAL; | ||
| 399 | } | ||
| 400 | |||
| 401 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); | ||
| 402 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, | ||
| 403 | map, SST_HSW_CHANNEL_CONFIG_STEREO); | ||
| 404 | |||
| 405 | ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels); | ||
| 406 | if (ret < 0) { | ||
| 407 | dev_err(rtd->dev, "error: could not set channels %d\n", | ||
| 408 | channels); | ||
| 409 | return ret; | ||
| 410 | } | ||
| 411 | |||
| 412 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
| 413 | if (ret < 0) { | ||
| 414 | dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n", | ||
| 415 | params_buffer_bytes(params), ret); | ||
| 416 | return ret; | ||
| 417 | } | ||
| 418 | |||
| 419 | ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, | ||
| 420 | runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); | ||
| 421 | if (ret < 0) | ||
| 422 | return ret; | ||
| 423 | |||
| 424 | sst_hsw_stream_set_style(hsw, pcm_data->stream, | ||
| 425 | SST_HSW_INTERLEAVING_PER_CHANNEL); | ||
| 426 | |||
| 427 | if (runtime->dma_bytes % PAGE_SIZE) | ||
| 428 | pages = (runtime->dma_bytes / PAGE_SIZE) + 1; | ||
| 429 | else | ||
| 430 | pages = runtime->dma_bytes / PAGE_SIZE; | ||
| 431 | |||
| 432 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, | ||
| 433 | virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), | ||
| 434 | pages, runtime->dma_bytes, 0, | ||
| 435 | (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); | ||
| 436 | if (ret < 0) { | ||
| 437 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); | ||
| 438 | return ret; | ||
| 439 | } | ||
| 440 | |||
| 441 | dsp = sst_hsw_get_dsp(hsw); | ||
| 442 | |||
| 443 | module_data = sst_module_get_from_id(dsp, module_id); | ||
| 444 | if (module_data == NULL) { | ||
| 445 | dev_err(rtd->dev, "error: failed to get module config\n"); | ||
| 446 | return -EINVAL; | ||
| 447 | } | ||
| 448 | |||
| 449 | /* we use hardcoded memory offsets atm, will be updated for new FW */ | ||
| 450 | if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) { | ||
| 451 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
| 452 | SST_HSW_MODULE_PCM_CAPTURE, module_data->entry); | ||
| 453 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
| 454 | 0x449400, 0x4000); | ||
| 455 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
| 456 | 0x400000, 0); | ||
| 457 | } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */ | ||
| 458 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
| 459 | SST_HSW_MODULE_PCM_SYSTEM, module_data->entry); | ||
| 460 | |||
| 461 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
| 462 | module_data->offset, module_data->size); | ||
| 463 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
| 464 | 0x44d400, 0x3800); | ||
| 465 | |||
| 466 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
| 467 | module_data->offset, module_data->size); | ||
| 468 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
| 469 | 0x400000, 0); | ||
| 470 | } | ||
| 471 | |||
| 472 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); | ||
| 473 | if (ret < 0) { | ||
| 474 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); | ||
| 475 | return ret; | ||
| 476 | } | ||
| 477 | |||
| 478 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); | ||
| 479 | if (ret < 0) | ||
| 480 | dev_err(rtd->dev, "error: failed to pause %d\n", ret); | ||
| 481 | |||
| 482 | return 0; | ||
| 483 | } | ||
| 484 | |||
| 485 | static int hsw_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 486 | { | ||
| 487 | snd_pcm_lib_free_pages(substream); | ||
| 488 | return 0; | ||
| 489 | } | ||
| 490 | |||
| 491 | static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 492 | { | ||
| 493 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 494 | struct hsw_priv_data *pdata = | ||
| 495 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 496 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 497 | struct sst_hsw *hsw = pdata->hsw; | ||
| 498 | |||
| 499 | switch (cmd) { | ||
| 500 | case SNDRV_PCM_TRIGGER_START: | ||
| 501 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 502 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 503 | sst_hsw_stream_resume(hsw, pcm_data->stream, 0); | ||
| 504 | break; | ||
| 505 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 506 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 507 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 508 | sst_hsw_stream_pause(hsw, pcm_data->stream, 0); | ||
| 509 | break; | ||
| 510 | default: | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | |||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) | ||
| 518 | { | ||
| 519 | struct hsw_pcm_data *pcm_data = data; | ||
| 520 | struct snd_pcm_substream *substream = pcm_data->substream; | ||
| 521 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 522 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 523 | u32 pos; | ||
| 524 | |||
| 525 | pos = frames_to_bytes(runtime, | ||
| 526 | (runtime->control->appl_ptr % runtime->buffer_size)); | ||
| 527 | |||
| 528 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | ||
| 529 | |||
| 530 | /* let alsa know we have play a period */ | ||
| 531 | snd_pcm_period_elapsed(substream); | ||
| 532 | return pos; | ||
| 533 | } | ||
| 534 | |||
| 535 | static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | ||
| 536 | { | ||
| 537 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 538 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 539 | struct hsw_priv_data *pdata = | ||
| 540 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 541 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 542 | struct sst_hsw *hsw = pdata->hsw; | ||
| 543 | snd_pcm_uframes_t offset; | ||
| 544 | |||
| 545 | offset = bytes_to_frames(runtime, | ||
| 546 | sst_hsw_get_dsp_position(hsw, pcm_data->stream)); | ||
| 547 | |||
| 548 | dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", | ||
| 549 | frames_to_bytes(runtime, (u32)offset)); | ||
| 550 | return offset; | ||
| 551 | } | ||
| 552 | |||
| 553 | static int hsw_pcm_open(struct snd_pcm_substream *substream) | ||
| 554 | { | ||
| 555 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 556 | struct hsw_priv_data *pdata = | ||
| 557 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 558 | struct hsw_pcm_data *pcm_data; | ||
| 559 | struct sst_hsw *hsw = pdata->hsw; | ||
| 560 | |||
| 561 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | ||
| 562 | |||
| 563 | mutex_lock(&pcm_data->mutex); | ||
| 564 | |||
| 565 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | ||
| 566 | pcm_data->substream = substream; | ||
| 567 | |||
| 568 | snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware); | ||
| 569 | |||
| 570 | pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, | ||
| 571 | hsw_notify_pointer, pcm_data); | ||
| 572 | if (pcm_data->stream == NULL) { | ||
| 573 | dev_err(rtd->dev, "error: failed to create stream\n"); | ||
| 574 | mutex_unlock(&pcm_data->mutex); | ||
| 575 | return -EINVAL; | ||
| 576 | } | ||
| 577 | |||
| 578 | /* Set previous saved volume */ | ||
| 579 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
| 580 | 0, pcm_data->volume[0]); | ||
| 581 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
| 582 | 1, pcm_data->volume[1]); | ||
| 583 | |||
| 584 | mutex_unlock(&pcm_data->mutex); | ||
| 585 | return 0; | ||
| 586 | } | ||
| 587 | |||
| 588 | static int hsw_pcm_close(struct snd_pcm_substream *substream) | ||
| 589 | { | ||
| 590 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
| 591 | struct hsw_priv_data *pdata = | ||
| 592 | snd_soc_platform_get_drvdata(rtd->platform); | ||
| 593 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
| 594 | struct sst_hsw *hsw = pdata->hsw; | ||
| 595 | int ret; | ||
| 596 | |||
| 597 | mutex_lock(&pcm_data->mutex); | ||
| 598 | ret = sst_hsw_stream_reset(hsw, pcm_data->stream); | ||
| 599 | if (ret < 0) { | ||
| 600 | dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret); | ||
| 601 | goto out; | ||
| 602 | } | ||
| 603 | |||
| 604 | ret = sst_hsw_stream_free(hsw, pcm_data->stream); | ||
| 605 | if (ret < 0) { | ||
| 606 | dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); | ||
| 607 | goto out; | ||
| 608 | } | ||
| 609 | pcm_data->stream = NULL; | ||
| 610 | |||
| 611 | out: | ||
| 612 | mutex_unlock(&pcm_data->mutex); | ||
| 613 | return ret; | ||
| 614 | } | ||
| 615 | |||
| 616 | static struct snd_pcm_ops hsw_pcm_ops = { | ||
| 617 | .open = hsw_pcm_open, | ||
| 618 | .close = hsw_pcm_close, | ||
| 619 | .ioctl = snd_pcm_lib_ioctl, | ||
| 620 | .hw_params = hsw_pcm_hw_params, | ||
| 621 | .hw_free = hsw_pcm_hw_free, | ||
| 622 | .trigger = hsw_pcm_trigger, | ||
| 623 | .pointer = hsw_pcm_pointer, | ||
| 624 | .mmap = snd_pcm_lib_default_mmap, | ||
| 625 | }; | ||
| 626 | |||
| 627 | static void hsw_pcm_free(struct snd_pcm *pcm) | ||
| 628 | { | ||
| 629 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
| 630 | } | ||
| 631 | |||
| 632 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
| 633 | { | ||
| 634 | struct snd_pcm *pcm = rtd->pcm; | ||
| 635 | int ret = 0; | ||
| 636 | |||
| 637 | ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); | ||
| 638 | if (ret) | ||
| 639 | return ret; | ||
| 640 | |||
| 641 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | ||
| 642 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
| 643 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
| 644 | SNDRV_DMA_TYPE_DEV, | ||
| 645 | rtd->card->dev, | ||
| 646 | hsw_pcm_hardware.buffer_bytes_max, | ||
| 647 | hsw_pcm_hardware.buffer_bytes_max); | ||
| 648 | if (ret) { | ||
| 649 | dev_err(rtd->dev, "dma buffer allocation failed %d\n", | ||
| 650 | ret); | ||
| 651 | return ret; | ||
| 652 | } | ||
| 653 | } | ||
| 654 | |||
| 655 | return ret; | ||
| 656 | } | ||
| 657 | |||
| 658 | #define HSW_FORMATS \ | ||
| 659 | (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ | ||
| 660 | SNDRV_PCM_FMTBIT_S32_LE) | ||
| 661 | |||
| 662 | static struct snd_soc_dai_driver hsw_dais[] = { | ||
| 663 | { | ||
| 664 | .name = "System Pin", | ||
| 665 | .playback = { | ||
| 666 | .stream_name = "System Playback", | ||
| 667 | .channels_min = 2, | ||
| 668 | .channels_max = 2, | ||
| 669 | .rates = SNDRV_PCM_RATE_48000, | ||
| 670 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 671 | }, | ||
| 672 | }, | ||
| 673 | { | ||
| 674 | /* PCM */ | ||
| 675 | .name = "Offload0 Pin", | ||
| 676 | .playback = { | ||
| 677 | .stream_name = "Offload0 Playback", | ||
| 678 | .channels_min = 2, | ||
| 679 | .channels_max = 2, | ||
| 680 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 681 | .formats = HSW_FORMATS, | ||
| 682 | }, | ||
| 683 | }, | ||
| 684 | { | ||
| 685 | /* PCM */ | ||
| 686 | .name = "Offload1 Pin", | ||
| 687 | .playback = { | ||
| 688 | .stream_name = "Offload1 Playback", | ||
| 689 | .channels_min = 2, | ||
| 690 | .channels_max = 2, | ||
| 691 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 692 | .formats = HSW_FORMATS, | ||
| 693 | }, | ||
| 694 | }, | ||
| 695 | { | ||
| 696 | .name = "Loopback Pin", | ||
| 697 | .capture = { | ||
| 698 | .stream_name = "Loopback Capture", | ||
| 699 | .channels_min = 2, | ||
| 700 | .channels_max = 2, | ||
| 701 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 702 | .formats = HSW_FORMATS, | ||
| 703 | }, | ||
| 704 | }, | ||
| 705 | { | ||
| 706 | .name = "Capture Pin", | ||
| 707 | .capture = { | ||
| 708 | .stream_name = "Analog Capture", | ||
| 709 | .channels_min = 2, | ||
| 710 | .channels_max = 2, | ||
| 711 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 712 | .formats = HSW_FORMATS, | ||
| 713 | }, | ||
| 714 | }, | ||
| 715 | }; | ||
| 716 | |||
| 717 | static const struct snd_soc_dapm_widget widgets[] = { | ||
| 718 | |||
| 719 | /* Backend DAIs */ | ||
| 720 | SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
| 721 | SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
| 722 | SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
| 723 | SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
| 724 | |||
| 725 | /* Global Playback Mixer */ | ||
| 726 | SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
| 727 | }; | ||
| 728 | |||
| 729 | static const struct snd_soc_dapm_route graph[] = { | ||
| 730 | |||
| 731 | /* Playback Mixer */ | ||
| 732 | {"Playback VMixer", NULL, "System Playback"}, | ||
| 733 | {"Playback VMixer", NULL, "Offload0 Playback"}, | ||
| 734 | {"Playback VMixer", NULL, "Offload1 Playback"}, | ||
| 735 | |||
| 736 | {"SSP0 CODEC OUT", NULL, "Playback VMixer"}, | ||
| 737 | |||
| 738 | {"Analog Capture", NULL, "SSP0 CODEC IN"}, | ||
| 739 | }; | ||
| 740 | |||
| 741 | static int hsw_pcm_probe(struct snd_soc_platform *platform) | ||
| 742 | { | ||
| 743 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | ||
| 744 | struct hsw_priv_data *priv_data; | ||
| 745 | int i; | ||
| 746 | |||
| 747 | if (!pdata) | ||
| 748 | return -ENODEV; | ||
| 749 | |||
| 750 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); | ||
| 751 | priv_data->hsw = pdata->dsp; | ||
| 752 | snd_soc_platform_set_drvdata(platform, priv_data); | ||
| 753 | |||
| 754 | /* allocate DSP buffer page tables */ | ||
| 755 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | ||
| 756 | |||
| 757 | mutex_init(&priv_data->pcm[i].mutex); | ||
| 758 | |||
| 759 | /* playback */ | ||
| 760 | if (hsw_dais[i].playback.channels_min) { | ||
| 761 | priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); | ||
| 762 | if (priv_data->pcm_pg[i][0] == NULL) | ||
| 763 | goto err; | ||
| 764 | } | ||
| 765 | |||
| 766 | /* capture */ | ||
| 767 | if (hsw_dais[i].capture.channels_min) { | ||
| 768 | priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); | ||
| 769 | if (priv_data->pcm_pg[i][1] == NULL) | ||
| 770 | goto err; | ||
| 771 | } | ||
| 772 | } | ||
| 773 | |||
| 774 | return 0; | ||
| 775 | |||
| 776 | err: | ||
| 777 | for (;i >= 0; i--) { | ||
| 778 | if (hsw_dais[i].playback.channels_min) | ||
| 779 | kfree(priv_data->pcm_pg[i][0]); | ||
| 780 | if (hsw_dais[i].capture.channels_min) | ||
| 781 | kfree(priv_data->pcm_pg[i][1]); | ||
| 782 | } | ||
| 783 | return -ENOMEM; | ||
| 784 | } | ||
| 785 | |||
| 786 | static int hsw_pcm_remove(struct snd_soc_platform *platform) | ||
| 787 | { | ||
| 788 | struct hsw_priv_data *priv_data = | ||
| 789 | snd_soc_platform_get_drvdata(platform); | ||
| 790 | int i; | ||
| 791 | |||
| 792 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | ||
| 793 | if (hsw_dais[i].playback.channels_min) | ||
| 794 | kfree(priv_data->pcm_pg[i][0]); | ||
| 795 | if (hsw_dais[i].capture.channels_min) | ||
| 796 | kfree(priv_data->pcm_pg[i][1]); | ||
| 797 | } | ||
| 798 | |||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static struct snd_soc_platform_driver hsw_soc_platform = { | ||
| 803 | .probe = hsw_pcm_probe, | ||
| 804 | .remove = hsw_pcm_remove, | ||
| 805 | .ops = &hsw_pcm_ops, | ||
| 806 | .pcm_new = hsw_pcm_new, | ||
| 807 | .pcm_free = hsw_pcm_free, | ||
| 808 | .controls = hsw_volume_controls, | ||
| 809 | .num_controls = ARRAY_SIZE(hsw_volume_controls), | ||
| 810 | .dapm_widgets = widgets, | ||
| 811 | .num_dapm_widgets = ARRAY_SIZE(widgets), | ||
| 812 | .dapm_routes = graph, | ||
| 813 | .num_dapm_routes = ARRAY_SIZE(graph), | ||
| 814 | }; | ||
| 815 | |||
| 816 | static const struct snd_soc_component_driver hsw_dai_component = { | ||
| 817 | .name = "haswell-dai", | ||
| 818 | }; | ||
| 819 | |||
| 820 | static int hsw_pcm_dev_probe(struct platform_device *pdev) | ||
| 821 | { | ||
| 822 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
| 823 | int ret; | ||
| 824 | |||
| 825 | ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); | ||
| 826 | if (ret < 0) | ||
| 827 | return -ENODEV; | ||
| 828 | |||
| 829 | ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); | ||
| 830 | if (ret < 0) | ||
| 831 | goto err_plat; | ||
| 832 | |||
| 833 | ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component, | ||
| 834 | hsw_dais, ARRAY_SIZE(hsw_dais)); | ||
| 835 | if (ret < 0) | ||
| 836 | goto err_comp; | ||
| 837 | |||
| 838 | return 0; | ||
| 839 | |||
| 840 | err_comp: | ||
| 841 | snd_soc_unregister_platform(&pdev->dev); | ||
| 842 | err_plat: | ||
| 843 | sst_hsw_dsp_free(&pdev->dev, sst_pdata); | ||
| 844 | return 0; | ||
| 845 | } | ||
| 846 | |||
| 847 | static int hsw_pcm_dev_remove(struct platform_device *pdev) | ||
| 848 | { | ||
| 849 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
| 850 | |||
| 851 | snd_soc_unregister_platform(&pdev->dev); | ||
| 852 | snd_soc_unregister_component(&pdev->dev); | ||
| 853 | sst_hsw_dsp_free(&pdev->dev, sst_pdata); | ||
| 854 | |||
| 855 | return 0; | ||
| 856 | } | ||
| 857 | |||
| 858 | static struct platform_driver hsw_pcm_driver = { | ||
| 859 | .driver = { | ||
| 860 | .name = "haswell-pcm-audio", | ||
| 861 | .owner = THIS_MODULE, | ||
| 862 | }, | ||
| 863 | |||
| 864 | .probe = hsw_pcm_dev_probe, | ||
| 865 | .remove = hsw_pcm_dev_remove, | ||
| 866 | }; | ||
| 867 | module_platform_driver(hsw_pcm_driver); | ||
| 868 | |||
| 869 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
| 870 | MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM"); | ||
| 871 | MODULE_LICENSE("GPL v2"); | ||
| 872 | MODULE_ALIAS("platform:haswell-pcm-audio"); | ||
diff --git a/sound/soc/intel/sst_dsp.h b/sound/soc/intel/sst-mfld-dsp.h index 0fce1de284ff..3b63edc04b7f 100644 --- a/sound/soc/intel/sst_dsp.h +++ b/sound/soc/intel/sst-mfld-dsp.h | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | #ifndef __SST_DSP_H__ | 1 | #ifndef __SST_MFLD_DSP_H__ |
| 2 | #define __SST_DSP_H__ | 2 | #define __SST_MFLD_DSP_H__ |
| 3 | /* | 3 | /* |
| 4 | * sst_dsp.h - Intel SST Driver for audio engine | 4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2008-12 Intel Corporation | 6 | * Copyright (C) 2008-12 Intel Corporation |
| 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> | 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> |
| @@ -131,4 +131,4 @@ struct snd_sst_params { | |||
| 131 | struct snd_sst_alloc_params_ext aparams; | 131 | struct snd_sst_alloc_params_ext aparams; |
| 132 | }; | 132 | }; |
| 133 | 133 | ||
| 134 | #endif /* __SST_DSP_H__ */ | 134 | #endif /* __SST_MFLD_DSP_H__ */ |
diff --git a/sound/soc/intel/sst_platform.c b/sound/soc/intel/sst-mfld-platform.c index f465a8180863..840306c2ef14 100644 --- a/sound/soc/intel/sst_platform.c +++ b/sound/soc/intel/sst-mfld-platform.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * sst_platform.c - Intel MID Platform driver | 2 | * sst_mfld_platform.c - Intel MID Platform driver |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010-2013 Intel Corp | 4 | * Copyright (C) 2010-2013 Intel Corp |
| 5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
| @@ -33,7 +33,7 @@ | |||
| 33 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
| 34 | #include <sound/soc.h> | 34 | #include <sound/soc.h> |
| 35 | #include <sound/compress_driver.h> | 35 | #include <sound/compress_driver.h> |
| 36 | #include "sst_platform.h" | 36 | #include "sst-mfld-platform.h" |
| 37 | 37 | ||
| 38 | static struct sst_device *sst; | 38 | static struct sst_device *sst; |
| 39 | static DEFINE_MUTEX(sst_lock); | 39 | static DEFINE_MUTEX(sst_lock); |
| @@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev) | |||
| 709 | 709 | ||
| 710 | static struct platform_driver sst_platform_driver = { | 710 | static struct platform_driver sst_platform_driver = { |
| 711 | .driver = { | 711 | .driver = { |
| 712 | .name = "sst-platform", | 712 | .name = "sst-mfld-platform", |
| 713 | .owner = THIS_MODULE, | 713 | .owner = THIS_MODULE, |
| 714 | }, | 714 | }, |
| 715 | .probe = sst_platform_probe, | 715 | .probe = sst_platform_probe, |
| @@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); | |||
| 722 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | 722 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); |
| 723 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | 723 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); |
| 724 | MODULE_LICENSE("GPL v2"); | 724 | MODULE_LICENSE("GPL v2"); |
| 725 | MODULE_ALIAS("platform:sst-platform"); | 725 | MODULE_ALIAS("platform:sst-mfld-platform"); |
diff --git a/sound/soc/intel/sst_platform.h b/sound/soc/intel/sst-mfld-platform.h index bee64fb7d2ef..0c4e2ddcecb1 100644 --- a/sound/soc/intel/sst_platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * sst_platform.h - Intel MID Platform driver header file | 2 | * sst_mfld_platform.h - Intel MID Platform driver header file |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2010 Intel Corp | 4 | * Copyright (C) 2010 Intel Corp |
| 5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
| @@ -27,7 +27,7 @@ | |||
| 27 | #ifndef __SST_PLATFORMDRV_H__ | 27 | #ifndef __SST_PLATFORMDRV_H__ |
| 28 | #define __SST_PLATFORMDRV_H__ | 28 | #define __SST_PLATFORMDRV_H__ |
| 29 | 29 | ||
| 30 | #include "sst_dsp.h" | 30 | #include "sst-mfld-dsp.h" |
| 31 | 31 | ||
| 32 | #define SST_MONO 1 | 32 | #define SST_MONO 1 |
| 33 | #define SST_STEREO 2 | 33 | #define SST_STEREO 2 |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 22ad9c5654b5..e00659351a4e 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
| @@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912 | |||
| 58 | tristate "SoC Audio support for omap osk5912" | 58 | tristate "SoC Audio support for omap osk5912" |
| 59 | depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C | 59 | depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C |
| 60 | select SND_OMAP_SOC_MCBSP | 60 | select SND_OMAP_SOC_MCBSP |
| 61 | select SND_SOC_TLV320AIC23 | 61 | select SND_SOC_TLV320AIC23_I2C |
| 62 | help | 62 | help |
| 63 | Say Y if you want to add support for SoC audio on osk5912. | 63 | Say Y if you want to add support for SoC audio on osk5912. |
| 64 | 64 | ||
| @@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM | |||
| 66 | tristate "SoC Audio support for OMAP3517 / AM3517 EVM" | 66 | tristate "SoC Audio support for OMAP3517 / AM3517 EVM" |
| 67 | depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C | 67 | depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C |
| 68 | select SND_OMAP_SOC_MCBSP | 68 | select SND_OMAP_SOC_MCBSP |
| 69 | select SND_SOC_TLV320AIC23 | 69 | select SND_SOC_TLV320AIC23_I2C |
| 70 | help | 70 | help |
| 71 | Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 | 71 | Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 |
| 72 | EVM. | 72 | EVM. |
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 629446482a91..f141435b0b4a 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c | |||
| @@ -103,60 +103,62 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, | |||
| 103 | if (!codec->hw_write) | 103 | if (!codec->hw_write) |
| 104 | return -EUNATCH; | 104 | return -EUNATCH; |
| 105 | 105 | ||
| 106 | if (ucontrol->value.enumerated.item[0] >= control->max) | 106 | if (ucontrol->value.enumerated.item[0] >= control->items) |
| 107 | return -EINVAL; | 107 | return -EINVAL; |
| 108 | 108 | ||
| 109 | mutex_lock(&codec->mutex); | 109 | snd_soc_dapm_mutex_lock(dapm); |
| 110 | 110 | ||
| 111 | /* Translate selection to bitmap */ | 111 | /* Translate selection to bitmap */ |
| 112 | pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; | 112 | pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; |
| 113 | 113 | ||
| 114 | /* Setup pins after corresponding bits if changed */ | 114 | /* Setup pins after corresponding bits if changed */ |
| 115 | pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); | 115 | pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); |
| 116 | |||
| 116 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { | 117 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { |
| 117 | changed = 1; | 118 | changed = 1; |
| 118 | if (pin) | 119 | if (pin) |
| 119 | snd_soc_dapm_enable_pin(dapm, "Mouthpiece"); | 120 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece"); |
| 120 | else | 121 | else |
| 121 | snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); | 122 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); |
| 122 | } | 123 | } |
| 123 | pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); | 124 | pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); |
| 124 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { | 125 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { |
| 125 | changed = 1; | 126 | changed = 1; |
| 126 | if (pin) | 127 | if (pin) |
| 127 | snd_soc_dapm_enable_pin(dapm, "Earpiece"); | 128 | snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); |
| 128 | else | 129 | else |
| 129 | snd_soc_dapm_disable_pin(dapm, "Earpiece"); | 130 | snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece"); |
| 130 | } | 131 | } |
| 131 | pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); | 132 | pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); |
| 132 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { | 133 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { |
| 133 | changed = 1; | 134 | changed = 1; |
| 134 | if (pin) | 135 | if (pin) |
| 135 | snd_soc_dapm_enable_pin(dapm, "Microphone"); | 136 | snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); |
| 136 | else | 137 | else |
| 137 | snd_soc_dapm_disable_pin(dapm, "Microphone"); | 138 | snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone"); |
| 138 | } | 139 | } |
| 139 | pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); | 140 | pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); |
| 140 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { | 141 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { |
| 141 | changed = 1; | 142 | changed = 1; |
| 142 | if (pin) | 143 | if (pin) |
| 143 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 144 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
| 144 | else | 145 | else |
| 145 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 146 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
| 146 | } | 147 | } |
| 147 | pin = !!(pins & (1 << AMS_DELTA_AGC)); | 148 | pin = !!(pins & (1 << AMS_DELTA_AGC)); |
| 148 | if (pin != ams_delta_audio_agc) { | 149 | if (pin != ams_delta_audio_agc) { |
| 149 | ams_delta_audio_agc = pin; | 150 | ams_delta_audio_agc = pin; |
| 150 | changed = 1; | 151 | changed = 1; |
| 151 | if (pin) | 152 | if (pin) |
| 152 | snd_soc_dapm_enable_pin(dapm, "AGCIN"); | 153 | snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN"); |
| 153 | else | 154 | else |
| 154 | snd_soc_dapm_disable_pin(dapm, "AGCIN"); | 155 | snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); |
| 155 | } | 156 | } |
| 157 | |||
| 156 | if (changed) | 158 | if (changed) |
| 157 | snd_soc_dapm_sync(dapm); | 159 | snd_soc_dapm_sync_unlocked(dapm); |
| 158 | 160 | ||
| 159 | mutex_unlock(&codec->mutex); | 161 | snd_soc_dapm_mutex_unlock(dapm); |
| 160 | 162 | ||
| 161 | return changed; | 163 | return changed; |
| 162 | } | 164 | } |
| @@ -194,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, | |||
| 194 | return 0; | 196 | return 0; |
| 195 | } | 197 | } |
| 196 | 198 | ||
| 197 | static const struct soc_enum ams_delta_audio_enum[] = { | 199 | static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum, |
| 198 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode), | 200 | ams_delta_audio_mode); |
| 199 | ams_delta_audio_mode), | ||
| 200 | }; | ||
| 201 | 201 | ||
| 202 | static const struct snd_kcontrol_new ams_delta_audio_controls[] = { | 202 | static const struct snd_kcontrol_new ams_delta_audio_controls[] = { |
| 203 | SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0], | 203 | SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum, |
| 204 | ams_delta_get_audio_mode, ams_delta_set_audio_mode), | 204 | ams_delta_get_audio_mode, ams_delta_set_audio_mode), |
| 205 | }; | 205 | }; |
| 206 | 206 | ||
| @@ -315,12 +315,17 @@ static void cx81801_close(struct tty_struct *tty) | |||
| 315 | v253_ops.close(tty); | 315 | v253_ops.close(tty); |
| 316 | 316 | ||
| 317 | /* Revert back to default audio input/output constellation */ | 317 | /* Revert back to default audio input/output constellation */ |
| 318 | snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); | 318 | snd_soc_dapm_mutex_lock(dapm); |
| 319 | snd_soc_dapm_enable_pin(dapm, "Earpiece"); | 319 | |
| 320 | snd_soc_dapm_enable_pin(dapm, "Microphone"); | 320 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); |
| 321 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 321 | snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); |
| 322 | snd_soc_dapm_disable_pin(dapm, "AGCIN"); | 322 | snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); |
| 323 | snd_soc_dapm_sync(dapm); | 323 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
| 324 | snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); | ||
| 325 | |||
| 326 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 327 | |||
| 328 | snd_soc_dapm_mutex_unlock(codec); | ||
| 324 | } | 329 | } |
| 325 | 330 | ||
| 326 | /* Line discipline .hangup() */ | 331 | /* Line discipline .hangup() */ |
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index d163e18d85d4..fd4d9c809e50 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
| @@ -68,26 +68,30 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm) | |||
| 68 | break; | 68 | break; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | snd_soc_dapm_mutex_lock(dapm); | ||
| 72 | |||
| 71 | if (n810_spk_func) | 73 | if (n810_spk_func) |
| 72 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 74 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
| 73 | else | 75 | else |
| 74 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 76 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
| 75 | 77 | ||
| 76 | if (hp) | 78 | if (hp) |
| 77 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 79 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 78 | else | 80 | else |
| 79 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 81 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 80 | if (line1l) | 82 | if (line1l) |
| 81 | snd_soc_dapm_enable_pin(dapm, "LINE1L"); | 83 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L"); |
| 82 | else | 84 | else |
| 83 | snd_soc_dapm_disable_pin(dapm, "LINE1L"); | 85 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L"); |
| 84 | 86 | ||
| 85 | if (n810_dmic_func) | 87 | if (n810_dmic_func) |
| 86 | snd_soc_dapm_enable_pin(dapm, "DMic"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); |
| 87 | else | 89 | else |
| 88 | snd_soc_dapm_disable_pin(dapm, "DMic"); | 90 | snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); |
| 91 | |||
| 92 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 89 | 93 | ||
| 90 | snd_soc_dapm_sync(dapm); | 94 | snd_soc_dapm_mutex_unlock(dapm); |
| 91 | } | 95 | } |
| 92 | 96 | ||
| 93 | static int n810_startup(struct snd_pcm_substream *substream) | 97 | static int n810_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 611179c3bca4..7fb3d4b10370 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
| @@ -74,26 +74,30 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm) | |||
| 74 | break; | 74 | break; |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | snd_soc_dapm_mutex_lock(dapm); | ||
| 78 | |||
| 77 | if (rx51_spk_func) | 79 | if (rx51_spk_func) |
| 78 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 80 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
| 79 | else | 81 | else |
| 80 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 82 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
| 81 | if (rx51_dmic_func) | 83 | if (rx51_dmic_func) |
| 82 | snd_soc_dapm_enable_pin(dapm, "DMic"); | 84 | snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); |
| 83 | else | 85 | else |
| 84 | snd_soc_dapm_disable_pin(dapm, "DMic"); | 86 | snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); |
| 85 | if (hp) | 87 | if (hp) |
| 86 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 87 | else | 89 | else |
| 88 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 90 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 89 | if (hs) | 91 | if (hs) |
| 90 | snd_soc_dapm_enable_pin(dapm, "HS Mic"); | 92 | snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); |
| 91 | else | 93 | else |
| 92 | snd_soc_dapm_disable_pin(dapm, "HS Mic"); | 94 | snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); |
| 93 | 95 | ||
| 94 | gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); | 96 | gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); |
| 95 | 97 | ||
| 96 | snd_soc_dapm_sync(dapm); | 98 | snd_soc_dapm_sync_unlocked(dapm); |
| 99 | |||
| 100 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 97 | } | 101 | } |
| 98 | 102 | ||
| 99 | static int rx51_startup(struct snd_pcm_substream *substream) | 103 | static int rx51_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 1853d41034bf..5a88136aa800 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
| @@ -47,64 +47,63 @@ static int corgi_spk_func; | |||
| 47 | 47 | ||
| 48 | static void corgi_ext_control(struct snd_soc_dapm_context *dapm) | 48 | static void corgi_ext_control(struct snd_soc_dapm_context *dapm) |
| 49 | { | 49 | { |
| 50 | snd_soc_dapm_mutex_lock(dapm); | ||
| 51 | |||
| 50 | /* set up jack connection */ | 52 | /* set up jack connection */ |
| 51 | switch (corgi_jack_func) { | 53 | switch (corgi_jack_func) { |
| 52 | case CORGI_HP: | 54 | case CORGI_HP: |
| 53 | /* set = unmute headphone */ | 55 | /* set = unmute headphone */ |
| 54 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); | 56 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
| 55 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 57 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
| 56 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 58 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
| 57 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 59 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 58 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 60 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 59 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 60 | break; | 62 | break; |
| 61 | case CORGI_MIC: | 63 | case CORGI_MIC: |
| 62 | /* reset = mute headphone */ | 64 | /* reset = mute headphone */ |
| 63 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 65 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
| 64 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 66 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
| 65 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 67 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
| 66 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 68 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 69 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 68 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 70 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 69 | break; | 71 | break; |
| 70 | case CORGI_LINE: | 72 | case CORGI_LINE: |
| 71 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 73 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
| 72 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 74 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
| 73 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 75 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
| 74 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 76 | snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); |
| 75 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 77 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 76 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 78 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 77 | break; | 79 | break; |
| 78 | case CORGI_HEADSET: | 80 | case CORGI_HEADSET: |
| 79 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 81 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
| 80 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 82 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
| 81 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 83 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
| 82 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 84 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 83 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 85 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 84 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 86 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
| 85 | break; | 87 | break; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | if (corgi_spk_func == CORGI_SPK_ON) | 90 | if (corgi_spk_func == CORGI_SPK_ON) |
| 89 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 91 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
| 90 | else | 92 | else |
| 91 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 93 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
| 92 | 94 | ||
| 93 | /* signal a DAPM event */ | 95 | /* signal a DAPM event */ |
| 94 | snd_soc_dapm_sync(dapm); | 96 | snd_soc_dapm_sync_unlocked(dapm); |
| 97 | |||
| 98 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 95 | } | 99 | } |
| 96 | 100 | ||
| 97 | static int corgi_startup(struct snd_pcm_substream *substream) | 101 | static int corgi_startup(struct snd_pcm_substream *substream) |
| 98 | { | 102 | { |
| 99 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 103 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 100 | struct snd_soc_codec *codec = rtd->codec; | ||
| 101 | |||
| 102 | mutex_lock(&codec->mutex); | ||
| 103 | 104 | ||
| 104 | /* check the jack status at stream startup */ | 105 | /* check the jack status at stream startup */ |
| 105 | corgi_ext_control(&codec->dapm); | 106 | corgi_ext_control(&rtd->card->dapm); |
| 106 | |||
| 107 | mutex_unlock(&codec->mutex); | ||
| 108 | 107 | ||
| 109 | return 0; | 108 | return 0; |
| 110 | } | 109 | } |
diff --git a/sound/soc/pxa/e740_wm9705.c b/sound/soc/pxa/e740_wm9705.c index 44b5c09d296b..c29fedab2f49 100644 --- a/sound/soc/pxa/e740_wm9705.c +++ b/sound/soc/pxa/e740_wm9705.c | |||
| @@ -103,11 +103,6 @@ static int e740_ac97_init(struct snd_soc_pcm_runtime *rtd) | |||
| 103 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); | 103 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); |
| 104 | snd_soc_dapm_nc_pin(dapm, "MIC2"); | 104 | snd_soc_dapm_nc_pin(dapm, "MIC2"); |
| 105 | 105 | ||
| 106 | snd_soc_dapm_new_controls(dapm, e740_dapm_widgets, | ||
| 107 | ARRAY_SIZE(e740_dapm_widgets)); | ||
| 108 | |||
| 109 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 110 | |||
| 111 | return 0; | 106 | return 0; |
| 112 | } | 107 | } |
| 113 | 108 | ||
| @@ -136,6 +131,11 @@ static struct snd_soc_card e740 = { | |||
| 136 | .owner = THIS_MODULE, | 131 | .owner = THIS_MODULE, |
| 137 | .dai_link = e740_dai, | 132 | .dai_link = e740_dai, |
| 138 | .num_links = ARRAY_SIZE(e740_dai), | 133 | .num_links = ARRAY_SIZE(e740_dai), |
| 134 | |||
| 135 | .dapm_widgets = e740_dapm_widgets, | ||
| 136 | .num_dapm_widgets = ARRAY_SIZE(e740_dapm_widgets), | ||
| 137 | .dapm_routes = audio_map, | ||
| 138 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 139 | }; | 139 | }; |
| 140 | 140 | ||
| 141 | static struct gpio e740_audio_gpios[] = { | 141 | static struct gpio e740_audio_gpios[] = { |
diff --git a/sound/soc/pxa/e750_wm9705.c b/sound/soc/pxa/e750_wm9705.c index c34e447eb991..ee36aba88063 100644 --- a/sound/soc/pxa/e750_wm9705.c +++ b/sound/soc/pxa/e750_wm9705.c | |||
| @@ -85,11 +85,6 @@ static int e750_ac97_init(struct snd_soc_pcm_runtime *rtd) | |||
| 85 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); | 85 | snd_soc_dapm_nc_pin(dapm, "PCBEEP"); |
| 86 | snd_soc_dapm_nc_pin(dapm, "MIC2"); | 86 | snd_soc_dapm_nc_pin(dapm, "MIC2"); |
| 87 | 87 | ||
| 88 | snd_soc_dapm_new_controls(dapm, e750_dapm_widgets, | ||
| 89 | ARRAY_SIZE(e750_dapm_widgets)); | ||
| 90 | |||
| 91 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 92 | |||
| 93 | return 0; | 88 | return 0; |
| 94 | } | 89 | } |
| 95 | 90 | ||
| @@ -119,6 +114,11 @@ static struct snd_soc_card e750 = { | |||
| 119 | .owner = THIS_MODULE, | 114 | .owner = THIS_MODULE, |
| 120 | .dai_link = e750_dai, | 115 | .dai_link = e750_dai, |
| 121 | .num_links = ARRAY_SIZE(e750_dai), | 116 | .num_links = ARRAY_SIZE(e750_dai), |
| 117 | |||
| 118 | .dapm_widgets = e750_dapm_widgets, | ||
| 119 | .num_dapm_widgets = ARRAY_SIZE(e750_dapm_widgets), | ||
| 120 | .dapm_routes = audio_map, | ||
| 121 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 122 | }; | 122 | }; |
| 123 | 123 | ||
| 124 | static struct gpio e750_audio_gpios[] = { | 124 | static struct gpio e750_audio_gpios[] = { |
diff --git a/sound/soc/pxa/e800_wm9712.c b/sound/soc/pxa/e800_wm9712.c index 3137f800b43f..24c2078ce70b 100644 --- a/sound/soc/pxa/e800_wm9712.c +++ b/sound/soc/pxa/e800_wm9712.c | |||
| @@ -71,19 +71,6 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
| 71 | {"MIC2", NULL, "Mic (Internal2)"}, | 71 | {"MIC2", NULL, "Mic (Internal2)"}, |
| 72 | }; | 72 | }; |
| 73 | 73 | ||
| 74 | static int e800_ac97_init(struct snd_soc_pcm_runtime *rtd) | ||
| 75 | { | ||
| 76 | struct snd_soc_codec *codec = rtd->codec; | ||
| 77 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 78 | |||
| 79 | snd_soc_dapm_new_controls(dapm, e800_dapm_widgets, | ||
| 80 | ARRAY_SIZE(e800_dapm_widgets)); | ||
| 81 | |||
| 82 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 83 | |||
| 84 | return 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | static struct snd_soc_dai_link e800_dai[] = { | 74 | static struct snd_soc_dai_link e800_dai[] = { |
| 88 | { | 75 | { |
| 89 | .name = "AC97", | 76 | .name = "AC97", |
| @@ -92,7 +79,6 @@ static struct snd_soc_dai_link e800_dai[] = { | |||
| 92 | .codec_dai_name = "wm9712-hifi", | 79 | .codec_dai_name = "wm9712-hifi", |
| 93 | .platform_name = "pxa-pcm-audio", | 80 | .platform_name = "pxa-pcm-audio", |
| 94 | .codec_name = "wm9712-codec", | 81 | .codec_name = "wm9712-codec", |
| 95 | .init = e800_ac97_init, | ||
| 96 | }, | 82 | }, |
| 97 | { | 83 | { |
| 98 | .name = "AC97 Aux", | 84 | .name = "AC97 Aux", |
| @@ -109,6 +95,11 @@ static struct snd_soc_card e800 = { | |||
| 109 | .owner = THIS_MODULE, | 95 | .owner = THIS_MODULE, |
| 110 | .dai_link = e800_dai, | 96 | .dai_link = e800_dai, |
| 111 | .num_links = ARRAY_SIZE(e800_dai), | 97 | .num_links = ARRAY_SIZE(e800_dai), |
| 98 | |||
| 99 | .dapm_widgets = e800_dapm_widgets, | ||
| 100 | .num_dapm_widgets = ARRAY_SIZE(e800_dapm_widgets), | ||
| 101 | .dapm_routes = audio_map, | ||
| 102 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 112 | }; | 103 | }; |
| 113 | 104 | ||
| 114 | static struct gpio e800_audio_gpios[] = { | 105 | static struct gpio e800_audio_gpios[] = { |
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index aace19e0fe2c..41ab6678b65d 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c | |||
| @@ -45,27 +45,31 @@ static void magician_ext_control(struct snd_soc_codec *codec) | |||
| 45 | { | 45 | { |
| 46 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 46 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 47 | 47 | ||
| 48 | snd_soc_dapm_mutex_lock(dapm); | ||
| 49 | |||
| 48 | if (magician_spk_switch) | 50 | if (magician_spk_switch) |
| 49 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 51 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
| 50 | else | 52 | else |
| 51 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 53 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
| 52 | if (magician_hp_switch) | 54 | if (magician_hp_switch) |
| 53 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 55 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 54 | else | 56 | else |
| 55 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 57 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 56 | 58 | ||
| 57 | switch (magician_in_sel) { | 59 | switch (magician_in_sel) { |
| 58 | case MAGICIAN_MIC: | 60 | case MAGICIAN_MIC: |
| 59 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic"); |
| 60 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); | 62 | snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic"); |
| 61 | break; | 63 | break; |
| 62 | case MAGICIAN_MIC_EXT: | 64 | case MAGICIAN_MIC_EXT: |
| 63 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | 65 | snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic"); |
| 64 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | 66 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic"); |
| 65 | break; | 67 | break; |
| 66 | } | 68 | } |
| 67 | 69 | ||
| 68 | snd_soc_dapm_sync(dapm); | 70 | snd_soc_dapm_sync_unlocked(dapm); |
| 71 | |||
| 72 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | static int magician_startup(struct snd_pcm_substream *substream) | 75 | static int magician_startup(struct snd_pcm_substream *substream) |
| @@ -73,13 +77,9 @@ static int magician_startup(struct snd_pcm_substream *substream) | |||
| 73 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 74 | struct snd_soc_codec *codec = rtd->codec; | 78 | struct snd_soc_codec *codec = rtd->codec; |
| 75 | 79 | ||
| 76 | mutex_lock(&codec->mutex); | ||
| 77 | |||
| 78 | /* check the jack status at stream startup */ | 80 | /* check the jack status at stream startup */ |
| 79 | magician_ext_control(codec); | 81 | magician_ext_control(codec); |
| 80 | 82 | ||
| 81 | mutex_unlock(&codec->mutex); | ||
| 82 | |||
| 83 | return 0; | 83 | return 0; |
| 84 | } | 84 | } |
| 85 | 85 | ||
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 160c5245448f..595eee341e90 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
| @@ -127,16 +127,8 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
| 127 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) | 127 | static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
| 128 | { | 128 | { |
| 129 | struct snd_soc_codec *codec = rtd->codec; | 129 | struct snd_soc_codec *codec = rtd->codec; |
| 130 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 131 | unsigned short reg; | 130 | unsigned short reg; |
| 132 | 131 | ||
| 133 | /* Add mioa701 specific widgets */ | ||
| 134 | snd_soc_dapm_new_controls(dapm, mioa701_dapm_widgets, | ||
| 135 | ARRAY_SIZE(mioa701_dapm_widgets)); | ||
| 136 | |||
| 137 | /* Set up mioa701 specific audio path audio_mapnects */ | ||
| 138 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 139 | |||
| 140 | /* Prepare GPIO8 for rear speaker amplifier */ | 132 | /* Prepare GPIO8 for rear speaker amplifier */ |
| 141 | reg = codec->driver->read(codec, AC97_GPIO_CFG); | 133 | reg = codec->driver->read(codec, AC97_GPIO_CFG); |
| 142 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); | 134 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); |
| @@ -145,12 +137,6 @@ static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd) | |||
| 145 | reg = codec->driver->read(codec, AC97_3D_CONTROL); | 137 | reg = codec->driver->read(codec, AC97_3D_CONTROL); |
| 146 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); | 138 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); |
| 147 | 139 | ||
| 148 | snd_soc_dapm_enable_pin(dapm, "Front Speaker"); | ||
| 149 | snd_soc_dapm_enable_pin(dapm, "Rear Speaker"); | ||
| 150 | snd_soc_dapm_enable_pin(dapm, "Front Mic"); | ||
| 151 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); | ||
| 152 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); | ||
| 153 | |||
| 154 | return 0; | 140 | return 0; |
| 155 | } | 141 | } |
| 156 | 142 | ||
| @@ -183,6 +169,11 @@ static struct snd_soc_card mioa701 = { | |||
| 183 | .owner = THIS_MODULE, | 169 | .owner = THIS_MODULE, |
| 184 | .dai_link = mioa701_dai, | 170 | .dai_link = mioa701_dai, |
| 185 | .num_links = ARRAY_SIZE(mioa701_dai), | 171 | .num_links = ARRAY_SIZE(mioa701_dai), |
| 172 | |||
| 173 | .dapm_widgets = mioa701_dapm_widgets, | ||
| 174 | .num_dapm_widgets = ARRAY_SIZE(mioa701_dapm_widgets), | ||
| 175 | .dapm_routes = audio_map, | ||
| 176 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 186 | }; | 177 | }; |
| 187 | 178 | ||
| 188 | static int mioa701_wm9713_probe(struct platform_device *pdev) | 179 | static int mioa701_wm9713_probe(struct platform_device *pdev) |
diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c index c93e138d8dc3..c6bdc6c0eff6 100644 --- a/sound/soc/pxa/poodle.c +++ b/sound/soc/pxa/poodle.c | |||
| @@ -74,14 +74,9 @@ static void poodle_ext_control(struct snd_soc_dapm_context *dapm) | |||
| 74 | static int poodle_startup(struct snd_pcm_substream *substream) | 74 | static int poodle_startup(struct snd_pcm_substream *substream) |
| 75 | { | 75 | { |
| 76 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 76 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 77 | struct snd_soc_codec *codec = rtd->codec; | ||
| 78 | |||
| 79 | mutex_lock(&codec->mutex); | ||
| 80 | 77 | ||
| 81 | /* check the jack status at stream startup */ | 78 | /* check the jack status at stream startup */ |
| 82 | poodle_ext_control(&codec->dapm); | 79 | poodle_ext_control(&rtd->card->dapm); |
| 83 | |||
| 84 | mutex_unlock(&codec->mutex); | ||
| 85 | 80 | ||
| 86 | return 0; | 81 | return 0; |
| 87 | } | 82 | } |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index fc052d8247ff..1373b017a951 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
| @@ -46,74 +46,74 @@ static int spitz_mic_gpio; | |||
| 46 | 46 | ||
| 47 | static void spitz_ext_control(struct snd_soc_dapm_context *dapm) | 47 | static void spitz_ext_control(struct snd_soc_dapm_context *dapm) |
| 48 | { | 48 | { |
| 49 | snd_soc_dapm_mutex_lock(dapm); | ||
| 50 | |||
| 49 | if (spitz_spk_func == SPITZ_SPK_ON) | 51 | if (spitz_spk_func == SPITZ_SPK_ON) |
| 50 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 52 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
| 51 | else | 53 | else |
| 52 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 54 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
| 53 | 55 | ||
| 54 | /* set up jack connection */ | 56 | /* set up jack connection */ |
| 55 | switch (spitz_jack_func) { | 57 | switch (spitz_jack_func) { |
| 56 | case SPITZ_HP: | 58 | case SPITZ_HP: |
| 57 | /* enable and unmute hp jack, disable mic bias */ | 59 | /* enable and unmute hp jack, disable mic bias */ |
| 58 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 60 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 59 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
| 60 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 62 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 61 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 63 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 62 | gpio_set_value(SPITZ_GPIO_MUTE_L, 1); | 64 | gpio_set_value(SPITZ_GPIO_MUTE_L, 1); |
| 63 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); | 65 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
| 64 | break; | 66 | break; |
| 65 | case SPITZ_MIC: | 67 | case SPITZ_MIC: |
| 66 | /* enable mic jack and bias, mute hp */ | 68 | /* enable mic jack and bias, mute hp */ |
| 67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 69 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 68 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 70 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 69 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 71 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 70 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 72 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
| 71 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 73 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
| 72 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 74 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
| 73 | break; | 75 | break; |
| 74 | case SPITZ_LINE: | 76 | case SPITZ_LINE: |
| 75 | /* enable line jack, disable mic bias and mute hp */ | 77 | /* enable line jack, disable mic bias and mute hp */ |
| 76 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 78 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 77 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 79 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 78 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 80 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
| 79 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 81 | snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); |
| 80 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 82 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
| 81 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 83 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
| 82 | break; | 84 | break; |
| 83 | case SPITZ_HEADSET: | 85 | case SPITZ_HEADSET: |
| 84 | /* enable and unmute headset jack enable mic bias, mute L hp */ | 86 | /* enable and unmute headset jack enable mic bias, mute L hp */ |
| 85 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 87 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 86 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
| 87 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 89 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 88 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 90 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
| 89 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 91 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
| 90 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); | 92 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
| 91 | break; | 93 | break; |
| 92 | case SPITZ_HP_OFF: | 94 | case SPITZ_HP_OFF: |
| 93 | 95 | ||
| 94 | /* jack removed, everything off */ | 96 | /* jack removed, everything off */ |
| 95 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 97 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 96 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 98 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 97 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 99 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
| 98 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 100 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
| 99 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 101 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
| 100 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 102 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
| 101 | break; | 103 | break; |
| 102 | } | 104 | } |
| 103 | snd_soc_dapm_sync(dapm); | 105 | |
| 106 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 107 | |||
| 108 | snd_soc_dapm_mutex_unlock(dapm); | ||
| 104 | } | 109 | } |
| 105 | 110 | ||
| 106 | static int spitz_startup(struct snd_pcm_substream *substream) | 111 | static int spitz_startup(struct snd_pcm_substream *substream) |
| 107 | { | 112 | { |
| 108 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 113 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 109 | struct snd_soc_codec *codec = rtd->codec; | ||
| 110 | |||
| 111 | mutex_lock(&codec->mutex); | ||
| 112 | 114 | ||
| 113 | /* check the jack status at stream startup */ | 115 | /* check the jack status at stream startup */ |
| 114 | spitz_ext_control(&codec->dapm); | 116 | spitz_ext_control(&rtd->card->dapm); |
| 115 | |||
| 116 | mutex_unlock(&codec->mutex); | ||
| 117 | 117 | ||
| 118 | return 0; | 118 | return 0; |
| 119 | } | 119 | } |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 1d9c2ed223bc..cead1658d10a 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
| @@ -48,31 +48,35 @@ static void tosa_ext_control(struct snd_soc_codec *codec) | |||
| 48 | { | 48 | { |
| 49 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 49 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 50 | 50 | ||
| 51 | snd_soc_dapm_mutex_lock(dapm); | ||
| 52 | |||
| 51 | /* set up jack connection */ | 53 | /* set up jack connection */ |
| 52 | switch (tosa_jack_func) { | 54 | switch (tosa_jack_func) { |
| 53 | case TOSA_HP: | 55 | case TOSA_HP: |
| 54 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 56 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); |
| 55 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 57 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
| 56 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 58 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 57 | break; | 59 | break; |
| 58 | case TOSA_MIC_INT: | 60 | case TOSA_MIC_INT: |
| 59 | snd_soc_dapm_enable_pin(dapm, "Mic (Internal)"); | 61 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)"); |
| 60 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 62 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 61 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 63 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
| 62 | break; | 64 | break; |
| 63 | case TOSA_HEADSET: | 65 | case TOSA_HEADSET: |
| 64 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 66 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); |
| 65 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 67 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
| 66 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 68 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
| 67 | break; | 69 | break; |
| 68 | } | 70 | } |
| 69 | 71 | ||
| 70 | if (tosa_spk_func == TOSA_SPK_ON) | 72 | if (tosa_spk_func == TOSA_SPK_ON) |
| 71 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 73 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
| 72 | else | 74 | else |
| 73 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 75 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
| 76 | |||
| 77 | snd_soc_dapm_sync_unlocked(dapm); | ||
| 74 | 78 | ||
| 75 | snd_soc_dapm_sync(dapm); | 79 | snd_soc_dapm_mutex_unlock(dapm); |
| 76 | } | 80 | } |
| 77 | 81 | ||
| 78 | static int tosa_startup(struct snd_pcm_substream *substream) | 82 | static int tosa_startup(struct snd_pcm_substream *substream) |
| @@ -80,13 +84,9 @@ static int tosa_startup(struct snd_pcm_substream *substream) | |||
| 80 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 84 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 81 | struct snd_soc_codec *codec = rtd->codec; | 85 | struct snd_soc_codec *codec = rtd->codec; |
| 82 | 86 | ||
| 83 | mutex_lock(&codec->mutex); | ||
| 84 | |||
| 85 | /* check the jack status at stream startup */ | 87 | /* check the jack status at stream startup */ |
| 86 | tosa_ext_control(codec); | 88 | tosa_ext_control(codec); |
| 87 | 89 | ||
| 88 | mutex_unlock(&codec->mutex); | ||
| 89 | |||
| 90 | return 0; | 90 | return 0; |
| 91 | } | 91 | } |
| 92 | 92 | ||
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index db8aadf8932d..23bf991e95d5 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
| @@ -71,22 +71,10 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
| 71 | 71 | ||
| 72 | static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd) | 72 | static int zylonite_wm9713_init(struct snd_soc_pcm_runtime *rtd) |
| 73 | { | 73 | { |
| 74 | struct snd_soc_codec *codec = rtd->codec; | ||
| 75 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 76 | |||
| 77 | if (clk_pout) | 74 | if (clk_pout) |
| 78 | snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, | 75 | snd_soc_dai_set_pll(rtd->codec_dai, 0, 0, |
| 79 | clk_get_rate(pout), 0); | 76 | clk_get_rate(pout), 0); |
| 80 | 77 | ||
| 81 | snd_soc_dapm_new_controls(dapm, zylonite_dapm_widgets, | ||
| 82 | ARRAY_SIZE(zylonite_dapm_widgets)); | ||
| 83 | |||
| 84 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 85 | |||
| 86 | /* Static setup for now */ | ||
| 87 | snd_soc_dapm_enable_pin(dapm, "Headphone"); | ||
| 88 | snd_soc_dapm_enable_pin(dapm, "Headset Earpiece"); | ||
| 89 | |||
| 90 | return 0; | 78 | return 0; |
| 91 | } | 79 | } |
| 92 | 80 | ||
| @@ -256,6 +244,11 @@ static struct snd_soc_card zylonite = { | |||
| 256 | .resume_pre = &zylonite_resume_pre, | 244 | .resume_pre = &zylonite_resume_pre, |
| 257 | .dai_link = zylonite_dai, | 245 | .dai_link = zylonite_dai, |
| 258 | .num_links = ARRAY_SIZE(zylonite_dai), | 246 | .num_links = ARRAY_SIZE(zylonite_dai), |
| 247 | |||
| 248 | .dapm_widgets = zylonite_dapm_widgets, | ||
| 249 | .num_dapm_widgets = ARRAY_SIZE(zylonite_dapm_widgets), | ||
| 250 | .dapm_routes = audio_map, | ||
| 251 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 259 | }; | 252 | }; |
| 260 | 253 | ||
| 261 | static struct platform_device *zylonite_snd_ac97_device; | 254 | static struct platform_device *zylonite_snd_ac97_device; |
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 350757400391..f2e289180e46 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
| @@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 | |||
| 117 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" | 117 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" |
| 118 | depends on SND_SOC_SAMSUNG && ARCH_S3C24XX | 118 | depends on SND_SOC_SAMSUNG && ARCH_S3C24XX |
| 119 | select SND_S3C24XX_I2S | 119 | select SND_S3C24XX_I2S |
| 120 | select SND_SOC_TLV320AIC23 | 120 | select SND_SOC_TLV320AIC23_I2C |
| 121 | select SND_SOC_SAMSUNG_SIMTEC | 121 | select SND_SOC_SAMSUNG_SIMTEC |
| 122 | 122 | ||
| 123 | config SND_SOC_SAMSUNG_SIMTEC_HERMES | 123 | config SND_SOC_SAMSUNG_SIMTEC_HERMES |
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index fbced589d077..88b09e022503 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c | |||
| @@ -66,10 +66,6 @@ static int h1940_startup(struct snd_pcm_substream *substream) | |||
| 66 | { | 66 | { |
| 67 | struct snd_pcm_runtime *runtime = substream->runtime; | 67 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 68 | 68 | ||
| 69 | runtime->hw.rate_min = hw_rates.list[0]; | ||
| 70 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; | ||
| 71 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; | ||
| 72 | |||
| 73 | return snd_pcm_hw_constraint_list(runtime, 0, | 69 | return snd_pcm_hw_constraint_list(runtime, 0, |
| 74 | SNDRV_PCM_HW_PARAM_RATE, | 70 | SNDRV_PCM_HW_PARAM_RATE, |
| 75 | &hw_rates); | 71 | &hw_rates); |
| @@ -94,7 +90,7 @@ static int h1940_hw_params(struct snd_pcm_substream *substream, | |||
| 94 | div++; | 90 | div++; |
| 95 | break; | 91 | break; |
| 96 | default: | 92 | default: |
| 97 | dev_err(&rtd->dev, "%s: rate %d is not supported\n", | 93 | dev_err(rtd->dev, "%s: rate %d is not supported\n", |
| 98 | __func__, rate); | 94 | __func__, rate); |
| 99 | return -EINVAL; | 95 | return -EINVAL; |
| 100 | } | 96 | } |
| @@ -181,7 +177,6 @@ static int h1940_uda1380_init(struct snd_soc_pcm_runtime *rtd) | |||
| 181 | { | 177 | { |
| 182 | struct snd_soc_codec *codec = rtd->codec; | 178 | struct snd_soc_codec *codec = rtd->codec; |
| 183 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 179 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 184 | int err; | ||
| 185 | 180 | ||
| 186 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 181 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
| 187 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 182 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index 98a04c11202d..b0800337b79e 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c | |||
| @@ -192,44 +192,6 @@ static struct snd_soc_ops neo1973_voice_ops = { | |||
| 192 | .hw_free = neo1973_voice_hw_free, | 192 | .hw_free = neo1973_voice_hw_free, |
| 193 | }; | 193 | }; |
| 194 | 194 | ||
| 195 | /* Shared routes and controls */ | ||
| 196 | |||
| 197 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { | ||
| 198 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
| 199 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
| 200 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
| 201 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
| 202 | }; | ||
| 203 | |||
| 204 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { | ||
| 205 | /* Connections to the GSM Module */ | ||
| 206 | {"GSM Line Out", NULL, "MONO1"}, | ||
| 207 | {"GSM Line Out", NULL, "MONO2"}, | ||
| 208 | {"RXP", NULL, "GSM Line In"}, | ||
| 209 | {"RXN", NULL, "GSM Line In"}, | ||
| 210 | |||
| 211 | /* Connections to Headset */ | ||
| 212 | {"MIC1", NULL, "Mic Bias"}, | ||
| 213 | {"Mic Bias", NULL, "Headset Mic"}, | ||
| 214 | |||
| 215 | /* Call Mic */ | ||
| 216 | {"MIC2", NULL, "Mic Bias"}, | ||
| 217 | {"MIC2N", NULL, "Mic Bias"}, | ||
| 218 | {"Mic Bias", NULL, "Handset Mic"}, | ||
| 219 | |||
| 220 | /* Connect the ALC pins */ | ||
| 221 | {"ACIN", NULL, "ACOP"}, | ||
| 222 | }; | ||
| 223 | |||
| 224 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { | ||
| 225 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | ||
| 226 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | ||
| 227 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
| 228 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
| 229 | }; | ||
| 230 | |||
| 231 | /* GTA02 specific routes and controls */ | ||
| 232 | |||
| 233 | static int gta02_speaker_enabled; | 195 | static int gta02_speaker_enabled; |
| 234 | 196 | ||
| 235 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, | 197 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, |
| @@ -257,7 +219,34 @@ static int lm4853_event(struct snd_soc_dapm_widget *w, | |||
| 257 | return 0; | 219 | return 0; |
| 258 | } | 220 | } |
| 259 | 221 | ||
| 260 | static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { | 222 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { |
| 223 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
| 224 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
| 225 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
| 226 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
| 227 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
| 228 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | ||
| 229 | }; | ||
| 230 | |||
| 231 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { | ||
| 232 | /* Connections to the GSM Module */ | ||
| 233 | {"GSM Line Out", NULL, "MONO1"}, | ||
| 234 | {"GSM Line Out", NULL, "MONO2"}, | ||
| 235 | {"RXP", NULL, "GSM Line In"}, | ||
| 236 | {"RXN", NULL, "GSM Line In"}, | ||
| 237 | |||
| 238 | /* Connections to Headset */ | ||
| 239 | {"MIC1", NULL, "Mic Bias"}, | ||
| 240 | {"Mic Bias", NULL, "Headset Mic"}, | ||
| 241 | |||
| 242 | /* Call Mic */ | ||
| 243 | {"MIC2", NULL, "Mic Bias"}, | ||
| 244 | {"MIC2N", NULL, "Mic Bias"}, | ||
| 245 | {"Mic Bias", NULL, "Handset Mic"}, | ||
| 246 | |||
| 247 | /* Connect the ALC pins */ | ||
| 248 | {"ACIN", NULL, "ACOP"}, | ||
| 249 | |||
| 261 | /* Connections to the amp */ | 250 | /* Connections to the amp */ |
| 262 | {"Stereo Out", NULL, "LOUT1"}, | 251 | {"Stereo Out", NULL, "LOUT1"}, |
| 263 | {"Stereo Out", NULL, "ROUT1"}, | 252 | {"Stereo Out", NULL, "ROUT1"}, |
| @@ -267,7 +256,11 @@ static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { | |||
| 267 | {"Handset Spk", NULL, "ROUT2"}, | 256 | {"Handset Spk", NULL, "ROUT2"}, |
| 268 | }; | 257 | }; |
| 269 | 258 | ||
| 270 | static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { | 259 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { |
| 260 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | ||
| 261 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | ||
| 262 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
| 263 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
| 271 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | 264 | SOC_DAPM_PIN_SWITCH("Handset Spk"), |
| 272 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | 265 | SOC_DAPM_PIN_SWITCH("Stereo Out"), |
| 273 | 266 | ||
| @@ -276,86 +269,32 @@ static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { | |||
| 276 | lm4853_set_spk), | 269 | lm4853_set_spk), |
| 277 | }; | 270 | }; |
| 278 | 271 | ||
| 279 | static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { | ||
| 280 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
| 281 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | ||
| 282 | }; | ||
| 283 | |||
| 284 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) | ||
| 285 | { | ||
| 286 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 287 | int ret; | ||
| 288 | |||
| 289 | ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, | ||
| 290 | ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); | ||
| 291 | if (ret) | ||
| 292 | return ret; | ||
| 293 | |||
| 294 | ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, | ||
| 295 | ARRAY_SIZE(neo1973_gta02_routes)); | ||
| 296 | if (ret) | ||
| 297 | return ret; | ||
| 298 | |||
| 299 | ret = snd_soc_add_card_controls(codec->card, neo1973_gta02_wm8753_controls, | ||
| 300 | ARRAY_SIZE(neo1973_gta02_wm8753_controls)); | ||
| 301 | if (ret) | ||
| 302 | return ret; | ||
| 303 | |||
| 304 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); | ||
| 305 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); | ||
| 306 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
| 307 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
| 308 | |||
| 309 | return 0; | ||
| 310 | } | ||
| 311 | |||
| 312 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) | 272 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) |
| 313 | { | 273 | { |
| 314 | struct snd_soc_codec *codec = rtd->codec; | 274 | struct snd_soc_codec *codec = rtd->codec; |
| 315 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 275 | struct snd_soc_card *card = rtd->card; |
| 316 | int ret; | ||
| 317 | 276 | ||
| 318 | /* set up NC codec pins */ | 277 | /* set up NC codec pins */ |
| 319 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 278 | snd_soc_dapm_nc_pin(&codec->dapm, "OUT3"); |
| 320 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | 279 | snd_soc_dapm_nc_pin(&codec->dapm, "OUT4"); |
| 321 | snd_soc_dapm_nc_pin(dapm, "LINE1"); | 280 | snd_soc_dapm_nc_pin(&codec->dapm, "LINE1"); |
| 322 | snd_soc_dapm_nc_pin(dapm, "LINE2"); | 281 | snd_soc_dapm_nc_pin(&codec->dapm, "LINE2"); |
| 323 | |||
| 324 | /* Add neo1973 specific widgets */ | ||
| 325 | ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, | ||
| 326 | ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); | ||
| 327 | if (ret) | ||
| 328 | return ret; | ||
| 329 | |||
| 330 | /* add neo1973 specific controls */ | ||
| 331 | ret = snd_soc_add_card_controls(rtd->card, neo1973_wm8753_controls, | ||
| 332 | ARRAY_SIZE(neo1973_wm8753_controls)); | ||
| 333 | if (ret) | ||
| 334 | return ret; | ||
| 335 | |||
| 336 | /* set up neo1973 specific audio routes */ | ||
| 337 | ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, | ||
| 338 | ARRAY_SIZE(neo1973_wm8753_routes)); | ||
| 339 | if (ret) | ||
| 340 | return ret; | ||
| 341 | 282 | ||
| 342 | /* set endpoints to default off mode */ | 283 | /* set endpoints to default off mode */ |
| 343 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | 284 | snd_soc_dapm_disable_pin(&card->dapm, "GSM Line Out"); |
| 344 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | 285 | snd_soc_dapm_disable_pin(&card->dapm, "GSM Line In"); |
| 345 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 286 | snd_soc_dapm_disable_pin(&card->dapm, "Headset Mic"); |
| 346 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); | 287 | snd_soc_dapm_disable_pin(&card->dapm, "Handset Mic"); |
| 288 | snd_soc_dapm_disable_pin(&card->dapm, "Stereo Out"); | ||
| 289 | snd_soc_dapm_disable_pin(&card->dapm, "Handset Spk"); | ||
| 347 | 290 | ||
| 348 | /* allow audio paths from the GSM modem to run during suspend */ | 291 | /* allow audio paths from the GSM modem to run during suspend */ |
| 349 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); | 292 | snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line Out"); |
| 350 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); | 293 | snd_soc_dapm_ignore_suspend(&card->dapm, "GSM Line In"); |
| 351 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); | 294 | snd_soc_dapm_ignore_suspend(&card->dapm, "Headset Mic"); |
| 352 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); | 295 | snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Mic"); |
| 353 | 296 | snd_soc_dapm_ignore_suspend(&card->dapm, "Stereo Out"); | |
| 354 | if (machine_is_neo1973_gta02()) { | 297 | snd_soc_dapm_ignore_suspend(&card->dapm, "Handset Spk"); |
| 355 | ret = neo1973_gta02_wm8753_init(codec); | ||
| 356 | if (ret) | ||
| 357 | return ret; | ||
| 358 | } | ||
| 359 | 298 | ||
| 360 | return 0; | 299 | return 0; |
| 361 | } | 300 | } |
| @@ -409,6 +348,13 @@ static struct snd_soc_card neo1973 = { | |||
| 409 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), | 348 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), |
| 410 | .codec_conf = neo1973_codec_conf, | 349 | .codec_conf = neo1973_codec_conf, |
| 411 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), | 350 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), |
| 351 | |||
| 352 | .controls = neo1973_wm8753_controls, | ||
| 353 | .num_controls = ARRAY_SIZE(neo1973_wm8753_controls), | ||
| 354 | .dapm_widgets = neo1973_wm8753_dapm_widgets, | ||
| 355 | .num_dapm_widgets = ARRAY_SIZE(neo1973_wm8753_dapm_widgets), | ||
| 356 | .dapm_routes = neo1973_wm8753_routes, | ||
| 357 | .num_dapm_routes = ARRAY_SIZE(neo1973_wm8753_routes), | ||
| 412 | }; | 358 | }; |
| 413 | 359 | ||
| 414 | static struct platform_device *neo1973_snd_device; | 360 | static struct platform_device *neo1973_snd_device; |
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index 06ebdc061770..2982d9e7f268 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c | |||
| @@ -131,10 +131,6 @@ static int rx1950_startup(struct snd_pcm_substream *substream) | |||
| 131 | { | 131 | { |
| 132 | struct snd_pcm_runtime *runtime = substream->runtime; | 132 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 133 | 133 | ||
| 134 | runtime->hw.rate_min = hw_rates.list[0]; | ||
| 135 | runtime->hw.rate_max = hw_rates.list[hw_rates.count - 1]; | ||
| 136 | runtime->hw.rates = SNDRV_PCM_RATE_KNOT; | ||
| 137 | |||
| 138 | return snd_pcm_hw_constraint_list(runtime, 0, | 134 | return snd_pcm_hw_constraint_list(runtime, 0, |
| 139 | SNDRV_PCM_HW_PARAM_RATE, | 135 | SNDRV_PCM_HW_PARAM_RATE, |
| 140 | &hw_rates); | 136 | &hw_rates); |
| @@ -226,7 +222,6 @@ static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd) | |||
| 226 | { | 222 | { |
| 227 | struct snd_soc_codec *codec = rtd->codec; | 223 | struct snd_soc_codec *codec = rtd->codec; |
| 228 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 224 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 229 | int err; | ||
| 230 | 225 | ||
| 231 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 226 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
| 232 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 227 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index d38ae98e2f32..682eb4f7ba0c 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
| @@ -202,7 +202,7 @@ static int smdk_audio_probe(struct platform_device *pdev) | |||
| 202 | 202 | ||
| 203 | static struct platform_driver smdk_audio_driver = { | 203 | static struct platform_driver smdk_audio_driver = { |
| 204 | .driver = { | 204 | .driver = { |
| 205 | .name = "smdk-audio-wm8894", | 205 | .name = "smdk-audio-wm8994", |
| 206 | .owner = THIS_MODULE, | 206 | .owner = THIS_MODULE, |
| 207 | .of_match_table = of_match_ptr(samsung_wm8994_of_match), | 207 | .of_match_table = of_match_ptr(samsung_wm8994_of_match), |
| 208 | .pm = &snd_soc_pm_ops, | 208 | .pm = &snd_soc_pm_ops, |
diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index f21ff608a819..1807b75ccc12 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c | |||
| @@ -44,6 +44,8 @@ static int tobermory_set_bias_level(struct snd_soc_card *card, | |||
| 44 | SND_SOC_CLOCK_IN); | 44 | SND_SOC_CLOCK_IN); |
| 45 | if (ret < 0) { | 45 | if (ret < 0) { |
| 46 | pr_err("Failed to set SYSCLK: %d\n", ret); | 46 | pr_err("Failed to set SYSCLK: %d\n", ret); |
| 47 | snd_soc_dai_set_pll(codec_dai, WM8962_FLL, | ||
| 48 | 0, 0, 0); | ||
| 47 | return ret; | 49 | return ret; |
| 48 | } | 50 | } |
| 49 | } | 51 | } |
diff --git a/sound/soc/sh/migor.c b/sound/soc/sh/migor.c index 5014a884afee..c58c2529f103 100644 --- a/sound/soc/sh/migor.c +++ b/sound/soc/sh/migor.c | |||
| @@ -136,19 +136,6 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
| 136 | { "Mic Bias", NULL, "External Microphone" }, | 136 | { "Mic Bias", NULL, "External Microphone" }, |
| 137 | }; | 137 | }; |
| 138 | 138 | ||
| 139 | static int migor_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
| 140 | { | ||
| 141 | struct snd_soc_codec *codec = rtd->codec; | ||
| 142 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
| 143 | |||
| 144 | snd_soc_dapm_new_controls(dapm, migor_dapm_widgets, | ||
| 145 | ARRAY_SIZE(migor_dapm_widgets)); | ||
| 146 | |||
| 147 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
| 148 | |||
| 149 | return 0; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* migor digital audio interface glue - connects codec <--> CPU */ | 139 | /* migor digital audio interface glue - connects codec <--> CPU */ |
| 153 | static struct snd_soc_dai_link migor_dai = { | 140 | static struct snd_soc_dai_link migor_dai = { |
| 154 | .name = "wm8978", | 141 | .name = "wm8978", |
| @@ -158,7 +145,6 @@ static struct snd_soc_dai_link migor_dai = { | |||
| 158 | .platform_name = "siu-pcm-audio", | 145 | .platform_name = "siu-pcm-audio", |
| 159 | .codec_name = "wm8978.0-001a", | 146 | .codec_name = "wm8978.0-001a", |
| 160 | .ops = &migor_dai_ops, | 147 | .ops = &migor_dai_ops, |
| 161 | .init = migor_dai_init, | ||
| 162 | }; | 148 | }; |
| 163 | 149 | ||
| 164 | /* migor audio machine driver */ | 150 | /* migor audio machine driver */ |
| @@ -167,6 +153,11 @@ static struct snd_soc_card snd_soc_migor = { | |||
| 167 | .owner = THIS_MODULE, | 153 | .owner = THIS_MODULE, |
| 168 | .dai_link = &migor_dai, | 154 | .dai_link = &migor_dai, |
| 169 | .num_links = 1, | 155 | .num_links = 1, |
| 156 | |||
| 157 | .dapm_widgets = migor_dapm_widgets, | ||
| 158 | .num_dapm_widgets = ARRAY_SIZE(migor_dapm_widgets), | ||
| 159 | .dapm_routes = audio_map, | ||
| 160 | .num_dapm_routes = ARRAY_SIZE(audio_map), | ||
| 170 | }; | 161 | }; |
| 171 | 162 | ||
| 172 | static struct platform_device *migor_snd_device; | 163 | static struct platform_device *migor_snd_device; |
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 0ff492df7929..7d0051ced838 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile | |||
| @@ -1,2 +1,2 @@ | |||
| 1 | snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o | 1 | snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o |
| 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file | 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index a53235c4d1b0..953f1cce982d 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
| @@ -25,15 +25,165 @@ struct rsnd_adg { | |||
| 25 | }; | 25 | }; |
| 26 | 26 | ||
| 27 | #define for_each_rsnd_clk(pos, adg, i) \ | 27 | #define for_each_rsnd_clk(pos, adg, i) \ |
| 28 | for (i = 0, (pos) = adg->clk[i]; \ | 28 | for (i = 0; \ |
| 29 | i < CLKMAX; \ | 29 | (i < CLKMAX) && \ |
| 30 | i++, (pos) = adg->clk[i]) | 30 | ((pos) = adg->clk[i]); \ |
| 31 | i++) | ||
| 31 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) | 32 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) |
| 32 | 33 | ||
| 33 | static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | 34 | |
| 34 | struct rsnd_mod *mod, | 35 | static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) |
| 35 | unsigned int src_rate, | 36 | { |
| 36 | unsigned int dst_rate) | 37 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); |
| 38 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 39 | int id = rsnd_mod_id(mod); | ||
| 40 | int ws = id; | ||
| 41 | |||
| 42 | if (rsnd_ssi_is_pin_sharing(rsnd_ssi_mod_get(priv, id))) { | ||
| 43 | switch (id) { | ||
| 44 | case 1: | ||
| 45 | case 2: | ||
| 46 | ws = 0; | ||
| 47 | break; | ||
| 48 | case 4: | ||
| 49 | ws = 3; | ||
| 50 | break; | ||
| 51 | case 8: | ||
| 52 | ws = 7; | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | return (0x6 + ws) << 8; | ||
| 58 | } | ||
| 59 | |||
| 60 | static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai, | ||
| 61 | struct rsnd_mod *mod, | ||
| 62 | struct rsnd_dai_stream *io, | ||
| 63 | u32 timsel) | ||
| 64 | { | ||
| 65 | int is_play = rsnd_dai_is_play(rdai, io); | ||
| 66 | int id = rsnd_mod_id(mod); | ||
| 67 | int shift = (id % 2) ? 16 : 0; | ||
| 68 | u32 mask, ws; | ||
| 69 | u32 in, out; | ||
| 70 | |||
| 71 | ws = rsnd_adg_ssi_ws_timing_gen2(io); | ||
| 72 | |||
| 73 | in = (is_play) ? timsel : ws; | ||
| 74 | out = (is_play) ? ws : timsel; | ||
| 75 | |||
| 76 | in = in << shift; | ||
| 77 | out = out << shift; | ||
| 78 | mask = 0xffff << shift; | ||
| 79 | |||
| 80 | switch (id / 2) { | ||
| 81 | case 0: | ||
| 82 | rsnd_mod_bset(mod, SRCIN_TIMSEL0, mask, in); | ||
| 83 | rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out); | ||
| 84 | break; | ||
| 85 | case 1: | ||
| 86 | rsnd_mod_bset(mod, SRCIN_TIMSEL1, mask, in); | ||
| 87 | rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out); | ||
| 88 | break; | ||
| 89 | case 2: | ||
| 90 | rsnd_mod_bset(mod, SRCIN_TIMSEL2, mask, in); | ||
| 91 | rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out); | ||
| 92 | break; | ||
| 93 | case 3: | ||
| 94 | rsnd_mod_bset(mod, SRCIN_TIMSEL3, mask, in); | ||
| 95 | rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out); | ||
| 96 | break; | ||
| 97 | case 4: | ||
| 98 | rsnd_mod_bset(mod, SRCIN_TIMSEL4, mask, in); | ||
| 99 | rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out); | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, | ||
| 107 | struct rsnd_dai *rdai, | ||
| 108 | struct rsnd_dai_stream *io, | ||
| 109 | unsigned int src_rate, | ||
| 110 | unsigned int dst_rate) | ||
| 111 | { | ||
| 112 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 113 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
| 114 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 115 | int idx, sel, div, step, ret; | ||
| 116 | u32 val, en; | ||
| 117 | unsigned int min, diff; | ||
| 118 | unsigned int sel_rate [] = { | ||
| 119 | clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ | ||
| 120 | clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ | ||
| 121 | clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ | ||
| 122 | adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */ | ||
| 123 | adg->rbgb_rate_for_48khz_div_6, /* 0100: RBGB */ | ||
| 124 | }; | ||
| 125 | |||
| 126 | min = ~0; | ||
| 127 | val = 0; | ||
| 128 | en = 0; | ||
| 129 | for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { | ||
| 130 | idx = 0; | ||
| 131 | step = 2; | ||
| 132 | |||
| 133 | if (!sel_rate[sel]) | ||
| 134 | continue; | ||
| 135 | |||
| 136 | for (div = 2; div <= 98304; div += step) { | ||
| 137 | diff = abs(src_rate - sel_rate[sel] / div); | ||
| 138 | if (min > diff) { | ||
| 139 | val = (sel << 8) | idx; | ||
| 140 | min = diff; | ||
| 141 | en = 1 << (sel + 1); /* fixme */ | ||
| 142 | } | ||
| 143 | |||
| 144 | /* | ||
| 145 | * step of 0_0000 / 0_0001 / 0_1101 | ||
| 146 | * are out of order | ||
| 147 | */ | ||
| 148 | if ((idx > 2) && (idx % 2)) | ||
| 149 | step *= 2; | ||
| 150 | if (idx == 0x1c) { | ||
| 151 | div += step; | ||
| 152 | step *= 2; | ||
| 153 | } | ||
| 154 | idx++; | ||
| 155 | } | ||
| 156 | } | ||
| 157 | |||
| 158 | if (min == ~0) { | ||
| 159 | dev_err(dev, "no Input clock\n"); | ||
| 160 | return -EIO; | ||
| 161 | } | ||
| 162 | |||
| 163 | ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val); | ||
| 164 | if (ret < 0) { | ||
| 165 | dev_err(dev, "timsel error\n"); | ||
| 166 | return ret; | ||
| 167 | } | ||
| 168 | |||
| 169 | rsnd_mod_bset(mod, DIV_EN, en, en); | ||
| 170 | |||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | |||
| 174 | int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
| 175 | struct rsnd_dai *rdai, | ||
| 176 | struct rsnd_dai_stream *io) | ||
| 177 | { | ||
| 178 | u32 val = rsnd_adg_ssi_ws_timing_gen2(io); | ||
| 179 | |||
| 180 | return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val); | ||
| 181 | } | ||
| 182 | |||
| 183 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | ||
| 184 | struct rsnd_mod *mod, | ||
| 185 | unsigned int src_rate, | ||
| 186 | unsigned int dst_rate) | ||
| 37 | { | 187 | { |
| 38 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 188 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
| 39 | struct device *dev = rsnd_priv_to_dev(priv); | 189 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -91,18 +241,6 @@ find_rate: | |||
| 91 | return 0; | 241 | return 0; |
| 92 | } | 242 | } |
| 93 | 243 | ||
| 94 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | ||
| 95 | struct rsnd_mod *mod, | ||
| 96 | unsigned int src_rate, | ||
| 97 | unsigned int dst_rate) | ||
| 98 | { | ||
| 99 | if (rsnd_is_gen1(priv)) | ||
| 100 | return rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
| 101 | src_rate, dst_rate); | ||
| 102 | |||
| 103 | return -EINVAL; | ||
| 104 | } | ||
| 105 | |||
| 106 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) | 244 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) |
| 107 | { | 245 | { |
| 108 | int id = rsnd_mod_id(mod); | 246 | int id = rsnd_mod_id(mod); |
| @@ -254,13 +392,13 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) | |||
| 254 | } | 392 | } |
| 255 | 393 | ||
| 256 | int rsnd_adg_probe(struct platform_device *pdev, | 394 | int rsnd_adg_probe(struct platform_device *pdev, |
| 257 | struct rcar_snd_info *info, | ||
| 258 | struct rsnd_priv *priv) | 395 | struct rsnd_priv *priv) |
| 259 | { | 396 | { |
| 260 | struct rsnd_adg *adg; | 397 | struct rsnd_adg *adg; |
| 261 | struct device *dev = rsnd_priv_to_dev(priv); | 398 | struct device *dev = rsnd_priv_to_dev(priv); |
| 262 | struct clk *clk; | 399 | struct clk *clk, *clk_orig; |
| 263 | int i; | 400 | int i; |
| 401 | bool use_old_style = false; | ||
| 264 | 402 | ||
| 265 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); | 403 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); |
| 266 | if (!adg) { | 404 | if (!adg) { |
| @@ -268,10 +406,39 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
| 268 | return -ENOMEM; | 406 | return -ENOMEM; |
| 269 | } | 407 | } |
| 270 | 408 | ||
| 271 | adg->clk[CLKA] = clk_get(NULL, "audio_clk_a"); | 409 | clk_orig = devm_clk_get(dev, NULL); |
| 272 | adg->clk[CLKB] = clk_get(NULL, "audio_clk_b"); | 410 | adg->clk[CLKA] = devm_clk_get(dev, "clk_a"); |
| 273 | adg->clk[CLKC] = clk_get(NULL, "audio_clk_c"); | 411 | adg->clk[CLKB] = devm_clk_get(dev, "clk_b"); |
| 274 | adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal"); | 412 | adg->clk[CLKC] = devm_clk_get(dev, "clk_c"); |
| 413 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); | ||
| 414 | |||
| 415 | /* | ||
| 416 | * It request device dependent audio clock. | ||
| 417 | * But above all clks will indicate rsnd module clock | ||
| 418 | * if platform doesn't it | ||
| 419 | */ | ||
| 420 | for_each_rsnd_clk(clk, adg, i) { | ||
| 421 | if (clk_orig == clk) { | ||
| 422 | dev_warn(dev, | ||
| 423 | "doesn't have device dependent clock, use independent clock\n"); | ||
| 424 | use_old_style = true; | ||
| 425 | break; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | /* | ||
| 430 | * note: | ||
| 431 | * these exist in order to keep compatible with | ||
| 432 | * platform which has device independent audio clock, | ||
| 433 | * but will be removed soon | ||
| 434 | */ | ||
| 435 | if (use_old_style) { | ||
| 436 | adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a"); | ||
| 437 | adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b"); | ||
| 438 | adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c"); | ||
| 439 | adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal"); | ||
| 440 | } | ||
| 441 | |||
| 275 | for_each_rsnd_clk(clk, adg, i) { | 442 | for_each_rsnd_clk(clk, adg, i) { |
| 276 | if (IS_ERR(clk)) { | 443 | if (IS_ERR(clk)) { |
| 277 | dev_err(dev, "Audio clock failed\n"); | 444 | dev_err(dev, "Audio clock failed\n"); |
| @@ -287,14 +454,3 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
| 287 | 454 | ||
| 288 | return 0; | 455 | return 0; |
| 289 | } | 456 | } |
| 290 | |||
| 291 | void rsnd_adg_remove(struct platform_device *pdev, | ||
| 292 | struct rsnd_priv *priv) | ||
| 293 | { | ||
| 294 | struct rsnd_adg *adg = priv->adg; | ||
| 295 | struct clk *clk; | ||
| 296 | int i; | ||
| 297 | |||
| 298 | for_each_rsnd_clk(clk, adg, i) | ||
| 299 | clk_put(clk); | ||
| 300 | } | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 3a4fe9d0d4f2..d836e8a9fdce 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
| @@ -73,13 +73,13 @@ | |||
| 73 | * | +- ssi[2] | 73 | * | +- ssi[2] |
| 74 | * | ... | 74 | * | ... |
| 75 | * | | 75 | * | |
| 76 | * | ** these control scu | 76 | * | ** these control src |
| 77 | * | | 77 | * | |
| 78 | * +- scu | 78 | * +- src |
| 79 | * | | 79 | * | |
| 80 | * +- scu[0] | 80 | * +- src[0] |
| 81 | * +- scu[1] | 81 | * +- src[1] |
| 82 | * +- scu[2] | 82 | * +- src[2] |
| 83 | * ... | 83 | * ... |
| 84 | * | 84 | * |
| 85 | * | 85 | * |
| @@ -107,6 +107,11 @@ | |||
| 107 | (!(priv->info->func) ? 0 : \ | 107 | (!(priv->info->func) ? 0 : \ |
| 108 | priv->info->func(param)) | 108 | priv->info->func(param)) |
| 109 | 109 | ||
| 110 | #define rsnd_is_enable_path(io, name) \ | ||
| 111 | ((io)->info ? (io)->info->name : NULL) | ||
| 112 | #define rsnd_info_id(priv, io, name) \ | ||
| 113 | ((io)->info->name - priv->info->name##_info) | ||
| 114 | |||
| 110 | /* | 115 | /* |
| 111 | * rsnd_mod functions | 116 | * rsnd_mod functions |
| 112 | */ | 117 | */ |
| @@ -121,17 +126,19 @@ char *rsnd_mod_name(struct rsnd_mod *mod) | |||
| 121 | void rsnd_mod_init(struct rsnd_priv *priv, | 126 | void rsnd_mod_init(struct rsnd_priv *priv, |
| 122 | struct rsnd_mod *mod, | 127 | struct rsnd_mod *mod, |
| 123 | struct rsnd_mod_ops *ops, | 128 | struct rsnd_mod_ops *ops, |
| 129 | enum rsnd_mod_type type, | ||
| 124 | int id) | 130 | int id) |
| 125 | { | 131 | { |
| 126 | mod->priv = priv; | 132 | mod->priv = priv; |
| 127 | mod->id = id; | 133 | mod->id = id; |
| 128 | mod->ops = ops; | 134 | mod->ops = ops; |
| 129 | INIT_LIST_HEAD(&mod->list); | 135 | mod->type = type; |
| 130 | } | 136 | } |
| 131 | 137 | ||
| 132 | /* | 138 | /* |
| 133 | * rsnd_dma functions | 139 | * rsnd_dma functions |
| 134 | */ | 140 | */ |
| 141 | static void __rsnd_dma_start(struct rsnd_dma *dma); | ||
| 135 | static void rsnd_dma_continue(struct rsnd_dma *dma) | 142 | static void rsnd_dma_continue(struct rsnd_dma *dma) |
| 136 | { | 143 | { |
| 137 | /* push next A or B plane */ | 144 | /* push next A or B plane */ |
| @@ -142,8 +149,9 @@ static void rsnd_dma_continue(struct rsnd_dma *dma) | |||
| 142 | void rsnd_dma_start(struct rsnd_dma *dma) | 149 | void rsnd_dma_start(struct rsnd_dma *dma) |
| 143 | { | 150 | { |
| 144 | /* push both A and B plane*/ | 151 | /* push both A and B plane*/ |
| 152 | dma->offset = 0; | ||
| 145 | dma->submit_loop = 2; | 153 | dma->submit_loop = 2; |
| 146 | schedule_work(&dma->work); | 154 | __rsnd_dma_start(dma); |
| 147 | } | 155 | } |
| 148 | 156 | ||
| 149 | void rsnd_dma_stop(struct rsnd_dma *dma) | 157 | void rsnd_dma_stop(struct rsnd_dma *dma) |
| @@ -156,12 +164,26 @@ void rsnd_dma_stop(struct rsnd_dma *dma) | |||
| 156 | static void rsnd_dma_complete(void *data) | 164 | static void rsnd_dma_complete(void *data) |
| 157 | { | 165 | { |
| 158 | struct rsnd_dma *dma = (struct rsnd_dma *)data; | 166 | struct rsnd_dma *dma = (struct rsnd_dma *)data; |
| 159 | struct rsnd_priv *priv = dma->priv; | 167 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
| 168 | struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma)); | ||
| 169 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
| 160 | unsigned long flags; | 170 | unsigned long flags; |
| 161 | 171 | ||
| 162 | rsnd_lock(priv, flags); | 172 | rsnd_lock(priv, flags); |
| 163 | 173 | ||
| 164 | dma->complete(dma); | 174 | /* |
| 175 | * Renesas sound Gen1 needs 1 DMAC, | ||
| 176 | * Gen2 needs 2 DMAC. | ||
| 177 | * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. | ||
| 178 | * But, Audio-DMAC-peri-peri doesn't have interrupt, | ||
| 179 | * and this driver is assuming that here. | ||
| 180 | * | ||
| 181 | * If Audio-DMAC-peri-peri has interrpt, | ||
| 182 | * rsnd_dai_pointer_update() will be called twice, | ||
| 183 | * ant it will breaks io->byte_pos | ||
| 184 | */ | ||
| 185 | |||
| 186 | rsnd_dai_pointer_update(io, io->byte_per_period); | ||
| 165 | 187 | ||
| 166 | if (dma->submit_loop) | 188 | if (dma->submit_loop) |
| 167 | rsnd_dma_continue(dma); | 189 | rsnd_dma_continue(dma); |
| @@ -169,20 +191,23 @@ static void rsnd_dma_complete(void *data) | |||
| 169 | rsnd_unlock(priv, flags); | 191 | rsnd_unlock(priv, flags); |
| 170 | } | 192 | } |
| 171 | 193 | ||
| 172 | static void rsnd_dma_do_work(struct work_struct *work) | 194 | static void __rsnd_dma_start(struct rsnd_dma *dma) |
| 173 | { | 195 | { |
| 174 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | 196 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
| 175 | struct rsnd_priv *priv = dma->priv; | 197 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 198 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
| 199 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 176 | struct device *dev = rsnd_priv_to_dev(priv); | 200 | struct device *dev = rsnd_priv_to_dev(priv); |
| 177 | struct dma_async_tx_descriptor *desc; | 201 | struct dma_async_tx_descriptor *desc; |
| 178 | dma_addr_t buf; | 202 | dma_addr_t buf; |
| 179 | size_t len; | 203 | size_t len = io->byte_per_period; |
| 180 | int i; | 204 | int i; |
| 181 | 205 | ||
| 182 | for (i = 0; i < dma->submit_loop; i++) { | 206 | for (i = 0; i < dma->submit_loop; i++) { |
| 183 | 207 | ||
| 184 | if (dma->inquiry(dma, &buf, &len) < 0) | 208 | buf = runtime->dma_addr + |
| 185 | return; | 209 | rsnd_dai_pointer_offset(io, dma->offset + len); |
| 210 | dma->offset = len; | ||
| 186 | 211 | ||
| 187 | desc = dmaengine_prep_slave_single( | 212 | desc = dmaengine_prep_slave_single( |
| 188 | dma->chan, buf, len, dma->dir, | 213 | dma->chan, buf, len, dma->dir, |
| @@ -204,16 +229,20 @@ static void rsnd_dma_do_work(struct work_struct *work) | |||
| 204 | } | 229 | } |
| 205 | } | 230 | } |
| 206 | 231 | ||
| 232 | static void rsnd_dma_do_work(struct work_struct *work) | ||
| 233 | { | ||
| 234 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | ||
| 235 | |||
| 236 | __rsnd_dma_start(dma); | ||
| 237 | } | ||
| 238 | |||
| 207 | int rsnd_dma_available(struct rsnd_dma *dma) | 239 | int rsnd_dma_available(struct rsnd_dma *dma) |
| 208 | { | 240 | { |
| 209 | return !!dma->chan; | 241 | return !!dma->chan; |
| 210 | } | 242 | } |
| 211 | 243 | ||
| 212 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 244 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
| 213 | int is_play, int id, | 245 | int is_play, int id) |
| 214 | int (*inquiry)(struct rsnd_dma *dma, | ||
| 215 | dma_addr_t *buf, int *len), | ||
| 216 | int (*complete)(struct rsnd_dma *dma)) | ||
| 217 | { | 246 | { |
| 218 | struct device *dev = rsnd_priv_to_dev(priv); | 247 | struct device *dev = rsnd_priv_to_dev(priv); |
| 219 | struct dma_slave_config cfg; | 248 | struct dma_slave_config cfg; |
| @@ -246,9 +275,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
| 246 | goto rsnd_dma_init_err; | 275 | goto rsnd_dma_init_err; |
| 247 | 276 | ||
| 248 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 277 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
| 249 | dma->priv = priv; | ||
| 250 | dma->inquiry = inquiry; | ||
| 251 | dma->complete = complete; | ||
| 252 | INIT_WORK(&dma->work, rsnd_dma_do_work); | 278 | INIT_WORK(&dma->work, rsnd_dma_do_work); |
| 253 | 279 | ||
| 254 | return 0; | 280 | return 0; |
| @@ -271,26 +297,42 @@ void rsnd_dma_quit(struct rsnd_priv *priv, | |||
| 271 | /* | 297 | /* |
| 272 | * rsnd_dai functions | 298 | * rsnd_dai functions |
| 273 | */ | 299 | */ |
| 274 | #define rsnd_dai_call(rdai, io, fn) \ | 300 | #define __rsnd_mod_call(mod, func, rdai, io) \ |
| 275 | ({ \ | 301 | ({ \ |
| 276 | struct rsnd_mod *mod, *n; \ | 302 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
| 277 | int ret = 0; \ | 303 | struct device *dev = rsnd_priv_to_dev(priv); \ |
| 278 | for_each_rsnd_mod(mod, n, io) { \ | 304 | dev_dbg(dev, "%s [%d] %s\n", \ |
| 279 | ret = rsnd_mod_call(mod, fn, rdai, io); \ | 305 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ |
| 280 | if (ret < 0) \ | 306 | (mod)->ops->func(mod, rdai, io); \ |
| 281 | break; \ | 307 | }) |
| 282 | } \ | 308 | |
| 283 | ret; \ | 309 | #define rsnd_mod_call(mod, func, rdai, io) \ |
| 310 | (!(mod) ? -ENODEV : \ | ||
| 311 | !((mod)->ops->func) ? 0 : \ | ||
| 312 | __rsnd_mod_call(mod, func, (rdai), (io))) | ||
| 313 | |||
| 314 | #define rsnd_dai_call(rdai, io, fn) \ | ||
| 315 | ({ \ | ||
| 316 | struct rsnd_mod *mod; \ | ||
| 317 | int ret = 0, i; \ | ||
| 318 | for (i = 0; i < RSND_MOD_MAX; i++) { \ | ||
| 319 | mod = (io)->mod[i]; \ | ||
| 320 | if (!mod) \ | ||
| 321 | continue; \ | ||
| 322 | ret = rsnd_mod_call(mod, fn, (rdai), (io)); \ | ||
| 323 | if (ret < 0) \ | ||
| 324 | break; \ | ||
| 325 | } \ | ||
| 326 | ret; \ | ||
| 284 | }) | 327 | }) |
| 285 | 328 | ||
| 286 | int rsnd_dai_connect(struct rsnd_dai *rdai, | 329 | static int rsnd_dai_connect(struct rsnd_mod *mod, |
| 287 | struct rsnd_mod *mod, | 330 | struct rsnd_dai_stream *io) |
| 288 | struct rsnd_dai_stream *io) | ||
| 289 | { | 331 | { |
| 290 | if (!mod) | 332 | if (!mod) |
| 291 | return -EIO; | 333 | return -EIO; |
| 292 | 334 | ||
| 293 | if (!list_empty(&mod->list)) { | 335 | if (io->mod[mod->type]) { |
| 294 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 336 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 295 | struct device *dev = rsnd_priv_to_dev(priv); | 337 | struct device *dev = rsnd_priv_to_dev(priv); |
| 296 | 338 | ||
| @@ -300,14 +342,8 @@ int rsnd_dai_connect(struct rsnd_dai *rdai, | |||
| 300 | return -EIO; | 342 | return -EIO; |
| 301 | } | 343 | } |
| 302 | 344 | ||
| 303 | list_add_tail(&mod->list, &io->head); | 345 | io->mod[mod->type] = mod; |
| 304 | 346 | mod->io = io; | |
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | int rsnd_dai_disconnect(struct rsnd_mod *mod) | ||
| 309 | { | ||
| 310 | list_del_init(&mod->list); | ||
| 311 | 347 | ||
| 312 | return 0; | 348 | return 0; |
| 313 | } | 349 | } |
| @@ -316,7 +352,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | |||
| 316 | { | 352 | { |
| 317 | int id = rdai - priv->rdai; | 353 | int id = rdai - priv->rdai; |
| 318 | 354 | ||
| 319 | if ((id < 0) || (id >= rsnd_dai_nr(priv))) | 355 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
| 320 | return -EINVAL; | 356 | return -EINVAL; |
| 321 | 357 | ||
| 322 | return id; | 358 | return id; |
| @@ -324,7 +360,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | |||
| 324 | 360 | ||
| 325 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) | 361 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) |
| 326 | { | 362 | { |
| 327 | if ((id < 0) || (id >= rsnd_dai_nr(priv))) | 363 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
| 328 | return NULL; | 364 | return NULL; |
| 329 | 365 | ||
| 330 | return priv->rdai + id; | 366 | return priv->rdai + id; |
| @@ -382,10 +418,6 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | |||
| 382 | { | 418 | { |
| 383 | struct snd_pcm_runtime *runtime = substream->runtime; | 419 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 384 | 420 | ||
| 385 | if (!list_empty(&io->head)) | ||
| 386 | return -EIO; | ||
| 387 | |||
| 388 | INIT_LIST_HEAD(&io->head); | ||
| 389 | io->substream = substream; | 421 | io->substream = substream; |
| 390 | io->byte_pos = 0; | 422 | io->byte_pos = 0; |
| 391 | io->period_pos = 0; | 423 | io->period_pos = 0; |
| @@ -440,10 +472,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 440 | if (ret < 0) | 472 | if (ret < 0) |
| 441 | goto dai_trigger_end; | 473 | goto dai_trigger_end; |
| 442 | 474 | ||
| 443 | ret = rsnd_gen_path_init(priv, rdai, io); | ||
| 444 | if (ret < 0) | ||
| 445 | goto dai_trigger_end; | ||
| 446 | |||
| 447 | ret = rsnd_dai_call(rdai, io, init); | 475 | ret = rsnd_dai_call(rdai, io, init); |
| 448 | if (ret < 0) | 476 | if (ret < 0) |
| 449 | goto dai_trigger_end; | 477 | goto dai_trigger_end; |
| @@ -461,10 +489,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 461 | if (ret < 0) | 489 | if (ret < 0) |
| 462 | goto dai_trigger_end; | 490 | goto dai_trigger_end; |
| 463 | 491 | ||
| 464 | ret = rsnd_gen_path_exit(priv, rdai, io); | ||
| 465 | if (ret < 0) | ||
| 466 | goto dai_trigger_end; | ||
| 467 | |||
| 468 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); | 492 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); |
| 469 | if (ret < 0) | 493 | if (ret < 0) |
| 470 | goto dai_trigger_end; | 494 | goto dai_trigger_end; |
| @@ -540,24 +564,86 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | |||
| 540 | .set_fmt = rsnd_soc_dai_set_fmt, | 564 | .set_fmt = rsnd_soc_dai_set_fmt, |
| 541 | }; | 565 | }; |
| 542 | 566 | ||
| 567 | static int rsnd_path_init(struct rsnd_priv *priv, | ||
| 568 | struct rsnd_dai *rdai, | ||
| 569 | struct rsnd_dai_stream *io) | ||
| 570 | { | ||
| 571 | struct rsnd_mod *mod; | ||
| 572 | struct rsnd_dai_platform_info *dai_info = rdai->info; | ||
| 573 | int ret; | ||
| 574 | int ssi_id = -1; | ||
| 575 | int src_id = -1; | ||
| 576 | |||
| 577 | /* | ||
| 578 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
| 579 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
| 580 | * | ||
| 581 | * Easy image is.. | ||
| 582 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
| 583 | * | ||
| 584 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
| 585 | * using fixed path. | ||
| 586 | */ | ||
| 587 | if (dai_info) { | ||
| 588 | if (rsnd_is_enable_path(io, ssi)) | ||
| 589 | ssi_id = rsnd_info_id(priv, io, ssi); | ||
| 590 | if (rsnd_is_enable_path(io, src)) | ||
| 591 | src_id = rsnd_info_id(priv, io, src); | ||
| 592 | } else { | ||
| 593 | /* get SSI's ID */ | ||
| 594 | mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
| 595 | rsnd_dai_id(priv, rdai), | ||
| 596 | rsnd_dai_is_play(rdai, io)); | ||
| 597 | if (!mod) | ||
| 598 | return 0; | ||
| 599 | ssi_id = src_id = rsnd_mod_id(mod); | ||
| 600 | } | ||
| 601 | |||
| 602 | ret = 0; | ||
| 603 | |||
| 604 | /* SRC */ | ||
| 605 | if (src_id >= 0) { | ||
| 606 | mod = rsnd_src_mod_get(priv, src_id); | ||
| 607 | ret = rsnd_dai_connect(mod, io); | ||
| 608 | if (ret < 0) | ||
| 609 | return ret; | ||
| 610 | } | ||
| 611 | |||
| 612 | /* SSI */ | ||
| 613 | if (ssi_id >= 0) { | ||
| 614 | mod = rsnd_ssi_mod_get(priv, ssi_id); | ||
| 615 | ret = rsnd_dai_connect(mod, io); | ||
| 616 | if (ret < 0) | ||
| 617 | return ret; | ||
| 618 | } | ||
| 619 | |||
| 620 | return ret; | ||
| 621 | } | ||
| 622 | |||
| 543 | static int rsnd_dai_probe(struct platform_device *pdev, | 623 | static int rsnd_dai_probe(struct platform_device *pdev, |
| 544 | struct rcar_snd_info *info, | ||
| 545 | struct rsnd_priv *priv) | 624 | struct rsnd_priv *priv) |
| 546 | { | 625 | { |
| 547 | struct snd_soc_dai_driver *drv; | 626 | struct snd_soc_dai_driver *drv; |
| 627 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 548 | struct rsnd_dai *rdai; | 628 | struct rsnd_dai *rdai; |
| 549 | struct rsnd_mod *pmod, *cmod; | 629 | struct rsnd_mod *pmod, *cmod; |
| 550 | struct device *dev = rsnd_priv_to_dev(priv); | 630 | struct device *dev = rsnd_priv_to_dev(priv); |
| 551 | int dai_nr; | 631 | int dai_nr = info->dai_info_nr; |
| 552 | int i; | 632 | int i; |
| 553 | 633 | ||
| 554 | /* get max dai nr */ | 634 | /* |
| 555 | for (dai_nr = 0; dai_nr < 32; dai_nr++) { | 635 | * dai_nr should be set via dai_info_nr, |
| 556 | pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); | 636 | * but allow it to keeping compatible |
| 557 | cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); | 637 | */ |
| 638 | if (!dai_nr) { | ||
| 639 | /* get max dai nr */ | ||
| 640 | for (dai_nr = 0; dai_nr < 32; dai_nr++) { | ||
| 641 | pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); | ||
| 642 | cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); | ||
| 558 | 643 | ||
| 559 | if (!pmod && !cmod) | 644 | if (!pmod && !cmod) |
| 560 | break; | 645 | break; |
| 646 | } | ||
| 561 | } | 647 | } |
| 562 | 648 | ||
| 563 | if (!dai_nr) { | 649 | if (!dai_nr) { |
| @@ -572,7 +658,13 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
| 572 | return -ENOMEM; | 658 | return -ENOMEM; |
| 573 | } | 659 | } |
| 574 | 660 | ||
| 661 | priv->rdai_nr = dai_nr; | ||
| 662 | priv->daidrv = drv; | ||
| 663 | priv->rdai = rdai; | ||
| 664 | |||
| 575 | for (i = 0; i < dai_nr; i++) { | 665 | for (i = 0; i < dai_nr; i++) { |
| 666 | if (info->dai_info) | ||
| 667 | rdai[i].info = &info->dai_info[i]; | ||
| 576 | 668 | ||
| 577 | pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); | 669 | pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); |
| 578 | cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); | 670 | cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); |
| @@ -580,9 +672,6 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
| 580 | /* | 672 | /* |
| 581 | * init rsnd_dai | 673 | * init rsnd_dai |
| 582 | */ | 674 | */ |
| 583 | INIT_LIST_HEAD(&rdai[i].playback.head); | ||
| 584 | INIT_LIST_HEAD(&rdai[i].capture.head); | ||
| 585 | |||
| 586 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); | 675 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); |
| 587 | 676 | ||
| 588 | /* | 677 | /* |
| @@ -595,12 +684,20 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
| 595 | drv[i].playback.formats = RSND_FMTS; | 684 | drv[i].playback.formats = RSND_FMTS; |
| 596 | drv[i].playback.channels_min = 2; | 685 | drv[i].playback.channels_min = 2; |
| 597 | drv[i].playback.channels_max = 2; | 686 | drv[i].playback.channels_max = 2; |
| 687 | |||
| 688 | if (info->dai_info) | ||
| 689 | rdai[i].playback.info = &info->dai_info[i].playback; | ||
| 690 | rsnd_path_init(priv, &rdai[i], &rdai[i].playback); | ||
| 598 | } | 691 | } |
| 599 | if (cmod) { | 692 | if (cmod) { |
| 600 | drv[i].capture.rates = RSND_RATES; | 693 | drv[i].capture.rates = RSND_RATES; |
| 601 | drv[i].capture.formats = RSND_FMTS; | 694 | drv[i].capture.formats = RSND_FMTS; |
| 602 | drv[i].capture.channels_min = 2; | 695 | drv[i].capture.channels_min = 2; |
| 603 | drv[i].capture.channels_max = 2; | 696 | drv[i].capture.channels_max = 2; |
| 697 | |||
| 698 | if (info->dai_info) | ||
| 699 | rdai[i].capture.info = &info->dai_info[i].capture; | ||
| 700 | rsnd_path_init(priv, &rdai[i], &rdai[i].capture); | ||
| 604 | } | 701 | } |
| 605 | 702 | ||
| 606 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, | 703 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, |
| @@ -608,18 +705,9 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
| 608 | cmod ? "capture" : " -- "); | 705 | cmod ? "capture" : " -- "); |
| 609 | } | 706 | } |
| 610 | 707 | ||
| 611 | priv->dai_nr = dai_nr; | ||
| 612 | priv->daidrv = drv; | ||
| 613 | priv->rdai = rdai; | ||
| 614 | |||
| 615 | return 0; | 708 | return 0; |
| 616 | } | 709 | } |
| 617 | 710 | ||
| 618 | static void rsnd_dai_remove(struct platform_device *pdev, | ||
| 619 | struct rsnd_priv *priv) | ||
| 620 | { | ||
| 621 | } | ||
| 622 | |||
| 623 | /* | 711 | /* |
| 624 | * pcm ops | 712 | * pcm ops |
| 625 | */ | 713 | */ |
| @@ -713,7 +801,16 @@ static int rsnd_probe(struct platform_device *pdev) | |||
| 713 | struct rcar_snd_info *info; | 801 | struct rcar_snd_info *info; |
| 714 | struct rsnd_priv *priv; | 802 | struct rsnd_priv *priv; |
| 715 | struct device *dev = &pdev->dev; | 803 | struct device *dev = &pdev->dev; |
| 716 | int ret; | 804 | struct rsnd_dai *rdai; |
| 805 | int (*probe_func[])(struct platform_device *pdev, | ||
| 806 | struct rsnd_priv *priv) = { | ||
| 807 | rsnd_gen_probe, | ||
| 808 | rsnd_ssi_probe, | ||
| 809 | rsnd_src_probe, | ||
| 810 | rsnd_adg_probe, | ||
| 811 | rsnd_dai_probe, | ||
| 812 | }; | ||
| 813 | int ret, i; | ||
| 717 | 814 | ||
| 718 | info = pdev->dev.platform_data; | 815 | info = pdev->dev.platform_data; |
| 719 | if (!info) { | 816 | if (!info) { |
| @@ -737,25 +834,21 @@ static int rsnd_probe(struct platform_device *pdev) | |||
| 737 | /* | 834 | /* |
| 738 | * init each module | 835 | * init each module |
| 739 | */ | 836 | */ |
| 740 | ret = rsnd_gen_probe(pdev, info, priv); | 837 | for (i = 0; i < ARRAY_SIZE(probe_func); i++) { |
| 741 | if (ret < 0) | 838 | ret = probe_func[i](pdev, priv); |
| 742 | return ret; | 839 | if (ret) |
| 743 | 840 | return ret; | |
| 744 | ret = rsnd_scu_probe(pdev, info, priv); | 841 | } |
| 745 | if (ret < 0) | ||
| 746 | return ret; | ||
| 747 | 842 | ||
| 748 | ret = rsnd_adg_probe(pdev, info, priv); | 843 | for_each_rsnd_dai(rdai, priv, i) { |
| 749 | if (ret < 0) | 844 | ret = rsnd_dai_call(rdai, &rdai->playback, probe); |
| 750 | return ret; | 845 | if (ret) |
| 846 | return ret; | ||
| 751 | 847 | ||
| 752 | ret = rsnd_ssi_probe(pdev, info, priv); | 848 | ret = rsnd_dai_call(rdai, &rdai->capture, probe); |
| 753 | if (ret < 0) | 849 | if (ret) |
| 754 | return ret; | 850 | return ret; |
| 755 | 851 | } | |
| 756 | ret = rsnd_dai_probe(pdev, info, priv); | ||
| 757 | if (ret < 0) | ||
| 758 | return ret; | ||
| 759 | 852 | ||
| 760 | /* | 853 | /* |
| 761 | * asoc register | 854 | * asoc register |
| @@ -767,7 +860,7 @@ static int rsnd_probe(struct platform_device *pdev) | |||
| 767 | } | 860 | } |
| 768 | 861 | ||
| 769 | ret = snd_soc_register_component(dev, &rsnd_soc_component, | 862 | ret = snd_soc_register_component(dev, &rsnd_soc_component, |
| 770 | priv->daidrv, rsnd_dai_nr(priv)); | 863 | priv->daidrv, rsnd_rdai_nr(priv)); |
| 771 | if (ret < 0) { | 864 | if (ret < 0) { |
| 772 | dev_err(dev, "cannot snd dai register\n"); | 865 | dev_err(dev, "cannot snd dai register\n"); |
| 773 | goto exit_snd_soc; | 866 | goto exit_snd_soc; |
| @@ -789,17 +882,20 @@ exit_snd_soc: | |||
| 789 | static int rsnd_remove(struct platform_device *pdev) | 882 | static int rsnd_remove(struct platform_device *pdev) |
| 790 | { | 883 | { |
| 791 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | 884 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); |
| 885 | struct rsnd_dai *rdai; | ||
| 886 | int ret, i; | ||
| 792 | 887 | ||
| 793 | pm_runtime_disable(&pdev->dev); | 888 | pm_runtime_disable(&pdev->dev); |
| 794 | 889 | ||
| 795 | /* | 890 | for_each_rsnd_dai(rdai, priv, i) { |
| 796 | * remove each module | 891 | ret = rsnd_dai_call(rdai, &rdai->playback, remove); |
| 797 | */ | 892 | if (ret) |
| 798 | rsnd_ssi_remove(pdev, priv); | 893 | return ret; |
| 799 | rsnd_adg_remove(pdev, priv); | 894 | |
| 800 | rsnd_scu_remove(pdev, priv); | 895 | ret = rsnd_dai_call(rdai, &rdai->capture, remove); |
| 801 | rsnd_dai_remove(pdev, priv); | 896 | if (ret) |
| 802 | rsnd_gen_remove(pdev, priv); | 897 | return ret; |
| 898 | } | ||
| 803 | 899 | ||
| 804 | return 0; | 900 | return 0; |
| 805 | } | 901 | } |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index add088bd4b2a..9094970dbdfb 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
| @@ -155,62 +155,6 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
| 155 | return 0; | 155 | return 0; |
| 156 | } | 156 | } |
| 157 | 157 | ||
| 158 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
| 159 | struct rsnd_dai *rdai, | ||
| 160 | struct rsnd_dai_stream *io) | ||
| 161 | { | ||
| 162 | struct rsnd_mod *mod; | ||
| 163 | int ret; | ||
| 164 | int id; | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
| 168 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
| 169 | * | ||
| 170 | * Easy image is.. | ||
| 171 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
| 172 | * | ||
| 173 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
| 174 | * using fixed path. | ||
| 175 | * | ||
| 176 | * Then, SSI id = SCU id here | ||
| 177 | */ | ||
| 178 | |||
| 179 | /* get SSI's ID */ | ||
| 180 | mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
| 181 | rsnd_dai_id(priv, rdai), | ||
| 182 | rsnd_dai_is_play(rdai, io)); | ||
| 183 | id = rsnd_mod_id(mod); | ||
| 184 | |||
| 185 | /* SSI */ | ||
| 186 | mod = rsnd_ssi_mod_get(priv, id); | ||
| 187 | ret = rsnd_dai_connect(rdai, mod, io); | ||
| 188 | if (ret < 0) | ||
| 189 | return ret; | ||
| 190 | |||
| 191 | /* SCU */ | ||
| 192 | mod = rsnd_scu_mod_get(priv, id); | ||
| 193 | ret = rsnd_dai_connect(rdai, mod, io); | ||
| 194 | |||
| 195 | return ret; | ||
| 196 | } | ||
| 197 | |||
| 198 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
| 199 | struct rsnd_dai *rdai, | ||
| 200 | struct rsnd_dai_stream *io) | ||
| 201 | { | ||
| 202 | struct rsnd_mod *mod, *n; | ||
| 203 | int ret = 0; | ||
| 204 | |||
| 205 | /* | ||
| 206 | * remove all mod from rdai | ||
| 207 | */ | ||
| 208 | for_each_rsnd_mod(mod, n, io) | ||
| 209 | ret |= rsnd_dai_disconnect(mod); | ||
| 210 | |||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | /* | 158 | /* |
| 215 | * Gen2 | 159 | * Gen2 |
| 216 | */ | 160 | */ |
| @@ -229,14 +173,40 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
| 229 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), | 173 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), |
| 230 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), | 174 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), |
| 231 | /* FIXME: it needs SSI_MODE2/3 in the future */ | 175 | /* FIXME: it needs SSI_MODE2/3 in the future */ |
| 176 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80), | ||
| 177 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80), | ||
| 178 | RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80), | ||
| 232 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), | 179 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), |
| 233 | 180 | ||
| 181 | RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), | ||
| 182 | RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), | ||
| 183 | RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), | ||
| 184 | RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), | ||
| 185 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), | ||
| 186 | RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), | ||
| 187 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40), | ||
| 188 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40), | ||
| 189 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), | ||
| 190 | RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), | ||
| 191 | RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), | ||
| 192 | |||
| 234 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), | 193 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), |
| 235 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), | 194 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), |
| 236 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), | 195 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), |
| 237 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | 196 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), |
| 238 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | 197 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), |
| 239 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), | 198 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), |
| 199 | RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30), | ||
| 200 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34), | ||
| 201 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38), | ||
| 202 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c), | ||
| 203 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40), | ||
| 204 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44), | ||
| 205 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48), | ||
| 206 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c), | ||
| 207 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), | ||
| 208 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), | ||
| 209 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), | ||
| 240 | 210 | ||
| 241 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), | 211 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), |
| 242 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), | 212 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), |
| @@ -249,7 +219,6 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
| 249 | } | 219 | } |
| 250 | 220 | ||
| 251 | static int rsnd_gen2_probe(struct platform_device *pdev, | 221 | static int rsnd_gen2_probe(struct platform_device *pdev, |
| 252 | struct rcar_snd_info *info, | ||
| 253 | struct rsnd_priv *priv) | 222 | struct rsnd_priv *priv) |
| 254 | { | 223 | { |
| 255 | struct device *dev = rsnd_priv_to_dev(priv); | 224 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -283,7 +252,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
| 283 | return ret; | 252 | return ret; |
| 284 | 253 | ||
| 285 | dev_dbg(dev, "Gen2 device probed\n"); | 254 | dev_dbg(dev, "Gen2 device probed\n"); |
| 286 | dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start, | 255 | dev_dbg(dev, "SCU : %08x => %p\n", scu_res->start, |
| 287 | gen->base[RSND_GEN2_SCU]); | 256 | gen->base[RSND_GEN2_SCU]); |
| 288 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, | 257 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, |
| 289 | gen->base[RSND_GEN2_ADG]); | 258 | gen->base[RSND_GEN2_ADG]); |
| @@ -317,7 +286,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
| 317 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), | 286 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), |
| 318 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), | 287 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), |
| 319 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), | 288 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), |
| 320 | RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), | 289 | RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4), |
| 321 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), | 290 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), |
| 322 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), | 291 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), |
| 323 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), | 292 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), |
| @@ -347,7 +316,6 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
| 347 | } | 316 | } |
| 348 | 317 | ||
| 349 | static int rsnd_gen1_probe(struct platform_device *pdev, | 318 | static int rsnd_gen1_probe(struct platform_device *pdev, |
| 350 | struct rcar_snd_info *info, | ||
| 351 | struct rsnd_priv *priv) | 319 | struct rsnd_priv *priv) |
| 352 | { | 320 | { |
| 353 | struct device *dev = rsnd_priv_to_dev(priv); | 321 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -392,7 +360,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev, | |||
| 392 | * Gen | 360 | * Gen |
| 393 | */ | 361 | */ |
| 394 | int rsnd_gen_probe(struct platform_device *pdev, | 362 | int rsnd_gen_probe(struct platform_device *pdev, |
| 395 | struct rcar_snd_info *info, | ||
| 396 | struct rsnd_priv *priv) | 363 | struct rsnd_priv *priv) |
| 397 | { | 364 | { |
| 398 | struct device *dev = rsnd_priv_to_dev(priv); | 365 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -409,17 +376,12 @@ int rsnd_gen_probe(struct platform_device *pdev, | |||
| 409 | 376 | ||
| 410 | ret = -ENODEV; | 377 | ret = -ENODEV; |
| 411 | if (rsnd_is_gen1(priv)) | 378 | if (rsnd_is_gen1(priv)) |
| 412 | ret = rsnd_gen1_probe(pdev, info, priv); | 379 | ret = rsnd_gen1_probe(pdev, priv); |
| 413 | else if (rsnd_is_gen2(priv)) | 380 | else if (rsnd_is_gen2(priv)) |
| 414 | ret = rsnd_gen2_probe(pdev, info, priv); | 381 | ret = rsnd_gen2_probe(pdev, priv); |
| 415 | 382 | ||
| 416 | if (ret < 0) | 383 | if (ret < 0) |
| 417 | dev_err(dev, "unknown generation R-Car sound device\n"); | 384 | dev_err(dev, "unknown generation R-Car sound device\n"); |
| 418 | 385 | ||
| 419 | return ret; | 386 | return ret; |
| 420 | } | 387 | } |
| 421 | |||
| 422 | void rsnd_gen_remove(struct platform_device *pdev, | ||
| 423 | struct rsnd_priv *priv) | ||
| 424 | { | ||
| 425 | } | ||
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4ca66cd899c8..c46e0afa54ae 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
| @@ -32,15 +32,9 @@ | |||
| 32 | */ | 32 | */ |
| 33 | enum rsnd_reg { | 33 | enum rsnd_reg { |
| 34 | /* SRU/SCU/SSIU */ | 34 | /* SRU/SCU/SSIU */ |
| 35 | RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */ | ||
| 36 | RSND_REG_SRC_TMG_SEL0, /* for Gen1 */ | ||
| 37 | RSND_REG_SRC_TMG_SEL1, /* for Gen1 */ | ||
| 38 | RSND_REG_SRC_TMG_SEL2, /* for Gen1 */ | ||
| 39 | RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */ | ||
| 40 | RSND_REG_SSI_MODE0, | 35 | RSND_REG_SSI_MODE0, |
| 41 | RSND_REG_SSI_MODE1, | 36 | RSND_REG_SSI_MODE1, |
| 42 | RSND_REG_BUSIF_MODE, | 37 | RSND_REG_SRC_BUSIF_MODE, |
| 43 | RSND_REG_INT_ENABLE, /* for Gen2 */ | ||
| 44 | RSND_REG_SRC_ROUTE_MODE0, | 38 | RSND_REG_SRC_ROUTE_MODE0, |
| 45 | RSND_REG_SRC_SWRSR, | 39 | RSND_REG_SRC_SWRSR, |
| 46 | RSND_REG_SRC_SRCIR, | 40 | RSND_REG_SRC_SRCIR, |
| @@ -48,7 +42,6 @@ enum rsnd_reg { | |||
| 48 | RSND_REG_SRC_IFSCR, | 42 | RSND_REG_SRC_IFSCR, |
| 49 | RSND_REG_SRC_IFSVR, | 43 | RSND_REG_SRC_IFSVR, |
| 50 | RSND_REG_SRC_SRCCR, | 44 | RSND_REG_SRC_SRCCR, |
| 51 | RSND_REG_SRC_MNFSR, | ||
| 52 | 45 | ||
| 53 | /* ADG */ | 46 | /* ADG */ |
| 54 | RSND_REG_BRRA, | 47 | RSND_REG_BRRA, |
| @@ -56,10 +49,6 @@ enum rsnd_reg { | |||
| 56 | RSND_REG_SSICKR, | 49 | RSND_REG_SSICKR, |
| 57 | RSND_REG_AUDIO_CLK_SEL0, | 50 | RSND_REG_AUDIO_CLK_SEL0, |
| 58 | RSND_REG_AUDIO_CLK_SEL1, | 51 | RSND_REG_AUDIO_CLK_SEL1, |
| 59 | RSND_REG_AUDIO_CLK_SEL2, | ||
| 60 | RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */ | ||
| 61 | RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */ | ||
| 62 | RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */ | ||
| 63 | 52 | ||
| 64 | /* SSI */ | 53 | /* SSI */ |
| 65 | RSND_REG_SSICR, | 54 | RSND_REG_SSICR, |
| @@ -68,9 +57,62 @@ enum rsnd_reg { | |||
| 68 | RSND_REG_SSIRDR, | 57 | RSND_REG_SSIRDR, |
| 69 | RSND_REG_SSIWSR, | 58 | RSND_REG_SSIWSR, |
| 70 | 59 | ||
| 60 | /* SHARE see below */ | ||
| 61 | RSND_REG_SHARE01, | ||
| 62 | RSND_REG_SHARE02, | ||
| 63 | RSND_REG_SHARE03, | ||
| 64 | RSND_REG_SHARE04, | ||
| 65 | RSND_REG_SHARE05, | ||
| 66 | RSND_REG_SHARE06, | ||
| 67 | RSND_REG_SHARE07, | ||
| 68 | RSND_REG_SHARE08, | ||
| 69 | RSND_REG_SHARE09, | ||
| 70 | RSND_REG_SHARE10, | ||
| 71 | RSND_REG_SHARE11, | ||
| 72 | RSND_REG_SHARE12, | ||
| 73 | RSND_REG_SHARE13, | ||
| 74 | RSND_REG_SHARE14, | ||
| 75 | RSND_REG_SHARE15, | ||
| 76 | RSND_REG_SHARE16, | ||
| 77 | RSND_REG_SHARE17, | ||
| 78 | RSND_REG_SHARE18, | ||
| 79 | RSND_REG_SHARE19, | ||
| 80 | |||
| 71 | RSND_REG_MAX, | 81 | RSND_REG_MAX, |
| 72 | }; | 82 | }; |
| 73 | 83 | ||
| 84 | /* Gen1 only */ | ||
| 85 | #define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01 | ||
| 86 | #define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02 | ||
| 87 | #define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03 | ||
| 88 | #define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04 | ||
| 89 | #define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05 | ||
| 90 | #define RSND_REG_SRC_MNFSR RSND_REG_SHARE06 | ||
| 91 | #define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07 | ||
| 92 | #define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08 | ||
| 93 | #define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09 | ||
| 94 | |||
| 95 | /* Gen2 only */ | ||
| 96 | #define RSND_REG_SRC_CTRL RSND_REG_SHARE01 | ||
| 97 | #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 | ||
| 98 | #define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 | ||
| 99 | #define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 | ||
| 100 | #define RSND_REG_INT_ENABLE RSND_REG_SHARE05 | ||
| 101 | #define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 | ||
| 102 | #define RSND_REG_SRC_BSISR RSND_REG_SHARE07 | ||
| 103 | #define RSND_REG_DIV_EN RSND_REG_SHARE08 | ||
| 104 | #define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09 | ||
| 105 | #define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10 | ||
| 106 | #define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11 | ||
| 107 | #define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12 | ||
| 108 | #define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13 | ||
| 109 | #define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14 | ||
| 110 | #define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15 | ||
| 111 | #define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16 | ||
| 112 | #define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 | ||
| 113 | #define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 | ||
| 114 | #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 | ||
| 115 | |||
| 74 | struct rsnd_priv; | 116 | struct rsnd_priv; |
| 75 | struct rsnd_mod; | 117 | struct rsnd_mod; |
| 76 | struct rsnd_dai; | 118 | struct rsnd_dai; |
| @@ -96,24 +138,20 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | |||
| 96 | * R-Car DMA | 138 | * R-Car DMA |
| 97 | */ | 139 | */ |
| 98 | struct rsnd_dma { | 140 | struct rsnd_dma { |
| 99 | struct rsnd_priv *priv; | ||
| 100 | struct sh_dmae_slave slave; | 141 | struct sh_dmae_slave slave; |
| 101 | struct work_struct work; | 142 | struct work_struct work; |
| 102 | struct dma_chan *chan; | 143 | struct dma_chan *chan; |
| 103 | enum dma_data_direction dir; | 144 | enum dma_data_direction dir; |
| 104 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len); | ||
| 105 | int (*complete)(struct rsnd_dma *dma); | ||
| 106 | 145 | ||
| 107 | int submit_loop; | 146 | int submit_loop; |
| 147 | int offset; /* it cares A/B plane */ | ||
| 108 | }; | 148 | }; |
| 109 | 149 | ||
| 110 | void rsnd_dma_start(struct rsnd_dma *dma); | 150 | void rsnd_dma_start(struct rsnd_dma *dma); |
| 111 | void rsnd_dma_stop(struct rsnd_dma *dma); | 151 | void rsnd_dma_stop(struct rsnd_dma *dma); |
| 112 | int rsnd_dma_available(struct rsnd_dma *dma); | 152 | int rsnd_dma_available(struct rsnd_dma *dma); |
| 113 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 153 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
| 114 | int is_play, int id, | 154 | int is_play, int id); |
| 115 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len), | ||
| 116 | int (*complete)(struct rsnd_dma *dma)); | ||
| 117 | void rsnd_dma_quit(struct rsnd_priv *priv, | 155 | void rsnd_dma_quit(struct rsnd_priv *priv, |
| 118 | struct rsnd_dma *dma); | 156 | struct rsnd_dma *dma); |
| 119 | 157 | ||
| @@ -121,9 +159,20 @@ void rsnd_dma_quit(struct rsnd_priv *priv, | |||
| 121 | /* | 159 | /* |
| 122 | * R-Car sound mod | 160 | * R-Car sound mod |
| 123 | */ | 161 | */ |
| 162 | enum rsnd_mod_type { | ||
| 163 | RSND_MOD_SRC = 0, | ||
| 164 | RSND_MOD_SSI, | ||
| 165 | RSND_MOD_MAX, | ||
| 166 | }; | ||
| 124 | 167 | ||
| 125 | struct rsnd_mod_ops { | 168 | struct rsnd_mod_ops { |
| 126 | char *name; | 169 | char *name; |
| 170 | int (*probe)(struct rsnd_mod *mod, | ||
| 171 | struct rsnd_dai *rdai, | ||
| 172 | struct rsnd_dai_stream *io); | ||
| 173 | int (*remove)(struct rsnd_mod *mod, | ||
| 174 | struct rsnd_dai *rdai, | ||
| 175 | struct rsnd_dai_stream *io); | ||
| 127 | int (*init)(struct rsnd_mod *mod, | 176 | int (*init)(struct rsnd_mod *mod, |
| 128 | struct rsnd_dai *rdai, | 177 | struct rsnd_dai *rdai, |
| 129 | struct rsnd_dai_stream *io); | 178 | struct rsnd_dai_stream *io); |
| @@ -138,28 +187,26 @@ struct rsnd_mod_ops { | |||
| 138 | struct rsnd_dai_stream *io); | 187 | struct rsnd_dai_stream *io); |
| 139 | }; | 188 | }; |
| 140 | 189 | ||
| 190 | struct rsnd_dai_stream; | ||
| 141 | struct rsnd_mod { | 191 | struct rsnd_mod { |
| 142 | int id; | 192 | int id; |
| 193 | enum rsnd_mod_type type; | ||
| 143 | struct rsnd_priv *priv; | 194 | struct rsnd_priv *priv; |
| 144 | struct rsnd_mod_ops *ops; | 195 | struct rsnd_mod_ops *ops; |
| 145 | struct list_head list; /* connect to rsnd_dai playback/capture */ | ||
| 146 | struct rsnd_dma dma; | 196 | struct rsnd_dma dma; |
| 197 | struct rsnd_dai_stream *io; | ||
| 147 | }; | 198 | }; |
| 148 | 199 | ||
| 149 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 200 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
| 150 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 201 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
| 151 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | 202 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) |
| 203 | #define rsnd_mod_to_io(mod) ((mod)->io) | ||
| 152 | #define rsnd_mod_id(mod) ((mod)->id) | 204 | #define rsnd_mod_id(mod) ((mod)->id) |
| 153 | #define for_each_rsnd_mod(pos, n, io) \ | ||
| 154 | list_for_each_entry_safe(pos, n, &(io)->head, list) | ||
| 155 | #define rsnd_mod_call(mod, func, rdai, io) \ | ||
| 156 | (!(mod) ? -ENODEV : \ | ||
| 157 | !((mod)->ops->func) ? 0 : \ | ||
| 158 | (mod)->ops->func(mod, rdai, io)) | ||
| 159 | 205 | ||
| 160 | void rsnd_mod_init(struct rsnd_priv *priv, | 206 | void rsnd_mod_init(struct rsnd_priv *priv, |
| 161 | struct rsnd_mod *mod, | 207 | struct rsnd_mod *mod, |
| 162 | struct rsnd_mod_ops *ops, | 208 | struct rsnd_mod_ops *ops, |
| 209 | enum rsnd_mod_type type, | ||
| 163 | int id); | 210 | int id); |
| 164 | char *rsnd_mod_name(struct rsnd_mod *mod); | 211 | char *rsnd_mod_name(struct rsnd_mod *mod); |
| 165 | 212 | ||
| @@ -168,13 +215,16 @@ char *rsnd_mod_name(struct rsnd_mod *mod); | |||
| 168 | */ | 215 | */ |
| 169 | #define RSND_DAI_NAME_SIZE 16 | 216 | #define RSND_DAI_NAME_SIZE 16 |
| 170 | struct rsnd_dai_stream { | 217 | struct rsnd_dai_stream { |
| 171 | struct list_head head; /* head of rsnd_mod list */ | ||
| 172 | struct snd_pcm_substream *substream; | 218 | struct snd_pcm_substream *substream; |
| 219 | struct rsnd_mod *mod[RSND_MOD_MAX]; | ||
| 220 | struct rsnd_dai_path_info *info; /* rcar_snd.h */ | ||
| 173 | int byte_pos; | 221 | int byte_pos; |
| 174 | int period_pos; | 222 | int period_pos; |
| 175 | int byte_per_period; | 223 | int byte_per_period; |
| 176 | int next_period_byte; | 224 | int next_period_byte; |
| 177 | }; | 225 | }; |
| 226 | #define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI]) | ||
| 227 | #define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC]) | ||
| 178 | 228 | ||
| 179 | struct rsnd_dai { | 229 | struct rsnd_dai { |
| 180 | char name[RSND_DAI_NAME_SIZE]; | 230 | char name[RSND_DAI_NAME_SIZE]; |
| @@ -189,16 +239,14 @@ struct rsnd_dai { | |||
| 189 | unsigned int data_alignment:1; | 239 | unsigned int data_alignment:1; |
| 190 | }; | 240 | }; |
| 191 | 241 | ||
| 192 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) | 242 | #define rsnd_rdai_nr(priv) ((priv)->rdai_nr) |
| 193 | #define for_each_rsnd_dai(rdai, priv, i) \ | 243 | #define for_each_rsnd_dai(rdai, priv, i) \ |
| 194 | for (i = 0, (rdai) = rsnd_dai_get(priv, i); \ | 244 | for (i = 0; \ |
| 195 | i < rsnd_dai_nr(priv); \ | 245 | (i < rsnd_rdai_nr(priv)) && \ |
| 196 | i++, (rdai) = rsnd_dai_get(priv, i)) | 246 | ((rdai) = rsnd_dai_get(priv, i)); \ |
| 247 | i++) | ||
| 197 | 248 | ||
| 198 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | 249 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); |
| 199 | int rsnd_dai_disconnect(struct rsnd_mod *mod); | ||
| 200 | int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, | ||
| 201 | struct rsnd_dai_stream *io); | ||
| 202 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | 250 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
| 203 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | 251 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); |
| 204 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | 252 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
| @@ -206,21 +254,13 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | |||
| 206 | 254 | ||
| 207 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 255 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
| 208 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 256 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
| 257 | #define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master) | ||
| 209 | 258 | ||
| 210 | /* | 259 | /* |
| 211 | * R-Car Gen1/Gen2 | 260 | * R-Car Gen1/Gen2 |
| 212 | */ | 261 | */ |
| 213 | int rsnd_gen_probe(struct platform_device *pdev, | 262 | int rsnd_gen_probe(struct platform_device *pdev, |
| 214 | struct rcar_snd_info *info, | ||
| 215 | struct rsnd_priv *priv); | 263 | struct rsnd_priv *priv); |
| 216 | void rsnd_gen_remove(struct platform_device *pdev, | ||
| 217 | struct rsnd_priv *priv); | ||
| 218 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
| 219 | struct rsnd_dai *rdai, | ||
| 220 | struct rsnd_dai_stream *io); | ||
| 221 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
| 222 | struct rsnd_dai *rdai, | ||
| 223 | struct rsnd_dai_stream *io); | ||
| 224 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 264 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
| 225 | struct rsnd_mod *mod, | 265 | struct rsnd_mod *mod, |
| 226 | enum rsnd_reg reg); | 266 | enum rsnd_reg reg); |
| @@ -233,14 +273,19 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | |||
| 233 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | 273 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); |
| 234 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | 274 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); |
| 235 | int rsnd_adg_probe(struct platform_device *pdev, | 275 | int rsnd_adg_probe(struct platform_device *pdev, |
| 236 | struct rcar_snd_info *info, | ||
| 237 | struct rsnd_priv *priv); | ||
| 238 | void rsnd_adg_remove(struct platform_device *pdev, | ||
| 239 | struct rsnd_priv *priv); | 276 | struct rsnd_priv *priv); |
| 240 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | 277 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, |
| 241 | struct rsnd_mod *mod, | 278 | struct rsnd_mod *mod, |
| 242 | unsigned int src_rate, | 279 | unsigned int src_rate, |
| 243 | unsigned int dst_rate); | 280 | unsigned int dst_rate); |
| 281 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, | ||
| 282 | struct rsnd_dai *rdai, | ||
| 283 | struct rsnd_dai_stream *io, | ||
| 284 | unsigned int src_rate, | ||
| 285 | unsigned int dst_rate); | ||
| 286 | int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
| 287 | struct rsnd_dai *rdai, | ||
| 288 | struct rsnd_dai_stream *io); | ||
| 244 | 289 | ||
| 245 | /* | 290 | /* |
| 246 | * R-Car sound priv | 291 | * R-Car sound priv |
| @@ -257,10 +302,10 @@ struct rsnd_priv { | |||
| 257 | void *gen; | 302 | void *gen; |
| 258 | 303 | ||
| 259 | /* | 304 | /* |
| 260 | * below value will be filled on rsnd_scu_probe() | 305 | * below value will be filled on rsnd_src_probe() |
| 261 | */ | 306 | */ |
| 262 | void *scu; | 307 | void *src; |
| 263 | int scu_nr; | 308 | int src_nr; |
| 264 | 309 | ||
| 265 | /* | 310 | /* |
| 266 | * below value will be filled on rsnd_adg_probe() | 311 | * below value will be filled on rsnd_adg_probe() |
| @@ -270,46 +315,62 @@ struct rsnd_priv { | |||
| 270 | /* | 315 | /* |
| 271 | * below value will be filled on rsnd_ssi_probe() | 316 | * below value will be filled on rsnd_ssi_probe() |
| 272 | */ | 317 | */ |
| 273 | void *ssiu; | 318 | void *ssi; |
| 319 | int ssi_nr; | ||
| 274 | 320 | ||
| 275 | /* | 321 | /* |
| 276 | * below value will be filled on rsnd_dai_probe() | 322 | * below value will be filled on rsnd_dai_probe() |
| 277 | */ | 323 | */ |
| 278 | struct snd_soc_dai_driver *daidrv; | 324 | struct snd_soc_dai_driver *daidrv; |
| 279 | struct rsnd_dai *rdai; | 325 | struct rsnd_dai *rdai; |
| 280 | int dai_nr; | 326 | int rdai_nr; |
| 281 | }; | 327 | }; |
| 282 | 328 | ||
| 283 | #define rsnd_priv_to_dev(priv) ((priv)->dev) | 329 | #define rsnd_priv_to_dev(priv) ((priv)->dev) |
| 330 | #define rsnd_priv_to_info(priv) ((priv)->info) | ||
| 284 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) | 331 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) |
| 285 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) | 332 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) |
| 286 | 333 | ||
| 334 | #define rsnd_info_is_playback(priv, type) \ | ||
| 335 | ({ \ | ||
| 336 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); \ | ||
| 337 | int i, is_play = 0; \ | ||
| 338 | for (i = 0; i < info->dai_info_nr; i++) { \ | ||
| 339 | if (info->dai_info[i].playback.type == (type)->info) { \ | ||
| 340 | is_play = 1; \ | ||
| 341 | break; \ | ||
| 342 | } \ | ||
| 343 | } \ | ||
| 344 | is_play; \ | ||
| 345 | }) | ||
| 346 | |||
| 287 | /* | 347 | /* |
| 288 | * R-Car SCU | 348 | * R-Car SRC |
| 289 | */ | 349 | */ |
| 290 | int rsnd_scu_probe(struct platform_device *pdev, | 350 | int rsnd_src_probe(struct platform_device *pdev, |
| 291 | struct rcar_snd_info *info, | ||
| 292 | struct rsnd_priv *priv); | 351 | struct rsnd_priv *priv); |
| 293 | void rsnd_scu_remove(struct platform_device *pdev, | 352 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); |
| 294 | struct rsnd_priv *priv); | 353 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
| 295 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); | 354 | struct rsnd_dai_stream *io, |
| 296 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); | ||
| 297 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, | ||
| 298 | struct rsnd_mod *ssi_mod, | ||
| 299 | struct snd_pcm_runtime *runtime); | 355 | struct snd_pcm_runtime *runtime); |
| 356 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | ||
| 357 | struct rsnd_dai *rdai, | ||
| 358 | struct rsnd_dai_stream *io); | ||
| 359 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
| 360 | struct rsnd_dai *rdai, | ||
| 361 | struct rsnd_dai_stream *io); | ||
| 300 | 362 | ||
| 301 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) | 363 | #define rsnd_src_nr(priv) ((priv)->src_nr) |
| 302 | 364 | ||
| 303 | /* | 365 | /* |
| 304 | * R-Car SSI | 366 | * R-Car SSI |
| 305 | */ | 367 | */ |
| 306 | int rsnd_ssi_probe(struct platform_device *pdev, | 368 | int rsnd_ssi_probe(struct platform_device *pdev, |
| 307 | struct rcar_snd_info *info, | ||
| 308 | struct rsnd_priv *priv); | ||
| 309 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
| 310 | struct rsnd_priv *priv); | 369 | struct rsnd_priv *priv); |
| 311 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 370 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
| 312 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 371 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
| 313 | int dai_id, int is_play); | 372 | int dai_id, int is_play); |
| 373 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | ||
| 374 | int rsnd_ssi_is_play(struct rsnd_mod *mod); | ||
| 314 | 375 | ||
| 315 | #endif | 376 | #endif |
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c deleted file mode 100644 index 9bb08bb1d455..000000000000 --- a/sound/soc/sh/rcar/scu.c +++ /dev/null | |||
| @@ -1,384 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Renesas R-Car SCU support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
| 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include "rsnd.h" | ||
| 12 | |||
| 13 | struct rsnd_scu { | ||
| 14 | struct rsnd_scu_platform_info *info; /* rcar_snd.h */ | ||
| 15 | struct rsnd_mod mod; | ||
| 16 | struct clk *clk; | ||
| 17 | }; | ||
| 18 | |||
| 19 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) | ||
| 20 | #define rsnd_scu_convert_rate(p) ((p)->info->convert_rate) | ||
| 21 | |||
| 22 | #define RSND_SCU_NAME_SIZE 16 | ||
| 23 | |||
| 24 | /* | ||
| 25 | * ADINR | ||
| 26 | */ | ||
| 27 | #define OTBL_24 (0 << 16) | ||
| 28 | #define OTBL_22 (2 << 16) | ||
| 29 | #define OTBL_20 (4 << 16) | ||
| 30 | #define OTBL_18 (6 << 16) | ||
| 31 | #define OTBL_16 (8 << 16) | ||
| 32 | |||
| 33 | /* | ||
| 34 | * image of SRC (Sampling Rate Converter) | ||
| 35 | * | ||
| 36 | * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ | ||
| 37 | * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | | ||
| 38 | * 44.1kHz <-> +-----+ +-----+ +-------+ | ||
| 39 | * ... | ||
| 40 | * | ||
| 41 | */ | ||
| 42 | |||
| 43 | #define rsnd_mod_to_scu(_mod) \ | ||
| 44 | container_of((_mod), struct rsnd_scu, mod) | ||
| 45 | |||
| 46 | #define for_each_rsnd_scu(pos, priv, i) \ | ||
| 47 | for ((i) = 0; \ | ||
| 48 | ((i) < rsnd_scu_nr(priv)) && \ | ||
| 49 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ | ||
| 50 | i++) | ||
| 51 | |||
| 52 | /* Gen1 only */ | ||
| 53 | static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, | ||
| 54 | struct rsnd_mod *mod, | ||
| 55 | struct rsnd_dai *rdai, | ||
| 56 | struct rsnd_dai_stream *io) | ||
| 57 | { | ||
| 58 | struct scu_route_config { | ||
| 59 | u32 mask; | ||
| 60 | int shift; | ||
| 61 | } routes[] = { | ||
| 62 | { 0xF, 0, }, /* 0 */ | ||
| 63 | { 0xF, 4, }, /* 1 */ | ||
| 64 | { 0xF, 8, }, /* 2 */ | ||
| 65 | { 0x7, 12, }, /* 3 */ | ||
| 66 | { 0x7, 16, }, /* 4 */ | ||
| 67 | { 0x7, 20, }, /* 5 */ | ||
| 68 | { 0x7, 24, }, /* 6 */ | ||
| 69 | { 0x3, 28, }, /* 7 */ | ||
| 70 | { 0x3, 30, }, /* 8 */ | ||
| 71 | }; | ||
| 72 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 73 | u32 mask; | ||
| 74 | u32 val; | ||
| 75 | int shift; | ||
| 76 | int id; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Gen1 only | ||
| 80 | */ | ||
| 81 | if (!rsnd_is_gen1(priv)) | ||
| 82 | return 0; | ||
| 83 | |||
| 84 | id = rsnd_mod_id(mod); | ||
| 85 | if (id < 0 || id >= ARRAY_SIZE(routes)) | ||
| 86 | return -EIO; | ||
| 87 | |||
| 88 | /* | ||
| 89 | * SRC_ROUTE_SELECT | ||
| 90 | */ | ||
| 91 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
| 92 | val = val << routes[id].shift; | ||
| 93 | mask = routes[id].mask << routes[id].shift; | ||
| 94 | |||
| 95 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
| 96 | |||
| 97 | /* | ||
| 98 | * SRC_TIMING_SELECT | ||
| 99 | */ | ||
| 100 | shift = (id % 4) * 8; | ||
| 101 | mask = 0x1F << shift; | ||
| 102 | |||
| 103 | /* | ||
| 104 | * ADG is used as source clock if SRC was used, | ||
| 105 | * then, SSI WS is used as destination clock. | ||
| 106 | * SSI WS is used as source clock if SRC is not used | ||
| 107 | * (when playback, source/destination become reverse when capture) | ||
| 108 | */ | ||
| 109 | if (rsnd_scu_convert_rate(scu)) /* use ADG */ | ||
| 110 | val = 0; | ||
| 111 | else if (8 == id) /* use SSI WS, but SRU8 is special */ | ||
| 112 | val = id << shift; | ||
| 113 | else /* use SSI WS */ | ||
| 114 | val = (id + 1) << shift; | ||
| 115 | |||
| 116 | switch (id / 4) { | ||
| 117 | case 0: | ||
| 118 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
| 119 | break; | ||
| 120 | case 1: | ||
| 121 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
| 122 | break; | ||
| 123 | case 2: | ||
| 124 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | |||
| 131 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, | ||
| 132 | struct rsnd_mod *ssi_mod, | ||
| 133 | struct snd_pcm_runtime *runtime) | ||
| 134 | { | ||
| 135 | struct rsnd_scu *scu; | ||
| 136 | unsigned int rate; | ||
| 137 | |||
| 138 | /* this function is assuming SSI id = SCU id here */ | ||
| 139 | scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod))); | ||
| 140 | |||
| 141 | /* | ||
| 142 | * return convert rate if SRC is used, | ||
| 143 | * otherwise, return runtime->rate as usual | ||
| 144 | */ | ||
| 145 | rate = rsnd_scu_convert_rate(scu); | ||
| 146 | if (!rate) | ||
| 147 | rate = runtime->rate; | ||
| 148 | |||
| 149 | return rate; | ||
| 150 | } | ||
| 151 | |||
| 152 | static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv, | ||
| 153 | struct rsnd_mod *mod, | ||
| 154 | struct rsnd_dai *rdai, | ||
| 155 | struct rsnd_dai_stream *io) | ||
| 156 | { | ||
| 157 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 158 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 159 | u32 convert_rate = rsnd_scu_convert_rate(scu); | ||
| 160 | u32 adinr = runtime->channels; | ||
| 161 | |||
| 162 | /* set/clear soft reset */ | ||
| 163 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
| 164 | rsnd_mod_write(mod, SRC_SWRSR, 1); | ||
| 165 | |||
| 166 | /* Initialize the operation of the SRC internal circuits */ | ||
| 167 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
| 168 | |||
| 169 | /* Set channel number and output bit length */ | ||
| 170 | switch (runtime->sample_bits) { | ||
| 171 | case 16: | ||
| 172 | adinr |= OTBL_16; | ||
| 173 | break; | ||
| 174 | case 32: | ||
| 175 | adinr |= OTBL_24; | ||
| 176 | break; | ||
| 177 | default: | ||
| 178 | return -EIO; | ||
| 179 | } | ||
| 180 | rsnd_mod_write(mod, SRC_ADINR, adinr); | ||
| 181 | |||
| 182 | if (convert_rate) { | ||
| 183 | u32 fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
| 184 | int ret; | ||
| 185 | |||
| 186 | /* Enable the initial value of IFS */ | ||
| 187 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
| 188 | |||
| 189 | /* Set initial value of IFS */ | ||
| 190 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
| 191 | |||
| 192 | /* Select SRC mode (fixed value) */ | ||
| 193 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
| 194 | |||
| 195 | /* Set the restriction value of the FS ratio (98%) */ | ||
| 196 | rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98); | ||
| 197 | |||
| 198 | if (rsnd_is_gen1(priv)) { | ||
| 199 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
| 200 | } | ||
| 201 | |||
| 202 | /* set convert clock */ | ||
| 203 | ret = rsnd_adg_set_convert_clk(priv, mod, | ||
| 204 | runtime->rate, | ||
| 205 | convert_rate); | ||
| 206 | if (ret < 0) | ||
| 207 | return ret; | ||
| 208 | } | ||
| 209 | |||
| 210 | /* Cancel the initialization and operate the SRC function */ | ||
| 211 | rsnd_mod_write(mod, SRC_SRCIR, 0); | ||
| 212 | |||
| 213 | /* use DMA transfer */ | ||
| 214 | rsnd_mod_write(mod, BUSIF_MODE, 1); | ||
| 215 | |||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int rsnd_scu_transfer_start(struct rsnd_priv *priv, | ||
| 220 | struct rsnd_mod *mod, | ||
| 221 | struct rsnd_dai *rdai, | ||
| 222 | struct rsnd_dai_stream *io) | ||
| 223 | { | ||
| 224 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 225 | int id = rsnd_mod_id(mod); | ||
| 226 | u32 val; | ||
| 227 | |||
| 228 | if (rsnd_is_gen1(priv)) { | ||
| 229 | val = (1 << id); | ||
| 230 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); | ||
| 231 | } | ||
| 232 | |||
| 233 | if (rsnd_scu_convert_rate(scu)) | ||
| 234 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static int rsnd_scu_transfer_stop(struct rsnd_priv *priv, | ||
| 240 | struct rsnd_mod *mod, | ||
| 241 | struct rsnd_dai *rdai, | ||
| 242 | struct rsnd_dai_stream *io) | ||
| 243 | { | ||
| 244 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 245 | int id = rsnd_mod_id(mod); | ||
| 246 | u32 mask; | ||
| 247 | |||
| 248 | if (rsnd_is_gen1(priv)) { | ||
| 249 | mask = (1 << id); | ||
| 250 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0); | ||
| 251 | } | ||
| 252 | |||
| 253 | if (rsnd_scu_convert_rate(scu)) | ||
| 254 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod) | ||
| 260 | { | ||
| 261 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 262 | u32 flags = rsnd_scu_mode_flags(scu); | ||
| 263 | |||
| 264 | return !!(flags & RSND_SCU_USE_HPBIF); | ||
| 265 | } | ||
| 266 | |||
| 267 | static int rsnd_scu_start(struct rsnd_mod *mod, | ||
| 268 | struct rsnd_dai *rdai, | ||
| 269 | struct rsnd_dai_stream *io) | ||
| 270 | { | ||
| 271 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 272 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 273 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 274 | int ret; | ||
| 275 | |||
| 276 | /* | ||
| 277 | * SCU will be used if it has RSND_SCU_USE_HPBIF flags | ||
| 278 | */ | ||
| 279 | if (!rsnd_scu_hpbif_is_enable(mod)) { | ||
| 280 | /* it use PIO transter */ | ||
| 281 | dev_dbg(dev, "%s%d is not used\n", | ||
| 282 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 283 | |||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | |||
| 287 | clk_enable(scu->clk); | ||
| 288 | |||
| 289 | /* it use DMA transter */ | ||
| 290 | |||
| 291 | ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); | ||
| 292 | if (ret < 0) | ||
| 293 | return ret; | ||
| 294 | |||
| 295 | ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io); | ||
| 296 | if (ret < 0) | ||
| 297 | return ret; | ||
| 298 | |||
| 299 | ret = rsnd_scu_transfer_start(priv, mod, rdai, io); | ||
| 300 | if (ret < 0) | ||
| 301 | return ret; | ||
| 302 | |||
| 303 | dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 304 | |||
| 305 | return 0; | ||
| 306 | } | ||
| 307 | |||
| 308 | static int rsnd_scu_stop(struct rsnd_mod *mod, | ||
| 309 | struct rsnd_dai *rdai, | ||
| 310 | struct rsnd_dai_stream *io) | ||
| 311 | { | ||
| 312 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 313 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
| 314 | |||
| 315 | if (!rsnd_scu_hpbif_is_enable(mod)) | ||
| 316 | return 0; | ||
| 317 | |||
| 318 | rsnd_scu_transfer_stop(priv, mod, rdai, io); | ||
| 319 | |||
| 320 | clk_disable(scu->clk); | ||
| 321 | |||
| 322 | return 0; | ||
| 323 | } | ||
| 324 | |||
| 325 | static struct rsnd_mod_ops rsnd_scu_ops = { | ||
| 326 | .name = "scu", | ||
| 327 | .start = rsnd_scu_start, | ||
| 328 | .stop = rsnd_scu_stop, | ||
| 329 | }; | ||
| 330 | |||
| 331 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) | ||
| 332 | { | ||
| 333 | if (WARN_ON(id < 0 || id >= rsnd_scu_nr(priv))) | ||
| 334 | id = 0; | ||
| 335 | |||
| 336 | return &((struct rsnd_scu *)(priv->scu) + id)->mod; | ||
| 337 | } | ||
| 338 | |||
| 339 | int rsnd_scu_probe(struct platform_device *pdev, | ||
| 340 | struct rcar_snd_info *info, | ||
| 341 | struct rsnd_priv *priv) | ||
| 342 | { | ||
| 343 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 344 | struct rsnd_scu *scu; | ||
| 345 | struct clk *clk; | ||
| 346 | char name[RSND_SCU_NAME_SIZE]; | ||
| 347 | int i, nr; | ||
| 348 | |||
| 349 | /* | ||
| 350 | * init SCU | ||
| 351 | */ | ||
| 352 | nr = info->scu_info_nr; | ||
| 353 | scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL); | ||
| 354 | if (!scu) { | ||
| 355 | dev_err(dev, "SCU allocate failed\n"); | ||
| 356 | return -ENOMEM; | ||
| 357 | } | ||
| 358 | |||
| 359 | priv->scu_nr = nr; | ||
| 360 | priv->scu = scu; | ||
| 361 | |||
| 362 | for_each_rsnd_scu(scu, priv, i) { | ||
| 363 | snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i); | ||
| 364 | |||
| 365 | clk = devm_clk_get(dev, name); | ||
| 366 | if (IS_ERR(clk)) | ||
| 367 | return PTR_ERR(clk); | ||
| 368 | |||
| 369 | rsnd_mod_init(priv, &scu->mod, | ||
| 370 | &rsnd_scu_ops, i); | ||
| 371 | scu->info = &info->scu_info[i]; | ||
| 372 | scu->clk = clk; | ||
| 373 | |||
| 374 | dev_dbg(dev, "SCU%d probed\n", i); | ||
| 375 | } | ||
| 376 | dev_dbg(dev, "scu probed\n"); | ||
| 377 | |||
| 378 | return 0; | ||
| 379 | } | ||
| 380 | |||
| 381 | void rsnd_scu_remove(struct platform_device *pdev, | ||
| 382 | struct rsnd_priv *priv) | ||
| 383 | { | ||
| 384 | } | ||
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c new file mode 100644 index 000000000000..ea6a214985d0 --- /dev/null +++ b/sound/soc/sh/rcar/src.c | |||
| @@ -0,0 +1,687 @@ | |||
| 1 | /* | ||
| 2 | * Renesas R-Car SRC support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
| 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include "rsnd.h" | ||
| 12 | |||
| 13 | struct rsnd_src { | ||
| 14 | struct rsnd_src_platform_info *info; /* rcar_snd.h */ | ||
| 15 | struct rsnd_mod mod; | ||
| 16 | struct clk *clk; | ||
| 17 | }; | ||
| 18 | |||
| 19 | #define RSND_SRC_NAME_SIZE 16 | ||
| 20 | |||
| 21 | /* | ||
| 22 | * ADINR | ||
| 23 | */ | ||
| 24 | #define OTBL_24 (0 << 16) | ||
| 25 | #define OTBL_22 (2 << 16) | ||
| 26 | #define OTBL_20 (4 << 16) | ||
| 27 | #define OTBL_18 (6 << 16) | ||
| 28 | #define OTBL_16 (8 << 16) | ||
| 29 | |||
| 30 | #define rsnd_src_mode_flags(p) ((p)->info->flags) | ||
| 31 | #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) | ||
| 32 | #define rsnd_mod_to_src(_mod) \ | ||
| 33 | container_of((_mod), struct rsnd_src, mod) | ||
| 34 | #define rsnd_src_hpbif_is_enable(src) \ | ||
| 35 | (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF) | ||
| 36 | #define rsnd_src_dma_available(src) \ | ||
| 37 | rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod)) | ||
| 38 | |||
| 39 | #define for_each_rsnd_src(pos, priv, i) \ | ||
| 40 | for ((i) = 0; \ | ||
| 41 | ((i) < rsnd_src_nr(priv)) && \ | ||
| 42 | ((pos) = (struct rsnd_src *)(priv)->src + i); \ | ||
| 43 | i++) | ||
| 44 | |||
| 45 | |||
| 46 | /* | ||
| 47 | * image of SRC (Sampling Rate Converter) | ||
| 48 | * | ||
| 49 | * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ | ||
| 50 | * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | | ||
| 51 | * 44.1kHz <-> +-----+ +-----+ +-------+ | ||
| 52 | * ... | ||
| 53 | * | ||
| 54 | */ | ||
| 55 | |||
| 56 | /* | ||
| 57 | * src.c is caring... | ||
| 58 | * | ||
| 59 | * Gen1 | ||
| 60 | * | ||
| 61 | * [mem] -> [SRU] -> [SSI] | ||
| 62 | * |--------| | ||
| 63 | * | ||
| 64 | * Gen2 | ||
| 65 | * | ||
| 66 | * [mem] -> [SRC] -> [SSIU] -> [SSI] | ||
| 67 | * |-----------------| | ||
| 68 | */ | ||
| 69 | |||
| 70 | /* | ||
| 71 | * How to use SRC bypass mode for debugging | ||
| 72 | * | ||
| 73 | * SRC has bypass mode, and it is useful for debugging. | ||
| 74 | * In Gen2 case, | ||
| 75 | * SRCm_MODE controls whether SRC is used or not | ||
| 76 | * SSI_MODE0 controls whether SSIU which receives SRC data | ||
| 77 | * is used or not. | ||
| 78 | * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC, | ||
| 79 | * but SRC bypass mode needs SSI_MODE0 only. | ||
| 80 | * | ||
| 81 | * This driver request | ||
| 82 | * struct rsnd_src_platform_info { | ||
| 83 | * u32 flags; | ||
| 84 | * u32 convert_rate; | ||
| 85 | * } | ||
| 86 | * | ||
| 87 | * rsnd_src_hpbif_is_enable() will be true | ||
| 88 | * if flags had RSND_SRC_USE_HPBIF, | ||
| 89 | * and it controls whether SSIU is used or not. | ||
| 90 | * | ||
| 91 | * rsnd_src_convert_rate() indicates | ||
| 92 | * above convert_rate, and it controls | ||
| 93 | * whether SRC is used or not. | ||
| 94 | * | ||
| 95 | * ex) doesn't use SRC | ||
| 96 | * struct rsnd_src_platform_info info = { | ||
| 97 | * .flags = 0, | ||
| 98 | * .convert_rate = 0, | ||
| 99 | * }; | ||
| 100 | * | ||
| 101 | * ex) uses SRC | ||
| 102 | * struct rsnd_src_platform_info info = { | ||
| 103 | * .flags = RSND_SRC_USE_HPBIF, | ||
| 104 | * .convert_rate = 48000, | ||
| 105 | * }; | ||
| 106 | * | ||
| 107 | * ex) uses SRC bypass mode | ||
| 108 | * struct rsnd_src_platform_info info = { | ||
| 109 | * .flags = RSND_SRC_USE_HPBIF, | ||
| 110 | * .convert_rate = 0, | ||
| 111 | * }; | ||
| 112 | * | ||
| 113 | */ | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Gen1/Gen2 common functions | ||
| 117 | */ | ||
| 118 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | ||
| 119 | struct rsnd_dai *rdai, | ||
| 120 | struct rsnd_dai_stream *io) | ||
| 121 | { | ||
| 122 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 123 | struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); | ||
| 124 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 125 | int ssi_id = rsnd_mod_id(ssi_mod); | ||
| 126 | int has_src = 0; | ||
| 127 | |||
| 128 | /* | ||
| 129 | * SSI_MODE0 | ||
| 130 | */ | ||
| 131 | if (info->dai_info) { | ||
| 132 | has_src = !!src_mod; | ||
| 133 | } else { | ||
| 134 | struct rsnd_src *src = rsnd_mod_to_src(src_mod); | ||
| 135 | has_src = rsnd_src_hpbif_is_enable(src); | ||
| 136 | } | ||
| 137 | |||
| 138 | rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), | ||
| 139 | has_src ? 0 : (1 << ssi_id)); | ||
| 140 | |||
| 141 | /* | ||
| 142 | * SSI_MODE1 | ||
| 143 | */ | ||
| 144 | if (rsnd_ssi_is_pin_sharing(ssi_mod)) { | ||
| 145 | int shift = -1; | ||
| 146 | switch (ssi_id) { | ||
| 147 | case 1: | ||
| 148 | shift = 0; | ||
| 149 | break; | ||
| 150 | case 2: | ||
| 151 | shift = 2; | ||
| 152 | break; | ||
| 153 | case 4: | ||
| 154 | shift = 16; | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (shift >= 0) | ||
| 159 | rsnd_mod_bset(ssi_mod, SSI_MODE1, | ||
| 160 | 0x3 << shift, | ||
| 161 | rsnd_dai_is_clk_master(rdai) ? | ||
| 162 | 0x2 << shift : 0x1 << shift); | ||
| 163 | } | ||
| 164 | |||
| 165 | return 0; | ||
| 166 | } | ||
| 167 | |||
| 168 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
| 169 | struct rsnd_dai *rdai, | ||
| 170 | struct rsnd_dai_stream *io) | ||
| 171 | { | ||
| 172 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 173 | |||
| 174 | /* enable PIO interrupt if Gen2 */ | ||
| 175 | if (rsnd_is_gen2(priv)) | ||
| 176 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | ||
| 182 | struct rsnd_dai_stream *io, | ||
| 183 | struct snd_pcm_runtime *runtime) | ||
| 184 | { | ||
| 185 | struct rsnd_src *src; | ||
| 186 | unsigned int rate; | ||
| 187 | |||
| 188 | src = rsnd_mod_to_src(rsnd_io_to_mod_src(io)); | ||
| 189 | |||
| 190 | /* | ||
| 191 | * return convert rate if SRC is used, | ||
| 192 | * otherwise, return runtime->rate as usual | ||
| 193 | */ | ||
| 194 | rate = rsnd_src_convert_rate(src); | ||
| 195 | if (!rate) | ||
| 196 | rate = runtime->rate; | ||
| 197 | |||
| 198 | return rate; | ||
| 199 | } | ||
| 200 | |||
| 201 | static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, | ||
| 202 | struct rsnd_dai *rdai, | ||
| 203 | struct rsnd_dai_stream *io) | ||
| 204 | { | ||
| 205 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 206 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 207 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
| 208 | u32 adinr = runtime->channels; | ||
| 209 | u32 fsrate = 0; | ||
| 210 | |||
| 211 | if (convert_rate) | ||
| 212 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
| 213 | |||
| 214 | /* set/clear soft reset */ | ||
| 215 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
| 216 | rsnd_mod_write(mod, SRC_SWRSR, 1); | ||
| 217 | |||
| 218 | /* | ||
| 219 | * Initialize the operation of the SRC internal circuits | ||
| 220 | * see rsnd_src_start() | ||
| 221 | */ | ||
| 222 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
| 223 | |||
| 224 | /* Set channel number and output bit length */ | ||
| 225 | switch (runtime->sample_bits) { | ||
| 226 | case 16: | ||
| 227 | adinr |= OTBL_16; | ||
| 228 | break; | ||
| 229 | case 32: | ||
| 230 | adinr |= OTBL_24; | ||
| 231 | break; | ||
| 232 | default: | ||
| 233 | return -EIO; | ||
| 234 | } | ||
| 235 | rsnd_mod_write(mod, SRC_ADINR, adinr); | ||
| 236 | |||
| 237 | /* Enable the initial value of IFS */ | ||
| 238 | if (fsrate) { | ||
| 239 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
| 240 | |||
| 241 | /* Set initial value of IFS */ | ||
| 242 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
| 243 | } | ||
| 244 | |||
| 245 | /* use DMA transfer */ | ||
| 246 | rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); | ||
| 247 | |||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 251 | static int rsnd_src_init(struct rsnd_mod *mod, | ||
| 252 | struct rsnd_dai *rdai, | ||
| 253 | struct rsnd_dai_stream *io) | ||
| 254 | { | ||
| 255 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 256 | |||
| 257 | clk_enable(src->clk); | ||
| 258 | |||
| 259 | return 0; | ||
| 260 | } | ||
| 261 | |||
| 262 | static int rsnd_src_quit(struct rsnd_mod *mod, | ||
| 263 | struct rsnd_dai *rdai, | ||
| 264 | struct rsnd_dai_stream *io) | ||
| 265 | { | ||
| 266 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 267 | |||
| 268 | clk_disable(src->clk); | ||
| 269 | |||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int rsnd_src_start(struct rsnd_mod *mod, | ||
| 274 | struct rsnd_dai *rdai, | ||
| 275 | struct rsnd_dai_stream *io) | ||
| 276 | { | ||
| 277 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 278 | |||
| 279 | /* | ||
| 280 | * Cancel the initialization and operate the SRC function | ||
| 281 | * see rsnd_src_set_convert_rate() | ||
| 282 | */ | ||
| 283 | rsnd_mod_write(mod, SRC_SRCIR, 0); | ||
| 284 | |||
| 285 | if (rsnd_src_convert_rate(src)) | ||
| 286 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
| 287 | |||
| 288 | return 0; | ||
| 289 | } | ||
| 290 | |||
| 291 | |||
| 292 | static int rsnd_src_stop(struct rsnd_mod *mod, | ||
| 293 | struct rsnd_dai *rdai, | ||
| 294 | struct rsnd_dai_stream *io) | ||
| 295 | { | ||
| 296 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 297 | |||
| 298 | if (rsnd_src_convert_rate(src)) | ||
| 299 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
| 300 | |||
| 301 | return 0; | ||
| 302 | } | ||
| 303 | |||
| 304 | static struct rsnd_mod_ops rsnd_src_non_ops = { | ||
| 305 | .name = "src (non)", | ||
| 306 | }; | ||
| 307 | |||
| 308 | /* | ||
| 309 | * Gen1 functions | ||
| 310 | */ | ||
| 311 | static int rsnd_src_set_route_gen1(struct rsnd_mod *mod, | ||
| 312 | struct rsnd_dai *rdai, | ||
| 313 | struct rsnd_dai_stream *io) | ||
| 314 | { | ||
| 315 | struct src_route_config { | ||
| 316 | u32 mask; | ||
| 317 | int shift; | ||
| 318 | } routes[] = { | ||
| 319 | { 0xF, 0, }, /* 0 */ | ||
| 320 | { 0xF, 4, }, /* 1 */ | ||
| 321 | { 0xF, 8, }, /* 2 */ | ||
| 322 | { 0x7, 12, }, /* 3 */ | ||
| 323 | { 0x7, 16, }, /* 4 */ | ||
| 324 | { 0x7, 20, }, /* 5 */ | ||
| 325 | { 0x7, 24, }, /* 6 */ | ||
| 326 | { 0x3, 28, }, /* 7 */ | ||
| 327 | { 0x3, 30, }, /* 8 */ | ||
| 328 | }; | ||
| 329 | u32 mask; | ||
| 330 | u32 val; | ||
| 331 | int id; | ||
| 332 | |||
| 333 | id = rsnd_mod_id(mod); | ||
| 334 | if (id < 0 || id >= ARRAY_SIZE(routes)) | ||
| 335 | return -EIO; | ||
| 336 | |||
| 337 | /* | ||
| 338 | * SRC_ROUTE_SELECT | ||
| 339 | */ | ||
| 340 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
| 341 | val = val << routes[id].shift; | ||
| 342 | mask = routes[id].mask << routes[id].shift; | ||
| 343 | |||
| 344 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
| 345 | |||
| 346 | return 0; | ||
| 347 | } | ||
| 348 | |||
| 349 | static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, | ||
| 350 | struct rsnd_dai *rdai, | ||
| 351 | struct rsnd_dai_stream *io) | ||
| 352 | { | ||
| 353 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 354 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 355 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 356 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
| 357 | u32 mask; | ||
| 358 | u32 val; | ||
| 359 | int shift; | ||
| 360 | int id = rsnd_mod_id(mod); | ||
| 361 | int ret; | ||
| 362 | |||
| 363 | /* | ||
| 364 | * SRC_TIMING_SELECT | ||
| 365 | */ | ||
| 366 | shift = (id % 4) * 8; | ||
| 367 | mask = 0x1F << shift; | ||
| 368 | |||
| 369 | /* | ||
| 370 | * ADG is used as source clock if SRC was used, | ||
| 371 | * then, SSI WS is used as destination clock. | ||
| 372 | * SSI WS is used as source clock if SRC is not used | ||
| 373 | * (when playback, source/destination become reverse when capture) | ||
| 374 | */ | ||
| 375 | ret = 0; | ||
| 376 | if (convert_rate) { | ||
| 377 | /* use ADG */ | ||
| 378 | val = 0; | ||
| 379 | ret = rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
| 380 | runtime->rate, | ||
| 381 | convert_rate); | ||
| 382 | } else if (8 == id) { | ||
| 383 | /* use SSI WS, but SRU8 is special */ | ||
| 384 | val = id << shift; | ||
| 385 | } else { | ||
| 386 | /* use SSI WS */ | ||
| 387 | val = (id + 1) << shift; | ||
| 388 | } | ||
| 389 | |||
| 390 | if (ret < 0) | ||
| 391 | return ret; | ||
| 392 | |||
| 393 | switch (id / 4) { | ||
| 394 | case 0: | ||
| 395 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
| 396 | break; | ||
| 397 | case 1: | ||
| 398 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
| 399 | break; | ||
| 400 | case 2: | ||
| 401 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
| 402 | break; | ||
| 403 | } | ||
| 404 | |||
| 405 | return 0; | ||
| 406 | } | ||
| 407 | |||
| 408 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | ||
| 409 | struct rsnd_dai *rdai, | ||
| 410 | struct rsnd_dai_stream *io) | ||
| 411 | { | ||
| 412 | int ret; | ||
| 413 | |||
| 414 | ret = rsnd_src_set_convert_rate(mod, rdai, io); | ||
| 415 | if (ret < 0) | ||
| 416 | return ret; | ||
| 417 | |||
| 418 | /* Select SRC mode (fixed value) */ | ||
| 419 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
| 420 | |||
| 421 | /* Set the restriction value of the FS ratio (98%) */ | ||
| 422 | rsnd_mod_write(mod, SRC_MNFSR, | ||
| 423 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | ||
| 424 | |||
| 425 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
| 426 | |||
| 427 | return 0; | ||
| 428 | } | ||
| 429 | |||
| 430 | static int rsnd_src_init_gen1(struct rsnd_mod *mod, | ||
| 431 | struct rsnd_dai *rdai, | ||
| 432 | struct rsnd_dai_stream *io) | ||
| 433 | { | ||
| 434 | int ret; | ||
| 435 | |||
| 436 | ret = rsnd_src_init(mod, rdai, io); | ||
| 437 | if (ret < 0) | ||
| 438 | return ret; | ||
| 439 | |||
| 440 | ret = rsnd_src_set_route_gen1(mod, rdai, io); | ||
| 441 | if (ret < 0) | ||
| 442 | return ret; | ||
| 443 | |||
| 444 | ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io); | ||
| 445 | if (ret < 0) | ||
| 446 | return ret; | ||
| 447 | |||
| 448 | ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io); | ||
| 449 | if (ret < 0) | ||
| 450 | return ret; | ||
| 451 | |||
| 452 | return 0; | ||
| 453 | } | ||
| 454 | |||
| 455 | static int rsnd_src_start_gen1(struct rsnd_mod *mod, | ||
| 456 | struct rsnd_dai *rdai, | ||
| 457 | struct rsnd_dai_stream *io) | ||
| 458 | { | ||
| 459 | int id = rsnd_mod_id(mod); | ||
| 460 | |||
| 461 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); | ||
| 462 | |||
| 463 | return rsnd_src_start(mod, rdai, io); | ||
| 464 | } | ||
| 465 | |||
| 466 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | ||
| 467 | struct rsnd_dai *rdai, | ||
| 468 | struct rsnd_dai_stream *io) | ||
| 469 | { | ||
| 470 | int id = rsnd_mod_id(mod); | ||
| 471 | |||
| 472 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); | ||
| 473 | |||
| 474 | return rsnd_src_stop(mod, rdai, io); | ||
| 475 | } | ||
| 476 | |||
| 477 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { | ||
| 478 | .name = "sru (gen1)", | ||
| 479 | .init = rsnd_src_init_gen1, | ||
| 480 | .quit = rsnd_src_quit, | ||
| 481 | .start = rsnd_src_start_gen1, | ||
| 482 | .stop = rsnd_src_stop_gen1, | ||
| 483 | }; | ||
| 484 | |||
| 485 | /* | ||
| 486 | * Gen2 functions | ||
| 487 | */ | ||
| 488 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | ||
| 489 | struct rsnd_dai *rdai, | ||
| 490 | struct rsnd_dai_stream *io) | ||
| 491 | { | ||
| 492 | int ret; | ||
| 493 | |||
| 494 | ret = rsnd_src_set_convert_rate(mod, rdai, io); | ||
| 495 | if (ret < 0) | ||
| 496 | return ret; | ||
| 497 | |||
| 498 | rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR)); | ||
| 499 | rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE)); | ||
| 500 | |||
| 501 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | ||
| 502 | |||
| 503 | rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); | ||
| 504 | rsnd_mod_write(mod, SRC_BSISR, 0x00100060); | ||
| 505 | |||
| 506 | return 0; | ||
| 507 | } | ||
| 508 | |||
| 509 | static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
| 510 | struct rsnd_dai *rdai, | ||
| 511 | struct rsnd_dai_stream *io) | ||
| 512 | { | ||
| 513 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 514 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 515 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
| 516 | int ret; | ||
| 517 | |||
| 518 | if (convert_rate) | ||
| 519 | ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io, | ||
| 520 | runtime->rate, | ||
| 521 | convert_rate); | ||
| 522 | else | ||
| 523 | ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io); | ||
| 524 | |||
| 525 | return ret; | ||
| 526 | } | ||
| 527 | |||
| 528 | static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | ||
| 529 | struct rsnd_dai *rdai, | ||
| 530 | struct rsnd_dai_stream *io) | ||
| 531 | { | ||
| 532 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 533 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 534 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 535 | struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod)); | ||
| 536 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 537 | int ret; | ||
| 538 | int is_play; | ||
| 539 | |||
| 540 | if (info->dai_info) | ||
| 541 | is_play = rsnd_info_is_playback(priv, src); | ||
| 542 | else | ||
| 543 | is_play = rsnd_ssi_is_play(ssi); | ||
| 544 | |||
| 545 | ret = rsnd_dma_init(priv, | ||
| 546 | rsnd_mod_to_dma(mod), | ||
| 547 | is_play, | ||
| 548 | src->info->dma_id); | ||
| 549 | if (ret < 0) | ||
| 550 | dev_err(dev, "SRC DMA failed\n"); | ||
| 551 | |||
| 552 | return ret; | ||
| 553 | } | ||
| 554 | |||
| 555 | static int rsnd_src_remove_gen2(struct rsnd_mod *mod, | ||
| 556 | struct rsnd_dai *rdai, | ||
| 557 | struct rsnd_dai_stream *io) | ||
| 558 | { | ||
| 559 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | ||
| 560 | |||
| 561 | return 0; | ||
| 562 | } | ||
| 563 | |||
| 564 | static int rsnd_src_init_gen2(struct rsnd_mod *mod, | ||
| 565 | struct rsnd_dai *rdai, | ||
| 566 | struct rsnd_dai_stream *io) | ||
| 567 | { | ||
| 568 | int ret; | ||
| 569 | |||
| 570 | ret = rsnd_src_init(mod, rdai, io); | ||
| 571 | if (ret < 0) | ||
| 572 | return ret; | ||
| 573 | |||
| 574 | ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io); | ||
| 575 | if (ret < 0) | ||
| 576 | return ret; | ||
| 577 | |||
| 578 | ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io); | ||
| 579 | if (ret < 0) | ||
| 580 | return ret; | ||
| 581 | |||
| 582 | return 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | static int rsnd_src_start_gen2(struct rsnd_mod *mod, | ||
| 586 | struct rsnd_dai *rdai, | ||
| 587 | struct rsnd_dai_stream *io) | ||
| 588 | { | ||
| 589 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 590 | |||
| 591 | rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); | ||
| 592 | |||
| 593 | rsnd_mod_write(mod, SSI_CTRL, 0x1); | ||
| 594 | rsnd_mod_write(mod, SRC_CTRL, 0x11); | ||
| 595 | |||
| 596 | return rsnd_src_start(mod, rdai, io); | ||
| 597 | } | ||
| 598 | |||
| 599 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | ||
| 600 | struct rsnd_dai *rdai, | ||
| 601 | struct rsnd_dai_stream *io) | ||
| 602 | { | ||
| 603 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 604 | |||
| 605 | rsnd_mod_write(mod, SSI_CTRL, 0); | ||
| 606 | rsnd_mod_write(mod, SRC_CTRL, 0); | ||
| 607 | |||
| 608 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); | ||
| 609 | |||
| 610 | return rsnd_src_stop(mod, rdai, io); | ||
| 611 | } | ||
| 612 | |||
| 613 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | ||
| 614 | .name = "src (gen2)", | ||
| 615 | .probe = rsnd_src_probe_gen2, | ||
| 616 | .remove = rsnd_src_remove_gen2, | ||
| 617 | .init = rsnd_src_init_gen2, | ||
| 618 | .quit = rsnd_src_quit, | ||
| 619 | .start = rsnd_src_start_gen2, | ||
| 620 | .stop = rsnd_src_stop_gen2, | ||
| 621 | }; | ||
| 622 | |||
| 623 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | ||
| 624 | { | ||
| 625 | if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) | ||
| 626 | id = 0; | ||
| 627 | |||
| 628 | return &((struct rsnd_src *)(priv->src) + id)->mod; | ||
| 629 | } | ||
| 630 | |||
| 631 | int rsnd_src_probe(struct platform_device *pdev, | ||
| 632 | struct rsnd_priv *priv) | ||
| 633 | { | ||
| 634 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 635 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 636 | struct rsnd_src *src; | ||
| 637 | struct rsnd_mod_ops *ops; | ||
| 638 | struct clk *clk; | ||
| 639 | char name[RSND_SRC_NAME_SIZE]; | ||
| 640 | int i, nr; | ||
| 641 | |||
| 642 | /* | ||
| 643 | * init SRC | ||
| 644 | */ | ||
| 645 | nr = info->src_info_nr; | ||
| 646 | if (!nr) | ||
| 647 | return 0; | ||
| 648 | |||
| 649 | src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); | ||
| 650 | if (!src) { | ||
| 651 | dev_err(dev, "SRC allocate failed\n"); | ||
| 652 | return -ENOMEM; | ||
| 653 | } | ||
| 654 | |||
| 655 | priv->src_nr = nr; | ||
| 656 | priv->src = src; | ||
| 657 | |||
| 658 | for_each_rsnd_src(src, priv, i) { | ||
| 659 | snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i); | ||
| 660 | |||
| 661 | clk = devm_clk_get(dev, name); | ||
| 662 | if (IS_ERR(clk)) { | ||
| 663 | snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i); | ||
| 664 | clk = devm_clk_get(dev, name); | ||
| 665 | } | ||
| 666 | |||
| 667 | if (IS_ERR(clk)) | ||
| 668 | return PTR_ERR(clk); | ||
| 669 | |||
| 670 | src->info = &info->src_info[i]; | ||
| 671 | src->clk = clk; | ||
| 672 | |||
| 673 | ops = &rsnd_src_non_ops; | ||
| 674 | if (rsnd_src_hpbif_is_enable(src)) { | ||
| 675 | if (rsnd_is_gen1(priv)) | ||
| 676 | ops = &rsnd_src_gen1_ops; | ||
| 677 | if (rsnd_is_gen2(priv)) | ||
| 678 | ops = &rsnd_src_gen2_ops; | ||
| 679 | } | ||
| 680 | |||
| 681 | rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i); | ||
| 682 | |||
| 683 | dev_dbg(dev, "SRC%d probed\n", i); | ||
| 684 | } | ||
| 685 | |||
| 686 | return 0; | ||
| 687 | } | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b8cf7ca9d19..633b23d209b9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
| @@ -64,108 +64,29 @@ struct rsnd_ssi { | |||
| 64 | struct rsnd_mod mod; | 64 | struct rsnd_mod mod; |
| 65 | 65 | ||
| 66 | struct rsnd_dai *rdai; | 66 | struct rsnd_dai *rdai; |
| 67 | struct rsnd_dai_stream *io; | ||
| 68 | u32 cr_own; | 67 | u32 cr_own; |
| 69 | u32 cr_clk; | 68 | u32 cr_clk; |
| 70 | u32 cr_etc; | 69 | u32 cr_etc; |
| 71 | int err; | 70 | int err; |
| 72 | int dma_offset; | ||
| 73 | unsigned int usrcnt; | 71 | unsigned int usrcnt; |
| 74 | unsigned int rate; | 72 | unsigned int rate; |
| 75 | }; | 73 | }; |
| 76 | 74 | ||
| 77 | struct rsnd_ssiu { | ||
| 78 | u32 ssi_mode0; | ||
| 79 | u32 ssi_mode1; | ||
| 80 | |||
| 81 | int ssi_nr; | ||
| 82 | struct rsnd_ssi *ssi; | ||
| 83 | }; | ||
| 84 | |||
| 85 | #define for_each_rsnd_ssi(pos, priv, i) \ | 75 | #define for_each_rsnd_ssi(pos, priv, i) \ |
| 86 | for (i = 0; \ | 76 | for (i = 0; \ |
| 87 | (i < rsnd_ssi_nr(priv)) && \ | 77 | (i < rsnd_ssi_nr(priv)) && \ |
| 88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ | 78 | ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ |
| 89 | i++) | 79 | i++) |
| 90 | 80 | ||
| 91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) | 81 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
| 92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 82 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
| 93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 83 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
| 94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 84 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) |
| 95 | #define rsnd_ssi_dma_available(ssi) \ | 85 | #define rsnd_ssi_dma_available(ssi) \ |
| 96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 86 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
| 97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 87 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
| 98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) | ||
| 99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 88 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
| 100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 89 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
| 101 | #define rsnd_ssi_to_ssiu(ssi)\ | ||
| 102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) | ||
| 103 | |||
| 104 | static void rsnd_ssi_mode_set(struct rsnd_priv *priv, | ||
| 105 | struct rsnd_dai *rdai, | ||
| 106 | struct rsnd_ssi *ssi) | ||
| 107 | { | ||
| 108 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 109 | struct rsnd_mod *scu; | ||
| 110 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); | ||
| 111 | int id = rsnd_mod_id(&ssi->mod); | ||
| 112 | u32 flags; | ||
| 113 | u32 val; | ||
| 114 | |||
| 115 | scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); | ||
| 116 | |||
| 117 | /* | ||
| 118 | * SSI_MODE0 | ||
| 119 | */ | ||
| 120 | |||
| 121 | /* see also BUSIF_MODE */ | ||
| 122 | if (rsnd_scu_hpbif_is_enable(scu)) { | ||
| 123 | ssiu->ssi_mode0 &= ~(1 << id); | ||
| 124 | dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id); | ||
| 125 | } else { | ||
| 126 | ssiu->ssi_mode0 |= (1 << id); | ||
| 127 | dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id); | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * SSI_MODE1 | ||
| 132 | */ | ||
| 133 | #define ssi_parent_set(p, sync, adg, ext) \ | ||
| 134 | do { \ | ||
| 135 | ssi->parent = ssiu->ssi + p; \ | ||
| 136 | if (rsnd_rdai_is_clk_master(rdai)) \ | ||
| 137 | val = adg; \ | ||
| 138 | else \ | ||
| 139 | val = ext; \ | ||
| 140 | if (flags & RSND_SSI_SYNC) \ | ||
| 141 | val |= sync; \ | ||
| 142 | } while (0) | ||
| 143 | |||
| 144 | flags = rsnd_ssi_mode_flags(ssi); | ||
| 145 | if (flags & RSND_SSI_CLK_PIN_SHARE) { | ||
| 146 | |||
| 147 | val = 0; | ||
| 148 | switch (id) { | ||
| 149 | case 1: | ||
| 150 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); | ||
| 151 | break; | ||
| 152 | case 2: | ||
| 153 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); | ||
| 154 | break; | ||
| 155 | case 4: | ||
| 156 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); | ||
| 157 | break; | ||
| 158 | case 8: | ||
| 159 | ssi_parent_set(7, 0, 0, 0); | ||
| 160 | break; | ||
| 161 | } | ||
| 162 | |||
| 163 | ssiu->ssi_mode1 |= val; | ||
| 164 | } | ||
| 165 | |||
| 166 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); | ||
| 167 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); | ||
| 168 | } | ||
| 169 | 90 | ||
| 170 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 91 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
| 171 | u32 bit) | 92 | u32 bit) |
| @@ -200,7 +121,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
| 200 | 1, 2, 4, 8, 16, 6, 12, | 121 | 1, 2, 4, 8, 16, 6, 12, |
| 201 | }; | 122 | }; |
| 202 | unsigned int main_rate; | 123 | unsigned int main_rate; |
| 203 | unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); | 124 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); |
| 204 | 125 | ||
| 205 | /* | 126 | /* |
| 206 | * Find best clock, and try to start ADG | 127 | * Find best clock, and try to start ADG |
| @@ -252,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
| 252 | if (0 == ssi->usrcnt) { | 173 | if (0 == ssi->usrcnt) { |
| 253 | clk_enable(ssi->clk); | 174 | clk_enable(ssi->clk); |
| 254 | 175 | ||
| 255 | if (rsnd_rdai_is_clk_master(rdai)) { | 176 | if (rsnd_dai_is_clk_master(rdai)) { |
| 256 | if (rsnd_ssi_clk_from_parent(ssi)) | 177 | if (rsnd_ssi_clk_from_parent(ssi)) |
| 257 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | 178 | rsnd_ssi_hw_start(ssi->parent, rdai, io); |
| 258 | else | 179 | else |
| @@ -302,7 +223,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | |||
| 302 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ | 223 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ |
| 303 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | 224 | rsnd_ssi_status_check(&ssi->mod, IIRQ); |
| 304 | 225 | ||
| 305 | if (rsnd_rdai_is_clk_master(rdai)) { | 226 | if (rsnd_dai_is_clk_master(rdai)) { |
| 306 | if (rsnd_ssi_clk_from_parent(ssi)) | 227 | if (rsnd_ssi_clk_from_parent(ssi)) |
| 307 | rsnd_ssi_hw_stop(ssi->parent, rdai); | 228 | rsnd_ssi_hw_stop(ssi->parent, rdai); |
| 308 | else | 229 | else |
| @@ -323,8 +244,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
| 323 | struct rsnd_dai_stream *io) | 244 | struct rsnd_dai_stream *io) |
| 324 | { | 245 | { |
| 325 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 246 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 326 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 327 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 328 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 247 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| 329 | u32 cr; | 248 | u32 cr; |
| 330 | 249 | ||
| @@ -365,13 +284,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
| 365 | * set ssi parameter | 284 | * set ssi parameter |
| 366 | */ | 285 | */ |
| 367 | ssi->rdai = rdai; | 286 | ssi->rdai = rdai; |
| 368 | ssi->io = io; | ||
| 369 | ssi->cr_own = cr; | 287 | ssi->cr_own = cr; |
| 370 | ssi->err = -1; /* ignore 1st error */ | 288 | ssi->err = -1; /* ignore 1st error */ |
| 371 | 289 | ||
| 372 | rsnd_ssi_mode_set(priv, rdai, ssi); | 290 | rsnd_src_ssi_mode_init(mod, rdai, io); |
| 373 | |||
| 374 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 375 | 291 | ||
| 376 | return 0; | 292 | return 0; |
| 377 | } | 293 | } |
| @@ -384,13 +300,10 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
| 384 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 300 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 385 | struct device *dev = rsnd_priv_to_dev(priv); | 301 | struct device *dev = rsnd_priv_to_dev(priv); |
| 386 | 302 | ||
| 387 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 388 | |||
| 389 | if (ssi->err > 0) | 303 | if (ssi->err > 0) |
| 390 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); | 304 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); |
| 391 | 305 | ||
| 392 | ssi->rdai = NULL; | 306 | ssi->rdai = NULL; |
| 393 | ssi->io = NULL; | ||
| 394 | ssi->cr_own = 0; | 307 | ssi->cr_own = 0; |
| 395 | ssi->err = 0; | 308 | ssi->err = 0; |
| 396 | 309 | ||
| @@ -414,8 +327,9 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
| 414 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 327 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) |
| 415 | { | 328 | { |
| 416 | struct rsnd_ssi *ssi = data; | 329 | struct rsnd_ssi *ssi = data; |
| 417 | struct rsnd_dai_stream *io = ssi->io; | 330 | struct rsnd_mod *mod = &ssi->mod; |
| 418 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | 331 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
| 332 | u32 status = rsnd_mod_read(mod, SSISR); | ||
| 419 | irqreturn_t ret = IRQ_NONE; | 333 | irqreturn_t ret = IRQ_NONE; |
| 420 | 334 | ||
| 421 | if (io && (status & DIRQ)) { | 335 | if (io && (status & DIRQ)) { |
| @@ -432,9 +346,9 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
| 432 | * see rsnd_ssi_init() | 346 | * see rsnd_ssi_init() |
| 433 | */ | 347 | */ |
| 434 | if (rsnd_dai_is_play(rdai, io)) | 348 | if (rsnd_dai_is_play(rdai, io)) |
| 435 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); | 349 | rsnd_mod_write(mod, SSITDR, *buf); |
| 436 | else | 350 | else |
| 437 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); | 351 | *buf = rsnd_mod_read(mod, SSIRDR); |
| 438 | 352 | ||
| 439 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 353 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
| 440 | 354 | ||
| @@ -444,25 +358,39 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
| 444 | return ret; | 358 | return ret; |
| 445 | } | 359 | } |
| 446 | 360 | ||
| 447 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | 361 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
| 448 | struct rsnd_dai *rdai, | 362 | struct rsnd_dai *rdai, |
| 449 | struct rsnd_dai_stream *io) | 363 | struct rsnd_dai_stream *io) |
| 450 | { | 364 | { |
| 451 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 365 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 452 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 453 | struct device *dev = rsnd_priv_to_dev(priv); | 366 | struct device *dev = rsnd_priv_to_dev(priv); |
| 367 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 368 | int irq = ssi->info->pio_irq; | ||
| 369 | int ret; | ||
| 370 | |||
| 371 | ret = devm_request_irq(dev, irq, | ||
| 372 | rsnd_ssi_pio_interrupt, | ||
| 373 | IRQF_SHARED, | ||
| 374 | dev_name(dev), ssi); | ||
| 375 | if (ret) | ||
| 376 | dev_err(dev, "SSI request interrupt failed\n"); | ||
| 377 | |||
| 378 | return ret; | ||
| 379 | } | ||
| 380 | |||
| 381 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
| 382 | struct rsnd_dai *rdai, | ||
| 383 | struct rsnd_dai_stream *io) | ||
| 384 | { | ||
| 385 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 454 | 386 | ||
| 455 | /* enable PIO IRQ */ | 387 | /* enable PIO IRQ */ |
| 456 | ssi->cr_etc = UIEN | OIEN | DIEN; | 388 | ssi->cr_etc = UIEN | OIEN | DIEN; |
| 457 | 389 | ||
| 458 | /* enable PIO interrupt if gen2 */ | 390 | rsnd_src_enable_ssi_irq(mod, rdai, io); |
| 459 | if (rsnd_is_gen2(priv)) | ||
| 460 | rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000); | ||
| 461 | 391 | ||
| 462 | rsnd_ssi_hw_start(ssi, rdai, io); | 392 | rsnd_ssi_hw_start(ssi, rdai, io); |
| 463 | 393 | ||
| 464 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 465 | |||
| 466 | return 0; | 394 | return 0; |
| 467 | } | 395 | } |
| 468 | 396 | ||
| @@ -470,12 +398,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
| 470 | struct rsnd_dai *rdai, | 398 | struct rsnd_dai *rdai, |
| 471 | struct rsnd_dai_stream *io) | 399 | struct rsnd_dai_stream *io) |
| 472 | { | 400 | { |
| 473 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 474 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 475 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 401 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 476 | 402 | ||
| 477 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 478 | |||
| 479 | ssi->cr_etc = 0; | 403 | ssi->cr_etc = 0; |
| 480 | 404 | ||
| 481 | rsnd_ssi_hw_stop(ssi, rdai); | 405 | rsnd_ssi_hw_stop(ssi, rdai); |
| @@ -485,35 +409,46 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
| 485 | 409 | ||
| 486 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 410 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
| 487 | .name = "ssi (pio)", | 411 | .name = "ssi (pio)", |
| 412 | .probe = rsnd_ssi_pio_probe, | ||
| 488 | .init = rsnd_ssi_init, | 413 | .init = rsnd_ssi_init, |
| 489 | .quit = rsnd_ssi_quit, | 414 | .quit = rsnd_ssi_quit, |
| 490 | .start = rsnd_ssi_pio_start, | 415 | .start = rsnd_ssi_pio_start, |
| 491 | .stop = rsnd_ssi_pio_stop, | 416 | .stop = rsnd_ssi_pio_stop, |
| 492 | }; | 417 | }; |
| 493 | 418 | ||
| 494 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) | 419 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
| 420 | struct rsnd_dai *rdai, | ||
| 421 | struct rsnd_dai_stream *io) | ||
| 495 | { | 422 | { |
| 496 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | 423 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 497 | struct rsnd_dai_stream *io = ssi->io; | 424 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 498 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 425 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); |
| 426 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 427 | int dma_id = ssi->info->dma_id; | ||
| 428 | int is_play; | ||
| 429 | int ret; | ||
| 499 | 430 | ||
| 500 | *len = io->byte_per_period; | 431 | if (info->dai_info) |
| 501 | *buf = runtime->dma_addr + | 432 | is_play = rsnd_info_is_playback(priv, ssi); |
| 502 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); | 433 | else |
| 503 | ssi->dma_offset = *len; /* it cares A/B plane */ | 434 | is_play = rsnd_ssi_is_play(&ssi->mod); |
| 504 | 435 | ||
| 505 | return 0; | 436 | ret = rsnd_dma_init( |
| 506 | } | 437 | priv, rsnd_mod_to_dma(mod), |
| 438 | is_play, | ||
| 439 | dma_id); | ||
| 507 | 440 | ||
| 508 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) | 441 | if (ret < 0) |
| 509 | { | 442 | dev_err(dev, "SSI DMA failed\n"); |
| 510 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | ||
| 511 | struct rsnd_dai_stream *io = ssi->io; | ||
| 512 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | ||
| 513 | 443 | ||
| 514 | rsnd_ssi_record_error(ssi, status); | 444 | return ret; |
| 445 | } | ||
| 515 | 446 | ||
| 516 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); | 447 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
| 448 | struct rsnd_dai *rdai, | ||
| 449 | struct rsnd_dai_stream *io) | ||
| 450 | { | ||
| 451 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | ||
| 517 | 452 | ||
| 518 | return 0; | 453 | return 0; |
| 519 | } | 454 | } |
| @@ -527,14 +462,13 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
| 527 | 462 | ||
| 528 | /* enable DMA transfer */ | 463 | /* enable DMA transfer */ |
| 529 | ssi->cr_etc = DMEN; | 464 | ssi->cr_etc = DMEN; |
| 530 | ssi->dma_offset = 0; | ||
| 531 | 465 | ||
| 532 | rsnd_dma_start(dma); | 466 | rsnd_dma_start(dma); |
| 533 | 467 | ||
| 534 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 468 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); |
| 535 | 469 | ||
| 536 | /* enable WS continue */ | 470 | /* enable WS continue */ |
| 537 | if (rsnd_rdai_is_clk_master(rdai)) | 471 | if (rsnd_dai_is_clk_master(rdai)) |
| 538 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 472 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); |
| 539 | 473 | ||
| 540 | return 0; | 474 | return 0; |
| @@ -549,6 +483,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
| 549 | 483 | ||
| 550 | ssi->cr_etc = 0; | 484 | ssi->cr_etc = 0; |
| 551 | 485 | ||
| 486 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
| 487 | |||
| 552 | rsnd_ssi_hw_stop(ssi, rdai); | 488 | rsnd_ssi_hw_stop(ssi, rdai); |
| 553 | 489 | ||
| 554 | rsnd_dma_stop(dma); | 490 | rsnd_dma_stop(dma); |
| @@ -558,6 +494,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
| 558 | 494 | ||
| 559 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 495 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
| 560 | .name = "ssi (dma)", | 496 | .name = "ssi (dma)", |
| 497 | .probe = rsnd_ssi_dma_probe, | ||
| 498 | .remove = rsnd_ssi_dma_remove, | ||
| 561 | .init = rsnd_ssi_init, | 499 | .init = rsnd_ssi_init, |
| 562 | .quit = rsnd_ssi_quit, | 500 | .quit = rsnd_ssi_quit, |
| 563 | .start = rsnd_ssi_dma_start, | 501 | .start = rsnd_ssi_dma_start, |
| @@ -567,24 +505,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
| 567 | /* | 505 | /* |
| 568 | * Non SSI | 506 | * Non SSI |
| 569 | */ | 507 | */ |
| 570 | static int rsnd_ssi_non(struct rsnd_mod *mod, | ||
| 571 | struct rsnd_dai *rdai, | ||
| 572 | struct rsnd_dai_stream *io) | ||
| 573 | { | ||
| 574 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 575 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 576 | |||
| 577 | dev_dbg(dev, "%s\n", __func__); | ||
| 578 | |||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | |||
| 582 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | 508 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { |
| 583 | .name = "ssi (non)", | 509 | .name = "ssi (non)", |
| 584 | .init = rsnd_ssi_non, | ||
| 585 | .quit = rsnd_ssi_non, | ||
| 586 | .start = rsnd_ssi_non, | ||
| 587 | .stop = rsnd_ssi_non, | ||
| 588 | }; | 510 | }; |
| 589 | 511 | ||
| 590 | /* | 512 | /* |
| @@ -593,16 +515,30 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { | |||
| 593 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 515 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
| 594 | int dai_id, int is_play) | 516 | int dai_id, int is_play) |
| 595 | { | 517 | { |
| 518 | struct rsnd_dai_platform_info *dai_info = NULL; | ||
| 519 | struct rsnd_dai_path_info *path_info = NULL; | ||
| 520 | struct rsnd_ssi_platform_info *target_info = NULL; | ||
| 596 | struct rsnd_ssi *ssi; | 521 | struct rsnd_ssi *ssi; |
| 597 | int i, has_play; | 522 | int i, has_play; |
| 598 | 523 | ||
| 524 | if (priv->rdai) | ||
| 525 | dai_info = priv->rdai[dai_id].info; | ||
| 526 | if (dai_info) | ||
| 527 | path_info = (is_play) ? &dai_info->playback : &dai_info->capture; | ||
| 528 | if (path_info) | ||
| 529 | target_info = path_info->ssi; | ||
| 530 | |||
| 599 | is_play = !!is_play; | 531 | is_play = !!is_play; |
| 600 | 532 | ||
| 601 | for_each_rsnd_ssi(ssi, priv, i) { | 533 | for_each_rsnd_ssi(ssi, priv, i) { |
| 534 | if (target_info == ssi->info) | ||
| 535 | return &ssi->mod; | ||
| 536 | |||
| 537 | /* for compatible */ | ||
| 602 | if (rsnd_ssi_dai_id(ssi) != dai_id) | 538 | if (rsnd_ssi_dai_id(ssi) != dai_id) |
| 603 | continue; | 539 | continue; |
| 604 | 540 | ||
| 605 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | 541 | has_play = rsnd_ssi_is_play(&ssi->mod); |
| 606 | 542 | ||
| 607 | if (is_play == has_play) | 543 | if (is_play == has_play) |
| 608 | return &ssi->mod; | 544 | return &ssi->mod; |
| @@ -616,36 +552,66 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | |||
| 616 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 552 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
| 617 | id = 0; | 553 | id = 0; |
| 618 | 554 | ||
| 619 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; | 555 | return &((struct rsnd_ssi *)(priv->ssi) + id)->mod; |
| 556 | } | ||
| 557 | |||
| 558 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | ||
| 559 | { | ||
| 560 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 561 | |||
| 562 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | ||
| 563 | } | ||
| 564 | |||
| 565 | int rsnd_ssi_is_play(struct rsnd_mod *mod) | ||
| 566 | { | ||
| 567 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 568 | |||
| 569 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | ||
| 570 | } | ||
| 571 | |||
| 572 | static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | ||
| 573 | { | ||
| 574 | if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) | ||
| 575 | return; | ||
| 576 | |||
| 577 | switch (rsnd_mod_id(&ssi->mod)) { | ||
| 578 | case 1: | ||
| 579 | case 2: | ||
| 580 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); | ||
| 581 | break; | ||
| 582 | case 4: | ||
| 583 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); | ||
| 584 | break; | ||
| 585 | case 8: | ||
| 586 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); | ||
| 587 | break; | ||
| 588 | } | ||
| 620 | } | 589 | } |
| 621 | 590 | ||
| 622 | int rsnd_ssi_probe(struct platform_device *pdev, | 591 | int rsnd_ssi_probe(struct platform_device *pdev, |
| 623 | struct rcar_snd_info *info, | ||
| 624 | struct rsnd_priv *priv) | 592 | struct rsnd_priv *priv) |
| 625 | { | 593 | { |
| 594 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 626 | struct rsnd_ssi_platform_info *pinfo; | 595 | struct rsnd_ssi_platform_info *pinfo; |
| 627 | struct device *dev = rsnd_priv_to_dev(priv); | 596 | struct device *dev = rsnd_priv_to_dev(priv); |
| 628 | struct rsnd_mod_ops *ops; | 597 | struct rsnd_mod_ops *ops; |
| 629 | struct clk *clk; | 598 | struct clk *clk; |
| 630 | struct rsnd_ssiu *ssiu; | ||
| 631 | struct rsnd_ssi *ssi; | 599 | struct rsnd_ssi *ssi; |
| 632 | char name[RSND_SSI_NAME_SIZE]; | 600 | char name[RSND_SSI_NAME_SIZE]; |
| 633 | int i, nr, ret; | 601 | int i, nr; |
| 634 | 602 | ||
| 635 | /* | 603 | /* |
| 636 | * init SSI | 604 | * init SSI |
| 637 | */ | 605 | */ |
| 638 | nr = info->ssi_info_nr; | 606 | nr = info->ssi_info_nr; |
| 639 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), | 607 | ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); |
| 640 | GFP_KERNEL); | 608 | if (!ssi) { |
| 641 | if (!ssiu) { | ||
| 642 | dev_err(dev, "SSI allocate failed\n"); | 609 | dev_err(dev, "SSI allocate failed\n"); |
| 643 | return -ENOMEM; | 610 | return -ENOMEM; |
| 644 | } | 611 | } |
| 645 | 612 | ||
| 646 | priv->ssiu = ssiu; | 613 | priv->ssi = ssi; |
| 647 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); | 614 | priv->ssi_nr = nr; |
| 648 | ssiu->ssi_nr = nr; | ||
| 649 | 615 | ||
| 650 | for_each_rsnd_ssi(ssi, priv, i) { | 616 | for_each_rsnd_ssi(ssi, priv, i) { |
| 651 | pinfo = &info->ssi_info[i]; | 617 | pinfo = &info->ssi_info[i]; |
| @@ -660,61 +626,15 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
| 660 | ssi->clk = clk; | 626 | ssi->clk = clk; |
| 661 | 627 | ||
| 662 | ops = &rsnd_ssi_non_ops; | 628 | ops = &rsnd_ssi_non_ops; |
| 629 | if (pinfo->dma_id > 0) | ||
| 630 | ops = &rsnd_ssi_dma_ops; | ||
| 631 | else if (rsnd_ssi_pio_available(ssi)) | ||
| 632 | ops = &rsnd_ssi_pio_ops; | ||
| 663 | 633 | ||
| 664 | /* | 634 | rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i); |
| 665 | * SSI DMA case | ||
| 666 | */ | ||
| 667 | if (pinfo->dma_id > 0) { | ||
| 668 | ret = rsnd_dma_init( | ||
| 669 | priv, rsnd_mod_to_dma(&ssi->mod), | ||
| 670 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), | ||
| 671 | pinfo->dma_id, | ||
| 672 | rsnd_ssi_dma_inquiry, | ||
| 673 | rsnd_ssi_dma_complete); | ||
| 674 | if (ret < 0) | ||
| 675 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); | ||
| 676 | else | ||
| 677 | ops = &rsnd_ssi_dma_ops; | ||
| 678 | |||
| 679 | dev_dbg(dev, "SSI%d use DMA transfer\n", i); | ||
| 680 | } | ||
| 681 | |||
| 682 | /* | ||
| 683 | * SSI PIO case | ||
| 684 | */ | ||
| 685 | if (!rsnd_ssi_dma_available(ssi) && | ||
| 686 | rsnd_ssi_pio_available(ssi)) { | ||
| 687 | ret = devm_request_irq(dev, pinfo->pio_irq, | ||
| 688 | &rsnd_ssi_pio_interrupt, | ||
| 689 | IRQF_SHARED, | ||
| 690 | dev_name(dev), ssi); | ||
| 691 | if (ret) { | ||
| 692 | dev_err(dev, "SSI request interrupt failed\n"); | ||
| 693 | return ret; | ||
| 694 | } | ||
| 695 | |||
| 696 | ops = &rsnd_ssi_pio_ops; | ||
| 697 | 635 | ||
| 698 | dev_dbg(dev, "SSI%d use PIO transfer\n", i); | 636 | rsnd_ssi_parent_clk_setup(priv, ssi); |
| 699 | } | ||
| 700 | |||
| 701 | rsnd_mod_init(priv, &ssi->mod, ops, i); | ||
| 702 | } | 637 | } |
| 703 | 638 | ||
| 704 | dev_dbg(dev, "ssi probed\n"); | ||
| 705 | |||
| 706 | return 0; | 639 | return 0; |
| 707 | } | 640 | } |
| 708 | |||
| 709 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
| 710 | struct rsnd_priv *priv) | ||
| 711 | { | ||
| 712 | struct rsnd_ssi *ssi; | ||
| 713 | int i; | ||
| 714 | |||
| 715 | for_each_rsnd_ssi(ssi, priv, i) { | ||
| 716 | if (rsnd_ssi_dma_available(ssi)) | ||
| 717 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | ||
| 718 | } | ||
| 719 | |||
| 720 | } | ||
diff --git a/sound/soc/sirf/Kconfig b/sound/soc/sirf/Kconfig new file mode 100644 index 000000000000..89e89429b04a --- /dev/null +++ b/sound/soc/sirf/Kconfig | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | config SND_SOC_SIRF | ||
| 2 | tristate "SoC Audio for the SiRF SoC chips" | ||
| 3 | depends on ARCH_SIRF || COMPILE_TEST | ||
| 4 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
| 5 | |||
| 6 | config SND_SOC_SIRF_AUDIO | ||
| 7 | tristate "SoC Audio support for SiRF internal audio codec" | ||
| 8 | depends on SND_SOC_SIRF | ||
| 9 | select SND_SOC_SIRF_AUDIO_CODEC | ||
| 10 | select SND_SOC_SIRF_AUDIO_PORT | ||
| 11 | |||
| 12 | config SND_SOC_SIRF_AUDIO_PORT | ||
| 13 | select REGMAP_MMIO | ||
| 14 | tristate | ||
diff --git a/sound/soc/sirf/Makefile b/sound/soc/sirf/Makefile new file mode 100644 index 000000000000..913b93231d4e --- /dev/null +++ b/sound/soc/sirf/Makefile | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | snd-soc-sirf-audio-objs := sirf-audio.o | ||
| 2 | snd-soc-sirf-audio-port-objs := sirf-audio-port.o | ||
| 3 | |||
| 4 | obj-$(CONFIG_SND_SOC_SIRF_AUDIO) += snd-soc-sirf-audio.o | ||
| 5 | obj-$(CONFIG_SND_SOC_SIRF_AUDIO_PORT) += snd-soc-sirf-audio-port.o | ||
diff --git a/sound/soc/sirf/sirf-audio-port.c b/sound/soc/sirf/sirf-audio-port.c new file mode 100644 index 000000000000..b04a53f2b4f6 --- /dev/null +++ b/sound/soc/sirf/sirf-audio-port.c | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * SiRF Audio port driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | #include <linux/module.h> | ||
| 9 | #include <linux/io.h> | ||
| 10 | #include <linux/regmap.h> | ||
| 11 | #include <sound/soc.h> | ||
| 12 | #include <sound/dmaengine_pcm.h> | ||
| 13 | |||
| 14 | #include "sirf-audio-port.h" | ||
| 15 | |||
| 16 | struct sirf_audio_port { | ||
| 17 | struct regmap *regmap; | ||
| 18 | struct snd_dmaengine_dai_dma_data playback_dma_data; | ||
| 19 | struct snd_dmaengine_dai_dma_data capture_dma_data; | ||
| 20 | }; | ||
| 21 | |||
| 22 | static void sirf_audio_port_tx_enable(struct sirf_audio_port *port) | ||
| 23 | { | ||
| 24 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, | ||
| 25 | AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); | ||
| 26 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_INT_MSK, 0); | ||
| 27 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); | ||
| 28 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, | ||
| 29 | AUDIO_FIFO_START, AUDIO_FIFO_START); | ||
| 30 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL, | ||
| 31 | IC_TX_ENABLE, IC_TX_ENABLE); | ||
| 32 | } | ||
| 33 | |||
| 34 | static void sirf_audio_port_tx_disable(struct sirf_audio_port *port) | ||
| 35 | { | ||
| 36 | regmap_write(port->regmap, AUDIO_PORT_IC_TXFIFO_OP, 0); | ||
| 37 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_TX_CTRL, | ||
| 38 | IC_TX_ENABLE, ~IC_TX_ENABLE); | ||
| 39 | } | ||
| 40 | |||
| 41 | static void sirf_audio_port_rx_enable(struct sirf_audio_port *port, | ||
| 42 | int channels) | ||
| 43 | { | ||
| 44 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, | ||
| 45 | AUDIO_FIFO_RESET, AUDIO_FIFO_RESET); | ||
| 46 | regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_INT_MSK, 0); | ||
| 47 | regmap_write(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, 0); | ||
| 48 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_RXFIFO_OP, | ||
| 49 | AUDIO_FIFO_START, AUDIO_FIFO_START); | ||
| 50 | if (channels == 1) | ||
| 51 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
| 52 | IC_RX_ENABLE_MONO, IC_RX_ENABLE_MONO); | ||
| 53 | else | ||
| 54 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
| 55 | IC_RX_ENABLE_STEREO, IC_RX_ENABLE_STEREO); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void sirf_audio_port_rx_disable(struct sirf_audio_port *port) | ||
| 59 | { | ||
| 60 | regmap_update_bits(port->regmap, AUDIO_PORT_IC_CODEC_RX_CTRL, | ||
| 61 | IC_RX_ENABLE_STEREO, ~IC_RX_ENABLE_STEREO); | ||
| 62 | } | ||
| 63 | |||
| 64 | static int sirf_audio_port_dai_probe(struct snd_soc_dai *dai) | ||
| 65 | { | ||
| 66 | struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai); | ||
| 67 | snd_soc_dai_init_dma_data(dai, &port->playback_dma_data, | ||
| 68 | &port->capture_dma_data); | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int sirf_audio_port_trigger(struct snd_pcm_substream *substream, int cmd, | ||
| 73 | struct snd_soc_dai *dai) | ||
| 74 | { | ||
| 75 | struct sirf_audio_port *port = snd_soc_dai_get_drvdata(dai); | ||
| 76 | int playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
| 77 | |||
| 78 | switch (cmd) { | ||
| 79 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 80 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 81 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 82 | if (playback) | ||
| 83 | sirf_audio_port_tx_disable(port); | ||
| 84 | else | ||
| 85 | sirf_audio_port_rx_disable(port); | ||
| 86 | break; | ||
| 87 | case SNDRV_PCM_TRIGGER_START: | ||
| 88 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 89 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 90 | if (playback) | ||
| 91 | sirf_audio_port_tx_enable(port); | ||
| 92 | else | ||
| 93 | sirf_audio_port_rx_enable(port, | ||
| 94 | substream->runtime->channels); | ||
| 95 | break; | ||
| 96 | default: | ||
| 97 | return -EINVAL; | ||
| 98 | } | ||
| 99 | |||
| 100 | return 0; | ||
| 101 | } | ||
| 102 | |||
| 103 | static const struct snd_soc_dai_ops sirf_audio_port_dai_ops = { | ||
| 104 | .trigger = sirf_audio_port_trigger, | ||
| 105 | }; | ||
| 106 | |||
| 107 | static struct snd_soc_dai_driver sirf_audio_port_dai = { | ||
| 108 | .probe = sirf_audio_port_dai_probe, | ||
| 109 | .name = "sirf-audio-port", | ||
| 110 | .id = 0, | ||
| 111 | .playback = { | ||
| 112 | .channels_min = 2, | ||
| 113 | .channels_max = 2, | ||
| 114 | .rates = SNDRV_PCM_RATE_48000, | ||
| 115 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 116 | }, | ||
| 117 | .capture = { | ||
| 118 | .channels_min = 1, | ||
| 119 | .channels_max = 2, | ||
| 120 | .rates = SNDRV_PCM_RATE_48000, | ||
| 121 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 122 | }, | ||
| 123 | .ops = &sirf_audio_port_dai_ops, | ||
| 124 | }; | ||
| 125 | |||
| 126 | static const struct snd_soc_component_driver sirf_audio_port_component = { | ||
| 127 | .name = "sirf-audio-port", | ||
| 128 | }; | ||
| 129 | |||
| 130 | static const struct regmap_config sirf_audio_port_regmap_config = { | ||
| 131 | .reg_bits = 32, | ||
| 132 | .reg_stride = 4, | ||
| 133 | .val_bits = 32, | ||
| 134 | .max_register = AUDIO_PORT_IC_RXFIFO_INT_MSK, | ||
| 135 | .cache_type = REGCACHE_NONE, | ||
| 136 | }; | ||
| 137 | |||
| 138 | static int sirf_audio_port_probe(struct platform_device *pdev) | ||
| 139 | { | ||
| 140 | int ret; | ||
| 141 | struct sirf_audio_port *port; | ||
| 142 | void __iomem *base; | ||
| 143 | struct resource *mem_res; | ||
| 144 | |||
| 145 | port = devm_kzalloc(&pdev->dev, | ||
| 146 | sizeof(struct sirf_audio_port), GFP_KERNEL); | ||
| 147 | if (!port) | ||
| 148 | return -ENOMEM; | ||
| 149 | |||
| 150 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 151 | if (!mem_res) { | ||
| 152 | dev_err(&pdev->dev, "no mem resource?\n"); | ||
| 153 | return -ENODEV; | ||
| 154 | } | ||
| 155 | |||
| 156 | base = devm_ioremap(&pdev->dev, mem_res->start, | ||
| 157 | resource_size(mem_res)); | ||
| 158 | if (base == NULL) | ||
| 159 | return -ENOMEM; | ||
| 160 | |||
| 161 | port->regmap = devm_regmap_init_mmio(&pdev->dev, base, | ||
| 162 | &sirf_audio_port_regmap_config); | ||
| 163 | if (IS_ERR(port->regmap)) | ||
| 164 | return PTR_ERR(port->regmap); | ||
| 165 | |||
| 166 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
| 167 | &sirf_audio_port_component, &sirf_audio_port_dai, 1); | ||
| 168 | if (ret) | ||
| 169 | return ret; | ||
| 170 | |||
| 171 | platform_set_drvdata(pdev, port); | ||
| 172 | return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
| 173 | } | ||
| 174 | |||
| 175 | static const struct of_device_id sirf_audio_port_of_match[] = { | ||
| 176 | { .compatible = "sirf,audio-port", }, | ||
| 177 | {} | ||
| 178 | }; | ||
| 179 | MODULE_DEVICE_TABLE(of, sirf_audio_port_of_match); | ||
| 180 | |||
| 181 | static struct platform_driver sirf_audio_port_driver = { | ||
| 182 | .driver = { | ||
| 183 | .name = "sirf-audio-port", | ||
| 184 | .owner = THIS_MODULE, | ||
| 185 | .of_match_table = sirf_audio_port_of_match, | ||
| 186 | }, | ||
| 187 | .probe = sirf_audio_port_probe, | ||
| 188 | }; | ||
| 189 | |||
| 190 | module_platform_driver(sirf_audio_port_driver); | ||
| 191 | |||
| 192 | MODULE_DESCRIPTION("SiRF Audio Port driver"); | ||
| 193 | MODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); | ||
| 194 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/sirf/sirf-audio-port.h b/sound/soc/sirf/sirf-audio-port.h new file mode 100644 index 000000000000..f32dc54f4499 --- /dev/null +++ b/sound/soc/sirf/sirf-audio-port.h | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | /* | ||
| 2 | * SiRF Audio port controllers define | ||
| 3 | * | ||
| 4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef _SIRF_AUDIO_PORT_H | ||
| 10 | #define _SIRF_AUDIO_PORT_H | ||
| 11 | |||
| 12 | #define AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK 0x3F | ||
| 13 | #define AUDIO_PORT_TX_FIFO_SC_OFFSET 0 | ||
| 14 | #define AUDIO_PORT_TX_FIFO_LC_OFFSET 10 | ||
| 15 | #define AUDIO_PORT_TX_FIFO_HC_OFFSET 20 | ||
| 16 | |||
| 17 | #define TX_FIFO_SC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 18 | << AUDIO_PORT_TX_FIFO_SC_OFFSET) | ||
| 19 | #define TX_FIFO_LC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 20 | << AUDIO_PORT_TX_FIFO_LC_OFFSET) | ||
| 21 | #define TX_FIFO_HC(x) (((x) & AUDIO_PORT_TX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 22 | << AUDIO_PORT_TX_FIFO_HC_OFFSET) | ||
| 23 | |||
| 24 | #define AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK 0x0F | ||
| 25 | #define AUDIO_PORT_RX_FIFO_SC_OFFSET 0 | ||
| 26 | #define AUDIO_PORT_RX_FIFO_LC_OFFSET 10 | ||
| 27 | #define AUDIO_PORT_RX_FIFO_HC_OFFSET 20 | ||
| 28 | |||
| 29 | #define RX_FIFO_SC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 30 | << AUDIO_PORT_RX_FIFO_SC_OFFSET) | ||
| 31 | #define RX_FIFO_LC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 32 | << AUDIO_PORT_RX_FIFO_LC_OFFSET) | ||
| 33 | #define RX_FIFO_HC(x) (((x) & AUDIO_PORT_RX_FIFO_LEVEL_CHECK_MASK) \ | ||
| 34 | << AUDIO_PORT_RX_FIFO_HC_OFFSET) | ||
| 35 | #define AUDIO_PORT_IC_CODEC_TX_CTRL (0x00F4) | ||
| 36 | #define AUDIO_PORT_IC_CODEC_RX_CTRL (0x00F8) | ||
| 37 | |||
| 38 | #define AUDIO_PORT_IC_TXFIFO_OP (0x00FC) | ||
| 39 | #define AUDIO_PORT_IC_TXFIFO_LEV_CHK (0x0100) | ||
| 40 | #define AUDIO_PORT_IC_TXFIFO_STS (0x0104) | ||
| 41 | #define AUDIO_PORT_IC_TXFIFO_INT (0x0108) | ||
| 42 | #define AUDIO_PORT_IC_TXFIFO_INT_MSK (0x010C) | ||
| 43 | |||
| 44 | #define AUDIO_PORT_IC_RXFIFO_OP (0x0110) | ||
| 45 | #define AUDIO_PORT_IC_RXFIFO_LEV_CHK (0x0114) | ||
| 46 | #define AUDIO_PORT_IC_RXFIFO_STS (0x0118) | ||
| 47 | #define AUDIO_PORT_IC_RXFIFO_INT (0x011C) | ||
| 48 | #define AUDIO_PORT_IC_RXFIFO_INT_MSK (0x0120) | ||
| 49 | |||
| 50 | #define AUDIO_FIFO_START (1 << 0) | ||
| 51 | #define AUDIO_FIFO_RESET (1 << 1) | ||
| 52 | |||
| 53 | #define AUDIO_FIFO_FULL (1 << 0) | ||
| 54 | #define AUDIO_FIFO_EMPTY (1 << 1) | ||
| 55 | #define AUDIO_FIFO_OFLOW (1 << 2) | ||
| 56 | #define AUDIO_FIFO_UFLOW (1 << 3) | ||
| 57 | |||
| 58 | #define IC_TX_ENABLE (0x03) | ||
| 59 | #define IC_RX_ENABLE_MONO (0x01) | ||
| 60 | #define IC_RX_ENABLE_STEREO (0x03) | ||
| 61 | |||
| 62 | #endif /*__SIRF_AUDIO_PORT_H*/ | ||
diff --git a/sound/soc/sirf/sirf-audio.c b/sound/soc/sirf/sirf-audio.c new file mode 100644 index 000000000000..ecef51021653 --- /dev/null +++ b/sound/soc/sirf/sirf-audio.c | |||
| @@ -0,0 +1,156 @@ | |||
| 1 | /* | ||
| 2 | * SiRF audio card driver | ||
| 3 | * | ||
| 4 | * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/platform_device.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/of.h> | ||
| 12 | #include <linux/gpio.h> | ||
| 13 | #include <linux/of_gpio.h> | ||
| 14 | #include <sound/core.h> | ||
| 15 | #include <sound/pcm.h> | ||
| 16 | #include <sound/soc.h> | ||
| 17 | |||
| 18 | struct sirf_audio_card { | ||
| 19 | unsigned int gpio_hp_pa; | ||
| 20 | unsigned int gpio_spk_pa; | ||
| 21 | }; | ||
| 22 | |||
| 23 | static int sirf_audio_hp_event(struct snd_soc_dapm_widget *w, | ||
| 24 | struct snd_kcontrol *ctrl, int event) | ||
| 25 | { | ||
| 26 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
| 27 | struct snd_soc_card *card = dapm->card; | ||
| 28 | struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); | ||
| 29 | int on = !SND_SOC_DAPM_EVENT_OFF(event); | ||
| 30 | if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) | ||
| 31 | gpio_set_value(sirf_audio_card->gpio_hp_pa, on); | ||
| 32 | return 0; | ||
| 33 | } | ||
| 34 | |||
| 35 | static int sirf_audio_spk_event(struct snd_soc_dapm_widget *w, | ||
| 36 | struct snd_kcontrol *ctrl, int event) | ||
| 37 | { | ||
| 38 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
| 39 | struct snd_soc_card *card = dapm->card; | ||
| 40 | struct sirf_audio_card *sirf_audio_card = snd_soc_card_get_drvdata(card); | ||
| 41 | int on = !SND_SOC_DAPM_EVENT_OFF(event); | ||
| 42 | |||
| 43 | if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) | ||
| 44 | gpio_set_value(sirf_audio_card->gpio_spk_pa, on); | ||
| 45 | |||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | static const struct snd_soc_dapm_widget sirf_audio_dapm_widgets[] = { | ||
| 49 | SND_SOC_DAPM_HP("Hp", sirf_audio_hp_event), | ||
| 50 | SND_SOC_DAPM_SPK("Ext Spk", sirf_audio_spk_event), | ||
| 51 | SND_SOC_DAPM_MIC("Ext Mic", NULL), | ||
| 52 | }; | ||
| 53 | |||
| 54 | static const struct snd_soc_dapm_route intercon[] = { | ||
| 55 | {"Hp", NULL, "HPOUTL"}, | ||
| 56 | {"Hp", NULL, "HPOUTR"}, | ||
| 57 | {"Ext Spk", NULL, "SPKOUT"}, | ||
| 58 | {"MICIN1", NULL, "Mic Bias"}, | ||
| 59 | {"Mic Bias", NULL, "Ext Mic"}, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
| 63 | static struct snd_soc_dai_link sirf_audio_dai_link[] = { | ||
| 64 | { | ||
| 65 | .name = "SiRF audio card", | ||
| 66 | .stream_name = "SiRF audio HiFi", | ||
| 67 | .codec_dai_name = "sirf-audio-codec", | ||
| 68 | }, | ||
| 69 | }; | ||
| 70 | |||
| 71 | /* Audio machine driver */ | ||
| 72 | static struct snd_soc_card snd_soc_sirf_audio_card = { | ||
| 73 | .name = "SiRF audio card", | ||
| 74 | .owner = THIS_MODULE, | ||
| 75 | .dai_link = sirf_audio_dai_link, | ||
| 76 | .num_links = ARRAY_SIZE(sirf_audio_dai_link), | ||
| 77 | .dapm_widgets = sirf_audio_dapm_widgets, | ||
| 78 | .num_dapm_widgets = ARRAY_SIZE(sirf_audio_dapm_widgets), | ||
| 79 | .dapm_routes = intercon, | ||
| 80 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
| 81 | }; | ||
| 82 | |||
| 83 | static int sirf_audio_probe(struct platform_device *pdev) | ||
| 84 | { | ||
| 85 | struct snd_soc_card *card = &snd_soc_sirf_audio_card; | ||
| 86 | struct sirf_audio_card *sirf_audio_card; | ||
| 87 | int ret; | ||
| 88 | |||
| 89 | sirf_audio_card = devm_kzalloc(&pdev->dev, sizeof(struct sirf_audio_card), | ||
| 90 | GFP_KERNEL); | ||
| 91 | if (sirf_audio_card == NULL) | ||
| 92 | return -ENOMEM; | ||
| 93 | |||
| 94 | sirf_audio_dai_link[0].cpu_of_node = | ||
| 95 | of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); | ||
| 96 | sirf_audio_dai_link[0].platform_of_node = | ||
| 97 | of_parse_phandle(pdev->dev.of_node, "sirf,audio-platform", 0); | ||
| 98 | sirf_audio_dai_link[0].codec_of_node = | ||
| 99 | of_parse_phandle(pdev->dev.of_node, "sirf,audio-codec", 0); | ||
| 100 | sirf_audio_card->gpio_spk_pa = of_get_named_gpio(pdev->dev.of_node, | ||
| 101 | "spk-pa-gpios", 0); | ||
| 102 | sirf_audio_card->gpio_hp_pa = of_get_named_gpio(pdev->dev.of_node, | ||
| 103 | "hp-pa-gpios", 0); | ||
| 104 | if (gpio_is_valid(sirf_audio_card->gpio_spk_pa)) { | ||
| 105 | ret = devm_gpio_request_one(&pdev->dev, | ||
| 106 | sirf_audio_card->gpio_spk_pa, | ||
| 107 | GPIOF_OUT_INIT_LOW, "SPA_PA_SD"); | ||
| 108 | if (ret) { | ||
| 109 | dev_err(&pdev->dev, | ||
| 110 | "Failed to request GPIO_%d for reset: %d\n", | ||
| 111 | sirf_audio_card->gpio_spk_pa, ret); | ||
| 112 | return ret; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | if (gpio_is_valid(sirf_audio_card->gpio_hp_pa)) { | ||
| 116 | ret = devm_gpio_request_one(&pdev->dev, | ||
| 117 | sirf_audio_card->gpio_hp_pa, | ||
| 118 | GPIOF_OUT_INIT_LOW, "HP_PA_SD"); | ||
| 119 | if (ret) { | ||
| 120 | dev_err(&pdev->dev, | ||
| 121 | "Failed to request GPIO_%d for reset: %d\n", | ||
| 122 | sirf_audio_card->gpio_hp_pa, ret); | ||
| 123 | return ret; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | card->dev = &pdev->dev; | ||
| 128 | snd_soc_card_set_drvdata(card, sirf_audio_card); | ||
| 129 | |||
| 130 | ret = devm_snd_soc_register_card(&pdev->dev, card); | ||
| 131 | if (ret) | ||
| 132 | dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); | ||
| 133 | |||
| 134 | return ret; | ||
| 135 | } | ||
| 136 | |||
| 137 | static const struct of_device_id sirf_audio_of_match[] = { | ||
| 138 | {.compatible = "sirf,sirf-audio-card", }, | ||
| 139 | { }, | ||
| 140 | }; | ||
| 141 | MODULE_DEVICE_TABLE(of, sirf_audio_of_match); | ||
| 142 | |||
| 143 | static struct platform_driver sirf_audio_driver = { | ||
| 144 | .driver = { | ||
| 145 | .name = "sirf-audio-card", | ||
| 146 | .owner = THIS_MODULE, | ||
| 147 | .pm = &snd_soc_pm_ops, | ||
| 148 | .of_match_table = sirf_audio_of_match, | ||
| 149 | }, | ||
| 150 | .probe = sirf_audio_probe, | ||
| 151 | }; | ||
| 152 | module_platform_driver(sirf_audio_driver); | ||
| 153 | |||
| 154 | MODULE_AUTHOR("RongJun Ying <RongJun.Ying@csr.com>"); | ||
| 155 | MODULE_DESCRIPTION("ALSA SoC SIRF audio card driver"); | ||
| 156 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 375dc6dfba4e..bfed3e4c45ff 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
| @@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
| 96 | { | 96 | { |
| 97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", | 97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", |
| 98 | codec->name); | 98 | codec->name); |
| 99 | if (!codec->reg_cache) | 99 | |
| 100 | return 0; | ||
| 101 | kfree(codec->reg_cache); | 100 | kfree(codec->reg_cache); |
| 102 | codec->reg_cache = NULL; | 101 | codec->reg_cache = NULL; |
| 103 | return 0; | 102 | return 0; |
| @@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec, | |||
| 117 | return -EINVAL; | 116 | return -EINVAL; |
| 118 | 117 | ||
| 119 | mutex_lock(&codec->cache_rw_mutex); | 118 | mutex_lock(&codec->cache_rw_mutex); |
| 120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | 119 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
| 121 | codec->driver->reg_word_size); | 120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
| 121 | codec->driver->reg_word_size); | ||
| 122 | mutex_unlock(&codec->cache_rw_mutex); | 122 | mutex_unlock(&codec->cache_rw_mutex); |
| 123 | 123 | ||
| 124 | return 0; | 124 | return 0; |
| @@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, | |||
| 136 | unsigned int reg, unsigned int value) | 136 | unsigned int reg, unsigned int value) |
| 137 | { | 137 | { |
| 138 | mutex_lock(&codec->cache_rw_mutex); | 138 | mutex_lock(&codec->cache_rw_mutex); |
| 139 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | 139 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
| 140 | codec->driver->reg_word_size); | 140 | snd_soc_set_cache_val(codec->reg_cache, reg, value, |
| 141 | codec->driver->reg_word_size); | ||
| 141 | mutex_unlock(&codec->cache_rw_mutex); | 142 | mutex_unlock(&codec->cache_rw_mutex); |
| 142 | 143 | ||
| 143 | return 0; | 144 | return 0; |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 5e9690c85d8f..91083e6a6b38 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
| @@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
| 30 | { | 30 | { |
| 31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
| 32 | struct snd_soc_platform *platform = rtd->platform; | 32 | struct snd_soc_platform *platform = rtd->platform; |
| 33 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 35 | int ret = 0; | 33 | int ret = 0; |
| 36 | 34 | ||
| 37 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 35 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| @@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
| 52 | } | 50 | } |
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 53 | snd_soc_runtime_activate(rtd, cstream->direction); |
| 56 | cpu_dai->playback_active++; | ||
| 57 | codec_dai->playback_active++; | ||
| 58 | } else { | ||
| 59 | cpu_dai->capture_active++; | ||
| 60 | codec_dai->capture_active++; | ||
| 61 | } | ||
| 62 | |||
| 63 | cpu_dai->active++; | ||
| 64 | codec_dai->active++; | ||
| 65 | rtd->codec->active++; | ||
| 66 | 54 | ||
| 67 | mutex_unlock(&rtd->pcm_mutex); | 55 | mutex_unlock(&rtd->pcm_mutex); |
| 68 | 56 | ||
| @@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
| 81 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 69 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
| 82 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; | 70 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; |
| 83 | struct snd_soc_platform *platform = fe->platform; | 71 | struct snd_soc_platform *platform = fe->platform; |
| 84 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
| 85 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
| 86 | struct snd_soc_dpcm *dpcm; | 72 | struct snd_soc_dpcm *dpcm; |
| 87 | struct snd_soc_dapm_widget_list *list; | 73 | struct snd_soc_dapm_widget_list *list; |
| 88 | int stream; | 74 | int stream; |
| @@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
| 140 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | 126 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; |
| 141 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 127 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
| 142 | 128 | ||
| 143 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 129 | snd_soc_runtime_activate(fe, stream); |
| 144 | cpu_dai->playback_active++; | ||
| 145 | codec_dai->playback_active++; | ||
| 146 | } else { | ||
| 147 | cpu_dai->capture_active++; | ||
| 148 | codec_dai->capture_active++; | ||
| 149 | } | ||
| 150 | |||
| 151 | cpu_dai->active++; | ||
| 152 | codec_dai->active++; | ||
| 153 | fe->codec->active++; | ||
| 154 | 130 | ||
| 155 | mutex_unlock(&fe->card->mutex); | 131 | mutex_unlock(&fe->card->mutex); |
| 156 | 132 | ||
| @@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
| 202 | struct snd_soc_platform *platform = rtd->platform; | 178 | struct snd_soc_platform *platform = rtd->platform; |
| 203 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 179 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 204 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 180 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 205 | struct snd_soc_codec *codec = rtd->codec; | 181 | int stream; |
| 206 | 182 | ||
| 207 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 183 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| 208 | 184 | ||
| 209 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 185 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
| 210 | cpu_dai->playback_active--; | 186 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
| 211 | codec_dai->playback_active--; | 187 | else |
| 212 | } else { | 188 | stream = SNDRV_PCM_STREAM_CAPTURE; |
| 213 | cpu_dai->capture_active--; | ||
| 214 | codec_dai->capture_active--; | ||
| 215 | } | ||
| 216 | 189 | ||
| 217 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); | 190 | snd_soc_runtime_deactivate(rtd, stream); |
| 218 | 191 | ||
| 219 | cpu_dai->active--; | 192 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); |
| 220 | codec_dai->active--; | ||
| 221 | codec->active--; | ||
| 222 | 193 | ||
| 223 | if (!cpu_dai->active) | 194 | if (!cpu_dai->active) |
| 224 | cpu_dai->rate = 0; | 195 | cpu_dai->rate = 0; |
| @@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
| 235 | cpu_dai->runtime = NULL; | 206 | cpu_dai->runtime = NULL; |
| 236 | 207 | ||
| 237 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 208 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
| 238 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 209 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
| 239 | rtd->dai_link->ignore_pmdown_time) { | ||
| 240 | snd_soc_dapm_stream_event(rtd, | 210 | snd_soc_dapm_stream_event(rtd, |
| 241 | SNDRV_PCM_STREAM_PLAYBACK, | 211 | SNDRV_PCM_STREAM_PLAYBACK, |
| 242 | SND_SOC_DAPM_STREAM_STOP); | 212 | SND_SOC_DAPM_STREAM_STOP); |
| @@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) | |||
| 261 | { | 231 | { |
| 262 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 232 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
| 263 | struct snd_soc_platform *platform = fe->platform; | 233 | struct snd_soc_platform *platform = fe->platform; |
| 264 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
| 265 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
| 266 | struct snd_soc_dpcm *dpcm; | 234 | struct snd_soc_dpcm *dpcm; |
| 267 | int stream, ret; | 235 | int stream, ret; |
| 268 | 236 | ||
| 269 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 237 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
| 270 | 238 | ||
| 271 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 239 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
| 272 | stream = SNDRV_PCM_STREAM_PLAYBACK; | 240 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
| 273 | cpu_dai->playback_active--; | 241 | else |
| 274 | codec_dai->playback_active--; | ||
| 275 | } else { | ||
| 276 | stream = SNDRV_PCM_STREAM_CAPTURE; | 242 | stream = SNDRV_PCM_STREAM_CAPTURE; |
| 277 | cpu_dai->capture_active--; | ||
| 278 | codec_dai->capture_active--; | ||
| 279 | } | ||
| 280 | 243 | ||
| 281 | cpu_dai->active--; | 244 | snd_soc_runtime_deactivate(fe, stream); |
| 282 | codec_dai->active--; | ||
| 283 | fe->codec->active--; | ||
| 284 | 245 | ||
| 285 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 246 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
| 286 | 247 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe1df50805a3..359c2849b364 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
| @@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | |||
| 56 | #endif | 56 | #endif |
| 57 | 57 | ||
| 58 | static DEFINE_MUTEX(client_mutex); | 58 | static DEFINE_MUTEX(client_mutex); |
| 59 | static LIST_HEAD(dai_list); | ||
| 60 | static LIST_HEAD(platform_list); | 59 | static LIST_HEAD(platform_list); |
| 61 | static LIST_HEAD(codec_list); | 60 | static LIST_HEAD(codec_list); |
| 62 | static LIST_HEAD(component_list); | 61 | static LIST_HEAD(component_list); |
| @@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, | |||
| 370 | { | 369 | { |
| 371 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 370 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
| 372 | ssize_t len, ret = 0; | 371 | ssize_t len, ret = 0; |
| 372 | struct snd_soc_component *component; | ||
| 373 | struct snd_soc_dai *dai; | 373 | struct snd_soc_dai *dai; |
| 374 | 374 | ||
| 375 | if (!buf) | 375 | if (!buf) |
| 376 | return -ENOMEM; | 376 | return -ENOMEM; |
| 377 | 377 | ||
| 378 | list_for_each_entry(dai, &dai_list, list) { | 378 | list_for_each_entry(component, &component_list, list) { |
| 379 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); | 379 | list_for_each_entry(dai, &component->dai_list, list) { |
| 380 | if (len >= 0) | 380 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
| 381 | ret += len; | 381 | dai->name); |
| 382 | if (ret > PAGE_SIZE) { | 382 | if (len >= 0) |
| 383 | ret = PAGE_SIZE; | 383 | ret += len; |
| 384 | break; | 384 | if (ret > PAGE_SIZE) { |
| 385 | ret = PAGE_SIZE; | ||
| 386 | break; | ||
| 387 | } | ||
| 385 | } | 388 | } |
| 386 | } | 389 | } |
| 387 | 390 | ||
| @@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 855 | { | 858 | { |
| 856 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 859 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
| 857 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 860 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
| 861 | struct snd_soc_component *component; | ||
| 858 | struct snd_soc_codec *codec; | 862 | struct snd_soc_codec *codec; |
| 859 | struct snd_soc_platform *platform; | 863 | struct snd_soc_platform *platform; |
| 860 | struct snd_soc_dai *codec_dai, *cpu_dai; | 864 | struct snd_soc_dai *codec_dai, *cpu_dai; |
| @@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 863 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); | 867 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); |
| 864 | 868 | ||
| 865 | /* Find CPU DAI from registered DAIs*/ | 869 | /* Find CPU DAI from registered DAIs*/ |
| 866 | list_for_each_entry(cpu_dai, &dai_list, list) { | 870 | list_for_each_entry(component, &component_list, list) { |
| 867 | if (dai_link->cpu_of_node && | 871 | if (dai_link->cpu_of_node && |
| 868 | (cpu_dai->dev->of_node != dai_link->cpu_of_node)) | 872 | component->dev->of_node != dai_link->cpu_of_node) |
| 869 | continue; | 873 | continue; |
| 870 | if (dai_link->cpu_name && | 874 | if (dai_link->cpu_name && |
| 871 | strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) | 875 | strcmp(dev_name(component->dev), dai_link->cpu_name)) |
| 872 | continue; | ||
| 873 | if (dai_link->cpu_dai_name && | ||
| 874 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
| 875 | continue; | 876 | continue; |
| 877 | list_for_each_entry(cpu_dai, &component->dai_list, list) { | ||
| 878 | if (dai_link->cpu_dai_name && | ||
| 879 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
| 880 | continue; | ||
| 876 | 881 | ||
| 877 | rtd->cpu_dai = cpu_dai; | 882 | rtd->cpu_dai = cpu_dai; |
| 883 | } | ||
| 878 | } | 884 | } |
| 879 | 885 | ||
| 880 | if (!rtd->cpu_dai) { | 886 | if (!rtd->cpu_dai) { |
| @@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 899 | * CODEC found, so find CODEC DAI from registered DAIs from | 905 | * CODEC found, so find CODEC DAI from registered DAIs from |
| 900 | * this CODEC | 906 | * this CODEC |
| 901 | */ | 907 | */ |
| 902 | list_for_each_entry(codec_dai, &dai_list, list) { | 908 | list_for_each_entry(codec_dai, &codec->component.dai_list, list) { |
| 903 | if (codec->dev == codec_dai->dev && | 909 | if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) { |
| 904 | !strcmp(codec_dai->name, | ||
| 905 | dai_link->codec_dai_name)) { | ||
| 906 | |||
| 907 | rtd->codec_dai = codec_dai; | 910 | rtd->codec_dai = codec_dai; |
| 911 | break; | ||
| 908 | } | 912 | } |
| 909 | } | 913 | } |
| 910 | 914 | ||
| @@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
| 1128 | driver->num_dapm_widgets); | 1132 | driver->num_dapm_widgets); |
| 1129 | 1133 | ||
| 1130 | /* Create DAPM widgets for each DAI stream */ | 1134 | /* Create DAPM widgets for each DAI stream */ |
| 1131 | list_for_each_entry(dai, &dai_list, list) { | 1135 | list_for_each_entry(dai, &codec->component.dai_list, list) |
| 1132 | if (dai->dev != codec->dev) | ||
| 1133 | continue; | ||
| 1134 | |||
| 1135 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); | 1136 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); |
| 1136 | } | ||
| 1137 | 1137 | ||
| 1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; | 1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; |
| 1139 | 1139 | ||
| @@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
| 1180 | { | 1180 | { |
| 1181 | int ret = 0; | 1181 | int ret = 0; |
| 1182 | const struct snd_soc_platform_driver *driver = platform->driver; | 1182 | const struct snd_soc_platform_driver *driver = platform->driver; |
| 1183 | struct snd_soc_component *component; | ||
| 1183 | struct snd_soc_dai *dai; | 1184 | struct snd_soc_dai *dai; |
| 1184 | 1185 | ||
| 1185 | platform->card = card; | 1186 | platform->card = card; |
| @@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
| 1195 | driver->dapm_widgets, driver->num_dapm_widgets); | 1196 | driver->dapm_widgets, driver->num_dapm_widgets); |
| 1196 | 1197 | ||
| 1197 | /* Create DAPM widgets for each DAI stream */ | 1198 | /* Create DAPM widgets for each DAI stream */ |
| 1198 | list_for_each_entry(dai, &dai_list, list) { | 1199 | list_for_each_entry(component, &component_list, list) { |
| 1199 | if (dai->dev != platform->dev) | 1200 | if (component->dev != platform->dev) |
| 1200 | continue; | 1201 | continue; |
| 1201 | 1202 | list_for_each_entry(dai, &component->dai_list, list) | |
| 1202 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); | 1203 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); |
| 1203 | } | 1204 | } |
| 1204 | 1205 | ||
| 1205 | platform->dapm.idle_bias_off = 1; | 1206 | platform->dapm.idle_bias_off = 1; |
| @@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | |||
| 2571 | 2572 | ||
| 2572 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2573 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
| 2573 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | 2574 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; |
| 2574 | uinfo->value.enumerated.items = e->max; | 2575 | uinfo->value.enumerated.items = e->items; |
| 2575 | 2576 | ||
| 2576 | if (uinfo->value.enumerated.item > e->max - 1) | 2577 | if (uinfo->value.enumerated.item >= e->items) |
| 2577 | uinfo->value.enumerated.item = e->max - 1; | 2578 | uinfo->value.enumerated.item = e->items - 1; |
| 2578 | strlcpy(uinfo->value.enumerated.name, | 2579 | strlcpy(uinfo->value.enumerated.name, |
| 2579 | e->texts[uinfo->value.enumerated.item], | 2580 | e->texts[uinfo->value.enumerated.item], |
| 2580 | sizeof(uinfo->value.enumerated.name)); | 2581 | sizeof(uinfo->value.enumerated.name)); |
| @@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
| 2596 | { | 2597 | { |
| 2597 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2598 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 2598 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2599 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 2599 | unsigned int val; | 2600 | unsigned int val, item; |
| 2601 | unsigned int reg_val; | ||
| 2600 | 2602 | ||
| 2601 | val = snd_soc_read(codec, e->reg); | 2603 | reg_val = snd_soc_read(codec, e->reg); |
| 2602 | ucontrol->value.enumerated.item[0] | 2604 | val = (reg_val >> e->shift_l) & e->mask; |
| 2603 | = (val >> e->shift_l) & e->mask; | 2605 | item = snd_soc_enum_val_to_item(e, val); |
| 2604 | if (e->shift_l != e->shift_r) | 2606 | ucontrol->value.enumerated.item[0] = item; |
| 2605 | ucontrol->value.enumerated.item[1] = | 2607 | if (e->shift_l != e->shift_r) { |
| 2606 | (val >> e->shift_r) & e->mask; | 2608 | val = (reg_val >> e->shift_l) & e->mask; |
| 2609 | item = snd_soc_enum_val_to_item(e, val); | ||
| 2610 | ucontrol->value.enumerated.item[1] = item; | ||
| 2611 | } | ||
| 2607 | 2612 | ||
| 2608 | return 0; | 2613 | return 0; |
| 2609 | } | 2614 | } |
| @@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
| 2623 | { | 2628 | { |
| 2624 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2629 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 2625 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2630 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 2631 | unsigned int *item = ucontrol->value.enumerated.item; | ||
| 2626 | unsigned int val; | 2632 | unsigned int val; |
| 2627 | unsigned int mask; | 2633 | unsigned int mask; |
| 2628 | 2634 | ||
| 2629 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2635 | if (item[0] >= e->items) |
| 2630 | return -EINVAL; | 2636 | return -EINVAL; |
| 2631 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 2637 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
| 2632 | mask = e->mask << e->shift_l; | 2638 | mask = e->mask << e->shift_l; |
| 2633 | if (e->shift_l != e->shift_r) { | 2639 | if (e->shift_l != e->shift_r) { |
| 2634 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2640 | if (item[1] >= e->items) |
| 2635 | return -EINVAL; | 2641 | return -EINVAL; |
| 2636 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 2642 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; |
| 2637 | mask |= e->mask << e->shift_r; | 2643 | mask |= e->mask << e->shift_r; |
| 2638 | } | 2644 | } |
| 2639 | 2645 | ||
| @@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
| 2642 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | 2648 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); |
| 2643 | 2649 | ||
| 2644 | /** | 2650 | /** |
| 2645 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback | 2651 | * snd_soc_read_signed - Read a codec register and interprete as signed value |
| 2646 | * @kcontrol: mixer control | 2652 | * @codec: codec |
| 2647 | * @ucontrol: control element information | 2653 | * @reg: Register to read |
| 2648 | * | 2654 | * @mask: Mask to use after shifting the register value |
| 2649 | * Callback to get the value of a double semi enumerated mixer. | 2655 | * @shift: Right shift of register value |
| 2656 | * @sign_bit: Bit that describes if a number is negative or not. | ||
| 2650 | * | 2657 | * |
| 2651 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | 2658 | * This functions reads a codec register. The register value is shifted right |
| 2652 | * used for handling bitfield coded enumeration for example. | 2659 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates |
| 2660 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
| 2653 | * | 2661 | * |
| 2654 | * Returns 0 for success. | 2662 | * Returns the register value as signed int. |
| 2655 | */ | 2663 | */ |
| 2656 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | 2664 | static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, |
| 2657 | struct snd_ctl_elem_value *ucontrol) | 2665 | unsigned int mask, unsigned int shift, unsigned int sign_bit) |
| 2658 | { | 2666 | { |
| 2659 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2667 | int ret; |
| 2660 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2668 | unsigned int val; |
| 2661 | unsigned int reg_val, val, mux; | ||
| 2662 | 2669 | ||
| 2663 | reg_val = snd_soc_read(codec, e->reg); | 2670 | val = (snd_soc_read(codec, reg) >> shift) & mask; |
| 2664 | val = (reg_val >> e->shift_l) & e->mask; | ||
| 2665 | for (mux = 0; mux < e->max; mux++) { | ||
| 2666 | if (val == e->values[mux]) | ||
| 2667 | break; | ||
| 2668 | } | ||
| 2669 | ucontrol->value.enumerated.item[0] = mux; | ||
| 2670 | if (e->shift_l != e->shift_r) { | ||
| 2671 | val = (reg_val >> e->shift_r) & e->mask; | ||
| 2672 | for (mux = 0; mux < e->max; mux++) { | ||
| 2673 | if (val == e->values[mux]) | ||
| 2674 | break; | ||
| 2675 | } | ||
| 2676 | ucontrol->value.enumerated.item[1] = mux; | ||
| 2677 | } | ||
| 2678 | 2671 | ||
| 2679 | return 0; | 2672 | if (!sign_bit) |
| 2680 | } | 2673 | return val; |
| 2681 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); | ||
| 2682 | 2674 | ||
| 2683 | /** | 2675 | /* non-negative number */ |
| 2684 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback | 2676 | if (!(val & BIT(sign_bit))) |
| 2685 | * @kcontrol: mixer control | 2677 | return val; |
| 2686 | * @ucontrol: control element information | ||
| 2687 | * | ||
| 2688 | * Callback to set the value of a double semi enumerated mixer. | ||
| 2689 | * | ||
| 2690 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
| 2691 | * used for handling bitfield coded enumeration for example. | ||
| 2692 | * | ||
| 2693 | * Returns 0 for success. | ||
| 2694 | */ | ||
| 2695 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 2696 | struct snd_ctl_elem_value *ucontrol) | ||
| 2697 | { | ||
| 2698 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 2699 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
| 2700 | unsigned int val; | ||
| 2701 | unsigned int mask; | ||
| 2702 | 2678 | ||
| 2703 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2679 | ret = val; |
| 2704 | return -EINVAL; | ||
| 2705 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
| 2706 | mask = e->mask << e->shift_l; | ||
| 2707 | if (e->shift_l != e->shift_r) { | ||
| 2708 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
| 2709 | return -EINVAL; | ||
| 2710 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
| 2711 | mask |= e->mask << e->shift_r; | ||
| 2712 | } | ||
| 2713 | 2680 | ||
| 2714 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); | 2681 | /* |
| 2682 | * The register most probably does not contain a full-sized int. | ||
| 2683 | * Instead we have an arbitrary number of bits in a signed | ||
| 2684 | * representation which has to be translated into a full-sized int. | ||
| 2685 | * This is done by filling up all bits above the sign-bit. | ||
| 2686 | */ | ||
| 2687 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
| 2688 | |||
| 2689 | return ret; | ||
| 2715 | } | 2690 | } |
| 2716 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | ||
| 2717 | 2691 | ||
| 2718 | /** | 2692 | /** |
| 2719 | * snd_soc_info_volsw - single mixer info callback | 2693 | * snd_soc_info_volsw - single mixer info callback |
| @@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | |||
| 2743 | 2717 | ||
| 2744 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | 2718 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; |
| 2745 | uinfo->value.integer.min = 0; | 2719 | uinfo->value.integer.min = 0; |
| 2746 | uinfo->value.integer.max = platform_max; | 2720 | uinfo->value.integer.max = platform_max - mc->min; |
| 2747 | return 0; | 2721 | return 0; |
| 2748 | } | 2722 | } |
| 2749 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2723 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
| @@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
| 2769 | unsigned int shift = mc->shift; | 2743 | unsigned int shift = mc->shift; |
| 2770 | unsigned int rshift = mc->rshift; | 2744 | unsigned int rshift = mc->rshift; |
| 2771 | int max = mc->max; | 2745 | int max = mc->max; |
| 2746 | int min = mc->min; | ||
| 2747 | int sign_bit = mc->sign_bit; | ||
| 2772 | unsigned int mask = (1 << fls(max)) - 1; | 2748 | unsigned int mask = (1 << fls(max)) - 1; |
| 2773 | unsigned int invert = mc->invert; | 2749 | unsigned int invert = mc->invert; |
| 2774 | 2750 | ||
| 2775 | ucontrol->value.integer.value[0] = | 2751 | if (sign_bit) |
| 2776 | (snd_soc_read(codec, reg) >> shift) & mask; | 2752 | mask = BIT(sign_bit + 1) - 1; |
| 2753 | |||
| 2754 | ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask, | ||
| 2755 | shift, sign_bit) - min; | ||
| 2777 | if (invert) | 2756 | if (invert) |
| 2778 | ucontrol->value.integer.value[0] = | 2757 | ucontrol->value.integer.value[0] = |
| 2779 | max - ucontrol->value.integer.value[0]; | 2758 | max - ucontrol->value.integer.value[0]; |
| @@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
| 2781 | if (snd_soc_volsw_is_stereo(mc)) { | 2760 | if (snd_soc_volsw_is_stereo(mc)) { |
| 2782 | if (reg == reg2) | 2761 | if (reg == reg2) |
| 2783 | ucontrol->value.integer.value[1] = | 2762 | ucontrol->value.integer.value[1] = |
| 2784 | (snd_soc_read(codec, reg) >> rshift) & mask; | 2763 | snd_soc_read_signed(codec, reg, mask, rshift, |
| 2764 | sign_bit) - min; | ||
| 2785 | else | 2765 | else |
| 2786 | ucontrol->value.integer.value[1] = | 2766 | ucontrol->value.integer.value[1] = |
| 2787 | (snd_soc_read(codec, reg2) >> shift) & mask; | 2767 | snd_soc_read_signed(codec, reg2, mask, shift, |
| 2768 | sign_bit) - min; | ||
| 2788 | if (invert) | 2769 | if (invert) |
| 2789 | ucontrol->value.integer.value[1] = | 2770 | ucontrol->value.integer.value[1] = |
| 2790 | max - ucontrol->value.integer.value[1]; | 2771 | max - ucontrol->value.integer.value[1]; |
| @@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
| 2815 | unsigned int shift = mc->shift; | 2796 | unsigned int shift = mc->shift; |
| 2816 | unsigned int rshift = mc->rshift; | 2797 | unsigned int rshift = mc->rshift; |
| 2817 | int max = mc->max; | 2798 | int max = mc->max; |
| 2799 | int min = mc->min; | ||
| 2800 | unsigned int sign_bit = mc->sign_bit; | ||
| 2818 | unsigned int mask = (1 << fls(max)) - 1; | 2801 | unsigned int mask = (1 << fls(max)) - 1; |
| 2819 | unsigned int invert = mc->invert; | 2802 | unsigned int invert = mc->invert; |
| 2820 | int err; | 2803 | int err; |
| 2821 | bool type_2r = 0; | 2804 | bool type_2r = false; |
| 2822 | unsigned int val2 = 0; | 2805 | unsigned int val2 = 0; |
| 2823 | unsigned int val, val_mask; | 2806 | unsigned int val, val_mask; |
| 2824 | 2807 | ||
| 2825 | val = (ucontrol->value.integer.value[0] & mask); | 2808 | if (sign_bit) |
| 2809 | mask = BIT(sign_bit + 1) - 1; | ||
| 2810 | |||
| 2811 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
| 2826 | if (invert) | 2812 | if (invert) |
| 2827 | val = max - val; | 2813 | val = max - val; |
| 2828 | val_mask = mask << shift; | 2814 | val_mask = mask << shift; |
| 2829 | val = val << shift; | 2815 | val = val << shift; |
| 2830 | if (snd_soc_volsw_is_stereo(mc)) { | 2816 | if (snd_soc_volsw_is_stereo(mc)) { |
| 2831 | val2 = (ucontrol->value.integer.value[1] & mask); | 2817 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); |
| 2832 | if (invert) | 2818 | if (invert) |
| 2833 | val2 = max - val2; | 2819 | val2 = max - val2; |
| 2834 | if (reg == reg2) { | 2820 | if (reg == reg2) { |
| @@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
| 2836 | val |= val2 << rshift; | 2822 | val |= val2 << rshift; |
| 2837 | } else { | 2823 | } else { |
| 2838 | val2 = val2 << shift; | 2824 | val2 = val2 << shift; |
| 2839 | type_2r = 1; | 2825 | type_2r = true; |
| 2840 | } | 2826 | } |
| 2841 | } | 2827 | } |
| 2842 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2828 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); |
| @@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
| 3234 | struct soc_bytes *params = (void *)kcontrol->private_value; | 3220 | struct soc_bytes *params = (void *)kcontrol->private_value; |
| 3235 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 3221 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 3236 | int ret, len; | 3222 | int ret, len; |
| 3237 | unsigned int val; | 3223 | unsigned int val, mask; |
| 3238 | void *data; | 3224 | void *data; |
| 3239 | 3225 | ||
| 3240 | if (!codec->using_regmap) | 3226 | if (!codec->using_regmap) |
| @@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
| 3264 | ((u8 *)data)[0] |= val; | 3250 | ((u8 *)data)[0] |= val; |
| 3265 | break; | 3251 | break; |
| 3266 | case 2: | 3252 | case 2: |
| 3267 | ((u16 *)data)[0] &= cpu_to_be16(~params->mask); | 3253 | mask = ~params->mask; |
| 3268 | ((u16 *)data)[0] |= cpu_to_be16(val); | 3254 | ret = regmap_parse_val(codec->control_data, |
| 3255 | &mask, &mask); | ||
| 3256 | if (ret != 0) | ||
| 3257 | goto out; | ||
| 3258 | |||
| 3259 | ((u16 *)data)[0] &= mask; | ||
| 3260 | |||
| 3261 | ret = regmap_parse_val(codec->control_data, | ||
| 3262 | &val, &val); | ||
| 3263 | if (ret != 0) | ||
| 3264 | goto out; | ||
| 3265 | |||
| 3266 | ((u16 *)data)[0] |= val; | ||
| 3269 | break; | 3267 | break; |
| 3270 | case 4: | 3268 | case 4: |
| 3271 | ((u32 *)data)[0] &= cpu_to_be32(~params->mask); | 3269 | mask = ~params->mask; |
| 3272 | ((u32 *)data)[0] |= cpu_to_be32(val); | 3270 | ret = regmap_parse_val(codec->control_data, |
| 3271 | &mask, &mask); | ||
| 3272 | if (ret != 0) | ||
| 3273 | goto out; | ||
| 3274 | |||
| 3275 | ((u32 *)data)[0] &= mask; | ||
| 3276 | |||
| 3277 | ret = regmap_parse_val(codec->control_data, | ||
| 3278 | &val, &val); | ||
| 3279 | if (ret != 0) | ||
| 3280 | goto out; | ||
| 3281 | |||
| 3282 | ((u32 *)data)[0] |= val; | ||
| 3273 | break; | 3283 | break; |
| 3274 | default: | 3284 | default: |
| 3275 | ret = -EINVAL; | 3285 | ret = -EINVAL; |
| @@ -3609,6 +3619,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
| 3609 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | 3619 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); |
| 3610 | 3620 | ||
| 3611 | /** | 3621 | /** |
| 3622 | * snd_soc_of_xlate_tdm_slot - generate tx/rx slot mask. | ||
| 3623 | * @slots: Number of slots in use. | ||
| 3624 | * @tx_mask: bitmask representing active TX slots. | ||
| 3625 | * @rx_mask: bitmask representing active RX slots. | ||
| 3626 | * | ||
| 3627 | * Generates the TDM tx and rx slot default masks for DAI. | ||
| 3628 | */ | ||
| 3629 | static int snd_soc_of_xlate_tdm_slot_mask(unsigned int slots, | ||
| 3630 | unsigned int *tx_mask, | ||
| 3631 | unsigned int *rx_mask) | ||
| 3632 | { | ||
| 3633 | if (*tx_mask || *rx_mask) | ||
| 3634 | return 0; | ||
| 3635 | |||
| 3636 | if (!slots) | ||
| 3637 | return -EINVAL; | ||
| 3638 | |||
| 3639 | *tx_mask = (1 << slots) - 1; | ||
| 3640 | *rx_mask = (1 << slots) - 1; | ||
| 3641 | |||
| 3642 | return 0; | ||
| 3643 | } | ||
| 3644 | |||
| 3645 | /** | ||
| 3612 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | 3646 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. |
| 3613 | * @dai: DAI | 3647 | * @dai: DAI |
| 3614 | * @tx_mask: bitmask representing active TX slots. | 3648 | * @tx_mask: bitmask representing active TX slots. |
| @@ -3622,11 +3656,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | |||
| 3622 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 3656 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
| 3623 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) | 3657 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) |
| 3624 | { | 3658 | { |
| 3659 | if (dai->driver && dai->driver->ops->of_xlate_tdm_slot_mask) | ||
| 3660 | dai->driver->ops->of_xlate_tdm_slot_mask(slots, | ||
| 3661 | &tx_mask, &rx_mask); | ||
| 3662 | else | ||
| 3663 | snd_soc_of_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); | ||
| 3664 | |||
| 3625 | if (dai->driver && dai->driver->ops->set_tdm_slot) | 3665 | if (dai->driver && dai->driver->ops->set_tdm_slot) |
| 3626 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, | 3666 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
| 3627 | slots, slot_width); | 3667 | slots, slot_width); |
| 3628 | else | 3668 | else |
| 3629 | return -EINVAL; | 3669 | return -ENOTSUPP; |
| 3630 | } | 3670 | } |
| 3631 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 3671 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
| 3632 | 3672 | ||
| @@ -3882,95 +3922,42 @@ static inline char *fmt_multiple_name(struct device *dev, | |||
| 3882 | } | 3922 | } |
| 3883 | 3923 | ||
| 3884 | /** | 3924 | /** |
| 3885 | * snd_soc_register_dai - Register a DAI with the ASoC core | 3925 | * snd_soc_unregister_dai - Unregister DAIs from the ASoC core |
| 3886 | * | 3926 | * |
| 3887 | * @dai: DAI to register | 3927 | * @component: The component for which the DAIs should be unregistered |
| 3888 | */ | 3928 | */ |
| 3889 | static int snd_soc_register_dai(struct device *dev, | 3929 | static void snd_soc_unregister_dais(struct snd_soc_component *component) |
| 3890 | struct snd_soc_dai_driver *dai_drv) | ||
| 3891 | { | 3930 | { |
| 3892 | struct snd_soc_codec *codec; | 3931 | struct snd_soc_dai *dai, *_dai; |
| 3893 | struct snd_soc_dai *dai; | ||
| 3894 | |||
| 3895 | dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); | ||
| 3896 | 3932 | ||
| 3897 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 3933 | list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { |
| 3898 | if (dai == NULL) | 3934 | dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", |
| 3899 | return -ENOMEM; | 3935 | dai->name); |
| 3900 | 3936 | list_del(&dai->list); | |
| 3901 | /* create DAI component name */ | 3937 | kfree(dai->name); |
| 3902 | dai->name = fmt_single_name(dev, &dai->id); | ||
| 3903 | if (dai->name == NULL) { | ||
| 3904 | kfree(dai); | 3938 | kfree(dai); |
| 3905 | return -ENOMEM; | ||
| 3906 | } | ||
| 3907 | |||
| 3908 | dai->dev = dev; | ||
| 3909 | dai->driver = dai_drv; | ||
| 3910 | dai->dapm.dev = dev; | ||
| 3911 | if (!dai->driver->ops) | ||
| 3912 | dai->driver->ops = &null_dai_ops; | ||
| 3913 | |||
| 3914 | mutex_lock(&client_mutex); | ||
| 3915 | |||
| 3916 | list_for_each_entry(codec, &codec_list, list) { | ||
| 3917 | if (codec->dev == dev) { | ||
| 3918 | dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", | ||
| 3919 | dai->name, codec->name); | ||
| 3920 | dai->codec = codec; | ||
| 3921 | break; | ||
| 3922 | } | ||
| 3923 | } | 3939 | } |
| 3924 | |||
| 3925 | if (!dai->codec) | ||
| 3926 | dai->dapm.idle_bias_off = 1; | ||
| 3927 | |||
| 3928 | list_add(&dai->list, &dai_list); | ||
| 3929 | |||
| 3930 | mutex_unlock(&client_mutex); | ||
| 3931 | |||
| 3932 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); | ||
| 3933 | |||
| 3934 | return 0; | ||
| 3935 | } | 3940 | } |
| 3936 | 3941 | ||
| 3937 | /** | 3942 | /** |
| 3938 | * snd_soc_unregister_dai - Unregister a DAI from the ASoC core | 3943 | * snd_soc_register_dais - Register a DAI with the ASoC core |
| 3939 | * | 3944 | * |
| 3940 | * @dai: DAI to unregister | 3945 | * @component: The component the DAIs are registered for |
| 3941 | */ | 3946 | * @codec: The CODEC that the DAIs are registered for, NULL if the component is |
| 3942 | static void snd_soc_unregister_dai(struct device *dev) | 3947 | * not a CODEC. |
| 3943 | { | 3948 | * @dai_drv: DAI driver to use for the DAIs |
| 3944 | struct snd_soc_dai *dai; | ||
| 3945 | |||
| 3946 | list_for_each_entry(dai, &dai_list, list) { | ||
| 3947 | if (dev == dai->dev) | ||
| 3948 | goto found; | ||
| 3949 | } | ||
| 3950 | return; | ||
| 3951 | |||
| 3952 | found: | ||
| 3953 | mutex_lock(&client_mutex); | ||
| 3954 | list_del(&dai->list); | ||
| 3955 | mutex_unlock(&client_mutex); | ||
| 3956 | |||
| 3957 | dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); | ||
| 3958 | kfree(dai->name); | ||
| 3959 | kfree(dai); | ||
| 3960 | } | ||
| 3961 | |||
| 3962 | /** | ||
| 3963 | * snd_soc_register_dais - Register multiple DAIs with the ASoC core | ||
| 3964 | * | ||
| 3965 | * @dai: Array of DAIs to register | ||
| 3966 | * @count: Number of DAIs | 3949 | * @count: Number of DAIs |
| 3950 | * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the | ||
| 3951 | * parent's name. | ||
| 3967 | */ | 3952 | */ |
| 3968 | static int snd_soc_register_dais(struct device *dev, | 3953 | static int snd_soc_register_dais(struct snd_soc_component *component, |
| 3969 | struct snd_soc_dai_driver *dai_drv, size_t count) | 3954 | struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, |
| 3955 | size_t count, bool legacy_dai_naming) | ||
| 3970 | { | 3956 | { |
| 3971 | struct snd_soc_codec *codec; | 3957 | struct device *dev = component->dev; |
| 3972 | struct snd_soc_dai *dai; | 3958 | struct snd_soc_dai *dai; |
| 3973 | int i, ret = 0; | 3959 | unsigned int i; |
| 3960 | int ret; | ||
| 3974 | 3961 | ||
| 3975 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); | 3962 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); |
| 3976 | 3963 | ||
| @@ -3982,70 +3969,54 @@ static int snd_soc_register_dais(struct device *dev, | |||
| 3982 | goto err; | 3969 | goto err; |
| 3983 | } | 3970 | } |
| 3984 | 3971 | ||
| 3985 | /* create DAI component name */ | 3972 | /* |
| 3986 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | 3973 | * Back in the old days when we still had component-less DAIs, |
| 3974 | * instead of having a static name, component-less DAIs would | ||
| 3975 | * inherit the name of the parent device so it is possible to | ||
| 3976 | * register multiple instances of the DAI. We still need to keep | ||
| 3977 | * the same naming style even though those DAIs are not | ||
| 3978 | * component-less anymore. | ||
| 3979 | */ | ||
| 3980 | if (count == 1 && legacy_dai_naming) { | ||
| 3981 | dai->name = fmt_single_name(dev, &dai->id); | ||
| 3982 | } else { | ||
| 3983 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | ||
| 3984 | if (dai_drv[i].id) | ||
| 3985 | dai->id = dai_drv[i].id; | ||
| 3986 | else | ||
| 3987 | dai->id = i; | ||
| 3988 | } | ||
| 3987 | if (dai->name == NULL) { | 3989 | if (dai->name == NULL) { |
| 3988 | kfree(dai); | 3990 | kfree(dai); |
| 3989 | ret = -EINVAL; | 3991 | ret = -ENOMEM; |
| 3990 | goto err; | 3992 | goto err; |
| 3991 | } | 3993 | } |
| 3992 | 3994 | ||
| 3995 | dai->component = component; | ||
| 3996 | dai->codec = codec; | ||
| 3993 | dai->dev = dev; | 3997 | dai->dev = dev; |
| 3994 | dai->driver = &dai_drv[i]; | 3998 | dai->driver = &dai_drv[i]; |
| 3995 | if (dai->driver->id) | ||
| 3996 | dai->id = dai->driver->id; | ||
| 3997 | else | ||
| 3998 | dai->id = i; | ||
| 3999 | dai->dapm.dev = dev; | 3999 | dai->dapm.dev = dev; |
| 4000 | if (!dai->driver->ops) | 4000 | if (!dai->driver->ops) |
| 4001 | dai->driver->ops = &null_dai_ops; | 4001 | dai->driver->ops = &null_dai_ops; |
| 4002 | 4002 | ||
| 4003 | mutex_lock(&client_mutex); | ||
| 4004 | |||
| 4005 | list_for_each_entry(codec, &codec_list, list) { | ||
| 4006 | if (codec->dev == dev) { | ||
| 4007 | dev_dbg(dev, | ||
| 4008 | "ASoC: Mapped DAI %s to CODEC %s\n", | ||
| 4009 | dai->name, codec->name); | ||
| 4010 | dai->codec = codec; | ||
| 4011 | break; | ||
| 4012 | } | ||
| 4013 | } | ||
| 4014 | |||
| 4015 | if (!dai->codec) | 4003 | if (!dai->codec) |
| 4016 | dai->dapm.idle_bias_off = 1; | 4004 | dai->dapm.idle_bias_off = 1; |
| 4017 | 4005 | ||
| 4018 | list_add(&dai->list, &dai_list); | 4006 | list_add(&dai->list, &component->dai_list); |
| 4019 | 4007 | ||
| 4020 | mutex_unlock(&client_mutex); | 4008 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); |
| 4021 | |||
| 4022 | dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); | ||
| 4023 | } | 4009 | } |
| 4024 | 4010 | ||
| 4025 | return 0; | 4011 | return 0; |
| 4026 | 4012 | ||
| 4027 | err: | 4013 | err: |
| 4028 | for (i--; i >= 0; i--) | 4014 | snd_soc_unregister_dais(component); |
| 4029 | snd_soc_unregister_dai(dev); | ||
| 4030 | 4015 | ||
| 4031 | return ret; | 4016 | return ret; |
| 4032 | } | 4017 | } |
| 4033 | 4018 | ||
| 4034 | /** | 4019 | /** |
| 4035 | * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core | ||
| 4036 | * | ||
| 4037 | * @dai: Array of DAIs to unregister | ||
| 4038 | * @count: Number of DAIs | ||
| 4039 | */ | ||
| 4040 | static void snd_soc_unregister_dais(struct device *dev, size_t count) | ||
| 4041 | { | ||
| 4042 | int i; | ||
| 4043 | |||
| 4044 | for (i = 0; i < count; i++) | ||
| 4045 | snd_soc_unregister_dai(dev); | ||
| 4046 | } | ||
| 4047 | |||
| 4048 | /** | ||
| 4049 | * snd_soc_register_component - Register a component with the ASoC core | 4020 | * snd_soc_register_component - Register a component with the ASoC core |
| 4050 | * | 4021 | * |
| 4051 | */ | 4022 | */ |
| @@ -4053,6 +4024,7 @@ static int | |||
| 4053 | __snd_soc_register_component(struct device *dev, | 4024 | __snd_soc_register_component(struct device *dev, |
| 4054 | struct snd_soc_component *cmpnt, | 4025 | struct snd_soc_component *cmpnt, |
| 4055 | const struct snd_soc_component_driver *cmpnt_drv, | 4026 | const struct snd_soc_component_driver *cmpnt_drv, |
| 4027 | struct snd_soc_codec *codec, | ||
| 4056 | struct snd_soc_dai_driver *dai_drv, | 4028 | struct snd_soc_dai_driver *dai_drv, |
| 4057 | int num_dai, bool allow_single_dai) | 4029 | int num_dai, bool allow_single_dai) |
| 4058 | { | 4030 | { |
| @@ -4075,20 +4047,10 @@ __snd_soc_register_component(struct device *dev, | |||
| 4075 | cmpnt->driver = cmpnt_drv; | 4047 | cmpnt->driver = cmpnt_drv; |
| 4076 | cmpnt->dai_drv = dai_drv; | 4048 | cmpnt->dai_drv = dai_drv; |
| 4077 | cmpnt->num_dai = num_dai; | 4049 | cmpnt->num_dai = num_dai; |
| 4050 | INIT_LIST_HEAD(&cmpnt->dai_list); | ||
| 4078 | 4051 | ||
| 4079 | /* | 4052 | ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, |
| 4080 | * snd_soc_register_dai() uses fmt_single_name(), and | 4053 | allow_single_dai); |
| 4081 | * snd_soc_register_dais() uses fmt_multiple_name() | ||
| 4082 | * for dai->name which is used for name based matching | ||
| 4083 | * | ||
| 4084 | * this function is used from cpu/codec. | ||
| 4085 | * allow_single_dai flag can ignore "codec" driver reworking | ||
| 4086 | * since it had been used snd_soc_register_dais(), | ||
| 4087 | */ | ||
| 4088 | if ((1 == num_dai) && allow_single_dai) | ||
| 4089 | ret = snd_soc_register_dai(dev, dai_drv); | ||
| 4090 | else | ||
| 4091 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | ||
| 4092 | if (ret < 0) { | 4054 | if (ret < 0) { |
| 4093 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | 4055 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); |
| 4094 | goto error_component_name; | 4056 | goto error_component_name; |
| @@ -4121,7 +4083,9 @@ int snd_soc_register_component(struct device *dev, | |||
| 4121 | return -ENOMEM; | 4083 | return -ENOMEM; |
| 4122 | } | 4084 | } |
| 4123 | 4085 | ||
| 4124 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, | 4086 | cmpnt->ignore_pmdown_time = true; |
| 4087 | |||
| 4088 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, | ||
| 4125 | dai_drv, num_dai, true); | 4089 | dai_drv, num_dai, true); |
| 4126 | } | 4090 | } |
| 4127 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | 4091 | EXPORT_SYMBOL_GPL(snd_soc_register_component); |
| @@ -4141,7 +4105,7 @@ void snd_soc_unregister_component(struct device *dev) | |||
| 4141 | return; | 4105 | return; |
| 4142 | 4106 | ||
| 4143 | found: | 4107 | found: |
| 4144 | snd_soc_unregister_dais(dev, cmpnt->num_dai); | 4108 | snd_soc_unregister_dais(cmpnt); |
| 4145 | 4109 | ||
| 4146 | mutex_lock(&client_mutex); | 4110 | mutex_lock(&client_mutex); |
| 4147 | list_del(&cmpnt->list); | 4111 | list_del(&cmpnt->list); |
| @@ -4319,7 +4283,7 @@ int snd_soc_register_codec(struct device *dev, | |||
| 4319 | codec->volatile_register = codec_drv->volatile_register; | 4283 | codec->volatile_register = codec_drv->volatile_register; |
| 4320 | codec->readable_register = codec_drv->readable_register; | 4284 | codec->readable_register = codec_drv->readable_register; |
| 4321 | codec->writable_register = codec_drv->writable_register; | 4285 | codec->writable_register = codec_drv->writable_register; |
| 4322 | codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; | 4286 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; |
| 4323 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 4287 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
| 4324 | codec->dapm.dev = dev; | 4288 | codec->dapm.dev = dev; |
| 4325 | codec->dapm.codec = codec; | 4289 | codec->dapm.codec = codec; |
| @@ -4342,7 +4306,7 @@ int snd_soc_register_codec(struct device *dev, | |||
| 4342 | /* register component */ | 4306 | /* register component */ |
| 4343 | ret = __snd_soc_register_component(dev, &codec->component, | 4307 | ret = __snd_soc_register_component(dev, &codec->component, |
| 4344 | &codec_drv->component_driver, | 4308 | &codec_drv->component_driver, |
| 4345 | dai_drv, num_dai, false); | 4309 | codec, dai_drv, num_dai, false); |
| 4346 | if (ret < 0) { | 4310 | if (ret < 0) { |
| 4347 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); | 4311 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); |
| 4348 | goto fail_codec_name; | 4312 | goto fail_codec_name; |
| @@ -4417,6 +4381,122 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, | |||
| 4417 | } | 4381 | } |
| 4418 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); | 4382 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); |
| 4419 | 4383 | ||
| 4384 | static const struct snd_soc_dapm_widget simple_widgets[] = { | ||
| 4385 | SND_SOC_DAPM_MIC("Microphone", NULL), | ||
| 4386 | SND_SOC_DAPM_LINE("Line", NULL), | ||
| 4387 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
| 4388 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
| 4389 | }; | ||
| 4390 | |||
| 4391 | int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, | ||
| 4392 | const char *propname) | ||
| 4393 | { | ||
| 4394 | struct device_node *np = card->dev->of_node; | ||
| 4395 | struct snd_soc_dapm_widget *widgets; | ||
| 4396 | const char *template, *wname; | ||
| 4397 | int i, j, num_widgets, ret; | ||
| 4398 | |||
| 4399 | num_widgets = of_property_count_strings(np, propname); | ||
| 4400 | if (num_widgets < 0) { | ||
| 4401 | dev_err(card->dev, | ||
| 4402 | "ASoC: Property '%s' does not exist\n", propname); | ||
| 4403 | return -EINVAL; | ||
| 4404 | } | ||
| 4405 | if (num_widgets & 1) { | ||
| 4406 | dev_err(card->dev, | ||
| 4407 | "ASoC: Property '%s' length is not even\n", propname); | ||
| 4408 | return -EINVAL; | ||
| 4409 | } | ||
| 4410 | |||
| 4411 | num_widgets /= 2; | ||
| 4412 | if (!num_widgets) { | ||
| 4413 | dev_err(card->dev, "ASoC: Property '%s's length is zero\n", | ||
| 4414 | propname); | ||
| 4415 | return -EINVAL; | ||
| 4416 | } | ||
| 4417 | |||
| 4418 | widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), | ||
| 4419 | GFP_KERNEL); | ||
| 4420 | if (!widgets) { | ||
| 4421 | dev_err(card->dev, | ||
| 4422 | "ASoC: Could not allocate memory for widgets\n"); | ||
| 4423 | return -ENOMEM; | ||
| 4424 | } | ||
| 4425 | |||
| 4426 | for (i = 0; i < num_widgets; i++) { | ||
| 4427 | ret = of_property_read_string_index(np, propname, | ||
| 4428 | 2 * i, &template); | ||
| 4429 | if (ret) { | ||
| 4430 | dev_err(card->dev, | ||
| 4431 | "ASoC: Property '%s' index %d read error:%d\n", | ||
| 4432 | propname, 2 * i, ret); | ||
| 4433 | return -EINVAL; | ||
| 4434 | } | ||
| 4435 | |||
| 4436 | for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { | ||
| 4437 | if (!strncmp(template, simple_widgets[j].name, | ||
| 4438 | strlen(simple_widgets[j].name))) { | ||
| 4439 | widgets[i] = simple_widgets[j]; | ||
| 4440 | break; | ||
| 4441 | } | ||
| 4442 | } | ||
| 4443 | |||
| 4444 | if (j >= ARRAY_SIZE(simple_widgets)) { | ||
| 4445 | dev_err(card->dev, | ||
| 4446 | "ASoC: DAPM widget '%s' is not supported\n", | ||
| 4447 | template); | ||
| 4448 | return -EINVAL; | ||
| 4449 | } | ||
| 4450 | |||
| 4451 | ret = of_property_read_string_index(np, propname, | ||
| 4452 | (2 * i) + 1, | ||
| 4453 | &wname); | ||
| 4454 | if (ret) { | ||
| 4455 | dev_err(card->dev, | ||
| 4456 | "ASoC: Property '%s' index %d read error:%d\n", | ||
| 4457 | propname, (2 * i) + 1, ret); | ||
| 4458 | return -EINVAL; | ||
| 4459 | } | ||
| 4460 | |||
| 4461 | widgets[i].name = wname; | ||
| 4462 | } | ||
| 4463 | |||
| 4464 | card->dapm_widgets = widgets; | ||
| 4465 | card->num_dapm_widgets = num_widgets; | ||
| 4466 | |||
| 4467 | return 0; | ||
| 4468 | } | ||
| 4469 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); | ||
| 4470 | |||
| 4471 | int snd_soc_of_parse_tdm_slot(struct device_node *np, | ||
| 4472 | unsigned int *slots, | ||
| 4473 | unsigned int *slot_width) | ||
| 4474 | { | ||
| 4475 | u32 val; | ||
| 4476 | int ret; | ||
| 4477 | |||
| 4478 | if (of_property_read_bool(np, "dai-tdm-slot-num")) { | ||
| 4479 | ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); | ||
| 4480 | if (ret) | ||
| 4481 | return ret; | ||
| 4482 | |||
| 4483 | if (slots) | ||
| 4484 | *slots = val; | ||
| 4485 | } | ||
| 4486 | |||
| 4487 | if (of_property_read_bool(np, "dai-tdm-slot-width")) { | ||
| 4488 | ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); | ||
| 4489 | if (ret) | ||
| 4490 | return ret; | ||
| 4491 | |||
| 4492 | if (slot_width) | ||
| 4493 | *slot_width = val; | ||
| 4494 | } | ||
| 4495 | |||
| 4496 | return 0; | ||
| 4497 | } | ||
| 4498 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); | ||
| 4499 | |||
| 4420 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | 4500 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
| 4421 | const char *propname) | 4501 | const char *propname) |
| 4422 | { | 4502 | { |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b9dc6acbba8c..c8a780d0d057 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
| @@ -70,8 +70,6 @@ static int dapm_up_seq[] = { | |||
| 70 | [snd_soc_dapm_aif_out] = 4, | 70 | [snd_soc_dapm_aif_out] = 4, |
| 71 | [snd_soc_dapm_mic] = 5, | 71 | [snd_soc_dapm_mic] = 5, |
| 72 | [snd_soc_dapm_mux] = 6, | 72 | [snd_soc_dapm_mux] = 6, |
| 73 | [snd_soc_dapm_virt_mux] = 6, | ||
| 74 | [snd_soc_dapm_value_mux] = 6, | ||
| 75 | [snd_soc_dapm_dac] = 7, | 73 | [snd_soc_dapm_dac] = 7, |
| 76 | [snd_soc_dapm_switch] = 8, | 74 | [snd_soc_dapm_switch] = 8, |
| 77 | [snd_soc_dapm_mixer] = 8, | 75 | [snd_soc_dapm_mixer] = 8, |
| @@ -102,8 +100,6 @@ static int dapm_down_seq[] = { | |||
| 102 | [snd_soc_dapm_mic] = 7, | 100 | [snd_soc_dapm_mic] = 7, |
| 103 | [snd_soc_dapm_micbias] = 8, | 101 | [snd_soc_dapm_micbias] = 8, |
| 104 | [snd_soc_dapm_mux] = 9, | 102 | [snd_soc_dapm_mux] = 9, |
| 105 | [snd_soc_dapm_virt_mux] = 9, | ||
| 106 | [snd_soc_dapm_value_mux] = 9, | ||
| 107 | [snd_soc_dapm_aif_in] = 10, | 103 | [snd_soc_dapm_aif_in] = 10, |
| 108 | [snd_soc_dapm_aif_out] = 10, | 104 | [snd_soc_dapm_aif_out] = 10, |
| 109 | [snd_soc_dapm_dai_in] = 10, | 105 | [snd_soc_dapm_dai_in] = 10, |
| @@ -115,6 +111,12 @@ static int dapm_down_seq[] = { | |||
| 115 | [snd_soc_dapm_post] = 14, | 111 | [snd_soc_dapm_post] = 14, |
| 116 | }; | 112 | }; |
| 117 | 113 | ||
| 114 | static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) | ||
| 115 | { | ||
| 116 | if (dapm->card && dapm->card->instantiated) | ||
| 117 | lockdep_assert_held(&dapm->card->dapm_mutex); | ||
| 118 | } | ||
| 119 | |||
| 118 | static void pop_wait(u32 pop_time) | 120 | static void pop_wait(u32 pop_time) |
| 119 | { | 121 | { |
| 120 | if (pop_time) | 122 | if (pop_time) |
| @@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) | |||
| 146 | return !list_empty(&w->dirty); | 148 | return !list_empty(&w->dirty); |
| 147 | } | 149 | } |
| 148 | 150 | ||
| 149 | void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | 151 | static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) |
| 150 | { | 152 | { |
| 153 | dapm_assert_locked(w->dapm); | ||
| 154 | |||
| 151 | if (!dapm_dirty_widget(w)) { | 155 | if (!dapm_dirty_widget(w)) { |
| 152 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", | 156 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", |
| 153 | w->name, reason); | 157 | w->name, reason); |
| 154 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); | 158 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); |
| 155 | } | 159 | } |
| 156 | } | 160 | } |
| 157 | EXPORT_SYMBOL_GPL(dapm_mark_dirty); | ||
| 158 | 161 | ||
| 159 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) |
| 160 | { | 163 | { |
| @@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card) | |||
| 361 | { | 364 | { |
| 362 | struct snd_soc_dapm_widget *w; | 365 | struct snd_soc_dapm_widget *w; |
| 363 | 366 | ||
| 367 | lockdep_assert_held(&card->dapm_mutex); | ||
| 368 | |||
| 364 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 369 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
| 365 | 370 | ||
| 366 | list_for_each_entry(w, &card->widgets, list) { | 371 | list_for_each_entry(w, &card->widgets, list) { |
| @@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, | |||
| 386 | return -1; | 391 | return -1; |
| 387 | } | 392 | } |
| 388 | 393 | ||
| 389 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | 394 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, |
| 395 | unsigned int val) | ||
| 390 | { | 396 | { |
| 391 | if (w->codec) | 397 | if (w->codec) |
| 392 | return snd_soc_write(w->codec, reg, val); | 398 | return snd_soc_write(w->codec, reg, val); |
| @@ -498,131 +504,40 @@ out: | |||
| 498 | return ret; | 504 | return ret; |
| 499 | } | 505 | } |
| 500 | 506 | ||
| 501 | /* set up initial codec paths */ | 507 | /* connect mux widget to its interconnecting audio paths */ |
| 502 | static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | 508 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
| 503 | struct snd_soc_dapm_path *p, int i) | 509 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
| 510 | struct snd_soc_dapm_path *path, const char *control_name, | ||
| 511 | const struct snd_kcontrol_new *kcontrol) | ||
| 504 | { | 512 | { |
| 505 | switch (w->id) { | 513 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 506 | case snd_soc_dapm_switch: | 514 | unsigned int val, item; |
| 507 | case snd_soc_dapm_mixer: | 515 | int i; |
| 508 | case snd_soc_dapm_mixer_named_ctl: { | ||
| 509 | int val; | ||
| 510 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
| 511 | w->kcontrol_news[i].private_value; | ||
| 512 | int reg = mc->reg; | ||
| 513 | unsigned int shift = mc->shift; | ||
| 514 | int max = mc->max; | ||
| 515 | unsigned int mask = (1 << fls(max)) - 1; | ||
| 516 | unsigned int invert = mc->invert; | ||
| 517 | |||
| 518 | if (reg != SND_SOC_NOPM) { | ||
| 519 | soc_widget_read(w, reg, &val); | ||
| 520 | val = (val >> shift) & mask; | ||
| 521 | if (invert) | ||
| 522 | val = max - val; | ||
| 523 | p->connect = !!val; | ||
| 524 | } else { | ||
| 525 | p->connect = 0; | ||
| 526 | } | ||
| 527 | |||
| 528 | } | ||
| 529 | break; | ||
| 530 | case snd_soc_dapm_mux: { | ||
| 531 | struct soc_enum *e = (struct soc_enum *) | ||
| 532 | w->kcontrol_news[i].private_value; | ||
| 533 | int val, item; | ||
| 534 | |||
| 535 | soc_widget_read(w, e->reg, &val); | ||
| 536 | item = (val >> e->shift_l) & e->mask; | ||
| 537 | |||
| 538 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
| 539 | p->connect = 1; | ||
| 540 | else | ||
| 541 | p->connect = 0; | ||
| 542 | } | ||
| 543 | break; | ||
| 544 | case snd_soc_dapm_virt_mux: { | ||
| 545 | struct soc_enum *e = (struct soc_enum *) | ||
| 546 | w->kcontrol_news[i].private_value; | ||
| 547 | 516 | ||
| 548 | p->connect = 0; | 517 | if (e->reg != SND_SOC_NOPM) { |
| 518 | soc_widget_read(dest, e->reg, &val); | ||
| 519 | val = (val >> e->shift_l) & e->mask; | ||
| 520 | item = snd_soc_enum_val_to_item(e, val); | ||
| 521 | } else { | ||
| 549 | /* since a virtual mux has no backing registers to | 522 | /* since a virtual mux has no backing registers to |
| 550 | * decide which path to connect, it will try to match | 523 | * decide which path to connect, it will try to match |
| 551 | * with the first enumeration. This is to ensure | 524 | * with the first enumeration. This is to ensure |
| 552 | * that the default mux choice (the first) will be | 525 | * that the default mux choice (the first) will be |
| 553 | * correctly powered up during initialization. | 526 | * correctly powered up during initialization. |
| 554 | */ | 527 | */ |
| 555 | if (!strcmp(p->name, e->texts[0])) | 528 | item = 0; |
| 556 | p->connect = 1; | ||
| 557 | } | 529 | } |
| 558 | break; | ||
| 559 | case snd_soc_dapm_value_mux: { | ||
| 560 | struct soc_enum *e = (struct soc_enum *) | ||
| 561 | w->kcontrol_news[i].private_value; | ||
| 562 | int val, item; | ||
| 563 | 530 | ||
| 564 | soc_widget_read(w, e->reg, &val); | 531 | for (i = 0; i < e->items; i++) { |
| 565 | val = (val >> e->shift_l) & e->mask; | ||
| 566 | for (item = 0; item < e->max; item++) { | ||
| 567 | if (val == e->values[item]) | ||
| 568 | break; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
| 572 | p->connect = 1; | ||
| 573 | else | ||
| 574 | p->connect = 0; | ||
| 575 | } | ||
| 576 | break; | ||
| 577 | /* does not affect routing - always connected */ | ||
| 578 | case snd_soc_dapm_pga: | ||
| 579 | case snd_soc_dapm_out_drv: | ||
| 580 | case snd_soc_dapm_output: | ||
| 581 | case snd_soc_dapm_adc: | ||
| 582 | case snd_soc_dapm_input: | ||
| 583 | case snd_soc_dapm_siggen: | ||
| 584 | case snd_soc_dapm_dac: | ||
| 585 | case snd_soc_dapm_micbias: | ||
| 586 | case snd_soc_dapm_vmid: | ||
| 587 | case snd_soc_dapm_supply: | ||
| 588 | case snd_soc_dapm_regulator_supply: | ||
| 589 | case snd_soc_dapm_clock_supply: | ||
| 590 | case snd_soc_dapm_aif_in: | ||
| 591 | case snd_soc_dapm_aif_out: | ||
| 592 | case snd_soc_dapm_dai_in: | ||
| 593 | case snd_soc_dapm_dai_out: | ||
| 594 | case snd_soc_dapm_hp: | ||
| 595 | case snd_soc_dapm_mic: | ||
| 596 | case snd_soc_dapm_spk: | ||
| 597 | case snd_soc_dapm_line: | ||
| 598 | case snd_soc_dapm_dai_link: | ||
| 599 | case snd_soc_dapm_kcontrol: | ||
| 600 | p->connect = 1; | ||
| 601 | break; | ||
| 602 | /* does affect routing - dynamically connected */ | ||
| 603 | case snd_soc_dapm_pre: | ||
| 604 | case snd_soc_dapm_post: | ||
| 605 | p->connect = 0; | ||
| 606 | break; | ||
| 607 | } | ||
| 608 | } | ||
| 609 | |||
| 610 | /* connect mux widget to its interconnecting audio paths */ | ||
| 611 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | ||
| 612 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
| 613 | struct snd_soc_dapm_path *path, const char *control_name, | ||
| 614 | const struct snd_kcontrol_new *kcontrol) | ||
| 615 | { | ||
| 616 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
| 617 | int i; | ||
| 618 | |||
| 619 | for (i = 0; i < e->max; i++) { | ||
| 620 | if (!(strcmp(control_name, e->texts[i]))) { | 532 | if (!(strcmp(control_name, e->texts[i]))) { |
| 621 | list_add(&path->list, &dapm->card->paths); | 533 | list_add(&path->list, &dapm->card->paths); |
| 622 | list_add(&path->list_sink, &dest->sources); | 534 | list_add(&path->list_sink, &dest->sources); |
| 623 | list_add(&path->list_source, &src->sinks); | 535 | list_add(&path->list_source, &src->sinks); |
| 624 | path->name = (char*)e->texts[i]; | 536 | path->name = (char*)e->texts[i]; |
| 625 | dapm_set_path_status(dest, path, 0); | 537 | if (i == item) |
| 538 | path->connect = 1; | ||
| 539 | else | ||
| 540 | path->connect = 0; | ||
| 626 | return 0; | 541 | return 0; |
| 627 | } | 542 | } |
| 628 | } | 543 | } |
| @@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
| 630 | return -ENODEV; | 545 | return -ENODEV; |
| 631 | } | 546 | } |
| 632 | 547 | ||
| 548 | /* set up initial codec paths */ | ||
| 549 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | ||
| 550 | struct snd_soc_dapm_path *p, int i) | ||
| 551 | { | ||
| 552 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
| 553 | w->kcontrol_news[i].private_value; | ||
| 554 | unsigned int reg = mc->reg; | ||
| 555 | unsigned int shift = mc->shift; | ||
| 556 | unsigned int max = mc->max; | ||
| 557 | unsigned int mask = (1 << fls(max)) - 1; | ||
| 558 | unsigned int invert = mc->invert; | ||
| 559 | unsigned int val; | ||
| 560 | |||
| 561 | if (reg != SND_SOC_NOPM) { | ||
| 562 | soc_widget_read(w, reg, &val); | ||
| 563 | val = (val >> shift) & mask; | ||
| 564 | if (invert) | ||
| 565 | val = max - val; | ||
| 566 | p->connect = !!val; | ||
| 567 | } else { | ||
| 568 | p->connect = 0; | ||
| 569 | } | ||
| 570 | } | ||
| 571 | |||
| 633 | /* connect mixer widget to its interconnecting audio paths */ | 572 | /* connect mixer widget to its interconnecting audio paths */ |
| 634 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 573 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
| 635 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 574 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
| @@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | |||
| 644 | list_add(&path->list_sink, &dest->sources); | 583 | list_add(&path->list_sink, &dest->sources); |
| 645 | list_add(&path->list_source, &src->sinks); | 584 | list_add(&path->list_source, &src->sinks); |
| 646 | path->name = dest->kcontrol_news[i].name; | 585 | path->name = dest->kcontrol_news[i].name; |
| 647 | dapm_set_path_status(dest, path, i); | 586 | dapm_set_mixer_path_status(dest, path, i); |
| 648 | return 0; | 587 | return 0; |
| 649 | } | 588 | } |
| 650 | } | 589 | } |
| @@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
| 723 | kcname_in_long_name = true; | 662 | kcname_in_long_name = true; |
| 724 | break; | 663 | break; |
| 725 | case snd_soc_dapm_mux: | 664 | case snd_soc_dapm_mux: |
| 726 | case snd_soc_dapm_virt_mux: | ||
| 727 | case snd_soc_dapm_value_mux: | ||
| 728 | wname_in_long_name = true; | 665 | wname_in_long_name = true; |
| 729 | kcname_in_long_name = false; | 666 | kcname_in_long_name = false; |
| 730 | break; | 667 | break; |
| @@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
| 1823 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); | 1760 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); |
| 1824 | enum snd_soc_bias_level bias; | 1761 | enum snd_soc_bias_level bias; |
| 1825 | 1762 | ||
| 1763 | lockdep_assert_held(&card->dapm_mutex); | ||
| 1764 | |||
| 1826 | trace_snd_soc_dapm_start(card); | 1765 | trace_snd_soc_dapm_start(card); |
| 1827 | 1766 | ||
| 1828 | list_for_each_entry(d, &card->dapm_list, list) { | 1767 | list_for_each_entry(d, &card->dapm_list, list) { |
| @@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
| 1897 | 1836 | ||
| 1898 | trace_snd_soc_dapm_walk_done(card); | 1837 | trace_snd_soc_dapm_walk_done(card); |
| 1899 | 1838 | ||
| 1900 | /* Run all the bias changes in parallel */ | 1839 | /* Run card bias changes at first */ |
| 1901 | list_for_each_entry(d, &card->dapm_list, list) | 1840 | dapm_pre_sequence_async(&card->dapm, 0); |
| 1902 | async_schedule_domain(dapm_pre_sequence_async, d, | 1841 | /* Run other bias changes in parallel */ |
| 1903 | &async_domain); | 1842 | list_for_each_entry(d, &card->dapm_list, list) { |
| 1843 | if (d != &card->dapm) | ||
| 1844 | async_schedule_domain(dapm_pre_sequence_async, d, | ||
| 1845 | &async_domain); | ||
| 1846 | } | ||
| 1904 | async_synchronize_full_domain(&async_domain); | 1847 | async_synchronize_full_domain(&async_domain); |
| 1905 | 1848 | ||
| 1906 | list_for_each_entry(w, &down_list, power_list) { | 1849 | list_for_each_entry(w, &down_list, power_list) { |
| @@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
| 1920 | dapm_seq_run(card, &up_list, event, true); | 1863 | dapm_seq_run(card, &up_list, event, true); |
| 1921 | 1864 | ||
| 1922 | /* Run all the bias changes in parallel */ | 1865 | /* Run all the bias changes in parallel */ |
| 1923 | list_for_each_entry(d, &card->dapm_list, list) | 1866 | list_for_each_entry(d, &card->dapm_list, list) { |
| 1924 | async_schedule_domain(dapm_post_sequence_async, d, | 1867 | if (d != &card->dapm) |
| 1925 | &async_domain); | 1868 | async_schedule_domain(dapm_post_sequence_async, d, |
| 1869 | &async_domain); | ||
| 1870 | } | ||
| 1926 | async_synchronize_full_domain(&async_domain); | 1871 | async_synchronize_full_domain(&async_domain); |
| 1872 | /* Run card bias changes at last */ | ||
| 1873 | dapm_post_sequence_async(&card->dapm, 0); | ||
| 1927 | 1874 | ||
| 1928 | /* do we need to notify any clients that DAPM event is complete */ | 1875 | /* do we need to notify any clients that DAPM event is complete */ |
| 1929 | list_for_each_entry(d, &card->dapm_list, list) { | 1876 | list_for_each_entry(d, &card->dapm_list, list) { |
| @@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, | |||
| 2110 | struct snd_soc_dapm_path *path; | 2057 | struct snd_soc_dapm_path *path; |
| 2111 | int found = 0; | 2058 | int found = 0; |
| 2112 | 2059 | ||
| 2060 | lockdep_assert_held(&card->dapm_mutex); | ||
| 2061 | |||
| 2113 | /* find dapm widget path assoc with kcontrol */ | 2062 | /* find dapm widget path assoc with kcontrol */ |
| 2114 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2063 | dapm_kcontrol_for_each_path(path, kcontrol) { |
| 2115 | if (!path->name || !e->texts[mux]) | 2064 | if (!path->name || !e->texts[mux]) |
| @@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
| 2160 | struct snd_soc_dapm_path *path; | 2109 | struct snd_soc_dapm_path *path; |
| 2161 | int found = 0; | 2110 | int found = 0; |
| 2162 | 2111 | ||
| 2112 | lockdep_assert_held(&card->dapm_mutex); | ||
| 2113 | |||
| 2163 | /* find dapm widget path assoc with kcontrol */ | 2114 | /* find dapm widget path assoc with kcontrol */ |
| 2164 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2115 | dapm_kcontrol_for_each_path(path, kcontrol) { |
| 2165 | found = 1; | 2116 | found = 1; |
| @@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
| 2325 | { | 2276 | { |
| 2326 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | 2277 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
| 2327 | 2278 | ||
| 2279 | dapm_assert_locked(dapm); | ||
| 2280 | |||
| 2328 | if (!w) { | 2281 | if (!w) { |
| 2329 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); | 2282 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); |
| 2330 | return -EINVAL; | 2283 | return -EINVAL; |
| @@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
| 2341 | } | 2294 | } |
| 2342 | 2295 | ||
| 2343 | /** | 2296 | /** |
| 2344 | * snd_soc_dapm_sync - scan and power dapm paths | 2297 | * snd_soc_dapm_sync_unlocked - scan and power dapm paths |
| 2345 | * @dapm: DAPM context | 2298 | * @dapm: DAPM context |
| 2346 | * | 2299 | * |
| 2347 | * Walks all dapm audio paths and powers widgets according to their | 2300 | * Walks all dapm audio paths and powers widgets according to their |
| 2348 | * stream or path usage. | 2301 | * stream or path usage. |
| 2349 | * | 2302 | * |
| 2303 | * Requires external locking. | ||
| 2304 | * | ||
| 2350 | * Returns 0 for success. | 2305 | * Returns 0 for success. |
| 2351 | */ | 2306 | */ |
| 2352 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | 2307 | int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) |
| 2353 | { | 2308 | { |
| 2354 | int ret; | ||
| 2355 | |||
| 2356 | /* | 2309 | /* |
| 2357 | * Suppress early reports (eg, jacks syncing their state) to avoid | 2310 | * Suppress early reports (eg, jacks syncing their state) to avoid |
| 2358 | * silly DAPM runs during card startup. | 2311 | * silly DAPM runs during card startup. |
| @@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
| 2360 | if (!dapm->card || !dapm->card->instantiated) | 2313 | if (!dapm->card || !dapm->card->instantiated) |
| 2361 | return 0; | 2314 | return 0; |
| 2362 | 2315 | ||
| 2316 | return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | ||
| 2317 | } | ||
| 2318 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); | ||
| 2319 | |||
| 2320 | /** | ||
| 2321 | * snd_soc_dapm_sync - scan and power dapm paths | ||
| 2322 | * @dapm: DAPM context | ||
| 2323 | * | ||
| 2324 | * Walks all dapm audio paths and powers widgets according to their | ||
| 2325 | * stream or path usage. | ||
| 2326 | * | ||
| 2327 | * Returns 0 for success. | ||
| 2328 | */ | ||
| 2329 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | ||
| 2330 | { | ||
| 2331 | int ret; | ||
| 2332 | |||
| 2363 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2333 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
| 2364 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | 2334 | ret = snd_soc_dapm_sync_unlocked(dapm); |
| 2365 | mutex_unlock(&dapm->card->dapm_mutex); | 2335 | mutex_unlock(&dapm->card->dapm_mutex); |
| 2366 | return ret; | 2336 | return ret; |
| 2367 | } | 2337 | } |
| @@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
| 2444 | path->connect = 1; | 2414 | path->connect = 1; |
| 2445 | return 0; | 2415 | return 0; |
| 2446 | case snd_soc_dapm_mux: | 2416 | case snd_soc_dapm_mux: |
| 2447 | case snd_soc_dapm_virt_mux: | ||
| 2448 | case snd_soc_dapm_value_mux: | ||
| 2449 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | 2417 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, |
| 2450 | &wsink->kcontrol_news[0]); | 2418 | &wsink->kcontrol_news[0]); |
| 2451 | if (ret != 0) | 2419 | if (ret != 0) |
| @@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
| 2772 | dapm_new_mixer(w); | 2740 | dapm_new_mixer(w); |
| 2773 | break; | 2741 | break; |
| 2774 | case snd_soc_dapm_mux: | 2742 | case snd_soc_dapm_mux: |
| 2775 | case snd_soc_dapm_virt_mux: | ||
| 2776 | case snd_soc_dapm_value_mux: | ||
| 2777 | dapm_new_mux(w); | 2743 | dapm_new_mux(w); |
| 2778 | break; | 2744 | break; |
| 2779 | case snd_soc_dapm_pga: | 2745 | case snd_soc_dapm_pga: |
| @@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
| 2935 | { | 2901 | { |
| 2936 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2902 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
| 2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2903 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 2938 | unsigned int val; | 2904 | unsigned int reg_val, val; |
| 2939 | |||
| 2940 | val = snd_soc_read(codec, e->reg); | ||
| 2941 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | ||
| 2942 | if (e->shift_l != e->shift_r) | ||
| 2943 | ucontrol->value.enumerated.item[1] = | ||
| 2944 | (val >> e->shift_r) & e->mask; | ||
| 2945 | |||
| 2946 | return 0; | ||
| 2947 | } | ||
| 2948 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | ||
| 2949 | |||
| 2950 | /** | ||
| 2951 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback | ||
| 2952 | * @kcontrol: mixer control | ||
| 2953 | * @ucontrol: control element information | ||
| 2954 | * | ||
| 2955 | * Callback to set the value of a dapm enumerated double mixer control. | ||
| 2956 | * | ||
| 2957 | * Returns 0 for success. | ||
| 2958 | */ | ||
| 2959 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | ||
| 2960 | struct snd_ctl_elem_value *ucontrol) | ||
| 2961 | { | ||
| 2962 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
| 2963 | struct snd_soc_card *card = codec->card; | ||
| 2964 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
| 2965 | unsigned int val, mux, change; | ||
| 2966 | unsigned int mask; | ||
| 2967 | struct snd_soc_dapm_update update; | ||
| 2968 | int ret = 0; | ||
| 2969 | |||
| 2970 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
| 2971 | return -EINVAL; | ||
| 2972 | mux = ucontrol->value.enumerated.item[0]; | ||
| 2973 | val = mux << e->shift_l; | ||
| 2974 | mask = e->mask << e->shift_l; | ||
| 2975 | if (e->shift_l != e->shift_r) { | ||
| 2976 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
| 2977 | return -EINVAL; | ||
| 2978 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
| 2979 | mask |= e->mask << e->shift_r; | ||
| 2980 | } | ||
| 2981 | |||
| 2982 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
| 2983 | |||
| 2984 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
| 2985 | if (change) { | ||
| 2986 | update.kcontrol = kcontrol; | ||
| 2987 | update.reg = e->reg; | ||
| 2988 | update.mask = mask; | ||
| 2989 | update.val = val; | ||
| 2990 | card->update = &update; | ||
| 2991 | |||
| 2992 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
| 2993 | |||
| 2994 | card->update = NULL; | ||
| 2995 | } | ||
| 2996 | |||
| 2997 | mutex_unlock(&card->dapm_mutex); | ||
| 2998 | |||
| 2999 | if (ret > 0) | ||
| 3000 | soc_dpcm_runtime_update(card); | ||
| 3001 | |||
| 3002 | return change; | ||
| 3003 | } | ||
| 3004 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | ||
| 3005 | |||
| 3006 | /** | ||
| 3007 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
| 3008 | * @kcontrol: mixer control | ||
| 3009 | * @ucontrol: control element information | ||
| 3010 | * | ||
| 3011 | * Returns 0 for success. | ||
| 3012 | */ | ||
| 3013 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
| 3014 | struct snd_ctl_elem_value *ucontrol) | ||
| 3015 | { | ||
| 3016 | ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); | ||
| 3017 | return 0; | ||
| 3018 | } | ||
| 3019 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
| 3020 | |||
| 3021 | /** | ||
| 3022 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
| 3023 | * @kcontrol: mixer control | ||
| 3024 | * @ucontrol: control element information | ||
| 3025 | * | ||
| 3026 | * Returns 0 for success. | ||
| 3027 | */ | ||
| 3028 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
| 3029 | struct snd_ctl_elem_value *ucontrol) | ||
| 3030 | { | ||
| 3031 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
| 3032 | struct snd_soc_card *card = codec->card; | ||
| 3033 | unsigned int value; | ||
| 3034 | struct soc_enum *e = | ||
| 3035 | (struct soc_enum *)kcontrol->private_value; | ||
| 3036 | int change; | ||
| 3037 | int ret = 0; | ||
| 3038 | |||
| 3039 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
| 3040 | return -EINVAL; | ||
| 3041 | 2905 | ||
| 3042 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2906 | if (e->reg != SND_SOC_NOPM) |
| 3043 | 2907 | reg_val = snd_soc_read(codec, e->reg); | |
| 3044 | value = ucontrol->value.enumerated.item[0]; | 2908 | else |
| 3045 | change = dapm_kcontrol_set_value(kcontrol, value); | 2909 | reg_val = dapm_kcontrol_get_value(kcontrol); |
| 3046 | if (change) | ||
| 3047 | ret = soc_dapm_mux_update_power(card, kcontrol, value, e); | ||
| 3048 | |||
| 3049 | mutex_unlock(&card->dapm_mutex); | ||
| 3050 | |||
| 3051 | if (ret > 0) | ||
| 3052 | soc_dpcm_runtime_update(card); | ||
| 3053 | |||
| 3054 | return change; | ||
| 3055 | } | ||
| 3056 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
| 3057 | |||
| 3058 | /** | ||
| 3059 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | ||
| 3060 | * callback | ||
| 3061 | * @kcontrol: mixer control | ||
| 3062 | * @ucontrol: control element information | ||
| 3063 | * | ||
| 3064 | * Callback to get the value of a dapm semi enumerated double mixer control. | ||
| 3065 | * | ||
| 3066 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
| 3067 | * used for handling bitfield coded enumeration for example. | ||
| 3068 | * | ||
| 3069 | * Returns 0 for success. | ||
| 3070 | */ | ||
| 3071 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
| 3072 | struct snd_ctl_elem_value *ucontrol) | ||
| 3073 | { | ||
| 3074 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
| 3075 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
| 3076 | unsigned int reg_val, val, mux; | ||
| 3077 | 2910 | ||
| 3078 | reg_val = snd_soc_read(codec, e->reg); | ||
| 3079 | val = (reg_val >> e->shift_l) & e->mask; | 2911 | val = (reg_val >> e->shift_l) & e->mask; |
| 3080 | for (mux = 0; mux < e->max; mux++) { | 2912 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); |
| 3081 | if (val == e->values[mux]) | ||
| 3082 | break; | ||
| 3083 | } | ||
| 3084 | ucontrol->value.enumerated.item[0] = mux; | ||
| 3085 | if (e->shift_l != e->shift_r) { | 2913 | if (e->shift_l != e->shift_r) { |
| 3086 | val = (reg_val >> e->shift_r) & e->mask; | 2914 | val = (reg_val >> e->shift_r) & e->mask; |
| 3087 | for (mux = 0; mux < e->max; mux++) { | 2915 | val = snd_soc_enum_val_to_item(e, val); |
| 3088 | if (val == e->values[mux]) | 2916 | ucontrol->value.enumerated.item[1] = val; |
| 3089 | break; | ||
| 3090 | } | ||
| 3091 | ucontrol->value.enumerated.item[1] = mux; | ||
| 3092 | } | 2917 | } |
| 3093 | 2918 | ||
| 3094 | return 0; | 2919 | return 0; |
| 3095 | } | 2920 | } |
| 3096 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | 2921 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
| 3097 | 2922 | ||
| 3098 | /** | 2923 | /** |
| 3099 | * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set | 2924 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback |
| 3100 | * callback | ||
| 3101 | * @kcontrol: mixer control | 2925 | * @kcontrol: mixer control |
| 3102 | * @ucontrol: control element information | 2926 | * @ucontrol: control element information |
| 3103 | * | 2927 | * |
| 3104 | * Callback to set the value of a dapm semi enumerated double mixer control. | 2928 | * Callback to set the value of a dapm enumerated double mixer control. |
| 3105 | * | ||
| 3106 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
| 3107 | * used for handling bitfield coded enumeration for example. | ||
| 3108 | * | 2929 | * |
| 3109 | * Returns 0 for success. | 2930 | * Returns 0 for success. |
| 3110 | */ | 2931 | */ |
| 3111 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2932 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
| 3112 | struct snd_ctl_elem_value *ucontrol) | 2933 | struct snd_ctl_elem_value *ucontrol) |
| 3113 | { | 2934 | { |
| 3114 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2935 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
| 3115 | struct snd_soc_card *card = codec->card; | 2936 | struct snd_soc_card *card = codec->card; |
| 3116 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
| 3117 | unsigned int val, mux, change; | 2938 | unsigned int *item = ucontrol->value.enumerated.item; |
| 2939 | unsigned int val, change; | ||
| 3118 | unsigned int mask; | 2940 | unsigned int mask; |
| 3119 | struct snd_soc_dapm_update update; | 2941 | struct snd_soc_dapm_update update; |
| 3120 | int ret = 0; | 2942 | int ret = 0; |
| 3121 | 2943 | ||
| 3122 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2944 | if (item[0] >= e->items) |
| 3123 | return -EINVAL; | 2945 | return -EINVAL; |
| 3124 | mux = ucontrol->value.enumerated.item[0]; | 2946 | |
| 3125 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | 2947 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
| 3126 | mask = e->mask << e->shift_l; | 2948 | mask = e->mask << e->shift_l; |
| 3127 | if (e->shift_l != e->shift_r) { | 2949 | if (e->shift_l != e->shift_r) { |
| 3128 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2950 | if (item[1] > e->items) |
| 3129 | return -EINVAL; | 2951 | return -EINVAL; |
| 3130 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | 2952 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l; |
| 3131 | mask |= e->mask << e->shift_r; | 2953 | mask |= e->mask << e->shift_r; |
| 3132 | } | 2954 | } |
| 3133 | 2955 | ||
| 3134 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2956 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
| 3135 | 2957 | ||
| 3136 | change = snd_soc_test_bits(codec, e->reg, mask, val); | 2958 | if (e->reg != SND_SOC_NOPM) |
| 2959 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
| 2960 | else | ||
| 2961 | change = dapm_kcontrol_set_value(kcontrol, val); | ||
| 2962 | |||
| 3137 | if (change) { | 2963 | if (change) { |
| 3138 | update.kcontrol = kcontrol; | 2964 | if (e->reg != SND_SOC_NOPM) { |
| 3139 | update.reg = e->reg; | 2965 | update.kcontrol = kcontrol; |
| 3140 | update.mask = mask; | 2966 | update.reg = e->reg; |
| 3141 | update.val = val; | 2967 | update.mask = mask; |
| 3142 | card->update = &update; | 2968 | update.val = val; |
| 2969 | card->update = &update; | ||
| 2970 | } | ||
| 3143 | 2971 | ||
| 3144 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | 2972 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); |
| 3145 | 2973 | ||
| 3146 | card->update = NULL; | 2974 | card->update = NULL; |
| 3147 | } | 2975 | } |
| @@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
| 3153 | 2981 | ||
| 3154 | return change; | 2982 | return change; |
| 3155 | } | 2983 | } |
| 3156 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2984 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
| 3157 | 2985 | ||
| 3158 | /** | 2986 | /** |
| 3159 | * snd_soc_dapm_info_pin_switch - Info for a pin switch | 2987 | * snd_soc_dapm_info_pin_switch - Info for a pin switch |
| @@ -3283,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
| 3283 | w->power_check = dapm_generic_check_power; | 3111 | w->power_check = dapm_generic_check_power; |
| 3284 | break; | 3112 | break; |
| 3285 | case snd_soc_dapm_mux: | 3113 | case snd_soc_dapm_mux: |
| 3286 | case snd_soc_dapm_virt_mux: | ||
| 3287 | case snd_soc_dapm_value_mux: | ||
| 3288 | w->power_check = dapm_generic_check_power; | 3114 | w->power_check = dapm_generic_check_power; |
| 3289 | break; | 3115 | break; |
| 3290 | case snd_soc_dapm_dai_out: | 3116 | case snd_soc_dapm_dai_out: |
| @@ -4098,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) | |||
| 4098 | } | 3924 | } |
| 4099 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 3925 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
| 4100 | 3926 | ||
| 4101 | static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | 3927 | static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) |
| 4102 | { | 3928 | { |
| 4103 | struct snd_soc_card *card = dapm->card; | 3929 | struct snd_soc_card *card = dapm->card; |
| 4104 | struct snd_soc_dapm_widget *w; | 3930 | struct snd_soc_dapm_widget *w; |
| @@ -4138,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
| 4138 | */ | 3964 | */ |
| 4139 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) | 3965 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) |
| 4140 | { | 3966 | { |
| 4141 | struct snd_soc_codec *codec; | 3967 | struct snd_soc_dapm_context *dapm; |
| 4142 | 3968 | ||
| 4143 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | 3969 | list_for_each_entry(dapm, &card->dapm_list, list) { |
| 4144 | soc_dapm_shutdown_codec(&codec->dapm); | 3970 | if (dapm != &card->dapm) { |
| 4145 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 3971 | soc_dapm_shutdown_dapm(dapm); |
| 4146 | snd_soc_dapm_set_bias_level(&codec->dapm, | 3972 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) |
| 4147 | SND_SOC_BIAS_OFF); | 3973 | snd_soc_dapm_set_bias_level(dapm, |
| 3974 | SND_SOC_BIAS_OFF); | ||
| 3975 | } | ||
| 4148 | } | 3976 | } |
| 3977 | |||
| 3978 | soc_dapm_shutdown_dapm(&card->dapm); | ||
| 3979 | if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) | ||
| 3980 | snd_soc_dapm_set_bias_level(&card->dapm, | ||
| 3981 | SND_SOC_BIAS_OFF); | ||
| 4149 | } | 3982 | } |
| 4150 | 3983 | ||
| 4151 | /* Module information */ | 3984 | /* Module information */ |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 47e1ce771e65..2cedf09f6d96 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
| @@ -35,6 +35,86 @@ | |||
| 35 | #define DPCM_MAX_BE_USERS 8 | 35 | #define DPCM_MAX_BE_USERS 8 |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | * snd_soc_runtime_activate() - Increment active count for PCM runtime components | ||
| 39 | * @rtd: ASoC PCM runtime that is activated | ||
| 40 | * @stream: Direction of the PCM stream | ||
| 41 | * | ||
| 42 | * Increments the active count for all the DAIs and components attached to a PCM | ||
| 43 | * runtime. Should typically be called when a stream is opened. | ||
| 44 | * | ||
| 45 | * Must be called with the rtd->pcm_mutex being held | ||
| 46 | */ | ||
| 47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
| 48 | { | ||
| 49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 50 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 51 | |||
| 52 | lockdep_assert_held(&rtd->pcm_mutex); | ||
| 53 | |||
| 54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 55 | cpu_dai->playback_active++; | ||
| 56 | codec_dai->playback_active++; | ||
| 57 | } else { | ||
| 58 | cpu_dai->capture_active++; | ||
| 59 | codec_dai->capture_active++; | ||
| 60 | } | ||
| 61 | |||
| 62 | cpu_dai->active++; | ||
| 63 | codec_dai->active++; | ||
| 64 | cpu_dai->component->active++; | ||
| 65 | codec_dai->component->active++; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components | ||
| 70 | * @rtd: ASoC PCM runtime that is deactivated | ||
| 71 | * @stream: Direction of the PCM stream | ||
| 72 | * | ||
| 73 | * Decrements the active count for all the DAIs and components attached to a PCM | ||
| 74 | * runtime. Should typically be called when a stream is closed. | ||
| 75 | * | ||
| 76 | * Must be called with the rtd->pcm_mutex being held | ||
| 77 | */ | ||
| 78 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
| 79 | { | ||
| 80 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 82 | |||
| 83 | lockdep_assert_held(&rtd->pcm_mutex); | ||
| 84 | |||
| 85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 86 | cpu_dai->playback_active--; | ||
| 87 | codec_dai->playback_active--; | ||
| 88 | } else { | ||
| 89 | cpu_dai->capture_active--; | ||
| 90 | codec_dai->capture_active--; | ||
| 91 | } | ||
| 92 | |||
| 93 | cpu_dai->active--; | ||
| 94 | codec_dai->active--; | ||
| 95 | cpu_dai->component->active--; | ||
| 96 | codec_dai->component->active--; | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay | ||
| 101 | * @rtd: The ASoC PCM runtime that should be checked. | ||
| 102 | * | ||
| 103 | * This function checks whether the power down delay should be ignored for a | ||
| 104 | * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has | ||
| 105 | * been configured to ignore the delay, or if none of the components benefits | ||
| 106 | * from having the delay. | ||
| 107 | */ | ||
| 108 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) | ||
| 109 | { | ||
| 110 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) | ||
| 111 | return true; | ||
| 112 | |||
| 113 | return rtd->cpu_dai->component->ignore_pmdown_time && | ||
| 114 | rtd->codec_dai->component->ignore_pmdown_time; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 38 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | 118 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters |
| 39 | * @substream: the pcm substream | 119 | * @substream: the pcm substream |
| 40 | * @hw: the hardware parameters | 120 | * @hw: the hardware parameters |
| @@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 378 | runtime->hw.rate_max); | 458 | runtime->hw.rate_max); |
| 379 | 459 | ||
| 380 | dynamic: | 460 | dynamic: |
| 381 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 461 | |
| 382 | cpu_dai->playback_active++; | 462 | snd_soc_runtime_activate(rtd, substream->stream); |
| 383 | codec_dai->playback_active++; | 463 | |
| 384 | } else { | ||
| 385 | cpu_dai->capture_active++; | ||
| 386 | codec_dai->capture_active++; | ||
| 387 | } | ||
| 388 | cpu_dai->active++; | ||
| 389 | codec_dai->active++; | ||
| 390 | rtd->codec->active++; | ||
| 391 | mutex_unlock(&rtd->pcm_mutex); | 464 | mutex_unlock(&rtd->pcm_mutex); |
| 392 | return 0; | 465 | return 0; |
| 393 | 466 | ||
| @@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
| 459 | struct snd_soc_platform *platform = rtd->platform; | 532 | struct snd_soc_platform *platform = rtd->platform; |
| 460 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 533 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 461 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 534 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 462 | struct snd_soc_codec *codec = rtd->codec; | ||
| 463 | 535 | ||
| 464 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 536 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| 465 | 537 | ||
| 466 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 538 | snd_soc_runtime_deactivate(rtd, substream->stream); |
| 467 | cpu_dai->playback_active--; | ||
| 468 | codec_dai->playback_active--; | ||
| 469 | } else { | ||
| 470 | cpu_dai->capture_active--; | ||
| 471 | codec_dai->capture_active--; | ||
| 472 | } | ||
| 473 | |||
| 474 | cpu_dai->active--; | ||
| 475 | codec_dai->active--; | ||
| 476 | codec->active--; | ||
| 477 | 539 | ||
| 478 | /* clear the corresponding DAIs rate when inactive */ | 540 | /* clear the corresponding DAIs rate when inactive */ |
| 479 | if (!cpu_dai->active) | 541 | if (!cpu_dai->active) |
| @@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
| 496 | cpu_dai->runtime = NULL; | 558 | cpu_dai->runtime = NULL; |
| 497 | 559 | ||
| 498 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 560 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 499 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 561 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
| 500 | rtd->dai_link->ignore_pmdown_time) { | ||
| 501 | /* powered down playback stream now */ | 562 | /* powered down playback stream now */ |
| 502 | snd_soc_dapm_stream_event(rtd, | 563 | snd_soc_dapm_stream_event(rtd, |
| 503 | SNDRV_PCM_STREAM_PLAYBACK, | 564 | SNDRV_PCM_STREAM_PLAYBACK, |
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 9f9c1856f822..31198cf7f88d 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
| @@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE | |||
| 105 | tristate "SoC Audio support for TrimSlice board" | 105 | tristate "SoC Audio support for TrimSlice board" |
| 106 | depends on SND_SOC_TEGRA && I2C | 106 | depends on SND_SOC_TEGRA && I2C |
| 107 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 107 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
| 108 | select SND_SOC_TLV320AIC23 | 108 | select SND_SOC_TLV320AIC23_I2C |
| 109 | help | 109 | help |
| 110 | Say Y or M here if you want to add support for SoC audio on the | 110 | Say Y or M here if you want to add support for SoC audio on the |
| 111 | TrimSlice platform. | 111 | TrimSlice platform. |
