diff options
440 files changed, 18916 insertions, 6632 deletions
diff --git a/Documentation/devicetree/bindings/sound/arndale.txt b/Documentation/devicetree/bindings/sound/arndale.txt new file mode 100644 index 000000000000..0e76946385ae --- /dev/null +++ b/Documentation/devicetree/bindings/sound/arndale.txt | |||
@@ -0,0 +1,24 @@ | |||
1 | Audio Binding for Arndale boards | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : Can be the following, | ||
5 | "samsung,arndale-rt5631" | ||
6 | |||
7 | - samsung,audio-cpu: The phandle of the Samsung I2S controller | ||
8 | - samsung,audio-codec: The phandle of the audio codec | ||
9 | |||
10 | Optional: | ||
11 | - samsung,model: The name of the sound-card | ||
12 | |||
13 | Arndale Boards has many audio daughter cards, one of them is | ||
14 | rt5631/alc5631. Below example shows audio bindings for rt5631/ | ||
15 | alc5631 based codec. | ||
16 | |||
17 | Example: | ||
18 | |||
19 | sound { | ||
20 | compatible = "samsung,arndale-rt5631"; | ||
21 | |||
22 | samsung,audio-cpu = <&i2s0> | ||
23 | samsung,audio-codec = <&rt5631>; | ||
24 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 60ca07996458..46bc9829c71a 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt | |||
@@ -32,7 +32,7 @@ Optional properties: | |||
32 | - rx-num-evt : FIFO levels. | 32 | - rx-num-evt : FIFO levels. |
33 | - sram-size-playback : size of sram to be allocated during playback | 33 | - sram-size-playback : size of sram to be allocated during playback |
34 | - sram-size-capture : size of sram to be allocated during capture | 34 | - sram-size-capture : size of sram to be allocated during capture |
35 | - interrupts : Interrupt numbers for McASP, currently not used by the driver | 35 | - interrupts : Interrupt numbers for McASP |
36 | - interrupt-names : Known interrupt names are "tx" and "rx" | 36 | - interrupt-names : Known interrupt names are "tx" and "rx" |
37 | - pinctrl-0: Should specify pin control group used for this controller. | 37 | - pinctrl-0: Should specify pin control group used for this controller. |
38 | - pinctrl-names: Should contain only one value - "default", for more details | 38 | - pinctrl-names: Should contain only one value - "default", for more details |
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt index 0d7985c864af..6dfa88c4dc1e 100644 --- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt +++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt | |||
@@ -1,11 +1,16 @@ | |||
1 | Audio complex for Eukrea boards with tlv320aic23 codec. | 1 | Audio complex for Eukrea boards with tlv320aic23 codec. |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "eukrea,asoc-tlv320" | 4 | |
5 | - eukrea,model : The user-visible name of this sound complex. | 5 | - compatible : "eukrea,asoc-tlv320" |
6 | - ssi-controller : The phandle of the SSI controller. | 6 | |
7 | - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). | 7 | - eukrea,model : The user-visible name of this sound complex. |
8 | - fsl,mux-ext-port : The external port of the i.MX audio muxer. | 8 | |
9 | - ssi-controller : The phandle of the SSI controller. | ||
10 | |||
11 | - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX). | ||
12 | |||
13 | - fsl,mux-ext-port : The external port of the i.MX audio muxer. | ||
9 | 14 | ||
10 | Note: The AUDMUX port numbering should start at 1, which is consistent with | 15 | Note: The AUDMUX port numbering should start at 1, which is consistent with |
11 | hardware manual. | 16 | hardware manual. |
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt index 52f5b6bf3e8e..d3b6b5f48010 100644 --- a/Documentation/devicetree/bindings/sound/fsl,esai.txt +++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt | |||
@@ -7,37 +7,39 @@ other DSPs. It has up to six transmitters and four receivers. | |||
7 | 7 | ||
8 | Required properties: | 8 | Required properties: |
9 | 9 | ||
10 | - compatible : Compatible list, must contain "fsl,imx35-esai" or | 10 | - compatible : Compatible list, must contain "fsl,imx35-esai" or |
11 | "fsl,vf610-esai" | 11 | "fsl,vf610-esai" |
12 | 12 | ||
13 | - reg : Offset and length of the register set for the device. | 13 | - reg : Offset and length of the register set for the device. |
14 | 14 | ||
15 | - interrupts : Contains the spdif interrupt. | 15 | - interrupts : Contains the spdif interrupt. |
16 | 16 | ||
17 | - dmas : Generic dma devicetree binding as described in | 17 | - dmas : Generic dma devicetree binding as described in |
18 | Documentation/devicetree/bindings/dma/dma.txt. | 18 | Documentation/devicetree/bindings/dma/dma.txt. |
19 | 19 | ||
20 | - dma-names : Two dmas have to be defined, "tx" and "rx". | 20 | - dma-names : Two dmas have to be defined, "tx" and "rx". |
21 | 21 | ||
22 | - clocks: Contains an entry for each entry in clock-names. | 22 | - clocks : Contains an entry for each entry in clock-names. |
23 | 23 | ||
24 | - clock-names : Includes the following entries: | 24 | - clock-names : Includes the following entries: |
25 | "core" The core clock used to access registers | 25 | "core" The core clock used to access registers |
26 | "extal" The esai baud clock for esai controller used to derive | 26 | "extal" The esai baud clock for esai controller used to |
27 | HCK, SCK and FS. | 27 | derive HCK, SCK and FS. |
28 | "fsys" The system clock derived from ahb clock used to derive | 28 | "fsys" The system clock derived from ahb clock used to |
29 | HCK, SCK and FS. | 29 | derive HCK, SCK and FS. |
30 | 30 | ||
31 | - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs. | 31 | - fsl,fifo-depth : The number of elements in the transmit and receive |
32 | This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM]. | 32 | FIFOs. This number is the maximum allowed value for |
33 | TFCR[TFWM] or RFCR[RFWM]. | ||
33 | 34 | ||
34 | - fsl,esai-synchronous: This is a boolean property. If present, indicating | 35 | - fsl,esai-synchronous: This is a boolean property. If present, indicating |
35 | that ESAI would work in the synchronous mode, which means all the settings | 36 | that ESAI would work in the synchronous mode, which |
36 | for Receiving would be duplicated from Transmition related registers. | 37 | means all the settings for Receiving would be |
38 | duplicated from Transmition related registers. | ||
37 | 39 | ||
38 | - big-endian : If this property is absent, the native endian mode will | 40 | - big-endian : If this property is absent, the native endian mode |
39 | be in use as default, or the big endian mode will be in use for all the | 41 | will be in use as default, or the big endian mode |
40 | device registers. | 42 | will be in use for all the device registers. |
41 | 43 | ||
42 | Example: | 44 | Example: |
43 | 45 | ||
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt index 3e9e82c8eab3..b5ee32ee3706 100644 --- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt +++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt | |||
@@ -6,32 +6,31 @@ a fibre cable. | |||
6 | 6 | ||
7 | Required properties: | 7 | Required properties: |
8 | 8 | ||
9 | - compatible : Compatible list, must contain "fsl,imx35-spdif". | 9 | - compatible : Compatible list, must contain "fsl,imx35-spdif". |
10 | 10 | ||
11 | - reg : Offset and length of the register set for the device. | 11 | - reg : Offset and length of the register set for the device. |
12 | 12 | ||
13 | - interrupts : Contains the spdif interrupt. | 13 | - interrupts : Contains the spdif interrupt. |
14 | 14 | ||
15 | - dmas : Generic dma devicetree binding as described in | 15 | - dmas : Generic dma devicetree binding as described in |
16 | Documentation/devicetree/bindings/dma/dma.txt. | 16 | Documentation/devicetree/bindings/dma/dma.txt. |
17 | 17 | ||
18 | - dma-names : Two dmas have to be defined, "tx" and "rx". | 18 | - dma-names : Two dmas have to be defined, "tx" and "rx". |
19 | 19 | ||
20 | - clocks : Contains an entry for each entry in clock-names. | 20 | - clocks : Contains an entry for each entry in clock-names. |
21 | 21 | ||
22 | - clock-names : Includes the following entries: | 22 | - clock-names : Includes the following entries: |
23 | "core" The core clock of spdif controller | 23 | "core" The core clock of spdif controller. |
24 | "rxtx<0-7>" Clock source list for tx and rx clock. | 24 | "rxtx<0-7>" Clock source list for tx and rx clock. |
25 | This clock list should be identical to | 25 | This clock list should be identical to the source |
26 | the source list connecting to the spdif | 26 | list connecting to the spdif clock mux in "SPDIF |
27 | clock mux in "SPDIF Transceiver Clock | 27 | Transceiver Clock Diagram" of SoC reference manual. |
28 | Diagram" of SoC reference manual. It | 28 | It can also be referred to TxClk_Source bit of |
29 | can also be referred to TxClk_Source | 29 | register SPDIF_STC. |
30 | bit of register SPDIF_STC. | ||
31 | 30 | ||
32 | - big-endian : If this property is absent, the native endian mode will | 31 | - big-endian : If this property is absent, the native endian mode |
33 | be in use as default, or the big endian mode will be in use for all the | 32 | will be in use as default, or the big endian mode |
34 | device registers. | 33 | will be in use for all the device registers. |
35 | 34 | ||
36 | Example: | 35 | Example: |
37 | 36 | ||
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt index 4956b14d4b06..044e5d76e2dd 100644 --- a/Documentation/devicetree/bindings/sound/fsl-sai.txt +++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt | |||
@@ -5,32 +5,48 @@ which provides a synchronous audio interface that supports fullduplex | |||
5 | serial interfaces with frame synchronization such as I2S, AC97, TDM, and | 5 | serial interfaces with frame synchronization such as I2S, AC97, TDM, and |
6 | codec/DSP interfaces. | 6 | codec/DSP interfaces. |
7 | 7 | ||
8 | |||
9 | Required properties: | 8 | Required properties: |
10 | - compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai". | 9 | |
11 | - reg: Offset and length of the register set for the device. | 10 | - compatible : Compatible list, contains "fsl,vf610-sai" or |
12 | - clocks: Must contain an entry for each entry in clock-names. | 11 | "fsl,imx6sx-sai". |
13 | - clock-names : Must include the "bus" for register access and "mclk1" "mclk2" | 12 | |
14 | "mclk3" for bit clock and frame clock providing. | 13 | - reg : Offset and length of the register set for the device. |
15 | - dmas : Generic dma devicetree binding as described in | 14 | |
16 | Documentation/devicetree/bindings/dma/dma.txt. | 15 | - clocks : Must contain an entry for each entry in clock-names. |
17 | - dma-names : Two dmas have to be defined, "tx" and "rx". | 16 | |
18 | - pinctrl-names: Must contain a "default" entry. | 17 | - clock-names : Must include the "bus" for register access and |
19 | - pinctrl-NNN: One property must exist for each entry in pinctrl-names. | 18 | "mclk1", "mclk2", "mclk3" for bit clock and frame |
20 | See ../pinctrl/pinctrl-bindings.txt for details of the property values. | 19 | clock providing. |
21 | - big-endian: Boolean property, required if all the FTM_PWM registers | 20 | - dmas : Generic dma devicetree binding as described in |
22 | are big-endian rather than little-endian. | 21 | Documentation/devicetree/bindings/dma/dma.txt. |
23 | - lsb-first: Configures whether the LSB or the MSB is transmitted first for | 22 | |
24 | the fifo data. If this property is absent, the MSB is transmitted first as | 23 | - dma-names : Two dmas have to be defined, "tx" and "rx". |
25 | default, or the LSB is transmitted first. | 24 | |
26 | - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating | 25 | - pinctrl-names : Must contain a "default" entry. |
27 | that SAI will work in the synchronous mode (sync Tx with Rx) which means | 26 | |
28 | both the transimitter and receiver will send and receive data by following | 27 | - pinctrl-NNN : One property must exist for each entry in |
29 | receiver's bit clocks and frame sync clocks. | 28 | pinctrl-names. See ../pinctrl/pinctrl-bindings.txt |
30 | - fsl,sai-asynchronous: This is a boolean property. If present, indicating | 29 | for details of the property values. |
31 | that SAI will work in the asynchronous mode, which means both transimitter | 30 | |
32 | and receiver will send and receive data by following their own bit clocks | 31 | - big-endian : Boolean property, required if all the FTM_PWM |
33 | and frame sync clocks separately. | 32 | registers are big-endian rather than little-endian. |
33 | |||
34 | - lsb-first : Configures whether the LSB or the MSB is transmitted | ||
35 | first for the fifo data. If this property is absent, | ||
36 | the MSB is transmitted first as default, or the LSB | ||
37 | is transmitted first. | ||
38 | |||
39 | - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating | ||
40 | that SAI will work in the synchronous mode (sync Tx | ||
41 | with Rx) which means both the transimitter and the | ||
42 | receiver will send and receive data by following | ||
43 | receiver's bit clocks and frame sync clocks. | ||
44 | |||
45 | - fsl,sai-asynchronous: This is a boolean property. If present, indicating | ||
46 | that SAI will work in the asynchronous mode, which | ||
47 | means both transimitter and receiver will send and | ||
48 | receive data by following their own bit clocks and | ||
49 | frame sync clocks separately. | ||
34 | 50 | ||
35 | Note: | 51 | Note: |
36 | - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the | 52 | - If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the |
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt index e4acdd891e49..2f89db88fd57 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt | |||
@@ -1,33 +1,40 @@ | |||
1 | Freescale i.MX audio complex with SGTL5000 codec | 1 | Freescale i.MX audio complex with SGTL5000 codec |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "fsl,imx-audio-sgtl5000" | 4 | |
5 | - model : The user-visible name of this sound complex | 5 | - compatible : "fsl,imx-audio-sgtl5000" |
6 | - ssi-controller : The phandle of the i.MX SSI controller | 6 | |
7 | - audio-codec : The phandle of the SGTL5000 audio codec | 7 | - model : The user-visible name of this sound complex |
8 | - audio-routing : A list of the connections between audio components. | 8 | |
9 | Each entry is a pair of strings, the first being the connection's sink, | 9 | - ssi-controller : The phandle of the i.MX SSI controller |
10 | the second being the connection's source. Valid names could be power | 10 | |
11 | supplies, SGTL5000 pins, and the jacks on the board: | 11 | - audio-codec : The phandle of the SGTL5000 audio codec |
12 | 12 | ||
13 | Power supplies: | 13 | - audio-routing : A list of the connections between audio components. |
14 | * Mic Bias | 14 | Each entry is a pair of strings, the first being the |
15 | 15 | connection's sink, the second being the connection's | |
16 | SGTL5000 pins: | 16 | source. Valid names could be power supplies, SGTL5000 |
17 | * MIC_IN | 17 | pins, and the jacks on the board: |
18 | * LINE_IN | 18 | |
19 | * HP_OUT | 19 | Power supplies: |
20 | * LINE_OUT | 20 | * Mic Bias |
21 | 21 | ||
22 | Board connectors: | 22 | SGTL5000 pins: |
23 | * Mic Jack | 23 | * MIC_IN |
24 | * Line In Jack | 24 | * LINE_IN |
25 | * Headphone Jack | 25 | * HP_OUT |
26 | * Line Out Jack | 26 | * LINE_OUT |
27 | * Ext Spk | 27 | |
28 | 28 | Board connectors: | |
29 | - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) | 29 | * Mic Jack |
30 | - mux-ext-port : The external port of the i.MX audio muxer | 30 | * Line In Jack |
31 | * Headphone Jack | ||
32 | * Line Out Jack | ||
33 | * Ext Spk | ||
34 | |||
35 | - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) | ||
36 | |||
37 | - mux-ext-port : The external port of the i.MX audio muxer | ||
31 | 38 | ||
32 | Note: The AUDMUX port numbering should start at 1, which is consistent with | 39 | Note: The AUDMUX port numbering should start at 1, which is consistent with |
33 | hardware manual. | 40 | hardware manual. |
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt index 7d13479f9c3c..da84a442ccea 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt | |||
@@ -2,23 +2,25 @@ Freescale i.MX audio complex with S/PDIF transceiver | |||
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | 4 | ||
5 | - compatible : "fsl,imx-audio-spdif" | 5 | - compatible : "fsl,imx-audio-spdif" |
6 | 6 | ||
7 | - model : The user-visible name of this sound complex | 7 | - model : The user-visible name of this sound complex |
8 | 8 | ||
9 | - spdif-controller : The phandle of the i.MX S/PDIF controller | 9 | - spdif-controller : The phandle of the i.MX S/PDIF controller |
10 | 10 | ||
11 | 11 | ||
12 | Optional properties: | 12 | Optional properties: |
13 | 13 | ||
14 | - spdif-out : This is a boolean property. If present, the transmitting | 14 | - spdif-out : This is a boolean property. If present, the |
15 | function of S/PDIF will be enabled, indicating there's a physical | 15 | transmitting function of S/PDIF will be enabled, |
16 | S/PDIF out connector/jack on the board or it's connecting to some | 16 | indicating there's a physical S/PDIF out connector |
17 | other IP block, such as an HDMI encoder/display-controller. | 17 | or jack on the board or it's connecting to some |
18 | other IP block, such as an HDMI encoder or | ||
19 | display-controller. | ||
18 | 20 | ||
19 | - spdif-in : This is a boolean property. If present, the receiving | 21 | - spdif-in : This is a boolean property. If present, the receiving |
20 | function of S/PDIF will be enabled, indicating there's a physical | 22 | function of S/PDIF will be enabled, indicating there |
21 | S/PDIF in connector/jack on the board. | 23 | is a physical S/PDIF in connector/jack on the board. |
22 | 24 | ||
23 | * Note: At least one of these two properties should be set in the DT binding. | 25 | * Note: At least one of these two properties should be set in the DT binding. |
24 | 26 | ||
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt index f49450a87890..acea71bee34f 100644 --- a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt +++ b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt | |||
@@ -1,25 +1,32 @@ | |||
1 | Freescale i.MX audio complex with WM8962 codec | 1 | Freescale i.MX audio complex with WM8962 codec |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "fsl,imx-audio-wm8962" | 4 | |
5 | - model : The user-visible name of this sound complex | 5 | - compatible : "fsl,imx-audio-wm8962" |
6 | - ssi-controller : The phandle of the i.MX SSI controller | 6 | |
7 | - audio-codec : The phandle of the WM8962 audio codec | 7 | - model : The user-visible name of this sound complex |
8 | - audio-routing : A list of the connections between audio components. | 8 | |
9 | Each entry is a pair of strings, the first being the connection's sink, | 9 | - ssi-controller : The phandle of the i.MX SSI controller |
10 | the second being the connection's source. Valid names could be power | 10 | |
11 | supplies, WM8962 pins, and the jacks on the board: | 11 | - audio-codec : The phandle of the WM8962 audio codec |
12 | 12 | ||
13 | Power supplies: | 13 | - audio-routing : A list of the connections between audio components. |
14 | * Mic Bias | 14 | Each entry is a pair of strings, the first being the |
15 | 15 | connection's sink, the second being the connection's | |
16 | Board connectors: | 16 | source. Valid names could be power supplies, WM8962 |
17 | * Mic Jack | 17 | pins, and the jacks on the board: |
18 | * Headphone Jack | 18 | |
19 | * Ext Spk | 19 | Power supplies: |
20 | 20 | * Mic Bias | |
21 | - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) | 21 | |
22 | - mux-ext-port : The external port of the i.MX audio muxer | 22 | Board connectors: |
23 | * Mic Jack | ||
24 | * Headphone Jack | ||
25 | * Ext Spk | ||
26 | |||
27 | - mux-int-port : The internal port of the i.MX audio muxer (AUDMUX) | ||
28 | |||
29 | - mux-ext-port : The external port of the i.MX audio muxer | ||
23 | 30 | ||
24 | Note: The AUDMUX port numbering should start at 1, which is consistent with | 31 | Note: The AUDMUX port numbering should start at 1, which is consistent with |
25 | hardware manual. | 32 | hardware manual. |
diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.txt b/Documentation/devicetree/bindings/sound/imx-audmux.txt index f88a00e54c63..b30a737e209e 100644 --- a/Documentation/devicetree/bindings/sound/imx-audmux.txt +++ b/Documentation/devicetree/bindings/sound/imx-audmux.txt | |||
@@ -1,18 +1,24 @@ | |||
1 | Freescale Digital Audio Mux (AUDMUX) device | 1 | Freescale Digital Audio Mux (AUDMUX) device |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21, | 4 | |
5 | or "fsl,imx31-audmux" for the version firstly used on i.MX31. | 5 | - compatible : "fsl,imx21-audmux" for AUDMUX version firstly used |
6 | - reg : Should contain AUDMUX registers location and length | 6 | on i.MX21, or "fsl,imx31-audmux" for the version |
7 | firstly used on i.MX31. | ||
8 | |||
9 | - reg : Should contain AUDMUX registers location and length. | ||
7 | 10 | ||
8 | An initial configuration can be setup using child nodes. | 11 | An initial configuration can be setup using child nodes. |
9 | 12 | ||
10 | Required properties of optional child nodes: | 13 | Required properties of optional child nodes: |
11 | - fsl,audmux-port : Integer of the audmux port that is configured by this | 14 | |
12 | child node. | 15 | - fsl,audmux-port : Integer of the audmux port that is configured by this |
13 | - fsl,port-config : List of configuration options for the specific port. For | 16 | child node. |
14 | imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For | 17 | |
15 | imx21-audmux it is a list of pcr values. | 18 | - fsl,port-config : List of configuration options for the specific port. |
19 | For imx31-audmux and above, it is a list of tuples | ||
20 | <ptcr pdcr>. For imx21-audmux it is a list of pcr | ||
21 | values. | ||
16 | 22 | ||
17 | Example: | 23 | Example: |
18 | 24 | ||
diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt index c454e67f54bb..aa802a274520 100644 --- a/Documentation/devicetree/bindings/sound/max98090.txt +++ b/Documentation/devicetree/bindings/sound/max98090.txt | |||
@@ -16,6 +16,8 @@ Optional properties: | |||
16 | 16 | ||
17 | - clock-names: Should be "mclk" | 17 | - clock-names: Should be "mclk" |
18 | 18 | ||
19 | - maxim,dmic-freq: Frequency at which to clock DMIC | ||
20 | |||
19 | Pins on the device (for linking into audio routes): | 21 | Pins on the device (for linking into audio routes): |
20 | 22 | ||
21 | * MIC1 | 23 | * MIC1 |
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt index c5be003f413e..0d0ab51105b0 100644 --- a/Documentation/devicetree/bindings/sound/renesas,fsi.txt +++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt | |||
@@ -1,11 +1,16 @@ | |||
1 | Renesas FSI | 1 | Renesas FSI |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "renesas,sh_fsi2" or "renesas,sh_fsi" | 4 | - compatible : "renesas,fsi2-<soctype>", |
5 | "renesas,sh_fsi2" or "renesas,sh_fsi" as | ||
6 | fallback. | ||
7 | Examples with soctypes are: | ||
8 | - "renesas,fsi2-r8a7740" (R-Mobile A1) | ||
9 | - "renesas,fsi2-sh73a0" (SH-Mobile AG5) | ||
5 | - reg : Should contain the register physical address and length | 10 | - reg : Should contain the register physical address and length |
6 | - interrupts : Should contain FSI interrupt | 11 | - interrupts : Should contain FSI interrupt |
7 | 12 | ||
8 | - fsia,spdif-connection : FSI is connected by S/PDFI | 13 | - fsia,spdif-connection : FSI is connected by S/PDIF |
9 | - fsia,stream-mode-support : FSI supports 16bit stream mode. | 14 | - fsia,stream-mode-support : FSI supports 16bit stream mode. |
10 | - fsia,use-internal-clock : FSI uses internal clock when master mode. | 15 | - fsia,use-internal-clock : FSI uses internal clock when master mode. |
11 | 16 | ||
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index aa697abf337e..2dd690bc19cc 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt | |||
@@ -1,8 +1,12 @@ | |||
1 | Renesas R-Car sound | 1 | Renesas R-Car sound |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "renesas,rcar_sound-gen1" if generation1 | 4 | - compatible : "renesas,rcar_sound-<soctype>", fallbacks |
5 | "renesas,rcar_sound-gen1" if generation1, and | ||
5 | "renesas,rcar_sound-gen2" if generation2 | 6 | "renesas,rcar_sound-gen2" if generation2 |
7 | Examples with soctypes are: | ||
8 | - "renesas,rcar_sound-r8a7790" (R-Car H2) | ||
9 | - "renesas,rcar_sound-r8a7791" (R-Car M2-W) | ||
6 | - reg : Should contain the register physical address. | 10 | - reg : Should contain the register physical address. |
7 | required register is | 11 | required register is |
8 | SRU/ADG/SSI if generation1 | 12 | SRU/ADG/SSI if generation1 |
@@ -35,9 +39,9 @@ DAI subnode properties: | |||
35 | 39 | ||
36 | Example: | 40 | Example: |
37 | 41 | ||
38 | rcar_sound: rcar_sound@0xffd90000 { | 42 | rcar_sound: rcar_sound@ec500000 { |
39 | #sound-dai-cells = <1>; | 43 | #sound-dai-cells = <1>; |
40 | compatible = "renesas,rcar_sound-gen2"; | 44 | compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2"; |
41 | reg = <0 0xec500000 0 0x1000>, /* SCU */ | 45 | reg = <0 0xec500000 0 0x1000>, /* SCU */ |
42 | <0 0xec5a0000 0 0x100>, /* ADG */ | 46 | <0 0xec5a0000 0 0x100>, /* ADG */ |
43 | <0 0xec540000 0 0x1000>, /* SSIU */ | 47 | <0 0xec540000 0 0x1000>, /* SSIU */ |
diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt new file mode 100644 index 000000000000..92b986ca337b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rt5631.txt | |||
@@ -0,0 +1,48 @@ | |||
1 | ALC5631/RT5631 audio CODEC | ||
2 | |||
3 | This device supports I2C only. | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible : "realtek,alc5631" or "realtek,rt5631" | ||
8 | |||
9 | - reg : the I2C address of the device. | ||
10 | |||
11 | Pins on the device (for linking into audio routes): | ||
12 | |||
13 | * SPK_OUT_R_P | ||
14 | * SPK_OUT_R_N | ||
15 | * SPK_OUT_L_P | ||
16 | * SPK_OUT_L_N | ||
17 | * HP_OUT_L | ||
18 | * HP_OUT_R | ||
19 | * AUX_OUT2_LP | ||
20 | * AUX_OUT2_RN | ||
21 | * AUX_OUT1_LP | ||
22 | * AUX_OUT1_RN | ||
23 | * AUX_IN_L_JD | ||
24 | * AUX_IN_R_JD | ||
25 | * MONO_IN_P | ||
26 | * MONO_IN_N | ||
27 | * MIC1_P | ||
28 | * MIC1_N | ||
29 | * MIC2_P | ||
30 | * MIC2_N | ||
31 | * MONO_OUT_P | ||
32 | * MONO_OUT_N | ||
33 | * MICBIAS1 | ||
34 | * MICBIAS2 | ||
35 | |||
36 | Example: | ||
37 | |||
38 | alc5631: alc5631@1a { | ||
39 | compatible = "realtek,alc5631"; | ||
40 | reg = <0x1a>; | ||
41 | }; | ||
42 | |||
43 | or | ||
44 | |||
45 | rt5631: rt5631@1a { | ||
46 | compatible = "realtek,rt5631"; | ||
47 | reg = <0x1a>; | ||
48 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt index 0701b834fc73..740ff771aa8b 100644 --- a/Documentation/devicetree/bindings/sound/rt5677.txt +++ b/Documentation/devicetree/bindings/sound/rt5677.txt | |||
@@ -27,6 +27,21 @@ Optional properties: | |||
27 | Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, | 27 | Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential, |
28 | rather than single-ended. | 28 | rather than single-ended. |
29 | 29 | ||
30 | - realtek,gpio-config | ||
31 | Array of six 8bit elements that configures GPIO. | ||
32 | 0 - floating (reset value) | ||
33 | 1 - pull down | ||
34 | 2 - pull up | ||
35 | |||
36 | - realtek,jd1-gpio | ||
37 | Configures GPIO Mic Jack detection 1. | ||
38 | Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively. | ||
39 | |||
40 | - realtek,jd2-gpio | ||
41 | - realtek,jd3-gpio | ||
42 | Configures GPIO Mic Jack detection 2 and 3. | ||
43 | Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively. | ||
44 | |||
30 | Pins on the device (for linking into audio routes): | 45 | Pins on the device (for linking into audio routes): |
31 | 46 | ||
32 | * IN1P | 47 | * IN1P |
@@ -56,4 +71,6 @@ rt5677 { | |||
56 | realtek,pow-ldo2-gpio = | 71 | realtek,pow-ldo2-gpio = |
57 | <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; | 72 | <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>; |
58 | realtek,in1-differential = "true"; | 73 | realtek,in1-differential = "true"; |
74 | realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */ | ||
75 | realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */ | ||
59 | }; | 76 | }; |
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt index 7386d444ada1..d188296bb6ec 100644 --- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt +++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt | |||
@@ -6,10 +6,17 @@ Required SoC Specific Properties: | |||
6 | - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S. | 6 | - samsung,s3c6410-i2s: for 8/16/24bit stereo I2S. |
7 | - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with | 7 | - samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with |
8 | secondary fifo, s/w reset control and internal mux for root clk src. | 8 | secondary fifo, s/w reset control and internal mux for root clk src. |
9 | - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with | 9 | - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for |
10 | secondary fifo, s/w reset control, internal mux for root clk src and | 10 | playback, sterio channel capture, secondary fifo using internal |
11 | TDM support. TDM (Time division multiplexing) is to allow transfer of | 11 | or external dma, s/w reset control, internal mux for root clk src |
12 | multiple channel audio data on single data line. | 12 | and 7.1 channel TDM support for playback. TDM (Time division multiplexing) |
13 | is to allow transfer of multiple channel audio data on single data line. | ||
14 | - samsung,exynos7-i2s: with all the available features of exynos5 i2s, | ||
15 | exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo | ||
16 | with only external dma and more no.of root clk sampling frequencies. | ||
17 | - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports | ||
18 | stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with | ||
19 | slightly modified bit offsets. | ||
13 | 20 | ||
14 | - reg: physical base address of the controller and length of memory mapped | 21 | - reg: physical base address of the controller and length of memory mapped |
15 | region. | 22 | region. |
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index d556dcb8816b..0e5e4eb3ef1b 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt | |||
@@ -7,6 +7,17 @@ Required properties: | |||
7 | 7 | ||
8 | - clocks : the clock provider of SYS_MCLK | 8 | - clocks : the clock provider of SYS_MCLK |
9 | 9 | ||
10 | - micbias-resistor-k-ohms : the bias resistor to be used in kOmhs | ||
11 | The resistor can take values of 2k, 4k or 8k. | ||
12 | If set to 0 it will be off. | ||
13 | If this node is not mentioned or if the value is unknown, then | ||
14 | micbias resistor is set to 4K. | ||
15 | |||
16 | - micbias-voltage-m-volts : the bias voltage to be used in mVolts | ||
17 | The voltage can take values from 1.25V to 3V by 250mV steps | ||
18 | If this node is not mentionned or the value is unknown, then | ||
19 | the value is set to 1.25V. | ||
20 | |||
10 | - VDDA-supply : the regulator provider of VDDA | 21 | - VDDA-supply : the regulator provider of VDDA |
11 | 22 | ||
12 | - VDDIO-supply: the regulator provider of VDDIO | 23 | - VDDIO-supply: the regulator provider of VDDIO |
@@ -21,6 +32,8 @@ codec: sgtl5000@0a { | |||
21 | compatible = "fsl,sgtl5000"; | 32 | compatible = "fsl,sgtl5000"; |
22 | reg = <0x0a>; | 33 | reg = <0x0a>; |
23 | clocks = <&clks 150>; | 34 | clocks = <&clks 150>; |
35 | micbias-resistor-k-ohms = <2>; | ||
36 | micbias-voltage-m-volts = <2250>; | ||
24 | VDDA-supply = <®_3p3v>; | 37 | VDDA-supply = <®_3p3v>; |
25 | VDDIO-supply = <®_3p3v>; | 38 | VDDIO-supply = <®_3p3v>; |
26 | }; | 39 | }; |
diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt new file mode 100644 index 000000000000..e8bf23eb1803 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt | |||
@@ -0,0 +1,26 @@ | |||
1 | Texas Instruments TS3A227E | ||
2 | Autonomous Audio Accessory Detection and Configuration Switch | ||
3 | |||
4 | The TS3A227E detect headsets of 3-ring and 4-ring standards and | ||
5 | switches automatically to route the microphone correctly. It also | ||
6 | handles key press detection in accordance with the Android audio | ||
7 | headset specification v1.0. | ||
8 | |||
9 | Required properties: | ||
10 | |||
11 | - compatible: Should contain "ti,ts3a227e". | ||
12 | - reg: The i2c address. Should contain <0x3b>. | ||
13 | - interrupt-parent: The parent interrupt controller | ||
14 | - interrupts: Interrupt number for /INT pin from the 227e | ||
15 | |||
16 | |||
17 | Examples: | ||
18 | |||
19 | i2c { | ||
20 | ts3a227e@3b { | ||
21 | compatible = "ti,ts3a227e"; | ||
22 | reg = <0x3b>; | ||
23 | interrupt-parent = <&gpio>; | ||
24 | interrupts = <3 IRQ_TYPE_LEVEL_LOW>; | ||
25 | }; | ||
26 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/wm8960.txt b/Documentation/devicetree/bindings/sound/wm8960.txt new file mode 100644 index 000000000000..2deb8a3da9c5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/wm8960.txt | |||
@@ -0,0 +1,31 @@ | |||
1 | WM8960 audio CODEC | ||
2 | |||
3 | This device supports I2C only. | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible : "wlf,wm8960" | ||
8 | |||
9 | - reg : the I2C address of the device. | ||
10 | |||
11 | Optional properties: | ||
12 | - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of | ||
13 | R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins | ||
14 | will be disabled only when ADC (Left and Right) and DAC (Left and Right) | ||
15 | are disabled. | ||
16 | When wm8960 works on synchronize mode and DACLRC pin is used to supply | ||
17 | frame clock, it will no frame clock for captrue unless enable DAC to enable | ||
18 | DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue. | ||
19 | |||
20 | - wlf,capless: This is a boolean property. If present, OUT3 pin will be | ||
21 | enabled and disabled together with HP_L and HP_R pins in response to jack | ||
22 | detect events. | ||
23 | |||
24 | Example: | ||
25 | |||
26 | codec: wm8960@1a { | ||
27 | compatible = "wlf,wm8960"; | ||
28 | reg = <0x1a>; | ||
29 | |||
30 | wlf,shared-lrclk; | ||
31 | }; | ||
diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 412f45ca2d73..1d6d02d6ba52 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt | |||
@@ -136,7 +136,7 @@ SOF_TIMESTAMPING_OPT_ID: | |||
136 | 136 | ||
137 | This option is implemented only for transmit timestamps. There, the | 137 | This option is implemented only for transmit timestamps. There, the |
138 | timestamp is always looped along with a struct sock_extended_err. | 138 | timestamp is always looped along with a struct sock_extended_err. |
139 | The option modifies field ee_info to pass an id that is unique | 139 | The option modifies field ee_data to pass an id that is unique |
140 | among all possibly concurrently outstanding timestamp requests for | 140 | among all possibly concurrently outstanding timestamp requests for |
141 | that socket. In practice, it is a monotonically increasing u32 | 141 | that socket. In practice, it is a monotonically increasing u32 |
142 | (that wraps). | 142 | (that wraps). |
diff --git a/MAINTAINERS b/MAINTAINERS index 0ff630de8a6d..dd9a4e979a08 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1828,7 +1828,7 @@ F: include/net/ax25.h | |||
1828 | F: net/ax25/ | 1828 | F: net/ax25/ |
1829 | 1829 | ||
1830 | AZ6007 DVB DRIVER | 1830 | AZ6007 DVB DRIVER |
1831 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 1831 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
1832 | L: linux-media@vger.kernel.org | 1832 | L: linux-media@vger.kernel.org |
1833 | W: http://linuxtv.org | 1833 | W: http://linuxtv.org |
1834 | T: git git://linuxtv.org/media_tree.git | 1834 | T: git git://linuxtv.org/media_tree.git |
@@ -2198,7 +2198,7 @@ F: Documentation/filesystems/btrfs.txt | |||
2198 | F: fs/btrfs/ | 2198 | F: fs/btrfs/ |
2199 | 2199 | ||
2200 | BTTV VIDEO4LINUX DRIVER | 2200 | BTTV VIDEO4LINUX DRIVER |
2201 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 2201 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
2202 | L: linux-media@vger.kernel.org | 2202 | L: linux-media@vger.kernel.org |
2203 | W: http://linuxtv.org | 2203 | W: http://linuxtv.org |
2204 | T: git git://linuxtv.org/media_tree.git | 2204 | T: git git://linuxtv.org/media_tree.git |
@@ -2719,7 +2719,7 @@ F: drivers/media/common/cx2341x* | |||
2719 | F: include/media/cx2341x* | 2719 | F: include/media/cx2341x* |
2720 | 2720 | ||
2721 | CX88 VIDEO4LINUX DRIVER | 2721 | CX88 VIDEO4LINUX DRIVER |
2722 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 2722 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
2723 | L: linux-media@vger.kernel.org | 2723 | L: linux-media@vger.kernel.org |
2724 | W: http://linuxtv.org | 2724 | W: http://linuxtv.org |
2725 | T: git git://linuxtv.org/media_tree.git | 2725 | T: git git://linuxtv.org/media_tree.git |
@@ -3402,7 +3402,7 @@ F: fs/ecryptfs/ | |||
3402 | EDAC-CORE | 3402 | EDAC-CORE |
3403 | M: Doug Thompson <dougthompson@xmission.com> | 3403 | M: Doug Thompson <dougthompson@xmission.com> |
3404 | M: Borislav Petkov <bp@alien8.de> | 3404 | M: Borislav Petkov <bp@alien8.de> |
3405 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3405 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3406 | L: linux-edac@vger.kernel.org | 3406 | L: linux-edac@vger.kernel.org |
3407 | W: bluesmoke.sourceforge.net | 3407 | W: bluesmoke.sourceforge.net |
3408 | S: Supported | 3408 | S: Supported |
@@ -3451,7 +3451,7 @@ S: Maintained | |||
3451 | F: drivers/edac/e7xxx_edac.c | 3451 | F: drivers/edac/e7xxx_edac.c |
3452 | 3452 | ||
3453 | EDAC-GHES | 3453 | EDAC-GHES |
3454 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3454 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3455 | L: linux-edac@vger.kernel.org | 3455 | L: linux-edac@vger.kernel.org |
3456 | W: bluesmoke.sourceforge.net | 3456 | W: bluesmoke.sourceforge.net |
3457 | S: Maintained | 3457 | S: Maintained |
@@ -3479,21 +3479,21 @@ S: Maintained | |||
3479 | F: drivers/edac/i5000_edac.c | 3479 | F: drivers/edac/i5000_edac.c |
3480 | 3480 | ||
3481 | EDAC-I5400 | 3481 | EDAC-I5400 |
3482 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3482 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3483 | L: linux-edac@vger.kernel.org | 3483 | L: linux-edac@vger.kernel.org |
3484 | W: bluesmoke.sourceforge.net | 3484 | W: bluesmoke.sourceforge.net |
3485 | S: Maintained | 3485 | S: Maintained |
3486 | F: drivers/edac/i5400_edac.c | 3486 | F: drivers/edac/i5400_edac.c |
3487 | 3487 | ||
3488 | EDAC-I7300 | 3488 | EDAC-I7300 |
3489 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3489 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3490 | L: linux-edac@vger.kernel.org | 3490 | L: linux-edac@vger.kernel.org |
3491 | W: bluesmoke.sourceforge.net | 3491 | W: bluesmoke.sourceforge.net |
3492 | S: Maintained | 3492 | S: Maintained |
3493 | F: drivers/edac/i7300_edac.c | 3493 | F: drivers/edac/i7300_edac.c |
3494 | 3494 | ||
3495 | EDAC-I7CORE | 3495 | EDAC-I7CORE |
3496 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3496 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3497 | L: linux-edac@vger.kernel.org | 3497 | L: linux-edac@vger.kernel.org |
3498 | W: bluesmoke.sourceforge.net | 3498 | W: bluesmoke.sourceforge.net |
3499 | S: Maintained | 3499 | S: Maintained |
@@ -3536,7 +3536,7 @@ S: Maintained | |||
3536 | F: drivers/edac/r82600_edac.c | 3536 | F: drivers/edac/r82600_edac.c |
3537 | 3537 | ||
3538 | EDAC-SBRIDGE | 3538 | EDAC-SBRIDGE |
3539 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3539 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3540 | L: linux-edac@vger.kernel.org | 3540 | L: linux-edac@vger.kernel.org |
3541 | W: bluesmoke.sourceforge.net | 3541 | W: bluesmoke.sourceforge.net |
3542 | S: Maintained | 3542 | S: Maintained |
@@ -3596,7 +3596,7 @@ S: Maintained | |||
3596 | F: drivers/net/ethernet/ibm/ehea/ | 3596 | F: drivers/net/ethernet/ibm/ehea/ |
3597 | 3597 | ||
3598 | EM28XX VIDEO4LINUX DRIVER | 3598 | EM28XX VIDEO4LINUX DRIVER |
3599 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 3599 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
3600 | L: linux-media@vger.kernel.org | 3600 | L: linux-media@vger.kernel.org |
3601 | W: http://linuxtv.org | 3601 | W: http://linuxtv.org |
3602 | T: git git://linuxtv.org/media_tree.git | 3602 | T: git git://linuxtv.org/media_tree.git |
@@ -5962,7 +5962,7 @@ S: Maintained | |||
5962 | F: drivers/media/radio/radio-maxiradio* | 5962 | F: drivers/media/radio/radio-maxiradio* |
5963 | 5963 | ||
5964 | MEDIA INPUT INFRASTRUCTURE (V4L/DVB) | 5964 | MEDIA INPUT INFRASTRUCTURE (V4L/DVB) |
5965 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 5965 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
5966 | P: LinuxTV.org Project | 5966 | P: LinuxTV.org Project |
5967 | L: linux-media@vger.kernel.org | 5967 | L: linux-media@vger.kernel.org |
5968 | W: http://linuxtv.org | 5968 | W: http://linuxtv.org |
@@ -6601,6 +6601,12 @@ S: Supported | |||
6601 | F: drivers/gpu/drm/i2c/tda998x_drv.c | 6601 | F: drivers/gpu/drm/i2c/tda998x_drv.c |
6602 | F: include/drm/i2c/tda998x.h | 6602 | F: include/drm/i2c/tda998x.h |
6603 | 6603 | ||
6604 | NXP TFA9879 DRIVER | ||
6605 | M: Peter Rosin <peda@axentia.se> | ||
6606 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
6607 | S: Maintained | ||
6608 | F: sound/soc/codecs/tfa9879* | ||
6609 | |||
6604 | OMAP SUPPORT | 6610 | OMAP SUPPORT |
6605 | M: Tony Lindgren <tony@atomide.com> | 6611 | M: Tony Lindgren <tony@atomide.com> |
6606 | L: linux-omap@vger.kernel.org | 6612 | L: linux-omap@vger.kernel.org |
@@ -8013,7 +8019,7 @@ S: Odd Fixes | |||
8013 | F: drivers/media/i2c/saa6588* | 8019 | F: drivers/media/i2c/saa6588* |
8014 | 8020 | ||
8015 | SAA7134 VIDEO4LINUX DRIVER | 8021 | SAA7134 VIDEO4LINUX DRIVER |
8016 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 8022 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
8017 | L: linux-media@vger.kernel.org | 8023 | L: linux-media@vger.kernel.org |
8018 | W: http://linuxtv.org | 8024 | W: http://linuxtv.org |
8019 | T: git git://linuxtv.org/media_tree.git | 8025 | T: git git://linuxtv.org/media_tree.git |
@@ -8471,7 +8477,7 @@ S: Maintained | |||
8471 | F: drivers/media/radio/si4713/radio-usb-si4713.c | 8477 | F: drivers/media/radio/si4713/radio-usb-si4713.c |
8472 | 8478 | ||
8473 | SIANO DVB DRIVER | 8479 | SIANO DVB DRIVER |
8474 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 8480 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
8475 | L: linux-media@vger.kernel.org | 8481 | L: linux-media@vger.kernel.org |
8476 | W: http://linuxtv.org | 8482 | W: http://linuxtv.org |
8477 | T: git git://linuxtv.org/media_tree.git | 8483 | T: git git://linuxtv.org/media_tree.git |
@@ -8682,7 +8688,9 @@ S: Maintained | |||
8682 | F: drivers/leds/leds-net48xx.c | 8688 | F: drivers/leds/leds-net48xx.c |
8683 | 8689 | ||
8684 | SOFTLOGIC 6x10 MPEG CODEC | 8690 | SOFTLOGIC 6x10 MPEG CODEC |
8685 | M: Ismael Luceno <ismael.luceno@corp.bluecherry.net> | 8691 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> |
8692 | M: Andrey Utkin <andrey.utkin@corp.bluecherry.net> | ||
8693 | M: Andrey Utkin <andrey.krieger.utkin@gmail.com> | ||
8686 | L: linux-media@vger.kernel.org | 8694 | L: linux-media@vger.kernel.org |
8687 | S: Supported | 8695 | S: Supported |
8688 | F: drivers/media/pci/solo6x10/ | 8696 | F: drivers/media/pci/solo6x10/ |
@@ -9156,7 +9164,7 @@ S: Maintained | |||
9156 | F: drivers/media/i2c/tda9840* | 9164 | F: drivers/media/i2c/tda9840* |
9157 | 9165 | ||
9158 | TEA5761 TUNER DRIVER | 9166 | TEA5761 TUNER DRIVER |
9159 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 9167 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
9160 | L: linux-media@vger.kernel.org | 9168 | L: linux-media@vger.kernel.org |
9161 | W: http://linuxtv.org | 9169 | W: http://linuxtv.org |
9162 | T: git git://linuxtv.org/media_tree.git | 9170 | T: git git://linuxtv.org/media_tree.git |
@@ -9164,7 +9172,7 @@ S: Odd fixes | |||
9164 | F: drivers/media/tuners/tea5761.* | 9172 | F: drivers/media/tuners/tea5761.* |
9165 | 9173 | ||
9166 | TEA5767 TUNER DRIVER | 9174 | TEA5767 TUNER DRIVER |
9167 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 9175 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
9168 | L: linux-media@vger.kernel.org | 9176 | L: linux-media@vger.kernel.org |
9169 | W: http://linuxtv.org | 9177 | W: http://linuxtv.org |
9170 | T: git git://linuxtv.org/media_tree.git | 9178 | T: git git://linuxtv.org/media_tree.git |
@@ -9476,7 +9484,7 @@ F: include/linux/shmem_fs.h | |||
9476 | F: mm/shmem.c | 9484 | F: mm/shmem.c |
9477 | 9485 | ||
9478 | TM6000 VIDEO4LINUX DRIVER | 9486 | TM6000 VIDEO4LINUX DRIVER |
9479 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 9487 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
9480 | L: linux-media@vger.kernel.org | 9488 | L: linux-media@vger.kernel.org |
9481 | W: http://linuxtv.org | 9489 | W: http://linuxtv.org |
9482 | T: git git://linuxtv.org/media_tree.git | 9490 | T: git git://linuxtv.org/media_tree.git |
@@ -10297,7 +10305,7 @@ S: Maintained | |||
10297 | F: arch/x86/kernel/cpu/mcheck/* | 10305 | F: arch/x86/kernel/cpu/mcheck/* |
10298 | 10306 | ||
10299 | XC2028/3028 TUNER DRIVER | 10307 | XC2028/3028 TUNER DRIVER |
10300 | M: Mauro Carvalho Chehab <m.chehab@samsung.com> | 10308 | M: Mauro Carvalho Chehab <mchehab@osg.samsung.com> |
10301 | L: linux-media@vger.kernel.org | 10309 | L: linux-media@vger.kernel.org |
10302 | W: http://linuxtv.org | 10310 | W: http://linuxtv.org |
10303 | T: git git://linuxtv.org/media_tree.git | 10311 | T: git git://linuxtv.org/media_tree.git |
@@ -1,7 +1,7 @@ | |||
1 | VERSION = 3 | 1 | VERSION = 3 |
2 | PATCHLEVEL = 18 | 2 | PATCHLEVEL = 18 |
3 | SUBLEVEL = 0 | 3 | SUBLEVEL = 0 |
4 | EXTRAVERSION = -rc6 | 4 | EXTRAVERSION = |
5 | NAME = Diseased Newt | 5 | NAME = Diseased Newt |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts index e51fcef884a4..60429ad1c5d8 100644 --- a/arch/arm/boot/dts/exynos5250-snow.dts +++ b/arch/arm/boot/dts/exynos5250-snow.dts | |||
@@ -624,4 +624,8 @@ | |||
624 | num-cs = <1>; | 624 | num-cs = <1>; |
625 | }; | 625 | }; |
626 | 626 | ||
627 | &usbdrd_dwc3 { | ||
628 | dr_mode = "host"; | ||
629 | }; | ||
630 | |||
627 | #include "cros-ec-keyboard.dtsi" | 631 | #include "cros-ec-keyboard.dtsi" |
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index f21b9aa00fbb..d55c1a2eb798 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi | |||
@@ -555,7 +555,7 @@ | |||
555 | #size-cells = <1>; | 555 | #size-cells = <1>; |
556 | ranges; | 556 | ranges; |
557 | 557 | ||
558 | dwc3 { | 558 | usbdrd_dwc3: dwc3 { |
559 | compatible = "synopsys,dwc3"; | 559 | compatible = "synopsys,dwc3"; |
560 | reg = <0x12000000 0x10000>; | 560 | reg = <0x12000000 0x10000>; |
561 | interrupts = <0 72 0>; | 561 | interrupts = <0 72 0>; |
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig index 72058b8a6f4d..e21ef830a483 100644 --- a/arch/arm/configs/exynos_defconfig +++ b/arch/arm/configs/exynos_defconfig | |||
@@ -142,11 +142,13 @@ CONFIG_MMC_DW_IDMAC=y | |||
142 | CONFIG_MMC_DW_EXYNOS=y | 142 | CONFIG_MMC_DW_EXYNOS=y |
143 | CONFIG_RTC_CLASS=y | 143 | CONFIG_RTC_CLASS=y |
144 | CONFIG_RTC_DRV_MAX77686=y | 144 | CONFIG_RTC_DRV_MAX77686=y |
145 | CONFIG_RTC_DRV_MAX77802=y | ||
145 | CONFIG_RTC_DRV_S5M=y | 146 | CONFIG_RTC_DRV_S5M=y |
146 | CONFIG_RTC_DRV_S3C=y | 147 | CONFIG_RTC_DRV_S3C=y |
147 | CONFIG_DMADEVICES=y | 148 | CONFIG_DMADEVICES=y |
148 | CONFIG_PL330_DMA=y | 149 | CONFIG_PL330_DMA=y |
149 | CONFIG_COMMON_CLK_MAX77686=y | 150 | CONFIG_COMMON_CLK_MAX77686=y |
151 | CONFIG_COMMON_CLK_MAX77802=y | ||
150 | CONFIG_COMMON_CLK_S2MPS11=y | 152 | CONFIG_COMMON_CLK_S2MPS11=y |
151 | CONFIG_EXYNOS_IOMMU=y | 153 | CONFIG_EXYNOS_IOMMU=y |
152 | CONFIG_IIO=y | 154 | CONFIG_IIO=y |
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index fc44d3761f9e..ce73ab635414 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h | |||
@@ -44,16 +44,6 @@ struct cpu_context_save { | |||
44 | __u32 extra[2]; /* Xscale 'acc' register, etc */ | 44 | __u32 extra[2]; /* Xscale 'acc' register, etc */ |
45 | }; | 45 | }; |
46 | 46 | ||
47 | struct arm_restart_block { | ||
48 | union { | ||
49 | /* For user cache flushing */ | ||
50 | struct { | ||
51 | unsigned long start; | ||
52 | unsigned long end; | ||
53 | } cache; | ||
54 | }; | ||
55 | }; | ||
56 | |||
57 | /* | 47 | /* |
58 | * low level task data that entry.S needs immediate access to. | 48 | * low level task data that entry.S needs immediate access to. |
59 | * __switch_to() assumes cpu_context follows immediately after cpu_domain. | 49 | * __switch_to() assumes cpu_context follows immediately after cpu_domain. |
@@ -79,7 +69,6 @@ struct thread_info { | |||
79 | unsigned long thumbee_state; /* ThumbEE Handler Base register */ | 69 | unsigned long thumbee_state; /* ThumbEE Handler Base register */ |
80 | #endif | 70 | #endif |
81 | struct restart_block restart_block; | 71 | struct restart_block restart_block; |
82 | struct arm_restart_block arm_restart_block; | ||
83 | }; | 72 | }; |
84 | 73 | ||
85 | #define INIT_THREAD_INFO(tsk) \ | 74 | #define INIT_THREAD_INFO(tsk) \ |
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 0c8b10801d36..9f5d81881eb6 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -533,8 +533,6 @@ static int bad_syscall(int n, struct pt_regs *regs) | |||
533 | return regs->ARM_r0; | 533 | return regs->ARM_r0; |
534 | } | 534 | } |
535 | 535 | ||
536 | static long do_cache_op_restart(struct restart_block *); | ||
537 | |||
538 | static inline int | 536 | static inline int |
539 | __do_cache_op(unsigned long start, unsigned long end) | 537 | __do_cache_op(unsigned long start, unsigned long end) |
540 | { | 538 | { |
@@ -543,24 +541,8 @@ __do_cache_op(unsigned long start, unsigned long end) | |||
543 | do { | 541 | do { |
544 | unsigned long chunk = min(PAGE_SIZE, end - start); | 542 | unsigned long chunk = min(PAGE_SIZE, end - start); |
545 | 543 | ||
546 | if (signal_pending(current)) { | 544 | if (fatal_signal_pending(current)) |
547 | struct thread_info *ti = current_thread_info(); | 545 | return 0; |
548 | |||
549 | ti->restart_block = (struct restart_block) { | ||
550 | .fn = do_cache_op_restart, | ||
551 | }; | ||
552 | |||
553 | ti->arm_restart_block = (struct arm_restart_block) { | ||
554 | { | ||
555 | .cache = { | ||
556 | .start = start, | ||
557 | .end = end, | ||
558 | }, | ||
559 | }, | ||
560 | }; | ||
561 | |||
562 | return -ERESTART_RESTARTBLOCK; | ||
563 | } | ||
564 | 546 | ||
565 | ret = flush_cache_user_range(start, start + chunk); | 547 | ret = flush_cache_user_range(start, start + chunk); |
566 | if (ret) | 548 | if (ret) |
@@ -573,15 +555,6 @@ __do_cache_op(unsigned long start, unsigned long end) | |||
573 | return 0; | 555 | return 0; |
574 | } | 556 | } |
575 | 557 | ||
576 | static long do_cache_op_restart(struct restart_block *unused) | ||
577 | { | ||
578 | struct arm_restart_block *restart_block; | ||
579 | |||
580 | restart_block = ¤t_thread_info()->arm_restart_block; | ||
581 | return __do_cache_op(restart_block->cache.start, | ||
582 | restart_block->cache.end); | ||
583 | } | ||
584 | |||
585 | static inline int | 558 | static inline int |
586 | do_cache_op(unsigned long start, unsigned long end, int flags) | 559 | do_cache_op(unsigned long start, unsigned long end, int flags) |
587 | { | 560 | { |
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c index 57a403a5c22b..8664ff17cbbe 100644 --- a/arch/arm/kvm/mmu.c +++ b/arch/arm/kvm/mmu.c | |||
@@ -197,7 +197,8 @@ static void unmap_range(struct kvm *kvm, pgd_t *pgdp, | |||
197 | pgd = pgdp + pgd_index(addr); | 197 | pgd = pgdp + pgd_index(addr); |
198 | do { | 198 | do { |
199 | next = kvm_pgd_addr_end(addr, end); | 199 | next = kvm_pgd_addr_end(addr, end); |
200 | unmap_puds(kvm, pgd, addr, next); | 200 | if (!pgd_none(*pgd)) |
201 | unmap_puds(kvm, pgd, addr, next); | ||
201 | } while (pgd++, addr = next, addr != end); | 202 | } while (pgd++, addr = next, addr != end); |
202 | } | 203 | } |
203 | 204 | ||
@@ -834,6 +835,11 @@ static bool kvm_is_write_fault(struct kvm_vcpu *vcpu) | |||
834 | return kvm_vcpu_dabt_iswrite(vcpu); | 835 | return kvm_vcpu_dabt_iswrite(vcpu); |
835 | } | 836 | } |
836 | 837 | ||
838 | static bool kvm_is_device_pfn(unsigned long pfn) | ||
839 | { | ||
840 | return !pfn_valid(pfn); | ||
841 | } | ||
842 | |||
837 | static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | 843 | static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, |
838 | struct kvm_memory_slot *memslot, unsigned long hva, | 844 | struct kvm_memory_slot *memslot, unsigned long hva, |
839 | unsigned long fault_status) | 845 | unsigned long fault_status) |
@@ -904,7 +910,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa, | |||
904 | if (is_error_pfn(pfn)) | 910 | if (is_error_pfn(pfn)) |
905 | return -EFAULT; | 911 | return -EFAULT; |
906 | 912 | ||
907 | if (kvm_is_mmio_pfn(pfn)) | 913 | if (kvm_is_device_pfn(pfn)) |
908 | mem_type = PAGE_S2_DEVICE; | 914 | mem_type = PAGE_S2_DEVICE; |
909 | 915 | ||
910 | spin_lock(&kvm->mmu_lock); | 916 | spin_lock(&kvm->mmu_lock); |
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c index 2bdc3233abe2..044b51185fcc 100644 --- a/arch/arm/mach-mvebu/coherency.c +++ b/arch/arm/mach-mvebu/coherency.c | |||
@@ -400,6 +400,8 @@ int __init coherency_init(void) | |||
400 | type == COHERENCY_FABRIC_TYPE_ARMADA_380) | 400 | type == COHERENCY_FABRIC_TYPE_ARMADA_380) |
401 | armada_375_380_coherency_init(np); | 401 | armada_375_380_coherency_init(np); |
402 | 402 | ||
403 | of_node_put(np); | ||
404 | |||
403 | return 0; | 405 | return 0; |
404 | } | 406 | } |
405 | 407 | ||
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c index 840c3a48e720..962a7f31f596 100644 --- a/arch/arm/mach-pxa/spitz.c +++ b/arch/arm/mach-pxa/spitz.c | |||
@@ -924,6 +924,14 @@ static inline void spitz_i2c_init(void) {} | |||
924 | #endif | 924 | #endif |
925 | 925 | ||
926 | /****************************************************************************** | 926 | /****************************************************************************** |
927 | * Audio devices | ||
928 | ******************************************************************************/ | ||
929 | static inline void spitz_audio_init(void) | ||
930 | { | ||
931 | platform_device_register_simple("spitz-audio", -1, NULL, 0); | ||
932 | } | ||
933 | |||
934 | /****************************************************************************** | ||
927 | * Machine init | 935 | * Machine init |
928 | ******************************************************************************/ | 936 | ******************************************************************************/ |
929 | static void spitz_poweroff(void) | 937 | static void spitz_poweroff(void) |
@@ -970,6 +978,7 @@ static void __init spitz_init(void) | |||
970 | spitz_nor_init(); | 978 | spitz_nor_init(); |
971 | spitz_nand_init(); | 979 | spitz_nand_init(); |
972 | spitz_i2c_init(); | 980 | spitz_i2c_init(); |
981 | spitz_audio_init(); | ||
973 | } | 982 | } |
974 | 983 | ||
975 | static void __init spitz_fixup(struct tag *tags, char **cmdline) | 984 | static void __init spitz_fixup(struct tag *tags, char **cmdline) |
diff --git a/arch/arm/mach-tegra/irq.c b/arch/arm/mach-tegra/irq.c index da7be13aecce..ab95f5391a2b 100644 --- a/arch/arm/mach-tegra/irq.c +++ b/arch/arm/mach-tegra/irq.c | |||
@@ -99,42 +99,42 @@ static inline void tegra_irq_write_mask(unsigned int irq, unsigned long reg) | |||
99 | 99 | ||
100 | static void tegra_mask(struct irq_data *d) | 100 | static void tegra_mask(struct irq_data *d) |
101 | { | 101 | { |
102 | if (d->irq < FIRST_LEGACY_IRQ) | 102 | if (d->hwirq < FIRST_LEGACY_IRQ) |
103 | return; | 103 | return; |
104 | 104 | ||
105 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_CLR); | 105 | tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_CLR); |
106 | } | 106 | } |
107 | 107 | ||
108 | static void tegra_unmask(struct irq_data *d) | 108 | static void tegra_unmask(struct irq_data *d) |
109 | { | 109 | { |
110 | if (d->irq < FIRST_LEGACY_IRQ) | 110 | if (d->hwirq < FIRST_LEGACY_IRQ) |
111 | return; | 111 | return; |
112 | 112 | ||
113 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IER_SET); | 113 | tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IER_SET); |
114 | } | 114 | } |
115 | 115 | ||
116 | static void tegra_ack(struct irq_data *d) | 116 | static void tegra_ack(struct irq_data *d) |
117 | { | 117 | { |
118 | if (d->irq < FIRST_LEGACY_IRQ) | 118 | if (d->hwirq < FIRST_LEGACY_IRQ) |
119 | return; | 119 | return; |
120 | 120 | ||
121 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); | 121 | tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); |
122 | } | 122 | } |
123 | 123 | ||
124 | static void tegra_eoi(struct irq_data *d) | 124 | static void tegra_eoi(struct irq_data *d) |
125 | { | 125 | { |
126 | if (d->irq < FIRST_LEGACY_IRQ) | 126 | if (d->hwirq < FIRST_LEGACY_IRQ) |
127 | return; | 127 | return; |
128 | 128 | ||
129 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_CLR); | 129 | tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_CLR); |
130 | } | 130 | } |
131 | 131 | ||
132 | static int tegra_retrigger(struct irq_data *d) | 132 | static int tegra_retrigger(struct irq_data *d) |
133 | { | 133 | { |
134 | if (d->irq < FIRST_LEGACY_IRQ) | 134 | if (d->hwirq < FIRST_LEGACY_IRQ) |
135 | return 0; | 135 | return 0; |
136 | 136 | ||
137 | tegra_irq_write_mask(d->irq, ICTLR_CPU_IEP_FIR_SET); | 137 | tegra_irq_write_mask(d->hwirq, ICTLR_CPU_IEP_FIR_SET); |
138 | 138 | ||
139 | return 1; | 139 | return 1; |
140 | } | 140 | } |
@@ -142,7 +142,7 @@ static int tegra_retrigger(struct irq_data *d) | |||
142 | #ifdef CONFIG_PM_SLEEP | 142 | #ifdef CONFIG_PM_SLEEP |
143 | static int tegra_set_wake(struct irq_data *d, unsigned int enable) | 143 | static int tegra_set_wake(struct irq_data *d, unsigned int enable) |
144 | { | 144 | { |
145 | u32 irq = d->irq; | 145 | u32 irq = d->hwirq; |
146 | u32 index, mask; | 146 | u32 index, mask; |
147 | 147 | ||
148 | if (irq < FIRST_LEGACY_IRQ || | 148 | if (irq < FIRST_LEGACY_IRQ || |
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S index b3a947863ac7..22ac2a6fbfe3 100644 --- a/arch/arm/mm/proc-v7.S +++ b/arch/arm/mm/proc-v7.S | |||
@@ -270,7 +270,6 @@ __v7_pj4b_setup: | |||
270 | /* Auxiliary Debug Modes Control 1 Register */ | 270 | /* Auxiliary Debug Modes Control 1 Register */ |
271 | #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */ | 271 | #define PJ4B_STATIC_BP (1 << 2) /* Enable Static BP */ |
272 | #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */ | 272 | #define PJ4B_INTER_PARITY (1 << 8) /* Disable Internal Parity Handling */ |
273 | #define PJ4B_BCK_OFF_STREX (1 << 5) /* Enable the back off of STREX instr */ | ||
274 | #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */ | 273 | #define PJ4B_CLEAN_LINE (1 << 16) /* Disable data transfer for clean line */ |
275 | 274 | ||
276 | /* Auxiliary Debug Modes Control 2 Register */ | 275 | /* Auxiliary Debug Modes Control 2 Register */ |
@@ -293,7 +292,6 @@ __v7_pj4b_setup: | |||
293 | /* Auxiliary Debug Modes Control 1 Register */ | 292 | /* Auxiliary Debug Modes Control 1 Register */ |
294 | mrc p15, 1, r0, c15, c1, 1 | 293 | mrc p15, 1, r0, c15, c1, 1 |
295 | orr r0, r0, #PJ4B_CLEAN_LINE | 294 | orr r0, r0, #PJ4B_CLEAN_LINE |
296 | orr r0, r0, #PJ4B_BCK_OFF_STREX | ||
297 | orr r0, r0, #PJ4B_INTER_PARITY | 295 | orr r0, r0, #PJ4B_INTER_PARITY |
298 | bic r0, r0, #PJ4B_STATIC_BP | 296 | bic r0, r0, #PJ4B_STATIC_BP |
299 | mcr p15, 1, r0, c15, c1, 1 | 297 | mcr p15, 1, r0, c15, c1, 1 |
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S index 23259f104c66..afa2b3c4df4a 100644 --- a/arch/arm/mm/proc-xscale.S +++ b/arch/arm/mm/proc-xscale.S | |||
@@ -535,7 +535,7 @@ ENTRY(cpu_xscale_do_suspend) | |||
535 | mrc p15, 0, r5, c15, c1, 0 @ CP access reg | 535 | mrc p15, 0, r5, c15, c1, 0 @ CP access reg |
536 | mrc p15, 0, r6, c13, c0, 0 @ PID | 536 | mrc p15, 0, r6, c13, c0, 0 @ PID |
537 | mrc p15, 0, r7, c3, c0, 0 @ domain ID | 537 | mrc p15, 0, r7, c3, c0, 0 @ domain ID |
538 | mrc p15, 0, r8, c1, c1, 0 @ auxiliary control reg | 538 | mrc p15, 0, r8, c1, c0, 1 @ auxiliary control reg |
539 | mrc p15, 0, r9, c1, c0, 0 @ control reg | 539 | mrc p15, 0, r9, c1, c0, 0 @ control reg |
540 | bic r4, r4, #2 @ clear frequency change bit | 540 | bic r4, r4, #2 @ clear frequency change bit |
541 | stmia r0, {r4 - r9} @ store cp regs | 541 | stmia r0, {r4 - r9} @ store cp regs |
@@ -552,7 +552,7 @@ ENTRY(cpu_xscale_do_resume) | |||
552 | mcr p15, 0, r6, c13, c0, 0 @ PID | 552 | mcr p15, 0, r6, c13, c0, 0 @ PID |
553 | mcr p15, 0, r7, c3, c0, 0 @ domain ID | 553 | mcr p15, 0, r7, c3, c0, 0 @ domain ID |
554 | mcr p15, 0, r1, c2, c0, 0 @ translation table base addr | 554 | mcr p15, 0, r1, c2, c0, 0 @ translation table base addr |
555 | mcr p15, 0, r8, c1, c1, 0 @ auxiliary control reg | 555 | mcr p15, 0, r8, c1, c0, 1 @ auxiliary control reg |
556 | mov r0, r9 @ control register | 556 | mov r0, r9 @ control register |
557 | b cpu_resume_mmu | 557 | b cpu_resume_mmu |
558 | ENDPROC(cpu_xscale_do_resume) | 558 | ENDPROC(cpu_xscale_do_resume) |
diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 4cc3b719208e..3d7c2df89946 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c | |||
@@ -424,6 +424,11 @@ static const struct sys_reg_desc sys_reg_descs[] = { | |||
424 | /* VBAR_EL1 */ | 424 | /* VBAR_EL1 */ |
425 | { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), | 425 | { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b0000), Op2(0b000), |
426 | NULL, reset_val, VBAR_EL1, 0 }, | 426 | NULL, reset_val, VBAR_EL1, 0 }, |
427 | |||
428 | /* ICC_SRE_EL1 */ | ||
429 | { Op0(0b11), Op1(0b000), CRn(0b1100), CRm(0b1100), Op2(0b101), | ||
430 | trap_raz_wi }, | ||
431 | |||
427 | /* CONTEXTIDR_EL1 */ | 432 | /* CONTEXTIDR_EL1 */ |
428 | { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), | 433 | { Op0(0b11), Op1(0b000), CRn(0b1101), CRm(0b0000), Op2(0b001), |
429 | access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, | 434 | access_vm_reg, reset_val, CONTEXTIDR_EL1, 0 }, |
@@ -690,6 +695,10 @@ static const struct sys_reg_desc cp15_regs[] = { | |||
690 | { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR }, | 695 | { Op1( 0), CRn(10), CRm( 2), Op2( 1), access_vm_reg, NULL, c10_NMRR }, |
691 | { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 }, | 696 | { Op1( 0), CRn(10), CRm( 3), Op2( 0), access_vm_reg, NULL, c10_AMAIR0 }, |
692 | { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 }, | 697 | { Op1( 0), CRn(10), CRm( 3), Op2( 1), access_vm_reg, NULL, c10_AMAIR1 }, |
698 | |||
699 | /* ICC_SRE */ | ||
700 | { Op1( 0), CRn(12), CRm(12), Op2( 5), trap_raz_wi }, | ||
701 | |||
693 | { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID }, | 702 | { Op1( 0), CRn(13), CRm( 0), Op2( 1), access_vm_reg, NULL, c13_CID }, |
694 | }; | 703 | }; |
695 | 704 | ||
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c index ec6b9acb6bea..dbe46f43884d 100644 --- a/arch/ia64/kvm/kvm-ia64.c +++ b/arch/ia64/kvm/kvm-ia64.c | |||
@@ -1563,7 +1563,7 @@ int kvm_arch_prepare_memory_region(struct kvm *kvm, | |||
1563 | 1563 | ||
1564 | for (i = 0; i < npages; i++) { | 1564 | for (i = 0; i < npages; i++) { |
1565 | pfn = gfn_to_pfn(kvm, base_gfn + i); | 1565 | pfn = gfn_to_pfn(kvm, base_gfn + i); |
1566 | if (!kvm_is_mmio_pfn(pfn)) { | 1566 | if (!kvm_is_reserved_pfn(pfn)) { |
1567 | kvm_set_pmt_entry(kvm, base_gfn + i, | 1567 | kvm_set_pmt_entry(kvm, base_gfn + i, |
1568 | pfn << PAGE_SHIFT, | 1568 | pfn << PAGE_SHIFT, |
1569 | _PAGE_AR_RWX | _PAGE_MA_WB); | 1569 | _PAGE_AR_RWX | _PAGE_MA_WB); |
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f43aa536c517..9536ef912f59 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig | |||
@@ -2101,9 +2101,17 @@ config 64BIT_PHYS_ADDR | |||
2101 | config ARCH_PHYS_ADDR_T_64BIT | 2101 | config ARCH_PHYS_ADDR_T_64BIT |
2102 | def_bool 64BIT_PHYS_ADDR | 2102 | def_bool 64BIT_PHYS_ADDR |
2103 | 2103 | ||
2104 | choice | ||
2105 | prompt "SmartMIPS or microMIPS ASE support" | ||
2106 | |||
2107 | config CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS | ||
2108 | bool "None" | ||
2109 | help | ||
2110 | Select this if you want neither microMIPS nor SmartMIPS support | ||
2111 | |||
2104 | config CPU_HAS_SMARTMIPS | 2112 | config CPU_HAS_SMARTMIPS |
2105 | depends on SYS_SUPPORTS_SMARTMIPS | 2113 | depends on SYS_SUPPORTS_SMARTMIPS |
2106 | bool "Support for the SmartMIPS ASE" | 2114 | bool "SmartMIPS" |
2107 | help | 2115 | help |
2108 | SmartMIPS is a extension of the MIPS32 architecture aimed at | 2116 | SmartMIPS is a extension of the MIPS32 architecture aimed at |
2109 | increased security at both hardware and software level for | 2117 | increased security at both hardware and software level for |
@@ -2115,11 +2123,13 @@ config CPU_HAS_SMARTMIPS | |||
2115 | 2123 | ||
2116 | config CPU_MICROMIPS | 2124 | config CPU_MICROMIPS |
2117 | depends on SYS_SUPPORTS_MICROMIPS | 2125 | depends on SYS_SUPPORTS_MICROMIPS |
2118 | bool "Build kernel using microMIPS ISA" | 2126 | bool "microMIPS" |
2119 | help | 2127 | help |
2120 | When this option is enabled the kernel will be built using the | 2128 | When this option is enabled the kernel will be built using the |
2121 | microMIPS ISA | 2129 | microMIPS ISA |
2122 | 2130 | ||
2131 | endchoice | ||
2132 | |||
2123 | config CPU_HAS_MSA | 2133 | config CPU_HAS_MSA |
2124 | bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" | 2134 | bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" |
2125 | depends on CPU_SUPPORTS_MSA | 2135 | depends on CPU_SUPPORTS_MSA |
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b46cd220a018..22a135ac91de 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h | |||
@@ -661,6 +661,8 @@ | |||
661 | #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) | 661 | #define MIPS_CONF6_SYND (_ULCAST_(1) << 13) |
662 | /* proAptiv FTLB on/off bit */ | 662 | /* proAptiv FTLB on/off bit */ |
663 | #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) | 663 | #define MIPS_CONF6_FTLBEN (_ULCAST_(1) << 15) |
664 | /* FTLB probability bits */ | ||
665 | #define MIPS_CONF6_FTLBP_SHIFT (16) | ||
664 | 666 | ||
665 | #define MIPS_CONF7_WII (_ULCAST_(1) << 31) | 667 | #define MIPS_CONF7_WII (_ULCAST_(1) << 31) |
666 | 668 | ||
diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 4520adc8699b..cd6e0afc6833 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h | |||
@@ -257,7 +257,11 @@ static inline void protected_flush_icache_line(unsigned long addr) | |||
257 | */ | 257 | */ |
258 | static inline void protected_writeback_dcache_line(unsigned long addr) | 258 | static inline void protected_writeback_dcache_line(unsigned long addr) |
259 | { | 259 | { |
260 | #ifdef CONFIG_EVA | ||
261 | protected_cachee_op(Hit_Writeback_Inv_D, addr); | ||
262 | #else | ||
260 | protected_cache_op(Hit_Writeback_Inv_D, addr); | 263 | protected_cache_op(Hit_Writeback_Inv_D, addr); |
264 | #endif | ||
261 | } | 265 | } |
262 | 266 | ||
263 | static inline void protected_writeback_scache_line(unsigned long addr) | 267 | static inline void protected_writeback_scache_line(unsigned long addr) |
diff --git a/arch/mips/include/asm/uaccess.h b/arch/mips/include/asm/uaccess.h index 133678ab4eb8..22a5624e2fd2 100644 --- a/arch/mips/include/asm/uaccess.h +++ b/arch/mips/include/asm/uaccess.h | |||
@@ -1422,7 +1422,7 @@ static inline long __strnlen_user(const char __user *s, long n) | |||
1422 | } | 1422 | } |
1423 | 1423 | ||
1424 | /* | 1424 | /* |
1425 | * strlen_user: - Get the size of a string in user space. | 1425 | * strnlen_user: - Get the size of a string in user space. |
1426 | * @str: The string to measure. | 1426 | * @str: The string to measure. |
1427 | * | 1427 | * |
1428 | * Context: User context only. This function may sleep. | 1428 | * Context: User context only. This function may sleep. |
@@ -1431,9 +1431,7 @@ static inline long __strnlen_user(const char __user *s, long n) | |||
1431 | * | 1431 | * |
1432 | * Returns the size of the string INCLUDING the terminating NUL. | 1432 | * Returns the size of the string INCLUDING the terminating NUL. |
1433 | * On exception, returns 0. | 1433 | * On exception, returns 0. |
1434 | * | 1434 | * If the string is too long, returns a value greater than @n. |
1435 | * If there is a limit on the length of a valid string, you may wish to | ||
1436 | * consider using strnlen_user() instead. | ||
1437 | */ | 1435 | */ |
1438 | static inline long strnlen_user(const char __user *s, long n) | 1436 | static inline long strnlen_user(const char __user *s, long n) |
1439 | { | 1437 | { |
diff --git a/arch/mips/include/uapi/asm/unistd.h b/arch/mips/include/uapi/asm/unistd.h index 9dc58568f230..d001bb1ad177 100644 --- a/arch/mips/include/uapi/asm/unistd.h +++ b/arch/mips/include/uapi/asm/unistd.h | |||
@@ -1045,7 +1045,7 @@ | |||
1045 | #define __NR_seccomp (__NR_Linux + 316) | 1045 | #define __NR_seccomp (__NR_Linux + 316) |
1046 | #define __NR_getrandom (__NR_Linux + 317) | 1046 | #define __NR_getrandom (__NR_Linux + 317) |
1047 | #define __NR_memfd_create (__NR_Linux + 318) | 1047 | #define __NR_memfd_create (__NR_Linux + 318) |
1048 | #define __NR_memfd_create (__NR_Linux + 319) | 1048 | #define __NR_bpf (__NR_Linux + 319) |
1049 | 1049 | ||
1050 | /* | 1050 | /* |
1051 | * Offset of the last N32 flavoured syscall | 1051 | * Offset of the last N32 flavoured syscall |
diff --git a/arch/mips/kernel/bmips_vec.S b/arch/mips/kernel/bmips_vec.S index 290c23b51678..86495072a922 100644 --- a/arch/mips/kernel/bmips_vec.S +++ b/arch/mips/kernel/bmips_vec.S | |||
@@ -208,7 +208,6 @@ bmips_reset_nmi_vec_end: | |||
208 | END(bmips_reset_nmi_vec) | 208 | END(bmips_reset_nmi_vec) |
209 | 209 | ||
210 | .set pop | 210 | .set pop |
211 | .previous | ||
212 | 211 | ||
213 | /*********************************************************************** | 212 | /*********************************************************************** |
214 | * CPU1 warm restart vector (used for second and subsequent boots). | 213 | * CPU1 warm restart vector (used for second and subsequent boots). |
@@ -281,5 +280,3 @@ LEAF(bmips_enable_xks01) | |||
281 | jr ra | 280 | jr ra |
282 | 281 | ||
283 | END(bmips_enable_xks01) | 282 | END(bmips_enable_xks01) |
284 | |||
285 | .previous | ||
diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index e6e97d2a5c9e..0384b05ab5a0 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S | |||
@@ -229,6 +229,7 @@ LEAF(mips_cps_core_init) | |||
229 | nop | 229 | nop |
230 | 230 | ||
231 | .set push | 231 | .set push |
232 | .set mips32r2 | ||
232 | .set mt | 233 | .set mt |
233 | 234 | ||
234 | /* Only allow 1 TC per VPE to execute... */ | 235 | /* Only allow 1 TC per VPE to execute... */ |
@@ -345,6 +346,7 @@ LEAF(mips_cps_boot_vpes) | |||
345 | nop | 346 | nop |
346 | 347 | ||
347 | .set push | 348 | .set push |
349 | .set mips32r2 | ||
348 | .set mt | 350 | .set mt |
349 | 351 | ||
350 | 1: /* Enter VPE configuration state */ | 352 | 1: /* Enter VPE configuration state */ |
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index d5a4f380b019..dc49cf30c2db 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c | |||
@@ -193,6 +193,32 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa) | |||
193 | static char unknown_isa[] = KERN_ERR \ | 193 | static char unknown_isa[] = KERN_ERR \ |
194 | "Unsupported ISA type, c0.config0: %d."; | 194 | "Unsupported ISA type, c0.config0: %d."; |
195 | 195 | ||
196 | static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) | ||
197 | { | ||
198 | |||
199 | unsigned int probability = c->tlbsize / c->tlbsizevtlb; | ||
200 | |||
201 | /* | ||
202 | * 0 = All TLBWR instructions go to FTLB | ||
203 | * 1 = 15:1: For every 16 TBLWR instructions, 15 go to the | ||
204 | * FTLB and 1 goes to the VTLB. | ||
205 | * 2 = 7:1: As above with 7:1 ratio. | ||
206 | * 3 = 3:1: As above with 3:1 ratio. | ||
207 | * | ||
208 | * Use the linear midpoint as the probability threshold. | ||
209 | */ | ||
210 | if (probability >= 12) | ||
211 | return 1; | ||
212 | else if (probability >= 6) | ||
213 | return 2; | ||
214 | else | ||
215 | /* | ||
216 | * So FTLB is less than 4 times bigger than VTLB. | ||
217 | * A 3:1 ratio can still be useful though. | ||
218 | */ | ||
219 | return 3; | ||
220 | } | ||
221 | |||
196 | static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) | 222 | static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) |
197 | { | 223 | { |
198 | unsigned int config6; | 224 | unsigned int config6; |
@@ -203,9 +229,14 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) | |||
203 | case CPU_P5600: | 229 | case CPU_P5600: |
204 | /* proAptiv & related cores use Config6 to enable the FTLB */ | 230 | /* proAptiv & related cores use Config6 to enable the FTLB */ |
205 | config6 = read_c0_config6(); | 231 | config6 = read_c0_config6(); |
232 | /* Clear the old probability value */ | ||
233 | config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); | ||
206 | if (enable) | 234 | if (enable) |
207 | /* Enable FTLB */ | 235 | /* Enable FTLB */ |
208 | write_c0_config6(config6 | MIPS_CONF6_FTLBEN); | 236 | write_c0_config6(config6 | |
237 | (calculate_ftlb_probability(c) | ||
238 | << MIPS_CONF6_FTLBP_SHIFT) | ||
239 | | MIPS_CONF6_FTLBEN); | ||
209 | else | 240 | else |
210 | /* Disable FTLB */ | 241 | /* Disable FTLB */ |
211 | write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); | 242 | write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); |
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c index 31b1b763cb29..c5c4fd54d797 100644 --- a/arch/mips/kernel/rtlx.c +++ b/arch/mips/kernel/rtlx.c | |||
@@ -94,12 +94,12 @@ int rtlx_open(int index, int can_sleep) | |||
94 | int ret = 0; | 94 | int ret = 0; |
95 | 95 | ||
96 | if (index >= RTLX_CHANNELS) { | 96 | if (index >= RTLX_CHANNELS) { |
97 | pr_debug(KERN_DEBUG "rtlx_open index out of range\n"); | 97 | pr_debug("rtlx_open index out of range\n"); |
98 | return -ENOSYS; | 98 | return -ENOSYS; |
99 | } | 99 | } |
100 | 100 | ||
101 | if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { | 101 | if (atomic_inc_return(&channel_wqs[index].in_open) > 1) { |
102 | pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index); | 102 | pr_debug("rtlx_open channel %d already opened\n", index); |
103 | ret = -EBUSY; | 103 | ret = -EBUSY; |
104 | goto out_fail; | 104 | goto out_fail; |
105 | } | 105 | } |
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index d21ec57b6e95..f3b635f86c39 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -485,7 +485,7 @@ static void __init bootmem_init(void) | |||
485 | * NOTE: historically plat_mem_setup did the entire platform initialization. | 485 | * NOTE: historically plat_mem_setup did the entire platform initialization. |
486 | * This was rather impractical because it meant plat_mem_setup had to | 486 | * This was rather impractical because it meant plat_mem_setup had to |
487 | * get away without any kind of memory allocator. To keep old code from | 487 | * get away without any kind of memory allocator. To keep old code from |
488 | * breaking plat_setup was just renamed to plat_setup and a second platform | 488 | * breaking plat_setup was just renamed to plat_mem_setup and a second platform |
489 | * initialization hook for anything else was introduced. | 489 | * initialization hook for anything else was introduced. |
490 | */ | 490 | */ |
491 | 491 | ||
@@ -493,7 +493,7 @@ static int usermem __initdata; | |||
493 | 493 | ||
494 | static int __init early_parse_mem(char *p) | 494 | static int __init early_parse_mem(char *p) |
495 | { | 495 | { |
496 | unsigned long start, size; | 496 | phys_t start, size; |
497 | 497 | ||
498 | /* | 498 | /* |
499 | * If a user specifies memory size, we | 499 | * If a user specifies memory size, we |
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 1d57605e4615..16f1e4f2bf3c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -658,13 +658,13 @@ static int signal_setup(void) | |||
658 | save_fp_context = _save_fp_context; | 658 | save_fp_context = _save_fp_context; |
659 | restore_fp_context = _restore_fp_context; | 659 | restore_fp_context = _restore_fp_context; |
660 | } else { | 660 | } else { |
661 | save_fp_context = copy_fp_from_sigcontext; | 661 | save_fp_context = copy_fp_to_sigcontext; |
662 | restore_fp_context = copy_fp_to_sigcontext; | 662 | restore_fp_context = copy_fp_from_sigcontext; |
663 | } | 663 | } |
664 | #endif /* CONFIG_SMP */ | 664 | #endif /* CONFIG_SMP */ |
665 | #else | 665 | #else |
666 | save_fp_context = copy_fp_from_sigcontext;; | 666 | save_fp_context = copy_fp_to_sigcontext; |
667 | restore_fp_context = copy_fp_to_sigcontext; | 667 | restore_fp_context = copy_fp_from_sigcontext; |
668 | #endif | 668 | #endif |
669 | 669 | ||
670 | return 0; | 670 | return 0; |
diff --git a/arch/mips/loongson/common/Makefile b/arch/mips/loongson/common/Makefile index 0bb9cc9dc621..d87e03330b29 100644 --- a/arch/mips/loongson/common/Makefile +++ b/arch/mips/loongson/common/Makefile | |||
@@ -11,7 +11,8 @@ obj-$(CONFIG_PCI) += pci.o | |||
11 | # Serial port support | 11 | # Serial port support |
12 | # | 12 | # |
13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o | 13 | obj-$(CONFIG_EARLY_PRINTK) += early_printk.o |
14 | obj-$(CONFIG_SERIAL_8250) += serial.o | 14 | loongson-serial-$(CONFIG_SERIAL_8250) := serial.o |
15 | obj-y += $(loongson-serial-m) $(loongson-serial-y) | ||
15 | obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o | 16 | obj-$(CONFIG_LOONGSON_UART_BASE) += uart_base.o |
16 | obj-$(CONFIG_LOONGSON_MC146818) += rtc.o | 17 | obj-$(CONFIG_LOONGSON_MC146818) += rtc.o |
17 | 18 | ||
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c index b5f228e7eae6..e3328a96e809 100644 --- a/arch/mips/mm/tlbex.c +++ b/arch/mips/mm/tlbex.c | |||
@@ -1872,8 +1872,16 @@ build_r4000_tlbchange_handler_head(u32 **p, struct uasm_label **l, | |||
1872 | uasm_l_smp_pgtable_change(l, *p); | 1872 | uasm_l_smp_pgtable_change(l, *p); |
1873 | #endif | 1873 | #endif |
1874 | iPTE_LW(p, wr.r1, wr.r2); /* get even pte */ | 1874 | iPTE_LW(p, wr.r1, wr.r2); /* get even pte */ |
1875 | if (!m4kc_tlbp_war()) | 1875 | if (!m4kc_tlbp_war()) { |
1876 | build_tlb_probe_entry(p); | 1876 | build_tlb_probe_entry(p); |
1877 | if (cpu_has_htw) { | ||
1878 | /* race condition happens, leaving */ | ||
1879 | uasm_i_ehb(p); | ||
1880 | uasm_i_mfc0(p, wr.r3, C0_INDEX); | ||
1881 | uasm_il_bltz(p, r, wr.r3, label_leave); | ||
1882 | uasm_i_nop(p); | ||
1883 | } | ||
1884 | } | ||
1877 | return wr; | 1885 | return wr; |
1878 | } | 1886 | } |
1879 | 1887 | ||
diff --git a/arch/mips/mti-sead3/sead3-leds.c b/arch/mips/mti-sead3/sead3-leds.c index 20102a6d4141..c427c5778186 100644 --- a/arch/mips/mti-sead3/sead3-leds.c +++ b/arch/mips/mti-sead3/sead3-leds.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * | 5 | * |
6 | * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. | 6 | * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. |
7 | */ | 7 | */ |
8 | #include <linux/module.h> | 8 | #include <linux/init.h> |
9 | #include <linux/leds.h> | 9 | #include <linux/leds.h> |
10 | #include <linux/platform_device.h> | 10 | #include <linux/platform_device.h> |
11 | 11 | ||
@@ -76,8 +76,4 @@ static int __init led_init(void) | |||
76 | return platform_device_register(&fled_device); | 76 | return platform_device_register(&fled_device); |
77 | } | 77 | } |
78 | 78 | ||
79 | module_init(led_init); | 79 | device_initcall(led_init); |
80 | |||
81 | MODULE_AUTHOR("Chris Dearman <chris@mips.com>"); | ||
82 | MODULE_LICENSE("GPL"); | ||
83 | MODULE_DESCRIPTION("LED probe driver for SEAD-3"); | ||
diff --git a/arch/mips/netlogic/xlp/Makefile b/arch/mips/netlogic/xlp/Makefile index be358a8050c5..6b43af0a34d9 100644 --- a/arch/mips/netlogic/xlp/Makefile +++ b/arch/mips/netlogic/xlp/Makefile | |||
@@ -1,6 +1,10 @@ | |||
1 | obj-y += setup.o nlm_hal.o cop2-ex.o dt.o | 1 | obj-y += setup.o nlm_hal.o cop2-ex.o dt.o |
2 | obj-$(CONFIG_SMP) += wakeup.o | 2 | obj-$(CONFIG_SMP) += wakeup.o |
3 | obj-$(CONFIG_USB) += usb-init.o | 3 | ifdef CONFIG_USB |
4 | obj-$(CONFIG_USB) += usb-init-xlp2.o | 4 | obj-y += usb-init.o |
5 | obj-$(CONFIG_SATA_AHCI) += ahci-init.o | 5 | obj-y += usb-init-xlp2.o |
6 | obj-$(CONFIG_SATA_AHCI) += ahci-init-xlp2.o | 6 | endif |
7 | ifdef CONFIG_SATA_AHCI | ||
8 | obj-y += ahci-init.o | ||
9 | obj-y += ahci-init-xlp2.o | ||
10 | endif | ||
diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 4ca90a39d6d0..725247beebec 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h | |||
@@ -159,8 +159,6 @@ struct pci_dn { | |||
159 | 159 | ||
160 | int pci_ext_config_space; /* for pci devices */ | 160 | int pci_ext_config_space; /* for pci devices */ |
161 | 161 | ||
162 | bool force_32bit_msi; | ||
163 | |||
164 | struct pci_dev *pcidev; /* back-pointer to the pci device */ | 162 | struct pci_dev *pcidev; /* back-pointer to the pci device */ |
165 | #ifdef CONFIG_EEH | 163 | #ifdef CONFIG_EEH |
166 | struct eeh_dev *edev; /* eeh device */ | 164 | struct eeh_dev *edev; /* eeh device */ |
diff --git a/arch/powerpc/kernel/eeh_sysfs.c b/arch/powerpc/kernel/eeh_sysfs.c index f19b1e5cb060..1ceecdda810b 100644 --- a/arch/powerpc/kernel/eeh_sysfs.c +++ b/arch/powerpc/kernel/eeh_sysfs.c | |||
@@ -65,7 +65,7 @@ static ssize_t eeh_pe_state_show(struct device *dev, | |||
65 | return -ENODEV; | 65 | return -ENODEV; |
66 | 66 | ||
67 | state = eeh_ops->get_state(edev->pe, NULL); | 67 | state = eeh_ops->get_state(edev->pe, NULL); |
68 | return sprintf(buf, "%0x08x %0x08x\n", | 68 | return sprintf(buf, "0x%08x 0x%08x\n", |
69 | state, edev->pe->state); | 69 | state, edev->pe->state); |
70 | } | 70 | } |
71 | 71 | ||
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 155013da27e0..b15194e2c5fc 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c | |||
@@ -266,13 +266,3 @@ int pcibus_to_node(struct pci_bus *bus) | |||
266 | } | 266 | } |
267 | EXPORT_SYMBOL(pcibus_to_node); | 267 | EXPORT_SYMBOL(pcibus_to_node); |
268 | #endif | 268 | #endif |
269 | |||
270 | static void quirk_radeon_32bit_msi(struct pci_dev *dev) | ||
271 | { | ||
272 | struct pci_dn *pdn = pci_get_pdn(dev); | ||
273 | |||
274 | if (pdn) | ||
275 | pdn->force_32bit_msi = true; | ||
276 | } | ||
277 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0x68f2, quirk_radeon_32bit_msi); | ||
278 | DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_ATI, 0xaa68, quirk_radeon_32bit_msi); | ||
diff --git a/arch/powerpc/kernel/vdso32/getcpu.S b/arch/powerpc/kernel/vdso32/getcpu.S index 23eb9a9441bd..c62be60c7274 100644 --- a/arch/powerpc/kernel/vdso32/getcpu.S +++ b/arch/powerpc/kernel/vdso32/getcpu.S | |||
@@ -30,8 +30,8 @@ | |||
30 | V_FUNCTION_BEGIN(__kernel_getcpu) | 30 | V_FUNCTION_BEGIN(__kernel_getcpu) |
31 | .cfi_startproc | 31 | .cfi_startproc |
32 | mfspr r5,SPRN_SPRG_VDSO_READ | 32 | mfspr r5,SPRN_SPRG_VDSO_READ |
33 | cmpdi cr0,r3,0 | 33 | cmpwi cr0,r3,0 |
34 | cmpdi cr1,r4,0 | 34 | cmpwi cr1,r4,0 |
35 | clrlwi r6,r5,16 | 35 | clrlwi r6,r5,16 |
36 | rlwinm r7,r5,16,31-15,31-0 | 36 | rlwinm r7,r5,16,31-15,31-0 |
37 | beq cr0,1f | 37 | beq cr0,1f |
diff --git a/arch/powerpc/platforms/powernv/opal-hmi.c b/arch/powerpc/platforms/powernv/opal-hmi.c index 5e1ed1575aab..b322bfb51343 100644 --- a/arch/powerpc/platforms/powernv/opal-hmi.c +++ b/arch/powerpc/platforms/powernv/opal-hmi.c | |||
@@ -57,7 +57,7 @@ static void print_hmi_event_info(struct OpalHMIEvent *hmi_evt) | |||
57 | }; | 57 | }; |
58 | 58 | ||
59 | /* Print things out */ | 59 | /* Print things out */ |
60 | if (hmi_evt->version != OpalHMIEvt_V1) { | 60 | if (hmi_evt->version < OpalHMIEvt_V1) { |
61 | pr_err("HMI Interrupt, Unknown event version %d !\n", | 61 | pr_err("HMI Interrupt, Unknown event version %d !\n", |
62 | hmi_evt->version); | 62 | hmi_evt->version); |
63 | return; | 63 | return; |
diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 468a0f23c7f2..3ba435ec3dcd 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c | |||
@@ -1509,7 +1509,6 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, | |||
1509 | unsigned int is_64, struct msi_msg *msg) | 1509 | unsigned int is_64, struct msi_msg *msg) |
1510 | { | 1510 | { |
1511 | struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); | 1511 | struct pnv_ioda_pe *pe = pnv_ioda_get_pe(dev); |
1512 | struct pci_dn *pdn = pci_get_pdn(dev); | ||
1513 | unsigned int xive_num = hwirq - phb->msi_base; | 1512 | unsigned int xive_num = hwirq - phb->msi_base; |
1514 | __be32 data; | 1513 | __be32 data; |
1515 | int rc; | 1514 | int rc; |
@@ -1523,7 +1522,7 @@ static int pnv_pci_ioda_msi_setup(struct pnv_phb *phb, struct pci_dev *dev, | |||
1523 | return -ENXIO; | 1522 | return -ENXIO; |
1524 | 1523 | ||
1525 | /* Force 32-bit MSI on some broken devices */ | 1524 | /* Force 32-bit MSI on some broken devices */ |
1526 | if (pdn && pdn->force_32bit_msi) | 1525 | if (dev->no_64bit_msi) |
1527 | is_64 = 0; | 1526 | is_64 = 0; |
1528 | 1527 | ||
1529 | /* Assign XIVE to PE */ | 1528 | /* Assign XIVE to PE */ |
@@ -1997,7 +1996,7 @@ static void __init pnv_pci_init_ioda_phb(struct device_node *np, | |||
1997 | if (is_kdump_kernel()) { | 1996 | if (is_kdump_kernel()) { |
1998 | pr_info(" Issue PHB reset ...\n"); | 1997 | pr_info(" Issue PHB reset ...\n"); |
1999 | ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); | 1998 | ioda_eeh_phb_reset(hose, EEH_RESET_FUNDAMENTAL); |
2000 | ioda_eeh_phb_reset(hose, OPAL_DEASSERT_RESET); | 1999 | ioda_eeh_phb_reset(hose, EEH_RESET_DEACTIVATE); |
2001 | } | 2000 | } |
2002 | 2001 | ||
2003 | /* Configure M64 window */ | 2002 | /* Configure M64 window */ |
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c index b2187d0068b8..4b20f2c6b3b2 100644 --- a/arch/powerpc/platforms/powernv/pci.c +++ b/arch/powerpc/platforms/powernv/pci.c | |||
@@ -50,7 +50,6 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
50 | { | 50 | { |
51 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); | 51 | struct pci_controller *hose = pci_bus_to_host(pdev->bus); |
52 | struct pnv_phb *phb = hose->private_data; | 52 | struct pnv_phb *phb = hose->private_data; |
53 | struct pci_dn *pdn = pci_get_pdn(pdev); | ||
54 | struct msi_desc *entry; | 53 | struct msi_desc *entry; |
55 | struct msi_msg msg; | 54 | struct msi_msg msg; |
56 | int hwirq; | 55 | int hwirq; |
@@ -60,7 +59,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) | |||
60 | if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) | 59 | if (WARN_ON(!phb) || !phb->msi_bmp.bitmap) |
61 | return -ENODEV; | 60 | return -ENODEV; |
62 | 61 | ||
63 | if (pdn && pdn->force_32bit_msi && !phb->msi32_support) | 62 | if (pdev->no_64bit_msi && !phb->msi32_support) |
64 | return -ENODEV; | 63 | return -ENODEV; |
65 | 64 | ||
66 | list_for_each_entry(entry, &pdev->msi_list, list) { | 65 | list_for_each_entry(entry, &pdev->msi_list, list) { |
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c index 8ab5add4ac82..8b909e94fd9a 100644 --- a/arch/powerpc/platforms/pseries/msi.c +++ b/arch/powerpc/platforms/pseries/msi.c | |||
@@ -420,7 +420,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type) | |||
420 | */ | 420 | */ |
421 | again: | 421 | again: |
422 | if (type == PCI_CAP_ID_MSI) { | 422 | if (type == PCI_CAP_ID_MSI) { |
423 | if (pdn->force_32bit_msi) { | 423 | if (pdev->no_64bit_msi) { |
424 | rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); | 424 | rc = rtas_change_msi(pdn, RTAS_CHANGE_32MSI_FN, nvec); |
425 | if (rc < 0) { | 425 | if (rc < 0) { |
426 | /* | 426 | /* |
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c index b988b5addf86..c8efbb37d6e0 100644 --- a/arch/powerpc/xmon/xmon.c +++ b/arch/powerpc/xmon/xmon.c | |||
@@ -293,10 +293,10 @@ static inline void disable_surveillance(void) | |||
293 | args.token = rtas_token("set-indicator"); | 293 | args.token = rtas_token("set-indicator"); |
294 | if (args.token == RTAS_UNKNOWN_SERVICE) | 294 | if (args.token == RTAS_UNKNOWN_SERVICE) |
295 | return; | 295 | return; |
296 | args.nargs = 3; | 296 | args.nargs = cpu_to_be32(3); |
297 | args.nret = 1; | 297 | args.nret = cpu_to_be32(1); |
298 | args.rets = &args.args[3]; | 298 | args.rets = &args.args[3]; |
299 | args.args[0] = SURVEILLANCE_TOKEN; | 299 | args.args[0] = cpu_to_be32(SURVEILLANCE_TOKEN); |
300 | args.args[1] = 0; | 300 | args.args[1] = 0; |
301 | args.args[2] = 0; | 301 | args.args[2] = 0; |
302 | enter_rtas(__pa(&args)); | 302 | enter_rtas(__pa(&args)); |
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index dd1c24ceda50..3f51cf4e8f02 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c | |||
@@ -54,12 +54,8 @@ void s390_handle_mcck(void) | |||
54 | */ | 54 | */ |
55 | local_irq_save(flags); | 55 | local_irq_save(flags); |
56 | local_mcck_disable(); | 56 | local_mcck_disable(); |
57 | /* | 57 | mcck = *this_cpu_ptr(&cpu_mcck); |
58 | * Ummm... Does this make sense at all? Copying the percpu struct | 58 | memset(this_cpu_ptr(&cpu_mcck), 0, sizeof(mcck)); |
59 | * and then zapping it one statement later? | ||
60 | */ | ||
61 | memcpy(&mcck, this_cpu_ptr(&cpu_mcck), sizeof(mcck)); | ||
62 | memset(&mcck, 0, sizeof(struct mcck_struct)); | ||
63 | clear_cpu_flag(CIF_MCCK_PENDING); | 59 | clear_cpu_flag(CIF_MCCK_PENDING); |
64 | local_mcck_enable(); | 60 | local_mcck_enable(); |
65 | local_irq_restore(flags); | 61 | local_irq_restore(flags); |
diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 5b1b52a04ad6..7e064c68c5ec 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h | |||
@@ -12,6 +12,14 @@ int dma_supported(struct device *dev, u64 mask); | |||
12 | #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) | 12 | #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) |
13 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) | 13 | #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) |
14 | 14 | ||
15 | static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, | ||
16 | enum dma_data_direction dir) | ||
17 | { | ||
18 | /* Since dma_{alloc,free}_noncoherent() allocated coherent memory, this | ||
19 | * routine can be a nop. | ||
20 | */ | ||
21 | } | ||
22 | |||
15 | extern struct dma_map_ops *dma_ops; | 23 | extern struct dma_map_ops *dma_ops; |
16 | extern struct dma_map_ops *leon_dma_ops; | 24 | extern struct dma_map_ops *leon_dma_ops; |
17 | extern struct dma_map_ops pci32_dma_ops; | 25 | extern struct dma_map_ops pci32_dma_ops; |
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index be1e07d4b596..45abc363dd3e 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile | |||
@@ -76,7 +76,7 @@ suffix-$(CONFIG_KERNEL_XZ) := xz | |||
76 | suffix-$(CONFIG_KERNEL_LZO) := lzo | 76 | suffix-$(CONFIG_KERNEL_LZO) := lzo |
77 | suffix-$(CONFIG_KERNEL_LZ4) := lz4 | 77 | suffix-$(CONFIG_KERNEL_LZ4) := lz4 |
78 | 78 | ||
79 | RUN_SIZE = $(shell objdump -h vmlinux | \ | 79 | RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \ |
80 | perl $(srctree)/arch/x86/tools/calc_run_size.pl) | 80 | perl $(srctree)/arch/x86/tools/calc_run_size.pl) |
81 | quiet_cmd_mkpiggy = MKPIGGY $@ | 81 | quiet_cmd_mkpiggy = MKPIGGY $@ |
82 | cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false ) | 82 | cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false ) |
diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h index 0a4e140315b6..7249e6d0902d 100644 --- a/arch/x86/include/asm/platform_sst_audio.h +++ b/arch/x86/include/asm/platform_sst_audio.h | |||
@@ -16,6 +16,9 @@ | |||
16 | 16 | ||
17 | #include <linux/sfi.h> | 17 | #include <linux/sfi.h> |
18 | 18 | ||
19 | #define MAX_NUM_STREAMS_MRFLD 25 | ||
20 | #define MAX_NUM_STREAMS MAX_NUM_STREAMS_MRFLD | ||
21 | |||
19 | enum sst_audio_task_id_mrfld { | 22 | enum sst_audio_task_id_mrfld { |
20 | SST_TASK_ID_NONE = 0, | 23 | SST_TASK_ID_NONE = 0, |
21 | SST_TASK_ID_SBA = 1, | 24 | SST_TASK_ID_SBA = 1, |
@@ -73,6 +76,65 @@ struct sst_platform_data { | |||
73 | unsigned int strm_map_size; | 76 | unsigned int strm_map_size; |
74 | }; | 77 | }; |
75 | 78 | ||
79 | struct sst_info { | ||
80 | u32 iram_start; | ||
81 | u32 iram_end; | ||
82 | bool iram_use; | ||
83 | u32 dram_start; | ||
84 | u32 dram_end; | ||
85 | bool dram_use; | ||
86 | u32 imr_start; | ||
87 | u32 imr_end; | ||
88 | bool imr_use; | ||
89 | u32 mailbox_start; | ||
90 | bool use_elf; | ||
91 | bool lpe_viewpt_rqd; | ||
92 | unsigned int max_streams; | ||
93 | u32 dma_max_len; | ||
94 | u8 num_probes; | ||
95 | }; | ||
96 | |||
97 | struct sst_lib_dnld_info { | ||
98 | unsigned int mod_base; | ||
99 | unsigned int mod_end; | ||
100 | unsigned int mod_table_offset; | ||
101 | unsigned int mod_table_size; | ||
102 | bool mod_ddr_dnld; | ||
103 | }; | ||
104 | |||
105 | struct sst_res_info { | ||
106 | unsigned int shim_offset; | ||
107 | unsigned int shim_size; | ||
108 | unsigned int shim_phy_addr; | ||
109 | unsigned int ssp0_offset; | ||
110 | unsigned int ssp0_size; | ||
111 | unsigned int dma0_offset; | ||
112 | unsigned int dma0_size; | ||
113 | unsigned int dma1_offset; | ||
114 | unsigned int dma1_size; | ||
115 | unsigned int iram_offset; | ||
116 | unsigned int iram_size; | ||
117 | unsigned int dram_offset; | ||
118 | unsigned int dram_size; | ||
119 | unsigned int mbox_offset; | ||
120 | unsigned int mbox_size; | ||
121 | unsigned int acpi_lpe_res_index; | ||
122 | unsigned int acpi_ddr_index; | ||
123 | unsigned int acpi_ipc_irq_index; | ||
124 | }; | ||
125 | |||
126 | struct sst_ipc_info { | ||
127 | int ipc_offset; | ||
128 | unsigned int mbox_recv_off; | ||
129 | }; | ||
130 | |||
131 | struct sst_platform_info { | ||
132 | const struct sst_info *probe_data; | ||
133 | const struct sst_ipc_info *ipc_info; | ||
134 | const struct sst_res_info *res_info; | ||
135 | const struct sst_lib_dnld_info *lib_info; | ||
136 | const char *platform; | ||
137 | }; | ||
76 | int add_sst_platform_device(void); | 138 | int add_sst_platform_device(void); |
77 | #endif | 139 | #endif |
78 | 140 | ||
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c index 2ce9051174e6..08fe6e8a726e 100644 --- a/arch/x86/kernel/cpu/microcode/core.c +++ b/arch/x86/kernel/cpu/microcode/core.c | |||
@@ -465,6 +465,7 @@ static void mc_bp_resume(void) | |||
465 | 465 | ||
466 | if (uci->valid && uci->mc) | 466 | if (uci->valid && uci->mc) |
467 | microcode_ops->apply_microcode(cpu); | 467 | microcode_ops->apply_microcode(cpu); |
468 | #ifdef CONFIG_X86_64 | ||
468 | else if (!uci->mc) | 469 | else if (!uci->mc) |
469 | /* | 470 | /* |
470 | * We might resume and not have applied late microcode but still | 471 | * We might resume and not have applied late microcode but still |
@@ -473,6 +474,7 @@ static void mc_bp_resume(void) | |||
473 | * applying patches early on the APs. | 474 | * applying patches early on the APs. |
474 | */ | 475 | */ |
475 | load_ucode_ap(); | 476 | load_ucode_ap(); |
477 | #endif | ||
476 | } | 478 | } |
477 | 479 | ||
478 | static struct syscore_ops mc_syscore_ops = { | 480 | static struct syscore_ops mc_syscore_ops = { |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index ac1c4de3a484..978f402006ee 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -630,7 +630,7 @@ static int mmu_spte_clear_track_bits(u64 *sptep) | |||
630 | * kvm mmu, before reclaiming the page, we should | 630 | * kvm mmu, before reclaiming the page, we should |
631 | * unmap it from mmu first. | 631 | * unmap it from mmu first. |
632 | */ | 632 | */ |
633 | WARN_ON(!kvm_is_mmio_pfn(pfn) && !page_count(pfn_to_page(pfn))); | 633 | WARN_ON(!kvm_is_reserved_pfn(pfn) && !page_count(pfn_to_page(pfn))); |
634 | 634 | ||
635 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) | 635 | if (!shadow_accessed_mask || old_spte & shadow_accessed_mask) |
636 | kvm_set_pfn_accessed(pfn); | 636 | kvm_set_pfn_accessed(pfn); |
@@ -2461,7 +2461,7 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep, | |||
2461 | spte |= PT_PAGE_SIZE_MASK; | 2461 | spte |= PT_PAGE_SIZE_MASK; |
2462 | if (tdp_enabled) | 2462 | if (tdp_enabled) |
2463 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, | 2463 | spte |= kvm_x86_ops->get_mt_mask(vcpu, gfn, |
2464 | kvm_is_mmio_pfn(pfn)); | 2464 | kvm_is_reserved_pfn(pfn)); |
2465 | 2465 | ||
2466 | if (host_writable) | 2466 | if (host_writable) |
2467 | spte |= SPTE_HOST_WRITEABLE; | 2467 | spte |= SPTE_HOST_WRITEABLE; |
@@ -2737,7 +2737,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, | |||
2737 | * PT_PAGE_TABLE_LEVEL and there would be no adjustment done | 2737 | * PT_PAGE_TABLE_LEVEL and there would be no adjustment done |
2738 | * here. | 2738 | * here. |
2739 | */ | 2739 | */ |
2740 | if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn) && | 2740 | if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) && |
2741 | level == PT_PAGE_TABLE_LEVEL && | 2741 | level == PT_PAGE_TABLE_LEVEL && |
2742 | PageTransCompound(pfn_to_page(pfn)) && | 2742 | PageTransCompound(pfn_to_page(pfn)) && |
2743 | !has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) { | 2743 | !has_wrprotected_page(vcpu->kvm, gfn, PT_DIRECTORY_LEVEL)) { |
diff --git a/block/bio-integrity.c b/block/bio-integrity.c index 0984232e429f..5cbd5d9ea61d 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c | |||
@@ -216,9 +216,10 @@ static int bio_integrity_process(struct bio *bio, | |||
216 | { | 216 | { |
217 | struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); | 217 | struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev); |
218 | struct blk_integrity_iter iter; | 218 | struct blk_integrity_iter iter; |
219 | struct bio_vec *bv; | 219 | struct bvec_iter bviter; |
220 | struct bio_vec bv; | ||
220 | struct bio_integrity_payload *bip = bio_integrity(bio); | 221 | struct bio_integrity_payload *bip = bio_integrity(bio); |
221 | unsigned int i, ret = 0; | 222 | unsigned int ret = 0; |
222 | void *prot_buf = page_address(bip->bip_vec->bv_page) + | 223 | void *prot_buf = page_address(bip->bip_vec->bv_page) + |
223 | bip->bip_vec->bv_offset; | 224 | bip->bip_vec->bv_offset; |
224 | 225 | ||
@@ -227,11 +228,11 @@ static int bio_integrity_process(struct bio *bio, | |||
227 | iter.seed = bip_get_seed(bip); | 228 | iter.seed = bip_get_seed(bip); |
228 | iter.prot_buf = prot_buf; | 229 | iter.prot_buf = prot_buf; |
229 | 230 | ||
230 | bio_for_each_segment_all(bv, bio, i) { | 231 | bio_for_each_segment(bv, bio, bviter) { |
231 | void *kaddr = kmap_atomic(bv->bv_page); | 232 | void *kaddr = kmap_atomic(bv.bv_page); |
232 | 233 | ||
233 | iter.data_buf = kaddr + bv->bv_offset; | 234 | iter.data_buf = kaddr + bv.bv_offset; |
234 | iter.data_size = bv->bv_len; | 235 | iter.data_size = bv.bv_len; |
235 | 236 | ||
236 | ret = proc_fn(&iter); | 237 | ret = proc_fn(&iter); |
237 | if (ret) { | 238 | if (ret) { |
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index 807a88a0f394..9d75ead2a1f9 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c | |||
@@ -1164,7 +1164,8 @@ static bool acpi_video_device_in_dod(struct acpi_video_device *device) | |||
1164 | return true; | 1164 | return true; |
1165 | 1165 | ||
1166 | for (i = 0; i < video->attached_count; i++) { | 1166 | for (i = 0; i < video->attached_count; i++) { |
1167 | if (video->attached_array[i].bind_info == device) | 1167 | if ((video->attached_array[i].value.int_val & 0xfff) == |
1168 | (device->device_id & 0xfff)) | ||
1168 | return true; | 1169 | return true; |
1169 | } | 1170 | } |
1170 | 1171 | ||
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index e45f83789809..49f1e6890587 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c | |||
@@ -321,6 +321,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
321 | { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */ | 321 | { PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */ |
322 | { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */ | 322 | { PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */ |
323 | { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */ | 323 | { PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */ |
324 | { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */ | ||
325 | { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */ | ||
326 | { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */ | ||
324 | { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ | 327 | { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */ |
325 | { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */ | 328 | { PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */ |
326 | { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ | 329 | { PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */ |
@@ -492,6 +495,7 @@ static const struct pci_device_id ahci_pci_tbl[] = { | |||
492 | * enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731 | 495 | * enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731 |
493 | */ | 496 | */ |
494 | { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi }, | 497 | { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi }, |
498 | { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi }, | ||
495 | 499 | ||
496 | /* Enmotus */ | 500 | /* Enmotus */ |
497 | { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, | 501 | { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, |
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c index 07bc7e4dbd04..65071591b143 100644 --- a/drivers/ata/sata_fsl.c +++ b/drivers/ata/sata_fsl.c | |||
@@ -1488,7 +1488,7 @@ static int sata_fsl_probe(struct platform_device *ofdev) | |||
1488 | host_priv->csr_base = csr_base; | 1488 | host_priv->csr_base = csr_base; |
1489 | 1489 | ||
1490 | irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); | 1490 | irq = irq_of_parse_and_map(ofdev->dev.of_node, 0); |
1491 | if (irq < 0) { | 1491 | if (!irq) { |
1492 | dev_err(&ofdev->dev, "invalid irq from platform\n"); | 1492 | dev_err(&ofdev->dev, "invalid irq from platform\n"); |
1493 | goto error_exit_with_cleanup; | 1493 | goto error_exit_with_cleanup; |
1494 | } | 1494 | } |
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index 7652e8dc188f..21b0bc6a9c96 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c | |||
@@ -1225,11 +1225,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) | |||
1225 | card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); | 1225 | card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); |
1226 | if (!card->config_regs) { | 1226 | if (!card->config_regs) { |
1227 | dev_warn(&dev->dev, "Failed to ioremap config registers\n"); | 1227 | dev_warn(&dev->dev, "Failed to ioremap config registers\n"); |
1228 | err = -ENOMEM; | ||
1228 | goto out_release_regions; | 1229 | goto out_release_regions; |
1229 | } | 1230 | } |
1230 | card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); | 1231 | card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); |
1231 | if (!card->buffers) { | 1232 | if (!card->buffers) { |
1232 | dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); | 1233 | dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); |
1234 | err = -ENOMEM; | ||
1233 | goto out_unmap_config; | 1235 | goto out_unmap_config; |
1234 | } | 1236 | } |
1235 | 1237 | ||
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig index 8a3f51f7b1b9..db9d00c36a3e 100644 --- a/drivers/base/regmap/Kconfig +++ b/drivers/base/regmap/Kconfig | |||
@@ -3,12 +3,15 @@ | |||
3 | # subsystems should select the appropriate symbols. | 3 | # subsystems should select the appropriate symbols. |
4 | 4 | ||
5 | config REGMAP | 5 | config REGMAP |
6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ) | 6 | default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) |
7 | select LZO_COMPRESS | 7 | select LZO_COMPRESS |
8 | select LZO_DECOMPRESS | 8 | select LZO_DECOMPRESS |
9 | select IRQ_DOMAIN if REGMAP_IRQ | 9 | select IRQ_DOMAIN if REGMAP_IRQ |
10 | bool | 10 | bool |
11 | 11 | ||
12 | config REGMAP_AC97 | ||
13 | tristate | ||
14 | |||
12 | config REGMAP_I2C | 15 | config REGMAP_I2C |
13 | tristate | 16 | tristate |
14 | depends on I2C | 17 | depends on I2C |
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index a7c670b4123a..0a533653ef3b 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | obj-$(CONFIG_REGMAP) += regmap.o regcache.o | 1 | obj-$(CONFIG_REGMAP) += regmap.o regcache.o |
2 | obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o | 2 | obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o |
3 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o | 3 | obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o |
4 | obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o | ||
4 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o | 5 | obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o |
5 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o | 6 | obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o |
6 | obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o | 7 | obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o |
diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c new file mode 100644 index 000000000000..e4c45d2299c1 --- /dev/null +++ b/drivers/base/regmap/regmap-ac97.c | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Register map access API - AC'97 support | ||
3 | * | ||
4 | * Copyright 2013 Linaro Ltd. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #include <linux/clk.h> | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <sound/ac97_codec.h> | ||
28 | |||
29 | bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg) | ||
30 | { | ||
31 | switch (reg) { | ||
32 | case AC97_RESET: | ||
33 | case AC97_POWERDOWN: | ||
34 | case AC97_INT_PAGING: | ||
35 | case AC97_EXTENDED_ID: | ||
36 | case AC97_EXTENDED_STATUS: | ||
37 | case AC97_EXTENDED_MID: | ||
38 | case AC97_EXTENDED_MSTATUS: | ||
39 | case AC97_GPIO_STATUS: | ||
40 | case AC97_MISC_AFE: | ||
41 | case AC97_VENDOR_ID1: | ||
42 | case AC97_VENDOR_ID2: | ||
43 | case AC97_CODEC_CLASS_REV: | ||
44 | case AC97_PCI_SVID: | ||
45 | case AC97_PCI_SID: | ||
46 | case AC97_FUNC_SELECT: | ||
47 | case AC97_FUNC_INFO: | ||
48 | case AC97_SENSE_INFO: | ||
49 | return true; | ||
50 | default: | ||
51 | return false; | ||
52 | } | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile); | ||
55 | |||
56 | static int regmap_ac97_reg_read(void *context, unsigned int reg, | ||
57 | unsigned int *val) | ||
58 | { | ||
59 | struct snd_ac97 *ac97 = context; | ||
60 | |||
61 | *val = ac97->bus->ops->read(ac97, reg); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int regmap_ac97_reg_write(void *context, unsigned int reg, | ||
67 | unsigned int val) | ||
68 | { | ||
69 | struct snd_ac97 *ac97 = context; | ||
70 | |||
71 | ac97->bus->ops->write(ac97, reg, val); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static const struct regmap_bus ac97_regmap_bus = { | ||
77 | .reg_write = regmap_ac97_reg_write, | ||
78 | .reg_read = regmap_ac97_reg_read, | ||
79 | }; | ||
80 | |||
81 | /** | ||
82 | * regmap_init_ac97(): Initialise AC'97 register map | ||
83 | * | ||
84 | * @ac97: Device that will be interacted with | ||
85 | * @config: Configuration for register map | ||
86 | * | ||
87 | * The return value will be an ERR_PTR() on error or a valid pointer to | ||
88 | * a struct regmap. | ||
89 | */ | ||
90 | struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, | ||
91 | const struct regmap_config *config) | ||
92 | { | ||
93 | return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); | ||
94 | } | ||
95 | EXPORT_SYMBOL_GPL(regmap_init_ac97); | ||
96 | |||
97 | /** | ||
98 | * devm_regmap_init_ac97(): Initialise AC'97 register map | ||
99 | * | ||
100 | * @ac97: Device that will be interacted with | ||
101 | * @config: Configuration for register map | ||
102 | * | ||
103 | * The return value will be an ERR_PTR() on error or a valid pointer | ||
104 | * to a struct regmap. The regmap will be automatically freed by the | ||
105 | * device management code. | ||
106 | */ | ||
107 | struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, | ||
108 | const struct regmap_config *config) | ||
109 | { | ||
110 | return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config); | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(devm_regmap_init_ac97); | ||
113 | |||
114 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index 24b5b020753a..a23ac0c724f0 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c | |||
@@ -52,29 +52,26 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, | |||
52 | 52 | ||
53 | tmp = pmc_read(pmc, AT91_PMC_USB); | 53 | tmp = pmc_read(pmc, AT91_PMC_USB); |
54 | usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; | 54 | usbdiv = (tmp & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT; |
55 | return parent_rate / (usbdiv + 1); | 55 | |
56 | return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); | ||
56 | } | 57 | } |
57 | 58 | ||
58 | static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | 59 | static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, |
59 | unsigned long *parent_rate) | 60 | unsigned long *parent_rate) |
60 | { | 61 | { |
61 | unsigned long div; | 62 | unsigned long div; |
62 | unsigned long bestrate; | 63 | |
63 | unsigned long tmp; | 64 | if (!rate) |
65 | return -EINVAL; | ||
64 | 66 | ||
65 | if (rate >= *parent_rate) | 67 | if (rate >= *parent_rate) |
66 | return *parent_rate; | 68 | return *parent_rate; |
67 | 69 | ||
68 | div = *parent_rate / rate; | 70 | div = DIV_ROUND_CLOSEST(*parent_rate, rate); |
69 | if (div >= SAM9X5_USB_MAX_DIV) | 71 | if (div > SAM9X5_USB_MAX_DIV + 1) |
70 | return *parent_rate / (SAM9X5_USB_MAX_DIV + 1); | 72 | div = SAM9X5_USB_MAX_DIV + 1; |
71 | |||
72 | bestrate = *parent_rate / div; | ||
73 | tmp = *parent_rate / (div + 1); | ||
74 | if (bestrate - rate > rate - tmp) | ||
75 | bestrate = tmp; | ||
76 | 73 | ||
77 | return bestrate; | 74 | return DIV_ROUND_CLOSEST(*parent_rate, div); |
78 | } | 75 | } |
79 | 76 | ||
80 | static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) | 77 | static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) |
@@ -106,9 +103,13 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, | |||
106 | u32 tmp; | 103 | u32 tmp; |
107 | struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); | 104 | struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(hw); |
108 | struct at91_pmc *pmc = usb->pmc; | 105 | struct at91_pmc *pmc = usb->pmc; |
109 | unsigned long div = parent_rate / rate; | 106 | unsigned long div; |
107 | |||
108 | if (!rate) | ||
109 | return -EINVAL; | ||
110 | 110 | ||
111 | if (parent_rate % rate || div < 1 || div >= SAM9X5_USB_MAX_DIV) | 111 | div = DIV_ROUND_CLOSEST(parent_rate, rate); |
112 | if (div > SAM9X5_USB_MAX_DIV + 1 || !div) | ||
112 | return -EINVAL; | 113 | return -EINVAL; |
113 | 114 | ||
114 | tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; | 115 | tmp = pmc_read(pmc, AT91_PMC_USB) & ~AT91_PMC_OHCIUSBDIV; |
@@ -253,7 +254,7 @@ static long at91rm9200_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, | |||
253 | 254 | ||
254 | tmp_parent_rate = rate * usb->divisors[i]; | 255 | tmp_parent_rate = rate * usb->divisors[i]; |
255 | tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); | 256 | tmp_parent_rate = __clk_round_rate(parent, tmp_parent_rate); |
256 | tmprate = tmp_parent_rate / usb->divisors[i]; | 257 | tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]); |
257 | if (tmprate < rate) | 258 | if (tmprate < rate) |
258 | tmpdiff = rate - tmprate; | 259 | tmpdiff = rate - tmprate; |
259 | else | 260 | else |
@@ -281,10 +282,10 @@ static int at91rm9200_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, | |||
281 | struct at91_pmc *pmc = usb->pmc; | 282 | struct at91_pmc *pmc = usb->pmc; |
282 | unsigned long div; | 283 | unsigned long div; |
283 | 284 | ||
284 | if (!rate || parent_rate % rate) | 285 | if (!rate) |
285 | return -EINVAL; | 286 | return -EINVAL; |
286 | 287 | ||
287 | div = parent_rate / rate; | 288 | div = DIV_ROUND_CLOSEST(parent_rate, rate); |
288 | 289 | ||
289 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { | 290 | for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) { |
290 | if (usb->divisors[i] == div) { | 291 | if (usb->divisors[i] == div) { |
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 18a9de29df0e..c0a842b335c5 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c | |||
@@ -263,6 +263,14 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate, | |||
263 | if (!rate) | 263 | if (!rate) |
264 | rate = 1; | 264 | rate = 1; |
265 | 265 | ||
266 | /* if read only, just return current value */ | ||
267 | if (divider->flags & CLK_DIVIDER_READ_ONLY) { | ||
268 | bestdiv = readl(divider->reg) >> divider->shift; | ||
269 | bestdiv &= div_mask(divider); | ||
270 | bestdiv = _get_div(divider, bestdiv); | ||
271 | return bestdiv; | ||
272 | } | ||
273 | |||
266 | maxdiv = _get_maxdiv(divider); | 274 | maxdiv = _get_maxdiv(divider); |
267 | 275 | ||
268 | if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { | 276 | if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) { |
@@ -361,11 +369,6 @@ const struct clk_ops clk_divider_ops = { | |||
361 | }; | 369 | }; |
362 | EXPORT_SYMBOL_GPL(clk_divider_ops); | 370 | EXPORT_SYMBOL_GPL(clk_divider_ops); |
363 | 371 | ||
364 | const struct clk_ops clk_divider_ro_ops = { | ||
365 | .recalc_rate = clk_divider_recalc_rate, | ||
366 | }; | ||
367 | EXPORT_SYMBOL_GPL(clk_divider_ro_ops); | ||
368 | |||
369 | static struct clk *_register_divider(struct device *dev, const char *name, | 372 | static struct clk *_register_divider(struct device *dev, const char *name, |
370 | const char *parent_name, unsigned long flags, | 373 | const char *parent_name, unsigned long flags, |
371 | void __iomem *reg, u8 shift, u8 width, | 374 | void __iomem *reg, u8 shift, u8 width, |
@@ -391,10 +394,7 @@ static struct clk *_register_divider(struct device *dev, const char *name, | |||
391 | } | 394 | } |
392 | 395 | ||
393 | init.name = name; | 396 | init.name = name; |
394 | if (clk_divider_flags & CLK_DIVIDER_READ_ONLY) | 397 | init.ops = &clk_divider_ops; |
395 | init.ops = &clk_divider_ro_ops; | ||
396 | else | ||
397 | init.ops = &clk_divider_ops; | ||
398 | init.flags = flags | CLK_IS_BASIC; | 398 | init.flags = flags | CLK_IS_BASIC; |
399 | init.parent_names = (parent_name ? &parent_name: NULL); | 399 | init.parent_names = (parent_name ? &parent_name: NULL); |
400 | init.num_parents = (parent_name ? 1 : 0); | 400 | init.num_parents = (parent_name ? 1 : 0); |
diff --git a/drivers/clk/pxa/clk-pxa27x.c b/drivers/clk/pxa/clk-pxa27x.c index b345cc791e5d..88b9fe13fa44 100644 --- a/drivers/clk/pxa/clk-pxa27x.c +++ b/drivers/clk/pxa/clk-pxa27x.c | |||
@@ -322,7 +322,7 @@ static unsigned long clk_pxa27x_memory_get_rate(struct clk_hw *hw, | |||
322 | unsigned long ccsr = CCSR; | 322 | unsigned long ccsr = CCSR; |
323 | 323 | ||
324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | 324 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); |
325 | a = cccr & CCCR_A_BIT; | 325 | a = cccr & (1 << CCCR_A_BIT); |
326 | l = ccsr & CCSR_L_MASK; | 326 | l = ccsr & CCSR_L_MASK; |
327 | 327 | ||
328 | if (osc_forced || a) | 328 | if (osc_forced || a) |
@@ -341,7 +341,7 @@ static u8 clk_pxa27x_memory_get_parent(struct clk_hw *hw) | |||
341 | unsigned long ccsr = CCSR; | 341 | unsigned long ccsr = CCSR; |
342 | 342 | ||
343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); | 343 | osc_forced = ccsr & (1 << CCCR_CPDIS_BIT); |
344 | a = cccr & CCCR_A_BIT; | 344 | a = cccr & (1 << CCCR_A_BIT); |
345 | if (osc_forced) | 345 | if (osc_forced) |
346 | return PXA_MEM_13Mhz; | 346 | return PXA_MEM_13Mhz; |
347 | if (a) | 347 | if (a) |
diff --git a/drivers/clk/qcom/mmcc-apq8084.c b/drivers/clk/qcom/mmcc-apq8084.c index dab988ab8cf1..157139a5c1ca 100644 --- a/drivers/clk/qcom/mmcc-apq8084.c +++ b/drivers/clk/qcom/mmcc-apq8084.c | |||
@@ -3122,7 +3122,7 @@ static struct clk_regmap *mmcc_apq8084_clocks[] = { | |||
3122 | [ESC1_CLK_SRC] = &esc1_clk_src.clkr, | 3122 | [ESC1_CLK_SRC] = &esc1_clk_src.clkr, |
3123 | [HDMI_CLK_SRC] = &hdmi_clk_src.clkr, | 3123 | [HDMI_CLK_SRC] = &hdmi_clk_src.clkr, |
3124 | [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, | 3124 | [VSYNC_CLK_SRC] = &vsync_clk_src.clkr, |
3125 | [RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr, | 3125 | [MMSS_RBCPR_CLK_SRC] = &rbcpr_clk_src.clkr, |
3126 | [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr, | 3126 | [RBBMTIMER_CLK_SRC] = &rbbmtimer_clk_src.clkr, |
3127 | [MAPLE_CLK_SRC] = &maple_clk_src.clkr, | 3127 | [MAPLE_CLK_SRC] = &maple_clk_src.clkr, |
3128 | [VDP_CLK_SRC] = &vdp_clk_src.clkr, | 3128 | [VDP_CLK_SRC] = &vdp_clk_src.clkr, |
diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index 1e68bff481b8..880a266f0143 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c | |||
@@ -90,9 +90,7 @@ static struct clk *rockchip_clk_register_branch(const char *name, | |||
90 | div->width = div_width; | 90 | div->width = div_width; |
91 | div->lock = lock; | 91 | div->lock = lock; |
92 | div->table = div_table; | 92 | div->table = div_table; |
93 | div_ops = (div_flags & CLK_DIVIDER_READ_ONLY) | 93 | div_ops = &clk_divider_ops; |
94 | ? &clk_divider_ro_ops | ||
95 | : &clk_divider_ops; | ||
96 | } | 94 | } |
97 | 95 | ||
98 | clk = clk_register_composite(NULL, name, parent_names, num_parents, | 96 | clk = clk_register_composite(NULL, name, parent_names, num_parents, |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f0a1a56406eb..9cb5c95d5898 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -4325,7 +4325,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) | |||
4325 | ironlake_fdi_disable(crtc); | 4325 | ironlake_fdi_disable(crtc); |
4326 | 4326 | ||
4327 | ironlake_disable_pch_transcoder(dev_priv, pipe); | 4327 | ironlake_disable_pch_transcoder(dev_priv, pipe); |
4328 | intel_set_pch_fifo_underrun_reporting(dev, pipe, true); | ||
4329 | 4328 | ||
4330 | if (HAS_PCH_CPT(dev)) { | 4329 | if (HAS_PCH_CPT(dev)) { |
4331 | /* disable TRANS_DP_CTL */ | 4330 | /* disable TRANS_DP_CTL */ |
@@ -4389,7 +4388,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) | |||
4389 | 4388 | ||
4390 | if (intel_crtc->config.has_pch_encoder) { | 4389 | if (intel_crtc->config.has_pch_encoder) { |
4391 | lpt_disable_pch_transcoder(dev_priv); | 4390 | lpt_disable_pch_transcoder(dev_priv); |
4392 | intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A, true); | ||
4393 | intel_ddi_fdi_disable(crtc); | 4391 | intel_ddi_fdi_disable(crtc); |
4394 | } | 4392 | } |
4395 | 4393 | ||
@@ -9408,6 +9406,10 @@ static bool page_flip_finished(struct intel_crtc *crtc) | |||
9408 | struct drm_device *dev = crtc->base.dev; | 9406 | struct drm_device *dev = crtc->base.dev; |
9409 | struct drm_i915_private *dev_priv = dev->dev_private; | 9407 | struct drm_i915_private *dev_priv = dev->dev_private; |
9410 | 9408 | ||
9409 | if (i915_reset_in_progress(&dev_priv->gpu_error) || | ||
9410 | crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter)) | ||
9411 | return true; | ||
9412 | |||
9411 | /* | 9413 | /* |
9412 | * The relevant registers doen't exist on pre-ctg. | 9414 | * The relevant registers doen't exist on pre-ctg. |
9413 | * As the flip done interrupt doesn't trigger for mmio | 9415 | * As the flip done interrupt doesn't trigger for mmio |
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ad45bfff3fe..4bcd91757321 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c | |||
@@ -4450,6 +4450,7 @@ static void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) | |||
4450 | * vdd might still be enabled do to the delayed vdd off. | 4450 | * vdd might still be enabled do to the delayed vdd off. |
4451 | * Make sure vdd is actually turned off here. | 4451 | * Make sure vdd is actually turned off here. |
4452 | */ | 4452 | */ |
4453 | cancel_delayed_work_sync(&intel_dp->panel_vdd_work); | ||
4453 | pps_lock(intel_dp); | 4454 | pps_lock(intel_dp); |
4454 | edp_panel_vdd_off_sync(intel_dp); | 4455 | edp_panel_vdd_off_sync(intel_dp); |
4455 | pps_unlock(intel_dp); | 4456 | pps_unlock(intel_dp); |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index a6bd1422e38f..c0bbf2172446 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -899,6 +899,17 @@ void intel_lvds_init(struct drm_device *dev) | |||
899 | int pipe; | 899 | int pipe; |
900 | u8 pin; | 900 | u8 pin; |
901 | 901 | ||
902 | /* | ||
903 | * Unlock registers and just leave them unlocked. Do this before | ||
904 | * checking quirk lists to avoid bogus WARNINGs. | ||
905 | */ | ||
906 | if (HAS_PCH_SPLIT(dev)) { | ||
907 | I915_WRITE(PCH_PP_CONTROL, | ||
908 | I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); | ||
909 | } else { | ||
910 | I915_WRITE(PP_CONTROL, | ||
911 | I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); | ||
912 | } | ||
902 | if (!intel_lvds_supported(dev)) | 913 | if (!intel_lvds_supported(dev)) |
903 | return; | 914 | return; |
904 | 915 | ||
@@ -1097,17 +1108,6 @@ out: | |||
1097 | lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) & | 1108 | lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) & |
1098 | LVDS_A3_POWER_MASK; | 1109 | LVDS_A3_POWER_MASK; |
1099 | 1110 | ||
1100 | /* | ||
1101 | * Unlock registers and just | ||
1102 | * leave them unlocked | ||
1103 | */ | ||
1104 | if (HAS_PCH_SPLIT(dev)) { | ||
1105 | I915_WRITE(PCH_PP_CONTROL, | ||
1106 | I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS); | ||
1107 | } else { | ||
1108 | I915_WRITE(PP_CONTROL, | ||
1109 | I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS); | ||
1110 | } | ||
1111 | lvds_connector->lid_notifier.notifier_call = intel_lid_notify; | 1111 | lvds_connector->lid_notifier.notifier_call = intel_lid_notify; |
1112 | if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { | 1112 | if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) { |
1113 | DRM_DEBUG_KMS("lid notifier registration failed\n"); | 1113 | DRM_DEBUG_KMS("lid notifier registration failed\n"); |
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index cd05677ad4b7..72a40f95d048 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c | |||
@@ -218,7 +218,6 @@ nvc0_identify(struct nouveau_device *device) | |||
218 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; | 218 | device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass; |
219 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; | 219 | device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass; |
220 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; | 220 | device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass; |
221 | device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass; | ||
222 | device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; | 221 | device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass; |
223 | device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; | 222 | device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass; |
224 | break; | 223 | break; |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c index 5ae6a43893b5..1931057f9962 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c | |||
@@ -551,8 +551,8 @@ nv04_fifo_intr(struct nouveau_subdev *subdev) | |||
551 | } | 551 | } |
552 | 552 | ||
553 | if (status & 0x40000000) { | 553 | if (status & 0x40000000) { |
554 | nouveau_fifo_uevent(&priv->base); | ||
555 | nv_wr32(priv, 0x002100, 0x40000000); | 554 | nv_wr32(priv, 0x002100, 0x40000000); |
555 | nouveau_fifo_uevent(&priv->base); | ||
556 | status &= ~0x40000000; | 556 | status &= ~0x40000000; |
557 | } | 557 | } |
558 | } | 558 | } |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c index 1fe1f8fbda0c..074d434c3077 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c | |||
@@ -740,6 +740,8 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) | |||
740 | u32 inte = nv_rd32(priv, 0x002628); | 740 | u32 inte = nv_rd32(priv, 0x002628); |
741 | u32 unkn; | 741 | u32 unkn; |
742 | 742 | ||
743 | nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); | ||
744 | |||
743 | for (unkn = 0; unkn < 8; unkn++) { | 745 | for (unkn = 0; unkn < 8; unkn++) { |
744 | u32 ints = (intr >> (unkn * 0x04)) & inte; | 746 | u32 ints = (intr >> (unkn * 0x04)) & inte; |
745 | if (ints & 0x1) { | 747 | if (ints & 0x1) { |
@@ -751,8 +753,6 @@ nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn) | |||
751 | nv_mask(priv, 0x002628, ints, 0); | 753 | nv_mask(priv, 0x002628, ints, 0); |
752 | } | 754 | } |
753 | } | 755 | } |
754 | |||
755 | nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); | ||
756 | } | 756 | } |
757 | 757 | ||
758 | static void | 758 | static void |
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index d2f0fd39c145..f8734eb74eaa 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c | |||
@@ -952,8 +952,8 @@ nve0_fifo_intr(struct nouveau_subdev *subdev) | |||
952 | } | 952 | } |
953 | 953 | ||
954 | if (stat & 0x80000000) { | 954 | if (stat & 0x80000000) { |
955 | nve0_fifo_intr_engine(priv); | ||
956 | nv_wr32(priv, 0x002100, 0x80000000); | 955 | nv_wr32(priv, 0x002100, 0x80000000); |
956 | nve0_fifo_intr_engine(priv); | ||
957 | stat &= ~0x80000000; | 957 | stat &= ~0x80000000; |
958 | } | 958 | } |
959 | 959 | ||
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 57238076049f..62b97c4eef8d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c | |||
@@ -629,7 +629,6 @@ int nouveau_pmops_suspend(struct device *dev) | |||
629 | 629 | ||
630 | pci_save_state(pdev); | 630 | pci_save_state(pdev); |
631 | pci_disable_device(pdev); | 631 | pci_disable_device(pdev); |
632 | pci_ignore_hotplug(pdev); | ||
633 | pci_set_power_state(pdev, PCI_D3hot); | 632 | pci_set_power_state(pdev, PCI_D3hot); |
634 | return 0; | 633 | return 0; |
635 | } | 634 | } |
@@ -933,6 +932,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev) | |||
933 | ret = nouveau_do_suspend(drm_dev, true); | 932 | ret = nouveau_do_suspend(drm_dev, true); |
934 | pci_save_state(pdev); | 933 | pci_save_state(pdev); |
935 | pci_disable_device(pdev); | 934 | pci_disable_device(pdev); |
935 | pci_ignore_hotplug(pdev); | ||
936 | pci_set_power_state(pdev, PCI_D3cold); | 936 | pci_set_power_state(pdev, PCI_D3cold); |
937 | drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; | 937 | drm_dev->switch_power_state = DRM_SWITCH_POWER_DYNAMIC_OFF; |
938 | return ret; | 938 | return ret; |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index 515cd9aebb99..f32a434724e3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c | |||
@@ -52,20 +52,24 @@ nouveau_fctx(struct nouveau_fence *fence) | |||
52 | return container_of(fence->base.lock, struct nouveau_fence_chan, lock); | 52 | return container_of(fence->base.lock, struct nouveau_fence_chan, lock); |
53 | } | 53 | } |
54 | 54 | ||
55 | static void | 55 | static int |
56 | nouveau_fence_signal(struct nouveau_fence *fence) | 56 | nouveau_fence_signal(struct nouveau_fence *fence) |
57 | { | 57 | { |
58 | int drop = 0; | ||
59 | |||
58 | fence_signal_locked(&fence->base); | 60 | fence_signal_locked(&fence->base); |
59 | list_del(&fence->head); | 61 | list_del(&fence->head); |
62 | rcu_assign_pointer(fence->channel, NULL); | ||
60 | 63 | ||
61 | if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) { | 64 | if (test_bit(FENCE_FLAG_USER_BITS, &fence->base.flags)) { |
62 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); | 65 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
63 | 66 | ||
64 | if (!--fctx->notify_ref) | 67 | if (!--fctx->notify_ref) |
65 | nvif_notify_put(&fctx->notify); | 68 | drop = 1; |
66 | } | 69 | } |
67 | 70 | ||
68 | fence_put(&fence->base); | 71 | fence_put(&fence->base); |
72 | return drop; | ||
69 | } | 73 | } |
70 | 74 | ||
71 | static struct nouveau_fence * | 75 | static struct nouveau_fence * |
@@ -88,16 +92,23 @@ nouveau_fence_context_del(struct nouveau_fence_chan *fctx) | |||
88 | { | 92 | { |
89 | struct nouveau_fence *fence; | 93 | struct nouveau_fence *fence; |
90 | 94 | ||
91 | nvif_notify_fini(&fctx->notify); | ||
92 | |||
93 | spin_lock_irq(&fctx->lock); | 95 | spin_lock_irq(&fctx->lock); |
94 | while (!list_empty(&fctx->pending)) { | 96 | while (!list_empty(&fctx->pending)) { |
95 | fence = list_entry(fctx->pending.next, typeof(*fence), head); | 97 | fence = list_entry(fctx->pending.next, typeof(*fence), head); |
96 | 98 | ||
97 | nouveau_fence_signal(fence); | 99 | if (nouveau_fence_signal(fence)) |
98 | fence->channel = NULL; | 100 | nvif_notify_put(&fctx->notify); |
99 | } | 101 | } |
100 | spin_unlock_irq(&fctx->lock); | 102 | spin_unlock_irq(&fctx->lock); |
103 | |||
104 | nvif_notify_fini(&fctx->notify); | ||
105 | fctx->dead = 1; | ||
106 | |||
107 | /* | ||
108 | * Ensure that all accesses to fence->channel complete before freeing | ||
109 | * the channel. | ||
110 | */ | ||
111 | synchronize_rcu(); | ||
101 | } | 112 | } |
102 | 113 | ||
103 | static void | 114 | static void |
@@ -112,21 +123,23 @@ nouveau_fence_context_free(struct nouveau_fence_chan *fctx) | |||
112 | kref_put(&fctx->fence_ref, nouveau_fence_context_put); | 123 | kref_put(&fctx->fence_ref, nouveau_fence_context_put); |
113 | } | 124 | } |
114 | 125 | ||
115 | static void | 126 | static int |
116 | nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) | 127 | nouveau_fence_update(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) |
117 | { | 128 | { |
118 | struct nouveau_fence *fence; | 129 | struct nouveau_fence *fence; |
119 | 130 | int drop = 0; | |
120 | u32 seq = fctx->read(chan); | 131 | u32 seq = fctx->read(chan); |
121 | 132 | ||
122 | while (!list_empty(&fctx->pending)) { | 133 | while (!list_empty(&fctx->pending)) { |
123 | fence = list_entry(fctx->pending.next, typeof(*fence), head); | 134 | fence = list_entry(fctx->pending.next, typeof(*fence), head); |
124 | 135 | ||
125 | if ((int)(seq - fence->base.seqno) < 0) | 136 | if ((int)(seq - fence->base.seqno) < 0) |
126 | return; | 137 | break; |
127 | 138 | ||
128 | nouveau_fence_signal(fence); | 139 | drop |= nouveau_fence_signal(fence); |
129 | } | 140 | } |
141 | |||
142 | return drop; | ||
130 | } | 143 | } |
131 | 144 | ||
132 | static int | 145 | static int |
@@ -135,18 +148,21 @@ nouveau_fence_wait_uevent_handler(struct nvif_notify *notify) | |||
135 | struct nouveau_fence_chan *fctx = | 148 | struct nouveau_fence_chan *fctx = |
136 | container_of(notify, typeof(*fctx), notify); | 149 | container_of(notify, typeof(*fctx), notify); |
137 | unsigned long flags; | 150 | unsigned long flags; |
151 | int ret = NVIF_NOTIFY_KEEP; | ||
138 | 152 | ||
139 | spin_lock_irqsave(&fctx->lock, flags); | 153 | spin_lock_irqsave(&fctx->lock, flags); |
140 | if (!list_empty(&fctx->pending)) { | 154 | if (!list_empty(&fctx->pending)) { |
141 | struct nouveau_fence *fence; | 155 | struct nouveau_fence *fence; |
156 | struct nouveau_channel *chan; | ||
142 | 157 | ||
143 | fence = list_entry(fctx->pending.next, typeof(*fence), head); | 158 | fence = list_entry(fctx->pending.next, typeof(*fence), head); |
144 | nouveau_fence_update(fence->channel, fctx); | 159 | chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); |
160 | if (nouveau_fence_update(fence->channel, fctx)) | ||
161 | ret = NVIF_NOTIFY_DROP; | ||
145 | } | 162 | } |
146 | spin_unlock_irqrestore(&fctx->lock, flags); | 163 | spin_unlock_irqrestore(&fctx->lock, flags); |
147 | 164 | ||
148 | /* Always return keep here. NVIF refcount is handled with nouveau_fence_update */ | 165 | return ret; |
149 | return NVIF_NOTIFY_KEEP; | ||
150 | } | 166 | } |
151 | 167 | ||
152 | void | 168 | void |
@@ -262,7 +278,10 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan) | |||
262 | if (!ret) { | 278 | if (!ret) { |
263 | fence_get(&fence->base); | 279 | fence_get(&fence->base); |
264 | spin_lock_irq(&fctx->lock); | 280 | spin_lock_irq(&fctx->lock); |
265 | nouveau_fence_update(chan, fctx); | 281 | |
282 | if (nouveau_fence_update(chan, fctx)) | ||
283 | nvif_notify_put(&fctx->notify); | ||
284 | |||
266 | list_add_tail(&fence->head, &fctx->pending); | 285 | list_add_tail(&fence->head, &fctx->pending); |
267 | spin_unlock_irq(&fctx->lock); | 286 | spin_unlock_irq(&fctx->lock); |
268 | } | 287 | } |
@@ -276,13 +295,16 @@ nouveau_fence_done(struct nouveau_fence *fence) | |||
276 | if (fence->base.ops == &nouveau_fence_ops_legacy || | 295 | if (fence->base.ops == &nouveau_fence_ops_legacy || |
277 | fence->base.ops == &nouveau_fence_ops_uevent) { | 296 | fence->base.ops == &nouveau_fence_ops_uevent) { |
278 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); | 297 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
298 | struct nouveau_channel *chan; | ||
279 | unsigned long flags; | 299 | unsigned long flags; |
280 | 300 | ||
281 | if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) | 301 | if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) |
282 | return true; | 302 | return true; |
283 | 303 | ||
284 | spin_lock_irqsave(&fctx->lock, flags); | 304 | spin_lock_irqsave(&fctx->lock, flags); |
285 | nouveau_fence_update(fence->channel, fctx); | 305 | chan = rcu_dereference_protected(fence->channel, lockdep_is_held(&fctx->lock)); |
306 | if (chan && nouveau_fence_update(chan, fctx)) | ||
307 | nvif_notify_put(&fctx->notify); | ||
286 | spin_unlock_irqrestore(&fctx->lock, flags); | 308 | spin_unlock_irqrestore(&fctx->lock, flags); |
287 | } | 309 | } |
288 | return fence_is_signaled(&fence->base); | 310 | return fence_is_signaled(&fence->base); |
@@ -387,12 +409,18 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e | |||
387 | 409 | ||
388 | if (fence && (!exclusive || !fobj || !fobj->shared_count)) { | 410 | if (fence && (!exclusive || !fobj || !fobj->shared_count)) { |
389 | struct nouveau_channel *prev = NULL; | 411 | struct nouveau_channel *prev = NULL; |
412 | bool must_wait = true; | ||
390 | 413 | ||
391 | f = nouveau_local_fence(fence, chan->drm); | 414 | f = nouveau_local_fence(fence, chan->drm); |
392 | if (f) | 415 | if (f) { |
393 | prev = f->channel; | 416 | rcu_read_lock(); |
417 | prev = rcu_dereference(f->channel); | ||
418 | if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0)) | ||
419 | must_wait = false; | ||
420 | rcu_read_unlock(); | ||
421 | } | ||
394 | 422 | ||
395 | if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) | 423 | if (must_wait) |
396 | ret = fence_wait(fence, intr); | 424 | ret = fence_wait(fence, intr); |
397 | 425 | ||
398 | return ret; | 426 | return ret; |
@@ -403,19 +431,22 @@ nouveau_fence_sync(struct nouveau_bo *nvbo, struct nouveau_channel *chan, bool e | |||
403 | 431 | ||
404 | for (i = 0; i < fobj->shared_count && !ret; ++i) { | 432 | for (i = 0; i < fobj->shared_count && !ret; ++i) { |
405 | struct nouveau_channel *prev = NULL; | 433 | struct nouveau_channel *prev = NULL; |
434 | bool must_wait = true; | ||
406 | 435 | ||
407 | fence = rcu_dereference_protected(fobj->shared[i], | 436 | fence = rcu_dereference_protected(fobj->shared[i], |
408 | reservation_object_held(resv)); | 437 | reservation_object_held(resv)); |
409 | 438 | ||
410 | f = nouveau_local_fence(fence, chan->drm); | 439 | f = nouveau_local_fence(fence, chan->drm); |
411 | if (f) | 440 | if (f) { |
412 | prev = f->channel; | 441 | rcu_read_lock(); |
442 | prev = rcu_dereference(f->channel); | ||
443 | if (prev && (prev == chan || fctx->sync(f, prev, chan) == 0)) | ||
444 | must_wait = false; | ||
445 | rcu_read_unlock(); | ||
446 | } | ||
413 | 447 | ||
414 | if (!prev || (prev != chan && (ret = fctx->sync(f, prev, chan)))) | 448 | if (must_wait) |
415 | ret = fence_wait(fence, intr); | 449 | ret = fence_wait(fence, intr); |
416 | |||
417 | if (ret) | ||
418 | break; | ||
419 | } | 450 | } |
420 | 451 | ||
421 | return ret; | 452 | return ret; |
@@ -463,7 +494,7 @@ static const char *nouveau_fence_get_timeline_name(struct fence *f) | |||
463 | struct nouveau_fence *fence = from_fence(f); | 494 | struct nouveau_fence *fence = from_fence(f); |
464 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); | 495 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
465 | 496 | ||
466 | return fence->channel ? fctx->name : "dead channel"; | 497 | return !fctx->dead ? fctx->name : "dead channel"; |
467 | } | 498 | } |
468 | 499 | ||
469 | /* | 500 | /* |
@@ -476,9 +507,16 @@ static bool nouveau_fence_is_signaled(struct fence *f) | |||
476 | { | 507 | { |
477 | struct nouveau_fence *fence = from_fence(f); | 508 | struct nouveau_fence *fence = from_fence(f); |
478 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); | 509 | struct nouveau_fence_chan *fctx = nouveau_fctx(fence); |
479 | struct nouveau_channel *chan = fence->channel; | 510 | struct nouveau_channel *chan; |
511 | bool ret = false; | ||
512 | |||
513 | rcu_read_lock(); | ||
514 | chan = rcu_dereference(fence->channel); | ||
515 | if (chan) | ||
516 | ret = (int)(fctx->read(chan) - fence->base.seqno) >= 0; | ||
517 | rcu_read_unlock(); | ||
480 | 518 | ||
481 | return (int)(fctx->read(chan) - fence->base.seqno) >= 0; | 519 | return ret; |
482 | } | 520 | } |
483 | 521 | ||
484 | static bool nouveau_fence_no_signaling(struct fence *f) | 522 | static bool nouveau_fence_no_signaling(struct fence *f) |
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index 943b0b17b1fc..96e461c6f68f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h | |||
@@ -14,7 +14,7 @@ struct nouveau_fence { | |||
14 | 14 | ||
15 | bool sysmem; | 15 | bool sysmem; |
16 | 16 | ||
17 | struct nouveau_channel *channel; | 17 | struct nouveau_channel __rcu *channel; |
18 | unsigned long timeout; | 18 | unsigned long timeout; |
19 | }; | 19 | }; |
20 | 20 | ||
@@ -47,7 +47,7 @@ struct nouveau_fence_chan { | |||
47 | char name[32]; | 47 | char name[32]; |
48 | 48 | ||
49 | struct nvif_notify notify; | 49 | struct nvif_notify notify; |
50 | int notify_ref; | 50 | int notify_ref, dead; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | struct nouveau_fence_priv { | 53 | struct nouveau_fence_priv { |
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c index 300c4b3d4669..26baa9c05f6c 100644 --- a/drivers/gpu/drm/radeon/radeon_connectors.c +++ b/drivers/gpu/drm/radeon/radeon_connectors.c | |||
@@ -322,6 +322,12 @@ static void radeon_connector_get_edid(struct drm_connector *connector) | |||
322 | } | 322 | } |
323 | 323 | ||
324 | if (!radeon_connector->edid) { | 324 | if (!radeon_connector->edid) { |
325 | /* don't fetch the edid from the vbios if ddc fails and runpm is | ||
326 | * enabled so we report disconnected. | ||
327 | */ | ||
328 | if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) | ||
329 | return; | ||
330 | |||
325 | if (rdev->is_atom_bios) { | 331 | if (rdev->is_atom_bios) { |
326 | /* some laptops provide a hardcoded edid in rom for LCDs */ | 332 | /* some laptops provide a hardcoded edid in rom for LCDs */ |
327 | if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || | 333 | if (((connector->connector_type == DRM_MODE_CONNECTOR_LVDS) || |
@@ -826,6 +832,8 @@ static int radeon_lvds_mode_valid(struct drm_connector *connector, | |||
826 | static enum drm_connector_status | 832 | static enum drm_connector_status |
827 | radeon_lvds_detect(struct drm_connector *connector, bool force) | 833 | radeon_lvds_detect(struct drm_connector *connector, bool force) |
828 | { | 834 | { |
835 | struct drm_device *dev = connector->dev; | ||
836 | struct radeon_device *rdev = dev->dev_private; | ||
829 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); | 837 | struct radeon_connector *radeon_connector = to_radeon_connector(connector); |
830 | struct drm_encoder *encoder = radeon_best_single_encoder(connector); | 838 | struct drm_encoder *encoder = radeon_best_single_encoder(connector); |
831 | enum drm_connector_status ret = connector_status_disconnected; | 839 | enum drm_connector_status ret = connector_status_disconnected; |
@@ -842,7 +850,11 @@ radeon_lvds_detect(struct drm_connector *connector, bool force) | |||
842 | /* check if panel is valid */ | 850 | /* check if panel is valid */ |
843 | if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) | 851 | if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) |
844 | ret = connector_status_connected; | 852 | ret = connector_status_connected; |
845 | 853 | /* don't fetch the edid from the vbios if ddc fails and runpm is | |
854 | * enabled so we report disconnected. | ||
855 | */ | ||
856 | if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) | ||
857 | ret = connector_status_disconnected; | ||
846 | } | 858 | } |
847 | 859 | ||
848 | /* check for edid as well */ | 860 | /* check for edid as well */ |
@@ -1589,6 +1601,11 @@ radeon_dp_detect(struct drm_connector *connector, bool force) | |||
1589 | /* check if panel is valid */ | 1601 | /* check if panel is valid */ |
1590 | if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) | 1602 | if (native_mode->hdisplay >= 320 && native_mode->vdisplay >= 240) |
1591 | ret = connector_status_connected; | 1603 | ret = connector_status_connected; |
1604 | /* don't fetch the edid from the vbios if ddc fails and runpm is | ||
1605 | * enabled so we report disconnected. | ||
1606 | */ | ||
1607 | if ((rdev->flags & RADEON_IS_PX) && (radeon_runtime_pm != 0)) | ||
1608 | ret = connector_status_disconnected; | ||
1592 | } | 1609 | } |
1593 | /* eDP is always DP */ | 1610 | /* eDP is always DP */ |
1594 | radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; | 1611 | radeon_dig_connector->dp_sink_type = CONNECTOR_OBJECT_ID_DISPLAYPORT; |
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c index a3e7aed7e680..6f377de099f9 100644 --- a/drivers/gpu/drm/radeon/radeon_cs.c +++ b/drivers/gpu/drm/radeon/radeon_cs.c | |||
@@ -251,22 +251,19 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority | |||
251 | 251 | ||
252 | static int radeon_cs_sync_rings(struct radeon_cs_parser *p) | 252 | static int radeon_cs_sync_rings(struct radeon_cs_parser *p) |
253 | { | 253 | { |
254 | int i, r = 0; | 254 | struct radeon_cs_reloc *reloc; |
255 | int r; | ||
255 | 256 | ||
256 | for (i = 0; i < p->nrelocs; i++) { | 257 | list_for_each_entry(reloc, &p->validated, tv.head) { |
257 | struct reservation_object *resv; | 258 | struct reservation_object *resv; |
258 | 259 | ||
259 | if (!p->relocs[i].robj) | 260 | resv = reloc->robj->tbo.resv; |
260 | continue; | ||
261 | |||
262 | resv = p->relocs[i].robj->tbo.resv; | ||
263 | r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv, | 261 | r = radeon_semaphore_sync_resv(p->rdev, p->ib.semaphore, resv, |
264 | p->relocs[i].tv.shared); | 262 | reloc->tv.shared); |
265 | |||
266 | if (r) | 263 | if (r) |
267 | break; | 264 | return r; |
268 | } | 265 | } |
269 | return r; | 266 | return 0; |
270 | } | 267 | } |
271 | 268 | ||
272 | /* XXX: note that this is called from the legacy UMS CS ioctl as well */ | 269 | /* XXX: note that this is called from the legacy UMS CS ioctl as well */ |
diff --git a/drivers/gpu/drm/radeon/radeon_irq_kms.c b/drivers/gpu/drm/radeon/radeon_irq_kms.c index 7784911d78ef..00fc59762e0d 100644 --- a/drivers/gpu/drm/radeon/radeon_irq_kms.c +++ b/drivers/gpu/drm/radeon/radeon_irq_kms.c | |||
@@ -185,6 +185,16 @@ static bool radeon_msi_ok(struct radeon_device *rdev) | |||
185 | if (rdev->flags & RADEON_IS_AGP) | 185 | if (rdev->flags & RADEON_IS_AGP) |
186 | return false; | 186 | return false; |
187 | 187 | ||
188 | /* | ||
189 | * Older chips have a HW limitation, they can only generate 40 bits | ||
190 | * of address for "64-bit" MSIs which breaks on some platforms, notably | ||
191 | * IBM POWER servers, so we limit them | ||
192 | */ | ||
193 | if (rdev->family < CHIP_BONAIRE) { | ||
194 | dev_info(rdev->dev, "radeon: MSI limited to 32-bit\n"); | ||
195 | rdev->pdev->no_64bit_msi = 1; | ||
196 | } | ||
197 | |||
188 | /* force MSI on */ | 198 | /* force MSI on */ |
189 | if (radeon_msi == 1) | 199 | if (radeon_msi == 1) |
190 | return true; | 200 | return true; |
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 8309b11e674d..03586763ee86 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c | |||
@@ -795,6 +795,8 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc, | |||
795 | 795 | ||
796 | /* Get associated drm_crtc: */ | 796 | /* Get associated drm_crtc: */ |
797 | drmcrtc = &rdev->mode_info.crtcs[crtc]->base; | 797 | drmcrtc = &rdev->mode_info.crtcs[crtc]->base; |
798 | if (!drmcrtc) | ||
799 | return -EINVAL; | ||
798 | 800 | ||
799 | /* Helper routine in DRM core does all the work: */ | 801 | /* Helper routine in DRM core does all the work: */ |
800 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, | 802 | return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error, |
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c index 99a960a4f302..4c0d786d5c7a 100644 --- a/drivers/gpu/drm/radeon/radeon_object.c +++ b/drivers/gpu/drm/radeon/radeon_object.c | |||
@@ -213,6 +213,13 @@ int radeon_bo_create(struct radeon_device *rdev, | |||
213 | if (!(rdev->flags & RADEON_IS_PCIE)) | 213 | if (!(rdev->flags & RADEON_IS_PCIE)) |
214 | bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); | 214 | bo->flags &= ~(RADEON_GEM_GTT_WC | RADEON_GEM_GTT_UC); |
215 | 215 | ||
216 | #ifdef CONFIG_X86_32 | ||
217 | /* XXX: Write-combined CPU mappings of GTT seem broken on 32-bit | ||
218 | * See https://bugs.freedesktop.org/show_bug.cgi?id=84627 | ||
219 | */ | ||
220 | bo->flags &= ~RADEON_GEM_GTT_WC; | ||
221 | #endif | ||
222 | |||
216 | radeon_ttm_placement_from_domain(bo, domain); | 223 | radeon_ttm_placement_from_domain(bo, domain); |
217 | /* Kernel allocation are uninterruptible */ | 224 | /* Kernel allocation are uninterruptible */ |
218 | down_read(&rdev->pm.mclk_lock); | 225 | down_read(&rdev->pm.mclk_lock); |
diff --git a/drivers/hwmon/g762.c b/drivers/hwmon/g762.c index 6aac695b1688..9b55e673b67c 100644 --- a/drivers/hwmon/g762.c +++ b/drivers/hwmon/g762.c | |||
@@ -1084,10 +1084,8 @@ static int g762_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
1084 | if (ret) | 1084 | if (ret) |
1085 | goto clock_dis; | 1085 | goto clock_dis; |
1086 | 1086 | ||
1087 | data->hwmon_dev = devm_hwmon_device_register_with_groups(dev, | 1087 | data->hwmon_dev = hwmon_device_register_with_groups(dev, client->name, |
1088 | client->name, | 1088 | data, g762_groups); |
1089 | data, | ||
1090 | g762_groups); | ||
1091 | if (IS_ERR(data->hwmon_dev)) { | 1089 | if (IS_ERR(data->hwmon_dev)) { |
1092 | ret = PTR_ERR(data->hwmon_dev); | 1090 | ret = PTR_ERR(data->hwmon_dev); |
1093 | goto clock_dis; | 1091 | goto clock_dis; |
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 63f3f03ecc9b..c604f4c3ac0d 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c | |||
@@ -111,6 +111,8 @@ | |||
111 | #define CDNS_I2C_DIVA_MAX 4 | 111 | #define CDNS_I2C_DIVA_MAX 4 |
112 | #define CDNS_I2C_DIVB_MAX 64 | 112 | #define CDNS_I2C_DIVB_MAX 64 |
113 | 113 | ||
114 | #define CDNS_I2C_TIMEOUT_MAX 0xFF | ||
115 | |||
114 | #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) | 116 | #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) |
115 | #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) | 117 | #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) |
116 | 118 | ||
@@ -852,6 +854,15 @@ static int cdns_i2c_probe(struct platform_device *pdev) | |||
852 | goto err_clk_dis; | 854 | goto err_clk_dis; |
853 | } | 855 | } |
854 | 856 | ||
857 | /* | ||
858 | * Cadence I2C controller has a bug wherein it generates | ||
859 | * invalid read transaction after HW timeout in master receiver mode. | ||
860 | * HW timeout is not used by this driver and the interrupt is disabled. | ||
861 | * But the feature itself cannot be disabled. Hence maximum value | ||
862 | * is written to this register to reduce the chances of error. | ||
863 | */ | ||
864 | cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); | ||
865 | |||
855 | dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n", | 866 | dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n", |
856 | id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq); | 867 | id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq); |
857 | 868 | ||
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index d15b7c9b9219..01f0cd87a4a5 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c | |||
@@ -407,11 +407,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) | |||
407 | if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { | 407 | if (dev->cmd_err & DAVINCI_I2C_STR_NACK) { |
408 | if (msg->flags & I2C_M_IGNORE_NAK) | 408 | if (msg->flags & I2C_M_IGNORE_NAK) |
409 | return msg->len; | 409 | return msg->len; |
410 | if (stop) { | 410 | w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); |
411 | w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG); | 411 | w |= DAVINCI_I2C_MDR_STP; |
412 | w |= DAVINCI_I2C_MDR_STP; | 412 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); |
413 | davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w); | ||
414 | } | ||
415 | return -EREMOTEIO; | 413 | return -EREMOTEIO; |
416 | } | 414 | } |
417 | return -EIO; | 415 | return -EIO; |
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index edca99dbba23..23628b7bfb8d 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c | |||
@@ -359,7 +359,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev) | |||
359 | } | 359 | } |
360 | 360 | ||
361 | /* Configure Tx/Rx FIFO threshold levels */ | 361 | /* Configure Tx/Rx FIFO threshold levels */ |
362 | dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); | 362 | dw_writel(dev, dev->tx_fifo_depth / 2, DW_IC_TX_TL); |
363 | dw_writel(dev, 0, DW_IC_RX_TL); | 363 | dw_writel(dev, 0, DW_IC_RX_TL); |
364 | 364 | ||
365 | /* configure the i2c master */ | 365 | /* configure the i2c master */ |
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 26942c159de1..277a2288d4a8 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c | |||
@@ -922,14 +922,12 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) | |||
922 | if (stat & OMAP_I2C_STAT_NACK) { | 922 | if (stat & OMAP_I2C_STAT_NACK) { |
923 | err |= OMAP_I2C_STAT_NACK; | 923 | err |= OMAP_I2C_STAT_NACK; |
924 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); | 924 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_NACK); |
925 | break; | ||
926 | } | 925 | } |
927 | 926 | ||
928 | if (stat & OMAP_I2C_STAT_AL) { | 927 | if (stat & OMAP_I2C_STAT_AL) { |
929 | dev_err(dev->dev, "Arbitration lost\n"); | 928 | dev_err(dev->dev, "Arbitration lost\n"); |
930 | err |= OMAP_I2C_STAT_AL; | 929 | err |= OMAP_I2C_STAT_AL; |
931 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); | 930 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_AL); |
932 | break; | ||
933 | } | 931 | } |
934 | 932 | ||
935 | /* | 933 | /* |
@@ -954,11 +952,13 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) | |||
954 | if (dev->fifo_size) | 952 | if (dev->fifo_size) |
955 | num_bytes = dev->buf_len; | 953 | num_bytes = dev->buf_len; |
956 | 954 | ||
957 | omap_i2c_receive_data(dev, num_bytes, true); | 955 | if (dev->errata & I2C_OMAP_ERRATA_I207) { |
958 | |||
959 | if (dev->errata & I2C_OMAP_ERRATA_I207) | ||
960 | i2c_omap_errata_i207(dev, stat); | 956 | i2c_omap_errata_i207(dev, stat); |
957 | num_bytes = (omap_i2c_read_reg(dev, | ||
958 | OMAP_I2C_BUFSTAT_REG) >> 8) & 0x3F; | ||
959 | } | ||
961 | 960 | ||
961 | omap_i2c_receive_data(dev, num_bytes, true); | ||
962 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); | 962 | omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RDR); |
963 | continue; | 963 | continue; |
964 | } | 964 | } |
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c index 22c096ce39ad..513bd6d14293 100644 --- a/drivers/iio/accel/bmc150-accel.c +++ b/drivers/iio/accel/bmc150-accel.c | |||
@@ -44,6 +44,9 @@ | |||
44 | 44 | ||
45 | #define BMC150_ACCEL_REG_INT_STATUS_2 0x0B | 45 | #define BMC150_ACCEL_REG_INT_STATUS_2 0x0B |
46 | #define BMC150_ACCEL_ANY_MOTION_MASK 0x07 | 46 | #define BMC150_ACCEL_ANY_MOTION_MASK 0x07 |
47 | #define BMC150_ACCEL_ANY_MOTION_BIT_X BIT(0) | ||
48 | #define BMC150_ACCEL_ANY_MOTION_BIT_Y BIT(1) | ||
49 | #define BMC150_ACCEL_ANY_MOTION_BIT_Z BIT(2) | ||
47 | #define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) | 50 | #define BMC150_ACCEL_ANY_MOTION_BIT_SIGN BIT(3) |
48 | 51 | ||
49 | #define BMC150_ACCEL_REG_PMU_LPW 0x11 | 52 | #define BMC150_ACCEL_REG_PMU_LPW 0x11 |
@@ -92,9 +95,9 @@ | |||
92 | #define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF | 95 | #define BMC150_ACCEL_SLOPE_THRES_MASK 0xFF |
93 | 96 | ||
94 | /* Slope duration in terms of number of samples */ | 97 | /* Slope duration in terms of number of samples */ |
95 | #define BMC150_ACCEL_DEF_SLOPE_DURATION 2 | 98 | #define BMC150_ACCEL_DEF_SLOPE_DURATION 1 |
96 | /* in terms of multiples of g's/LSB, based on range */ | 99 | /* in terms of multiples of g's/LSB, based on range */ |
97 | #define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 5 | 100 | #define BMC150_ACCEL_DEF_SLOPE_THRESHOLD 1 |
98 | 101 | ||
99 | #define BMC150_ACCEL_REG_XOUT_L 0x02 | 102 | #define BMC150_ACCEL_REG_XOUT_L 0x02 |
100 | 103 | ||
@@ -536,6 +539,9 @@ static int bmc150_accel_set_power_state(struct bmc150_accel_data *data, bool on) | |||
536 | if (ret < 0) { | 539 | if (ret < 0) { |
537 | dev_err(&data->client->dev, | 540 | dev_err(&data->client->dev, |
538 | "Failed: bmc150_accel_set_power_state for %d\n", on); | 541 | "Failed: bmc150_accel_set_power_state for %d\n", on); |
542 | if (on) | ||
543 | pm_runtime_put_noidle(&data->client->dev); | ||
544 | |||
539 | return ret; | 545 | return ret; |
540 | } | 546 | } |
541 | 547 | ||
@@ -811,6 +817,7 @@ static int bmc150_accel_write_event_config(struct iio_dev *indio_dev, | |||
811 | 817 | ||
812 | ret = bmc150_accel_setup_any_motion_interrupt(data, state); | 818 | ret = bmc150_accel_setup_any_motion_interrupt(data, state); |
813 | if (ret < 0) { | 819 | if (ret < 0) { |
820 | bmc150_accel_set_power_state(data, false); | ||
814 | mutex_unlock(&data->mutex); | 821 | mutex_unlock(&data->mutex); |
815 | return ret; | 822 | return ret; |
816 | } | 823 | } |
@@ -846,7 +853,7 @@ static const struct attribute_group bmc150_accel_attrs_group = { | |||
846 | 853 | ||
847 | static const struct iio_event_spec bmc150_accel_event = { | 854 | static const struct iio_event_spec bmc150_accel_event = { |
848 | .type = IIO_EV_TYPE_ROC, | 855 | .type = IIO_EV_TYPE_ROC, |
849 | .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING, | 856 | .dir = IIO_EV_DIR_EITHER, |
850 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | | 857 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | |
851 | BIT(IIO_EV_INFO_ENABLE) | | 858 | BIT(IIO_EV_INFO_ENABLE) | |
852 | BIT(IIO_EV_INFO_PERIOD) | 859 | BIT(IIO_EV_INFO_PERIOD) |
@@ -1054,6 +1061,7 @@ static int bmc150_accel_data_rdy_trigger_set_state(struct iio_trigger *trig, | |||
1054 | else | 1061 | else |
1055 | ret = bmc150_accel_setup_new_data_interrupt(data, state); | 1062 | ret = bmc150_accel_setup_new_data_interrupt(data, state); |
1056 | if (ret < 0) { | 1063 | if (ret < 0) { |
1064 | bmc150_accel_set_power_state(data, false); | ||
1057 | mutex_unlock(&data->mutex); | 1065 | mutex_unlock(&data->mutex); |
1058 | return ret; | 1066 | return ret; |
1059 | } | 1067 | } |
@@ -1092,12 +1100,26 @@ static irqreturn_t bmc150_accel_event_handler(int irq, void *private) | |||
1092 | else | 1100 | else |
1093 | dir = IIO_EV_DIR_RISING; | 1101 | dir = IIO_EV_DIR_RISING; |
1094 | 1102 | ||
1095 | if (ret & BMC150_ACCEL_ANY_MOTION_MASK) | 1103 | if (ret & BMC150_ACCEL_ANY_MOTION_BIT_X) |
1104 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, | ||
1105 | 0, | ||
1106 | IIO_MOD_X, | ||
1107 | IIO_EV_TYPE_ROC, | ||
1108 | dir), | ||
1109 | data->timestamp); | ||
1110 | if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Y) | ||
1096 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, | 1111 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, |
1097 | 0, | 1112 | 0, |
1098 | IIO_MOD_X_OR_Y_OR_Z, | 1113 | IIO_MOD_Y, |
1099 | IIO_EV_TYPE_ROC, | 1114 | IIO_EV_TYPE_ROC, |
1100 | IIO_EV_DIR_EITHER), | 1115 | dir), |
1116 | data->timestamp); | ||
1117 | if (ret & BMC150_ACCEL_ANY_MOTION_BIT_Z) | ||
1118 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ACCEL, | ||
1119 | 0, | ||
1120 | IIO_MOD_Z, | ||
1121 | IIO_EV_TYPE_ROC, | ||
1122 | dir), | ||
1101 | data->timestamp); | 1123 | data->timestamp); |
1102 | ack_intr_status: | 1124 | ack_intr_status: |
1103 | if (!data->dready_trigger_on) | 1125 | if (!data->dready_trigger_on) |
@@ -1354,10 +1376,14 @@ static int bmc150_accel_runtime_suspend(struct device *dev) | |||
1354 | { | 1376 | { |
1355 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | 1377 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
1356 | struct bmc150_accel_data *data = iio_priv(indio_dev); | 1378 | struct bmc150_accel_data *data = iio_priv(indio_dev); |
1379 | int ret; | ||
1357 | 1380 | ||
1358 | dev_dbg(&data->client->dev, __func__); | 1381 | dev_dbg(&data->client->dev, __func__); |
1382 | ret = bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); | ||
1383 | if (ret < 0) | ||
1384 | return -EAGAIN; | ||
1359 | 1385 | ||
1360 | return bmc150_accel_set_mode(data, BMC150_ACCEL_SLEEP_MODE_SUSPEND, 0); | 1386 | return 0; |
1361 | } | 1387 | } |
1362 | 1388 | ||
1363 | static int bmc150_accel_runtime_resume(struct device *dev) | 1389 | static int bmc150_accel_runtime_resume(struct device *dev) |
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c index a23e58c4ed99..320aa72c0349 100644 --- a/drivers/iio/accel/kxcjk-1013.c +++ b/drivers/iio/accel/kxcjk-1013.c | |||
@@ -269,6 +269,8 @@ static int kxcjk1013_set_range(struct kxcjk1013_data *data, int range_index) | |||
269 | return ret; | 269 | return ret; |
270 | } | 270 | } |
271 | 271 | ||
272 | ret &= ~(KXCJK1013_REG_CTRL1_BIT_GSEL0 | | ||
273 | KXCJK1013_REG_CTRL1_BIT_GSEL1); | ||
272 | ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); | 274 | ret |= (KXCJK1013_scale_table[range_index].gsel_0 << 3); |
273 | ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); | 275 | ret |= (KXCJK1013_scale_table[range_index].gsel_1 << 4); |
274 | 276 | ||
diff --git a/drivers/iio/adc/men_z188_adc.c b/drivers/iio/adc/men_z188_adc.c index b58d6302521f..d095efe1ba14 100644 --- a/drivers/iio/adc/men_z188_adc.c +++ b/drivers/iio/adc/men_z188_adc.c | |||
@@ -152,6 +152,7 @@ static void men_z188_remove(struct mcb_device *dev) | |||
152 | 152 | ||
153 | static const struct mcb_device_id men_z188_ids[] = { | 153 | static const struct mcb_device_id men_z188_ids[] = { |
154 | { .device = 0xbc }, | 154 | { .device = 0xbc }, |
155 | { } | ||
155 | }; | 156 | }; |
156 | MODULE_DEVICE_TABLE(mcb, men_z188_ids); | 157 | MODULE_DEVICE_TABLE(mcb, men_z188_ids); |
157 | 158 | ||
diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c index 1f967e0d688e..d2fa526740ca 100644 --- a/drivers/iio/gyro/bmg160.c +++ b/drivers/iio/gyro/bmg160.c | |||
@@ -67,6 +67,9 @@ | |||
67 | #define BMG160_REG_INT_EN_0 0x15 | 67 | #define BMG160_REG_INT_EN_0 0x15 |
68 | #define BMG160_DATA_ENABLE_INT BIT(7) | 68 | #define BMG160_DATA_ENABLE_INT BIT(7) |
69 | 69 | ||
70 | #define BMG160_REG_INT_EN_1 0x16 | ||
71 | #define BMG160_INT1_BIT_OD BIT(1) | ||
72 | |||
70 | #define BMG160_REG_XOUT_L 0x02 | 73 | #define BMG160_REG_XOUT_L 0x02 |
71 | #define BMG160_AXIS_TO_REG(axis) (BMG160_REG_XOUT_L + (axis * 2)) | 74 | #define BMG160_AXIS_TO_REG(axis) (BMG160_REG_XOUT_L + (axis * 2)) |
72 | 75 | ||
@@ -82,6 +85,9 @@ | |||
82 | 85 | ||
83 | #define BMG160_REG_INT_STATUS_2 0x0B | 86 | #define BMG160_REG_INT_STATUS_2 0x0B |
84 | #define BMG160_ANY_MOTION_MASK 0x07 | 87 | #define BMG160_ANY_MOTION_MASK 0x07 |
88 | #define BMG160_ANY_MOTION_BIT_X BIT(0) | ||
89 | #define BMG160_ANY_MOTION_BIT_Y BIT(1) | ||
90 | #define BMG160_ANY_MOTION_BIT_Z BIT(2) | ||
85 | 91 | ||
86 | #define BMG160_REG_TEMP 0x08 | 92 | #define BMG160_REG_TEMP 0x08 |
87 | #define BMG160_TEMP_CENTER_VAL 23 | 93 | #define BMG160_TEMP_CENTER_VAL 23 |
@@ -222,6 +228,19 @@ static int bmg160_chip_init(struct bmg160_data *data) | |||
222 | data->slope_thres = ret; | 228 | data->slope_thres = ret; |
223 | 229 | ||
224 | /* Set default interrupt mode */ | 230 | /* Set default interrupt mode */ |
231 | ret = i2c_smbus_read_byte_data(data->client, BMG160_REG_INT_EN_1); | ||
232 | if (ret < 0) { | ||
233 | dev_err(&data->client->dev, "Error reading reg_int_en_1\n"); | ||
234 | return ret; | ||
235 | } | ||
236 | ret &= ~BMG160_INT1_BIT_OD; | ||
237 | ret = i2c_smbus_write_byte_data(data->client, | ||
238 | BMG160_REG_INT_EN_1, ret); | ||
239 | if (ret < 0) { | ||
240 | dev_err(&data->client->dev, "Error writing reg_int_en_1\n"); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
225 | ret = i2c_smbus_write_byte_data(data->client, | 244 | ret = i2c_smbus_write_byte_data(data->client, |
226 | BMG160_REG_INT_RST_LATCH, | 245 | BMG160_REG_INT_RST_LATCH, |
227 | BMG160_INT_MODE_LATCH_INT | | 246 | BMG160_INT_MODE_LATCH_INT | |
@@ -250,6 +269,9 @@ static int bmg160_set_power_state(struct bmg160_data *data, bool on) | |||
250 | if (ret < 0) { | 269 | if (ret < 0) { |
251 | dev_err(&data->client->dev, | 270 | dev_err(&data->client->dev, |
252 | "Failed: bmg160_set_power_state for %d\n", on); | 271 | "Failed: bmg160_set_power_state for %d\n", on); |
272 | if (on) | ||
273 | pm_runtime_put_noidle(&data->client->dev); | ||
274 | |||
253 | return ret; | 275 | return ret; |
254 | } | 276 | } |
255 | #endif | 277 | #endif |
@@ -705,6 +727,7 @@ static int bmg160_write_event_config(struct iio_dev *indio_dev, | |||
705 | 727 | ||
706 | ret = bmg160_setup_any_motion_interrupt(data, state); | 728 | ret = bmg160_setup_any_motion_interrupt(data, state); |
707 | if (ret < 0) { | 729 | if (ret < 0) { |
730 | bmg160_set_power_state(data, false); | ||
708 | mutex_unlock(&data->mutex); | 731 | mutex_unlock(&data->mutex); |
709 | return ret; | 732 | return ret; |
710 | } | 733 | } |
@@ -743,7 +766,7 @@ static const struct attribute_group bmg160_attrs_group = { | |||
743 | 766 | ||
744 | static const struct iio_event_spec bmg160_event = { | 767 | static const struct iio_event_spec bmg160_event = { |
745 | .type = IIO_EV_TYPE_ROC, | 768 | .type = IIO_EV_TYPE_ROC, |
746 | .dir = IIO_EV_DIR_RISING | IIO_EV_DIR_FALLING, | 769 | .dir = IIO_EV_DIR_EITHER, |
747 | .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | | 770 | .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE) | |
748 | BIT(IIO_EV_INFO_ENABLE) | 771 | BIT(IIO_EV_INFO_ENABLE) |
749 | }; | 772 | }; |
@@ -871,6 +894,7 @@ static int bmg160_data_rdy_trigger_set_state(struct iio_trigger *trig, | |||
871 | else | 894 | else |
872 | ret = bmg160_setup_new_data_interrupt(data, state); | 895 | ret = bmg160_setup_new_data_interrupt(data, state); |
873 | if (ret < 0) { | 896 | if (ret < 0) { |
897 | bmg160_set_power_state(data, false); | ||
874 | mutex_unlock(&data->mutex); | 898 | mutex_unlock(&data->mutex); |
875 | return ret; | 899 | return ret; |
876 | } | 900 | } |
@@ -908,10 +932,24 @@ static irqreturn_t bmg160_event_handler(int irq, void *private) | |||
908 | else | 932 | else |
909 | dir = IIO_EV_DIR_FALLING; | 933 | dir = IIO_EV_DIR_FALLING; |
910 | 934 | ||
911 | if (ret & BMG160_ANY_MOTION_MASK) | 935 | if (ret & BMG160_ANY_MOTION_BIT_X) |
912 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, | 936 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, |
913 | 0, | 937 | 0, |
914 | IIO_MOD_X_OR_Y_OR_Z, | 938 | IIO_MOD_X, |
939 | IIO_EV_TYPE_ROC, | ||
940 | dir), | ||
941 | data->timestamp); | ||
942 | if (ret & BMG160_ANY_MOTION_BIT_Y) | ||
943 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, | ||
944 | 0, | ||
945 | IIO_MOD_Y, | ||
946 | IIO_EV_TYPE_ROC, | ||
947 | dir), | ||
948 | data->timestamp); | ||
949 | if (ret & BMG160_ANY_MOTION_BIT_Z) | ||
950 | iio_push_event(indio_dev, IIO_MOD_EVENT_CODE(IIO_ANGL_VEL, | ||
951 | 0, | ||
952 | IIO_MOD_Z, | ||
915 | IIO_EV_TYPE_ROC, | 953 | IIO_EV_TYPE_ROC, |
916 | dir), | 954 | dir), |
917 | data->timestamp); | 955 | data->timestamp); |
@@ -1169,8 +1207,15 @@ static int bmg160_runtime_suspend(struct device *dev) | |||
1169 | { | 1207 | { |
1170 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); | 1208 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
1171 | struct bmg160_data *data = iio_priv(indio_dev); | 1209 | struct bmg160_data *data = iio_priv(indio_dev); |
1210 | int ret; | ||
1211 | |||
1212 | ret = bmg160_set_mode(data, BMG160_MODE_SUSPEND); | ||
1213 | if (ret < 0) { | ||
1214 | dev_err(&data->client->dev, "set mode failed\n"); | ||
1215 | return -EAGAIN; | ||
1216 | } | ||
1172 | 1217 | ||
1173 | return bmg160_set_mode(data, BMG160_MODE_SUSPEND); | 1218 | return 0; |
1174 | } | 1219 | } |
1175 | 1220 | ||
1176 | static int bmg160_runtime_resume(struct device *dev) | 1221 | static int bmg160_runtime_resume(struct device *dev) |
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index bc203485716d..8afa28e4570e 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c | |||
@@ -421,7 +421,7 @@ static int evdev_open(struct inode *inode, struct file *file) | |||
421 | 421 | ||
422 | err_free_client: | 422 | err_free_client: |
423 | evdev_detach_client(evdev, client); | 423 | evdev_detach_client(evdev, client); |
424 | kfree(client); | 424 | kvfree(client); |
425 | return error; | 425 | return error; |
426 | } | 426 | } |
427 | 427 | ||
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 2ed7905a068f..fc55f0d15b70 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c | |||
@@ -1179,9 +1179,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id | |||
1179 | } | 1179 | } |
1180 | 1180 | ||
1181 | ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; | 1181 | ep_irq_in = &intf->cur_altsetting->endpoint[1].desc; |
1182 | usb_fill_bulk_urb(xpad->bulk_out, udev, | 1182 | if (usb_endpoint_is_bulk_out(ep_irq_in)) { |
1183 | usb_sndbulkpipe(udev, ep_irq_in->bEndpointAddress), | 1183 | usb_fill_bulk_urb(xpad->bulk_out, udev, |
1184 | xpad->bdata, XPAD_PKT_LEN, xpad_bulk_out, xpad); | 1184 | usb_sndbulkpipe(udev, |
1185 | ep_irq_in->bEndpointAddress), | ||
1186 | xpad->bdata, XPAD_PKT_LEN, | ||
1187 | xpad_bulk_out, xpad); | ||
1188 | } else { | ||
1189 | usb_fill_int_urb(xpad->bulk_out, udev, | ||
1190 | usb_sndintpipe(udev, | ||
1191 | ep_irq_in->bEndpointAddress), | ||
1192 | xpad->bdata, XPAD_PKT_LEN, | ||
1193 | xpad_bulk_out, xpad, 0); | ||
1194 | } | ||
1185 | 1195 | ||
1186 | /* | 1196 | /* |
1187 | * Submit the int URB immediately rather than waiting for open | 1197 | * Submit the int URB immediately rather than waiting for open |
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index 3fcb6b3cb0bd..f2b978026407 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c | |||
@@ -428,14 +428,6 @@ static void elantech_report_trackpoint(struct psmouse *psmouse, | |||
428 | int x, y; | 428 | int x, y; |
429 | u32 t; | 429 | u32 t; |
430 | 430 | ||
431 | if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev, | ||
432 | !tp_dev, | ||
433 | psmouse_fmt("Unexpected trackpoint message\n"))) { | ||
434 | if (etd->debug == 1) | ||
435 | elantech_packet_dump(psmouse); | ||
436 | return; | ||
437 | } | ||
438 | |||
439 | t = get_unaligned_le32(&packet[0]); | 431 | t = get_unaligned_le32(&packet[0]); |
440 | 432 | ||
441 | switch (t & ~7U) { | 433 | switch (t & ~7U) { |
@@ -793,7 +785,7 @@ static int elantech_packet_check_v4(struct psmouse *psmouse) | |||
793 | unsigned char packet_type = packet[3] & 0x03; | 785 | unsigned char packet_type = packet[3] & 0x03; |
794 | bool sanity_check; | 786 | bool sanity_check; |
795 | 787 | ||
796 | if ((packet[3] & 0x0f) == 0x06) | 788 | if (etd->tp_dev && (packet[3] & 0x0f) == 0x06) |
797 | return PACKET_TRACKPOINT; | 789 | return PACKET_TRACKPOINT; |
798 | 790 | ||
799 | /* | 791 | /* |
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 2a7a9174c702..f9472920d986 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c | |||
@@ -143,6 +143,10 @@ static const struct min_max_quirk min_max_pnpid_table[] = { | |||
143 | (const char * const []){"LEN2001", NULL}, | 143 | (const char * const []){"LEN2001", NULL}, |
144 | 1024, 5022, 2508, 4832 | 144 | 1024, 5022, 2508, 4832 |
145 | }, | 145 | }, |
146 | { | ||
147 | (const char * const []){"LEN2006", NULL}, | ||
148 | 1264, 5675, 1171, 4688 | ||
149 | }, | ||
146 | { } | 150 | { } |
147 | }; | 151 | }; |
148 | 152 | ||
diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c index 6ae3cdee0681..cc4f9d80122e 100644 --- a/drivers/irqchip/irq-atmel-aic-common.c +++ b/drivers/irqchip/irq-atmel-aic-common.c | |||
@@ -217,8 +217,9 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node, | |||
217 | } | 217 | } |
218 | 218 | ||
219 | ret = irq_alloc_domain_generic_chips(domain, 32, 1, name, | 219 | ret = irq_alloc_domain_generic_chips(domain, 32, 1, name, |
220 | handle_level_irq, 0, 0, | 220 | handle_fasteoi_irq, |
221 | IRQCHIP_SKIP_SET_WAKE); | 221 | IRQ_NOREQUEST | IRQ_NOPROBE | |
222 | IRQ_NOAUTOEN, 0, 0); | ||
222 | if (ret) | 223 | if (ret) |
223 | goto err_domain_remove; | 224 | goto err_domain_remove; |
224 | 225 | ||
@@ -230,7 +231,6 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node, | |||
230 | gc->unused = 0; | 231 | gc->unused = 0; |
231 | gc->wake_enabled = ~0; | 232 | gc->wake_enabled = ~0; |
232 | gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK; | 233 | gc->chip_types[0].type = IRQ_TYPE_SENSE_MASK; |
233 | gc->chip_types[0].handler = handle_fasteoi_irq; | ||
234 | gc->chip_types[0].chip.irq_eoi = irq_gc_eoi; | 234 | gc->chip_types[0].chip.irq_eoi = irq_gc_eoi; |
235 | gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; | 235 | gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake; |
236 | gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown; | 236 | gc->chip_types[0].chip.irq_shutdown = aic_common_shutdown; |
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c index b9f4fb808e49..5fb38a2ac226 100644 --- a/drivers/irqchip/irq-bcm7120-l2.c +++ b/drivers/irqchip/irq-bcm7120-l2.c | |||
@@ -101,9 +101,9 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn, | |||
101 | int parent_irq; | 101 | int parent_irq; |
102 | 102 | ||
103 | parent_irq = irq_of_parse_and_map(dn, irq); | 103 | parent_irq = irq_of_parse_and_map(dn, irq); |
104 | if (parent_irq < 0) { | 104 | if (!parent_irq) { |
105 | pr_err("failed to map interrupt %d\n", irq); | 105 | pr_err("failed to map interrupt %d\n", irq); |
106 | return parent_irq; | 106 | return -EINVAL; |
107 | } | 107 | } |
108 | 108 | ||
109 | data->irq_map_mask |= be32_to_cpup(map_mask + irq); | 109 | data->irq_map_mask |= be32_to_cpup(map_mask + irq); |
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c index c15c840987d2..14691a4cb84c 100644 --- a/drivers/irqchip/irq-brcmstb-l2.c +++ b/drivers/irqchip/irq-brcmstb-l2.c | |||
@@ -135,9 +135,9 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np, | |||
135 | __raw_writel(0xffffffff, data->base + CPU_CLEAR); | 135 | __raw_writel(0xffffffff, data->base + CPU_CLEAR); |
136 | 136 | ||
137 | data->parent_irq = irq_of_parse_and_map(np, 0); | 137 | data->parent_irq = irq_of_parse_and_map(np, 0); |
138 | if (data->parent_irq < 0) { | 138 | if (!data->parent_irq) { |
139 | pr_err("failed to find parent interrupt\n"); | 139 | pr_err("failed to find parent interrupt\n"); |
140 | ret = data->parent_irq; | 140 | ret = -EINVAL; |
141 | goto out_unmap; | 141 | goto out_unmap; |
142 | } | 142 | } |
143 | 143 | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 932ed9be9ff3..b10aaeda2bb4 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c | |||
@@ -2190,7 +2190,7 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev, | |||
2190 | ret = smiapp_set_compose(subdev, fh, sel); | 2190 | ret = smiapp_set_compose(subdev, fh, sel); |
2191 | break; | 2191 | break; |
2192 | default: | 2192 | default: |
2193 | BUG(); | 2193 | ret = -EINVAL; |
2194 | } | 2194 | } |
2195 | 2195 | ||
2196 | mutex_unlock(&sensor->mutex); | 2196 | mutex_unlock(&sensor->mutex); |
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 331eddac7222..3bd386c371f7 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c | |||
@@ -1078,7 +1078,7 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
1078 | for (line = 0; line < lines; line++) { | 1078 | for (line = 0; line < lines; line++) { |
1079 | while (offset && offset >= sg_dma_len(sg)) { | 1079 | while (offset && offset >= sg_dma_len(sg)) { |
1080 | offset -= sg_dma_len(sg); | 1080 | offset -= sg_dma_len(sg); |
1081 | sg++; | 1081 | sg = sg_next(sg); |
1082 | } | 1082 | } |
1083 | 1083 | ||
1084 | if (lpi && line > 0 && !(line % lpi)) | 1084 | if (lpi && line > 0 && !(line % lpi)) |
@@ -1101,14 +1101,14 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, | |||
1101 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | 1101 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1102 | todo -= (sg_dma_len(sg)-offset); | 1102 | todo -= (sg_dma_len(sg)-offset); |
1103 | offset = 0; | 1103 | offset = 0; |
1104 | sg++; | 1104 | sg = sg_next(sg); |
1105 | while (todo > sg_dma_len(sg)) { | 1105 | while (todo > sg_dma_len(sg)) { |
1106 | *(rp++) = cpu_to_le32(RISC_WRITE| | 1106 | *(rp++) = cpu_to_le32(RISC_WRITE| |
1107 | sg_dma_len(sg)); | 1107 | sg_dma_len(sg)); |
1108 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | 1108 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
1109 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ | 1109 | *(rp++) = cpu_to_le32(0); /* bits 63-32 */ |
1110 | todo -= sg_dma_len(sg); | 1110 | todo -= sg_dma_len(sg); |
1111 | sg++; | 1111 | sg = sg_next(sg); |
1112 | } | 1112 | } |
1113 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); | 1113 | *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); |
1114 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); | 1114 | *(rp++) = cpu_to_le32(sg_dma_address(sg)); |
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 172583d736fe..8cbe6b49f4c2 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c | |||
@@ -105,11 +105,8 @@ static irqreturn_t solo_isr(int irq, void *data) | |||
105 | if (!status) | 105 | if (!status) |
106 | return IRQ_NONE; | 106 | return IRQ_NONE; |
107 | 107 | ||
108 | if (status & ~solo_dev->irq_mask) { | 108 | /* Acknowledge all interrupts immediately */ |
109 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, | 109 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); |
110 | status & ~solo_dev->irq_mask); | ||
111 | status &= solo_dev->irq_mask; | ||
112 | } | ||
113 | 110 | ||
114 | if (status & SOLO_IRQ_PCI_ERR) | 111 | if (status & SOLO_IRQ_PCI_ERR) |
115 | solo_p2m_error_isr(solo_dev); | 112 | solo_p2m_error_isr(solo_dev); |
@@ -132,9 +129,6 @@ static irqreturn_t solo_isr(int irq, void *data) | |||
132 | if (status & SOLO_IRQ_G723) | 129 | if (status & SOLO_IRQ_G723) |
133 | solo_g723_isr(solo_dev); | 130 | solo_g723_isr(solo_dev); |
134 | 131 | ||
135 | /* Clear all interrupts handled */ | ||
136 | solo_reg_write(solo_dev, SOLO_IRQ_STAT, status); | ||
137 | |||
138 | return IRQ_HANDLED; | 132 | return IRQ_HANDLED; |
139 | } | 133 | } |
140 | 134 | ||
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index f1f098e22f7e..d16bc67af732 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c | |||
@@ -259,8 +259,8 @@ again: | |||
259 | case 32: | 259 | case 32: |
260 | if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { | 260 | if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) { |
261 | protocol = RC_TYPE_RC6_MCE; | 261 | protocol = RC_TYPE_RC6_MCE; |
262 | scancode &= ~RC6_6A_MCE_TOGGLE_MASK; | ||
263 | toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); | 262 | toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK); |
263 | scancode &= ~RC6_6A_MCE_TOGGLE_MASK; | ||
264 | } else { | 264 | } else { |
265 | protocol = RC_BIT_RC6_6A_32; | 265 | protocol = RC_BIT_RC6_6A_32; |
266 | toggle = 0; | 266 | toggle = 0; |
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index ccc00099b261..1c0dbf428a3a 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c | |||
@@ -632,7 +632,7 @@ static void s2255_fillbuff(struct s2255_vc *vc, | |||
632 | break; | 632 | break; |
633 | case V4L2_PIX_FMT_JPEG: | 633 | case V4L2_PIX_FMT_JPEG: |
634 | case V4L2_PIX_FMT_MJPEG: | 634 | case V4L2_PIX_FMT_MJPEG: |
635 | buf->vb.v4l2_buf.length = jpgsize; | 635 | vb2_set_plane_payload(&buf->vb, 0, jpgsize); |
636 | memcpy(vbuf, tmpbuf, jpgsize); | 636 | memcpy(vbuf, tmpbuf, jpgsize); |
637 | break; | 637 | break; |
638 | case V4L2_PIX_FMT_YUV422P: | 638 | case V4L2_PIX_FMT_YUV422P: |
diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index c13d83e15ace..45f09a66e6c9 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c | |||
@@ -225,7 +225,12 @@ static int bond_changelink(struct net_device *bond_dev, | |||
225 | 225 | ||
226 | bond_option_arp_ip_targets_clear(bond); | 226 | bond_option_arp_ip_targets_clear(bond); |
227 | nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { | 227 | nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { |
228 | __be32 target = nla_get_be32(attr); | 228 | __be32 target; |
229 | |||
230 | if (nla_len(attr) < sizeof(target)) | ||
231 | return -EINVAL; | ||
232 | |||
233 | target = nla_get_be32(attr); | ||
229 | 234 | ||
230 | bond_opt_initval(&newval, (__force u64)target); | 235 | bond_opt_initval(&newval, (__force u64)target); |
231 | err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, | 236 | err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, |
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index b9625968daac..4f4c2a7888e5 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c | |||
@@ -377,6 +377,29 @@ static irqreturn_t bcm_sf2_switch_1_isr(int irq, void *dev_id) | |||
377 | return IRQ_HANDLED; | 377 | return IRQ_HANDLED; |
378 | } | 378 | } |
379 | 379 | ||
380 | static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) | ||
381 | { | ||
382 | unsigned int timeout = 1000; | ||
383 | u32 reg; | ||
384 | |||
385 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
386 | reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET; | ||
387 | core_writel(priv, reg, CORE_WATCHDOG_CTRL); | ||
388 | |||
389 | do { | ||
390 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
391 | if (!(reg & SOFTWARE_RESET)) | ||
392 | break; | ||
393 | |||
394 | usleep_range(1000, 2000); | ||
395 | } while (timeout-- > 0); | ||
396 | |||
397 | if (timeout == 0) | ||
398 | return -ETIMEDOUT; | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
380 | static int bcm_sf2_sw_setup(struct dsa_switch *ds) | 403 | static int bcm_sf2_sw_setup(struct dsa_switch *ds) |
381 | { | 404 | { |
382 | const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; | 405 | const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME; |
@@ -404,11 +427,18 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds) | |||
404 | *base = of_iomap(dn, i); | 427 | *base = of_iomap(dn, i); |
405 | if (*base == NULL) { | 428 | if (*base == NULL) { |
406 | pr_err("unable to find register: %s\n", reg_names[i]); | 429 | pr_err("unable to find register: %s\n", reg_names[i]); |
407 | return -ENODEV; | 430 | ret = -ENOMEM; |
431 | goto out_unmap; | ||
408 | } | 432 | } |
409 | base++; | 433 | base++; |
410 | } | 434 | } |
411 | 435 | ||
436 | ret = bcm_sf2_sw_rst(priv); | ||
437 | if (ret) { | ||
438 | pr_err("unable to software reset switch: %d\n", ret); | ||
439 | goto out_unmap; | ||
440 | } | ||
441 | |||
412 | /* Disable all interrupts and request them */ | 442 | /* Disable all interrupts and request them */ |
413 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); | 443 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET); |
414 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); | 444 | intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR); |
@@ -484,7 +514,8 @@ out_free_irq0: | |||
484 | out_unmap: | 514 | out_unmap: |
485 | base = &priv->core; | 515 | base = &priv->core; |
486 | for (i = 0; i < BCM_SF2_REGS_NUM; i++) { | 516 | for (i = 0; i < BCM_SF2_REGS_NUM; i++) { |
487 | iounmap(*base); | 517 | if (*base) |
518 | iounmap(*base); | ||
488 | base++; | 519 | base++; |
489 | } | 520 | } |
490 | return ret; | 521 | return ret; |
@@ -733,29 +764,6 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds) | |||
733 | return 0; | 764 | return 0; |
734 | } | 765 | } |
735 | 766 | ||
736 | static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv) | ||
737 | { | ||
738 | unsigned int timeout = 1000; | ||
739 | u32 reg; | ||
740 | |||
741 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
742 | reg |= SOFTWARE_RESET | EN_CHIP_RST | EN_SW_RESET; | ||
743 | core_writel(priv, reg, CORE_WATCHDOG_CTRL); | ||
744 | |||
745 | do { | ||
746 | reg = core_readl(priv, CORE_WATCHDOG_CTRL); | ||
747 | if (!(reg & SOFTWARE_RESET)) | ||
748 | break; | ||
749 | |||
750 | usleep_range(1000, 2000); | ||
751 | } while (timeout-- > 0); | ||
752 | |||
753 | if (timeout == 0) | ||
754 | return -ETIMEDOUT; | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int bcm_sf2_sw_resume(struct dsa_switch *ds) | 767 | static int bcm_sf2_sw_resume(struct dsa_switch *ds) |
760 | { | 768 | { |
761 | struct bcm_sf2_priv *priv = ds_to_priv(ds); | 769 | struct bcm_sf2_priv *priv = ds_to_priv(ds); |
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index dbb41c1923e6..77f8f836cbbe 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -8563,7 +8563,8 @@ static int tg3_init_rings(struct tg3 *tp) | |||
8563 | if (tnapi->rx_rcb) | 8563 | if (tnapi->rx_rcb) |
8564 | memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); | 8564 | memset(tnapi->rx_rcb, 0, TG3_RX_RCB_RING_BYTES(tp)); |
8565 | 8565 | ||
8566 | if (tg3_rx_prodring_alloc(tp, &tnapi->prodring)) { | 8566 | if (tnapi->prodring.rx_std && |
8567 | tg3_rx_prodring_alloc(tp, &tnapi->prodring)) { | ||
8567 | tg3_free_rings(tp); | 8568 | tg3_free_rings(tp); |
8568 | return -ENOMEM; | 8569 | return -ENOMEM; |
8569 | } | 8570 | } |
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 8520d5529df8..279873cb6e3a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | |||
@@ -2442,9 +2442,13 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) | |||
2442 | SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | | 2442 | SUPPORTED_10000baseKR_Full | SUPPORTED_1000baseKX_Full | |
2443 | SUPPORTED_10000baseKX4_Full; | 2443 | SUPPORTED_10000baseKX4_Full; |
2444 | else if (type == FW_PORT_TYPE_FIBER_XFI || | 2444 | else if (type == FW_PORT_TYPE_FIBER_XFI || |
2445 | type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) | 2445 | type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) { |
2446 | v |= SUPPORTED_FIBRE; | 2446 | v |= SUPPORTED_FIBRE; |
2447 | else if (type == FW_PORT_TYPE_BP40_BA) | 2447 | if (caps & FW_PORT_CAP_SPEED_1G) |
2448 | v |= SUPPORTED_1000baseT_Full; | ||
2449 | if (caps & FW_PORT_CAP_SPEED_10G) | ||
2450 | v |= SUPPORTED_10000baseT_Full; | ||
2451 | } else if (type == FW_PORT_TYPE_BP40_BA) | ||
2448 | v |= SUPPORTED_40000baseSR4_Full; | 2452 | v |= SUPPORTED_40000baseSR4_Full; |
2449 | 2453 | ||
2450 | if (caps & FW_PORT_CAP_ANEG) | 2454 | if (caps & FW_PORT_CAP_ANEG) |
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3e8475cae4f9..597c463e384d 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c | |||
@@ -4309,11 +4309,16 @@ static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh) | |||
4309 | return -EOPNOTSUPP; | 4309 | return -EOPNOTSUPP; |
4310 | 4310 | ||
4311 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); | 4311 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); |
4312 | if (!br_spec) | ||
4313 | return -EINVAL; | ||
4312 | 4314 | ||
4313 | nla_for_each_nested(attr, br_spec, rem) { | 4315 | nla_for_each_nested(attr, br_spec, rem) { |
4314 | if (nla_type(attr) != IFLA_BRIDGE_MODE) | 4316 | if (nla_type(attr) != IFLA_BRIDGE_MODE) |
4315 | continue; | 4317 | continue; |
4316 | 4318 | ||
4319 | if (nla_len(attr) < sizeof(mode)) | ||
4320 | return -EINVAL; | ||
4321 | |||
4317 | mode = nla_get_u16(attr); | 4322 | mode = nla_get_u16(attr); |
4318 | if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB) | 4323 | if (mode != BRIDGE_MODE_VEPA && mode != BRIDGE_MODE_VEB) |
4319 | return -EINVAL; | 4324 | return -EINVAL; |
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index a2d72a87cbde..487cd9c4ac0d 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c | |||
@@ -1012,7 +1012,8 @@ static void igb_free_q_vector(struct igb_adapter *adapter, int v_idx) | |||
1012 | /* igb_get_stats64() might access the rings on this vector, | 1012 | /* igb_get_stats64() might access the rings on this vector, |
1013 | * we must wait a grace period before freeing it. | 1013 | * we must wait a grace period before freeing it. |
1014 | */ | 1014 | */ |
1015 | kfree_rcu(q_vector, rcu); | 1015 | if (q_vector) |
1016 | kfree_rcu(q_vector, rcu); | ||
1016 | } | 1017 | } |
1017 | 1018 | ||
1018 | /** | 1019 | /** |
@@ -1792,8 +1793,10 @@ void igb_down(struct igb_adapter *adapter) | |||
1792 | adapter->flags &= ~IGB_FLAG_NEED_LINK_UPDATE; | 1793 | adapter->flags &= ~IGB_FLAG_NEED_LINK_UPDATE; |
1793 | 1794 | ||
1794 | for (i = 0; i < adapter->num_q_vectors; i++) { | 1795 | for (i = 0; i < adapter->num_q_vectors; i++) { |
1795 | napi_synchronize(&(adapter->q_vector[i]->napi)); | 1796 | if (adapter->q_vector[i]) { |
1796 | napi_disable(&(adapter->q_vector[i]->napi)); | 1797 | napi_synchronize(&adapter->q_vector[i]->napi); |
1798 | napi_disable(&adapter->q_vector[i]->napi); | ||
1799 | } | ||
1797 | } | 1800 | } |
1798 | 1801 | ||
1799 | 1802 | ||
@@ -3717,7 +3720,8 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter) | |||
3717 | int i; | 3720 | int i; |
3718 | 3721 | ||
3719 | for (i = 0; i < adapter->num_tx_queues; i++) | 3722 | for (i = 0; i < adapter->num_tx_queues; i++) |
3720 | igb_free_tx_resources(adapter->tx_ring[i]); | 3723 | if (adapter->tx_ring[i]) |
3724 | igb_free_tx_resources(adapter->tx_ring[i]); | ||
3721 | } | 3725 | } |
3722 | 3726 | ||
3723 | void igb_unmap_and_free_tx_resource(struct igb_ring *ring, | 3727 | void igb_unmap_and_free_tx_resource(struct igb_ring *ring, |
@@ -3782,7 +3786,8 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) | |||
3782 | int i; | 3786 | int i; |
3783 | 3787 | ||
3784 | for (i = 0; i < adapter->num_tx_queues; i++) | 3788 | for (i = 0; i < adapter->num_tx_queues; i++) |
3785 | igb_clean_tx_ring(adapter->tx_ring[i]); | 3789 | if (adapter->tx_ring[i]) |
3790 | igb_clean_tx_ring(adapter->tx_ring[i]); | ||
3786 | } | 3791 | } |
3787 | 3792 | ||
3788 | /** | 3793 | /** |
@@ -3819,7 +3824,8 @@ static void igb_free_all_rx_resources(struct igb_adapter *adapter) | |||
3819 | int i; | 3824 | int i; |
3820 | 3825 | ||
3821 | for (i = 0; i < adapter->num_rx_queues; i++) | 3826 | for (i = 0; i < adapter->num_rx_queues; i++) |
3822 | igb_free_rx_resources(adapter->rx_ring[i]); | 3827 | if (adapter->rx_ring[i]) |
3828 | igb_free_rx_resources(adapter->rx_ring[i]); | ||
3823 | } | 3829 | } |
3824 | 3830 | ||
3825 | /** | 3831 | /** |
@@ -3874,7 +3880,8 @@ static void igb_clean_all_rx_rings(struct igb_adapter *adapter) | |||
3874 | int i; | 3880 | int i; |
3875 | 3881 | ||
3876 | for (i = 0; i < adapter->num_rx_queues; i++) | 3882 | for (i = 0; i < adapter->num_rx_queues; i++) |
3877 | igb_clean_rx_ring(adapter->rx_ring[i]); | 3883 | if (adapter->rx_ring[i]) |
3884 | igb_clean_rx_ring(adapter->rx_ring[i]); | ||
3878 | } | 3885 | } |
3879 | 3886 | ||
3880 | /** | 3887 | /** |
@@ -7404,6 +7411,8 @@ static int igb_resume(struct device *dev) | |||
7404 | pci_restore_state(pdev); | 7411 | pci_restore_state(pdev); |
7405 | pci_save_state(pdev); | 7412 | pci_save_state(pdev); |
7406 | 7413 | ||
7414 | if (!pci_device_is_present(pdev)) | ||
7415 | return -ENODEV; | ||
7407 | err = pci_enable_device_mem(pdev); | 7416 | err = pci_enable_device_mem(pdev); |
7408 | if (err) { | 7417 | if (err) { |
7409 | dev_err(&pdev->dev, | 7418 | dev_err(&pdev->dev, |
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index d2df4e3d1032..cc51554c9e99 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | |||
@@ -3936,8 +3936,8 @@ void ixgbe_set_rx_mode(struct net_device *netdev) | |||
3936 | * if SR-IOV and VMDQ are disabled - otherwise ensure | 3936 | * if SR-IOV and VMDQ are disabled - otherwise ensure |
3937 | * that hardware VLAN filters remain enabled. | 3937 | * that hardware VLAN filters remain enabled. |
3938 | */ | 3938 | */ |
3939 | if (!(adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED | | 3939 | if (adapter->flags & (IXGBE_FLAG_VMDQ_ENABLED | |
3940 | IXGBE_FLAG_SRIOV_ENABLED))) | 3940 | IXGBE_FLAG_SRIOV_ENABLED)) |
3941 | vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN); | 3941 | vlnctrl |= (IXGBE_VLNCTRL_VFE | IXGBE_VLNCTRL_CFIEN); |
3942 | } else { | 3942 | } else { |
3943 | if (netdev->flags & IFF_ALLMULTI) { | 3943 | if (netdev->flags & IFF_ALLMULTI) { |
@@ -7669,6 +7669,8 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev, | |||
7669 | return -EOPNOTSUPP; | 7669 | return -EOPNOTSUPP; |
7670 | 7670 | ||
7671 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); | 7671 | br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); |
7672 | if (!br_spec) | ||
7673 | return -EINVAL; | ||
7672 | 7674 | ||
7673 | nla_for_each_nested(attr, br_spec, rem) { | 7675 | nla_for_each_nested(attr, br_spec, rem) { |
7674 | __u16 mode; | 7676 | __u16 mode; |
@@ -7677,6 +7679,9 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev, | |||
7677 | if (nla_type(attr) != IFLA_BRIDGE_MODE) | 7679 | if (nla_type(attr) != IFLA_BRIDGE_MODE) |
7678 | continue; | 7680 | continue; |
7679 | 7681 | ||
7682 | if (nla_len(attr) < sizeof(mode)) | ||
7683 | return -EINVAL; | ||
7684 | |||
7680 | mode = nla_get_u16(attr); | 7685 | mode = nla_get_u16(attr); |
7681 | if (mode == BRIDGE_MODE_VEPA) { | 7686 | if (mode == BRIDGE_MODE_VEPA) { |
7682 | reg = 0; | 7687 | reg = 0; |
@@ -7979,6 +7984,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
7979 | int i, err, pci_using_dac, expected_gts; | 7984 | int i, err, pci_using_dac, expected_gts; |
7980 | unsigned int indices = MAX_TX_QUEUES; | 7985 | unsigned int indices = MAX_TX_QUEUES; |
7981 | u8 part_str[IXGBE_PBANUM_LENGTH]; | 7986 | u8 part_str[IXGBE_PBANUM_LENGTH]; |
7987 | bool disable_dev = false; | ||
7982 | #ifdef IXGBE_FCOE | 7988 | #ifdef IXGBE_FCOE |
7983 | u16 device_caps; | 7989 | u16 device_caps; |
7984 | #endif | 7990 | #endif |
@@ -8369,13 +8375,14 @@ err_sw_init: | |||
8369 | iounmap(adapter->io_addr); | 8375 | iounmap(adapter->io_addr); |
8370 | kfree(adapter->mac_table); | 8376 | kfree(adapter->mac_table); |
8371 | err_ioremap: | 8377 | err_ioremap: |
8378 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); | ||
8372 | free_netdev(netdev); | 8379 | free_netdev(netdev); |
8373 | err_alloc_etherdev: | 8380 | err_alloc_etherdev: |
8374 | pci_release_selected_regions(pdev, | 8381 | pci_release_selected_regions(pdev, |
8375 | pci_select_bars(pdev, IORESOURCE_MEM)); | 8382 | pci_select_bars(pdev, IORESOURCE_MEM)); |
8376 | err_pci_reg: | 8383 | err_pci_reg: |
8377 | err_dma: | 8384 | err_dma: |
8378 | if (!adapter || !test_and_set_bit(__IXGBE_DISABLED, &adapter->state)) | 8385 | if (!adapter || disable_dev) |
8379 | pci_disable_device(pdev); | 8386 | pci_disable_device(pdev); |
8380 | return err; | 8387 | return err; |
8381 | } | 8388 | } |
@@ -8393,6 +8400,7 @@ static void ixgbe_remove(struct pci_dev *pdev) | |||
8393 | { | 8400 | { |
8394 | struct ixgbe_adapter *adapter = pci_get_drvdata(pdev); | 8401 | struct ixgbe_adapter *adapter = pci_get_drvdata(pdev); |
8395 | struct net_device *netdev = adapter->netdev; | 8402 | struct net_device *netdev = adapter->netdev; |
8403 | bool disable_dev; | ||
8396 | 8404 | ||
8397 | ixgbe_dbg_adapter_exit(adapter); | 8405 | ixgbe_dbg_adapter_exit(adapter); |
8398 | 8406 | ||
@@ -8442,11 +8450,12 @@ static void ixgbe_remove(struct pci_dev *pdev) | |||
8442 | e_dev_info("complete\n"); | 8450 | e_dev_info("complete\n"); |
8443 | 8451 | ||
8444 | kfree(adapter->mac_table); | 8452 | kfree(adapter->mac_table); |
8453 | disable_dev = !test_and_set_bit(__IXGBE_DISABLED, &adapter->state); | ||
8445 | free_netdev(netdev); | 8454 | free_netdev(netdev); |
8446 | 8455 | ||
8447 | pci_disable_pcie_error_reporting(pdev); | 8456 | pci_disable_pcie_error_reporting(pdev); |
8448 | 8457 | ||
8449 | if (!test_and_set_bit(__IXGBE_DISABLED, &adapter->state)) | 8458 | if (disable_dev) |
8450 | pci_disable_device(pdev); | 8459 | pci_disable_device(pdev); |
8451 | } | 8460 | } |
8452 | 8461 | ||
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 5d2498dcf536..cd5cf6d957c7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | |||
@@ -1546,7 +1546,7 @@ static int qp_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, | |||
1546 | 1546 | ||
1547 | switch (op) { | 1547 | switch (op) { |
1548 | case RES_OP_RESERVE: | 1548 | case RES_OP_RESERVE: |
1549 | count = get_param_l(&in_param); | 1549 | count = get_param_l(&in_param) & 0xffffff; |
1550 | align = get_param_h(&in_param); | 1550 | align = get_param_h(&in_param); |
1551 | err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); | 1551 | err = mlx4_grant_resource(dev, slave, RES_QP, count, 0); |
1552 | if (err) | 1552 | if (err) |
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 60e9c2cd051e..b5db6b3f939f 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c | |||
@@ -917,21 +917,13 @@ static int sh_eth_reset(struct net_device *ndev) | |||
917 | return ret; | 917 | return ret; |
918 | } | 918 | } |
919 | 919 | ||
920 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) | ||
921 | static void sh_eth_set_receive_align(struct sk_buff *skb) | 920 | static void sh_eth_set_receive_align(struct sk_buff *skb) |
922 | { | 921 | { |
923 | int reserve; | 922 | uintptr_t reserve = (uintptr_t)skb->data & (SH_ETH_RX_ALIGN - 1); |
924 | 923 | ||
925 | reserve = SH4_SKB_RX_ALIGN - ((u32)skb->data & (SH4_SKB_RX_ALIGN - 1)); | ||
926 | if (reserve) | 924 | if (reserve) |
927 | skb_reserve(skb, reserve); | 925 | skb_reserve(skb, SH_ETH_RX_ALIGN - reserve); |
928 | } | 926 | } |
929 | #else | ||
930 | static void sh_eth_set_receive_align(struct sk_buff *skb) | ||
931 | { | ||
932 | skb_reserve(skb, SH2_SH3_SKB_RX_ALIGN); | ||
933 | } | ||
934 | #endif | ||
935 | 927 | ||
936 | 928 | ||
937 | /* CPU <-> EDMAC endian convert */ | 929 | /* CPU <-> EDMAC endian convert */ |
@@ -1119,6 +1111,7 @@ static void sh_eth_ring_format(struct net_device *ndev) | |||
1119 | struct sh_eth_txdesc *txdesc = NULL; | 1111 | struct sh_eth_txdesc *txdesc = NULL; |
1120 | int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; | 1112 | int rx_ringsize = sizeof(*rxdesc) * mdp->num_rx_ring; |
1121 | int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; | 1113 | int tx_ringsize = sizeof(*txdesc) * mdp->num_tx_ring; |
1114 | int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; | ||
1122 | 1115 | ||
1123 | mdp->cur_rx = 0; | 1116 | mdp->cur_rx = 0; |
1124 | mdp->cur_tx = 0; | 1117 | mdp->cur_tx = 0; |
@@ -1131,21 +1124,21 @@ static void sh_eth_ring_format(struct net_device *ndev) | |||
1131 | for (i = 0; i < mdp->num_rx_ring; i++) { | 1124 | for (i = 0; i < mdp->num_rx_ring; i++) { |
1132 | /* skb */ | 1125 | /* skb */ |
1133 | mdp->rx_skbuff[i] = NULL; | 1126 | mdp->rx_skbuff[i] = NULL; |
1134 | skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz); | 1127 | skb = netdev_alloc_skb(ndev, skbuff_size); |
1135 | mdp->rx_skbuff[i] = skb; | 1128 | mdp->rx_skbuff[i] = skb; |
1136 | if (skb == NULL) | 1129 | if (skb == NULL) |
1137 | break; | 1130 | break; |
1138 | dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz, | ||
1139 | DMA_FROM_DEVICE); | ||
1140 | sh_eth_set_receive_align(skb); | 1131 | sh_eth_set_receive_align(skb); |
1141 | 1132 | ||
1142 | /* RX descriptor */ | 1133 | /* RX descriptor */ |
1143 | rxdesc = &mdp->rx_ring[i]; | 1134 | rxdesc = &mdp->rx_ring[i]; |
1135 | /* The size of the buffer is a multiple of 16 bytes. */ | ||
1136 | rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); | ||
1137 | dma_map_single(&ndev->dev, skb->data, rxdesc->buffer_length, | ||
1138 | DMA_FROM_DEVICE); | ||
1144 | rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); | 1139 | rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); |
1145 | rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); | 1140 | rxdesc->status = cpu_to_edmac(mdp, RD_RACT | RD_RFP); |
1146 | 1141 | ||
1147 | /* The size of the buffer is 16 byte boundary. */ | ||
1148 | rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); | ||
1149 | /* Rx descriptor address set */ | 1142 | /* Rx descriptor address set */ |
1150 | if (i == 0) { | 1143 | if (i == 0) { |
1151 | sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR); | 1144 | sh_eth_write(ndev, mdp->rx_desc_dma, RDLAR); |
@@ -1397,6 +1390,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) | |||
1397 | struct sk_buff *skb; | 1390 | struct sk_buff *skb; |
1398 | u16 pkt_len = 0; | 1391 | u16 pkt_len = 0; |
1399 | u32 desc_status; | 1392 | u32 desc_status; |
1393 | int skbuff_size = mdp->rx_buf_sz + SH_ETH_RX_ALIGN - 1; | ||
1400 | 1394 | ||
1401 | rxdesc = &mdp->rx_ring[entry]; | 1395 | rxdesc = &mdp->rx_ring[entry]; |
1402 | while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) { | 1396 | while (!(rxdesc->status & cpu_to_edmac(mdp, RD_RACT))) { |
@@ -1448,7 +1442,7 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) | |||
1448 | if (mdp->cd->rpadir) | 1442 | if (mdp->cd->rpadir) |
1449 | skb_reserve(skb, NET_IP_ALIGN); | 1443 | skb_reserve(skb, NET_IP_ALIGN); |
1450 | dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr, | 1444 | dma_sync_single_for_cpu(&ndev->dev, rxdesc->addr, |
1451 | mdp->rx_buf_sz, | 1445 | ALIGN(mdp->rx_buf_sz, 16), |
1452 | DMA_FROM_DEVICE); | 1446 | DMA_FROM_DEVICE); |
1453 | skb_put(skb, pkt_len); | 1447 | skb_put(skb, pkt_len); |
1454 | skb->protocol = eth_type_trans(skb, ndev); | 1448 | skb->protocol = eth_type_trans(skb, ndev); |
@@ -1468,13 +1462,13 @@ static int sh_eth_rx(struct net_device *ndev, u32 intr_status, int *quota) | |||
1468 | rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); | 1462 | rxdesc->buffer_length = ALIGN(mdp->rx_buf_sz, 16); |
1469 | 1463 | ||
1470 | if (mdp->rx_skbuff[entry] == NULL) { | 1464 | if (mdp->rx_skbuff[entry] == NULL) { |
1471 | skb = netdev_alloc_skb(ndev, mdp->rx_buf_sz); | 1465 | skb = netdev_alloc_skb(ndev, skbuff_size); |
1472 | mdp->rx_skbuff[entry] = skb; | 1466 | mdp->rx_skbuff[entry] = skb; |
1473 | if (skb == NULL) | 1467 | if (skb == NULL) |
1474 | break; /* Better luck next round. */ | 1468 | break; /* Better luck next round. */ |
1475 | dma_map_single(&ndev->dev, skb->data, mdp->rx_buf_sz, | ||
1476 | DMA_FROM_DEVICE); | ||
1477 | sh_eth_set_receive_align(skb); | 1469 | sh_eth_set_receive_align(skb); |
1470 | dma_map_single(&ndev->dev, skb->data, | ||
1471 | rxdesc->buffer_length, DMA_FROM_DEVICE); | ||
1478 | 1472 | ||
1479 | skb_checksum_none_assert(skb); | 1473 | skb_checksum_none_assert(skb); |
1480 | rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); | 1474 | rxdesc->addr = virt_to_phys(PTR_ALIGN(skb->data, 4)); |
@@ -2042,6 +2036,8 @@ static int sh_eth_open(struct net_device *ndev) | |||
2042 | if (ret) | 2036 | if (ret) |
2043 | goto out_free_irq; | 2037 | goto out_free_irq; |
2044 | 2038 | ||
2039 | mdp->is_opened = 1; | ||
2040 | |||
2045 | return ret; | 2041 | return ret; |
2046 | 2042 | ||
2047 | out_free_irq: | 2043 | out_free_irq: |
@@ -2131,6 +2127,36 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) | |||
2131 | return NETDEV_TX_OK; | 2127 | return NETDEV_TX_OK; |
2132 | } | 2128 | } |
2133 | 2129 | ||
2130 | static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) | ||
2131 | { | ||
2132 | struct sh_eth_private *mdp = netdev_priv(ndev); | ||
2133 | |||
2134 | if (sh_eth_is_rz_fast_ether(mdp)) | ||
2135 | return &ndev->stats; | ||
2136 | |||
2137 | if (!mdp->is_opened) | ||
2138 | return &ndev->stats; | ||
2139 | |||
2140 | ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR); | ||
2141 | sh_eth_write(ndev, 0, TROCR); /* (write clear) */ | ||
2142 | ndev->stats.collisions += sh_eth_read(ndev, CDCR); | ||
2143 | sh_eth_write(ndev, 0, CDCR); /* (write clear) */ | ||
2144 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR); | ||
2145 | sh_eth_write(ndev, 0, LCCR); /* (write clear) */ | ||
2146 | |||
2147 | if (sh_eth_is_gether(mdp)) { | ||
2148 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR); | ||
2149 | sh_eth_write(ndev, 0, CERCR); /* (write clear) */ | ||
2150 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR); | ||
2151 | sh_eth_write(ndev, 0, CEECR); /* (write clear) */ | ||
2152 | } else { | ||
2153 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR); | ||
2154 | sh_eth_write(ndev, 0, CNDCR); /* (write clear) */ | ||
2155 | } | ||
2156 | |||
2157 | return &ndev->stats; | ||
2158 | } | ||
2159 | |||
2134 | /* device close function */ | 2160 | /* device close function */ |
2135 | static int sh_eth_close(struct net_device *ndev) | 2161 | static int sh_eth_close(struct net_device *ndev) |
2136 | { | 2162 | { |
@@ -2145,6 +2171,7 @@ static int sh_eth_close(struct net_device *ndev) | |||
2145 | sh_eth_write(ndev, 0, EDTRR); | 2171 | sh_eth_write(ndev, 0, EDTRR); |
2146 | sh_eth_write(ndev, 0, EDRRR); | 2172 | sh_eth_write(ndev, 0, EDRRR); |
2147 | 2173 | ||
2174 | sh_eth_get_stats(ndev); | ||
2148 | /* PHY Disconnect */ | 2175 | /* PHY Disconnect */ |
2149 | if (mdp->phydev) { | 2176 | if (mdp->phydev) { |
2150 | phy_stop(mdp->phydev); | 2177 | phy_stop(mdp->phydev); |
@@ -2163,36 +2190,9 @@ static int sh_eth_close(struct net_device *ndev) | |||
2163 | 2190 | ||
2164 | pm_runtime_put_sync(&mdp->pdev->dev); | 2191 | pm_runtime_put_sync(&mdp->pdev->dev); |
2165 | 2192 | ||
2166 | return 0; | 2193 | mdp->is_opened = 0; |
2167 | } | ||
2168 | |||
2169 | static struct net_device_stats *sh_eth_get_stats(struct net_device *ndev) | ||
2170 | { | ||
2171 | struct sh_eth_private *mdp = netdev_priv(ndev); | ||
2172 | |||
2173 | if (sh_eth_is_rz_fast_ether(mdp)) | ||
2174 | return &ndev->stats; | ||
2175 | 2194 | ||
2176 | pm_runtime_get_sync(&mdp->pdev->dev); | 2195 | return 0; |
2177 | |||
2178 | ndev->stats.tx_dropped += sh_eth_read(ndev, TROCR); | ||
2179 | sh_eth_write(ndev, 0, TROCR); /* (write clear) */ | ||
2180 | ndev->stats.collisions += sh_eth_read(ndev, CDCR); | ||
2181 | sh_eth_write(ndev, 0, CDCR); /* (write clear) */ | ||
2182 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, LCCR); | ||
2183 | sh_eth_write(ndev, 0, LCCR); /* (write clear) */ | ||
2184 | if (sh_eth_is_gether(mdp)) { | ||
2185 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CERCR); | ||
2186 | sh_eth_write(ndev, 0, CERCR); /* (write clear) */ | ||
2187 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CEECR); | ||
2188 | sh_eth_write(ndev, 0, CEECR); /* (write clear) */ | ||
2189 | } else { | ||
2190 | ndev->stats.tx_carrier_errors += sh_eth_read(ndev, CNDCR); | ||
2191 | sh_eth_write(ndev, 0, CNDCR); /* (write clear) */ | ||
2192 | } | ||
2193 | pm_runtime_put_sync(&mdp->pdev->dev); | ||
2194 | |||
2195 | return &ndev->stats; | ||
2196 | } | 2196 | } |
2197 | 2197 | ||
2198 | /* ioctl to device function */ | 2198 | /* ioctl to device function */ |
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index b37c427144ee..22301bf9c21d 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h | |||
@@ -162,9 +162,9 @@ enum { | |||
162 | 162 | ||
163 | /* Driver's parameters */ | 163 | /* Driver's parameters */ |
164 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) | 164 | #if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARCH_SHMOBILE) |
165 | #define SH4_SKB_RX_ALIGN 32 | 165 | #define SH_ETH_RX_ALIGN 32 |
166 | #else | 166 | #else |
167 | #define SH2_SH3_SKB_RX_ALIGN 2 | 167 | #define SH_ETH_RX_ALIGN 2 |
168 | #endif | 168 | #endif |
169 | 169 | ||
170 | /* Register's bits | 170 | /* Register's bits |
@@ -522,6 +522,7 @@ struct sh_eth_private { | |||
522 | 522 | ||
523 | unsigned no_ether_link:1; | 523 | unsigned no_ether_link:1; |
524 | unsigned ether_link_active_low:1; | 524 | unsigned ether_link_active_low:1; |
525 | unsigned is_opened:1; | ||
525 | }; | 526 | }; |
526 | 527 | ||
527 | static inline void sh_eth_soft_swap(char *src, int len) | 528 | static inline void sh_eth_soft_swap(char *src, int len) |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index db56fa7ce8f9..58a1a0a423d4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | |||
@@ -177,12 +177,6 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, | |||
177 | */ | 177 | */ |
178 | plat->maxmtu = JUMBO_LEN; | 178 | plat->maxmtu = JUMBO_LEN; |
179 | 179 | ||
180 | /* Set default value for multicast hash bins */ | ||
181 | plat->multicast_filter_bins = HASH_TABLE_SIZE; | ||
182 | |||
183 | /* Set default value for unicast filter entries */ | ||
184 | plat->unicast_filter_entries = 1; | ||
185 | |||
186 | /* | 180 | /* |
187 | * Currently only the properties needed on SPEAr600 | 181 | * Currently only the properties needed on SPEAr600 |
188 | * are provided. All other properties should be added | 182 | * are provided. All other properties should be added |
@@ -270,16 +264,23 @@ static int stmmac_pltfr_probe(struct platform_device *pdev) | |||
270 | return PTR_ERR(addr); | 264 | return PTR_ERR(addr); |
271 | 265 | ||
272 | plat_dat = dev_get_platdata(&pdev->dev); | 266 | plat_dat = dev_get_platdata(&pdev->dev); |
273 | if (pdev->dev.of_node) { | 267 | |
274 | if (!plat_dat) | 268 | if (!plat_dat) |
275 | plat_dat = devm_kzalloc(&pdev->dev, | 269 | plat_dat = devm_kzalloc(&pdev->dev, |
276 | sizeof(struct plat_stmmacenet_data), | 270 | sizeof(struct plat_stmmacenet_data), |
277 | GFP_KERNEL); | 271 | GFP_KERNEL); |
278 | if (!plat_dat) { | 272 | if (!plat_dat) { |
279 | pr_err("%s: ERROR: no memory", __func__); | 273 | pr_err("%s: ERROR: no memory", __func__); |
280 | return -ENOMEM; | 274 | return -ENOMEM; |
281 | } | 275 | } |
276 | |||
277 | /* Set default value for multicast hash bins */ | ||
278 | plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; | ||
282 | 279 | ||
280 | /* Set default value for unicast filter entries */ | ||
281 | plat_dat->unicast_filter_entries = 1; | ||
282 | |||
283 | if (pdev->dev.of_node) { | ||
283 | ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); | 284 | ret = stmmac_probe_config_dt(pdev, plat_dat, &mac); |
284 | if (ret) { | 285 | if (ret) { |
285 | pr_err("%s: main dt probe failed", __func__); | 286 | pr_err("%s: main dt probe failed", __func__); |
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e1e335c339e3..be4649a49c5e 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c | |||
@@ -2306,9 +2306,9 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, | |||
2306 | if (ipv6) { | 2306 | if (ipv6) { |
2307 | udp_conf.family = AF_INET6; | 2307 | udp_conf.family = AF_INET6; |
2308 | udp_conf.use_udp6_tx_checksums = | 2308 | udp_conf.use_udp6_tx_checksums = |
2309 | !!(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); | 2309 | !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX); |
2310 | udp_conf.use_udp6_rx_checksums = | 2310 | udp_conf.use_udp6_rx_checksums = |
2311 | !!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); | 2311 | !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); |
2312 | } else { | 2312 | } else { |
2313 | udp_conf.family = AF_INET; | 2313 | udp_conf.family = AF_INET; |
2314 | udp_conf.local_ip.s_addr = INADDR_ANY; | 2314 | udp_conf.local_ip.s_addr = INADDR_ANY; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 4f6e66892acc..b894a84e8393 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h | |||
@@ -155,6 +155,7 @@ enum iwl_ucode_tlv_api { | |||
155 | * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests | 155 | * @IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT: supports Quiet Period requests |
156 | * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), | 156 | * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA), |
157 | * which also implies support for the scheduler configuration command | 157 | * which also implies support for the scheduler configuration command |
158 | * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command | ||
158 | */ | 159 | */ |
159 | enum iwl_ucode_tlv_capa { | 160 | enum iwl_ucode_tlv_capa { |
160 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), | 161 | IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0), |
@@ -163,6 +164,7 @@ enum iwl_ucode_tlv_capa { | |||
163 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), | 164 | IWL_UCODE_TLV_CAPA_WFA_TPC_REP_IE_SUPPORT = BIT(10), |
164 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), | 165 | IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT = BIT(11), |
165 | IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), | 166 | IWL_UCODE_TLV_CAPA_DQA_SUPPORT = BIT(12), |
167 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT = BIT(18), | ||
166 | }; | 168 | }; |
167 | 169 | ||
168 | /* The default calibrate table size if not specified by firmware file */ | 170 | /* The default calibrate table size if not specified by firmware file */ |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index b62405865b25..b6d2683da3a9 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -2448,9 +2448,15 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw, | |||
2448 | 2448 | ||
2449 | switch (vif->type) { | 2449 | switch (vif->type) { |
2450 | case NL80211_IFTYPE_STATION: | 2450 | case NL80211_IFTYPE_STATION: |
2451 | /* Use aux roc framework (HS20) */ | 2451 | if (mvm->fw->ucode_capa.capa[0] & |
2452 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | 2452 | IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT) { |
2453 | vif, duration); | 2453 | /* Use aux roc framework (HS20) */ |
2454 | ret = iwl_mvm_send_aux_roc_cmd(mvm, channel, | ||
2455 | vif, duration); | ||
2456 | goto out_unlock; | ||
2457 | } | ||
2458 | IWL_ERR(mvm, "hotspot not supported\n"); | ||
2459 | ret = -EINVAL; | ||
2454 | goto out_unlock; | 2460 | goto out_unlock; |
2455 | case NL80211_IFTYPE_P2P_DEVICE: | 2461 | case NL80211_IFTYPE_P2P_DEVICE: |
2456 | /* handle below */ | 2462 | /* handle below */ |
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 61f5d36eca6a..846a2e6e34d8 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c | |||
@@ -2249,6 +2249,16 @@ int rtl_pci_probe(struct pci_dev *pdev, | |||
2249 | /*like read eeprom and so on */ | 2249 | /*like read eeprom and so on */ |
2250 | rtlpriv->cfg->ops->read_eeprom_info(hw); | 2250 | rtlpriv->cfg->ops->read_eeprom_info(hw); |
2251 | 2251 | ||
2252 | if (rtlpriv->cfg->ops->init_sw_vars(hw)) { | ||
2253 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); | ||
2254 | err = -ENODEV; | ||
2255 | goto fail3; | ||
2256 | } | ||
2257 | rtlpriv->cfg->ops->init_sw_leds(hw); | ||
2258 | |||
2259 | /*aspm */ | ||
2260 | rtl_pci_init_aspm(hw); | ||
2261 | |||
2252 | /* Init mac80211 sw */ | 2262 | /* Init mac80211 sw */ |
2253 | err = rtl_init_core(hw); | 2263 | err = rtl_init_core(hw); |
2254 | if (err) { | 2264 | if (err) { |
@@ -2264,16 +2274,6 @@ int rtl_pci_probe(struct pci_dev *pdev, | |||
2264 | goto fail3; | 2274 | goto fail3; |
2265 | } | 2275 | } |
2266 | 2276 | ||
2267 | if (rtlpriv->cfg->ops->init_sw_vars(hw)) { | ||
2268 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n"); | ||
2269 | err = -ENODEV; | ||
2270 | goto fail3; | ||
2271 | } | ||
2272 | rtlpriv->cfg->ops->init_sw_leds(hw); | ||
2273 | |||
2274 | /*aspm */ | ||
2275 | rtl_pci_init_aspm(hw); | ||
2276 | |||
2277 | err = ieee80211_register_hw(hw); | 2277 | err = ieee80211_register_hw(hw); |
2278 | if (err) { | 2278 | if (err) { |
2279 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, | 2279 | RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, |
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 310d3163dc5b..8ec8200002c7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | |||
@@ -3672,8 +3672,9 @@ static void rtl8821ae_update_hal_rate_mask(struct ieee80211_hw *hw, | |||
3672 | mac->opmode == NL80211_IFTYPE_ADHOC) | 3672 | mac->opmode == NL80211_IFTYPE_ADHOC) |
3673 | macid = sta->aid + 1; | 3673 | macid = sta->aid + 1; |
3674 | if (wirelessmode == WIRELESS_MODE_N_5G || | 3674 | if (wirelessmode == WIRELESS_MODE_N_5G || |
3675 | wirelessmode == WIRELESS_MODE_AC_5G) | 3675 | wirelessmode == WIRELESS_MODE_AC_5G || |
3676 | ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ]; | 3676 | wirelessmode == WIRELESS_MODE_A) |
3677 | ratr_bitmap = sta->supp_rates[NL80211_BAND_5GHZ] << 4; | ||
3677 | else | 3678 | else |
3678 | ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ]; | 3679 | ratr_bitmap = sta->supp_rates[NL80211_BAND_2GHZ]; |
3679 | 3680 | ||
diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index 4e56a27f9689..fab0d4b42f58 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c | |||
@@ -39,7 +39,7 @@ struct backend_info { | |||
39 | static int connect_rings(struct backend_info *be, struct xenvif_queue *queue); | 39 | static int connect_rings(struct backend_info *be, struct xenvif_queue *queue); |
40 | static void connect(struct backend_info *be); | 40 | static void connect(struct backend_info *be); |
41 | static int read_xenbus_vif_flags(struct backend_info *be); | 41 | static int read_xenbus_vif_flags(struct backend_info *be); |
42 | static void backend_create_xenvif(struct backend_info *be); | 42 | static int backend_create_xenvif(struct backend_info *be); |
43 | static void unregister_hotplug_status_watch(struct backend_info *be); | 43 | static void unregister_hotplug_status_watch(struct backend_info *be); |
44 | static void set_backend_state(struct backend_info *be, | 44 | static void set_backend_state(struct backend_info *be, |
45 | enum xenbus_state state); | 45 | enum xenbus_state state); |
@@ -352,7 +352,9 @@ static int netback_probe(struct xenbus_device *dev, | |||
352 | be->state = XenbusStateInitWait; | 352 | be->state = XenbusStateInitWait; |
353 | 353 | ||
354 | /* This kicks hotplug scripts, so do it immediately. */ | 354 | /* This kicks hotplug scripts, so do it immediately. */ |
355 | backend_create_xenvif(be); | 355 | err = backend_create_xenvif(be); |
356 | if (err) | ||
357 | goto fail; | ||
356 | 358 | ||
357 | return 0; | 359 | return 0; |
358 | 360 | ||
@@ -397,19 +399,19 @@ static int netback_uevent(struct xenbus_device *xdev, | |||
397 | } | 399 | } |
398 | 400 | ||
399 | 401 | ||
400 | static void backend_create_xenvif(struct backend_info *be) | 402 | static int backend_create_xenvif(struct backend_info *be) |
401 | { | 403 | { |
402 | int err; | 404 | int err; |
403 | long handle; | 405 | long handle; |
404 | struct xenbus_device *dev = be->dev; | 406 | struct xenbus_device *dev = be->dev; |
405 | 407 | ||
406 | if (be->vif != NULL) | 408 | if (be->vif != NULL) |
407 | return; | 409 | return 0; |
408 | 410 | ||
409 | err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle); | 411 | err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle); |
410 | if (err != 1) { | 412 | if (err != 1) { |
411 | xenbus_dev_fatal(dev, err, "reading handle"); | 413 | xenbus_dev_fatal(dev, err, "reading handle"); |
412 | return; | 414 | return (err < 0) ? err : -EINVAL; |
413 | } | 415 | } |
414 | 416 | ||
415 | be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle); | 417 | be->vif = xenvif_alloc(&dev->dev, dev->otherend_id, handle); |
@@ -417,10 +419,11 @@ static void backend_create_xenvif(struct backend_info *be) | |||
417 | err = PTR_ERR(be->vif); | 419 | err = PTR_ERR(be->vif); |
418 | be->vif = NULL; | 420 | be->vif = NULL; |
419 | xenbus_dev_fatal(dev, err, "creating interface"); | 421 | xenbus_dev_fatal(dev, err, "creating interface"); |
420 | return; | 422 | return err; |
421 | } | 423 | } |
422 | 424 | ||
423 | kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); | 425 | kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE); |
426 | return 0; | ||
424 | } | 427 | } |
425 | 428 | ||
426 | static void backend_disconnect(struct backend_info *be) | 429 | static void backend_disconnect(struct backend_info *be) |
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index cca871346a0f..ece8d1804d13 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c | |||
@@ -496,9 +496,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, | |||
496 | len = skb_frag_size(frag); | 496 | len = skb_frag_size(frag); |
497 | offset = frag->page_offset; | 497 | offset = frag->page_offset; |
498 | 498 | ||
499 | /* Data must not cross a page boundary. */ | ||
500 | BUG_ON(len + offset > PAGE_SIZE<<compound_order(page)); | ||
501 | |||
502 | /* Skip unused frames from start of page */ | 499 | /* Skip unused frames from start of page */ |
503 | page += offset >> PAGE_SHIFT; | 500 | page += offset >> PAGE_SHIFT; |
504 | offset &= ~PAGE_MASK; | 501 | offset &= ~PAGE_MASK; |
@@ -506,8 +503,6 @@ static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue, | |||
506 | while (len > 0) { | 503 | while (len > 0) { |
507 | unsigned long bytes; | 504 | unsigned long bytes; |
508 | 505 | ||
509 | BUG_ON(offset >= PAGE_SIZE); | ||
510 | |||
511 | bytes = PAGE_SIZE - offset; | 506 | bytes = PAGE_SIZE - offset; |
512 | if (bytes > len) | 507 | if (bytes > len) |
513 | bytes = len; | 508 | bytes = len; |
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 30e97bcc4f88..d134710de96d 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
@@ -964,8 +964,6 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) | |||
964 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, | 964 | int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base, |
965 | phys_addr_t size, bool nomap) | 965 | phys_addr_t size, bool nomap) |
966 | { | 966 | { |
967 | if (memblock_is_region_reserved(base, size)) | ||
968 | return -EBUSY; | ||
969 | if (nomap) | 967 | if (nomap) |
970 | return memblock_remove(base, size); | 968 | return memblock_remove(base, size); |
971 | return memblock_reserve(base, size); | 969 | return memblock_reserve(base, size); |
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 3d43874319be..19bb19c7db4a 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c | |||
@@ -276,6 +276,7 @@ struct tegra_pcie { | |||
276 | 276 | ||
277 | struct resource all; | 277 | struct resource all; |
278 | struct resource io; | 278 | struct resource io; |
279 | struct resource pio; | ||
279 | struct resource mem; | 280 | struct resource mem; |
280 | struct resource prefetch; | 281 | struct resource prefetch; |
281 | struct resource busn; | 282 | struct resource busn; |
@@ -658,7 +659,6 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) | |||
658 | { | 659 | { |
659 | struct tegra_pcie *pcie = sys_to_pcie(sys); | 660 | struct tegra_pcie *pcie = sys_to_pcie(sys); |
660 | int err; | 661 | int err; |
661 | phys_addr_t io_start; | ||
662 | 662 | ||
663 | err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem); | 663 | err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem); |
664 | if (err < 0) | 664 | if (err < 0) |
@@ -668,14 +668,12 @@ static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) | |||
668 | if (err) | 668 | if (err) |
669 | return err; | 669 | return err; |
670 | 670 | ||
671 | io_start = pci_pio_to_address(pcie->io.start); | ||
672 | |||
673 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); | 671 | pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); |
674 | pci_add_resource_offset(&sys->resources, &pcie->prefetch, | 672 | pci_add_resource_offset(&sys->resources, &pcie->prefetch, |
675 | sys->mem_offset); | 673 | sys->mem_offset); |
676 | pci_add_resource(&sys->resources, &pcie->busn); | 674 | pci_add_resource(&sys->resources, &pcie->busn); |
677 | 675 | ||
678 | pci_ioremap_io(nr * SZ_64K, io_start); | 676 | pci_ioremap_io(pcie->pio.start, pcie->io.start); |
679 | 677 | ||
680 | return 1; | 678 | return 1; |
681 | } | 679 | } |
@@ -786,7 +784,6 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg) | |||
786 | static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) | 784 | static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) |
787 | { | 785 | { |
788 | u32 fpci_bar, size, axi_address; | 786 | u32 fpci_bar, size, axi_address; |
789 | phys_addr_t io_start = pci_pio_to_address(pcie->io.start); | ||
790 | 787 | ||
791 | /* Bar 0: type 1 extended configuration space */ | 788 | /* Bar 0: type 1 extended configuration space */ |
792 | fpci_bar = 0xfe100000; | 789 | fpci_bar = 0xfe100000; |
@@ -799,7 +796,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie) | |||
799 | /* Bar 1: downstream IO bar */ | 796 | /* Bar 1: downstream IO bar */ |
800 | fpci_bar = 0xfdfc0000; | 797 | fpci_bar = 0xfdfc0000; |
801 | size = resource_size(&pcie->io); | 798 | size = resource_size(&pcie->io); |
802 | axi_address = io_start; | 799 | axi_address = pcie->io.start; |
803 | afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); | 800 | afi_writel(pcie, axi_address, AFI_AXI_BAR1_START); |
804 | afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); | 801 | afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ); |
805 | afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); | 802 | afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1); |
@@ -1690,8 +1687,23 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie) | |||
1690 | 1687 | ||
1691 | switch (res.flags & IORESOURCE_TYPE_BITS) { | 1688 | switch (res.flags & IORESOURCE_TYPE_BITS) { |
1692 | case IORESOURCE_IO: | 1689 | case IORESOURCE_IO: |
1693 | memcpy(&pcie->io, &res, sizeof(res)); | 1690 | memcpy(&pcie->pio, &res, sizeof(res)); |
1694 | pcie->io.name = np->full_name; | 1691 | pcie->pio.name = np->full_name; |
1692 | |||
1693 | /* | ||
1694 | * The Tegra PCIe host bridge uses this to program the | ||
1695 | * mapping of the I/O space to the physical address, | ||
1696 | * so we override the .start and .end fields here that | ||
1697 | * of_pci_range_to_resource() converted to I/O space. | ||
1698 | * We also set the IORESOURCE_MEM type to clarify that | ||
1699 | * the resource is in the physical memory space. | ||
1700 | */ | ||
1701 | pcie->io.start = range.cpu_addr; | ||
1702 | pcie->io.end = range.cpu_addr + range.size - 1; | ||
1703 | pcie->io.flags = IORESOURCE_MEM; | ||
1704 | pcie->io.name = "I/O"; | ||
1705 | |||
1706 | memcpy(&res, &pcie->io, sizeof(res)); | ||
1695 | break; | 1707 | break; |
1696 | 1708 | ||
1697 | case IORESOURCE_MEM: | 1709 | case IORESOURCE_MEM: |
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 9fab30af0e75..084587d7cd13 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c | |||
@@ -590,6 +590,20 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev) | |||
590 | return entry; | 590 | return entry; |
591 | } | 591 | } |
592 | 592 | ||
593 | static int msi_verify_entries(struct pci_dev *dev) | ||
594 | { | ||
595 | struct msi_desc *entry; | ||
596 | |||
597 | list_for_each_entry(entry, &dev->msi_list, list) { | ||
598 | if (!dev->no_64bit_msi || !entry->msg.address_hi) | ||
599 | continue; | ||
600 | dev_err(&dev->dev, "Device has broken 64-bit MSI but arch" | ||
601 | " tried to assign one above 4G\n"); | ||
602 | return -EIO; | ||
603 | } | ||
604 | return 0; | ||
605 | } | ||
606 | |||
593 | /** | 607 | /** |
594 | * msi_capability_init - configure device's MSI capability structure | 608 | * msi_capability_init - configure device's MSI capability structure |
595 | * @dev: pointer to the pci_dev data structure of MSI device function | 609 | * @dev: pointer to the pci_dev data structure of MSI device function |
@@ -627,6 +641,13 @@ static int msi_capability_init(struct pci_dev *dev, int nvec) | |||
627 | return ret; | 641 | return ret; |
628 | } | 642 | } |
629 | 643 | ||
644 | ret = msi_verify_entries(dev); | ||
645 | if (ret) { | ||
646 | msi_mask_irq(entry, mask, ~mask); | ||
647 | free_msi_irqs(dev); | ||
648 | return ret; | ||
649 | } | ||
650 | |||
630 | ret = populate_msi_sysfs(dev); | 651 | ret = populate_msi_sysfs(dev); |
631 | if (ret) { | 652 | if (ret) { |
632 | msi_mask_irq(entry, mask, ~mask); | 653 | msi_mask_irq(entry, mask, ~mask); |
@@ -739,6 +760,11 @@ static int msix_capability_init(struct pci_dev *dev, | |||
739 | if (ret) | 760 | if (ret) |
740 | goto out_avail; | 761 | goto out_avail; |
741 | 762 | ||
763 | /* Check if all MSI entries honor device restrictions */ | ||
764 | ret = msi_verify_entries(dev); | ||
765 | if (ret) | ||
766 | goto out_free; | ||
767 | |||
742 | /* | 768 | /* |
743 | * Some devices require MSI-X to be enabled before we can touch the | 769 | * Some devices require MSI-X to be enabled before we can touch the |
744 | * MSI-X registers. We need to mask all the vectors to prevent | 770 | * MSI-X registers. We need to mask all the vectors to prevent |
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 79e5c94107a9..72533c58c1f3 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | |||
@@ -412,6 +412,7 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, | |||
412 | struct fc_frame_header *fh; | 412 | struct fc_frame_header *fh; |
413 | struct fcoe_rcv_info *fr; | 413 | struct fcoe_rcv_info *fr; |
414 | struct fcoe_percpu_s *bg; | 414 | struct fcoe_percpu_s *bg; |
415 | struct sk_buff *tmp_skb; | ||
415 | unsigned short oxid; | 416 | unsigned short oxid; |
416 | 417 | ||
417 | interface = container_of(ptype, struct bnx2fc_interface, | 418 | interface = container_of(ptype, struct bnx2fc_interface, |
@@ -424,6 +425,12 @@ static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, | |||
424 | goto err; | 425 | goto err; |
425 | } | 426 | } |
426 | 427 | ||
428 | tmp_skb = skb_share_check(skb, GFP_ATOMIC); | ||
429 | if (!tmp_skb) | ||
430 | goto err; | ||
431 | |||
432 | skb = tmp_skb; | ||
433 | |||
427 | if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { | 434 | if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { |
428 | printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); | 435 | printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); |
429 | goto err; | 436 | goto err; |
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 49014a143c6a..c1d04d4d3c6c 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c | |||
@@ -202,6 +202,7 @@ static struct { | |||
202 | {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, | 202 | {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, |
203 | {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, | 203 | {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, |
204 | {"INSITE", "I325VM", NULL, BLIST_KEY}, | 204 | {"INSITE", "I325VM", NULL, BLIST_KEY}, |
205 | {"Intel", "Multi-Flex", NULL, BLIST_NO_RSOC}, | ||
205 | {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, | 206 | {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, |
206 | {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, | 207 | {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, |
207 | {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, | 208 | {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, |
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 8adf067ff019..1c3467b82566 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c | |||
@@ -102,7 +102,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) | |||
102 | clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq), | 102 | clkfreq = devm_kzalloc(dev, sz * sizeof(*clkfreq), |
103 | GFP_KERNEL); | 103 | GFP_KERNEL); |
104 | if (!clkfreq) { | 104 | if (!clkfreq) { |
105 | dev_err(dev, "%s: no memory\n", "freq-table-hz"); | ||
106 | ret = -ENOMEM; | 105 | ret = -ENOMEM; |
107 | goto out; | 106 | goto out; |
108 | } | 107 | } |
@@ -112,19 +111,19 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) | |||
112 | if (ret && (ret != -EINVAL)) { | 111 | if (ret && (ret != -EINVAL)) { |
113 | dev_err(dev, "%s: error reading array %d\n", | 112 | dev_err(dev, "%s: error reading array %d\n", |
114 | "freq-table-hz", ret); | 113 | "freq-table-hz", ret); |
115 | goto free_clkfreq; | 114 | return ret; |
116 | } | 115 | } |
117 | 116 | ||
118 | for (i = 0; i < sz; i += 2) { | 117 | for (i = 0; i < sz; i += 2) { |
119 | ret = of_property_read_string_index(np, | 118 | ret = of_property_read_string_index(np, |
120 | "clock-names", i/2, (const char **)&name); | 119 | "clock-names", i/2, (const char **)&name); |
121 | if (ret) | 120 | if (ret) |
122 | goto free_clkfreq; | 121 | goto out; |
123 | 122 | ||
124 | clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); | 123 | clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL); |
125 | if (!clki) { | 124 | if (!clki) { |
126 | ret = -ENOMEM; | 125 | ret = -ENOMEM; |
127 | goto free_clkfreq; | 126 | goto out; |
128 | } | 127 | } |
129 | 128 | ||
130 | clki->min_freq = clkfreq[i]; | 129 | clki->min_freq = clkfreq[i]; |
@@ -134,8 +133,6 @@ static int ufshcd_parse_clock_info(struct ufs_hba *hba) | |||
134 | clki->min_freq, clki->max_freq, clki->name); | 133 | clki->min_freq, clki->max_freq, clki->name); |
135 | list_add_tail(&clki->list, &hba->clk_list_head); | 134 | list_add_tail(&clki->list, &hba->clk_list_head); |
136 | } | 135 | } |
137 | free_clkfreq: | ||
138 | kfree(clkfreq); | ||
139 | out: | 136 | out: |
140 | return ret; | 137 | return ret; |
141 | } | 138 | } |
@@ -162,10 +159,8 @@ static int ufshcd_populate_vreg(struct device *dev, const char *name, | |||
162 | } | 159 | } |
163 | 160 | ||
164 | vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); | 161 | vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL); |
165 | if (!vreg) { | 162 | if (!vreg) |
166 | dev_err(dev, "No memory for %s regulator\n", name); | 163 | return -ENOMEM; |
167 | goto out; | ||
168 | } | ||
169 | 164 | ||
170 | vreg->name = kstrdup(name, GFP_KERNEL); | 165 | vreg->name = kstrdup(name, GFP_KERNEL); |
171 | 166 | ||
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 497c38a4a866..605ca60e8a10 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c | |||
@@ -744,6 +744,8 @@ static void ufshcd_exit_clk_gating(struct ufs_hba *hba) | |||
744 | if (!ufshcd_is_clkgating_allowed(hba)) | 744 | if (!ufshcd_is_clkgating_allowed(hba)) |
745 | return; | 745 | return; |
746 | device_remove_file(hba->dev, &hba->clk_gating.delay_attr); | 746 | device_remove_file(hba->dev, &hba->clk_gating.delay_attr); |
747 | cancel_work_sync(&hba->clk_gating.ungate_work); | ||
748 | cancel_delayed_work_sync(&hba->clk_gating.gate_work); | ||
747 | } | 749 | } |
748 | 750 | ||
749 | /* Must be called with host lock acquired */ | 751 | /* Must be called with host lock acquired */ |
@@ -2246,6 +2248,22 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) | |||
2246 | return ret; | 2248 | return ret; |
2247 | } | 2249 | } |
2248 | 2250 | ||
2251 | /** | ||
2252 | * ufshcd_init_pwr_info - setting the POR (power on reset) | ||
2253 | * values in hba power info | ||
2254 | * @hba: per-adapter instance | ||
2255 | */ | ||
2256 | static void ufshcd_init_pwr_info(struct ufs_hba *hba) | ||
2257 | { | ||
2258 | hba->pwr_info.gear_rx = UFS_PWM_G1; | ||
2259 | hba->pwr_info.gear_tx = UFS_PWM_G1; | ||
2260 | hba->pwr_info.lane_rx = 1; | ||
2261 | hba->pwr_info.lane_tx = 1; | ||
2262 | hba->pwr_info.pwr_rx = SLOWAUTO_MODE; | ||
2263 | hba->pwr_info.pwr_tx = SLOWAUTO_MODE; | ||
2264 | hba->pwr_info.hs_rate = 0; | ||
2265 | } | ||
2266 | |||
2249 | /** | 2267 | /** |
2250 | * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device | 2268 | * ufshcd_get_max_pwr_mode - reads the max power mode negotiated with device |
2251 | * @hba: per-adapter instance | 2269 | * @hba: per-adapter instance |
@@ -2844,8 +2862,13 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev) | |||
2844 | hba = shost_priv(sdev->host); | 2862 | hba = shost_priv(sdev->host); |
2845 | scsi_deactivate_tcq(sdev, hba->nutrs); | 2863 | scsi_deactivate_tcq(sdev, hba->nutrs); |
2846 | /* Drop the reference as it won't be needed anymore */ | 2864 | /* Drop the reference as it won't be needed anymore */ |
2847 | if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) | 2865 | if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) { |
2866 | unsigned long flags; | ||
2867 | |||
2868 | spin_lock_irqsave(hba->host->host_lock, flags); | ||
2848 | hba->sdev_ufs_device = NULL; | 2869 | hba->sdev_ufs_device = NULL; |
2870 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
2871 | } | ||
2849 | } | 2872 | } |
2850 | 2873 | ||
2851 | /** | 2874 | /** |
@@ -4062,6 +4085,8 @@ static void ufshcd_init_icc_levels(struct ufs_hba *hba) | |||
4062 | static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) | 4085 | static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) |
4063 | { | 4086 | { |
4064 | int ret = 0; | 4087 | int ret = 0; |
4088 | struct scsi_device *sdev_rpmb; | ||
4089 | struct scsi_device *sdev_boot; | ||
4065 | 4090 | ||
4066 | hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, | 4091 | hba->sdev_ufs_device = __scsi_add_device(hba->host, 0, 0, |
4067 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL); | 4092 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_UFS_DEVICE_WLUN), NULL); |
@@ -4070,26 +4095,27 @@ static int ufshcd_scsi_add_wlus(struct ufs_hba *hba) | |||
4070 | hba->sdev_ufs_device = NULL; | 4095 | hba->sdev_ufs_device = NULL; |
4071 | goto out; | 4096 | goto out; |
4072 | } | 4097 | } |
4098 | scsi_device_put(hba->sdev_ufs_device); | ||
4073 | 4099 | ||
4074 | hba->sdev_boot = __scsi_add_device(hba->host, 0, 0, | 4100 | sdev_boot = __scsi_add_device(hba->host, 0, 0, |
4075 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL); | 4101 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_BOOT_WLUN), NULL); |
4076 | if (IS_ERR(hba->sdev_boot)) { | 4102 | if (IS_ERR(sdev_boot)) { |
4077 | ret = PTR_ERR(hba->sdev_boot); | 4103 | ret = PTR_ERR(sdev_boot); |
4078 | hba->sdev_boot = NULL; | ||
4079 | goto remove_sdev_ufs_device; | 4104 | goto remove_sdev_ufs_device; |
4080 | } | 4105 | } |
4106 | scsi_device_put(sdev_boot); | ||
4081 | 4107 | ||
4082 | hba->sdev_rpmb = __scsi_add_device(hba->host, 0, 0, | 4108 | sdev_rpmb = __scsi_add_device(hba->host, 0, 0, |
4083 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL); | 4109 | ufshcd_upiu_wlun_to_scsi_wlun(UFS_UPIU_RPMB_WLUN), NULL); |
4084 | if (IS_ERR(hba->sdev_rpmb)) { | 4110 | if (IS_ERR(sdev_rpmb)) { |
4085 | ret = PTR_ERR(hba->sdev_rpmb); | 4111 | ret = PTR_ERR(sdev_rpmb); |
4086 | hba->sdev_rpmb = NULL; | ||
4087 | goto remove_sdev_boot; | 4112 | goto remove_sdev_boot; |
4088 | } | 4113 | } |
4114 | scsi_device_put(sdev_rpmb); | ||
4089 | goto out; | 4115 | goto out; |
4090 | 4116 | ||
4091 | remove_sdev_boot: | 4117 | remove_sdev_boot: |
4092 | scsi_remove_device(hba->sdev_boot); | 4118 | scsi_remove_device(sdev_boot); |
4093 | remove_sdev_ufs_device: | 4119 | remove_sdev_ufs_device: |
4094 | scsi_remove_device(hba->sdev_ufs_device); | 4120 | scsi_remove_device(hba->sdev_ufs_device); |
4095 | out: | 4121 | out: |
@@ -4097,30 +4123,6 @@ out: | |||
4097 | } | 4123 | } |
4098 | 4124 | ||
4099 | /** | 4125 | /** |
4100 | * ufshcd_scsi_remove_wlus - Removes the W-LUs which were added by | ||
4101 | * ufshcd_scsi_add_wlus() | ||
4102 | * @hba: per-adapter instance | ||
4103 | * | ||
4104 | */ | ||
4105 | static void ufshcd_scsi_remove_wlus(struct ufs_hba *hba) | ||
4106 | { | ||
4107 | if (hba->sdev_ufs_device) { | ||
4108 | scsi_remove_device(hba->sdev_ufs_device); | ||
4109 | hba->sdev_ufs_device = NULL; | ||
4110 | } | ||
4111 | |||
4112 | if (hba->sdev_boot) { | ||
4113 | scsi_remove_device(hba->sdev_boot); | ||
4114 | hba->sdev_boot = NULL; | ||
4115 | } | ||
4116 | |||
4117 | if (hba->sdev_rpmb) { | ||
4118 | scsi_remove_device(hba->sdev_rpmb); | ||
4119 | hba->sdev_rpmb = NULL; | ||
4120 | } | ||
4121 | } | ||
4122 | |||
4123 | /** | ||
4124 | * ufshcd_probe_hba - probe hba to detect device and initialize | 4126 | * ufshcd_probe_hba - probe hba to detect device and initialize |
4125 | * @hba: per-adapter instance | 4127 | * @hba: per-adapter instance |
4126 | * | 4128 | * |
@@ -4134,6 +4136,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) | |||
4134 | if (ret) | 4136 | if (ret) |
4135 | goto out; | 4137 | goto out; |
4136 | 4138 | ||
4139 | ufshcd_init_pwr_info(hba); | ||
4140 | |||
4137 | /* UniPro link is active now */ | 4141 | /* UniPro link is active now */ |
4138 | ufshcd_set_link_active(hba); | 4142 | ufshcd_set_link_active(hba); |
4139 | 4143 | ||
@@ -4264,12 +4268,18 @@ static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, | |||
4264 | static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, | 4268 | static inline int ufshcd_config_vreg_lpm(struct ufs_hba *hba, |
4265 | struct ufs_vreg *vreg) | 4269 | struct ufs_vreg *vreg) |
4266 | { | 4270 | { |
4271 | if (!vreg) | ||
4272 | return 0; | ||
4273 | |||
4267 | return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA); | 4274 | return ufshcd_config_vreg_load(hba->dev, vreg, UFS_VREG_LPM_LOAD_UA); |
4268 | } | 4275 | } |
4269 | 4276 | ||
4270 | static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, | 4277 | static inline int ufshcd_config_vreg_hpm(struct ufs_hba *hba, |
4271 | struct ufs_vreg *vreg) | 4278 | struct ufs_vreg *vreg) |
4272 | { | 4279 | { |
4280 | if (!vreg) | ||
4281 | return 0; | ||
4282 | |||
4273 | return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); | 4283 | return ufshcd_config_vreg_load(hba->dev, vreg, vreg->max_uA); |
4274 | } | 4284 | } |
4275 | 4285 | ||
@@ -4471,7 +4481,7 @@ out: | |||
4471 | if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) | 4481 | if (!IS_ERR_OR_NULL(clki->clk) && clki->enabled) |
4472 | clk_disable_unprepare(clki->clk); | 4482 | clk_disable_unprepare(clki->clk); |
4473 | } | 4483 | } |
4474 | } else if (!ret && on) { | 4484 | } else if (on) { |
4475 | spin_lock_irqsave(hba->host->host_lock, flags); | 4485 | spin_lock_irqsave(hba->host->host_lock, flags); |
4476 | hba->clk_gating.state = CLKS_ON; | 4486 | hba->clk_gating.state = CLKS_ON; |
4477 | spin_unlock_irqrestore(hba->host->host_lock, flags); | 4487 | spin_unlock_irqrestore(hba->host->host_lock, flags); |
@@ -4675,11 +4685,25 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, | |||
4675 | { | 4685 | { |
4676 | unsigned char cmd[6] = { START_STOP }; | 4686 | unsigned char cmd[6] = { START_STOP }; |
4677 | struct scsi_sense_hdr sshdr; | 4687 | struct scsi_sense_hdr sshdr; |
4678 | struct scsi_device *sdp = hba->sdev_ufs_device; | 4688 | struct scsi_device *sdp; |
4689 | unsigned long flags; | ||
4679 | int ret; | 4690 | int ret; |
4680 | 4691 | ||
4681 | if (!sdp || !scsi_device_online(sdp)) | 4692 | spin_lock_irqsave(hba->host->host_lock, flags); |
4682 | return -ENODEV; | 4693 | sdp = hba->sdev_ufs_device; |
4694 | if (sdp) { | ||
4695 | ret = scsi_device_get(sdp); | ||
4696 | if (!ret && !scsi_device_online(sdp)) { | ||
4697 | ret = -ENODEV; | ||
4698 | scsi_device_put(sdp); | ||
4699 | } | ||
4700 | } else { | ||
4701 | ret = -ENODEV; | ||
4702 | } | ||
4703 | spin_unlock_irqrestore(hba->host->host_lock, flags); | ||
4704 | |||
4705 | if (ret) | ||
4706 | return ret; | ||
4683 | 4707 | ||
4684 | /* | 4708 | /* |
4685 | * If scsi commands fail, the scsi mid-layer schedules scsi error- | 4709 | * If scsi commands fail, the scsi mid-layer schedules scsi error- |
@@ -4718,6 +4742,7 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba, | |||
4718 | if (!ret) | 4742 | if (!ret) |
4719 | hba->curr_dev_pwr_mode = pwr_mode; | 4743 | hba->curr_dev_pwr_mode = pwr_mode; |
4720 | out: | 4744 | out: |
4745 | scsi_device_put(sdp); | ||
4721 | hba->host->eh_noresume = 0; | 4746 | hba->host->eh_noresume = 0; |
4722 | return ret; | 4747 | return ret; |
4723 | } | 4748 | } |
@@ -5087,7 +5112,7 @@ int ufshcd_system_suspend(struct ufs_hba *hba) | |||
5087 | int ret = 0; | 5112 | int ret = 0; |
5088 | 5113 | ||
5089 | if (!hba || !hba->is_powered) | 5114 | if (!hba || !hba->is_powered) |
5090 | goto out; | 5115 | return 0; |
5091 | 5116 | ||
5092 | if (pm_runtime_suspended(hba->dev)) { | 5117 | if (pm_runtime_suspended(hba->dev)) { |
5093 | if (hba->rpm_lvl == hba->spm_lvl) | 5118 | if (hba->rpm_lvl == hba->spm_lvl) |
@@ -5231,7 +5256,6 @@ EXPORT_SYMBOL(ufshcd_shutdown); | |||
5231 | void ufshcd_remove(struct ufs_hba *hba) | 5256 | void ufshcd_remove(struct ufs_hba *hba) |
5232 | { | 5257 | { |
5233 | scsi_remove_host(hba->host); | 5258 | scsi_remove_host(hba->host); |
5234 | ufshcd_scsi_remove_wlus(hba); | ||
5235 | /* disable interrupts */ | 5259 | /* disable interrupts */ |
5236 | ufshcd_disable_intr(hba, hba->intr_mask); | 5260 | ufshcd_disable_intr(hba, hba->intr_mask); |
5237 | ufshcd_hba_stop(hba); | 5261 | ufshcd_hba_stop(hba); |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 58ecdff5065c..4a574aa45855 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -392,8 +392,6 @@ struct ufs_hba { | |||
392 | * "UFS device" W-LU. | 392 | * "UFS device" W-LU. |
393 | */ | 393 | */ |
394 | struct scsi_device *sdev_ufs_device; | 394 | struct scsi_device *sdev_ufs_device; |
395 | struct scsi_device *sdev_rpmb; | ||
396 | struct scsi_device *sdev_boot; | ||
397 | 395 | ||
398 | enum ufs_dev_pwr_mode curr_dev_pwr_mode; | 396 | enum ufs_dev_pwr_mode curr_dev_pwr_mode; |
399 | enum uic_link_state uic_link_state; | 397 | enum uic_link_state uic_link_state; |
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c index 72e12bad14b9..d0d5542efc06 100644 --- a/drivers/spi/spi-dw.c +++ b/drivers/spi/spi-dw.c | |||
@@ -376,9 +376,6 @@ static void pump_transfers(unsigned long data) | |||
376 | chip = dws->cur_chip; | 376 | chip = dws->cur_chip; |
377 | spi = message->spi; | 377 | spi = message->spi; |
378 | 378 | ||
379 | if (unlikely(!chip->clk_div)) | ||
380 | chip->clk_div = dws->max_freq / chip->speed_hz; | ||
381 | |||
382 | if (message->state == ERROR_STATE) { | 379 | if (message->state == ERROR_STATE) { |
383 | message->status = -EIO; | 380 | message->status = -EIO; |
384 | goto early_exit; | 381 | goto early_exit; |
@@ -419,7 +416,7 @@ static void pump_transfers(unsigned long data) | |||
419 | if (transfer->speed_hz) { | 416 | if (transfer->speed_hz) { |
420 | speed = chip->speed_hz; | 417 | speed = chip->speed_hz; |
421 | 418 | ||
422 | if (transfer->speed_hz != speed) { | 419 | if ((transfer->speed_hz != speed) || (!chip->clk_div)) { |
423 | speed = transfer->speed_hz; | 420 | speed = transfer->speed_hz; |
424 | 421 | ||
425 | /* clk_div doesn't support odd number */ | 422 | /* clk_div doesn't support odd number */ |
@@ -581,7 +578,6 @@ static int dw_spi_setup(struct spi_device *spi) | |||
581 | dev_err(&spi->dev, "No max speed HZ parameter\n"); | 578 | dev_err(&spi->dev, "No max speed HZ parameter\n"); |
582 | return -EINVAL; | 579 | return -EINVAL; |
583 | } | 580 | } |
584 | chip->speed_hz = spi->max_speed_hz; | ||
585 | 581 | ||
586 | chip->tmode = 0; /* Tx & Rx */ | 582 | chip->tmode = 0; /* Tx & Rx */ |
587 | /* Default SPI mode is SCPOL = 0, SCPH = 0 */ | 583 | /* Default SPI mode is SCPOL = 0, SCPH = 0 */ |
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c index 39e2c0a55a28..f63de781c729 100644 --- a/drivers/spi/spi-sirf.c +++ b/drivers/spi/spi-sirf.c | |||
@@ -562,9 +562,9 @@ spi_sirfsoc_setup_transfer(struct spi_device *spi, struct spi_transfer *t) | |||
562 | 562 | ||
563 | sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); | 563 | sspi->word_width = DIV_ROUND_UP(bits_per_word, 8); |
564 | txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | | 564 | txfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | |
565 | sspi->word_width; | 565 | (sspi->word_width >> 1); |
566 | rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | | 566 | rxfifo_ctrl = SIRFSOC_SPI_FIFO_THD(SIRFSOC_SPI_FIFO_SIZE / 2) | |
567 | sspi->word_width; | 567 | (sspi->word_width >> 1); |
568 | 568 | ||
569 | if (!(spi->mode & SPI_CS_HIGH)) | 569 | if (!(spi->mode & SPI_CS_HIGH)) |
570 | regval |= SIRFSOC_SPI_CS_IDLE_STAT; | 570 | regval |= SIRFSOC_SPI_CS_IDLE_STAT; |
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ebcb33df2eb2..50f20f243981 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -615,13 +615,13 @@ static int spi_map_buf(struct spi_master *master, struct device *dev, | |||
615 | sg_free_table(sgt); | 615 | sg_free_table(sgt); |
616 | return -ENOMEM; | 616 | return -ENOMEM; |
617 | } | 617 | } |
618 | sg_buf = page_address(vm_page) + | 618 | sg_set_page(&sgt->sgl[i], vm_page, |
619 | ((size_t)buf & ~PAGE_MASK); | 619 | min, offset_in_page(buf)); |
620 | } else { | 620 | } else { |
621 | sg_buf = buf; | 621 | sg_buf = buf; |
622 | sg_set_buf(&sgt->sgl[i], sg_buf, min); | ||
622 | } | 623 | } |
623 | 624 | ||
624 | sg_set_buf(&sgt->sgl[i], sg_buf, min); | ||
625 | 625 | ||
626 | buf += min; | 626 | buf += min; |
627 | len -= min; | 627 | len -= min; |
diff --git a/drivers/staging/rtl8188eu/core/rtw_cmd.c b/drivers/staging/rtl8188eu/core/rtw_cmd.c index 9935e66935af..eddef9cd2e16 100644 --- a/drivers/staging/rtl8188eu/core/rtw_cmd.c +++ b/drivers/staging/rtl8188eu/core/rtw_cmd.c | |||
@@ -275,11 +275,11 @@ u8 rtw_sitesurvey_cmd(struct adapter *padapter, struct ndis_802_11_ssid *ssid, | |||
275 | if (check_fwstate(pmlmepriv, _FW_LINKED) == true) | 275 | if (check_fwstate(pmlmepriv, _FW_LINKED) == true) |
276 | rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); | 276 | rtw_lps_ctrl_wk_cmd(padapter, LPS_CTRL_SCAN, 1); |
277 | 277 | ||
278 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 278 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
279 | if (ph2c == NULL) | 279 | if (ph2c == NULL) |
280 | return _FAIL; | 280 | return _FAIL; |
281 | 281 | ||
282 | psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL); | 282 | psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); |
283 | if (psurveyPara == NULL) { | 283 | if (psurveyPara == NULL) { |
284 | kfree(ph2c); | 284 | kfree(ph2c); |
285 | return _FAIL; | 285 | return _FAIL; |
@@ -405,7 +405,7 @@ u8 rtw_joinbss_cmd(struct adapter *padapter, struct wlan_network *pnetwork) | |||
405 | else | 405 | else |
406 | RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); | 406 | RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_, ("+Join cmd: SSid =[%s]\n", pmlmepriv->assoc_ssid.Ssid)); |
407 | 407 | ||
408 | pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 408 | pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
409 | if (pcmd == NULL) { | 409 | if (pcmd == NULL) { |
410 | res = _FAIL; | 410 | res = _FAIL; |
411 | RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); | 411 | RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("rtw_joinbss_cmd: memory allocate for cmd_obj fail!!!\n")); |
@@ -755,13 +755,13 @@ u8 rtw_dynamic_chk_wk_cmd(struct adapter *padapter) | |||
755 | u8 res = _SUCCESS; | 755 | u8 res = _SUCCESS; |
756 | 756 | ||
757 | 757 | ||
758 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 758 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
759 | if (ph2c == NULL) { | 759 | if (ph2c == NULL) { |
760 | res = _FAIL; | 760 | res = _FAIL; |
761 | goto exit; | 761 | goto exit; |
762 | } | 762 | } |
763 | 763 | ||
764 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL); | 764 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); |
765 | if (pdrvextra_cmd_parm == NULL) { | 765 | if (pdrvextra_cmd_parm == NULL) { |
766 | kfree(ph2c); | 766 | kfree(ph2c); |
767 | res = _FAIL; | 767 | res = _FAIL; |
@@ -967,13 +967,13 @@ u8 rtw_lps_ctrl_wk_cmd(struct adapter *padapter, u8 lps_ctrl_type, u8 enqueue) | |||
967 | u8 res = _SUCCESS; | 967 | u8 res = _SUCCESS; |
968 | 968 | ||
969 | if (enqueue) { | 969 | if (enqueue) { |
970 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 970 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
971 | if (ph2c == NULL) { | 971 | if (ph2c == NULL) { |
972 | res = _FAIL; | 972 | res = _FAIL; |
973 | goto exit; | 973 | goto exit; |
974 | } | 974 | } |
975 | 975 | ||
976 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL); | 976 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); |
977 | if (pdrvextra_cmd_parm == NULL) { | 977 | if (pdrvextra_cmd_parm == NULL) { |
978 | kfree(ph2c); | 978 | kfree(ph2c); |
979 | res = _FAIL; | 979 | res = _FAIL; |
@@ -1010,13 +1010,13 @@ u8 rtw_rpt_timer_cfg_cmd(struct adapter *padapter, u16 min_time) | |||
1010 | 1010 | ||
1011 | u8 res = _SUCCESS; | 1011 | u8 res = _SUCCESS; |
1012 | 1012 | ||
1013 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 1013 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
1014 | if (ph2c == NULL) { | 1014 | if (ph2c == NULL) { |
1015 | res = _FAIL; | 1015 | res = _FAIL; |
1016 | goto exit; | 1016 | goto exit; |
1017 | } | 1017 | } |
1018 | 1018 | ||
1019 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL); | 1019 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); |
1020 | if (pdrvextra_cmd_parm == NULL) { | 1020 | if (pdrvextra_cmd_parm == NULL) { |
1021 | kfree(ph2c); | 1021 | kfree(ph2c); |
1022 | res = _FAIL; | 1022 | res = _FAIL; |
@@ -1088,13 +1088,13 @@ u8 rtw_ps_cmd(struct adapter *padapter) | |||
1088 | 1088 | ||
1089 | u8 res = _SUCCESS; | 1089 | u8 res = _SUCCESS; |
1090 | 1090 | ||
1091 | ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 1091 | ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
1092 | if (ppscmd == NULL) { | 1092 | if (ppscmd == NULL) { |
1093 | res = _FAIL; | 1093 | res = _FAIL; |
1094 | goto exit; | 1094 | goto exit; |
1095 | } | 1095 | } |
1096 | 1096 | ||
1097 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_KERNEL); | 1097 | pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC); |
1098 | if (pdrvextra_cmd_parm == NULL) { | 1098 | if (pdrvextra_cmd_parm == NULL) { |
1099 | kfree(ppscmd); | 1099 | kfree(ppscmd); |
1100 | res = _FAIL; | 1100 | res = _FAIL; |
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c index 5ba5099ec20d..70b1bc3e0e63 100644 --- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c +++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c | |||
@@ -4241,12 +4241,12 @@ void report_survey_event(struct adapter *padapter, | |||
4241 | pcmdpriv = &padapter->cmdpriv; | 4241 | pcmdpriv = &padapter->cmdpriv; |
4242 | 4242 | ||
4243 | 4243 | ||
4244 | pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 4244 | pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
4245 | if (pcmd_obj == NULL) | 4245 | if (pcmd_obj == NULL) |
4246 | return; | 4246 | return; |
4247 | 4247 | ||
4248 | cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); | 4248 | cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header)); |
4249 | pevtcmd = kzalloc(cmdsz, GFP_KERNEL); | 4249 | pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); |
4250 | if (pevtcmd == NULL) { | 4250 | if (pevtcmd == NULL) { |
4251 | kfree(pcmd_obj); | 4251 | kfree(pcmd_obj); |
4252 | return; | 4252 | return; |
@@ -4339,12 +4339,12 @@ void report_join_res(struct adapter *padapter, int res) | |||
4339 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); | 4339 | struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info); |
4340 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; | 4340 | struct cmd_priv *pcmdpriv = &padapter->cmdpriv; |
4341 | 4341 | ||
4342 | pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 4342 | pcmd_obj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
4343 | if (pcmd_obj == NULL) | 4343 | if (pcmd_obj == NULL) |
4344 | return; | 4344 | return; |
4345 | 4345 | ||
4346 | cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); | 4346 | cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header)); |
4347 | pevtcmd = kzalloc(cmdsz, GFP_KERNEL); | 4347 | pevtcmd = kzalloc(cmdsz, GFP_ATOMIC); |
4348 | if (pevtcmd == NULL) { | 4348 | if (pevtcmd == NULL) { |
4349 | kfree(pcmd_obj); | 4349 | kfree(pcmd_obj); |
4350 | return; | 4350 | return; |
@@ -4854,11 +4854,11 @@ void survey_timer_hdl(void *function_context) | |||
4854 | pmlmeext->scan_abort = false;/* reset */ | 4854 | pmlmeext->scan_abort = false;/* reset */ |
4855 | } | 4855 | } |
4856 | 4856 | ||
4857 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL); | 4857 | ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC); |
4858 | if (ph2c == NULL) | 4858 | if (ph2c == NULL) |
4859 | goto exit_survey_timer_hdl; | 4859 | goto exit_survey_timer_hdl; |
4860 | 4860 | ||
4861 | psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_KERNEL); | 4861 | psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC); |
4862 | if (psurveyPara == NULL) { | 4862 | if (psurveyPara == NULL) { |
4863 | kfree(ph2c); | 4863 | kfree(ph2c); |
4864 | goto exit_survey_timer_hdl; | 4864 | goto exit_survey_timer_hdl; |
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 33ccbbbd8ed6..d300369977fa 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c | |||
@@ -935,7 +935,7 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) | |||
935 | return true; | 935 | return true; |
936 | } | 936 | } |
937 | 937 | ||
938 | bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_KERNEL); | 938 | bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC); |
939 | 939 | ||
940 | subtype = GetFrameSubType(pframe) >> 4; | 940 | subtype = GetFrameSubType(pframe) >> 4; |
941 | 941 | ||
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 407a318b09db..2f87150a21b7 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c | |||
@@ -47,6 +47,7 @@ static struct usb_device_id rtw_usb_id_tbl[] = { | |||
47 | {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ | 47 | {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ |
48 | {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ | 48 | {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ |
49 | {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ | 49 | {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ |
50 | {USB_DEVICE(0x2001, 0x3311)}, /* DLink GO-USB-N150 REV B1 */ | ||
50 | {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ | 51 | {USB_DEVICE(0x0df6, 0x0076)}, /* Sitecom N150 v2 */ |
51 | {} /* Terminating entry */ | 52 | {} /* Terminating entry */ |
52 | }; | 53 | }; |
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 1ab0018271c5..ad09e51ffae4 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c | |||
@@ -50,15 +50,14 @@ struct cpufreq_cooling_device { | |||
50 | unsigned int cpufreq_state; | 50 | unsigned int cpufreq_state; |
51 | unsigned int cpufreq_val; | 51 | unsigned int cpufreq_val; |
52 | struct cpumask allowed_cpus; | 52 | struct cpumask allowed_cpus; |
53 | struct list_head node; | ||
53 | }; | 54 | }; |
54 | static DEFINE_IDR(cpufreq_idr); | 55 | static DEFINE_IDR(cpufreq_idr); |
55 | static DEFINE_MUTEX(cooling_cpufreq_lock); | 56 | static DEFINE_MUTEX(cooling_cpufreq_lock); |
56 | 57 | ||
57 | static unsigned int cpufreq_dev_count; | 58 | static unsigned int cpufreq_dev_count; |
58 | 59 | ||
59 | /* notify_table passes value to the CPUFREQ_ADJUST callback function. */ | 60 | static LIST_HEAD(cpufreq_dev_list); |
60 | #define NOTIFY_INVALID NULL | ||
61 | static struct cpufreq_cooling_device *notify_device; | ||
62 | 61 | ||
63 | /** | 62 | /** |
64 | * get_idr - function to get a unique id. | 63 | * get_idr - function to get a unique id. |
@@ -287,15 +286,12 @@ static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, | |||
287 | 286 | ||
288 | cpufreq_device->cpufreq_state = cooling_state; | 287 | cpufreq_device->cpufreq_state = cooling_state; |
289 | cpufreq_device->cpufreq_val = clip_freq; | 288 | cpufreq_device->cpufreq_val = clip_freq; |
290 | notify_device = cpufreq_device; | ||
291 | 289 | ||
292 | for_each_cpu(cpuid, mask) { | 290 | for_each_cpu(cpuid, mask) { |
293 | if (is_cpufreq_valid(cpuid)) | 291 | if (is_cpufreq_valid(cpuid)) |
294 | cpufreq_update_policy(cpuid); | 292 | cpufreq_update_policy(cpuid); |
295 | } | 293 | } |
296 | 294 | ||
297 | notify_device = NOTIFY_INVALID; | ||
298 | |||
299 | return 0; | 295 | return 0; |
300 | } | 296 | } |
301 | 297 | ||
@@ -316,21 +312,28 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, | |||
316 | { | 312 | { |
317 | struct cpufreq_policy *policy = data; | 313 | struct cpufreq_policy *policy = data; |
318 | unsigned long max_freq = 0; | 314 | unsigned long max_freq = 0; |
315 | struct cpufreq_cooling_device *cpufreq_dev; | ||
319 | 316 | ||
320 | if (event != CPUFREQ_ADJUST || notify_device == NOTIFY_INVALID) | 317 | if (event != CPUFREQ_ADJUST) |
321 | return 0; | 318 | return 0; |
322 | 319 | ||
323 | if (cpumask_test_cpu(policy->cpu, ¬ify_device->allowed_cpus)) | 320 | mutex_lock(&cooling_cpufreq_lock); |
324 | max_freq = notify_device->cpufreq_val; | 321 | list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { |
325 | else | 322 | if (!cpumask_test_cpu(policy->cpu, |
326 | return 0; | 323 | &cpufreq_dev->allowed_cpus)) |
324 | continue; | ||
325 | |||
326 | if (!cpufreq_dev->cpufreq_val) | ||
327 | cpufreq_dev->cpufreq_val = get_cpu_frequency( | ||
328 | cpumask_any(&cpufreq_dev->allowed_cpus), | ||
329 | cpufreq_dev->cpufreq_state); | ||
327 | 330 | ||
328 | /* Never exceed user_policy.max */ | 331 | max_freq = cpufreq_dev->cpufreq_val; |
329 | if (max_freq > policy->user_policy.max) | ||
330 | max_freq = policy->user_policy.max; | ||
331 | 332 | ||
332 | if (policy->max != max_freq) | 333 | if (policy->max != max_freq) |
333 | cpufreq_verify_within_limits(policy, 0, max_freq); | 334 | cpufreq_verify_within_limits(policy, 0, max_freq); |
335 | } | ||
336 | mutex_unlock(&cooling_cpufreq_lock); | ||
334 | 337 | ||
335 | return 0; | 338 | return 0; |
336 | } | 339 | } |
@@ -486,6 +489,7 @@ __cpufreq_cooling_register(struct device_node *np, | |||
486 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, | 489 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, |
487 | CPUFREQ_POLICY_NOTIFIER); | 490 | CPUFREQ_POLICY_NOTIFIER); |
488 | cpufreq_dev_count++; | 491 | cpufreq_dev_count++; |
492 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); | ||
489 | 493 | ||
490 | mutex_unlock(&cooling_cpufreq_lock); | 494 | mutex_unlock(&cooling_cpufreq_lock); |
491 | 495 | ||
@@ -549,6 +553,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |||
549 | 553 | ||
550 | cpufreq_dev = cdev->devdata; | 554 | cpufreq_dev = cdev->devdata; |
551 | mutex_lock(&cooling_cpufreq_lock); | 555 | mutex_lock(&cooling_cpufreq_lock); |
556 | list_del(&cpufreq_dev->node); | ||
552 | cpufreq_dev_count--; | 557 | cpufreq_dev_count--; |
553 | 558 | ||
554 | /* Unregister the notifier for the last cpufreq cooling device */ | 559 | /* Unregister the notifier for the last cpufreq cooling device */ |
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c index 3f5ad25ddca8..b6be572704a4 100644 --- a/drivers/thermal/samsung/exynos_thermal_common.c +++ b/drivers/thermal/samsung/exynos_thermal_common.c | |||
@@ -417,13 +417,10 @@ void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) | |||
417 | 417 | ||
418 | th_zone = sensor_conf->pzone_data; | 418 | th_zone = sensor_conf->pzone_data; |
419 | 419 | ||
420 | if (th_zone->therm_dev) | 420 | thermal_zone_device_unregister(th_zone->therm_dev); |
421 | thermal_zone_device_unregister(th_zone->therm_dev); | ||
422 | 421 | ||
423 | for (i = 0; i < th_zone->cool_dev_size; i++) { | 422 | for (i = 0; i < th_zone->cool_dev_size; ++i) |
424 | if (th_zone->cool_dev[i]) | 423 | cpufreq_cooling_unregister(th_zone->cool_dev[i]); |
425 | cpufreq_cooling_unregister(th_zone->cool_dev[i]); | ||
426 | } | ||
427 | 424 | ||
428 | dev_info(sensor_conf->dev, | 425 | dev_info(sensor_conf->dev, |
429 | "Exynos: Kernel Thermal management unregistered\n"); | 426 | "Exynos: Kernel Thermal management unregistered\n"); |
diff --git a/drivers/thermal/st/st_thermal.c b/drivers/thermal/st/st_thermal.c index 90163b384660..d1ec5804c0bb 100644 --- a/drivers/thermal/st/st_thermal.c +++ b/drivers/thermal/st/st_thermal.c | |||
@@ -275,6 +275,7 @@ int st_thermal_unregister(struct platform_device *pdev) | |||
275 | } | 275 | } |
276 | EXPORT_SYMBOL_GPL(st_thermal_unregister); | 276 | EXPORT_SYMBOL_GPL(st_thermal_unregister); |
277 | 277 | ||
278 | #ifdef CONFIG_PM_SLEEP | ||
278 | static int st_thermal_suspend(struct device *dev) | 279 | static int st_thermal_suspend(struct device *dev) |
279 | { | 280 | { |
280 | struct platform_device *pdev = to_platform_device(dev); | 281 | struct platform_device *pdev = to_platform_device(dev); |
@@ -305,6 +306,8 @@ static int st_thermal_resume(struct device *dev) | |||
305 | 306 | ||
306 | return 0; | 307 | return 0; |
307 | } | 308 | } |
309 | #endif | ||
310 | |||
308 | SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume); | 311 | SIMPLE_DEV_PM_OPS(st_thermal_pm_ops, st_thermal_suspend, st_thermal_resume); |
309 | EXPORT_SYMBOL_GPL(st_thermal_pm_ops); | 312 | EXPORT_SYMBOL_GPL(st_thermal_pm_ops); |
310 | 313 | ||
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c index 56982da4a9e9..bf355050eab6 100644 --- a/drivers/tty/serial/of_serial.c +++ b/drivers/tty/serial/of_serial.c | |||
@@ -240,32 +240,6 @@ static int of_platform_serial_remove(struct platform_device *ofdev) | |||
240 | return 0; | 240 | return 0; |
241 | } | 241 | } |
242 | 242 | ||
243 | #ifdef CONFIG_PM_SLEEP | ||
244 | static int of_serial_suspend(struct device *dev) | ||
245 | { | ||
246 | struct of_serial_info *info = dev_get_drvdata(dev); | ||
247 | |||
248 | serial8250_suspend_port(info->line); | ||
249 | if (info->clk) | ||
250 | clk_disable_unprepare(info->clk); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static int of_serial_resume(struct device *dev) | ||
256 | { | ||
257 | struct of_serial_info *info = dev_get_drvdata(dev); | ||
258 | |||
259 | if (info->clk) | ||
260 | clk_prepare_enable(info->clk); | ||
261 | |||
262 | serial8250_resume_port(info->line); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | #endif | ||
267 | static SIMPLE_DEV_PM_OPS(of_serial_pm_ops, of_serial_suspend, of_serial_resume); | ||
268 | |||
269 | /* | 243 | /* |
270 | * A few common types, add more as needed. | 244 | * A few common types, add more as needed. |
271 | */ | 245 | */ |
@@ -297,7 +271,6 @@ static struct platform_driver of_platform_serial_driver = { | |||
297 | .name = "of_serial", | 271 | .name = "of_serial", |
298 | .owner = THIS_MODULE, | 272 | .owner = THIS_MODULE, |
299 | .of_match_table = of_platform_serial_table, | 273 | .of_match_table = of_platform_serial_table, |
300 | .pm = &of_serial_pm_ops, | ||
301 | }, | 274 | }, |
302 | .probe = of_platform_serial_probe, | 275 | .probe = of_platform_serial_probe, |
303 | .remove = of_platform_serial_remove, | 276 | .remove = of_platform_serial_remove, |
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 39b4081b632d..96fafed92b76 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c | |||
@@ -44,6 +44,9 @@ static const struct usb_device_id usb_quirk_list[] = { | |||
44 | /* Creative SB Audigy 2 NX */ | 44 | /* Creative SB Audigy 2 NX */ |
45 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, | 45 | { USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME }, |
46 | 46 | ||
47 | /* Microsoft Wireless Laser Mouse 6000 Receiver */ | ||
48 | { USB_DEVICE(0x045e, 0x00e1), .driver_info = USB_QUIRK_RESET_RESUME }, | ||
49 | |||
47 | /* Microsoft LifeCam-VX700 v2.0 */ | 50 | /* Microsoft LifeCam-VX700 v2.0 */ |
48 | { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, | 51 | { USB_DEVICE(0x045e, 0x0770), .driver_info = USB_QUIRK_RESET_RESUME }, |
49 | 52 | ||
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 711b23019d54..df38e7ef4976 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c | |||
@@ -791,6 +791,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, | |||
791 | 791 | ||
792 | trb = dwc->ep0_trb; | 792 | trb = dwc->ep0_trb; |
793 | 793 | ||
794 | r = next_request(&ep0->request_list); | ||
795 | if (!r) | ||
796 | return; | ||
797 | |||
794 | status = DWC3_TRB_SIZE_TRBSTS(trb->size); | 798 | status = DWC3_TRB_SIZE_TRBSTS(trb->size); |
795 | if (status == DWC3_TRBSTS_SETUP_PENDING) { | 799 | if (status == DWC3_TRBSTS_SETUP_PENDING) { |
796 | dwc3_trace(trace_dwc3_ep0, "Setup Pending received"); | 800 | dwc3_trace(trace_dwc3_ep0, "Setup Pending received"); |
@@ -801,10 +805,6 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc, | |||
801 | return; | 805 | return; |
802 | } | 806 | } |
803 | 807 | ||
804 | r = next_request(&ep0->request_list); | ||
805 | if (!r) | ||
806 | return; | ||
807 | |||
808 | ur = &r->request; | 808 | ur = &r->request; |
809 | 809 | ||
810 | length = trb->size & DWC3_TRB_SIZE_MASK; | 810 | length = trb->size & DWC3_TRB_SIZE_MASK; |
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 696160d48ae8..388cfd83b6b6 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -22,7 +22,6 @@ | |||
22 | 22 | ||
23 | 23 | ||
24 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
25 | #include <linux/device.h> | ||
26 | #include <asm/unaligned.h> | 25 | #include <asm/unaligned.h> |
27 | 26 | ||
28 | #include "xhci.h" | 27 | #include "xhci.h" |
@@ -1149,9 +1148,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
1149 | * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME | 1148 | * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME |
1150 | * is enabled, so also enable remote wake here. | 1149 | * is enabled, so also enable remote wake here. |
1151 | */ | 1150 | */ |
1152 | if (hcd->self.root_hub->do_remote_wakeup | 1151 | if (hcd->self.root_hub->do_remote_wakeup) { |
1153 | && device_may_wakeup(hcd->self.controller)) { | ||
1154 | |||
1155 | if (t1 & PORT_CONNECT) { | 1152 | if (t1 & PORT_CONNECT) { |
1156 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; | 1153 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; |
1157 | t2 &= ~PORT_WKCONN_E; | 1154 | t2 &= ~PORT_WKCONN_E; |
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 9a69b1f1b300..142b601f9563 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c | |||
@@ -281,7 +281,7 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) | |||
281 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) | 281 | if (xhci->quirks & XHCI_COMP_MODE_QUIRK) |
282 | pdev->no_d3cold = true; | 282 | pdev->no_d3cold = true; |
283 | 283 | ||
284 | return xhci_suspend(xhci); | 284 | return xhci_suspend(xhci, do_wakeup); |
285 | } | 285 | } |
286 | 286 | ||
287 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) | 287 | static int xhci_pci_resume(struct usb_hcd *hcd, bool hibernated) |
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 3d78b0cd674b..646300cbe5f7 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c | |||
@@ -204,7 +204,15 @@ static int xhci_plat_suspend(struct device *dev) | |||
204 | struct usb_hcd *hcd = dev_get_drvdata(dev); | 204 | struct usb_hcd *hcd = dev_get_drvdata(dev); |
205 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); | 205 | struct xhci_hcd *xhci = hcd_to_xhci(hcd); |
206 | 206 | ||
207 | return xhci_suspend(xhci); | 207 | /* |
208 | * xhci_suspend() needs `do_wakeup` to know whether host is allowed | ||
209 | * to do wakeup during suspend. Since xhci_plat_suspend is currently | ||
210 | * only designed for system suspend, device_may_wakeup() is enough | ||
211 | * to dertermine whether host is allowed to do wakeup. Need to | ||
212 | * reconsider this when xhci_plat_suspend enlarges its scope, e.g., | ||
213 | * also applies to runtime suspend. | ||
214 | */ | ||
215 | return xhci_suspend(xhci, device_may_wakeup(dev)); | ||
208 | } | 216 | } |
209 | 217 | ||
210 | static int xhci_plat_resume(struct device *dev) | 218 | static int xhci_plat_resume(struct device *dev) |
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index bc6fcbc16f61..06433aec81d7 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c | |||
@@ -1067,9 +1067,8 @@ static void xhci_handle_cmd_reset_ep(struct xhci_hcd *xhci, int slot_id, | |||
1067 | false); | 1067 | false); |
1068 | xhci_ring_cmd_db(xhci); | 1068 | xhci_ring_cmd_db(xhci); |
1069 | } else { | 1069 | } else { |
1070 | /* Clear our internal halted state and restart the ring(s) */ | 1070 | /* Clear our internal halted state */ |
1071 | xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; | 1071 | xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_HALTED; |
1072 | ring_doorbell_for_active_rings(xhci, slot_id, ep_index); | ||
1073 | } | 1072 | } |
1074 | } | 1073 | } |
1075 | 1074 | ||
@@ -1823,22 +1822,13 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
1823 | ep->stopped_td = td; | 1822 | ep->stopped_td = td; |
1824 | return 0; | 1823 | return 0; |
1825 | } else { | 1824 | } else { |
1826 | if (trb_comp_code == COMP_STALL) { | 1825 | if (trb_comp_code == COMP_STALL || |
1827 | /* The transfer is completed from the driver's | 1826 | xhci_requires_manual_halt_cleanup(xhci, ep_ctx, |
1828 | * perspective, but we need to issue a set dequeue | 1827 | trb_comp_code)) { |
1829 | * command for this stalled endpoint to move the dequeue | 1828 | /* Issue a reset endpoint command to clear the host side |
1830 | * pointer past the TD. We can't do that here because | 1829 | * halt, followed by a set dequeue command to move the |
1831 | * the halt condition must be cleared first. Let the | 1830 | * dequeue pointer past the TD. |
1832 | * USB class driver clear the stall later. | 1831 | * The class driver clears the device side halt later. |
1833 | */ | ||
1834 | ep->stopped_td = td; | ||
1835 | ep->stopped_stream = ep_ring->stream_id; | ||
1836 | } else if (xhci_requires_manual_halt_cleanup(xhci, | ||
1837 | ep_ctx, trb_comp_code)) { | ||
1838 | /* Other types of errors halt the endpoint, but the | ||
1839 | * class driver doesn't call usb_reset_endpoint() unless | ||
1840 | * the error is -EPIPE. Clear the halted status in the | ||
1841 | * xHCI hardware manually. | ||
1842 | */ | 1832 | */ |
1843 | xhci_cleanup_halted_endpoint(xhci, | 1833 | xhci_cleanup_halted_endpoint(xhci, |
1844 | slot_id, ep_index, ep_ring->stream_id, | 1834 | slot_id, ep_index, ep_ring->stream_id, |
@@ -1958,9 +1948,7 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td, | |||
1958 | else | 1948 | else |
1959 | td->urb->actual_length = 0; | 1949 | td->urb->actual_length = 0; |
1960 | 1950 | ||
1961 | xhci_cleanup_halted_endpoint(xhci, | 1951 | return finish_td(xhci, td, event_trb, event, ep, status, false); |
1962 | slot_id, ep_index, 0, td, event_trb); | ||
1963 | return finish_td(xhci, td, event_trb, event, ep, status, true); | ||
1964 | } | 1952 | } |
1965 | /* | 1953 | /* |
1966 | * Did we transfer any data, despite the errors that might have | 1954 | * Did we transfer any data, despite the errors that might have |
@@ -2519,17 +2507,8 @@ cleanup: | |||
2519 | if (ret) { | 2507 | if (ret) { |
2520 | urb = td->urb; | 2508 | urb = td->urb; |
2521 | urb_priv = urb->hcpriv; | 2509 | urb_priv = urb->hcpriv; |
2522 | /* Leave the TD around for the reset endpoint function | 2510 | |
2523 | * to use(but only if it's not a control endpoint, | 2511 | xhci_urb_free_priv(xhci, urb_priv); |
2524 | * since we already queued the Set TR dequeue pointer | ||
2525 | * command for stalled control endpoints). | ||
2526 | */ | ||
2527 | if (usb_endpoint_xfer_control(&urb->ep->desc) || | ||
2528 | (trb_comp_code != COMP_STALL && | ||
2529 | trb_comp_code != COMP_BABBLE)) | ||
2530 | xhci_urb_free_priv(xhci, urb_priv); | ||
2531 | else | ||
2532 | kfree(urb_priv); | ||
2533 | 2512 | ||
2534 | usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); | 2513 | usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb); |
2535 | if ((urb->actual_length != urb->transfer_buffer_length && | 2514 | if ((urb->actual_length != urb->transfer_buffer_length && |
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 2a5d45b4cb15..033b46c470bd 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #define DRIVER_AUTHOR "Sarah Sharp" | 35 | #define DRIVER_AUTHOR "Sarah Sharp" |
36 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" | 36 | #define DRIVER_DESC "'eXtensible' Host Controller (xHC) Driver" |
37 | 37 | ||
38 | #define PORT_WAKE_BITS (PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E) | ||
39 | |||
38 | /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ | 40 | /* Some 0.95 hardware can't handle the chain bit on a Link TRB being cleared */ |
39 | static int link_quirk; | 41 | static int link_quirk; |
40 | module_param(link_quirk, int, S_IRUGO | S_IWUSR); | 42 | module_param(link_quirk, int, S_IRUGO | S_IWUSR); |
@@ -851,13 +853,47 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci) | |||
851 | xhci_set_cmd_ring_deq(xhci); | 853 | xhci_set_cmd_ring_deq(xhci); |
852 | } | 854 | } |
853 | 855 | ||
856 | static void xhci_disable_port_wake_on_bits(struct xhci_hcd *xhci) | ||
857 | { | ||
858 | int port_index; | ||
859 | __le32 __iomem **port_array; | ||
860 | unsigned long flags; | ||
861 | u32 t1, t2; | ||
862 | |||
863 | spin_lock_irqsave(&xhci->lock, flags); | ||
864 | |||
865 | /* disble usb3 ports Wake bits*/ | ||
866 | port_index = xhci->num_usb3_ports; | ||
867 | port_array = xhci->usb3_ports; | ||
868 | while (port_index--) { | ||
869 | t1 = readl(port_array[port_index]); | ||
870 | t1 = xhci_port_state_to_neutral(t1); | ||
871 | t2 = t1 & ~PORT_WAKE_BITS; | ||
872 | if (t1 != t2) | ||
873 | writel(t2, port_array[port_index]); | ||
874 | } | ||
875 | |||
876 | /* disble usb2 ports Wake bits*/ | ||
877 | port_index = xhci->num_usb2_ports; | ||
878 | port_array = xhci->usb2_ports; | ||
879 | while (port_index--) { | ||
880 | t1 = readl(port_array[port_index]); | ||
881 | t1 = xhci_port_state_to_neutral(t1); | ||
882 | t2 = t1 & ~PORT_WAKE_BITS; | ||
883 | if (t1 != t2) | ||
884 | writel(t2, port_array[port_index]); | ||
885 | } | ||
886 | |||
887 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
888 | } | ||
889 | |||
854 | /* | 890 | /* |
855 | * Stop HC (not bus-specific) | 891 | * Stop HC (not bus-specific) |
856 | * | 892 | * |
857 | * This is called when the machine transition into S3/S4 mode. | 893 | * This is called when the machine transition into S3/S4 mode. |
858 | * | 894 | * |
859 | */ | 895 | */ |
860 | int xhci_suspend(struct xhci_hcd *xhci) | 896 | int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) |
861 | { | 897 | { |
862 | int rc = 0; | 898 | int rc = 0; |
863 | unsigned int delay = XHCI_MAX_HALT_USEC; | 899 | unsigned int delay = XHCI_MAX_HALT_USEC; |
@@ -868,6 +904,10 @@ int xhci_suspend(struct xhci_hcd *xhci) | |||
868 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) | 904 | xhci->shared_hcd->state != HC_STATE_SUSPENDED) |
869 | return -EINVAL; | 905 | return -EINVAL; |
870 | 906 | ||
907 | /* Clear root port wake on bits if wakeup not allowed. */ | ||
908 | if (!do_wakeup) | ||
909 | xhci_disable_port_wake_on_bits(xhci); | ||
910 | |||
871 | /* Don't poll the roothubs on bus suspend. */ | 911 | /* Don't poll the roothubs on bus suspend. */ |
872 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); | 912 | xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); |
873 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); | 913 | clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); |
@@ -2912,68 +2952,33 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, | |||
2912 | } | 2952 | } |
2913 | } | 2953 | } |
2914 | 2954 | ||
2915 | /* Deal with stalled endpoints. The core should have sent the control message | 2955 | /* Called when clearing halted device. The core should have sent the control |
2916 | * to clear the halt condition. However, we need to make the xHCI hardware | 2956 | * message to clear the device halt condition. The host side of the halt should |
2917 | * reset its sequence number, since a device will expect a sequence number of | 2957 | * already be cleared with a reset endpoint command issued when the STALL tx |
2918 | * zero after the halt condition is cleared. | 2958 | * event was received. |
2959 | * | ||
2919 | * Context: in_interrupt | 2960 | * Context: in_interrupt |
2920 | */ | 2961 | */ |
2962 | |||
2921 | void xhci_endpoint_reset(struct usb_hcd *hcd, | 2963 | void xhci_endpoint_reset(struct usb_hcd *hcd, |
2922 | struct usb_host_endpoint *ep) | 2964 | struct usb_host_endpoint *ep) |
2923 | { | 2965 | { |
2924 | struct xhci_hcd *xhci; | 2966 | struct xhci_hcd *xhci; |
2925 | struct usb_device *udev; | ||
2926 | unsigned int ep_index; | ||
2927 | unsigned long flags; | ||
2928 | int ret; | ||
2929 | struct xhci_virt_ep *virt_ep; | ||
2930 | struct xhci_command *command; | ||
2931 | 2967 | ||
2932 | xhci = hcd_to_xhci(hcd); | 2968 | xhci = hcd_to_xhci(hcd); |
2933 | udev = (struct usb_device *) ep->hcpriv; | ||
2934 | /* Called with a root hub endpoint (or an endpoint that wasn't added | ||
2935 | * with xhci_add_endpoint() | ||
2936 | */ | ||
2937 | if (!ep->hcpriv) | ||
2938 | return; | ||
2939 | ep_index = xhci_get_endpoint_index(&ep->desc); | ||
2940 | virt_ep = &xhci->devs[udev->slot_id]->eps[ep_index]; | ||
2941 | if (!virt_ep->stopped_td) { | ||
2942 | xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, | ||
2943 | "Endpoint 0x%x not halted, refusing to reset.", | ||
2944 | ep->desc.bEndpointAddress); | ||
2945 | return; | ||
2946 | } | ||
2947 | if (usb_endpoint_xfer_control(&ep->desc)) { | ||
2948 | xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, | ||
2949 | "Control endpoint stall already handled."); | ||
2950 | return; | ||
2951 | } | ||
2952 | 2969 | ||
2953 | command = xhci_alloc_command(xhci, false, false, GFP_ATOMIC); | ||
2954 | if (!command) | ||
2955 | return; | ||
2956 | |||
2957 | xhci_dbg_trace(xhci, trace_xhci_dbg_reset_ep, | ||
2958 | "Queueing reset endpoint command"); | ||
2959 | spin_lock_irqsave(&xhci->lock, flags); | ||
2960 | ret = xhci_queue_reset_ep(xhci, command, udev->slot_id, ep_index); | ||
2961 | /* | 2970 | /* |
2962 | * Can't change the ring dequeue pointer until it's transitioned to the | 2971 | * We might need to implement the config ep cmd in xhci 4.8.1 note: |
2963 | * stopped state, which is only upon a successful reset endpoint | 2972 | * The Reset Endpoint Command may only be issued to endpoints in the |
2964 | * command. Better hope that last command worked! | 2973 | * Halted state. If software wishes reset the Data Toggle or Sequence |
2974 | * Number of an endpoint that isn't in the Halted state, then software | ||
2975 | * may issue a Configure Endpoint Command with the Drop and Add bits set | ||
2976 | * for the target endpoint. that is in the Stopped state. | ||
2965 | */ | 2977 | */ |
2966 | if (!ret) { | ||
2967 | xhci_cleanup_stalled_ring(xhci, udev, ep_index); | ||
2968 | kfree(virt_ep->stopped_td); | ||
2969 | xhci_ring_cmd_db(xhci); | ||
2970 | } | ||
2971 | virt_ep->stopped_td = NULL; | ||
2972 | virt_ep->stopped_stream = 0; | ||
2973 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
2974 | 2978 | ||
2975 | if (ret) | 2979 | /* For now just print debug to follow the situation */ |
2976 | xhci_warn(xhci, "FIXME allocate a new ring segment\n"); | 2980 | xhci_dbg(xhci, "Endpoint 0x%x ep reset callback called\n", |
2981 | ep->desc.bEndpointAddress); | ||
2977 | } | 2982 | } |
2978 | 2983 | ||
2979 | static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, | 2984 | static int xhci_check_streams_endpoint(struct xhci_hcd *xhci, |
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index df76d642e719..d745715a1e2f 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h | |||
@@ -1746,7 +1746,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); | |||
1746 | void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)); | 1746 | void xhci_init_driver(struct hc_driver *drv, int (*setup_fn)(struct usb_hcd *)); |
1747 | 1747 | ||
1748 | #ifdef CONFIG_PM | 1748 | #ifdef CONFIG_PM |
1749 | int xhci_suspend(struct xhci_hcd *xhci); | 1749 | int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup); |
1750 | int xhci_resume(struct xhci_hcd *xhci, bool hibernated); | 1750 | int xhci_resume(struct xhci_hcd *xhci, bool hibernated); |
1751 | #else | 1751 | #else |
1752 | #define xhci_suspend NULL | 1752 | #define xhci_suspend NULL |
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index cfd009dc4018..6c4eb3cf5efd 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c | |||
@@ -120,6 +120,7 @@ static const struct usb_device_id id_table[] = { | |||
120 | { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ | 120 | { USB_DEVICE(0x10C4, 0x85F8) }, /* Virtenio Preon32 */ |
121 | { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ | 121 | { USB_DEVICE(0x10C4, 0x8664) }, /* AC-Services CAN-IF */ |
122 | { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ | 122 | { USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */ |
123 | { USB_DEVICE(0x10C4, 0x8875) }, /* CEL MeshConnect USB Stick */ | ||
123 | { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ | 124 | { USB_DEVICE(0x10C4, 0x88A4) }, /* MMB Networks ZigBee USB Device */ |
124 | { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ | 125 | { USB_DEVICE(0x10C4, 0x88A5) }, /* Planet Innovation Ingeni ZigBee USB Device */ |
125 | { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ | 126 | { USB_DEVICE(0x10C4, 0x8946) }, /* Ketra N1 Wireless Interface */ |
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 0dad8ce5a609..1ebb351b9e9a 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c | |||
@@ -470,6 +470,39 @@ static const struct usb_device_id id_table_combined[] = { | |||
470 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, | 470 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FD_PID) }, |
471 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, | 471 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FE_PID) }, |
472 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, | 472 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_01FF_PID) }, |
473 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_4701_PID) }, | ||
474 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9300_PID) }, | ||
475 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9301_PID) }, | ||
476 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9302_PID) }, | ||
477 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9303_PID) }, | ||
478 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9304_PID) }, | ||
479 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9305_PID) }, | ||
480 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9306_PID) }, | ||
481 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9307_PID) }, | ||
482 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9308_PID) }, | ||
483 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9309_PID) }, | ||
484 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930A_PID) }, | ||
485 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930B_PID) }, | ||
486 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930C_PID) }, | ||
487 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930D_PID) }, | ||
488 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930E_PID) }, | ||
489 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_930F_PID) }, | ||
490 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9310_PID) }, | ||
491 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9311_PID) }, | ||
492 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9312_PID) }, | ||
493 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9313_PID) }, | ||
494 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9314_PID) }, | ||
495 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9315_PID) }, | ||
496 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9316_PID) }, | ||
497 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9317_PID) }, | ||
498 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9318_PID) }, | ||
499 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_9319_PID) }, | ||
500 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931A_PID) }, | ||
501 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931B_PID) }, | ||
502 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931C_PID) }, | ||
503 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931D_PID) }, | ||
504 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931E_PID) }, | ||
505 | { USB_DEVICE(MTXORB_VID, MTXORB_FTDI_RANGE_931F_PID) }, | ||
473 | { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, | 506 | { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) }, |
474 | { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, | 507 | { USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) }, |
475 | { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, | 508 | { USB_DEVICE(FTDI_VID, FTDI_TNC_X_PID) }, |
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 6786b705ccf6..e52409c9be99 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h | |||
@@ -926,8 +926,8 @@ | |||
926 | #define BAYER_CONTOUR_CABLE_PID 0x6001 | 926 | #define BAYER_CONTOUR_CABLE_PID 0x6001 |
927 | 927 | ||
928 | /* | 928 | /* |
929 | * The following are the values for the Matrix Orbital FTDI Range | 929 | * Matrix Orbital Intelligent USB displays. |
930 | * Anything in this range will use an FT232RL. | 930 | * http://www.matrixorbital.com |
931 | */ | 931 | */ |
932 | #define MTXORB_VID 0x1B3D | 932 | #define MTXORB_VID 0x1B3D |
933 | #define MTXORB_FTDI_RANGE_0100_PID 0x0100 | 933 | #define MTXORB_FTDI_RANGE_0100_PID 0x0100 |
@@ -1186,8 +1186,39 @@ | |||
1186 | #define MTXORB_FTDI_RANGE_01FD_PID 0x01FD | 1186 | #define MTXORB_FTDI_RANGE_01FD_PID 0x01FD |
1187 | #define MTXORB_FTDI_RANGE_01FE_PID 0x01FE | 1187 | #define MTXORB_FTDI_RANGE_01FE_PID 0x01FE |
1188 | #define MTXORB_FTDI_RANGE_01FF_PID 0x01FF | 1188 | #define MTXORB_FTDI_RANGE_01FF_PID 0x01FF |
1189 | 1189 | #define MTXORB_FTDI_RANGE_4701_PID 0x4701 | |
1190 | 1190 | #define MTXORB_FTDI_RANGE_9300_PID 0x9300 | |
1191 | #define MTXORB_FTDI_RANGE_9301_PID 0x9301 | ||
1192 | #define MTXORB_FTDI_RANGE_9302_PID 0x9302 | ||
1193 | #define MTXORB_FTDI_RANGE_9303_PID 0x9303 | ||
1194 | #define MTXORB_FTDI_RANGE_9304_PID 0x9304 | ||
1195 | #define MTXORB_FTDI_RANGE_9305_PID 0x9305 | ||
1196 | #define MTXORB_FTDI_RANGE_9306_PID 0x9306 | ||
1197 | #define MTXORB_FTDI_RANGE_9307_PID 0x9307 | ||
1198 | #define MTXORB_FTDI_RANGE_9308_PID 0x9308 | ||
1199 | #define MTXORB_FTDI_RANGE_9309_PID 0x9309 | ||
1200 | #define MTXORB_FTDI_RANGE_930A_PID 0x930A | ||
1201 | #define MTXORB_FTDI_RANGE_930B_PID 0x930B | ||
1202 | #define MTXORB_FTDI_RANGE_930C_PID 0x930C | ||
1203 | #define MTXORB_FTDI_RANGE_930D_PID 0x930D | ||
1204 | #define MTXORB_FTDI_RANGE_930E_PID 0x930E | ||
1205 | #define MTXORB_FTDI_RANGE_930F_PID 0x930F | ||
1206 | #define MTXORB_FTDI_RANGE_9310_PID 0x9310 | ||
1207 | #define MTXORB_FTDI_RANGE_9311_PID 0x9311 | ||
1208 | #define MTXORB_FTDI_RANGE_9312_PID 0x9312 | ||
1209 | #define MTXORB_FTDI_RANGE_9313_PID 0x9313 | ||
1210 | #define MTXORB_FTDI_RANGE_9314_PID 0x9314 | ||
1211 | #define MTXORB_FTDI_RANGE_9315_PID 0x9315 | ||
1212 | #define MTXORB_FTDI_RANGE_9316_PID 0x9316 | ||
1213 | #define MTXORB_FTDI_RANGE_9317_PID 0x9317 | ||
1214 | #define MTXORB_FTDI_RANGE_9318_PID 0x9318 | ||
1215 | #define MTXORB_FTDI_RANGE_9319_PID 0x9319 | ||
1216 | #define MTXORB_FTDI_RANGE_931A_PID 0x931A | ||
1217 | #define MTXORB_FTDI_RANGE_931B_PID 0x931B | ||
1218 | #define MTXORB_FTDI_RANGE_931C_PID 0x931C | ||
1219 | #define MTXORB_FTDI_RANGE_931D_PID 0x931D | ||
1220 | #define MTXORB_FTDI_RANGE_931E_PID 0x931E | ||
1221 | #define MTXORB_FTDI_RANGE_931F_PID 0x931F | ||
1191 | 1222 | ||
1192 | /* | 1223 | /* |
1193 | * The Mobility Lab (TML) | 1224 | * The Mobility Lab (TML) |
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index 93cb7cebda62..077c714f1285 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c | |||
@@ -311,24 +311,30 @@ static void usa26_indat_callback(struct urb *urb) | |||
311 | if ((data[0] & 0x80) == 0) { | 311 | if ((data[0] & 0x80) == 0) { |
312 | /* no errors on individual bytes, only | 312 | /* no errors on individual bytes, only |
313 | possible overrun err */ | 313 | possible overrun err */ |
314 | if (data[0] & RXERROR_OVERRUN) | 314 | if (data[0] & RXERROR_OVERRUN) { |
315 | err = TTY_OVERRUN; | 315 | tty_insert_flip_char(&port->port, 0, |
316 | else | 316 | TTY_OVERRUN); |
317 | err = 0; | 317 | } |
318 | for (i = 1; i < urb->actual_length ; ++i) | 318 | for (i = 1; i < urb->actual_length ; ++i) |
319 | tty_insert_flip_char(&port->port, data[i], err); | 319 | tty_insert_flip_char(&port->port, data[i], |
320 | TTY_NORMAL); | ||
320 | } else { | 321 | } else { |
321 | /* some bytes had errors, every byte has status */ | 322 | /* some bytes had errors, every byte has status */ |
322 | dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); | 323 | dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); |
323 | for (i = 0; i + 1 < urb->actual_length; i += 2) { | 324 | for (i = 0; i + 1 < urb->actual_length; i += 2) { |
324 | int stat = data[i], flag = 0; | 325 | int stat = data[i]; |
325 | if (stat & RXERROR_OVERRUN) | 326 | int flag = TTY_NORMAL; |
326 | flag |= TTY_OVERRUN; | 327 | |
327 | if (stat & RXERROR_FRAMING) | 328 | if (stat & RXERROR_OVERRUN) { |
328 | flag |= TTY_FRAME; | 329 | tty_insert_flip_char(&port->port, 0, |
329 | if (stat & RXERROR_PARITY) | 330 | TTY_OVERRUN); |
330 | flag |= TTY_PARITY; | 331 | } |
331 | /* XXX should handle break (0x10) */ | 332 | /* XXX should handle break (0x10) */ |
333 | if (stat & RXERROR_PARITY) | ||
334 | flag = TTY_PARITY; | ||
335 | else if (stat & RXERROR_FRAMING) | ||
336 | flag = TTY_FRAME; | ||
337 | |||
332 | tty_insert_flip_char(&port->port, data[i+1], | 338 | tty_insert_flip_char(&port->port, data[i+1], |
333 | flag); | 339 | flag); |
334 | } | 340 | } |
@@ -649,14 +655,19 @@ static void usa49_indat_callback(struct urb *urb) | |||
649 | } else { | 655 | } else { |
650 | /* some bytes had errors, every byte has status */ | 656 | /* some bytes had errors, every byte has status */ |
651 | for (i = 0; i + 1 < urb->actual_length; i += 2) { | 657 | for (i = 0; i + 1 < urb->actual_length; i += 2) { |
652 | int stat = data[i], flag = 0; | 658 | int stat = data[i]; |
653 | if (stat & RXERROR_OVERRUN) | 659 | int flag = TTY_NORMAL; |
654 | flag |= TTY_OVERRUN; | 660 | |
655 | if (stat & RXERROR_FRAMING) | 661 | if (stat & RXERROR_OVERRUN) { |
656 | flag |= TTY_FRAME; | 662 | tty_insert_flip_char(&port->port, 0, |
657 | if (stat & RXERROR_PARITY) | 663 | TTY_OVERRUN); |
658 | flag |= TTY_PARITY; | 664 | } |
659 | /* XXX should handle break (0x10) */ | 665 | /* XXX should handle break (0x10) */ |
666 | if (stat & RXERROR_PARITY) | ||
667 | flag = TTY_PARITY; | ||
668 | else if (stat & RXERROR_FRAMING) | ||
669 | flag = TTY_FRAME; | ||
670 | |||
660 | tty_insert_flip_char(&port->port, data[i+1], | 671 | tty_insert_flip_char(&port->port, data[i+1], |
661 | flag); | 672 | flag); |
662 | } | 673 | } |
@@ -713,15 +724,19 @@ static void usa49wg_indat_callback(struct urb *urb) | |||
713 | */ | 724 | */ |
714 | for (x = 0; x + 1 < len && | 725 | for (x = 0; x + 1 < len && |
715 | i + 1 < urb->actual_length; x += 2) { | 726 | i + 1 < urb->actual_length; x += 2) { |
716 | int stat = data[i], flag = 0; | 727 | int stat = data[i]; |
728 | int flag = TTY_NORMAL; | ||
717 | 729 | ||
718 | if (stat & RXERROR_OVERRUN) | 730 | if (stat & RXERROR_OVERRUN) { |
719 | flag |= TTY_OVERRUN; | 731 | tty_insert_flip_char(&port->port, 0, |
720 | if (stat & RXERROR_FRAMING) | 732 | TTY_OVERRUN); |
721 | flag |= TTY_FRAME; | 733 | } |
722 | if (stat & RXERROR_PARITY) | ||
723 | flag |= TTY_PARITY; | ||
724 | /* XXX should handle break (0x10) */ | 734 | /* XXX should handle break (0x10) */ |
735 | if (stat & RXERROR_PARITY) | ||
736 | flag = TTY_PARITY; | ||
737 | else if (stat & RXERROR_FRAMING) | ||
738 | flag = TTY_FRAME; | ||
739 | |||
725 | tty_insert_flip_char(&port->port, data[i+1], | 740 | tty_insert_flip_char(&port->port, data[i+1], |
726 | flag); | 741 | flag); |
727 | i += 2; | 742 | i += 2; |
@@ -773,25 +788,31 @@ static void usa90_indat_callback(struct urb *urb) | |||
773 | if ((data[0] & 0x80) == 0) { | 788 | if ((data[0] & 0x80) == 0) { |
774 | /* no errors on individual bytes, only | 789 | /* no errors on individual bytes, only |
775 | possible overrun err*/ | 790 | possible overrun err*/ |
776 | if (data[0] & RXERROR_OVERRUN) | 791 | if (data[0] & RXERROR_OVERRUN) { |
777 | err = TTY_OVERRUN; | 792 | tty_insert_flip_char(&port->port, 0, |
778 | else | 793 | TTY_OVERRUN); |
779 | err = 0; | 794 | } |
780 | for (i = 1; i < urb->actual_length ; ++i) | 795 | for (i = 1; i < urb->actual_length ; ++i) |
781 | tty_insert_flip_char(&port->port, | 796 | tty_insert_flip_char(&port->port, |
782 | data[i], err); | 797 | data[i], TTY_NORMAL); |
783 | } else { | 798 | } else { |
784 | /* some bytes had errors, every byte has status */ | 799 | /* some bytes had errors, every byte has status */ |
785 | dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); | 800 | dev_dbg(&port->dev, "%s - RX error!!!!\n", __func__); |
786 | for (i = 0; i + 1 < urb->actual_length; i += 2) { | 801 | for (i = 0; i + 1 < urb->actual_length; i += 2) { |
787 | int stat = data[i], flag = 0; | 802 | int stat = data[i]; |
788 | if (stat & RXERROR_OVERRUN) | 803 | int flag = TTY_NORMAL; |
789 | flag |= TTY_OVERRUN; | 804 | |
790 | if (stat & RXERROR_FRAMING) | 805 | if (stat & RXERROR_OVERRUN) { |
791 | flag |= TTY_FRAME; | 806 | tty_insert_flip_char( |
792 | if (stat & RXERROR_PARITY) | 807 | &port->port, 0, |
793 | flag |= TTY_PARITY; | 808 | TTY_OVERRUN); |
809 | } | ||
794 | /* XXX should handle break (0x10) */ | 810 | /* XXX should handle break (0x10) */ |
811 | if (stat & RXERROR_PARITY) | ||
812 | flag = TTY_PARITY; | ||
813 | else if (stat & RXERROR_FRAMING) | ||
814 | flag = TTY_FRAME; | ||
815 | |||
795 | tty_insert_flip_char(&port->port, | 816 | tty_insert_flip_char(&port->port, |
796 | data[i+1], flag); | 817 | data[i+1], flag); |
797 | } | 818 | } |
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index a7fe664b6b7d..70a098de429f 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c | |||
@@ -490,10 +490,9 @@ static void ssu100_update_lsr(struct usb_serial_port *port, u8 lsr, | |||
490 | if (*tty_flag == TTY_NORMAL) | 490 | if (*tty_flag == TTY_NORMAL) |
491 | *tty_flag = TTY_FRAME; | 491 | *tty_flag = TTY_FRAME; |
492 | } | 492 | } |
493 | if (lsr & UART_LSR_OE){ | 493 | if (lsr & UART_LSR_OE) { |
494 | port->icount.overrun++; | 494 | port->icount.overrun++; |
495 | if (*tty_flag == TTY_NORMAL) | 495 | tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); |
496 | *tty_flag = TTY_OVERRUN; | ||
497 | } | 496 | } |
498 | } | 497 | } |
499 | 498 | ||
@@ -511,12 +510,8 @@ static void ssu100_process_read_urb(struct urb *urb) | |||
511 | if ((len >= 4) && | 510 | if ((len >= 4) && |
512 | (packet[0] == 0x1b) && (packet[1] == 0x1b) && | 511 | (packet[0] == 0x1b) && (packet[1] == 0x1b) && |
513 | ((packet[2] == 0x00) || (packet[2] == 0x01))) { | 512 | ((packet[2] == 0x00) || (packet[2] == 0x01))) { |
514 | if (packet[2] == 0x00) { | 513 | if (packet[2] == 0x00) |
515 | ssu100_update_lsr(port, packet[3], &flag); | 514 | ssu100_update_lsr(port, packet[3], &flag); |
516 | if (flag == TTY_OVERRUN) | ||
517 | tty_insert_flip_char(&port->port, 0, | ||
518 | TTY_OVERRUN); | ||
519 | } | ||
520 | if (packet[2] == 0x01) | 515 | if (packet[2] == 0x01) |
521 | ssu100_update_msr(port, packet[3]); | 516 | ssu100_update_msr(port, packet[3]); |
522 | 517 | ||
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h index 2fefaf923e4a..18a283d6de1c 100644 --- a/drivers/usb/storage/unusual_uas.h +++ b/drivers/usb/storage/unusual_uas.h | |||
@@ -103,3 +103,10 @@ UNUSUAL_DEV(0x2109, 0x0711, 0x0000, 0x9999, | |||
103 | "VL711", | 103 | "VL711", |
104 | USB_SC_DEVICE, USB_PR_DEVICE, NULL, | 104 | USB_SC_DEVICE, USB_PR_DEVICE, NULL, |
105 | US_FL_NO_ATA_1X), | 105 | US_FL_NO_ATA_1X), |
106 | |||
107 | /* Reported-by: Hans de Goede <hdegoede@redhat.com> */ | ||
108 | UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, | ||
109 | "Hitachi", | ||
110 | "External HDD", | ||
111 | USB_SC_DEVICE, USB_PR_DEVICE, NULL, | ||
112 | US_FL_IGNORE_UAS), | ||
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index 8532c3e2aea7..1626dc66e763 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c | |||
@@ -161,7 +161,7 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = { | |||
161 | static const struct s3c2410_wdt_variant drv_data_exynos7 = { | 161 | static const struct s3c2410_wdt_variant drv_data_exynos7 = { |
162 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, | 162 | .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET, |
163 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, | 163 | .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET, |
164 | .mask_bit = 0, | 164 | .mask_bit = 23, |
165 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, | 165 | .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET, |
166 | .rst_stat_bit = 23, /* A57 WDTRESET */ | 166 | .rst_stat_bit = 23, /* A57 WDTRESET */ |
167 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, | 167 | .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT, |
@@ -165,6 +165,15 @@ static struct vfsmount *aio_mnt; | |||
165 | static const struct file_operations aio_ring_fops; | 165 | static const struct file_operations aio_ring_fops; |
166 | static const struct address_space_operations aio_ctx_aops; | 166 | static const struct address_space_operations aio_ctx_aops; |
167 | 167 | ||
168 | /* Backing dev info for aio fs. | ||
169 | * -no dirty page accounting or writeback happens | ||
170 | */ | ||
171 | static struct backing_dev_info aio_fs_backing_dev_info = { | ||
172 | .name = "aiofs", | ||
173 | .state = 0, | ||
174 | .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_MAP_COPY, | ||
175 | }; | ||
176 | |||
168 | static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) | 177 | static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) |
169 | { | 178 | { |
170 | struct qstr this = QSTR_INIT("[aio]", 5); | 179 | struct qstr this = QSTR_INIT("[aio]", 5); |
@@ -176,6 +185,7 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages) | |||
176 | 185 | ||
177 | inode->i_mapping->a_ops = &aio_ctx_aops; | 186 | inode->i_mapping->a_ops = &aio_ctx_aops; |
178 | inode->i_mapping->private_data = ctx; | 187 | inode->i_mapping->private_data = ctx; |
188 | inode->i_mapping->backing_dev_info = &aio_fs_backing_dev_info; | ||
179 | inode->i_size = PAGE_SIZE * nr_pages; | 189 | inode->i_size = PAGE_SIZE * nr_pages; |
180 | 190 | ||
181 | path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this); | 191 | path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this); |
@@ -220,6 +230,9 @@ static int __init aio_setup(void) | |||
220 | if (IS_ERR(aio_mnt)) | 230 | if (IS_ERR(aio_mnt)) |
221 | panic("Failed to create aio fs mount."); | 231 | panic("Failed to create aio fs mount."); |
222 | 232 | ||
233 | if (bdi_init(&aio_fs_backing_dev_info)) | ||
234 | panic("Failed to init aio fs backing dev info."); | ||
235 | |||
223 | kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 236 | kiocb_cachep = KMEM_CACHE(kiocb, SLAB_HWCACHE_ALIGN|SLAB_PANIC); |
224 | kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC); | 237 | kioctx_cachep = KMEM_CACHE(kioctx,SLAB_HWCACHE_ALIGN|SLAB_PANIC); |
225 | 238 | ||
@@ -281,11 +294,6 @@ static const struct file_operations aio_ring_fops = { | |||
281 | .mmap = aio_ring_mmap, | 294 | .mmap = aio_ring_mmap, |
282 | }; | 295 | }; |
283 | 296 | ||
284 | static int aio_set_page_dirty(struct page *page) | ||
285 | { | ||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | #if IS_ENABLED(CONFIG_MIGRATION) | 297 | #if IS_ENABLED(CONFIG_MIGRATION) |
290 | static int aio_migratepage(struct address_space *mapping, struct page *new, | 298 | static int aio_migratepage(struct address_space *mapping, struct page *new, |
291 | struct page *old, enum migrate_mode mode) | 299 | struct page *old, enum migrate_mode mode) |
@@ -357,7 +365,7 @@ out: | |||
357 | #endif | 365 | #endif |
358 | 366 | ||
359 | static const struct address_space_operations aio_ctx_aops = { | 367 | static const struct address_space_operations aio_ctx_aops = { |
360 | .set_page_dirty = aio_set_page_dirty, | 368 | .set_page_dirty = __set_page_dirty_no_writeback, |
361 | #if IS_ENABLED(CONFIG_MIGRATION) | 369 | #if IS_ENABLED(CONFIG_MIGRATION) |
362 | .migratepage = aio_migratepage, | 370 | .migratepage = aio_migratepage, |
363 | #endif | 371 | #endif |
@@ -412,7 +420,6 @@ static int aio_setup_ring(struct kioctx *ctx) | |||
412 | pr_debug("pid(%d) page[%d]->count=%d\n", | 420 | pr_debug("pid(%d) page[%d]->count=%d\n", |
413 | current->pid, i, page_count(page)); | 421 | current->pid, i, page_count(page)); |
414 | SetPageUptodate(page); | 422 | SetPageUptodate(page); |
415 | SetPageDirty(page); | ||
416 | unlock_page(page); | 423 | unlock_page(page); |
417 | 424 | ||
418 | ctx->ring_pages[i] = page; | 425 | ctx->ring_pages[i] = page; |
diff --git a/fs/btrfs/compression.c b/fs/btrfs/compression.c index d3220d31d3cb..dcd9be32ac57 100644 --- a/fs/btrfs/compression.c +++ b/fs/btrfs/compression.c | |||
@@ -1011,8 +1011,6 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | |||
1011 | bytes = min(bytes, working_bytes); | 1011 | bytes = min(bytes, working_bytes); |
1012 | kaddr = kmap_atomic(page_out); | 1012 | kaddr = kmap_atomic(page_out); |
1013 | memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); | 1013 | memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); |
1014 | if (*pg_index == (vcnt - 1) && *pg_offset == 0) | ||
1015 | memset(kaddr + bytes, 0, PAGE_CACHE_SIZE - bytes); | ||
1016 | kunmap_atomic(kaddr); | 1014 | kunmap_atomic(kaddr); |
1017 | flush_dcache_page(page_out); | 1015 | flush_dcache_page(page_out); |
1018 | 1016 | ||
@@ -1054,3 +1052,34 @@ int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, | |||
1054 | 1052 | ||
1055 | return 1; | 1053 | return 1; |
1056 | } | 1054 | } |
1055 | |||
1056 | /* | ||
1057 | * When uncompressing data, we need to make sure and zero any parts of | ||
1058 | * the biovec that were not filled in by the decompression code. pg_index | ||
1059 | * and pg_offset indicate the last page and the last offset of that page | ||
1060 | * that have been filled in. This will zero everything remaining in the | ||
1061 | * biovec. | ||
1062 | */ | ||
1063 | void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt, | ||
1064 | unsigned long pg_index, | ||
1065 | unsigned long pg_offset) | ||
1066 | { | ||
1067 | while (pg_index < vcnt) { | ||
1068 | struct page *page = bvec[pg_index].bv_page; | ||
1069 | unsigned long off = bvec[pg_index].bv_offset; | ||
1070 | unsigned long len = bvec[pg_index].bv_len; | ||
1071 | |||
1072 | if (pg_offset < off) | ||
1073 | pg_offset = off; | ||
1074 | if (pg_offset < off + len) { | ||
1075 | unsigned long bytes = off + len - pg_offset; | ||
1076 | char *kaddr; | ||
1077 | |||
1078 | kaddr = kmap_atomic(page); | ||
1079 | memset(kaddr + pg_offset, 0, bytes); | ||
1080 | kunmap_atomic(kaddr); | ||
1081 | } | ||
1082 | pg_index++; | ||
1083 | pg_offset = 0; | ||
1084 | } | ||
1085 | } | ||
diff --git a/fs/btrfs/compression.h b/fs/btrfs/compression.h index 0c803b4fbf93..d181f70caae0 100644 --- a/fs/btrfs/compression.h +++ b/fs/btrfs/compression.h | |||
@@ -45,7 +45,9 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start, | |||
45 | unsigned long nr_pages); | 45 | unsigned long nr_pages); |
46 | int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, | 46 | int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, |
47 | int mirror_num, unsigned long bio_flags); | 47 | int mirror_num, unsigned long bio_flags); |
48 | 48 | void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt, | |
49 | unsigned long pg_index, | ||
50 | unsigned long pg_offset); | ||
49 | struct btrfs_compress_op { | 51 | struct btrfs_compress_op { |
50 | struct list_head *(*alloc_workspace)(void); | 52 | struct list_head *(*alloc_workspace)(void); |
51 | 53 | ||
diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c index 78285f30909e..617553cdb7d3 100644 --- a/fs/btrfs/lzo.c +++ b/fs/btrfs/lzo.c | |||
@@ -373,6 +373,8 @@ cont: | |||
373 | } | 373 | } |
374 | done: | 374 | done: |
375 | kunmap(pages_in[page_in_index]); | 375 | kunmap(pages_in[page_in_index]); |
376 | if (!ret) | ||
377 | btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset); | ||
376 | return ret; | 378 | return ret; |
377 | } | 379 | } |
378 | 380 | ||
@@ -410,10 +412,23 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in, | |||
410 | goto out; | 412 | goto out; |
411 | } | 413 | } |
412 | 414 | ||
415 | /* | ||
416 | * the caller is already checking against PAGE_SIZE, but lets | ||
417 | * move this check closer to the memcpy/memset | ||
418 | */ | ||
419 | destlen = min_t(unsigned long, destlen, PAGE_SIZE); | ||
413 | bytes = min_t(unsigned long, destlen, out_len - start_byte); | 420 | bytes = min_t(unsigned long, destlen, out_len - start_byte); |
414 | 421 | ||
415 | kaddr = kmap_atomic(dest_page); | 422 | kaddr = kmap_atomic(dest_page); |
416 | memcpy(kaddr, workspace->buf + start_byte, bytes); | 423 | memcpy(kaddr, workspace->buf + start_byte, bytes); |
424 | |||
425 | /* | ||
426 | * btrfs_getblock is doing a zero on the tail of the page too, | ||
427 | * but this will cover anything missing from the decompressed | ||
428 | * data. | ||
429 | */ | ||
430 | if (bytes < destlen) | ||
431 | memset(kaddr+bytes, 0, destlen-bytes); | ||
417 | kunmap_atomic(kaddr); | 432 | kunmap_atomic(kaddr); |
418 | out: | 433 | out: |
419 | return ret; | 434 | return ret; |
diff --git a/fs/btrfs/zlib.c b/fs/btrfs/zlib.c index 759fa4e2de8f..fb22fd8d8fb8 100644 --- a/fs/btrfs/zlib.c +++ b/fs/btrfs/zlib.c | |||
@@ -299,6 +299,8 @@ done: | |||
299 | zlib_inflateEnd(&workspace->strm); | 299 | zlib_inflateEnd(&workspace->strm); |
300 | if (data_in) | 300 | if (data_in) |
301 | kunmap(pages_in[page_in_index]); | 301 | kunmap(pages_in[page_in_index]); |
302 | if (!ret) | ||
303 | btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset); | ||
302 | return ret; | 304 | return ret; |
303 | } | 305 | } |
304 | 306 | ||
@@ -310,10 +312,14 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in, | |||
310 | struct workspace *workspace = list_entry(ws, struct workspace, list); | 312 | struct workspace *workspace = list_entry(ws, struct workspace, list); |
311 | int ret = 0; | 313 | int ret = 0; |
312 | int wbits = MAX_WBITS; | 314 | int wbits = MAX_WBITS; |
313 | unsigned long bytes_left = destlen; | 315 | unsigned long bytes_left; |
314 | unsigned long total_out = 0; | 316 | unsigned long total_out = 0; |
317 | unsigned long pg_offset = 0; | ||
315 | char *kaddr; | 318 | char *kaddr; |
316 | 319 | ||
320 | destlen = min_t(unsigned long, destlen, PAGE_SIZE); | ||
321 | bytes_left = destlen; | ||
322 | |||
317 | workspace->strm.next_in = data_in; | 323 | workspace->strm.next_in = data_in; |
318 | workspace->strm.avail_in = srclen; | 324 | workspace->strm.avail_in = srclen; |
319 | workspace->strm.total_in = 0; | 325 | workspace->strm.total_in = 0; |
@@ -341,7 +347,6 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in, | |||
341 | unsigned long buf_start; | 347 | unsigned long buf_start; |
342 | unsigned long buf_offset; | 348 | unsigned long buf_offset; |
343 | unsigned long bytes; | 349 | unsigned long bytes; |
344 | unsigned long pg_offset = 0; | ||
345 | 350 | ||
346 | ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH); | 351 | ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH); |
347 | if (ret != Z_OK && ret != Z_STREAM_END) | 352 | if (ret != Z_OK && ret != Z_STREAM_END) |
@@ -384,6 +389,17 @@ next: | |||
384 | ret = 0; | 389 | ret = 0; |
385 | 390 | ||
386 | zlib_inflateEnd(&workspace->strm); | 391 | zlib_inflateEnd(&workspace->strm); |
392 | |||
393 | /* | ||
394 | * this should only happen if zlib returned fewer bytes than we | ||
395 | * expected. btrfs_get_block is responsible for zeroing from the | ||
396 | * end of the inline extent (destlen) to the end of the page | ||
397 | */ | ||
398 | if (pg_offset < destlen) { | ||
399 | kaddr = kmap_atomic(dest_page); | ||
400 | memset(kaddr + pg_offset, 0, destlen - pg_offset); | ||
401 | kunmap_atomic(kaddr); | ||
402 | } | ||
387 | return ret; | 403 | return ret; |
388 | } | 404 | } |
389 | 405 | ||
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index 6df8d3d885e5..b8b92c2f9683 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c | |||
@@ -736,7 +736,12 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
736 | } | 736 | } |
737 | 737 | ||
738 | alias = d_find_alias(inode); | 738 | alias = d_find_alias(inode); |
739 | if (alias && !vfat_d_anon_disconn(alias)) { | 739 | /* |
740 | * Checking "alias->d_parent == dentry->d_parent" to make sure | ||
741 | * FS is not corrupted (especially double linked dir). | ||
742 | */ | ||
743 | if (alias && alias->d_parent == dentry->d_parent && | ||
744 | !vfat_d_anon_disconn(alias)) { | ||
740 | /* | 745 | /* |
741 | * This inode has non anonymous-DCACHE_DISCONNECTED | 746 | * This inode has non anonymous-DCACHE_DISCONNECTED |
742 | * dentry. This means, the user did ->lookup() by an | 747 | * dentry. This means, the user did ->lookup() by an |
@@ -755,12 +760,9 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, | |||
755 | 760 | ||
756 | out: | 761 | out: |
757 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 762 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
758 | dentry->d_time = dentry->d_parent->d_inode->i_version; | 763 | if (!inode) |
759 | dentry = d_splice_alias(inode, dentry); | 764 | dentry->d_time = dir->i_version; |
760 | if (dentry) | 765 | return d_splice_alias(inode, dentry); |
761 | dentry->d_time = dentry->d_parent->d_inode->i_version; | ||
762 | return dentry; | ||
763 | |||
764 | error: | 766 | error: |
765 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 767 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
766 | return ERR_PTR(err); | 768 | return ERR_PTR(err); |
@@ -793,7 +795,6 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, | |||
793 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; | 795 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; |
794 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ | 796 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ |
795 | 797 | ||
796 | dentry->d_time = dentry->d_parent->d_inode->i_version; | ||
797 | d_instantiate(dentry, inode); | 798 | d_instantiate(dentry, inode); |
798 | out: | 799 | out: |
799 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 800 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
@@ -824,6 +825,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry) | |||
824 | clear_nlink(inode); | 825 | clear_nlink(inode); |
825 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; | 826 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; |
826 | fat_detach(inode); | 827 | fat_detach(inode); |
828 | dentry->d_time = dir->i_version; | ||
827 | out: | 829 | out: |
828 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 830 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
829 | 831 | ||
@@ -849,6 +851,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry) | |||
849 | clear_nlink(inode); | 851 | clear_nlink(inode); |
850 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; | 852 | inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC; |
851 | fat_detach(inode); | 853 | fat_detach(inode); |
854 | dentry->d_time = dir->i_version; | ||
852 | out: | 855 | out: |
853 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 856 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
854 | 857 | ||
@@ -889,7 +892,6 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
889 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; | 892 | inode->i_mtime = inode->i_atime = inode->i_ctime = ts; |
890 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ | 893 | /* timestamp is already written, so mark_inode_dirty() is unneeded. */ |
891 | 894 | ||
892 | dentry->d_time = dentry->d_parent->d_inode->i_version; | ||
893 | d_instantiate(dentry, inode); | 895 | d_instantiate(dentry, inode); |
894 | 896 | ||
895 | mutex_unlock(&MSDOS_SB(sb)->s_lock); | 897 | mutex_unlock(&MSDOS_SB(sb)->s_lock); |
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index e4dc74713a43..1df94fabe4eb 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c | |||
@@ -1853,13 +1853,12 @@ int jbd2_journal_set_features (journal_t *journal, unsigned long compat, | |||
1853 | journal->j_chksum_driver = NULL; | 1853 | journal->j_chksum_driver = NULL; |
1854 | return 0; | 1854 | return 0; |
1855 | } | 1855 | } |
1856 | } | ||
1857 | 1856 | ||
1858 | /* Precompute checksum seed for all metadata */ | 1857 | /* Precompute checksum seed for all metadata */ |
1859 | if (jbd2_journal_has_csum_v2or3(journal)) | ||
1860 | journal->j_csum_seed = jbd2_chksum(journal, ~0, | 1858 | journal->j_csum_seed = jbd2_chksum(journal, ~0, |
1861 | sb->s_uuid, | 1859 | sb->s_uuid, |
1862 | sizeof(sb->s_uuid)); | 1860 | sizeof(sb->s_uuid)); |
1861 | } | ||
1863 | } | 1862 | } |
1864 | 1863 | ||
1865 | /* If enabling v1 checksums, downgrade superblock */ | 1864 | /* If enabling v1 checksums, downgrade superblock */ |
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index ed2b1151b171..7cbdf1b2e4ab 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c | |||
@@ -774,8 +774,12 @@ static bool nfsd41_cb_get_slot(struct nfs4_client *clp, struct rpc_task *task) | |||
774 | { | 774 | { |
775 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { | 775 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { |
776 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); | 776 | rpc_sleep_on(&clp->cl_cb_waitq, task, NULL); |
777 | dprintk("%s slot is busy\n", __func__); | 777 | /* Race breaker */ |
778 | return false; | 778 | if (test_and_set_bit(0, &clp->cl_cb_slot_busy) != 0) { |
779 | dprintk("%s slot is busy\n", __func__); | ||
780 | return false; | ||
781 | } | ||
782 | rpc_wake_up_queued_task(&clp->cl_cb_waitq, task); | ||
779 | } | 783 | } |
780 | return true; | 784 | return true; |
781 | } | 785 | } |
diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 747f3b95bd11..33a46a8dfaf7 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h | |||
@@ -335,12 +335,15 @@ void nfsd_lockd_shutdown(void); | |||
335 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) | 335 | (NFSD4_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SUPPATTR_EXCLCREAT) |
336 | 336 | ||
337 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL | 337 | #ifdef CONFIG_NFSD_V4_SECURITY_LABEL |
338 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | 338 | #define NFSD4_2_SECURITY_ATTRS FATTR4_WORD2_SECURITY_LABEL |
339 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | FATTR4_WORD2_SECURITY_LABEL) | ||
340 | #else | 339 | #else |
341 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 0 | 340 | #define NFSD4_2_SECURITY_ATTRS 0 |
342 | #endif | 341 | #endif |
343 | 342 | ||
343 | #define NFSD4_2_SUPPORTED_ATTRS_WORD2 \ | ||
344 | (NFSD4_1_SUPPORTED_ATTRS_WORD2 | \ | ||
345 | NFSD4_2_SECURITY_ATTRS) | ||
346 | |||
344 | static inline u32 nfsd_suppattrs0(u32 minorversion) | 347 | static inline u32 nfsd_suppattrs0(u32 minorversion) |
345 | { | 348 | { |
346 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 | 349 | return minorversion ? NFSD4_1_SUPPORTED_ATTRS_WORD0 |
diff --git a/include/dt-bindings/clock/qcom,mmcc-apq8084.h b/include/dt-bindings/clock/qcom,mmcc-apq8084.h index a929f86d0ddd..d72b5b35f15e 100644 --- a/include/dt-bindings/clock/qcom,mmcc-apq8084.h +++ b/include/dt-bindings/clock/qcom,mmcc-apq8084.h | |||
@@ -60,7 +60,7 @@ | |||
60 | #define ESC1_CLK_SRC 43 | 60 | #define ESC1_CLK_SRC 43 |
61 | #define HDMI_CLK_SRC 44 | 61 | #define HDMI_CLK_SRC 44 |
62 | #define VSYNC_CLK_SRC 45 | 62 | #define VSYNC_CLK_SRC 45 |
63 | #define RBCPR_CLK_SRC 46 | 63 | #define MMSS_RBCPR_CLK_SRC 46 |
64 | #define RBBMTIMER_CLK_SRC 47 | 64 | #define RBBMTIMER_CLK_SRC 47 |
65 | #define MAPLE_CLK_SRC 48 | 65 | #define MAPLE_CLK_SRC 48 |
66 | #define VDP_CLK_SRC 49 | 66 | #define VDP_CLK_SRC 49 |
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h index be21af149f11..2839c639f092 100644 --- a/include/linux/clk-provider.h +++ b/include/linux/clk-provider.h | |||
@@ -352,7 +352,6 @@ struct clk_divider { | |||
352 | #define CLK_DIVIDER_READ_ONLY BIT(5) | 352 | #define CLK_DIVIDER_READ_ONLY BIT(5) |
353 | 353 | ||
354 | extern const struct clk_ops clk_divider_ops; | 354 | extern const struct clk_ops clk_divider_ops; |
355 | extern const struct clk_ops clk_divider_ro_ops; | ||
356 | struct clk *clk_register_divider(struct device *dev, const char *name, | 355 | struct clk *clk_register_divider(struct device *dev, const char *name, |
357 | const char *parent_name, unsigned long flags, | 356 | const char *parent_name, unsigned long flags, |
358 | void __iomem *reg, u8 shift, u8 width, | 357 | void __iomem *reg, u8 shift, u8 width, |
diff --git a/include/linux/iio/events.h b/include/linux/iio/events.h index 8bbd7bc1043d..03fa332ad2a8 100644 --- a/include/linux/iio/events.h +++ b/include/linux/iio/events.h | |||
@@ -72,7 +72,7 @@ struct iio_event_data { | |||
72 | 72 | ||
73 | #define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) | 73 | #define IIO_EVENT_CODE_EXTRACT_TYPE(mask) ((mask >> 56) & 0xFF) |
74 | 74 | ||
75 | #define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0xCF) | 75 | #define IIO_EVENT_CODE_EXTRACT_DIR(mask) ((mask >> 48) & 0x7F) |
76 | 76 | ||
77 | #define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) | 77 | #define IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(mask) ((mask >> 32) & 0xFF) |
78 | 78 | ||
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index ea53b04993f2..a6059bdf7b03 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h | |||
@@ -703,7 +703,7 @@ void kvm_arch_sync_events(struct kvm *kvm); | |||
703 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); | 703 | int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); |
704 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu); | 704 | void kvm_vcpu_kick(struct kvm_vcpu *vcpu); |
705 | 705 | ||
706 | bool kvm_is_mmio_pfn(pfn_t pfn); | 706 | bool kvm_is_reserved_pfn(pfn_t pfn); |
707 | 707 | ||
708 | struct kvm_irq_ack_notifier { | 708 | struct kvm_irq_ack_notifier { |
709 | struct hlist_node link; | 709 | struct hlist_node link; |
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index f34723f7663c..910e3aa1e965 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h | |||
@@ -141,6 +141,7 @@ struct arizona { | |||
141 | 141 | ||
142 | uint16_t dac_comp_coeff; | 142 | uint16_t dac_comp_coeff; |
143 | uint8_t dac_comp_enabled; | 143 | uint8_t dac_comp_enabled; |
144 | struct mutex dac_comp_lock; | ||
144 | }; | 145 | }; |
145 | 146 | ||
146 | int arizona_clk32k_enable(struct arizona *arizona); | 147 | int arizona_clk32k_enable(struct arizona *arizona); |
diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h index cb01496bfa49..8e1cdbef3dad 100644 --- a/include/linux/mfd/davinci_voicecodec.h +++ b/include/linux/mfd/davinci_voicecodec.h | |||
@@ -99,12 +99,6 @@ struct davinci_vcif { | |||
99 | dma_addr_t dma_rx_addr; | 99 | dma_addr_t dma_rx_addr; |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct cq93vc { | ||
103 | struct platform_device *pdev; | ||
104 | struct snd_soc_codec *codec; | ||
105 | u32 sysclk; | ||
106 | }; | ||
107 | |||
108 | struct davinci_vc; | 102 | struct davinci_vc; |
109 | 103 | ||
110 | struct davinci_vc { | 104 | struct davinci_vc { |
@@ -122,7 +116,6 @@ struct davinci_vc { | |||
122 | 116 | ||
123 | /* Client devices */ | 117 | /* Client devices */ |
124 | struct davinci_vcif davinci_vcif; | 118 | struct davinci_vcif davinci_vcif; |
125 | struct cq93vc cq93vc; | ||
126 | }; | 119 | }; |
127 | 120 | ||
128 | #endif | 121 | #endif |
diff --git a/include/linux/pci.h b/include/linux/pci.h index 5be8db45e368..4c8ac5fcc224 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h | |||
@@ -331,6 +331,7 @@ struct pci_dev { | |||
331 | unsigned int is_added:1; | 331 | unsigned int is_added:1; |
332 | unsigned int is_busmaster:1; /* device is busmaster */ | 332 | unsigned int is_busmaster:1; /* device is busmaster */ |
333 | unsigned int no_msi:1; /* device may not use msi */ | 333 | unsigned int no_msi:1; /* device may not use msi */ |
334 | unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */ | ||
334 | unsigned int block_cfg_access:1; /* config space access is blocked */ | 335 | unsigned int block_cfg_access:1; /* config space access is blocked */ |
335 | unsigned int broken_parity_status:1; /* Device generates false positive parity */ | 336 | unsigned int broken_parity_status:1; /* Device generates false positive parity */ |
336 | unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ | 337 | unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ |
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h index a6591c693ebb..5e0bc779e6c5 100644 --- a/include/linux/platform_data/asoc-s3c.h +++ b/include/linux/platform_data/asoc-s3c.h | |||
@@ -27,6 +27,7 @@ struct samsung_i2s { | |||
27 | #define QUIRK_NO_MUXPSR (1 << 2) | 27 | #define QUIRK_NO_MUXPSR (1 << 2) |
28 | #define QUIRK_NEED_RSTCLR (1 << 3) | 28 | #define QUIRK_NEED_RSTCLR (1 << 3) |
29 | #define QUIRK_SUPPORTS_TDM (1 << 4) | 29 | #define QUIRK_SUPPORTS_TDM (1 << 4) |
30 | #define QUIRK_SUPPORTS_IDMA (1 << 5) | ||
30 | /* Quirks of the I2S controller */ | 31 | /* Quirks of the I2S controller */ |
31 | u32 quirks; | 32 | u32 quirks; |
32 | dma_addr_t idma_addr; | 33 | dma_addr_t idma_addr; |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index c5ed83f49c4e..4419b99d8d6e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
@@ -27,6 +27,7 @@ struct spmi_device; | |||
27 | struct regmap; | 27 | struct regmap; |
28 | struct regmap_range_cfg; | 28 | struct regmap_range_cfg; |
29 | struct regmap_field; | 29 | struct regmap_field; |
30 | struct snd_ac97; | ||
30 | 31 | ||
31 | /* An enum of all the supported cache types */ | 32 | /* An enum of all the supported cache types */ |
32 | enum regcache_type { | 33 | enum regcache_type { |
@@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev, | |||
340 | struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, | 341 | struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
341 | void __iomem *regs, | 342 | void __iomem *regs, |
342 | const struct regmap_config *config); | 343 | const struct regmap_config *config); |
344 | struct regmap *regmap_init_ac97(struct snd_ac97 *ac97, | ||
345 | const struct regmap_config *config); | ||
343 | 346 | ||
344 | struct regmap *devm_regmap_init(struct device *dev, | 347 | struct regmap *devm_regmap_init(struct device *dev, |
345 | const struct regmap_bus *bus, | 348 | const struct regmap_bus *bus, |
@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev, | |||
356 | struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, | 359 | struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id, |
357 | void __iomem *regs, | 360 | void __iomem *regs, |
358 | const struct regmap_config *config); | 361 | const struct regmap_config *config); |
362 | struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97, | ||
363 | const struct regmap_config *config); | ||
364 | |||
365 | bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg); | ||
359 | 366 | ||
360 | /** | 367 | /** |
361 | * regmap_init_mmio(): Initialise register map | 368 | * regmap_init_mmio(): Initialise register map |
diff --git a/include/net/inet_common.h b/include/net/inet_common.h index fe7994c48b75..b2828a06a5a6 100644 --- a/include/net/inet_common.h +++ b/include/net/inet_common.h | |||
@@ -37,6 +37,8 @@ int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); | |||
37 | int inet_ctl_sock_create(struct sock **sk, unsigned short family, | 37 | int inet_ctl_sock_create(struct sock **sk, unsigned short family, |
38 | unsigned short type, unsigned char protocol, | 38 | unsigned short type, unsigned char protocol, |
39 | struct net *net); | 39 | struct net *net); |
40 | int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, | ||
41 | int *addr_len); | ||
40 | 42 | ||
41 | static inline void inet_ctl_sock_destroy(struct sock *sk) | 43 | static inline void inet_ctl_sock_destroy(struct sock *sk) |
42 | { | 44 | { |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index e862497f7556..8bb00a27e219 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
@@ -184,6 +184,8 @@ struct snd_pcm_ops { | |||
184 | #define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8) | 184 | #define SNDRV_PCM_FMTBIT_DSD_U8 _SNDRV_PCM_FMTBIT(DSD_U8) |
185 | #define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE) | 185 | #define SNDRV_PCM_FMTBIT_DSD_U16_LE _SNDRV_PCM_FMTBIT(DSD_U16_LE) |
186 | #define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE) | 186 | #define SNDRV_PCM_FMTBIT_DSD_U32_LE _SNDRV_PCM_FMTBIT(DSD_U32_LE) |
187 | #define SNDRV_PCM_FMTBIT_DSD_U16_BE _SNDRV_PCM_FMTBIT(DSD_U16_BE) | ||
188 | #define SNDRV_PCM_FMTBIT_DSD_U32_BE _SNDRV_PCM_FMTBIT(DSD_U32_BE) | ||
187 | 189 | ||
188 | #ifdef SNDRV_LITTLE_ENDIAN | 190 | #ifdef SNDRV_LITTLE_ENDIAN |
189 | #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE | 191 | #define SNDRV_PCM_FMTBIT_S16 SNDRV_PCM_FMTBIT_S16_LE |
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index d76412b84b48..83284cae464c 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h | |||
@@ -36,14 +36,14 @@ | |||
36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) | 36 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) |
37 | #define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ | 37 | #define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ |
38 | 38 | ||
39 | #define RSND_SSI(_dma_id, _pio_irq, _flags) \ | 39 | #define RSND_SSI(_dma_id, _irq, _flags) \ |
40 | { .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags } | 40 | { .dma_id = _dma_id, .irq = _irq, .flags = _flags } |
41 | #define RSND_SSI_UNUSED \ | 41 | #define RSND_SSI_UNUSED \ |
42 | { .dma_id = -1, .pio_irq = -1, .flags = 0 } | 42 | { .dma_id = -1, .irq = -1, .flags = 0 } |
43 | 43 | ||
44 | struct rsnd_ssi_platform_info { | 44 | struct rsnd_ssi_platform_info { |
45 | int dma_id; | 45 | int dma_id; |
46 | int pio_irq; | 46 | int irq; |
47 | u32 flags; | 47 | u32 flags; |
48 | }; | 48 | }; |
49 | 49 | ||
diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h index a5352712194b..120d9610054e 100644 --- a/include/sound/rt5645.h +++ b/include/sound/rt5645.h | |||
@@ -23,6 +23,10 @@ struct rt5645_platform_data { | |||
23 | 23 | ||
24 | unsigned int hp_det_gpio; | 24 | unsigned int hp_det_gpio; |
25 | bool gpio_hp_det_active_high; | 25 | bool gpio_hp_det_active_high; |
26 | |||
27 | /* true if codec's jd function is used */ | ||
28 | bool en_jd_func; | ||
29 | unsigned int jd_mode; | ||
26 | }; | 30 | }; |
27 | 31 | ||
28 | #endif | 32 | #endif |
diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h index 082670e3a353..d9eb7d861cd0 100644 --- a/include/sound/rt5677.h +++ b/include/sound/rt5677.h | |||
@@ -27,6 +27,16 @@ struct rt5677_platform_data { | |||
27 | bool lout3_diff; | 27 | bool lout3_diff; |
28 | /* DMIC2 clock source selection */ | 28 | /* DMIC2 clock source selection */ |
29 | enum rt5677_dmic2_clk dmic2_clk_pin; | 29 | enum rt5677_dmic2_clk dmic2_clk_pin; |
30 | |||
31 | /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */ | ||
32 | u8 gpio_config[6]; | ||
33 | |||
34 | /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */ | ||
35 | unsigned int jd1_gpio; | ||
36 | /* jd2 and jd3 can select 0 ~ 3 as | ||
37 | OFF, GPIO4, GPIO5 and GPIO6 respectively */ | ||
38 | unsigned int jd2_gpio; | ||
39 | unsigned int jd3_gpio; | ||
30 | }; | 40 | }; |
31 | 41 | ||
32 | #endif | 42 | #endif |
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index e8b3080d196a..2df96b1384c7 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h | |||
@@ -206,7 +206,6 @@ struct snd_soc_dai_driver { | |||
206 | /* DAI description */ | 206 | /* DAI description */ |
207 | const char *name; | 207 | const char *name; |
208 | unsigned int id; | 208 | unsigned int id; |
209 | int ac97_control; | ||
210 | unsigned int base; | 209 | unsigned int base; |
211 | 210 | ||
212 | /* DAI driver callbacks */ | 211 | /* DAI driver callbacks */ |
@@ -216,6 +215,8 @@ struct snd_soc_dai_driver { | |||
216 | int (*resume)(struct snd_soc_dai *dai); | 215 | int (*resume)(struct snd_soc_dai *dai); |
217 | /* compress dai */ | 216 | /* compress dai */ |
218 | bool compress_dai; | 217 | bool compress_dai; |
218 | /* DAI is also used for the control bus */ | ||
219 | bool bus_control; | ||
219 | 220 | ||
220 | /* ops */ | 221 | /* ops */ |
221 | const struct snd_soc_dai_ops *ops; | 222 | const struct snd_soc_dai_ops *ops; |
@@ -241,7 +242,6 @@ struct snd_soc_dai { | |||
241 | const char *name; | 242 | const char *name; |
242 | int id; | 243 | int id; |
243 | struct device *dev; | 244 | struct device *dev; |
244 | void *ac97_pdata; /* platform_data for the ac97 codec */ | ||
245 | 245 | ||
246 | /* driver ops */ | 246 | /* driver ops */ |
247 | struct snd_soc_dai_driver *driver; | 247 | struct snd_soc_dai_driver *driver; |
@@ -268,7 +268,6 @@ struct snd_soc_dai { | |||
268 | unsigned int sample_bits; | 268 | unsigned int sample_bits; |
269 | 269 | ||
270 | /* parent platform/codec */ | 270 | /* parent platform/codec */ |
271 | struct snd_soc_platform *platform; | ||
272 | struct snd_soc_codec *codec; | 271 | struct snd_soc_codec *codec; |
273 | struct snd_soc_component *component; | 272 | struct snd_soc_component *component; |
274 | 273 | ||
@@ -276,8 +275,6 @@ struct snd_soc_dai { | |||
276 | unsigned int tx_mask; | 275 | unsigned int tx_mask; |
277 | unsigned int rx_mask; | 276 | unsigned int rx_mask; |
278 | 277 | ||
279 | struct snd_soc_card *card; | ||
280 | |||
281 | struct list_head list; | 278 | struct list_head list; |
282 | }; | 279 | }; |
283 | 280 | ||
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 3a4d7da67b8d..89823cfe6f04 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card); | |||
435 | unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); | 435 | unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); |
436 | 436 | ||
437 | /* Mostly internal - should not normally be used */ | 437 | /* Mostly internal - should not normally be used */ |
438 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); | 438 | void dapm_mark_endpoints_dirty(struct snd_soc_card *card); |
439 | 439 | ||
440 | /* dapm path query */ | 440 | /* dapm path query */ |
441 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 441 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
@@ -508,9 +508,9 @@ struct snd_soc_dapm_path { | |||
508 | 508 | ||
509 | /* status */ | 509 | /* status */ |
510 | u32 connect:1; /* source and sink widgets are connected */ | 510 | u32 connect:1; /* source and sink widgets are connected */ |
511 | u32 walked:1; /* path has been walked */ | ||
512 | u32 walking:1; /* path is in the process of being walked */ | 511 | u32 walking:1; /* path is in the process of being walked */ |
513 | u32 weak:1; /* path ignored for power management */ | 512 | u32 weak:1; /* path ignored for power management */ |
513 | u32 is_supply:1; /* At least one of the connected widgets is a supply */ | ||
514 | 514 | ||
515 | int (*connected)(struct snd_soc_dapm_widget *source, | 515 | int (*connected)(struct snd_soc_dapm_widget *source, |
516 | struct snd_soc_dapm_widget *sink); | 516 | struct snd_soc_dapm_widget *sink); |
@@ -544,11 +544,13 @@ struct snd_soc_dapm_widget { | |||
544 | unsigned char active:1; /* active stream on DAC, ADC's */ | 544 | unsigned char active:1; /* active stream on DAC, ADC's */ |
545 | unsigned char connected:1; /* connected codec pin */ | 545 | unsigned char connected:1; /* connected codec pin */ |
546 | unsigned char new:1; /* cnew complete */ | 546 | unsigned char new:1; /* cnew complete */ |
547 | unsigned char ext:1; /* has external widgets */ | ||
548 | unsigned char force:1; /* force state */ | 547 | unsigned char force:1; /* force state */ |
549 | unsigned char ignore_suspend:1; /* kept enabled over suspend */ | 548 | unsigned char ignore_suspend:1; /* kept enabled over suspend */ |
550 | unsigned char new_power:1; /* power from this run */ | 549 | unsigned char new_power:1; /* power from this run */ |
551 | unsigned char power_checked:1; /* power checked this run */ | 550 | unsigned char power_checked:1; /* power checked this run */ |
551 | unsigned char is_supply:1; /* Widget is a supply type widget */ | ||
552 | unsigned char is_sink:1; /* Widget is a sink type widget */ | ||
553 | unsigned char is_source:1; /* Widget is a source type widget */ | ||
552 | int subseq; /* sort within widget type */ | 554 | int subseq; /* sort within widget type */ |
553 | 555 | ||
554 | int (*power_check)(struct snd_soc_dapm_widget *w); | 556 | int (*power_check)(struct snd_soc_dapm_widget *w); |
@@ -567,6 +569,7 @@ struct snd_soc_dapm_widget { | |||
567 | struct list_head sinks; | 569 | struct list_head sinks; |
568 | 570 | ||
569 | /* used during DAPM updates */ | 571 | /* used during DAPM updates */ |
572 | struct list_head work_list; | ||
570 | struct list_head power_list; | 573 | struct list_head power_list; |
571 | struct list_head dirty; | 574 | struct list_head dirty; |
572 | int inputs; | 575 | int inputs; |
diff --git a/include/sound/soc.h b/include/sound/soc.h index 7ba7130037a0..b4fca9aed2a2 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -36,6 +36,11 @@ | |||
36 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ | 36 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ |
37 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ | 37 | .rshift = shift_right, .max = xmax, .platform_max = xmax, \ |
38 | .invert = xinvert, .autodisable = xautodisable}) | 38 | .invert = xinvert, .autodisable = xautodisable}) |
39 | #define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \ | ||
40 | ((unsigned long)&(struct soc_mixer_control) \ | ||
41 | {.reg = xreg, .rreg = xreg, .shift = shift_left, \ | ||
42 | .rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \ | ||
43 | .sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable}) | ||
39 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \ | 44 | #define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \ |
40 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable) | 45 | SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable) |
41 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ | 46 | #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ |
@@ -171,11 +176,9 @@ | |||
171 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 176 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
172 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | 177 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ |
173 | .tlv.p = (tlv_array), \ | 178 | .tlv.p = (tlv_array), \ |
174 | .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \ | 179 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ |
175 | .put = snd_soc_put_volsw_s8, \ | 180 | .put = snd_soc_put_volsw, \ |
176 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | 181 | .private_value = SOC_DOUBLE_S_VALUE(xreg, 0, 8, xmin, xmax, 7, 0, 0) } |
177 | {.reg = xreg, .min = xmin, .max = xmax, \ | ||
178 | .platform_max = xmax} } | ||
179 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \ | 182 | #define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \ |
180 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ | 183 | { .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \ |
181 | .items = xitems, .texts = xtexts, \ | 184 | .items = xitems, .texts = xtexts, \ |
@@ -366,8 +369,6 @@ struct snd_soc_jack_gpio; | |||
366 | 369 | ||
367 | typedef int (*hw_write_t)(void *,const char* ,int); | 370 | typedef int (*hw_write_t)(void *,const char* ,int); |
368 | 371 | ||
369 | extern struct snd_ac97_bus_ops *soc_ac97_ops; | ||
370 | |||
371 | enum snd_soc_pcm_subclass { | 372 | enum snd_soc_pcm_subclass { |
372 | SND_SOC_PCM_CLASS_PCM = 0, | 373 | SND_SOC_PCM_CLASS_PCM = 0, |
373 | SND_SOC_PCM_CLASS_BE = 1, | 374 | SND_SOC_PCM_CLASS_BE = 1, |
@@ -409,13 +410,9 @@ int devm_snd_soc_register_component(struct device *dev, | |||
409 | const struct snd_soc_component_driver *cmpnt_drv, | 410 | const struct snd_soc_component_driver *cmpnt_drv, |
410 | struct snd_soc_dai_driver *dai_drv, int num_dai); | 411 | struct snd_soc_dai_driver *dai_drv, int num_dai); |
411 | void snd_soc_unregister_component(struct device *dev); | 412 | void snd_soc_unregister_component(struct device *dev); |
412 | int snd_soc_cache_sync(struct snd_soc_codec *codec); | ||
413 | int snd_soc_cache_init(struct snd_soc_codec *codec); | 413 | int snd_soc_cache_init(struct snd_soc_codec *codec); |
414 | int snd_soc_cache_exit(struct snd_soc_codec *codec); | 414 | int snd_soc_cache_exit(struct snd_soc_codec *codec); |
415 | int snd_soc_cache_write(struct snd_soc_codec *codec, | 415 | |
416 | unsigned int reg, unsigned int value); | ||
417 | int snd_soc_cache_read(struct snd_soc_codec *codec, | ||
418 | unsigned int reg, unsigned int *value); | ||
419 | int snd_soc_platform_read(struct snd_soc_platform *platform, | 416 | int snd_soc_platform_read(struct snd_soc_platform *platform, |
420 | unsigned int reg); | 417 | unsigned int reg); |
421 | int snd_soc_platform_write(struct snd_soc_platform *platform, | 418 | int snd_soc_platform_write(struct snd_soc_platform *platform, |
@@ -500,14 +497,28 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec, | |||
500 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, | 497 | int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, |
501 | unsigned int mask, unsigned int value); | 498 | unsigned int mask, unsigned int value); |
502 | 499 | ||
503 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 500 | #ifdef CONFIG_SND_SOC_AC97_BUS |
504 | struct snd_ac97_bus_ops *ops, int num); | 501 | struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec); |
505 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec); | 502 | void snd_soc_free_ac97_codec(struct snd_ac97 *ac97); |
506 | 503 | ||
507 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); | 504 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); |
508 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | 505 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, |
509 | struct platform_device *pdev); | 506 | struct platform_device *pdev); |
510 | 507 | ||
508 | extern struct snd_ac97_bus_ops *soc_ac97_ops; | ||
509 | #else | ||
510 | static inline int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
511 | struct platform_device *pdev) | ||
512 | { | ||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | static inline int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | ||
517 | { | ||
518 | return 0; | ||
519 | } | ||
520 | #endif | ||
521 | |||
511 | /* | 522 | /* |
512 | *Controls | 523 | *Controls |
513 | */ | 524 | */ |
@@ -545,12 +556,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | |||
545 | struct snd_ctl_elem_value *ucontrol); | 556 | struct snd_ctl_elem_value *ucontrol); |
546 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | 557 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, |
547 | struct snd_ctl_elem_value *ucontrol); | 558 | struct snd_ctl_elem_value *ucontrol); |
548 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
549 | struct snd_ctl_elem_info *uinfo); | ||
550 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
551 | struct snd_ctl_elem_value *ucontrol); | ||
552 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
553 | struct snd_ctl_elem_value *ucontrol); | ||
554 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | 559 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, |
555 | struct snd_ctl_elem_info *uinfo); | 560 | struct snd_ctl_elem_info *uinfo); |
556 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | 561 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, |
@@ -780,24 +785,18 @@ struct snd_soc_codec { | |||
780 | struct device *dev; | 785 | struct device *dev; |
781 | const struct snd_soc_codec_driver *driver; | 786 | const struct snd_soc_codec_driver *driver; |
782 | 787 | ||
783 | struct mutex mutex; | ||
784 | struct list_head list; | 788 | struct list_head list; |
785 | struct list_head card_list; | 789 | struct list_head card_list; |
786 | 790 | ||
787 | /* runtime */ | 791 | /* runtime */ |
788 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | ||
789 | unsigned int cache_bypass:1; /* Suppress access to the cache */ | 792 | unsigned int cache_bypass:1; /* Suppress access to the cache */ |
790 | unsigned int suspended:1; /* Codec is in suspend PM state */ | 793 | unsigned int suspended:1; /* Codec is in suspend PM state */ |
791 | unsigned int ac97_registered:1; /* Codec has been AC97 registered */ | ||
792 | unsigned int ac97_created:1; /* Codec has been created by SoC */ | ||
793 | unsigned int cache_init:1; /* codec cache has been initialized */ | 794 | unsigned int cache_init:1; /* codec cache has been initialized */ |
794 | u32 cache_sync; /* Cache needs to be synced to hardware */ | ||
795 | 795 | ||
796 | /* codec IO */ | 796 | /* codec IO */ |
797 | void *control_data; /* codec control (i2c/3wire) data */ | 797 | void *control_data; /* codec control (i2c/3wire) data */ |
798 | hw_write_t hw_write; | 798 | hw_write_t hw_write; |
799 | void *reg_cache; | 799 | void *reg_cache; |
800 | struct mutex cache_rw_mutex; | ||
801 | 800 | ||
802 | /* component */ | 801 | /* component */ |
803 | struct snd_soc_component component; | 802 | struct snd_soc_component component; |
@@ -860,8 +859,6 @@ struct snd_soc_platform_driver { | |||
860 | 859 | ||
861 | int (*probe)(struct snd_soc_platform *); | 860 | int (*probe)(struct snd_soc_platform *); |
862 | int (*remove)(struct snd_soc_platform *); | 861 | int (*remove)(struct snd_soc_platform *); |
863 | int (*suspend)(struct snd_soc_dai *dai); | ||
864 | int (*resume)(struct snd_soc_dai *dai); | ||
865 | struct snd_soc_component_driver component_driver; | 862 | struct snd_soc_component_driver component_driver; |
866 | 863 | ||
867 | /* pcm creation and destruction */ | 864 | /* pcm creation and destruction */ |
@@ -886,7 +883,7 @@ struct snd_soc_platform_driver { | |||
886 | 883 | ||
887 | struct snd_soc_dai_link_component { | 884 | struct snd_soc_dai_link_component { |
888 | const char *name; | 885 | const char *name; |
889 | const struct device_node *of_node; | 886 | struct device_node *of_node; |
890 | const char *dai_name; | 887 | const char *dai_name; |
891 | }; | 888 | }; |
892 | 889 | ||
@@ -894,8 +891,6 @@ struct snd_soc_platform { | |||
894 | struct device *dev; | 891 | struct device *dev; |
895 | const struct snd_soc_platform_driver *driver; | 892 | const struct snd_soc_platform_driver *driver; |
896 | 893 | ||
897 | unsigned int suspended:1; /* platform is suspended */ | ||
898 | |||
899 | struct list_head list; | 894 | struct list_head list; |
900 | 895 | ||
901 | struct snd_soc_component component; | 896 | struct snd_soc_component component; |
@@ -990,7 +985,7 @@ struct snd_soc_codec_conf { | |||
990 | * DT/OF node, but not both. | 985 | * DT/OF node, but not both. |
991 | */ | 986 | */ |
992 | const char *dev_name; | 987 | const char *dev_name; |
993 | const struct device_node *of_node; | 988 | struct device_node *of_node; |
994 | 989 | ||
995 | /* | 990 | /* |
996 | * optional map of kcontrol, widget and path name prefixes that are | 991 | * optional map of kcontrol, widget and path name prefixes that are |
@@ -1007,7 +1002,7 @@ struct snd_soc_aux_dev { | |||
1007 | * DT/OF node, but not both. | 1002 | * DT/OF node, but not both. |
1008 | */ | 1003 | */ |
1009 | const char *codec_name; | 1004 | const char *codec_name; |
1010 | const struct device_node *codec_of_node; | 1005 | struct device_node *codec_of_node; |
1011 | 1006 | ||
1012 | /* codec/machine specific init - e.g. add machine controls */ | 1007 | /* codec/machine specific init - e.g. add machine controls */ |
1013 | int (*init)(struct snd_soc_component *component); | 1008 | int (*init)(struct snd_soc_component *component); |
@@ -1264,6 +1259,17 @@ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg); | |||
1264 | int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, | 1259 | int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg, |
1265 | unsigned int val); | 1260 | unsigned int val); |
1266 | 1261 | ||
1262 | /** | ||
1263 | * snd_soc_cache_sync() - Sync the register cache with the hardware | ||
1264 | * @codec: CODEC to sync | ||
1265 | * | ||
1266 | * Note: This function will call regcache_sync() | ||
1267 | */ | ||
1268 | static inline int snd_soc_cache_sync(struct snd_soc_codec *codec) | ||
1269 | { | ||
1270 | return regcache_sync(codec->component.regmap); | ||
1271 | } | ||
1272 | |||
1267 | /* component IO */ | 1273 | /* component IO */ |
1268 | int snd_soc_component_read(struct snd_soc_component *component, | 1274 | int snd_soc_component_read(struct snd_soc_component *component, |
1269 | unsigned int reg, unsigned int *val); | 1275 | unsigned int reg, unsigned int *val); |
@@ -1277,6 +1283,45 @@ void snd_soc_component_async_complete(struct snd_soc_component *component); | |||
1277 | int snd_soc_component_test_bits(struct snd_soc_component *component, | 1283 | int snd_soc_component_test_bits(struct snd_soc_component *component, |
1278 | unsigned int reg, unsigned int mask, unsigned int value); | 1284 | unsigned int reg, unsigned int mask, unsigned int value); |
1279 | 1285 | ||
1286 | #ifdef CONFIG_REGMAP | ||
1287 | |||
1288 | void snd_soc_component_init_regmap(struct snd_soc_component *component, | ||
1289 | struct regmap *regmap); | ||
1290 | void snd_soc_component_exit_regmap(struct snd_soc_component *component); | ||
1291 | |||
1292 | /** | ||
1293 | * snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC | ||
1294 | * @codec: The CODEC for which to initialize the regmap instance | ||
1295 | * @regmap: The regmap instance that should be used by the CODEC | ||
1296 | * | ||
1297 | * This function allows deferred assignment of the regmap instance that is | ||
1298 | * associated with the CODEC. Only use this if the regmap instance is not yet | ||
1299 | * ready when the CODEC is registered. The function must also be called before | ||
1300 | * the first IO attempt of the CODEC. | ||
1301 | */ | ||
1302 | static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec, | ||
1303 | struct regmap *regmap) | ||
1304 | { | ||
1305 | snd_soc_component_init_regmap(&codec->component, regmap); | ||
1306 | } | ||
1307 | |||
1308 | /** | ||
1309 | * snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC | ||
1310 | * @codec: The CODEC for which to de-initialize the regmap instance | ||
1311 | * | ||
1312 | * Calls regmap_exit() on the regmap instance associated to the CODEC and | ||
1313 | * removes the regmap instance from the CODEC. | ||
1314 | * | ||
1315 | * This function should only be used if snd_soc_codec_init_regmap() was used to | ||
1316 | * initialize the regmap instance. | ||
1317 | */ | ||
1318 | static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec) | ||
1319 | { | ||
1320 | snd_soc_component_exit_regmap(&codec->component); | ||
1321 | } | ||
1322 | |||
1323 | #endif | ||
1324 | |||
1280 | /* device driver data */ | 1325 | /* device driver data */ |
1281 | 1326 | ||
1282 | static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, | 1327 | static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card, |
@@ -1451,6 +1496,9 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
1451 | struct device_node **framemaster); | 1496 | struct device_node **framemaster); |
1452 | int snd_soc_of_get_dai_name(struct device_node *of_node, | 1497 | int snd_soc_of_get_dai_name(struct device_node *of_node, |
1453 | const char **dai_name); | 1498 | const char **dai_name); |
1499 | int snd_soc_of_get_dai_link_codecs(struct device *dev, | ||
1500 | struct device_node *of_node, | ||
1501 | struct snd_soc_dai_link *dai_link); | ||
1454 | 1502 | ||
1455 | #include <sound/soc-dai.h> | 1503 | #include <sound/soc-dai.h> |
1456 | 1504 | ||
diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h index e475659bd3be..509efb050176 100644 --- a/include/sound/uda134x.h +++ b/include/sound/uda134x.h | |||
@@ -18,18 +18,6 @@ struct uda134x_platform_data { | |||
18 | struct l3_pins l3; | 18 | struct l3_pins l3; |
19 | void (*power) (int); | 19 | void (*power) (int); |
20 | int model; | 20 | int model; |
21 | /* | ||
22 | ALSA SOC usually puts the device in standby mode when it's not used | ||
23 | for sometime. If you unset is_powered_on_standby the driver will | ||
24 | turn off the ADC/DAC when this callback is invoked and turn it back | ||
25 | on when needed. Unfortunately this will result in a very light bump | ||
26 | (it can be audible only with good earphones). If this bothers you | ||
27 | set is_powered_on_standby, you will have slightly higher power | ||
28 | consumption. Please note that sending the L3 command for ADC is | ||
29 | enough to make the bump, so it doesn't make difference if you | ||
30 | completely take off power from the codec. | ||
31 | */ | ||
32 | int is_powered_on_standby; | ||
33 | #define UDA134X_UDA1340 1 | 21 | #define UDA134X_UDA1340 1 |
34 | #define UDA134X_UDA1341 2 | 22 | #define UDA134X_UDA1341 2 |
35 | #define UDA134X_UDA1344 3 | 23 | #define UDA134X_UDA1344 3 |
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h index b04ee7e5a466..88cf39d96d0f 100644 --- a/include/trace/events/asoc.h +++ b/include/trace/events/asoc.h | |||
@@ -288,31 +288,6 @@ TRACE_EVENT(snd_soc_jack_notify, | |||
288 | TP_printk("jack=%s %x", __get_str(name), (int)__entry->val) | 288 | TP_printk("jack=%s %x", __get_str(name), (int)__entry->val) |
289 | ); | 289 | ); |
290 | 290 | ||
291 | TRACE_EVENT(snd_soc_cache_sync, | ||
292 | |||
293 | TP_PROTO(struct snd_soc_codec *codec, const char *type, | ||
294 | const char *status), | ||
295 | |||
296 | TP_ARGS(codec, type, status), | ||
297 | |||
298 | TP_STRUCT__entry( | ||
299 | __string( name, codec->component.name) | ||
300 | __string( status, status ) | ||
301 | __string( type, type ) | ||
302 | __field( int, id ) | ||
303 | ), | ||
304 | |||
305 | TP_fast_assign( | ||
306 | __assign_str(name, codec->component.name); | ||
307 | __assign_str(status, status); | ||
308 | __assign_str(type, type); | ||
309 | __entry->id = codec->component.id; | ||
310 | ), | ||
311 | |||
312 | TP_printk("codec=%s.%d type=%s status=%s", __get_str(name), | ||
313 | (int)__entry->id, __get_str(type), __get_str(status)) | ||
314 | ); | ||
315 | |||
316 | #endif /* _TRACE_ASOC_H */ | 291 | #endif /* _TRACE_ASOC_H */ |
317 | 292 | ||
318 | /* This part must be outside protection */ | 293 | /* This part must be outside protection */ |
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 4c94f31a8c99..8523f9bb72f2 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild | |||
@@ -427,7 +427,7 @@ header-y += virtio_net.h | |||
427 | header-y += virtio_pci.h | 427 | header-y += virtio_pci.h |
428 | header-y += virtio_ring.h | 428 | header-y += virtio_ring.h |
429 | header-y += virtio_rng.h | 429 | header-y += virtio_rng.h |
430 | header=y += vm_sockets.h | 430 | header-y += vm_sockets.h |
431 | header-y += vt.h | 431 | header-y += vt.h |
432 | header-y += wait.h | 432 | header-y += wait.h |
433 | header-y += wanrouter.h | 433 | header-y += wanrouter.h |
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h index 6ee586728df9..941d32f007dc 100644 --- a/include/uapi/sound/asound.h +++ b/include/uapi/sound/asound.h | |||
@@ -220,7 +220,9 @@ typedef int __bitwise snd_pcm_format_t; | |||
220 | #define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ | 220 | #define SNDRV_PCM_FORMAT_DSD_U8 ((__force snd_pcm_format_t) 48) /* DSD, 1-byte samples DSD (x8) */ |
221 | #define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ | 221 | #define SNDRV_PCM_FORMAT_DSD_U16_LE ((__force snd_pcm_format_t) 49) /* DSD, 2-byte samples DSD (x16), little endian */ |
222 | #define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ | 222 | #define SNDRV_PCM_FORMAT_DSD_U32_LE ((__force snd_pcm_format_t) 50) /* DSD, 4-byte samples DSD (x32), little endian */ |
223 | #define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_LE | 223 | #define SNDRV_PCM_FORMAT_DSD_U16_BE ((__force snd_pcm_format_t) 51) /* DSD, 2-byte samples DSD (x16), big endian */ |
224 | #define SNDRV_PCM_FORMAT_DSD_U32_BE ((__force snd_pcm_format_t) 52) /* DSD, 4-byte samples DSD (x32), big endian */ | ||
225 | #define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_DSD_U32_BE | ||
224 | 226 | ||
225 | #ifdef SNDRV_LITTLE_ENDIAN | 227 | #ifdef SNDRV_LITTLE_ENDIAN |
226 | #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE | 228 | #define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE |
@@ -507,13 +507,6 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
507 | return retval; | 507 | return retval; |
508 | } | 508 | } |
509 | 509 | ||
510 | id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); | ||
511 | if (id < 0) { | ||
512 | ipc_rcu_putref(sma, sem_rcu_free); | ||
513 | return id; | ||
514 | } | ||
515 | ns->used_sems += nsems; | ||
516 | |||
517 | sma->sem_base = (struct sem *) &sma[1]; | 510 | sma->sem_base = (struct sem *) &sma[1]; |
518 | 511 | ||
519 | for (i = 0; i < nsems; i++) { | 512 | for (i = 0; i < nsems; i++) { |
@@ -528,6 +521,14 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params) | |||
528 | INIT_LIST_HEAD(&sma->list_id); | 521 | INIT_LIST_HEAD(&sma->list_id); |
529 | sma->sem_nsems = nsems; | 522 | sma->sem_nsems = nsems; |
530 | sma->sem_ctime = get_seconds(); | 523 | sma->sem_ctime = get_seconds(); |
524 | |||
525 | id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni); | ||
526 | if (id < 0) { | ||
527 | ipc_rcu_putref(sma, sem_rcu_free); | ||
528 | return id; | ||
529 | } | ||
530 | ns->used_sems += nsems; | ||
531 | |||
531 | sem_unlock(sma, -1); | 532 | sem_unlock(sma, -1); |
532 | rcu_read_unlock(); | 533 | rcu_read_unlock(); |
533 | 534 | ||
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 24beb9bb4c3e..89e7283015a6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -2874,10 +2874,14 @@ asmlinkage __visible void __sched schedule_user(void) | |||
2874 | * or we have been woken up remotely but the IPI has not yet arrived, | 2874 | * or we have been woken up remotely but the IPI has not yet arrived, |
2875 | * we haven't yet exited the RCU idle mode. Do it here manually until | 2875 | * we haven't yet exited the RCU idle mode. Do it here manually until |
2876 | * we find a better solution. | 2876 | * we find a better solution. |
2877 | * | ||
2878 | * NB: There are buggy callers of this function. Ideally we | ||
2879 | * should warn if prev_state != IN_USER, but that will trigger | ||
2880 | * too frequently to make sense yet. | ||
2877 | */ | 2881 | */ |
2878 | user_exit(); | 2882 | enum ctx_state prev_state = exception_enter(); |
2879 | schedule(); | 2883 | schedule(); |
2880 | user_enter(); | 2884 | exception_exit(prev_state); |
2881 | } | 2885 | } |
2882 | #endif | 2886 | #endif |
2883 | 2887 | ||
diff --git a/lib/genalloc.c b/lib/genalloc.c index cce4dd68c40d..2e65d206b01c 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c | |||
@@ -598,6 +598,7 @@ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order, | |||
598 | 598 | ||
599 | return pool; | 599 | return pool; |
600 | } | 600 | } |
601 | EXPORT_SYMBOL(devm_gen_pool_create); | ||
601 | 602 | ||
602 | /** | 603 | /** |
603 | * dev_get_gen_pool - Obtain the gen_pool (if any) for a device | 604 | * dev_get_gen_pool - Obtain the gen_pool (if any) for a device |
diff --git a/lib/show_mem.c b/lib/show_mem.c index 09225796991a..5e256271b47b 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c | |||
@@ -28,7 +28,7 @@ void show_mem(unsigned int filter) | |||
28 | continue; | 28 | continue; |
29 | 29 | ||
30 | total += zone->present_pages; | 30 | total += zone->present_pages; |
31 | reserved = zone->present_pages - zone->managed_pages; | 31 | reserved += zone->present_pages - zone->managed_pages; |
32 | 32 | ||
33 | if (is_highmem_idx(zoneid)) | 33 | if (is_highmem_idx(zoneid)) |
34 | highmem += zone->present_pages; | 34 | highmem += zone->present_pages; |
diff --git a/mm/frontswap.c b/mm/frontswap.c index c30eec536f03..f2a3571c6e22 100644 --- a/mm/frontswap.c +++ b/mm/frontswap.c | |||
@@ -244,8 +244,10 @@ int __frontswap_store(struct page *page) | |||
244 | the (older) page from frontswap | 244 | the (older) page from frontswap |
245 | */ | 245 | */ |
246 | inc_frontswap_failed_stores(); | 246 | inc_frontswap_failed_stores(); |
247 | if (dup) | 247 | if (dup) { |
248 | __frontswap_clear(sis, offset); | 248 | __frontswap_clear(sis, offset); |
249 | frontswap_ops->invalidate_page(type, offset); | ||
250 | } | ||
249 | } | 251 | } |
250 | if (frontswap_writethrough_enabled) | 252 | if (frontswap_writethrough_enabled) |
251 | /* report failure so swap also writes to swap device */ | 253 | /* report failure so swap also writes to swap device */ |
diff --git a/mm/memory.c b/mm/memory.c index 3e503831e042..d5f2ae9c4a23 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -815,20 +815,20 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm, | |||
815 | if (!pte_file(pte)) { | 815 | if (!pte_file(pte)) { |
816 | swp_entry_t entry = pte_to_swp_entry(pte); | 816 | swp_entry_t entry = pte_to_swp_entry(pte); |
817 | 817 | ||
818 | if (swap_duplicate(entry) < 0) | 818 | if (likely(!non_swap_entry(entry))) { |
819 | return entry.val; | 819 | if (swap_duplicate(entry) < 0) |
820 | 820 | return entry.val; | |
821 | /* make sure dst_mm is on swapoff's mmlist. */ | 821 | |
822 | if (unlikely(list_empty(&dst_mm->mmlist))) { | 822 | /* make sure dst_mm is on swapoff's mmlist. */ |
823 | spin_lock(&mmlist_lock); | 823 | if (unlikely(list_empty(&dst_mm->mmlist))) { |
824 | if (list_empty(&dst_mm->mmlist)) | 824 | spin_lock(&mmlist_lock); |
825 | list_add(&dst_mm->mmlist, | 825 | if (list_empty(&dst_mm->mmlist)) |
826 | &src_mm->mmlist); | 826 | list_add(&dst_mm->mmlist, |
827 | spin_unlock(&mmlist_lock); | 827 | &src_mm->mmlist); |
828 | } | 828 | spin_unlock(&mmlist_lock); |
829 | if (likely(!non_swap_entry(entry))) | 829 | } |
830 | rss[MM_SWAPENTS]++; | 830 | rss[MM_SWAPENTS]++; |
831 | else if (is_migration_entry(entry)) { | 831 | } else if (is_migration_entry(entry)) { |
832 | page = migration_entry_to_page(entry); | 832 | page = migration_entry_to_page(entry); |
833 | 833 | ||
834 | if (PageAnon(page)) | 834 | if (PageAnon(page)) |
@@ -776,8 +776,11 @@ again: remove_next = 1 + (end > next->vm_end); | |||
776 | * shrinking vma had, to cover any anon pages imported. | 776 | * shrinking vma had, to cover any anon pages imported. |
777 | */ | 777 | */ |
778 | if (exporter && exporter->anon_vma && !importer->anon_vma) { | 778 | if (exporter && exporter->anon_vma && !importer->anon_vma) { |
779 | if (anon_vma_clone(importer, exporter)) | 779 | int error; |
780 | return -ENOMEM; | 780 | |
781 | error = anon_vma_clone(importer, exporter); | ||
782 | if (error) | ||
783 | return error; | ||
781 | importer->anon_vma = exporter->anon_vma; | 784 | importer->anon_vma = exporter->anon_vma; |
782 | } | 785 | } |
783 | } | 786 | } |
@@ -2469,7 +2472,8 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, | |||
2469 | if (err) | 2472 | if (err) |
2470 | goto out_free_vma; | 2473 | goto out_free_vma; |
2471 | 2474 | ||
2472 | if (anon_vma_clone(new, vma)) | 2475 | err = anon_vma_clone(new, vma); |
2476 | if (err) | ||
2473 | goto out_free_mpol; | 2477 | goto out_free_mpol; |
2474 | 2478 | ||
2475 | if (new->vm_file) | 2479 | if (new->vm_file) |
@@ -274,6 +274,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) | |||
274 | { | 274 | { |
275 | struct anon_vma_chain *avc; | 275 | struct anon_vma_chain *avc; |
276 | struct anon_vma *anon_vma; | 276 | struct anon_vma *anon_vma; |
277 | int error; | ||
277 | 278 | ||
278 | /* Don't bother if the parent process has no anon_vma here. */ | 279 | /* Don't bother if the parent process has no anon_vma here. */ |
279 | if (!pvma->anon_vma) | 280 | if (!pvma->anon_vma) |
@@ -283,8 +284,9 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) | |||
283 | * First, attach the new VMA to the parent VMA's anon_vmas, | 284 | * First, attach the new VMA to the parent VMA's anon_vmas, |
284 | * so rmap can find non-COWed pages in child processes. | 285 | * so rmap can find non-COWed pages in child processes. |
285 | */ | 286 | */ |
286 | if (anon_vma_clone(vma, pvma)) | 287 | error = anon_vma_clone(vma, pvma); |
287 | return -ENOMEM; | 288 | if (error) |
289 | return error; | ||
288 | 290 | ||
289 | /* Then add our own anon_vma. */ | 291 | /* Then add our own anon_vma. */ |
290 | anon_vma = anon_vma_alloc(); | 292 | anon_vma = anon_vma_alloc(); |
@@ -3076,7 +3076,7 @@ static void *____cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, | |||
3076 | void *obj; | 3076 | void *obj; |
3077 | int x; | 3077 | int x; |
3078 | 3078 | ||
3079 | VM_BUG_ON(nodeid > num_online_nodes()); | 3079 | VM_BUG_ON(nodeid < 0 || nodeid >= MAX_NUMNODES); |
3080 | n = get_node(cachep, nodeid); | 3080 | n = get_node(cachep, nodeid); |
3081 | BUG_ON(!n); | 3081 | BUG_ON(!n); |
3082 | 3082 | ||
diff --git a/mm/vmpressure.c b/mm/vmpressure.c index d4042e75f7c7..c5afd573d7da 100644 --- a/mm/vmpressure.c +++ b/mm/vmpressure.c | |||
@@ -165,6 +165,7 @@ static void vmpressure_work_fn(struct work_struct *work) | |||
165 | unsigned long scanned; | 165 | unsigned long scanned; |
166 | unsigned long reclaimed; | 166 | unsigned long reclaimed; |
167 | 167 | ||
168 | spin_lock(&vmpr->sr_lock); | ||
168 | /* | 169 | /* |
169 | * Several contexts might be calling vmpressure(), so it is | 170 | * Several contexts might be calling vmpressure(), so it is |
170 | * possible that the work was rescheduled again before the old | 171 | * possible that the work was rescheduled again before the old |
@@ -173,11 +174,12 @@ static void vmpressure_work_fn(struct work_struct *work) | |||
173 | * here. No need for any locks here since we don't care if | 174 | * here. No need for any locks here since we don't care if |
174 | * vmpr->reclaimed is in sync. | 175 | * vmpr->reclaimed is in sync. |
175 | */ | 176 | */ |
176 | if (!vmpr->scanned) | 177 | scanned = vmpr->scanned; |
178 | if (!scanned) { | ||
179 | spin_unlock(&vmpr->sr_lock); | ||
177 | return; | 180 | return; |
181 | } | ||
178 | 182 | ||
179 | spin_lock(&vmpr->sr_lock); | ||
180 | scanned = vmpr->scanned; | ||
181 | reclaimed = vmpr->reclaimed; | 183 | reclaimed = vmpr->reclaimed; |
182 | vmpr->scanned = 0; | 184 | vmpr->scanned = 0; |
183 | vmpr->reclaimed = 0; | 185 | vmpr->reclaimed = 0; |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 2ff9706647f2..e5ec470b851f 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -280,6 +280,7 @@ static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = { | |||
280 | [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, | 280 | [IFLA_BRPORT_MODE] = { .type = NLA_U8 }, |
281 | [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, | 281 | [IFLA_BRPORT_GUARD] = { .type = NLA_U8 }, |
282 | [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, | 282 | [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 }, |
283 | [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 }, | ||
283 | [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, | 284 | [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 }, |
284 | [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, | 285 | [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 }, |
285 | }; | 286 | }; |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index a6882686ca3a..76321ea442c3 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -1498,6 +1498,7 @@ static int do_setlink(const struct sk_buff *skb, | |||
1498 | goto errout; | 1498 | goto errout; |
1499 | } | 1499 | } |
1500 | if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { | 1500 | if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { |
1501 | put_net(net); | ||
1501 | err = -EPERM; | 1502 | err = -EPERM; |
1502 | goto errout; | 1503 | goto errout; |
1503 | } | 1504 | } |
@@ -2685,13 +2686,20 @@ static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) | |||
2685 | int idx = 0; | 2686 | int idx = 0; |
2686 | u32 portid = NETLINK_CB(cb->skb).portid; | 2687 | u32 portid = NETLINK_CB(cb->skb).portid; |
2687 | u32 seq = cb->nlh->nlmsg_seq; | 2688 | u32 seq = cb->nlh->nlmsg_seq; |
2688 | struct nlattr *extfilt; | ||
2689 | u32 filter_mask = 0; | 2689 | u32 filter_mask = 0; |
2690 | 2690 | ||
2691 | extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg), | 2691 | if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) { |
2692 | IFLA_EXT_MASK); | 2692 | struct nlattr *extfilt; |
2693 | if (extfilt) | 2693 | |
2694 | filter_mask = nla_get_u32(extfilt); | 2694 | extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg), |
2695 | IFLA_EXT_MASK); | ||
2696 | if (extfilt) { | ||
2697 | if (nla_len(extfilt) < sizeof(filter_mask)) | ||
2698 | return -EINVAL; | ||
2699 | |||
2700 | filter_mask = nla_get_u32(extfilt); | ||
2701 | } | ||
2702 | } | ||
2695 | 2703 | ||
2696 | rcu_read_lock(); | 2704 | rcu_read_lock(); |
2697 | for_each_netdev_rcu(net, dev) { | 2705 | for_each_netdev_rcu(net, dev) { |
@@ -2798,6 +2806,9 @@ static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2798 | if (br_spec) { | 2806 | if (br_spec) { |
2799 | nla_for_each_nested(attr, br_spec, rem) { | 2807 | nla_for_each_nested(attr, br_spec, rem) { |
2800 | if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { | 2808 | if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { |
2809 | if (nla_len(attr) < sizeof(flags)) | ||
2810 | return -EINVAL; | ||
2811 | |||
2801 | have_flags = true; | 2812 | have_flags = true; |
2802 | flags = nla_get_u16(attr); | 2813 | flags = nla_get_u16(attr); |
2803 | break; | 2814 | break; |
@@ -2868,6 +2879,9 @@ static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) | |||
2868 | if (br_spec) { | 2879 | if (br_spec) { |
2869 | nla_for_each_nested(attr, br_spec, rem) { | 2880 | nla_for_each_nested(attr, br_spec, rem) { |
2870 | if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { | 2881 | if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { |
2882 | if (nla_len(attr) < sizeof(flags)) | ||
2883 | return -EINVAL; | ||
2884 | |||
2871 | have_flags = true; | 2885 | have_flags = true; |
2872 | flags = nla_get_u16(attr); | 2886 | flags = nla_get_u16(attr); |
2873 | break; | 2887 | break; |
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 8b7fe5b03906..e67da4e6c324 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c | |||
@@ -1386,6 +1386,17 @@ out: | |||
1386 | return pp; | 1386 | return pp; |
1387 | } | 1387 | } |
1388 | 1388 | ||
1389 | int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) | ||
1390 | { | ||
1391 | if (sk->sk_family == AF_INET) | ||
1392 | return ip_recv_error(sk, msg, len, addr_len); | ||
1393 | #if IS_ENABLED(CONFIG_IPV6) | ||
1394 | if (sk->sk_family == AF_INET6) | ||
1395 | return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len); | ||
1396 | #endif | ||
1397 | return -EINVAL; | ||
1398 | } | ||
1399 | |||
1389 | static int inet_gro_complete(struct sk_buff *skb, int nhoff) | 1400 | static int inet_gro_complete(struct sk_buff *skb, int nhoff) |
1390 | { | 1401 | { |
1391 | __be16 newlen = htons(skb->len - nhoff); | 1402 | __be16 newlen = htons(skb->len - nhoff); |
diff --git a/net/ipv4/ip_vti.c b/net/ipv4/ip_vti.c index 3e861011e4a3..1a7e979e80ba 100644 --- a/net/ipv4/ip_vti.c +++ b/net/ipv4/ip_vti.c | |||
@@ -528,6 +528,7 @@ static struct rtnl_link_ops vti_link_ops __read_mostly = { | |||
528 | .validate = vti_tunnel_validate, | 528 | .validate = vti_tunnel_validate, |
529 | .newlink = vti_newlink, | 529 | .newlink = vti_newlink, |
530 | .changelink = vti_changelink, | 530 | .changelink = vti_changelink, |
531 | .dellink = ip_tunnel_dellink, | ||
531 | .get_size = vti_get_size, | 532 | .get_size = vti_get_size, |
532 | .fill_info = vti_fill_info, | 533 | .fill_info = vti_fill_info, |
533 | }; | 534 | }; |
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 57f7c9804139..5d740cccf69e 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c | |||
@@ -217,6 +217,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident) | |||
217 | &ipv6_hdr(skb)->daddr)) | 217 | &ipv6_hdr(skb)->daddr)) |
218 | continue; | 218 | continue; |
219 | #endif | 219 | #endif |
220 | } else { | ||
221 | continue; | ||
220 | } | 222 | } |
221 | 223 | ||
222 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) | 224 | if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) |
@@ -853,16 +855,8 @@ int ping_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
853 | if (flags & MSG_OOB) | 855 | if (flags & MSG_OOB) |
854 | goto out; | 856 | goto out; |
855 | 857 | ||
856 | if (flags & MSG_ERRQUEUE) { | 858 | if (flags & MSG_ERRQUEUE) |
857 | if (family == AF_INET) { | 859 | return inet_recv_error(sk, msg, len, addr_len); |
858 | return ip_recv_error(sk, msg, len, addr_len); | ||
859 | #if IS_ENABLED(CONFIG_IPV6) | ||
860 | } else if (family == AF_INET6) { | ||
861 | return pingv6_ops.ipv6_recv_error(sk, msg, len, | ||
862 | addr_len); | ||
863 | #endif | ||
864 | } | ||
865 | } | ||
866 | 860 | ||
867 | skb = skb_recv_datagram(sk, flags, noblock, &err); | 861 | skb = skb_recv_datagram(sk, flags, noblock, &err); |
868 | if (!skb) | 862 | if (!skb) |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 39ec0c379545..38c2bcb8dd5d 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -1598,7 +1598,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, | |||
1598 | u32 urg_hole = 0; | 1598 | u32 urg_hole = 0; |
1599 | 1599 | ||
1600 | if (unlikely(flags & MSG_ERRQUEUE)) | 1600 | if (unlikely(flags & MSG_ERRQUEUE)) |
1601 | return ip_recv_error(sk, msg, len, addr_len); | 1601 | return inet_recv_error(sk, msg, len, addr_len); |
1602 | 1602 | ||
1603 | if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && | 1603 | if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && |
1604 | (sk->sk_state == TCP_ESTABLISHED)) | 1604 | (sk->sk_state == TCP_ESTABLISHED)) |
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 9c7d7621466b..147be2024290 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c | |||
@@ -598,7 +598,10 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) | |||
598 | if (th->rst) | 598 | if (th->rst) |
599 | return; | 599 | return; |
600 | 600 | ||
601 | if (skb_rtable(skb)->rt_type != RTN_LOCAL) | 601 | /* If sk not NULL, it means we did a successful lookup and incoming |
602 | * route had to be correct. prequeue might have dropped our dst. | ||
603 | */ | ||
604 | if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL) | ||
602 | return; | 605 | return; |
603 | 606 | ||
604 | /* Swap the send and the receive. */ | 607 | /* Swap the send and the receive. */ |
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c index 4564e1fca3eb..0e32d2e1bdbf 100644 --- a/net/ipv6/ip6_gre.c +++ b/net/ipv6/ip6_gre.c | |||
@@ -502,11 +502,11 @@ static int ip6gre_rcv(struct sk_buff *skb) | |||
502 | 502 | ||
503 | skb->protocol = gre_proto; | 503 | skb->protocol = gre_proto; |
504 | /* WCCP version 1 and 2 protocol decoding. | 504 | /* WCCP version 1 and 2 protocol decoding. |
505 | * - Change protocol to IP | 505 | * - Change protocol to IPv6 |
506 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | 506 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header |
507 | */ | 507 | */ |
508 | if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) { | 508 | if (flags == 0 && gre_proto == htons(ETH_P_WCCP)) { |
509 | skb->protocol = htons(ETH_P_IP); | 509 | skb->protocol = htons(ETH_P_IPV6); |
510 | if ((*(h + offset) & 0xF0) != 0x40) | 510 | if ((*(h + offset) & 0xF0) != 0x40) |
511 | offset += 4; | 511 | offset += 4; |
512 | } | 512 | } |
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c index a071563a7e6e..01e12d0d8fcc 100644 --- a/net/ipv6/ip6_offload.c +++ b/net/ipv6/ip6_offload.c | |||
@@ -69,7 +69,8 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, | |||
69 | int nhoff; | 69 | int nhoff; |
70 | 70 | ||
71 | if (unlikely(skb_shinfo(skb)->gso_type & | 71 | if (unlikely(skb_shinfo(skb)->gso_type & |
72 | ~(SKB_GSO_UDP | | 72 | ~(SKB_GSO_TCPV4 | |
73 | SKB_GSO_UDP | | ||
73 | SKB_GSO_DODGY | | 74 | SKB_GSO_DODGY | |
74 | SKB_GSO_TCP_ECN | | 75 | SKB_GSO_TCP_ECN | |
75 | SKB_GSO_GRE | | 76 | SKB_GSO_GRE | |
diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index b04ed72c4542..8db6c98fe218 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c | |||
@@ -79,15 +79,13 @@ int udp_tunnel6_xmit_skb(struct socket *sock, struct dst_entry *dst, | |||
79 | uh->source = src_port; | 79 | uh->source = src_port; |
80 | 80 | ||
81 | uh->len = htons(skb->len); | 81 | uh->len = htons(skb->len); |
82 | uh->check = 0; | ||
83 | 82 | ||
84 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); | 83 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
85 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED | 84 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
86 | | IPSKB_REROUTED); | 85 | | IPSKB_REROUTED); |
87 | skb_dst_set(skb, dst); | 86 | skb_dst_set(skb, dst); |
88 | 87 | ||
89 | udp6_set_csum(udp_get_no_check6_tx(sk), skb, &inet6_sk(sk)->saddr, | 88 | udp6_set_csum(udp_get_no_check6_tx(sk), skb, saddr, daddr, skb->len); |
90 | &sk->sk_v6_daddr, skb->len); | ||
91 | 89 | ||
92 | __skb_push(skb, sizeof(*ip6h)); | 90 | __skb_push(skb, sizeof(*ip6h)); |
93 | skb_reset_network_header(skb); | 91 | skb_reset_network_header(skb); |
diff --git a/net/ipv6/ip6_vti.c b/net/ipv6/ip6_vti.c index 31089d153fd3..bcda14de7f84 100644 --- a/net/ipv6/ip6_vti.c +++ b/net/ipv6/ip6_vti.c | |||
@@ -905,6 +905,15 @@ static int vti6_newlink(struct net *src_net, struct net_device *dev, | |||
905 | return vti6_tnl_create2(dev); | 905 | return vti6_tnl_create2(dev); |
906 | } | 906 | } |
907 | 907 | ||
908 | static void vti6_dellink(struct net_device *dev, struct list_head *head) | ||
909 | { | ||
910 | struct net *net = dev_net(dev); | ||
911 | struct vti6_net *ip6n = net_generic(net, vti6_net_id); | ||
912 | |||
913 | if (dev != ip6n->fb_tnl_dev) | ||
914 | unregister_netdevice_queue(dev, head); | ||
915 | } | ||
916 | |||
908 | static int vti6_changelink(struct net_device *dev, struct nlattr *tb[], | 917 | static int vti6_changelink(struct net_device *dev, struct nlattr *tb[], |
909 | struct nlattr *data[]) | 918 | struct nlattr *data[]) |
910 | { | 919 | { |
@@ -980,6 +989,7 @@ static struct rtnl_link_ops vti6_link_ops __read_mostly = { | |||
980 | .setup = vti6_dev_setup, | 989 | .setup = vti6_dev_setup, |
981 | .validate = vti6_validate, | 990 | .validate = vti6_validate, |
982 | .newlink = vti6_newlink, | 991 | .newlink = vti6_newlink, |
992 | .dellink = vti6_dellink, | ||
983 | .changelink = vti6_changelink, | 993 | .changelink = vti6_changelink, |
984 | .get_size = vti6_get_size, | 994 | .get_size = vti6_get_size, |
985 | .fill_info = vti6_fill_info, | 995 | .fill_info = vti6_fill_info, |
@@ -1020,6 +1030,7 @@ static int __net_init vti6_init_net(struct net *net) | |||
1020 | if (!ip6n->fb_tnl_dev) | 1030 | if (!ip6n->fb_tnl_dev) |
1021 | goto err_alloc_dev; | 1031 | goto err_alloc_dev; |
1022 | dev_net_set(ip6n->fb_tnl_dev, net); | 1032 | dev_net_set(ip6n->fb_tnl_dev, net); |
1033 | ip6n->fb_tnl_dev->rtnl_link_ops = &vti6_link_ops; | ||
1023 | 1034 | ||
1024 | err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev); | 1035 | err = vti6_fb_tnl_dev_init(ip6n->fb_tnl_dev); |
1025 | if (err < 0) | 1036 | if (err < 0) |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index ace29b60813c..dc495ae2ead0 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -903,7 +903,10 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) | |||
903 | if (th->rst) | 903 | if (th->rst) |
904 | return; | 904 | return; |
905 | 905 | ||
906 | if (!ipv6_unicast_destination(skb)) | 906 | /* If sk not NULL, it means we did a successful lookup and incoming |
907 | * route had to be correct. prequeue might have dropped our dst. | ||
908 | */ | ||
909 | if (!sk && !ipv6_unicast_destination(skb)) | ||
907 | return; | 910 | return; |
908 | 911 | ||
909 | #ifdef CONFIG_TCP_MD5SIG | 912 | #ifdef CONFIG_TCP_MD5SIG |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 2c699757bccf..5016a6929085 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -611,16 +611,12 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
611 | */ | 611 | */ |
612 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); | 612 | NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); |
613 | pr_debug("Confirming conntrack %p\n", ct); | 613 | pr_debug("Confirming conntrack %p\n", ct); |
614 | 614 | /* We have to check the DYING flag inside the lock to prevent | |
615 | /* We have to check the DYING flag after unlink to prevent | 615 | a race against nf_ct_get_next_corpse() possibly called from |
616 | * a race against nf_ct_get_next_corpse() possibly called from | 616 | user context, else we insert an already 'dead' hash, blocking |
617 | * user context, else we insert an already 'dead' hash, blocking | 617 | further use of that particular connection -JM */ |
618 | * further use of that particular connection -JM. | ||
619 | */ | ||
620 | nf_ct_del_from_dying_or_unconfirmed_list(ct); | ||
621 | 618 | ||
622 | if (unlikely(nf_ct_is_dying(ct))) { | 619 | if (unlikely(nf_ct_is_dying(ct))) { |
623 | nf_ct_add_to_dying_list(ct); | ||
624 | nf_conntrack_double_unlock(hash, reply_hash); | 620 | nf_conntrack_double_unlock(hash, reply_hash); |
625 | local_bh_enable(); | 621 | local_bh_enable(); |
626 | return NF_ACCEPT; | 622 | return NF_ACCEPT; |
@@ -640,6 +636,8 @@ __nf_conntrack_confirm(struct sk_buff *skb) | |||
640 | zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) | 636 | zone == nf_ct_zone(nf_ct_tuplehash_to_ctrack(h))) |
641 | goto out; | 637 | goto out; |
642 | 638 | ||
639 | nf_ct_del_from_dying_or_unconfirmed_list(ct); | ||
640 | |||
643 | /* Timer relative to confirmation time, not original | 641 | /* Timer relative to confirmation time, not original |
644 | setting time, otherwise we'd get timer wrap in | 642 | setting time, otherwise we'd get timer wrap in |
645 | weird delay cases. */ | 643 | weird delay cases. */ |
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 87d20f48ff06..07c04a841ba0 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -378,7 +378,7 @@ static void unregister_prot_hook(struct sock *sk, bool sync) | |||
378 | __unregister_prot_hook(sk, sync); | 378 | __unregister_prot_hook(sk, sync); |
379 | } | 379 | } |
380 | 380 | ||
381 | static inline __pure struct page *pgv_to_page(void *addr) | 381 | static inline struct page * __pure pgv_to_page(void *addr) |
382 | { | 382 | { |
383 | if (is_vmalloc_addr(addr)) | 383 | if (is_vmalloc_addr(addr)) |
384 | return vmalloc_to_page(addr); | 384 | return vmalloc_to_page(addr); |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index 3f959c681885..f9c052d508f0 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -1019,17 +1019,12 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1019 | xid = *p++; | 1019 | xid = *p++; |
1020 | calldir = *p; | 1020 | calldir = *p; |
1021 | 1021 | ||
1022 | if (bc_xprt) | 1022 | if (!bc_xprt) |
1023 | req = xprt_lookup_rqst(bc_xprt, xid); | ||
1024 | |||
1025 | if (!req) { | ||
1026 | printk(KERN_NOTICE | ||
1027 | "%s: Got unrecognized reply: " | ||
1028 | "calldir 0x%x xpt_bc_xprt %p xid %08x\n", | ||
1029 | __func__, ntohl(calldir), | ||
1030 | bc_xprt, ntohl(xid)); | ||
1031 | return -EAGAIN; | 1023 | return -EAGAIN; |
1032 | } | 1024 | spin_lock_bh(&bc_xprt->transport_lock); |
1025 | req = xprt_lookup_rqst(bc_xprt, xid); | ||
1026 | if (!req) | ||
1027 | goto unlock_notfound; | ||
1033 | 1028 | ||
1034 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); | 1029 | memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf)); |
1035 | /* | 1030 | /* |
@@ -1040,11 +1035,21 @@ static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp) | |||
1040 | dst = &req->rq_private_buf.head[0]; | 1035 | dst = &req->rq_private_buf.head[0]; |
1041 | src = &rqstp->rq_arg.head[0]; | 1036 | src = &rqstp->rq_arg.head[0]; |
1042 | if (dst->iov_len < src->iov_len) | 1037 | if (dst->iov_len < src->iov_len) |
1043 | return -EAGAIN; /* whatever; just giving up. */ | 1038 | goto unlock_eagain; /* whatever; just giving up. */ |
1044 | memcpy(dst->iov_base, src->iov_base, src->iov_len); | 1039 | memcpy(dst->iov_base, src->iov_base, src->iov_len); |
1045 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); | 1040 | xprt_complete_rqst(req->rq_task, rqstp->rq_arg.len); |
1046 | rqstp->rq_arg.len = 0; | 1041 | rqstp->rq_arg.len = 0; |
1042 | spin_unlock_bh(&bc_xprt->transport_lock); | ||
1047 | return 0; | 1043 | return 0; |
1044 | unlock_notfound: | ||
1045 | printk(KERN_NOTICE | ||
1046 | "%s: Got unrecognized reply: " | ||
1047 | "calldir 0x%x xpt_bc_xprt %p xid %08x\n", | ||
1048 | __func__, ntohl(calldir), | ||
1049 | bc_xprt, ntohl(xid)); | ||
1050 | unlock_eagain: | ||
1051 | spin_unlock_bh(&bc_xprt->transport_lock); | ||
1052 | return -EAGAIN; | ||
1048 | } | 1053 | } |
1049 | 1054 | ||
1050 | static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) | 1055 | static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len) |
diff --git a/security/keys/internal.h b/security/keys/internal.h index b8960c4959a5..200e37867336 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -117,6 +117,7 @@ struct keyring_search_context { | |||
117 | #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ | 117 | #define KEYRING_SEARCH_NO_UPDATE_TIME 0x0004 /* Don't update times */ |
118 | #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ | 118 | #define KEYRING_SEARCH_NO_CHECK_PERM 0x0008 /* Don't check permissions */ |
119 | #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ | 119 | #define KEYRING_SEARCH_DETECT_TOO_DEEP 0x0010 /* Give an error on excessive depth */ |
120 | #define KEYRING_SEARCH_SKIP_EXPIRED 0x0020 /* Ignore expired keys (intention to replace) */ | ||
120 | 121 | ||
121 | int (*iterator)(const void *object, void *iterator_data); | 122 | int (*iterator)(const void *object, void *iterator_data); |
122 | 123 | ||
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index eff88a5f5d40..4743d71e4aa6 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -26,6 +26,8 @@ | |||
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | #include "internal.h" | 27 | #include "internal.h" |
28 | 28 | ||
29 | #define KEY_MAX_DESC_SIZE 4096 | ||
30 | |||
29 | static int key_get_type_from_user(char *type, | 31 | static int key_get_type_from_user(char *type, |
30 | const char __user *_type, | 32 | const char __user *_type, |
31 | unsigned len) | 33 | unsigned len) |
@@ -78,7 +80,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
78 | 80 | ||
79 | description = NULL; | 81 | description = NULL; |
80 | if (_description) { | 82 | if (_description) { |
81 | description = strndup_user(_description, PAGE_SIZE); | 83 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
82 | if (IS_ERR(description)) { | 84 | if (IS_ERR(description)) { |
83 | ret = PTR_ERR(description); | 85 | ret = PTR_ERR(description); |
84 | goto error; | 86 | goto error; |
@@ -177,7 +179,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
177 | goto error; | 179 | goto error; |
178 | 180 | ||
179 | /* pull the description into kernel space */ | 181 | /* pull the description into kernel space */ |
180 | description = strndup_user(_description, PAGE_SIZE); | 182 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
181 | if (IS_ERR(description)) { | 183 | if (IS_ERR(description)) { |
182 | ret = PTR_ERR(description); | 184 | ret = PTR_ERR(description); |
183 | goto error; | 185 | goto error; |
@@ -287,7 +289,7 @@ long keyctl_join_session_keyring(const char __user *_name) | |||
287 | /* fetch the name from userspace */ | 289 | /* fetch the name from userspace */ |
288 | name = NULL; | 290 | name = NULL; |
289 | if (_name) { | 291 | if (_name) { |
290 | name = strndup_user(_name, PAGE_SIZE); | 292 | name = strndup_user(_name, KEY_MAX_DESC_SIZE); |
291 | if (IS_ERR(name)) { | 293 | if (IS_ERR(name)) { |
292 | ret = PTR_ERR(name); | 294 | ret = PTR_ERR(name); |
293 | goto error; | 295 | goto error; |
@@ -562,8 +564,9 @@ long keyctl_describe_key(key_serial_t keyid, | |||
562 | { | 564 | { |
563 | struct key *key, *instkey; | 565 | struct key *key, *instkey; |
564 | key_ref_t key_ref; | 566 | key_ref_t key_ref; |
565 | char *tmpbuf; | 567 | char *infobuf; |
566 | long ret; | 568 | long ret; |
569 | int desclen, infolen; | ||
567 | 570 | ||
568 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); | 571 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_NEED_VIEW); |
569 | if (IS_ERR(key_ref)) { | 572 | if (IS_ERR(key_ref)) { |
@@ -586,38 +589,31 @@ long keyctl_describe_key(key_serial_t keyid, | |||
586 | } | 589 | } |
587 | 590 | ||
588 | okay: | 591 | okay: |
589 | /* calculate how much description we're going to return */ | ||
590 | ret = -ENOMEM; | ||
591 | tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
592 | if (!tmpbuf) | ||
593 | goto error2; | ||
594 | |||
595 | key = key_ref_to_ptr(key_ref); | 592 | key = key_ref_to_ptr(key_ref); |
593 | desclen = strlen(key->description); | ||
596 | 594 | ||
597 | ret = snprintf(tmpbuf, PAGE_SIZE - 1, | 595 | /* calculate how much information we're going to return */ |
598 | "%s;%d;%d;%08x;%s", | 596 | ret = -ENOMEM; |
599 | key->type->name, | 597 | infobuf = kasprintf(GFP_KERNEL, |
600 | from_kuid_munged(current_user_ns(), key->uid), | 598 | "%s;%d;%d;%08x;", |
601 | from_kgid_munged(current_user_ns(), key->gid), | 599 | key->type->name, |
602 | key->perm, | 600 | from_kuid_munged(current_user_ns(), key->uid), |
603 | key->description ?: ""); | 601 | from_kgid_munged(current_user_ns(), key->gid), |
604 | 602 | key->perm); | |
605 | /* include a NUL char at the end of the data */ | 603 | if (!infobuf) |
606 | if (ret > PAGE_SIZE - 1) | 604 | goto error2; |
607 | ret = PAGE_SIZE - 1; | 605 | infolen = strlen(infobuf); |
608 | tmpbuf[ret] = 0; | 606 | ret = infolen + desclen + 1; |
609 | ret++; | ||
610 | 607 | ||
611 | /* consider returning the data */ | 608 | /* consider returning the data */ |
612 | if (buffer && buflen > 0) { | 609 | if (buffer && buflen >= ret) { |
613 | if (buflen > ret) | 610 | if (copy_to_user(buffer, infobuf, infolen) != 0 || |
614 | buflen = ret; | 611 | copy_to_user(buffer + infolen, key->description, |
615 | 612 | desclen + 1) != 0) | |
616 | if (copy_to_user(buffer, tmpbuf, buflen) != 0) | ||
617 | ret = -EFAULT; | 613 | ret = -EFAULT; |
618 | } | 614 | } |
619 | 615 | ||
620 | kfree(tmpbuf); | 616 | kfree(infobuf); |
621 | error2: | 617 | error2: |
622 | key_ref_put(key_ref); | 618 | key_ref_put(key_ref); |
623 | error: | 619 | error: |
@@ -649,7 +645,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
649 | if (ret < 0) | 645 | if (ret < 0) |
650 | goto error; | 646 | goto error; |
651 | 647 | ||
652 | description = strndup_user(_description, PAGE_SIZE); | 648 | description = strndup_user(_description, KEY_MAX_DESC_SIZE); |
653 | if (IS_ERR(description)) { | 649 | if (IS_ERR(description)) { |
654 | ret = PTR_ERR(description); | 650 | ret = PTR_ERR(description); |
655 | goto error; | 651 | goto error; |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 8177010174f7..e72548b5897e 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -546,7 +546,8 @@ static int keyring_search_iterator(const void *object, void *iterator_data) | |||
546 | } | 546 | } |
547 | 547 | ||
548 | if (key->expiry && ctx->now.tv_sec >= key->expiry) { | 548 | if (key->expiry && ctx->now.tv_sec >= key->expiry) { |
549 | ctx->result = ERR_PTR(-EKEYEXPIRED); | 549 | if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) |
550 | ctx->result = ERR_PTR(-EKEYEXPIRED); | ||
550 | kleave(" = %d [expire]", ctx->skipped_ret); | 551 | kleave(" = %d [expire]", ctx->skipped_ret); |
551 | goto skipped; | 552 | goto skipped; |
552 | } | 553 | } |
@@ -628,6 +629,10 @@ static bool search_nested_keyrings(struct key *keyring, | |||
628 | ctx->index_key.type->name, | 629 | ctx->index_key.type->name, |
629 | ctx->index_key.description); | 630 | ctx->index_key.description); |
630 | 631 | ||
632 | #define STATE_CHECKS (KEYRING_SEARCH_NO_STATE_CHECK | KEYRING_SEARCH_DO_STATE_CHECK) | ||
633 | BUG_ON((ctx->flags & STATE_CHECKS) == 0 || | ||
634 | (ctx->flags & STATE_CHECKS) == STATE_CHECKS); | ||
635 | |||
631 | if (ctx->index_key.description) | 636 | if (ctx->index_key.description) |
632 | ctx->index_key.desc_len = strlen(ctx->index_key.description); | 637 | ctx->index_key.desc_len = strlen(ctx->index_key.description); |
633 | 638 | ||
@@ -637,7 +642,6 @@ static bool search_nested_keyrings(struct key *keyring, | |||
637 | if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE || | 642 | if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE || |
638 | keyring_compare_object(keyring, &ctx->index_key)) { | 643 | keyring_compare_object(keyring, &ctx->index_key)) { |
639 | ctx->skipped_ret = 2; | 644 | ctx->skipped_ret = 2; |
640 | ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK; | ||
641 | switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { | 645 | switch (ctx->iterator(keyring_key_to_ptr(keyring), ctx)) { |
642 | case 1: | 646 | case 1: |
643 | goto found; | 647 | goto found; |
@@ -649,8 +653,6 @@ static bool search_nested_keyrings(struct key *keyring, | |||
649 | } | 653 | } |
650 | 654 | ||
651 | ctx->skipped_ret = 0; | 655 | ctx->skipped_ret = 0; |
652 | if (ctx->flags & KEYRING_SEARCH_NO_STATE_CHECK) | ||
653 | ctx->flags &= ~KEYRING_SEARCH_DO_STATE_CHECK; | ||
654 | 656 | ||
655 | /* Start processing a new keyring */ | 657 | /* Start processing a new keyring */ |
656 | descend_to_keyring: | 658 | descend_to_keyring: |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index bb4337c7ae1b..0c7aea4dea54 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -516,6 +516,8 @@ struct key *request_key_and_link(struct key_type *type, | |||
516 | .match_data.cmp = key_default_cmp, | 516 | .match_data.cmp = key_default_cmp, |
517 | .match_data.raw_data = description, | 517 | .match_data.raw_data = description, |
518 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 518 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
519 | .flags = (KEYRING_SEARCH_DO_STATE_CHECK | | ||
520 | KEYRING_SEARCH_SKIP_EXPIRED), | ||
519 | }; | 521 | }; |
520 | struct key *key; | 522 | struct key *key; |
521 | key_ref_t key_ref; | 523 | key_ref_t key_ref; |
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index 6639e2cb8853..5d672f7580dd 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -249,6 +249,7 @@ struct key *key_get_instantiation_authkey(key_serial_t target_id) | |||
249 | .match_data.cmp = key_default_cmp, | 249 | .match_data.cmp = key_default_cmp, |
250 | .match_data.raw_data = description, | 250 | .match_data.raw_data = description, |
251 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, | 251 | .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT, |
252 | .flags = KEYRING_SEARCH_DO_STATE_CHECK, | ||
252 | }; | 253 | }; |
253 | struct key *authkey; | 254 | struct key *authkey; |
254 | key_ref_t authkey_ref; | 255 | key_ref_t authkey_ref; |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 42ded997b223..c6ff94ab1ad6 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -216,6 +216,8 @@ static char *snd_pcm_format_names[] = { | |||
216 | FORMAT(DSD_U8), | 216 | FORMAT(DSD_U8), |
217 | FORMAT(DSD_U16_LE), | 217 | FORMAT(DSD_U16_LE), |
218 | FORMAT(DSD_U32_LE), | 218 | FORMAT(DSD_U32_LE), |
219 | FORMAT(DSD_U16_BE), | ||
220 | FORMAT(DSD_U32_BE), | ||
219 | }; | 221 | }; |
220 | 222 | ||
221 | const char *snd_pcm_format_name(snd_pcm_format_t format) | 223 | const char *snd_pcm_format_name(snd_pcm_format_t format) |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index ae7a0feb3b76..ebe8444de6c6 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -152,6 +152,14 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { | |||
152 | .width = 32, .phys = 32, .le = 1, .signd = 0, | 152 | .width = 32, .phys = 32, .le = 1, .signd = 0, |
153 | .silence = { 0x69, 0x69, 0x69, 0x69 }, | 153 | .silence = { 0x69, 0x69, 0x69, 0x69 }, |
154 | }, | 154 | }, |
155 | [SNDRV_PCM_FORMAT_DSD_U16_BE] = { | ||
156 | .width = 16, .phys = 16, .le = 0, .signd = 0, | ||
157 | .silence = { 0x69, 0x69 }, | ||
158 | }, | ||
159 | [SNDRV_PCM_FORMAT_DSD_U32_BE] = { | ||
160 | .width = 32, .phys = 32, .le = 0, .signd = 0, | ||
161 | .silence = { 0x69, 0x69, 0x69, 0x69 }, | ||
162 | }, | ||
155 | /* FIXME: the following three formats are not defined properly yet */ | 163 | /* FIXME: the following three formats are not defined properly yet */ |
156 | [SNDRV_PCM_FORMAT_MPEG] = { | 164 | [SNDRV_PCM_FORMAT_MPEG] = { |
157 | .le = -1, .signd = -1, | 165 | .le = -1, .signd = -1, |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 16660f312043..48b6c5a3884f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -298,7 +298,8 @@ enum { | |||
298 | 298 | ||
299 | /* quirks for ATI/AMD HDMI */ | 299 | /* quirks for ATI/AMD HDMI */ |
300 | #define AZX_DCAPS_PRESET_ATI_HDMI \ | 300 | #define AZX_DCAPS_PRESET_ATI_HDMI \ |
301 | (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB) | 301 | (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\ |
302 | AZX_DCAPS_NO_MSI64) | ||
302 | 303 | ||
303 | /* quirks for Nvidia */ | 304 | /* quirks for Nvidia */ |
304 | #define AZX_DCAPS_PRESET_NVIDIA \ | 305 | #define AZX_DCAPS_PRESET_NVIDIA \ |
@@ -1486,6 +1487,7 @@ static int azx_first_init(struct azx *chip) | |||
1486 | struct snd_card *card = chip->card; | 1487 | struct snd_card *card = chip->card; |
1487 | int err; | 1488 | int err; |
1488 | unsigned short gcap; | 1489 | unsigned short gcap; |
1490 | unsigned int dma_bits = 64; | ||
1489 | 1491 | ||
1490 | #if BITS_PER_LONG != 64 | 1492 | #if BITS_PER_LONG != 64 |
1491 | /* Fix up base address on ULI M5461 */ | 1493 | /* Fix up base address on ULI M5461 */ |
@@ -1509,9 +1511,14 @@ static int azx_first_init(struct azx *chip) | |||
1509 | return -ENXIO; | 1511 | return -ENXIO; |
1510 | } | 1512 | } |
1511 | 1513 | ||
1512 | if (chip->msi) | 1514 | if (chip->msi) { |
1515 | if (chip->driver_caps & AZX_DCAPS_NO_MSI64) { | ||
1516 | dev_dbg(card->dev, "Disabling 64bit MSI\n"); | ||
1517 | pci->no_64bit_msi = true; | ||
1518 | } | ||
1513 | if (pci_enable_msi(pci) < 0) | 1519 | if (pci_enable_msi(pci) < 0) |
1514 | chip->msi = 0; | 1520 | chip->msi = 0; |
1521 | } | ||
1515 | 1522 | ||
1516 | if (azx_acquire_irq(chip, 0) < 0) | 1523 | if (azx_acquire_irq(chip, 0) < 0) |
1517 | return -EBUSY; | 1524 | return -EBUSY; |
@@ -1522,9 +1529,14 @@ static int azx_first_init(struct azx *chip) | |||
1522 | gcap = azx_readw(chip, GCAP); | 1529 | gcap = azx_readw(chip, GCAP); |
1523 | dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); | 1530 | dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); |
1524 | 1531 | ||
1532 | /* AMD devices support 40 or 48bit DMA, take the safe one */ | ||
1533 | if (chip->pci->vendor == PCI_VENDOR_ID_AMD) | ||
1534 | dma_bits = 40; | ||
1535 | |||
1525 | /* disable SB600 64bit support for safety */ | 1536 | /* disable SB600 64bit support for safety */ |
1526 | if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { | 1537 | if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { |
1527 | struct pci_dev *p_smbus; | 1538 | struct pci_dev *p_smbus; |
1539 | dma_bits = 40; | ||
1528 | p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, | 1540 | p_smbus = pci_get_device(PCI_VENDOR_ID_ATI, |
1529 | PCI_DEVICE_ID_ATI_SBX00_SMBUS, | 1541 | PCI_DEVICE_ID_ATI_SBX00_SMBUS, |
1530 | NULL); | 1542 | NULL); |
@@ -1554,9 +1566,11 @@ static int azx_first_init(struct azx *chip) | |||
1554 | } | 1566 | } |
1555 | 1567 | ||
1556 | /* allow 64bit DMA address if supported by H/W */ | 1568 | /* allow 64bit DMA address if supported by H/W */ |
1557 | if ((gcap & AZX_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) | 1569 | if (!(gcap & AZX_GCAP_64OK)) |
1558 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); | 1570 | dma_bits = 32; |
1559 | else { | 1571 | if (!pci_set_dma_mask(pci, DMA_BIT_MASK(dma_bits))) { |
1572 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(dma_bits)); | ||
1573 | } else { | ||
1560 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); | 1574 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); |
1561 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); | 1575 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)); |
1562 | } | 1576 | } |
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h index 949cd437eeb2..5016014e57f2 100644 --- a/sound/pci/hda/hda_priv.h +++ b/sound/pci/hda/hda_priv.h | |||
@@ -171,6 +171,7 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
171 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ | 171 | #define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ |
172 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ | 172 | #define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ |
173 | #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ | 173 | #define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ |
174 | #define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */ | ||
174 | 175 | ||
175 | /* HD Audio class code */ | 176 | /* HD Audio class code */ |
176 | #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 | 177 | #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8fea1b86df25..b118a5be18df 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -4790,6 +4790,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4790 | SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), | 4790 | SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), |
4791 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4791 | SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4792 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4792 | SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4793 | SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4794 | SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4793 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4795 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4794 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 4796 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
4795 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), | 4797 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), |
@@ -4818,7 +4820,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4818 | SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4820 | SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4819 | SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4821 | SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4820 | SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4822 | SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4821 | SND_PCI_QUIRK(0x103c, 0x2246, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | ||
4822 | SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4823 | SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4823 | SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4824 | SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
4824 | SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), | 4825 | SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED), |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index d88edfced8c4..865e090c8061 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -1,10 +1,14 @@ | |||
1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o | 1 | snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o |
2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o | 2 | snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o |
3 | 3 | ||
4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) | 4 | ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) |
5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o | 5 | snd-soc-core-objs += soc-generic-dmaengine-pcm.o |
6 | endif | 6 | endif |
7 | 7 | ||
8 | ifneq ($(CONFIG_SND_SOC_AC97_BUS),) | ||
9 | snd-soc-core-objs += soc-ac97.o | ||
10 | endif | ||
11 | |||
8 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o | 12 | obj-$(CONFIG_SND_SOC) += snd-soc-core.o |
9 | obj-$(CONFIG_SND_SOC) += codecs/ | 13 | obj-$(CONFIG_SND_SOC) += codecs/ |
10 | obj-$(CONFIG_SND_SOC) += generic/ | 14 | obj-$(CONFIG_SND_SOC) += generic/ |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 27e3fc4a536b..fb3878312bf8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -52,12 +52,3 @@ config SND_AT91_SOC_SAM9X5_WM8731 | |||
52 | help | 52 | help |
53 | Say Y if you want to add support for audio SoC on an | 53 | Say Y if you want to add support for audio SoC on an |
54 | at91sam9x5 based board that is using WM8731 codec. | 54 | at91sam9x5 based board that is using WM8731 codec. |
55 | |||
56 | config SND_AT91_SOC_AFEB9260 | ||
57 | tristate "SoC Audio support for AFEB9260 board" | ||
58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC | ||
59 | select SND_ATMEL_SOC_PDC | ||
60 | select SND_ATMEL_SOC_SSC | ||
61 | select SND_SOC_TLV320AIC23_I2C | ||
62 | help | ||
63 | Say Y here to support sound on AFEB9260 board. | ||
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile index 5baabc8bde3a..466a821da98c 100644 --- a/sound/soc/atmel/Makefile +++ b/sound/soc/atmel/Makefile | |||
@@ -17,4 +17,3 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o | |||
17 | obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o | 17 | obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o |
18 | obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o | 18 | obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o |
19 | obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o | 19 | obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o |
20 | obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o | ||
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index f403f399808a..b1cc2a4a7fc0 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
310 | * transmit and receive, so if a value has already | 310 | * transmit and receive, so if a value has already |
311 | * been set, it must match this value. | 311 | * been set, it must match this value. |
312 | */ | 312 | */ |
313 | if (ssc_p->cmr_div == 0) | 313 | if (ssc_p->dir_mask != |
314 | (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE)) | ||
315 | ssc_p->cmr_div = div; | ||
316 | else if (ssc_p->cmr_div == 0) | ||
314 | ssc_p->cmr_div = div; | 317 | ssc_p->cmr_div = div; |
315 | else | 318 | else |
316 | if (div != ssc_p->cmr_div) | 319 | if (div != ssc_p->cmr_div) |
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c deleted file mode 100644 index 9579799ace54..000000000000 --- a/sound/soc/atmel/snd-soc-afeb9260.c +++ /dev/null | |||
@@ -1,151 +0,0 @@ | |||
1 | /* | ||
2 | * afeb9260.c -- SoC audio for AFEB9260 | ||
3 | * | ||
4 | * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org> | ||
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 | ||
8 | * version 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
18 | * 02110-1301 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | |||
28 | #include <linux/atmel-ssc.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/pcm_params.h> | ||
32 | #include <sound/soc.h> | ||
33 | |||
34 | #include <asm/mach-types.h> | ||
35 | #include <mach/hardware.h> | ||
36 | #include <linux/gpio.h> | ||
37 | |||
38 | #include "../codecs/tlv320aic23.h" | ||
39 | #include "atmel-pcm.h" | ||
40 | #include "atmel_ssc_dai.h" | ||
41 | |||
42 | #define CODEC_CLOCK 12000000 | ||
43 | |||
44 | static int afeb9260_hw_params(struct snd_pcm_substream *substream, | ||
45 | struct snd_pcm_hw_params *params) | ||
46 | { | ||
47 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
49 | int err; | ||
50 | |||
51 | /* Set the codec system clock for DAC and ADC */ | ||
52 | err = | ||
53 | snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
54 | |||
55 | if (err < 0) { | ||
56 | printk(KERN_ERR "can't set codec system clock\n"); | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | return err; | ||
61 | } | ||
62 | |||
63 | static struct snd_soc_ops afeb9260_ops = { | ||
64 | .hw_params = afeb9260_hw_params, | ||
65 | }; | ||
66 | |||
67 | static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = { | ||
68 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
69 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
70 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
71 | }; | ||
72 | |||
73 | static const struct snd_soc_dapm_route afeb9260_audio_map[] = { | ||
74 | {"Headphone Jack", NULL, "LHPOUT"}, | ||
75 | {"Headphone Jack", NULL, "RHPOUT"}, | ||
76 | |||
77 | {"LLINEIN", NULL, "Line In"}, | ||
78 | {"RLINEIN", NULL, "Line In"}, | ||
79 | |||
80 | {"MICIN", NULL, "Mic Jack"}, | ||
81 | }; | ||
82 | |||
83 | |||
84 | /* Digital audio interface glue - connects codec <--> CPU */ | ||
85 | static struct snd_soc_dai_link afeb9260_dai = { | ||
86 | .name = "TLV320AIC23", | ||
87 | .stream_name = "AIC23", | ||
88 | .cpu_dai_name = "atmel-ssc-dai.0", | ||
89 | .codec_dai_name = "tlv320aic23-hifi", | ||
90 | .platform_name = "atmel_pcm-audio", | ||
91 | .codec_name = "tlv320aic23-codec.0-001a", | ||
92 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF | | ||
93 | SND_SOC_DAIFMT_CBM_CFM, | ||
94 | .ops = &afeb9260_ops, | ||
95 | }; | ||
96 | |||
97 | /* Audio machine driver */ | ||
98 | static struct snd_soc_card snd_soc_machine_afeb9260 = { | ||
99 | .name = "AFEB9260", | ||
100 | .owner = THIS_MODULE, | ||
101 | .dai_link = &afeb9260_dai, | ||
102 | .num_links = 1, | ||
103 | |||
104 | .dapm_widgets = tlv320aic23_dapm_widgets, | ||
105 | .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), | ||
106 | .dapm_routes = afeb9260_audio_map, | ||
107 | .num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map), | ||
108 | }; | ||
109 | |||
110 | static struct platform_device *afeb9260_snd_device; | ||
111 | |||
112 | static int __init afeb9260_soc_init(void) | ||
113 | { | ||
114 | int err; | ||
115 | struct device *dev; | ||
116 | |||
117 | if (!(machine_is_afeb9260())) | ||
118 | return -ENODEV; | ||
119 | |||
120 | |||
121 | afeb9260_snd_device = platform_device_alloc("soc-audio", -1); | ||
122 | if (!afeb9260_snd_device) { | ||
123 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | |||
127 | platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260); | ||
128 | err = platform_device_add(afeb9260_snd_device); | ||
129 | if (err) | ||
130 | goto err1; | ||
131 | |||
132 | dev = &afeb9260_snd_device->dev; | ||
133 | |||
134 | return 0; | ||
135 | err1: | ||
136 | platform_device_put(afeb9260_snd_device); | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | static void __exit afeb9260_soc_exit(void) | ||
141 | { | ||
142 | platform_device_unregister(afeb9260_snd_device); | ||
143 | } | ||
144 | |||
145 | module_init(afeb9260_soc_init); | ||
146 | module_exit(afeb9260_soc_exit); | ||
147 | |||
148 | MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>"); | ||
149 | MODULE_DESCRIPTION("ALSA SoC for AFEB9260"); | ||
150 | MODULE_LICENSE("GPL"); | ||
151 | |||
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c index c8a2de103c5f..5159a50a45a6 100644 --- a/sound/soc/au1x/ac97c.c +++ b/sound/soc/au1x/ac97c.c | |||
@@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai) | |||
205 | 205 | ||
206 | static struct snd_soc_dai_driver au1xac97c_dai_driver = { | 206 | static struct snd_soc_dai_driver au1xac97c_dai_driver = { |
207 | .name = "alchemy-ac97c", | 207 | .name = "alchemy-ac97c", |
208 | .ac97_control = 1, | 208 | .bus_control = true, |
209 | .probe = au1xac97c_dai_probe, | 209 | .probe = au1xac97c_dai_probe, |
210 | .playback = { | 210 | .playback = { |
211 | .rates = AC97_RATES, | 211 | .rates = AC97_RATES, |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 84f31e1f9d24..c6daec98ff89 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = { | |||
343 | }; | 343 | }; |
344 | 344 | ||
345 | static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { | 345 | static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = { |
346 | .ac97_control = 1, | 346 | .bus_control = true, |
347 | .probe = au1xpsc_ac97_probe, | 347 | .probe = au1xpsc_ac97_probe, |
348 | .playback = { | 348 | .playback = { |
349 | .rates = AC97_RATES, | 349 | .rates = AC97_RATES, |
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index e82eb373a731..6bf21a6c02e4 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) | |||
260 | #endif | 260 | #endif |
261 | 261 | ||
262 | static struct snd_soc_dai_driver bfin_ac97_dai = { | 262 | static struct snd_soc_dai_driver bfin_ac97_dai = { |
263 | .ac97_control = 1, | 263 | .bus_control = true, |
264 | .suspend = bf5xx_ac97_suspend, | 264 | .suspend = bf5xx_ac97_suspend, |
265 | .resume = bf5xx_ac97_resume, | 265 | .resume = bf5xx_ac97_resume, |
266 | .playback = { | 266 | .playback = { |
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c index 3450e8f9080d..0fa81a523b8a 100644 --- a/sound/soc/blackfin/bf5xx-ad1980.c +++ b/sound/soc/blackfin/bf5xx-ad1980.c | |||
@@ -46,8 +46,6 @@ | |||
46 | #include <linux/gpio.h> | 46 | #include <linux/gpio.h> |
47 | #include <asm/portmux.h> | 47 | #include <asm/portmux.h> |
48 | 48 | ||
49 | #include "../codecs/ad1980.h" | ||
50 | |||
51 | #include "bf5xx-ac97.h" | 49 | #include "bf5xx-ac97.h" |
52 | 50 | ||
53 | static struct snd_soc_card bf5xx_board; | 51 | static struct snd_soc_card bf5xx_board; |
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 5477c5475923..7b7fbcd49e5e 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig | |||
@@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX | |||
36 | tristate "SoC Audio support for Cirrus Logic EDB93xx boards" | 36 | tristate "SoC Audio support for Cirrus Logic EDB93xx boards" |
37 | depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) | 37 | depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) |
38 | select SND_EP93XX_SOC_I2S | 38 | select SND_EP93XX_SOC_I2S |
39 | select SND_SOC_CS4271 | 39 | select SND_SOC_CS4271_I2C if I2C |
40 | select SND_SOC_CS4271_SPI if SPI_MASTER | ||
40 | help | 41 | help |
41 | Say Y or M here if you want to add support for I2S audio on the | 42 | Say Y or M here if you want to add support for I2S audio on the |
42 | Cirrus Logic EDB93xx boards. | 43 | Cirrus Logic EDB93xx boards. |
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c index f30dadf85b99..6b8a366b0211 100644 --- a/sound/soc/cirrus/ep93xx-ac97.c +++ b/sound/soc/cirrus/ep93xx-ac97.c | |||
@@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = { | |||
338 | static struct snd_soc_dai_driver ep93xx_ac97_dai = { | 338 | static struct snd_soc_dai_driver ep93xx_ac97_dai = { |
339 | .name = "ep93xx-ac97", | 339 | .name = "ep93xx-ac97", |
340 | .id = 0, | 340 | .id = 0, |
341 | .ac97_control = 1, | 341 | .bus_control = true, |
342 | .probe = ep93xx_ac97_dai_probe, | 342 | .probe = ep93xx_ac97_dai_probe, |
343 | .playback = { | 343 | .playback = { |
344 | .stream_name = "AC97 Playback", | 344 | .stream_name = "AC97 Playback", |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index a68d1731a8fd..883c5778b309 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS | |||
50 | select SND_SOC_CS42L73 if I2C | 50 | select SND_SOC_CS42L73 if I2C |
51 | select SND_SOC_CS4265 if I2C | 51 | select SND_SOC_CS4265 if I2C |
52 | select SND_SOC_CS4270 if I2C | 52 | select SND_SOC_CS4270 if I2C |
53 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI | 53 | select SND_SOC_CS4271_I2C if I2C |
54 | select SND_SOC_CS4271_SPI if SPI_MASTER | ||
54 | select SND_SOC_CS42XX8_I2C if I2C | 55 | select SND_SOC_CS42XX8_I2C if I2C |
55 | select SND_SOC_CX20442 if TTY | 56 | select SND_SOC_CX20442 if TTY |
56 | select SND_SOC_DA7210 if I2C | 57 | select SND_SOC_DA7210 if I2C |
@@ -85,7 +86,7 @@ config SND_SOC_ALL_CODECS | |||
85 | select SND_SOC_RT5645 if I2C | 86 | select SND_SOC_RT5645 if I2C |
86 | select SND_SOC_RT5651 if I2C | 87 | select SND_SOC_RT5651 if I2C |
87 | select SND_SOC_RT5670 if I2C | 88 | select SND_SOC_RT5670 if I2C |
88 | select SND_SOC_RT5677 if I2C | 89 | select SND_SOC_RT5677 if I2C && SPI_MASTER |
89 | select SND_SOC_SGTL5000 if I2C | 90 | select SND_SOC_SGTL5000 if I2C |
90 | select SND_SOC_SI476X if MFD_SI476X_CORE | 91 | select SND_SOC_SI476X if MFD_SI476X_CORE |
91 | select SND_SOC_SIRF_AUDIO_CODEC | 92 | select SND_SOC_SIRF_AUDIO_CODEC |
@@ -101,6 +102,7 @@ config SND_SOC_ALL_CODECS | |||
101 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 102 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
102 | select SND_SOC_TAS2552 if I2C | 103 | select SND_SOC_TAS2552 if I2C |
103 | select SND_SOC_TAS5086 if I2C | 104 | select SND_SOC_TAS5086 if I2C |
105 | select SND_SOC_TFA9879 if I2C | ||
104 | select SND_SOC_TLV320AIC23_I2C if I2C | 106 | select SND_SOC_TLV320AIC23_I2C if I2C |
105 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | 107 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER |
106 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 108 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
@@ -109,6 +111,7 @@ config SND_SOC_ALL_CODECS | |||
109 | select SND_SOC_TLV320AIC3X if I2C | 111 | select SND_SOC_TLV320AIC3X if I2C |
110 | select SND_SOC_TPA6130A2 if I2C | 112 | select SND_SOC_TPA6130A2 if I2C |
111 | select SND_SOC_TLV320DAC33 if I2C | 113 | select SND_SOC_TLV320DAC33 if I2C |
114 | select SND_SOC_TS3A227E if I2C | ||
112 | select SND_SOC_TWL4030 if TWL4030_CORE | 115 | select SND_SOC_TWL4030 if TWL4030_CORE |
113 | select SND_SOC_TWL6040 if TWL6040_CORE | 116 | select SND_SOC_TWL6040 if TWL6040_CORE |
114 | select SND_SOC_UDA134X | 117 | select SND_SOC_UDA134X |
@@ -223,6 +226,7 @@ config SND_SOC_AD193X_I2C | |||
223 | select SND_SOC_AD193X | 226 | select SND_SOC_AD193X |
224 | 227 | ||
225 | config SND_SOC_AD1980 | 228 | config SND_SOC_AD1980 |
229 | select REGMAP_AC97 | ||
226 | tristate | 230 | tristate |
227 | 231 | ||
228 | config SND_SOC_AD73311 | 232 | config SND_SOC_AD73311 |
@@ -336,7 +340,8 @@ config SND_SOC_CS42L51 | |||
336 | tristate | 340 | tristate |
337 | 341 | ||
338 | config SND_SOC_CS42L51_I2C | 342 | config SND_SOC_CS42L51_I2C |
339 | tristate | 343 | tristate "Cirrus Logic CS42L51 CODEC (I2C)" |
344 | depends on I2C | ||
340 | select SND_SOC_CS42L51 | 345 | select SND_SOC_CS42L51 |
341 | 346 | ||
342 | config SND_SOC_CS42L52 | 347 | config SND_SOC_CS42L52 |
@@ -370,8 +375,19 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
370 | depends on SND_SOC_CS4270 | 375 | depends on SND_SOC_CS4270 |
371 | 376 | ||
372 | config SND_SOC_CS4271 | 377 | config SND_SOC_CS4271 |
373 | tristate "Cirrus Logic CS4271 CODEC" | 378 | tristate |
374 | depends on SND_SOC_I2C_AND_SPI | 379 | |
380 | config SND_SOC_CS4271_I2C | ||
381 | tristate "Cirrus Logic CS4271 CODEC (I2C)" | ||
382 | depends on I2C | ||
383 | select SND_SOC_CS4271 | ||
384 | select REGMAP_I2C | ||
385 | |||
386 | config SND_SOC_CS4271_SPI | ||
387 | tristate "Cirrus Logic CS4271 CODEC (SPI)" | ||
388 | depends on SPI_MASTER | ||
389 | select SND_SOC_CS4271 | ||
390 | select REGMAP_SPI | ||
375 | 391 | ||
376 | config SND_SOC_CS42XX8 | 392 | config SND_SOC_CS42XX8 |
377 | tristate | 393 | tristate |
@@ -487,7 +503,8 @@ config SND_SOC_RT286 | |||
487 | depends on I2C | 503 | depends on I2C |
488 | 504 | ||
489 | config SND_SOC_RT5631 | 505 | config SND_SOC_RT5631 |
490 | tristate | 506 | tristate "Realtek ALC5631/RT5631 CODEC" |
507 | depends on I2C | ||
491 | 508 | ||
492 | config SND_SOC_RT5640 | 509 | config SND_SOC_RT5640 |
493 | tristate | 510 | tristate |
@@ -504,6 +521,10 @@ config SND_SOC_RT5670 | |||
504 | config SND_SOC_RT5677 | 521 | config SND_SOC_RT5677 |
505 | tristate | 522 | tristate |
506 | 523 | ||
524 | config SND_SOC_RT5677_SPI | ||
525 | tristate | ||
526 | default SND_SOC_RT5677 | ||
527 | |||
507 | #Freescale sgtl5000 codec | 528 | #Freescale sgtl5000 codec |
508 | config SND_SOC_SGTL5000 | 529 | config SND_SOC_SGTL5000 |
509 | tristate "Freescale SGTL5000 CODEC" | 530 | tristate "Freescale SGTL5000 CODEC" |
@@ -577,15 +598,21 @@ config SND_SOC_TAS5086 | |||
577 | tristate "Texas Instruments TAS5086 speaker amplifier" | 598 | tristate "Texas Instruments TAS5086 speaker amplifier" |
578 | depends on I2C | 599 | depends on I2C |
579 | 600 | ||
601 | config SND_SOC_TFA9879 | ||
602 | tristate "NXP Semiconductors TFA9879 amplifier" | ||
603 | depends on I2C | ||
604 | |||
580 | config SND_SOC_TLV320AIC23 | 605 | config SND_SOC_TLV320AIC23 |
581 | tristate | 606 | tristate |
582 | 607 | ||
583 | config SND_SOC_TLV320AIC23_I2C | 608 | config SND_SOC_TLV320AIC23_I2C |
584 | tristate | 609 | tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" |
610 | depends on I2C | ||
585 | select SND_SOC_TLV320AIC23 | 611 | select SND_SOC_TLV320AIC23 |
586 | 612 | ||
587 | config SND_SOC_TLV320AIC23_SPI | 613 | config SND_SOC_TLV320AIC23_SPI |
588 | tristate | 614 | tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" |
615 | depends on SPI_MASTER | ||
589 | select SND_SOC_TLV320AIC23 | 616 | select SND_SOC_TLV320AIC23 |
590 | 617 | ||
591 | config SND_SOC_TLV320AIC26 | 618 | config SND_SOC_TLV320AIC26 |
@@ -607,6 +634,10 @@ config SND_SOC_TLV320AIC3X | |||
607 | config SND_SOC_TLV320DAC33 | 634 | config SND_SOC_TLV320DAC33 |
608 | tristate | 635 | tristate |
609 | 636 | ||
637 | config SND_SOC_TS3A227E | ||
638 | tristate "TI Headset/Mic detect and keypress chip" | ||
639 | depends on I2C | ||
640 | |||
610 | config SND_SOC_TWL4030 | 641 | config SND_SOC_TWL4030 |
611 | select MFD_TWL4030_AUDIO | 642 | select MFD_TWL4030_AUDIO |
612 | tristate | 643 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 5dce451661e4..bbdfd1e1c182 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o | |||
41 | snd-soc-cs4265-objs := cs4265.o | 41 | snd-soc-cs4265-objs := cs4265.o |
42 | snd-soc-cs4270-objs := cs4270.o | 42 | snd-soc-cs4270-objs := cs4270.o |
43 | snd-soc-cs4271-objs := cs4271.o | 43 | snd-soc-cs4271-objs := cs4271.o |
44 | snd-soc-cs4271-i2c-objs := cs4271-i2c.o | ||
45 | snd-soc-cs4271-spi-objs := cs4271-spi.o | ||
44 | snd-soc-cs42xx8-objs := cs42xx8.o | 46 | snd-soc-cs42xx8-objs := cs42xx8.o |
45 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o | 47 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o |
46 | snd-soc-cx20442-objs := cx20442.o | 48 | snd-soc-cx20442-objs := cx20442.o |
@@ -80,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o | |||
80 | snd-soc-rt5651-objs := rt5651.o | 82 | snd-soc-rt5651-objs := rt5651.o |
81 | snd-soc-rt5670-objs := rt5670.o | 83 | snd-soc-rt5670-objs := rt5670.o |
82 | snd-soc-rt5677-objs := rt5677.o | 84 | snd-soc-rt5677-objs := rt5677.o |
85 | snd-soc-rt5677-spi-objs := rt5677-spi.o | ||
83 | snd-soc-sgtl5000-objs := sgtl5000.o | 86 | snd-soc-sgtl5000-objs := sgtl5000.o |
84 | snd-soc-alc5623-objs := alc5623.o | 87 | snd-soc-alc5623-objs := alc5623.o |
85 | snd-soc-alc5632-objs := alc5632.o | 88 | snd-soc-alc5632-objs := alc5632.o |
@@ -101,6 +104,7 @@ snd-soc-sta350-objs := sta350.o | |||
101 | snd-soc-sta529-objs := sta529.o | 104 | snd-soc-sta529-objs := sta529.o |
102 | snd-soc-stac9766-objs := stac9766.o | 105 | snd-soc-stac9766-objs := stac9766.o |
103 | snd-soc-tas5086-objs := tas5086.o | 106 | snd-soc-tas5086-objs := tas5086.o |
107 | snd-soc-tfa9879-objs := tfa9879.o | ||
104 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 108 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
105 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | 109 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o |
106 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | 110 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o |
@@ -109,6 +113,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o | |||
109 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 113 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
110 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 114 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
111 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 115 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
116 | snd-soc-ts3a227e-objs := ts3a227e.o | ||
112 | snd-soc-twl4030-objs := twl4030.o | 117 | snd-soc-twl4030-objs := twl4030.o |
113 | snd-soc-twl6040-objs := twl6040.o | 118 | snd-soc-twl6040-objs := twl6040.o |
114 | snd-soc-uda134x-objs := uda134x.o | 119 | snd-soc-uda134x-objs := uda134x.o |
@@ -217,6 +222,8 @@ obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o | |||
217 | obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o | 222 | obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o |
218 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 223 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
219 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o | 224 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o |
225 | obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o | ||
226 | obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o | ||
220 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o | 227 | obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o |
221 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o | 228 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o |
222 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 229 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
@@ -256,6 +263,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o | |||
256 | obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o | 263 | obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o |
257 | obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o | 264 | obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o |
258 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o | 265 | obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o |
266 | obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o | ||
259 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 267 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
260 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o | 268 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o |
261 | obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o | 269 | obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o |
@@ -274,6 +282,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | |||
274 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 282 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
275 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 283 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
276 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 284 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
285 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o | ||
277 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 286 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
278 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | 287 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o |
279 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | 288 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o |
@@ -282,6 +291,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o | |||
282 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 291 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
283 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 292 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
284 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 293 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
294 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o | ||
285 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o | 295 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o |
286 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o | 296 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o |
287 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o | 297 | obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index fd43827bb856..7dfbc9921e91 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg { | |||
126 | /* Private data for AB8500 device-driver */ | 126 | /* Private data for AB8500 device-driver */ |
127 | struct ab8500_codec_drvdata { | 127 | struct ab8500_codec_drvdata { |
128 | struct regmap *regmap; | 128 | struct regmap *regmap; |
129 | struct mutex ctrl_lock; | ||
129 | 130 | ||
130 | /* Sidetone */ | 131 | /* Sidetone */ |
131 | long *sid_fir_values; | 132 | long *sid_fir_values; |
132 | enum sid_state sid_status; | 133 | enum sid_state sid_status; |
133 | 134 | ||
134 | /* ANC */ | 135 | /* ANC */ |
135 | struct mutex anc_lock; | ||
136 | long *anc_fir_values; | 136 | long *anc_fir_values; |
137 | long *anc_iir_values; | 137 | long *anc_iir_values; |
138 | enum anc_state anc_status; | 138 | enum anc_state anc_status; |
@@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol, | |||
1129 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1129 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1130 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | 1130 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); |
1131 | 1131 | ||
1132 | mutex_lock(&codec->mutex); | 1132 | mutex_lock(&drvdata->ctrl_lock); |
1133 | ucontrol->value.integer.value[0] = drvdata->sid_status; | 1133 | ucontrol->value.integer.value[0] = drvdata->sid_status; |
1134 | mutex_unlock(&codec->mutex); | 1134 | mutex_unlock(&drvdata->ctrl_lock); |
1135 | 1135 | ||
1136 | return 0; | 1136 | return 0; |
1137 | } | 1137 | } |
@@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, | |||
1154 | return -EIO; | 1154 | return -EIO; |
1155 | } | 1155 | } |
1156 | 1156 | ||
1157 | mutex_lock(&codec->mutex); | 1157 | mutex_lock(&drvdata->ctrl_lock); |
1158 | 1158 | ||
1159 | sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); | 1159 | sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); |
1160 | if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { | 1160 | if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { |
@@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol, | |||
1185 | drvdata->sid_status = SID_FIR_CONFIGURED; | 1185 | drvdata->sid_status = SID_FIR_CONFIGURED; |
1186 | 1186 | ||
1187 | out: | 1187 | out: |
1188 | mutex_unlock(&codec->mutex); | 1188 | mutex_unlock(&drvdata->ctrl_lock); |
1189 | 1189 | ||
1190 | dev_dbg(codec->dev, "%s: Exit\n", __func__); | 1190 | dev_dbg(codec->dev, "%s: Exit\n", __func__); |
1191 | 1191 | ||
@@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol, | |||
1198 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1198 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1199 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | 1199 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); |
1200 | 1200 | ||
1201 | mutex_lock(&codec->mutex); | 1201 | mutex_lock(&drvdata->ctrl_lock); |
1202 | ucontrol->value.integer.value[0] = drvdata->anc_status; | 1202 | ucontrol->value.integer.value[0] = drvdata->anc_status; |
1203 | mutex_unlock(&codec->mutex); | 1203 | mutex_unlock(&drvdata->ctrl_lock); |
1204 | 1204 | ||
1205 | return 0; | 1205 | return 0; |
1206 | } | 1206 | } |
@@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1217 | 1217 | ||
1218 | dev_dbg(dev, "%s: Enter.\n", __func__); | 1218 | dev_dbg(dev, "%s: Enter.\n", __func__); |
1219 | 1219 | ||
1220 | mutex_lock(&drvdata->anc_lock); | 1220 | mutex_lock(&drvdata->ctrl_lock); |
1221 | 1221 | ||
1222 | req = ucontrol->value.integer.value[0]; | 1222 | req = ucontrol->value.integer.value[0]; |
1223 | if (req >= ARRAY_SIZE(enum_anc_state)) { | 1223 | if (req >= ARRAY_SIZE(enum_anc_state)) { |
@@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1244 | } | 1244 | } |
1245 | snd_soc_dapm_sync(&codec->dapm); | 1245 | snd_soc_dapm_sync(&codec->dapm); |
1246 | 1246 | ||
1247 | mutex_lock(&codec->mutex); | ||
1248 | anc_configure(codec, apply_fir, apply_iir); | 1247 | anc_configure(codec, apply_fir, apply_iir); |
1249 | mutex_unlock(&codec->mutex); | ||
1250 | 1248 | ||
1251 | if (apply_fir) { | 1249 | if (apply_fir) { |
1252 | if (drvdata->anc_status == ANC_IIR_CONFIGURED) | 1250 | if (drvdata->anc_status == ANC_IIR_CONFIGURED) |
@@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol, | |||
1265 | snd_soc_dapm_sync(&codec->dapm); | 1263 | snd_soc_dapm_sync(&codec->dapm); |
1266 | 1264 | ||
1267 | cleanup: | 1265 | cleanup: |
1268 | mutex_unlock(&drvdata->anc_lock); | 1266 | mutex_unlock(&drvdata->ctrl_lock); |
1269 | 1267 | ||
1270 | if (status < 0) | 1268 | if (status < 0) |
1271 | dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", | 1269 | dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", |
@@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol, | |||
1294 | struct snd_ctl_elem_value *ucontrol) | 1292 | struct snd_ctl_elem_value *ucontrol) |
1295 | { | 1293 | { |
1296 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1294 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1295 | struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); | ||
1297 | struct filter_control *fc = | 1296 | struct filter_control *fc = |
1298 | (struct filter_control *)kcontrol->private_value; | 1297 | (struct filter_control *)kcontrol->private_value; |
1299 | unsigned int i; | 1298 | unsigned int i; |
1300 | 1299 | ||
1301 | mutex_lock(&codec->mutex); | 1300 | mutex_lock(&drvdata->ctrl_lock); |
1302 | for (i = 0; i < fc->count; i++) | 1301 | for (i = 0; i < fc->count; i++) |
1303 | ucontrol->value.integer.value[i] = fc->value[i]; | 1302 | ucontrol->value.integer.value[i] = fc->value[i]; |
1304 | mutex_unlock(&codec->mutex); | 1303 | mutex_unlock(&drvdata->ctrl_lock); |
1305 | 1304 | ||
1306 | return 0; | 1305 | return 0; |
1307 | } | 1306 | } |
@@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol, | |||
1310 | struct snd_ctl_elem_value *ucontrol) | 1309 | struct snd_ctl_elem_value *ucontrol) |
1311 | { | 1310 | { |
1312 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 1311 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
1312 | struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec); | ||
1313 | struct filter_control *fc = | 1313 | struct filter_control *fc = |
1314 | (struct filter_control *)kcontrol->private_value; | 1314 | (struct filter_control *)kcontrol->private_value; |
1315 | unsigned int i; | 1315 | unsigned int i; |
1316 | 1316 | ||
1317 | mutex_lock(&codec->mutex); | 1317 | mutex_lock(&drvdata->ctrl_lock); |
1318 | for (i = 0; i < fc->count; i++) | 1318 | for (i = 0; i < fc->count; i++) |
1319 | fc->value[i] = ucontrol->value.integer.value[i]; | 1319 | fc->value[i] = ucontrol->value.integer.value[i]; |
1320 | mutex_unlock(&codec->mutex); | 1320 | mutex_unlock(&drvdata->ctrl_lock); |
1321 | 1321 | ||
1322 | return 0; | 1322 | return 0; |
1323 | } | 1323 | } |
@@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) | |||
2545 | 2545 | ||
2546 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | 2546 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); |
2547 | 2547 | ||
2548 | mutex_init(&drvdata->anc_lock); | 2548 | mutex_init(&drvdata->ctrl_lock); |
2549 | 2549 | ||
2550 | return status; | 2550 | return status; |
2551 | } | 2551 | } |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index bd9b1839c8b0..c6e5a313ebf4 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream, | |||
37 | struct snd_soc_dai *dai) | 37 | struct snd_soc_dai *dai) |
38 | { | 38 | { |
39 | struct snd_soc_codec *codec = dai->codec; | 39 | struct snd_soc_codec *codec = dai->codec; |
40 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
40 | 41 | ||
41 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? | 42 | int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? |
42 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; | 43 | AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE; |
43 | return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate); | 44 | return snd_ac97_set_rate(ac97, reg, substream->runtime->rate); |
44 | } | 45 | } |
45 | 46 | ||
46 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 47 | #define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
@@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = { | |||
53 | 54 | ||
54 | static struct snd_soc_dai_driver ac97_dai = { | 55 | static struct snd_soc_dai_driver ac97_dai = { |
55 | .name = "ac97-hifi", | 56 | .name = "ac97-hifi", |
56 | .ac97_control = 1, | ||
57 | .playback = { | 57 | .playback = { |
58 | .stream_name = "AC97 Playback", | 58 | .stream_name = "AC97 Playback", |
59 | .channels_min = 1, | 59 | .channels_min = 1, |
@@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = { | |||
71 | 71 | ||
72 | static int ac97_soc_probe(struct snd_soc_codec *codec) | 72 | static int ac97_soc_probe(struct snd_soc_codec *codec) |
73 | { | 73 | { |
74 | struct snd_ac97 *ac97; | ||
74 | struct snd_ac97_bus *ac97_bus; | 75 | struct snd_ac97_bus *ac97_bus; |
75 | struct snd_ac97_template ac97_template; | 76 | struct snd_ac97_template ac97_template; |
76 | int ret; | 77 | int ret; |
@@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) | |||
82 | return ret; | 83 | return ret; |
83 | 84 | ||
84 | memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); | 85 | memset(&ac97_template, 0, sizeof(struct snd_ac97_template)); |
85 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97); | 86 | ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97); |
86 | if (ret < 0) | 87 | if (ret < 0) |
87 | return ret; | 88 | return ret; |
88 | 89 | ||
90 | snd_soc_codec_set_drvdata(codec, ac97); | ||
91 | |||
89 | return 0; | 92 | return 0; |
90 | } | 93 | } |
91 | 94 | ||
92 | #ifdef CONFIG_PM | 95 | #ifdef CONFIG_PM |
93 | static int ac97_soc_suspend(struct snd_soc_codec *codec) | 96 | static int ac97_soc_suspend(struct snd_soc_codec *codec) |
94 | { | 97 | { |
95 | snd_ac97_suspend(codec->ac97); | 98 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
99 | |||
100 | snd_ac97_suspend(ac97); | ||
96 | 101 | ||
97 | return 0; | 102 | return 0; |
98 | } | 103 | } |
99 | 104 | ||
100 | static int ac97_soc_resume(struct snd_soc_codec *codec) | 105 | static int ac97_soc_resume(struct snd_soc_codec *codec) |
101 | { | 106 | { |
102 | snd_ac97_resume(codec->ac97); | 107 | |
108 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
109 | |||
110 | snd_ac97_resume(ac97); | ||
103 | 111 | ||
104 | return 0; | 112 | return 0; |
105 | } | 113 | } |
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 6844d0b2af68..387530b0b0fd 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = { | |||
72 | }; | 72 | }; |
73 | 73 | ||
74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | 74 | static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { |
75 | SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1), | 75 | SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0), |
76 | SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0), | ||
76 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), | 77 | SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), |
77 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), | 78 | SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0), |
78 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), | 79 | SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0), |
79 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), | 80 | SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0), |
81 | SND_SOC_DAPM_VMID("VMID"), | ||
80 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), | 82 | SND_SOC_DAPM_OUTPUT("DAC1OUT"), |
81 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), | 83 | SND_SOC_DAPM_OUTPUT("DAC2OUT"), |
82 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), | 84 | SND_SOC_DAPM_OUTPUT("DAC3OUT"), |
@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = { | |||
87 | 89 | ||
88 | static const struct snd_soc_dapm_route audio_paths[] = { | 90 | static const struct snd_soc_dapm_route audio_paths[] = { |
89 | { "DAC", NULL, "SYSCLK" }, | 91 | { "DAC", NULL, "SYSCLK" }, |
92 | { "DAC Output", NULL, "DAC" }, | ||
93 | { "DAC Output", NULL, "VMID" }, | ||
90 | { "ADC", NULL, "SYSCLK" }, | 94 | { "ADC", NULL, "SYSCLK" }, |
91 | { "DAC", NULL, "ADC_PWR" }, | 95 | { "DAC", NULL, "ADC_PWR" }, |
92 | { "ADC", NULL, "ADC_PWR" }, | 96 | { "ADC", NULL, "ADC_PWR" }, |
93 | { "DAC1OUT", NULL, "DAC" }, | 97 | { "DAC1OUT", NULL, "DAC Output" }, |
94 | { "DAC2OUT", NULL, "DAC" }, | 98 | { "DAC2OUT", NULL, "DAC Output" }, |
95 | { "DAC3OUT", NULL, "DAC" }, | 99 | { "DAC3OUT", NULL, "DAC Output" }, |
96 | { "DAC4OUT", NULL, "DAC" }, | 100 | { "DAC4OUT", NULL, "DAC Output" }, |
97 | { "ADC", NULL, "ADC1IN" }, | 101 | { "ADC", NULL, "ADC1IN" }, |
98 | { "ADC", NULL, "ADC2IN" }, | 102 | { "ADC", NULL, "ADC2IN" }, |
99 | { "SYSCLK", NULL, "PLL_PWR" }, | 103 | { "SYSCLK", NULL, "PLL_PWR" }, |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 304d3003339a..2860eef8610c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -24,34 +24,86 @@ | |||
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
26 | #include <linux/device.h> | 26 | #include <linux/device.h> |
27 | #include <linux/regmap.h> | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
29 | #include <sound/ac97_codec.h> | 30 | #include <sound/ac97_codec.h> |
30 | #include <sound/initval.h> | 31 | #include <sound/initval.h> |
31 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
32 | 33 | ||
33 | #include "ad1980.h" | 34 | static const struct reg_default ad1980_reg_defaults[] = { |
35 | { 0x02, 0x8000 }, | ||
36 | { 0x04, 0x8000 }, | ||
37 | { 0x06, 0x8000 }, | ||
38 | { 0x0c, 0x8008 }, | ||
39 | { 0x0e, 0x8008 }, | ||
40 | { 0x10, 0x8808 }, | ||
41 | { 0x12, 0x8808 }, | ||
42 | { 0x16, 0x8808 }, | ||
43 | { 0x18, 0x8808 }, | ||
44 | { 0x1a, 0x0000 }, | ||
45 | { 0x1c, 0x8000 }, | ||
46 | { 0x20, 0x0000 }, | ||
47 | { 0x28, 0x03c7 }, | ||
48 | { 0x2c, 0xbb80 }, | ||
49 | { 0x2e, 0xbb80 }, | ||
50 | { 0x30, 0xbb80 }, | ||
51 | { 0x32, 0xbb80 }, | ||
52 | { 0x36, 0x8080 }, | ||
53 | { 0x38, 0x8080 }, | ||
54 | { 0x3a, 0x2000 }, | ||
55 | { 0x60, 0x0000 }, | ||
56 | { 0x62, 0x0000 }, | ||
57 | { 0x72, 0x0000 }, | ||
58 | { 0x74, 0x1001 }, | ||
59 | { 0x76, 0x0000 }, | ||
60 | }; | ||
34 | 61 | ||
35 | /* | 62 | static bool ad1980_readable_reg(struct device *dev, unsigned int reg) |
36 | * AD1980 register cache | 63 | { |
37 | */ | 64 | switch (reg) { |
38 | static const u16 ad1980_reg[] = { | 65 | case AC97_RESET ... AC97_MASTER_MONO: |
39 | 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */ | 66 | case AC97_PHONE ... AC97_CD: |
40 | 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */ | 67 | case AC97_AUX ... AC97_GENERAL_PURPOSE: |
41 | 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */ | 68 | case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE: |
42 | 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */ | 69 | case AC97_SPDIF: |
43 | 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */ | 70 | case AC97_CODEC_CLASS_REV: |
44 | 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */ | 71 | case AC97_PCI_SVID: |
45 | 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */ | 72 | case AC97_AD_CODEC_CFG: |
46 | 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */ | 73 | case AC97_AD_JACK_SPDIF: |
47 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 74 | case AC97_AD_SERIAL_CFG: |
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 75 | case AC97_VENDOR_ID1: |
49 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 76 | case AC97_VENDOR_ID2: |
50 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 77 | return true; |
51 | 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */ | 78 | default: |
52 | 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */ | 79 | return false; |
53 | 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */ | 80 | } |
54 | 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */ | 81 | } |
82 | |||
83 | static bool ad1980_writeable_reg(struct device *dev, unsigned int reg) | ||
84 | { | ||
85 | switch (reg) { | ||
86 | case AC97_VENDOR_ID1: | ||
87 | case AC97_VENDOR_ID2: | ||
88 | return false; | ||
89 | default: | ||
90 | return ad1980_readable_reg(dev, reg); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | static const struct regmap_config ad1980_regmap_config = { | ||
95 | .reg_bits = 16, | ||
96 | .reg_stride = 2, | ||
97 | .val_bits = 16, | ||
98 | .max_register = 0x7e, | ||
99 | .cache_type = REGCACHE_RBTREE, | ||
100 | |||
101 | .volatile_reg = regmap_ac97_default_volatile, | ||
102 | .readable_reg = ad1980_readable_reg, | ||
103 | .writeable_reg = ad1980_writeable_reg, | ||
104 | |||
105 | .reg_defaults = ad1980_reg_defaults, | ||
106 | .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults), | ||
55 | }; | 107 | }; |
56 | 108 | ||
57 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | 109 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", |
@@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = { | |||
134 | { "HP_OUT_R", NULL, "Playback" }, | 186 | { "HP_OUT_R", NULL, "Playback" }, |
135 | }; | 187 | }; |
136 | 188 | ||
137 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
138 | unsigned int reg) | ||
139 | { | ||
140 | u16 *cache = codec->reg_cache; | ||
141 | |||
142 | switch (reg) { | ||
143 | case AC97_RESET: | ||
144 | case AC97_INT_PAGING: | ||
145 | case AC97_POWERDOWN: | ||
146 | case AC97_EXTENDED_STATUS: | ||
147 | case AC97_VENDOR_ID1: | ||
148 | case AC97_VENDOR_ID2: | ||
149 | return soc_ac97_ops->read(codec->ac97, reg); | ||
150 | default: | ||
151 | reg = reg >> 1; | ||
152 | |||
153 | if (reg >= ARRAY_SIZE(ad1980_reg)) | ||
154 | return -EINVAL; | ||
155 | |||
156 | return cache[reg]; | ||
157 | } | ||
158 | } | ||
159 | |||
160 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
161 | unsigned int val) | ||
162 | { | ||
163 | u16 *cache = codec->reg_cache; | ||
164 | |||
165 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
166 | reg = reg >> 1; | ||
167 | if (reg < ARRAY_SIZE(ad1980_reg)) | ||
168 | cache[reg] = val; | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static struct snd_soc_dai_driver ad1980_dai = { | 189 | static struct snd_soc_dai_driver ad1980_dai = { |
174 | .name = "ad1980-hifi", | 190 | .name = "ad1980-hifi", |
175 | .ac97_control = 1, | ||
176 | .playback = { | 191 | .playback = { |
177 | .stream_name = "Playback", | 192 | .stream_name = "Playback", |
178 | .channels_min = 2, | 193 | .channels_min = 2, |
@@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = { | |||
189 | 204 | ||
190 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) | 205 | static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) |
191 | { | 206 | { |
207 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
192 | unsigned int retry_cnt = 0; | 208 | unsigned int retry_cnt = 0; |
193 | 209 | ||
194 | do { | 210 | do { |
195 | if (try_warm && soc_ac97_ops->warm_reset) { | 211 | if (try_warm && soc_ac97_ops->warm_reset) { |
196 | soc_ac97_ops->warm_reset(codec->ac97); | 212 | soc_ac97_ops->warm_reset(ac97); |
197 | if (ac97_read(codec, AC97_RESET) == 0x0090) | 213 | if (snd_soc_read(codec, AC97_RESET) == 0x0090) |
198 | return 1; | 214 | return 1; |
199 | } | 215 | } |
200 | 216 | ||
201 | soc_ac97_ops->reset(codec->ac97); | 217 | soc_ac97_ops->reset(ac97); |
202 | /* | 218 | /* |
203 | * Set bit 16slot in register 74h, then every slot will has only | 219 | * Set bit 16slot in register 74h, then every slot will has only |
204 | * 16 bits. This command is sent out in 20bit mode, in which | 220 | * 16 bits. This command is sent out in 20bit mode, in which |
205 | * case the first nibble of data is eaten by the addr. (Tag is | 221 | * case the first nibble of data is eaten by the addr. (Tag is |
206 | * always 16 bit) | 222 | * always 16 bit) |
207 | */ | 223 | */ |
208 | ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900); | 224 | snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900); |
209 | 225 | ||
210 | if (ac97_read(codec, AC97_RESET) == 0x0090) | 226 | if (snd_soc_read(codec, AC97_RESET) == 0x0090) |
211 | return 0; | 227 | return 0; |
212 | } while (retry_cnt++ < 10); | 228 | } while (retry_cnt++ < 10); |
213 | 229 | ||
214 | printk(KERN_ERR "AD1980 AC97 reset failed\n"); | 230 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
231 | |||
215 | return -EIO; | 232 | return -EIO; |
216 | } | 233 | } |
217 | 234 | ||
218 | static int ad1980_soc_probe(struct snd_soc_codec *codec) | 235 | static int ad1980_soc_probe(struct snd_soc_codec *codec) |
219 | { | 236 | { |
237 | struct snd_ac97 *ac97; | ||
238 | struct regmap *regmap; | ||
220 | int ret; | 239 | int ret; |
221 | u16 vendor_id2; | 240 | u16 vendor_id2; |
222 | u16 ext_status; | 241 | u16 ext_status; |
223 | 242 | ||
224 | printk(KERN_INFO "AD1980 SoC Audio Codec\n"); | 243 | ac97 = snd_soc_new_ac97_codec(codec); |
225 | 244 | if (IS_ERR(ac97)) { | |
226 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 245 | ret = PTR_ERR(ac97); |
227 | if (ret < 0) { | 246 | dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); |
228 | printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); | ||
229 | return ret; | 247 | return ret; |
230 | } | 248 | } |
231 | 249 | ||
250 | regmap = regmap_init_ac97(ac97, &ad1980_regmap_config); | ||
251 | if (IS_ERR(regmap)) { | ||
252 | ret = PTR_ERR(regmap); | ||
253 | goto err_free_ac97; | ||
254 | } | ||
255 | |||
256 | snd_soc_codec_init_regmap(codec, regmap); | ||
257 | snd_soc_codec_set_drvdata(codec, ac97); | ||
258 | |||
232 | ret = ad1980_reset(codec, 0); | 259 | ret = ad1980_reset(codec, 0); |
233 | if (ret < 0) { | 260 | if (ret < 0) |
234 | printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n"); | ||
235 | goto reset_err; | 261 | goto reset_err; |
236 | } | ||
237 | 262 | ||
238 | /* Read out vendor ID to make sure it is ad1980 */ | 263 | /* Read out vendor ID to make sure it is ad1980 */ |
239 | if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) { | 264 | if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { |
240 | ret = -ENODEV; | 265 | ret = -ENODEV; |
241 | goto reset_err; | 266 | goto reset_err; |
242 | } | 267 | } |
243 | 268 | ||
244 | vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2); | 269 | vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2); |
245 | 270 | ||
246 | if (vendor_id2 != 0x5370) { | 271 | if (vendor_id2 != 0x5370) { |
247 | if (vendor_id2 != 0x5374) { | 272 | if (vendor_id2 != 0x5374) { |
248 | ret = -ENODEV; | 273 | ret = -ENODEV; |
249 | goto reset_err; | 274 | goto reset_err; |
250 | } else { | 275 | } else { |
251 | printk(KERN_WARNING "ad1980: " | 276 | dev_warn(codec->dev, |
252 | "Found AD1981 - only 2/2 IN/OUT Channels " | 277 | "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); |
253 | "supported\n"); | ||
254 | } | 278 | } |
255 | } | 279 | } |
256 | 280 | ||
257 | /* unmute captures and playbacks volume */ | 281 | /* unmute captures and playbacks volume */ |
258 | ac97_write(codec, AC97_MASTER, 0x0000); | 282 | snd_soc_write(codec, AC97_MASTER, 0x0000); |
259 | ac97_write(codec, AC97_PCM, 0x0000); | 283 | snd_soc_write(codec, AC97_PCM, 0x0000); |
260 | ac97_write(codec, AC97_REC_GAIN, 0x0000); | 284 | snd_soc_write(codec, AC97_REC_GAIN, 0x0000); |
261 | ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); | 285 | snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000); |
262 | ac97_write(codec, AC97_SURROUND_MASTER, 0x0000); | 286 | snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000); |
263 | 287 | ||
264 | /*power on LFE/CENTER/Surround DACs*/ | 288 | /*power on LFE/CENTER/Surround DACs*/ |
265 | ext_status = ac97_read(codec, AC97_EXTENDED_STATUS); | 289 | ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS); |
266 | ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); | 290 | snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800); |
267 | |||
268 | snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls, | ||
269 | ARRAY_SIZE(ad1980_snd_ac97_controls)); | ||
270 | 291 | ||
271 | return 0; | 292 | return 0; |
272 | 293 | ||
273 | reset_err: | 294 | reset_err: |
274 | snd_soc_free_ac97_codec(codec); | 295 | snd_soc_codec_exit_regmap(codec); |
296 | err_free_ac97: | ||
297 | snd_soc_free_ac97_codec(ac97); | ||
275 | return ret; | 298 | return ret; |
276 | } | 299 | } |
277 | 300 | ||
278 | static int ad1980_soc_remove(struct snd_soc_codec *codec) | 301 | static int ad1980_soc_remove(struct snd_soc_codec *codec) |
279 | { | 302 | { |
280 | snd_soc_free_ac97_codec(codec); | 303 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
304 | |||
305 | snd_soc_codec_exit_regmap(codec); | ||
306 | snd_soc_free_ac97_codec(ac97); | ||
281 | return 0; | 307 | return 0; |
282 | } | 308 | } |
283 | 309 | ||
284 | static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { | 310 | static struct snd_soc_codec_driver soc_codec_dev_ad1980 = { |
285 | .probe = ad1980_soc_probe, | 311 | .probe = ad1980_soc_probe, |
286 | .remove = ad1980_soc_remove, | 312 | .remove = ad1980_soc_remove, |
287 | .reg_cache_size = ARRAY_SIZE(ad1980_reg), | ||
288 | .reg_word_size = sizeof(u16), | ||
289 | .reg_cache_default = ad1980_reg, | ||
290 | .reg_cache_step = 2, | ||
291 | .write = ac97_write, | ||
292 | .read = ac97_read, | ||
293 | 313 | ||
314 | .controls = ad1980_snd_ac97_controls, | ||
315 | .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls), | ||
294 | .dapm_widgets = ad1980_dapm_widgets, | 316 | .dapm_widgets = ad1980_dapm_widgets, |
295 | .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), | 317 | .num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets), |
296 | .dapm_routes = ad1980_dapm_routes, | 318 | .dapm_routes = ad1980_dapm_routes, |
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h deleted file mode 100644 index eb0af44ad3df..000000000000 --- a/sound/soc/codecs/ad1980.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | /* | ||
2 | * ad1980.h -- ad1980 Soc Audio driver | ||
3 | * | ||
4 | * WARNING: | ||
5 | * | ||
6 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
7 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
8 | * by ADI now. | ||
9 | */ | ||
10 | |||
11 | #ifndef _AD1980_H | ||
12 | #define _AD1980_H | ||
13 | /* Bit definition of Power-Down Control/Status Register */ | ||
14 | #define ADC 0x0001 | ||
15 | #define DAC 0x0002 | ||
16 | #define ANL 0x0004 | ||
17 | #define REF 0x0008 | ||
18 | #define PR0 0x0100 | ||
19 | #define PR1 0x0200 | ||
20 | #define PR2 0x0400 | ||
21 | #define PR3 0x0800 | ||
22 | #define PR4 0x1000 | ||
23 | #define PR5 0x2000 | ||
24 | #define PR6 0x4000 | ||
25 | |||
26 | #endif | ||
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 7c784ad3e8b2..783dcb57043a 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = { | |||
551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, | 551 | static int adau1373_pll_event(struct snd_soc_dapm_widget *w, |
552 | struct snd_kcontrol *kcontrol, int event) | 552 | struct snd_kcontrol *kcontrol, int event) |
553 | { | 553 | { |
554 | struct snd_soc_codec *codec = w->codec; | 554 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 555 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
556 | unsigned int pll_id = w->name[3] - '1'; | 556 | unsigned int pll_id = w->name[3] - '1'; |
557 | unsigned int val; | 557 | unsigned int val; |
@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = { | |||
823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | 823 | static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, |
824 | struct snd_soc_dapm_widget *sink) | 824 | struct snd_soc_dapm_widget *sink) |
825 | { | 825 | { |
826 | struct snd_soc_codec *codec = source->codec; | 826 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 827 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
828 | unsigned int dai; | 828 | unsigned int dai; |
829 | const char *clk; | 829 | const char *clk; |
@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source, | |||
844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, | 844 | static int adau1373_check_src(struct snd_soc_dapm_widget *source, |
845 | struct snd_soc_dapm_widget *sink) | 845 | struct snd_soc_dapm_widget *sink) |
846 | { | 846 | { |
847 | struct snd_soc_codec *codec = source->codec; | 847 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 848 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
849 | unsigned int dai; | 849 | unsigned int dai; |
850 | 850 | ||
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 370b742117ef..d4e219b6b98f 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c | |||
@@ -22,9 +22,14 @@ | |||
22 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | 24 | ||
25 | #include <asm/unaligned.h> | ||
26 | |||
25 | #include "sigmadsp.h" | 27 | #include "sigmadsp.h" |
26 | #include "adau1701.h" | 28 | #include "adau1701.h" |
27 | 29 | ||
30 | #define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i)) | ||
31 | #define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i)) | ||
32 | |||
28 | #define ADAU1701_DSPCTRL 0x081c | 33 | #define ADAU1701_DSPCTRL 0x081c |
29 | #define ADAU1701_SEROCTL 0x081e | 34 | #define ADAU1701_SEROCTL 0x081e |
30 | #define ADAU1701_SERICTL 0x081f | 35 | #define ADAU1701_SERICTL 0x081f |
@@ -42,6 +47,7 @@ | |||
42 | #define ADAU1701_DSPCTRL_CR (1 << 2) | 47 | #define ADAU1701_DSPCTRL_CR (1 << 2) |
43 | #define ADAU1701_DSPCTRL_DAM (1 << 3) | 48 | #define ADAU1701_DSPCTRL_DAM (1 << 3) |
44 | #define ADAU1701_DSPCTRL_ADM (1 << 4) | 49 | #define ADAU1701_DSPCTRL_ADM (1 << 4) |
50 | #define ADAU1701_DSPCTRL_IST (1 << 5) | ||
45 | #define ADAU1701_DSPCTRL_SR_48 0x00 | 51 | #define ADAU1701_DSPCTRL_SR_48 0x00 |
46 | #define ADAU1701_DSPCTRL_SR_96 0x01 | 52 | #define ADAU1701_DSPCTRL_SR_96 0x01 |
47 | #define ADAU1701_DSPCTRL_SR_192 0x02 | 53 | #define ADAU1701_DSPCTRL_SR_192 0x02 |
@@ -102,7 +108,10 @@ struct adau1701 { | |||
102 | unsigned int pll_clkdiv; | 108 | unsigned int pll_clkdiv; |
103 | unsigned int sysclk; | 109 | unsigned int sysclk; |
104 | struct regmap *regmap; | 110 | struct regmap *regmap; |
111 | struct i2c_client *client; | ||
105 | u8 pin_config[12]; | 112 | u8 pin_config[12]; |
113 | |||
114 | struct sigmadsp *sigmadsp; | ||
106 | }; | 115 | }; |
107 | 116 | ||
108 | static const struct snd_kcontrol_new adau1701_controls[] = { | 117 | static const struct snd_kcontrol_new adau1701_controls[] = { |
@@ -159,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg) | |||
159 | { | 168 | { |
160 | switch (reg) { | 169 | switch (reg) { |
161 | case ADAU1701_DACSET: | 170 | case ADAU1701_DACSET: |
171 | case ADAU1701_DSPCTRL: | ||
162 | return true; | 172 | return true; |
163 | default: | 173 | default: |
164 | return false; | 174 | return false; |
@@ -238,12 +248,58 @@ static int adau1701_reg_read(void *context, unsigned int reg, | |||
238 | return 0; | 248 | return 0; |
239 | } | 249 | } |
240 | 250 | ||
241 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | 251 | static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr, |
252 | const uint8_t bytes[], size_t len) | ||
253 | { | ||
254 | struct i2c_client *client = to_i2c_client(sigmadsp->dev); | ||
255 | struct adau1701 *adau1701 = i2c_get_clientdata(client); | ||
256 | unsigned int val; | ||
257 | unsigned int i; | ||
258 | uint8_t buf[10]; | ||
259 | int ret; | ||
260 | |||
261 | ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val); | ||
262 | if (ret) | ||
263 | return ret; | ||
264 | |||
265 | if (val & ADAU1701_DSPCTRL_IST) | ||
266 | msleep(50); | ||
267 | |||
268 | for (i = 0; i < len / 4; i++) { | ||
269 | put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf); | ||
270 | buf[2] = 0x00; | ||
271 | memcpy(buf + 3, bytes + i * 4, 4); | ||
272 | ret = i2c_master_send(client, buf, 7); | ||
273 | if (ret < 0) | ||
274 | return ret; | ||
275 | else if (ret != 7) | ||
276 | return -EIO; | ||
277 | |||
278 | put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf); | ||
279 | put_unaligned_le16(addr + i, buf + 2); | ||
280 | ret = i2c_master_send(client, buf, 4); | ||
281 | if (ret < 0) | ||
282 | return ret; | ||
283 | else if (ret != 4) | ||
284 | return -EIO; | ||
285 | } | ||
286 | |||
287 | return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL, | ||
288 | ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST); | ||
289 | } | ||
290 | |||
291 | static const struct sigmadsp_ops adau1701_sigmadsp_ops = { | ||
292 | .safeload = adau1701_safeload, | ||
293 | }; | ||
294 | |||
295 | static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv, | ||
296 | unsigned int rate) | ||
242 | { | 297 | { |
243 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | 298 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
244 | struct i2c_client *client = to_i2c_client(codec->dev); | ||
245 | int ret; | 299 | int ret; |
246 | 300 | ||
301 | sigmadsp_reset(adau1701->sigmadsp); | ||
302 | |||
247 | if (clkdiv != ADAU1707_CLKDIV_UNSET && | 303 | if (clkdiv != ADAU1707_CLKDIV_UNSET && |
248 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && | 304 | gpio_is_valid(adau1701->gpio_pll_mode[0]) && |
249 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { | 305 | gpio_is_valid(adau1701->gpio_pll_mode[1])) { |
@@ -284,7 +340,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) | |||
284 | * know the correct PLL setup | 340 | * know the correct PLL setup |
285 | */ | 341 | */ |
286 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { | 342 | if (clkdiv != ADAU1707_CLKDIV_UNSET) { |
287 | ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); | 343 | ret = sigmadsp_setup(adau1701->sigmadsp, rate); |
288 | if (ret) { | 344 | if (ret) { |
289 | dev_warn(codec->dev, "Failed to load firmware\n"); | 345 | dev_warn(codec->dev, "Failed to load firmware\n"); |
290 | return ret; | 346 | return ret; |
@@ -385,7 +441,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, | |||
385 | * firmware upload. | 441 | * firmware upload. |
386 | */ | 442 | */ |
387 | if (clkdiv != adau1701->pll_clkdiv) { | 443 | if (clkdiv != adau1701->pll_clkdiv) { |
388 | ret = adau1701_reset(codec, clkdiv); | 444 | ret = adau1701_reset(codec, clkdiv, params_rate(params)); |
389 | if (ret < 0) | 445 | if (ret < 0) |
390 | return ret; | 446 | return ret; |
391 | } | 447 | } |
@@ -554,6 +610,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
554 | return 0; | 610 | return 0; |
555 | } | 611 | } |
556 | 612 | ||
613 | static int adau1701_startup(struct snd_pcm_substream *substream, | ||
614 | struct snd_soc_dai *dai) | ||
615 | { | ||
616 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec); | ||
617 | |||
618 | return sigmadsp_restrict_params(adau1701->sigmadsp, substream); | ||
619 | } | ||
620 | |||
557 | #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ | 621 | #define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ |
558 | SNDRV_PCM_RATE_192000) | 622 | SNDRV_PCM_RATE_192000) |
559 | 623 | ||
@@ -564,6 +628,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = { | |||
564 | .set_fmt = adau1701_set_dai_fmt, | 628 | .set_fmt = adau1701_set_dai_fmt, |
565 | .hw_params = adau1701_hw_params, | 629 | .hw_params = adau1701_hw_params, |
566 | .digital_mute = adau1701_digital_mute, | 630 | .digital_mute = adau1701_digital_mute, |
631 | .startup = adau1701_startup, | ||
567 | }; | 632 | }; |
568 | 633 | ||
569 | static struct snd_soc_dai_driver adau1701_dai = { | 634 | static struct snd_soc_dai_driver adau1701_dai = { |
@@ -600,6 +665,10 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
600 | unsigned int val; | 665 | unsigned int val; |
601 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); | 666 | struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); |
602 | 667 | ||
668 | ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component); | ||
669 | if (ret) | ||
670 | return ret; | ||
671 | |||
603 | /* | 672 | /* |
604 | * Let the pll_clkdiv variable default to something that won't happen | 673 | * Let the pll_clkdiv variable default to something that won't happen |
605 | * at runtime. That way, we can postpone the firmware download from | 674 | * at runtime. That way, we can postpone the firmware download from |
@@ -609,7 +678,7 @@ static int adau1701_probe(struct snd_soc_codec *codec) | |||
609 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; | 678 | adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; |
610 | 679 | ||
611 | /* initalize with pre-configured pll mode settings */ | 680 | /* initalize with pre-configured pll mode settings */ |
612 | ret = adau1701_reset(codec, adau1701->pll_clkdiv); | 681 | ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0); |
613 | if (ret < 0) | 682 | if (ret < 0) |
614 | return ret; | 683 | return ret; |
615 | 684 | ||
@@ -667,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
667 | if (!adau1701) | 736 | if (!adau1701) |
668 | return -ENOMEM; | 737 | return -ENOMEM; |
669 | 738 | ||
739 | adau1701->client = client; | ||
670 | adau1701->regmap = devm_regmap_init(dev, NULL, client, | 740 | adau1701->regmap = devm_regmap_init(dev, NULL, client, |
671 | &adau1701_regmap); | 741 | &adau1701_regmap); |
672 | if (IS_ERR(adau1701->regmap)) | 742 | if (IS_ERR(adau1701->regmap)) |
@@ -722,6 +792,12 @@ static int adau1701_i2c_probe(struct i2c_client *client, | |||
722 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; | 792 | adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; |
723 | 793 | ||
724 | i2c_set_clientdata(client, adau1701); | 794 | i2c_set_clientdata(client, adau1701); |
795 | |||
796 | adau1701->sigmadsp = devm_sigmadsp_init_i2c(client, | ||
797 | &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE); | ||
798 | if (IS_ERR(adau1701->sigmadsp)) | ||
799 | return PTR_ERR(adau1701->sigmadsp); | ||
800 | |||
725 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, | 801 | ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, |
726 | &adau1701_dai, 1); | 802 | &adau1701_dai, 1); |
727 | return ret; | 803 | return ret; |
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 91f60282fd2f..a1baeee160f4 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c | |||
@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control = | |||
255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, | 255 | static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w, |
256 | struct snd_kcontrol *kcontrol, int event) | 256 | struct snd_kcontrol *kcontrol, int event) |
257 | { | 257 | { |
258 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 258 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
259 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
259 | 260 | ||
260 | /* After any power changes have been made the dejitter circuit | 261 | /* After any power changes have been made the dejitter circuit |
261 | * has to be reinitialized. */ | 262 | * has to be reinitialized. */ |
@@ -702,11 +703,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) | |||
702 | ARRAY_SIZE(adau1761_dapm_routes)); | 703 | ARRAY_SIZE(adau1761_dapm_routes)); |
703 | if (ret) | 704 | if (ret) |
704 | return ret; | 705 | return ret; |
705 | |||
706 | ret = adau17x1_load_firmware(adau, codec->dev, | ||
707 | ADAU1761_FIRMWARE); | ||
708 | if (ret) | ||
709 | dev_warn(codec->dev, "Failed to firmware\n"); | ||
710 | } | 706 | } |
711 | 707 | ||
712 | ret = adau17x1_add_routes(codec); | 708 | ret = adau17x1_add_routes(codec); |
@@ -775,16 +771,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap, | |||
775 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 771 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) |
776 | { | 772 | { |
777 | struct snd_soc_dai_driver *dai_drv; | 773 | struct snd_soc_dai_driver *dai_drv; |
774 | const char *firmware_name; | ||
778 | int ret; | 775 | int ret; |
779 | 776 | ||
780 | ret = adau17x1_probe(dev, regmap, type, switch_mode); | 777 | if (type == ADAU1361) { |
781 | if (ret) | ||
782 | return ret; | ||
783 | |||
784 | if (type == ADAU1361) | ||
785 | dai_drv = &adau1361_dai_driver; | 778 | dai_drv = &adau1361_dai_driver; |
786 | else | 779 | firmware_name = NULL; |
780 | } else { | ||
787 | dai_drv = &adau1761_dai_driver; | 781 | dai_drv = &adau1761_dai_driver; |
782 | firmware_name = ADAU1761_FIRMWARE; | ||
783 | } | ||
784 | |||
785 | ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); | ||
786 | if (ret) | ||
787 | return ret; | ||
788 | 788 | ||
789 | return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); | 789 | return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1); |
790 | } | 790 | } |
@@ -798,6 +798,7 @@ const struct regmap_config adau1761_regmap_config = { | |||
798 | .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), | 798 | .num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults), |
799 | .readable_reg = adau1761_readable_register, | 799 | .readable_reg = adau1761_readable_register, |
800 | .volatile_reg = adau17x1_volatile_register, | 800 | .volatile_reg = adau17x1_volatile_register, |
801 | .precious_reg = adau17x1_precious_register, | ||
801 | .cache_type = REGCACHE_RBTREE, | 802 | .cache_type = REGCACHE_RBTREE, |
802 | }; | 803 | }; |
803 | EXPORT_SYMBOL_GPL(adau1761_regmap_config); | 804 | EXPORT_SYMBOL_GPL(adau1761_regmap_config); |
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index e9fc00fb13dd..35581f43fa6d 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c | |||
@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = { | |||
174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, | 174 | static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w, |
175 | struct snd_kcontrol *kcontrol, int event) | 175 | struct snd_kcontrol *kcontrol, int event) |
176 | { | 176 | { |
177 | struct snd_soc_codec *codec = w->codec; | 177 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 178 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
179 | 179 | ||
180 | /* After any power changes have been made the dejitter circuit | 180 | /* After any power changes have been made the dejitter circuit |
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
385 | { | 385 | { |
386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); | 386 | struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev); |
387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 387 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
388 | const char *firmware; | ||
389 | int ret; | 388 | int ret; |
390 | 389 | ||
391 | ret = adau17x1_add_widgets(codec); | 390 | ret = adau17x1_add_widgets(codec); |
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
422 | return ret; | 421 | return ret; |
423 | } | 422 | } |
424 | 423 | ||
425 | switch (adau->type) { | ||
426 | case ADAU1381: | ||
427 | firmware = ADAU1381_FIRMWARE; | ||
428 | break; | ||
429 | case ADAU1781: | ||
430 | firmware = ADAU1781_FIRMWARE; | ||
431 | break; | ||
432 | default: | ||
433 | return -EINVAL; | ||
434 | } | ||
435 | |||
436 | ret = adau17x1_add_routes(codec); | 424 | ret = adau17x1_add_routes(codec); |
437 | if (ret < 0) | 425 | if (ret < 0) |
438 | return ret; | 426 | return ret; |
439 | 427 | ||
440 | ret = adau17x1_load_firmware(adau, codec->dev, firmware); | ||
441 | if (ret) | ||
442 | dev_warn(codec->dev, "Failed to load firmware\n"); | ||
443 | |||
444 | return 0; | 428 | return 0; |
445 | } | 429 | } |
446 | 430 | ||
@@ -488,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = { | |||
488 | .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults), | 472 | .num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults), |
489 | .readable_reg = adau1781_readable_register, | 473 | .readable_reg = adau1781_readable_register, |
490 | .volatile_reg = adau17x1_volatile_register, | 474 | .volatile_reg = adau17x1_volatile_register, |
475 | .precious_reg = adau17x1_precious_register, | ||
491 | .cache_type = REGCACHE_RBTREE, | 476 | .cache_type = REGCACHE_RBTREE, |
492 | }; | 477 | }; |
493 | EXPORT_SYMBOL_GPL(adau1781_regmap_config); | 478 | EXPORT_SYMBOL_GPL(adau1781_regmap_config); |
@@ -495,9 +480,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config); | |||
495 | int adau1781_probe(struct device *dev, struct regmap *regmap, | 480 | int adau1781_probe(struct device *dev, struct regmap *regmap, |
496 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 481 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) |
497 | { | 482 | { |
483 | const char *firmware_name; | ||
498 | int ret; | 484 | int ret; |
499 | 485 | ||
500 | ret = adau17x1_probe(dev, regmap, type, switch_mode); | 486 | switch (type) { |
487 | case ADAU1381: | ||
488 | firmware_name = ADAU1381_FIRMWARE; | ||
489 | break; | ||
490 | case ADAU1781: | ||
491 | firmware_name = ADAU1781_FIRMWARE; | ||
492 | break; | ||
493 | default: | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | |||
497 | ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name); | ||
501 | if (ret) | 498 | if (ret) |
502 | return ret; | 499 | return ret; |
503 | 500 | ||
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 3e16c1c64115..fa2e690e51c8 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = { | |||
61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, | 61 | static int adau17x1_pll_event(struct snd_soc_dapm_widget *w, |
62 | struct snd_kcontrol *kcontrol, int event) | 62 | struct snd_kcontrol *kcontrol, int event) |
63 | { | 63 | { |
64 | struct adau *adau = snd_soc_codec_get_drvdata(w->codec); | 64 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
65 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
65 | int ret; | 66 | int ret; |
66 | 67 | ||
67 | if (SND_SOC_DAPM_EVENT_ON(event)) { | 68 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
@@ -307,6 +308,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
307 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 308 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
308 | unsigned int val, div, dsp_div; | 309 | unsigned int val, div, dsp_div; |
309 | unsigned int freq; | 310 | unsigned int freq; |
311 | int ret; | ||
310 | 312 | ||
311 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) | 313 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) |
312 | freq = adau->pll_freq; | 314 | freq = adau->pll_freq; |
@@ -356,6 +358,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
356 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); | 358 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div); |
357 | } | 359 | } |
358 | 360 | ||
361 | if (adau->sigmadsp) { | ||
362 | ret = adau17x1_setup_firmware(adau, params_rate(params)); | ||
363 | if (ret < 0) | ||
364 | return ret; | ||
365 | } | ||
366 | |||
359 | if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) | 367 | if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J) |
360 | return 0; | 368 | return 0; |
361 | 369 | ||
@@ -661,12 +669,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai, | |||
661 | return 0; | 669 | return 0; |
662 | } | 670 | } |
663 | 671 | ||
672 | static int adau17x1_startup(struct snd_pcm_substream *substream, | ||
673 | struct snd_soc_dai *dai) | ||
674 | { | ||
675 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
676 | |||
677 | if (adau->sigmadsp) | ||
678 | return sigmadsp_restrict_params(adau->sigmadsp, substream); | ||
679 | |||
680 | return 0; | ||
681 | } | ||
682 | |||
664 | const struct snd_soc_dai_ops adau17x1_dai_ops = { | 683 | const struct snd_soc_dai_ops adau17x1_dai_ops = { |
665 | .hw_params = adau17x1_hw_params, | 684 | .hw_params = adau17x1_hw_params, |
666 | .set_sysclk = adau17x1_set_dai_sysclk, | 685 | .set_sysclk = adau17x1_set_dai_sysclk, |
667 | .set_fmt = adau17x1_set_dai_fmt, | 686 | .set_fmt = adau17x1_set_dai_fmt, |
668 | .set_pll = adau17x1_set_dai_pll, | 687 | .set_pll = adau17x1_set_dai_pll, |
669 | .set_tdm_slot = adau17x1_set_dai_tdm_slot, | 688 | .set_tdm_slot = adau17x1_set_dai_tdm_slot, |
689 | .startup = adau17x1_startup, | ||
670 | }; | 690 | }; |
671 | EXPORT_SYMBOL_GPL(adau17x1_dai_ops); | 691 | EXPORT_SYMBOL_GPL(adau17x1_dai_ops); |
672 | 692 | ||
@@ -687,8 +707,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | |||
687 | } | 707 | } |
688 | EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); | 708 | EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage); |
689 | 709 | ||
710 | bool adau17x1_precious_register(struct device *dev, unsigned int reg) | ||
711 | { | ||
712 | /* SigmaDSP parameter memory */ | ||
713 | if (reg < 0x400) | ||
714 | return true; | ||
715 | |||
716 | return false; | ||
717 | } | ||
718 | EXPORT_SYMBOL_GPL(adau17x1_precious_register); | ||
719 | |||
690 | bool adau17x1_readable_register(struct device *dev, unsigned int reg) | 720 | bool adau17x1_readable_register(struct device *dev, unsigned int reg) |
691 | { | 721 | { |
722 | /* SigmaDSP parameter memory */ | ||
723 | if (reg < 0x400) | ||
724 | return true; | ||
725 | |||
692 | switch (reg) { | 726 | switch (reg) { |
693 | case ADAU17X1_CLOCK_CONTROL: | 727 | case ADAU17X1_CLOCK_CONTROL: |
694 | case ADAU17X1_PLL_CONTROL: | 728 | case ADAU17X1_PLL_CONTROL: |
@@ -745,8 +779,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg) | |||
745 | } | 779 | } |
746 | EXPORT_SYMBOL_GPL(adau17x1_volatile_register); | 780 | EXPORT_SYMBOL_GPL(adau17x1_volatile_register); |
747 | 781 | ||
748 | int adau17x1_load_firmware(struct adau *adau, struct device *dev, | 782 | int adau17x1_setup_firmware(struct adau *adau, unsigned int rate) |
749 | const char *firmware) | ||
750 | { | 783 | { |
751 | int ret; | 784 | int ret; |
752 | int dspsr; | 785 | int dspsr; |
@@ -758,7 +791,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, | |||
758 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); | 791 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1); |
759 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); | 792 | regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf); |
760 | 793 | ||
761 | ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware); | 794 | ret = sigmadsp_setup(adau->sigmadsp, rate); |
762 | if (ret) { | 795 | if (ret) { |
763 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); | 796 | regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0); |
764 | return ret; | 797 | return ret; |
@@ -767,7 +800,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev, | |||
767 | 800 | ||
768 | return 0; | 801 | return 0; |
769 | } | 802 | } |
770 | EXPORT_SYMBOL_GPL(adau17x1_load_firmware); | 803 | EXPORT_SYMBOL_GPL(adau17x1_setup_firmware); |
771 | 804 | ||
772 | int adau17x1_add_widgets(struct snd_soc_codec *codec) | 805 | int adau17x1_add_widgets(struct snd_soc_codec *codec) |
773 | { | 806 | { |
@@ -787,8 +820,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec) | |||
787 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 820 | ret = snd_soc_dapm_new_controls(&codec->dapm, |
788 | adau17x1_dsp_dapm_widgets, | 821 | adau17x1_dsp_dapm_widgets, |
789 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); | 822 | ARRAY_SIZE(adau17x1_dsp_dapm_widgets)); |
823 | if (ret) | ||
824 | return ret; | ||
825 | |||
826 | if (!adau->sigmadsp) | ||
827 | return 0; | ||
828 | |||
829 | ret = sigmadsp_attach(adau->sigmadsp, &codec->component); | ||
830 | if (ret) { | ||
831 | dev_err(codec->dev, "Failed to attach firmware: %d\n", | ||
832 | ret); | ||
833 | return ret; | ||
834 | } | ||
790 | } | 835 | } |
791 | return ret; | 836 | |
837 | return 0; | ||
792 | } | 838 | } |
793 | EXPORT_SYMBOL_GPL(adau17x1_add_widgets); | 839 | EXPORT_SYMBOL_GPL(adau17x1_add_widgets); |
794 | 840 | ||
@@ -829,7 +875,8 @@ int adau17x1_resume(struct snd_soc_codec *codec) | |||
829 | EXPORT_SYMBOL_GPL(adau17x1_resume); | 875 | EXPORT_SYMBOL_GPL(adau17x1_resume); |
830 | 876 | ||
831 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 877 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
832 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)) | 878 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
879 | const char *firmware_name) | ||
833 | { | 880 | { |
834 | struct adau *adau; | 881 | struct adau *adau; |
835 | 882 | ||
@@ -846,6 +893,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
846 | 893 | ||
847 | dev_set_drvdata(dev, adau); | 894 | dev_set_drvdata(dev, adau); |
848 | 895 | ||
896 | if (firmware_name) { | ||
897 | adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL, | ||
898 | firmware_name); | ||
899 | if (IS_ERR(adau->sigmadsp)) { | ||
900 | dev_warn(dev, "Could not find firmware file: %ld\n", | ||
901 | PTR_ERR(adau->sigmadsp)); | ||
902 | adau->sigmadsp = NULL; | ||
903 | } | ||
904 | } | ||
905 | |||
849 | if (switch_mode) | 906 | if (switch_mode) |
850 | switch_mode(dev); | 907 | switch_mode(dev); |
851 | 908 | ||
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index e4a557fd7155..e13583e6ff56 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h | |||
@@ -4,6 +4,8 @@ | |||
4 | #include <linux/regmap.h> | 4 | #include <linux/regmap.h> |
5 | #include <linux/platform_data/adau17x1.h> | 5 | #include <linux/platform_data/adau17x1.h> |
6 | 6 | ||
7 | #include "sigmadsp.h" | ||
8 | |||
7 | enum adau17x1_type { | 9 | enum adau17x1_type { |
8 | ADAU1361, | 10 | ADAU1361, |
9 | ADAU1761, | 11 | ADAU1761, |
@@ -42,22 +44,24 @@ struct adau { | |||
42 | bool dsp_bypass[2]; | 44 | bool dsp_bypass[2]; |
43 | 45 | ||
44 | struct regmap *regmap; | 46 | struct regmap *regmap; |
47 | struct sigmadsp *sigmadsp; | ||
45 | }; | 48 | }; |
46 | 49 | ||
47 | int adau17x1_add_widgets(struct snd_soc_codec *codec); | 50 | int adau17x1_add_widgets(struct snd_soc_codec *codec); |
48 | int adau17x1_add_routes(struct snd_soc_codec *codec); | 51 | int adau17x1_add_routes(struct snd_soc_codec *codec); |
49 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 52 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
50 | enum adau17x1_type type, void (*switch_mode)(struct device *dev)); | 53 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
54 | const char *firmware_name); | ||
51 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | 55 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, |
52 | enum adau17x1_micbias_voltage micbias); | 56 | enum adau17x1_micbias_voltage micbias); |
53 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); | 57 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); |
54 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); | 58 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); |
59 | bool adau17x1_precious_register(struct device *dev, unsigned int reg); | ||
55 | int adau17x1_resume(struct snd_soc_codec *codec); | 60 | int adau17x1_resume(struct snd_soc_codec *codec); |
56 | 61 | ||
57 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; | 62 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; |
58 | 63 | ||
59 | int adau17x1_load_firmware(struct adau *adau, struct device *dev, | 64 | int adau17x1_setup_firmware(struct adau *adau, unsigned int rate); |
60 | const char *firmware); | ||
61 | bool adau17x1_has_dsp(struct adau *adau); | 65 | bool adau17x1_has_dsp(struct adau *adau); |
62 | 66 | ||
63 | #define ADAU17X1_CLOCK_CONTROL 0x4000 | 67 | #define ADAU17X1_CLOCK_CONTROL 0x4000 |
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index ce3cdca9fc62..b67480f1b1aa 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = { | |||
212 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | 212 | static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, |
213 | struct snd_soc_dapm_widget *sink) | 213 | struct snd_soc_dapm_widget *sink) |
214 | { | 214 | { |
215 | struct snd_soc_codec *codec = source->codec; | 215 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
216 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 216 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
217 | const char *clk; | 217 | const char *clk; |
218 | 218 | ||
@@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source, | |||
236 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, | 236 | static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source, |
237 | struct snd_soc_dapm_widget *sink) | 237 | struct snd_soc_dapm_widget *sink) |
238 | { | 238 | { |
239 | struct snd_soc_codec *codec = source->codec; | 239 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); |
240 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 240 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
241 | 241 | ||
242 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; | 242 | return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL; |
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 30e297890fec..9130d916f2f4 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c | |||
@@ -373,33 +373,9 @@ static struct snd_soc_dai_driver ak4535_dai = { | |||
373 | .ops = &ak4535_dai_ops, | 373 | .ops = &ak4535_dai_ops, |
374 | }; | 374 | }; |
375 | 375 | ||
376 | static int ak4535_suspend(struct snd_soc_codec *codec) | ||
377 | { | ||
378 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int ak4535_resume(struct snd_soc_codec *codec) | 376 | static int ak4535_resume(struct snd_soc_codec *codec) |
383 | { | 377 | { |
384 | snd_soc_cache_sync(codec); | 378 | snd_soc_cache_sync(codec); |
385 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static int ak4535_probe(struct snd_soc_codec *codec) | ||
390 | { | ||
391 | /* power on device */ | ||
392 | ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
393 | |||
394 | snd_soc_add_codec_controls(codec, ak4535_snd_controls, | ||
395 | ARRAY_SIZE(ak4535_snd_controls)); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | /* power down chip */ | ||
400 | static int ak4535_remove(struct snd_soc_codec *codec) | ||
401 | { | ||
402 | ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
403 | return 0; | 379 | return 0; |
404 | } | 380 | } |
405 | 381 | ||
@@ -416,11 +392,12 @@ static const struct regmap_config ak4535_regmap = { | |||
416 | }; | 392 | }; |
417 | 393 | ||
418 | static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { | 394 | static struct snd_soc_codec_driver soc_codec_dev_ak4535 = { |
419 | .probe = ak4535_probe, | ||
420 | .remove = ak4535_remove, | ||
421 | .suspend = ak4535_suspend, | ||
422 | .resume = ak4535_resume, | 395 | .resume = ak4535_resume, |
423 | .set_bias_level = ak4535_set_bias_level, | 396 | .set_bias_level = ak4535_set_bias_level, |
397 | .suspend_bias_off = true, | ||
398 | |||
399 | .controls = ak4535_snd_controls, | ||
400 | .num_controls = ARRAY_SIZE(ak4535_snd_controls), | ||
424 | .dapm_widgets = ak4535_dapm_widgets, | 401 | .dapm_widgets = ak4535_dapm_widgets, |
425 | .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), | 402 | .num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets), |
426 | .dapm_routes = ak4535_audio_map, | 403 | .dapm_routes = ak4535_audio_map, |
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 7afe8f482088..70861c7b1631 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
@@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = { | |||
505 | }, | 505 | }, |
506 | }; | 506 | }; |
507 | 507 | ||
508 | static int ak4641_suspend(struct snd_soc_codec *codec) | ||
509 | { | ||
510 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int ak4641_resume(struct snd_soc_codec *codec) | ||
515 | { | ||
516 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int ak4641_probe(struct snd_soc_codec *codec) | ||
521 | { | ||
522 | /* power on device */ | ||
523 | ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int ak4641_remove(struct snd_soc_codec *codec) | ||
529 | { | ||
530 | ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | |||
536 | static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { | 508 | static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { |
537 | .probe = ak4641_probe, | ||
538 | .remove = ak4641_remove, | ||
539 | .suspend = ak4641_suspend, | ||
540 | .resume = ak4641_resume, | ||
541 | .controls = ak4641_snd_controls, | 509 | .controls = ak4641_snd_controls, |
542 | .num_controls = ARRAY_SIZE(ak4641_snd_controls), | 510 | .num_controls = ARRAY_SIZE(ak4641_snd_controls), |
543 | .dapm_widgets = ak4641_dapm_widgets, | 511 | .dapm_widgets = ak4641_dapm_widgets, |
@@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = { | |||
545 | .dapm_routes = ak4641_audio_map, | 513 | .dapm_routes = ak4641_audio_map, |
546 | .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), | 514 | .num_dapm_routes = ARRAY_SIZE(ak4641_audio_map), |
547 | .set_bias_level = ak4641_set_bias_level, | 515 | .set_bias_level = ak4641_set_bias_level, |
516 | .suspend_bias_off = true, | ||
548 | }; | 517 | }; |
549 | 518 | ||
550 | static const struct regmap_config ak4641_regmap = { | 519 | static const struct regmap_config ak4641_regmap = { |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 041712592e29..dde8b49c19ad 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec) | |||
491 | return 0; | 491 | return 0; |
492 | } | 492 | } |
493 | 493 | ||
494 | |||
495 | static int ak4642_probe(struct snd_soc_codec *codec) | ||
496 | { | ||
497 | ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static int ak4642_remove(struct snd_soc_codec *codec) | ||
503 | { | ||
504 | ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { | 494 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { |
509 | .probe = ak4642_probe, | ||
510 | .remove = ak4642_remove, | ||
511 | .resume = ak4642_resume, | 495 | .resume = ak4642_resume, |
512 | .set_bias_level = ak4642_set_bias_level, | 496 | .set_bias_level = ak4642_set_bias_level, |
513 | .controls = ak4642_snd_controls, | 497 | .controls = ak4642_snd_controls, |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 998fa0c5a0b9..686cacb0e835 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c | |||
@@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = { | |||
611 | .ops = &ak4671_dai_ops, | 611 | .ops = &ak4671_dai_ops, |
612 | }; | 612 | }; |
613 | 613 | ||
614 | static int ak4671_probe(struct snd_soc_codec *codec) | ||
615 | { | ||
616 | return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
617 | } | ||
618 | |||
619 | static int ak4671_remove(struct snd_soc_codec *codec) | ||
620 | { | ||
621 | ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { | 614 | static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { |
626 | .probe = ak4671_probe, | ||
627 | .remove = ak4671_remove, | ||
628 | .set_bias_level = ak4671_set_bias_level, | 615 | .set_bias_level = ak4671_set_bias_level, |
629 | .controls = ak4671_snd_controls, | 616 | .controls = ak4671_snd_controls, |
630 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), | 617 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), |
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 9d0755aa1d16..bdf8c5ac8ca4 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c | |||
@@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec) | |||
866 | { | 866 | { |
867 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); | 867 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); |
868 | 868 | ||
869 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
870 | regcache_cache_only(alc5623->regmap, true); | 869 | regcache_cache_only(alc5623->regmap, true); |
871 | 870 | ||
872 | return 0; | 871 | return 0; |
@@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec) | |||
887 | return ret; | 886 | return ret; |
888 | } | 887 | } |
889 | 888 | ||
890 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
891 | |||
892 | /* charge alc5623 caps */ | ||
893 | if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { | ||
894 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
895 | codec->dapm.bias_level = SND_SOC_BIAS_ON; | ||
896 | alc5623_set_bias_level(codec, codec->dapm.bias_level); | ||
897 | } | ||
898 | |||
899 | return 0; | 889 | return 0; |
900 | } | 890 | } |
901 | 891 | ||
@@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
906 | 896 | ||
907 | alc5623_reset(codec); | 897 | alc5623_reset(codec); |
908 | 898 | ||
909 | /* power on device */ | ||
910 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
911 | |||
912 | if (alc5623->add_ctrl) { | 899 | if (alc5623->add_ctrl) { |
913 | snd_soc_write(codec, ALC5623_ADD_CTRL_REG, | 900 | snd_soc_write(codec, ALC5623_ADD_CTRL_REG, |
914 | alc5623->add_ctrl); | 901 | alc5623->add_ctrl); |
@@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
964 | return 0; | 951 | return 0; |
965 | } | 952 | } |
966 | 953 | ||
967 | /* power down chip */ | ||
968 | static int alc5623_remove(struct snd_soc_codec *codec) | ||
969 | { | ||
970 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | static struct snd_soc_codec_driver soc_codec_device_alc5623 = { | 954 | static struct snd_soc_codec_driver soc_codec_device_alc5623 = { |
975 | .probe = alc5623_probe, | 955 | .probe = alc5623_probe, |
976 | .remove = alc5623_remove, | ||
977 | .suspend = alc5623_suspend, | 956 | .suspend = alc5623_suspend, |
978 | .resume = alc5623_resume, | 957 | .resume = alc5623_resume, |
979 | .set_bias_level = alc5623_set_bias_level, | 958 | .set_bias_level = alc5623_set_bias_level, |
959 | .suspend_bias_off = true, | ||
980 | }; | 960 | }; |
981 | 961 | ||
982 | static const struct regmap_config alc5623_regmap = { | 962 | static const struct regmap_config alc5623_regmap = { |
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 85942ca36cbf..d1fdbc266631 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c | |||
@@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = { | |||
1038 | }; | 1038 | }; |
1039 | 1039 | ||
1040 | #ifdef CONFIG_PM | 1040 | #ifdef CONFIG_PM |
1041 | static int alc5632_suspend(struct snd_soc_codec *codec) | ||
1042 | { | ||
1043 | alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | static int alc5632_resume(struct snd_soc_codec *codec) | 1041 | static int alc5632_resume(struct snd_soc_codec *codec) |
1048 | { | 1042 | { |
1049 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); | 1043 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); |
1050 | 1044 | ||
1051 | regcache_sync(alc5632->regmap); | 1045 | regcache_sync(alc5632->regmap); |
1052 | 1046 | ||
1053 | alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1054 | return 0; | 1047 | return 0; |
1055 | } | 1048 | } |
1056 | #else | 1049 | #else |
1057 | #define alc5632_suspend NULL | ||
1058 | #define alc5632_resume NULL | 1050 | #define alc5632_resume NULL |
1059 | #endif | 1051 | #endif |
1060 | 1052 | ||
@@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec) | |||
1062 | { | 1054 | { |
1063 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); | 1055 | struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec); |
1064 | 1056 | ||
1065 | /* power on device */ | ||
1066 | alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1067 | |||
1068 | switch (alc5632->id) { | 1057 | switch (alc5632->id) { |
1069 | case 0x5c: | 1058 | case 0x5c: |
1070 | snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, | 1059 | snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls, |
@@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec) | |||
1077 | return 0; | 1066 | return 0; |
1078 | } | 1067 | } |
1079 | 1068 | ||
1080 | /* power down chip */ | ||
1081 | static int alc5632_remove(struct snd_soc_codec *codec) | ||
1082 | { | ||
1083 | alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static struct snd_soc_codec_driver soc_codec_device_alc5632 = { | 1069 | static struct snd_soc_codec_driver soc_codec_device_alc5632 = { |
1088 | .probe = alc5632_probe, | 1070 | .probe = alc5632_probe, |
1089 | .remove = alc5632_remove, | ||
1090 | .suspend = alc5632_suspend, | ||
1091 | .resume = alc5632_resume, | 1071 | .resume = alc5632_resume, |
1092 | .set_bias_level = alc5632_set_bias_level, | 1072 | .set_bias_level = alc5632_set_bias_level, |
1073 | .suspend_bias_off = true, | ||
1074 | |||
1093 | .controls = alc5632_snd_controls, | 1075 | .controls = alc5632_snd_controls, |
1094 | .num_controls = ARRAY_SIZE(alc5632_snd_controls), | 1076 | .num_controls = ARRAY_SIZE(alc5632_snd_controls), |
1095 | .dapm_widgets = alc5632_dapm_widgets, | 1077 | .dapm_widgets = alc5632_dapm_widgets, |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 0c05e7a7945f..9550d7433ad0 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -61,6 +61,11 @@ | |||
61 | #define ARIZONA_FLL_MIN_OUTDIV 2 | 61 | #define ARIZONA_FLL_MIN_OUTDIV 2 |
62 | #define ARIZONA_FLL_MAX_OUTDIV 7 | 62 | #define ARIZONA_FLL_MAX_OUTDIV 7 |
63 | 63 | ||
64 | #define ARIZONA_FMT_DSP_MODE_A 0 | ||
65 | #define ARIZONA_FMT_DSP_MODE_B 1 | ||
66 | #define ARIZONA_FMT_I2S_MODE 2 | ||
67 | #define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3 | ||
68 | |||
64 | #define arizona_fll_err(_fll, fmt, ...) \ | 69 | #define arizona_fll_err(_fll, fmt, ...) \ |
65 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 70 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
66 | #define arizona_fll_warn(_fll, fmt, ...) \ | 71 | #define arizona_fll_warn(_fll, fmt, ...) \ |
@@ -648,7 +653,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, | |||
648 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); | 653 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); |
649 | 654 | ||
650 | static const char * const arizona_in_dmic_osr_text[] = { | 655 | static const char * const arizona_in_dmic_osr_text[] = { |
651 | "1.536MHz", "3.072MHz", "6.144MHz", | 656 | "1.536MHz", "3.072MHz", "6.144MHz", "768kHz", |
652 | }; | 657 | }; |
653 | 658 | ||
654 | const struct soc_enum arizona_in_dmic_osr[] = { | 659 | const struct soc_enum arizona_in_dmic_osr[] = { |
@@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
946 | 951 | ||
947 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 952 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
948 | case SND_SOC_DAIFMT_DSP_A: | 953 | case SND_SOC_DAIFMT_DSP_A: |
949 | mode = 0; | 954 | mode = ARIZONA_FMT_DSP_MODE_A; |
955 | break; | ||
956 | case SND_SOC_DAIFMT_DSP_B: | ||
957 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) | ||
958 | != SND_SOC_DAIFMT_CBM_CFM) { | ||
959 | arizona_aif_err(dai, "DSP_B not valid in slave mode\n"); | ||
960 | return -EINVAL; | ||
961 | } | ||
962 | mode = ARIZONA_FMT_DSP_MODE_B; | ||
950 | break; | 963 | break; |
951 | case SND_SOC_DAIFMT_I2S: | 964 | case SND_SOC_DAIFMT_I2S: |
952 | mode = 2; | 965 | mode = ARIZONA_FMT_I2S_MODE; |
966 | break; | ||
967 | case SND_SOC_DAIFMT_LEFT_J: | ||
968 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) | ||
969 | != SND_SOC_DAIFMT_CBM_CFM) { | ||
970 | arizona_aif_err(dai, "LEFT_J not valid in slave mode\n"); | ||
971 | return -EINVAL; | ||
972 | } | ||
973 | mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE; | ||
953 | break; | 974 | break; |
954 | default: | 975 | default: |
955 | arizona_aif_err(dai, "Unsupported DAI format %d\n", | 976 | arizona_aif_err(dai, "Unsupported DAI format %d\n", |
@@ -1164,13 +1185,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, | |||
1164 | { 0x80, 0x0 }, | 1185 | { 0x80, 0x0 }, |
1165 | }; | 1186 | }; |
1166 | 1187 | ||
1167 | mutex_lock(&codec->mutex); | 1188 | mutex_lock(&arizona->dac_comp_lock); |
1168 | 1189 | ||
1169 | dac_comp[1].def = arizona->dac_comp_coeff; | 1190 | dac_comp[1].def = arizona->dac_comp_coeff; |
1170 | if (rate >= 176400) | 1191 | if (rate >= 176400) |
1171 | dac_comp[2].def = arizona->dac_comp_enabled; | 1192 | dac_comp[2].def = arizona->dac_comp_enabled; |
1172 | 1193 | ||
1173 | mutex_unlock(&codec->mutex); | 1194 | mutex_unlock(&arizona->dac_comp_lock); |
1174 | 1195 | ||
1175 | regmap_multi_reg_write(arizona->regmap, | 1196 | regmap_multi_reg_write(arizona->regmap, |
1176 | dac_comp, | 1197 | dac_comp, |
@@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1298 | 1319 | ||
1299 | /* Force multiple of 2 channels for I2S mode */ | 1320 | /* Force multiple of 2 channels for I2S mode */ |
1300 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); | 1321 | val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT); |
1301 | if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) { | 1322 | val &= ARIZONA_AIF1_FMT_MASK; |
1323 | if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) { | ||
1302 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); | 1324 | arizona_aif_dbg(dai, "Forcing stereo mode\n"); |
1303 | bclk_target /= channels; | 1325 | bclk_target /= channels; |
1304 | bclk_target *= channels + 1; | 1326 | bclk_target *= channels + 1; |
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c index 537327c7f7f1..8d638e8aa8eb 100644 --- a/sound/soc/codecs/cq93vc.c +++ b/sound/soc/codecs/cq93vc.c | |||
@@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute) | |||
62 | static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai, | 62 | static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai, |
63 | int clk_id, unsigned int freq, int dir) | 63 | int clk_id, unsigned int freq, int dir) |
64 | { | 64 | { |
65 | struct snd_soc_codec *codec = codec_dai->codec; | ||
66 | struct davinci_vc *davinci_vc = codec->dev->platform_data; | ||
67 | |||
68 | switch (freq) { | 65 | switch (freq) { |
69 | case 22579200: | 66 | case 22579200: |
70 | case 27000000: | 67 | case 27000000: |
71 | case 33868800: | 68 | case 33868800: |
72 | davinci_vc->cq93vc.sysclk = freq; | ||
73 | return 0; | 69 | return 0; |
74 | } | 70 | } |
75 | 71 | ||
@@ -126,32 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = { | |||
126 | .ops = &cq93vc_dai_ops, | 122 | .ops = &cq93vc_dai_ops, |
127 | }; | 123 | }; |
128 | 124 | ||
129 | static int cq93vc_resume(struct snd_soc_codec *codec) | ||
130 | { | ||
131 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int cq93vc_probe(struct snd_soc_codec *codec) | ||
137 | { | ||
138 | struct davinci_vc *davinci_vc = codec->dev->platform_data; | ||
139 | |||
140 | davinci_vc->cq93vc.codec = codec; | ||
141 | |||
142 | /* Off, with power on */ | ||
143 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int cq93vc_remove(struct snd_soc_codec *codec) | ||
149 | { | ||
150 | cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static struct regmap *cq93vc_get_regmap(struct device *dev) | 125 | static struct regmap *cq93vc_get_regmap(struct device *dev) |
156 | { | 126 | { |
157 | struct davinci_vc *davinci_vc = dev->platform_data; | 127 | struct davinci_vc *davinci_vc = dev->platform_data; |
@@ -161,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev) | |||
161 | 131 | ||
162 | static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { | 132 | static struct snd_soc_codec_driver soc_codec_dev_cq93vc = { |
163 | .set_bias_level = cq93vc_set_bias_level, | 133 | .set_bias_level = cq93vc_set_bias_level, |
164 | .probe = cq93vc_probe, | ||
165 | .remove = cq93vc_remove, | ||
166 | .resume = cq93vc_resume, | ||
167 | .get_regmap = cq93vc_get_regmap, | 134 | .get_regmap = cq93vc_get_regmap, |
168 | .controls = cq93vc_snd_controls, | 135 | .controls = cq93vc_snd_controls, |
169 | .num_controls = ARRAY_SIZE(cq93vc_snd_controls), | 136 | .num_controls = ARRAY_SIZE(cq93vc_snd_controls), |
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 4fdd47d700e3..ce6086835ebd 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #include "cs4265.h" | 32 | #include "cs4265.h" |
33 | 33 | ||
34 | struct cs4265_private { | 34 | struct cs4265_private { |
35 | struct device *dev; | ||
36 | struct regmap *regmap; | 35 | struct regmap *regmap; |
37 | struct gpio_desc *reset_gpio; | 36 | struct gpio_desc *reset_gpio; |
38 | u8 format; | 37 | u8 format; |
@@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client, | |||
598 | GFP_KERNEL); | 597 | GFP_KERNEL); |
599 | if (cs4265 == NULL) | 598 | if (cs4265 == NULL) |
600 | return -ENOMEM; | 599 | return -ENOMEM; |
601 | cs4265->dev = &i2c_client->dev; | ||
602 | 600 | ||
603 | cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); | 601 | cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap); |
604 | if (IS_ERR(cs4265->regmap)) { | 602 | if (IS_ERR(cs4265->regmap)) { |
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c new file mode 100644 index 000000000000..b264da030340 --- /dev/null +++ b/sound/soc/codecs/cs4271-i2c.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * CS4271 I2C audio driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
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 | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "cs4271.h" | ||
22 | |||
23 | static int cs4271_i2c_probe(struct i2c_client *client, | ||
24 | const struct i2c_device_id *id) | ||
25 | { | ||
26 | struct regmap_config config; | ||
27 | |||
28 | config = cs4271_regmap_config; | ||
29 | config.reg_bits = 8; | ||
30 | config.val_bits = 8; | ||
31 | |||
32 | return cs4271_probe(&client->dev, | ||
33 | devm_regmap_init_i2c(client, &config)); | ||
34 | } | ||
35 | |||
36 | static int cs4271_i2c_remove(struct i2c_client *client) | ||
37 | { | ||
38 | snd_soc_unregister_codec(&client->dev); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
43 | { "cs4271", 0 }, | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
47 | |||
48 | static struct i2c_driver cs4271_i2c_driver = { | ||
49 | .driver = { | ||
50 | .name = "cs4271", | ||
51 | .owner = THIS_MODULE, | ||
52 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
53 | }, | ||
54 | .probe = cs4271_i2c_probe, | ||
55 | .remove = cs4271_i2c_remove, | ||
56 | .id_table = cs4271_i2c_id, | ||
57 | }; | ||
58 | module_i2c_driver(cs4271_i2c_driver); | ||
59 | |||
60 | MODULE_DESCRIPTION("ASoC CS4271 I2C Driver"); | ||
61 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
62 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c new file mode 100644 index 000000000000..acd49d86e706 --- /dev/null +++ b/sound/soc/codecs/cs4271-spi.c | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * CS4271 SPI audio driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
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 | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "cs4271.h" | ||
22 | |||
23 | static int cs4271_spi_probe(struct spi_device *spi) | ||
24 | { | ||
25 | struct regmap_config config; | ||
26 | |||
27 | config = cs4271_regmap_config; | ||
28 | config.reg_bits = 16; | ||
29 | config.val_bits = 8; | ||
30 | config.read_flag_mask = 0x21; | ||
31 | config.write_flag_mask = 0x20; | ||
32 | |||
33 | return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
34 | } | ||
35 | |||
36 | static int cs4271_spi_remove(struct spi_device *spi) | ||
37 | { | ||
38 | snd_soc_unregister_codec(&spi->dev); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static struct spi_driver cs4271_spi_driver = { | ||
43 | .driver = { | ||
44 | .name = "cs4271", | ||
45 | .owner = THIS_MODULE, | ||
46 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
47 | }, | ||
48 | .probe = cs4271_spi_probe, | ||
49 | .remove = cs4271_spi_remove, | ||
50 | }; | ||
51 | module_spi_driver(cs4271_spi_driver); | ||
52 | |||
53 | MODULE_DESCRIPTION("ASoC CS4271 SPI Driver"); | ||
54 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
55 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index 93cec52f4733..79a4efcb894c 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
@@ -23,8 +23,6 @@ | |||
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/gpio.h> | 25 | #include <linux/gpio.h> |
26 | #include <linux/i2c.h> | ||
27 | #include <linux/spi/spi.h> | ||
28 | #include <linux/of.h> | 26 | #include <linux/of.h> |
29 | #include <linux/of_device.h> | 27 | #include <linux/of_device.h> |
30 | #include <linux/of_gpio.h> | 28 | #include <linux/of_gpio.h> |
@@ -32,6 +30,7 @@ | |||
32 | #include <sound/soc.h> | 30 | #include <sound/soc.h> |
33 | #include <sound/tlv.h> | 31 | #include <sound/tlv.h> |
34 | #include <sound/cs4271.h> | 32 | #include <sound/cs4271.h> |
33 | #include "cs4271.h" | ||
35 | 34 | ||
36 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | 35 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ |
37 | SNDRV_PCM_FMTBIT_S24_LE | \ | 36 | SNDRV_PCM_FMTBIT_S24_LE | \ |
@@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec) | |||
527 | #endif /* CONFIG_PM */ | 526 | #endif /* CONFIG_PM */ |
528 | 527 | ||
529 | #ifdef CONFIG_OF | 528 | #ifdef CONFIG_OF |
530 | static const struct of_device_id cs4271_dt_ids[] = { | 529 | const struct of_device_id cs4271_dt_ids[] = { |
531 | { .compatible = "cirrus,cs4271", }, | 530 | { .compatible = "cirrus,cs4271", }, |
532 | { } | 531 | { } |
533 | }; | 532 | }; |
534 | MODULE_DEVICE_TABLE(of, cs4271_dt_ids); | 533 | MODULE_DEVICE_TABLE(of, cs4271_dt_ids); |
534 | EXPORT_SYMBOL_GPL(cs4271_dt_ids); | ||
535 | #endif | 535 | #endif |
536 | 536 | ||
537 | static int cs4271_probe(struct snd_soc_codec *codec) | 537 | static int cs4271_codec_probe(struct snd_soc_codec *codec) |
538 | { | 538 | { |
539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | 540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; |
@@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
587 | return 0; | 587 | return 0; |
588 | } | 588 | } |
589 | 589 | ||
590 | static int cs4271_remove(struct snd_soc_codec *codec) | 590 | static int cs4271_codec_remove(struct snd_soc_codec *codec) |
591 | { | 591 | { |
592 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 592 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
593 | 593 | ||
@@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec) | |||
599 | }; | 599 | }; |
600 | 600 | ||
601 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | 601 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { |
602 | .probe = cs4271_probe, | 602 | .probe = cs4271_codec_probe, |
603 | .remove = cs4271_remove, | 603 | .remove = cs4271_codec_remove, |
604 | .suspend = cs4271_soc_suspend, | 604 | .suspend = cs4271_soc_suspend, |
605 | .resume = cs4271_soc_resume, | 605 | .resume = cs4271_soc_resume, |
606 | 606 | ||
@@ -642,14 +642,8 @@ static int cs4271_common_probe(struct device *dev, | |||
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
644 | 644 | ||
645 | #if defined(CONFIG_SPI_MASTER) | 645 | const struct regmap_config cs4271_regmap_config = { |
646 | |||
647 | static const struct regmap_config cs4271_spi_regmap = { | ||
648 | .reg_bits = 16, | ||
649 | .val_bits = 8, | ||
650 | .max_register = CS4271_LASTREG, | 646 | .max_register = CS4271_LASTREG, |
651 | .read_flag_mask = 0x21, | ||
652 | .write_flag_mask = 0x20, | ||
653 | 647 | ||
654 | .reg_defaults = cs4271_reg_defaults, | 648 | .reg_defaults = cs4271_reg_defaults, |
655 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), | 649 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), |
@@ -657,140 +651,27 @@ static const struct regmap_config cs4271_spi_regmap = { | |||
657 | 651 | ||
658 | .volatile_reg = cs4271_volatile_reg, | 652 | .volatile_reg = cs4271_volatile_reg, |
659 | }; | 653 | }; |
654 | EXPORT_SYMBOL_GPL(cs4271_regmap_config); | ||
660 | 655 | ||
661 | static int cs4271_spi_probe(struct spi_device *spi) | 656 | int cs4271_probe(struct device *dev, struct regmap *regmap) |
662 | { | 657 | { |
663 | struct cs4271_private *cs4271; | 658 | struct cs4271_private *cs4271; |
664 | int ret; | 659 | int ret; |
665 | 660 | ||
666 | ret = cs4271_common_probe(&spi->dev, &cs4271); | 661 | if (IS_ERR(regmap)) |
667 | if (ret < 0) | 662 | return PTR_ERR(regmap); |
668 | return ret; | ||
669 | |||
670 | spi_set_drvdata(spi, cs4271); | ||
671 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); | ||
672 | if (IS_ERR(cs4271->regmap)) | ||
673 | return PTR_ERR(cs4271->regmap); | ||
674 | |||
675 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, | ||
676 | &cs4271_dai, 1); | ||
677 | } | ||
678 | |||
679 | static int cs4271_spi_remove(struct spi_device *spi) | ||
680 | { | ||
681 | snd_soc_unregister_codec(&spi->dev); | ||
682 | return 0; | ||
683 | } | ||
684 | |||
685 | static struct spi_driver cs4271_spi_driver = { | ||
686 | .driver = { | ||
687 | .name = "cs4271", | ||
688 | .owner = THIS_MODULE, | ||
689 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
690 | }, | ||
691 | .probe = cs4271_spi_probe, | ||
692 | .remove = cs4271_spi_remove, | ||
693 | }; | ||
694 | #endif /* defined(CONFIG_SPI_MASTER) */ | ||
695 | |||
696 | #if IS_ENABLED(CONFIG_I2C) | ||
697 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
698 | {"cs4271", 0}, | ||
699 | {} | ||
700 | }; | ||
701 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
702 | 663 | ||
703 | static const struct regmap_config cs4271_i2c_regmap = { | 664 | ret = cs4271_common_probe(dev, &cs4271); |
704 | .reg_bits = 8, | ||
705 | .val_bits = 8, | ||
706 | .max_register = CS4271_LASTREG, | ||
707 | |||
708 | .reg_defaults = cs4271_reg_defaults, | ||
709 | .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults), | ||
710 | .cache_type = REGCACHE_RBTREE, | ||
711 | |||
712 | .volatile_reg = cs4271_volatile_reg, | ||
713 | }; | ||
714 | |||
715 | static int cs4271_i2c_probe(struct i2c_client *client, | ||
716 | const struct i2c_device_id *id) | ||
717 | { | ||
718 | struct cs4271_private *cs4271; | ||
719 | int ret; | ||
720 | |||
721 | ret = cs4271_common_probe(&client->dev, &cs4271); | ||
722 | if (ret < 0) | 665 | if (ret < 0) |
723 | return ret; | 666 | return ret; |
724 | 667 | ||
725 | i2c_set_clientdata(client, cs4271); | 668 | dev_set_drvdata(dev, cs4271); |
726 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); | 669 | cs4271->regmap = regmap; |
727 | if (IS_ERR(cs4271->regmap)) | ||
728 | return PTR_ERR(cs4271->regmap); | ||
729 | 670 | ||
730 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, | 671 | return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai, |
731 | &cs4271_dai, 1); | 672 | 1); |
732 | } | ||
733 | |||
734 | static int cs4271_i2c_remove(struct i2c_client *client) | ||
735 | { | ||
736 | snd_soc_unregister_codec(&client->dev); | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static struct i2c_driver cs4271_i2c_driver = { | ||
741 | .driver = { | ||
742 | .name = "cs4271", | ||
743 | .owner = THIS_MODULE, | ||
744 | .of_match_table = of_match_ptr(cs4271_dt_ids), | ||
745 | }, | ||
746 | .id_table = cs4271_i2c_id, | ||
747 | .probe = cs4271_i2c_probe, | ||
748 | .remove = cs4271_i2c_remove, | ||
749 | }; | ||
750 | #endif /* IS_ENABLED(CONFIG_I2C) */ | ||
751 | |||
752 | /* | ||
753 | * We only register our serial bus driver here without | ||
754 | * assignment to particular chip. So if any of the below | ||
755 | * fails, there is some problem with I2C or SPI subsystem. | ||
756 | * In most cases this module will be compiled with support | ||
757 | * of only one serial bus. | ||
758 | */ | ||
759 | static int __init cs4271_modinit(void) | ||
760 | { | ||
761 | int ret; | ||
762 | |||
763 | #if IS_ENABLED(CONFIG_I2C) | ||
764 | ret = i2c_add_driver(&cs4271_i2c_driver); | ||
765 | if (ret) { | ||
766 | pr_err("Failed to register CS4271 I2C driver: %d\n", ret); | ||
767 | return ret; | ||
768 | } | ||
769 | #endif | ||
770 | |||
771 | #if defined(CONFIG_SPI_MASTER) | ||
772 | ret = spi_register_driver(&cs4271_spi_driver); | ||
773 | if (ret) { | ||
774 | pr_err("Failed to register CS4271 SPI driver: %d\n", ret); | ||
775 | return ret; | ||
776 | } | ||
777 | #endif | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | module_init(cs4271_modinit); | ||
782 | |||
783 | static void __exit cs4271_modexit(void) | ||
784 | { | ||
785 | #if defined(CONFIG_SPI_MASTER) | ||
786 | spi_unregister_driver(&cs4271_spi_driver); | ||
787 | #endif | ||
788 | |||
789 | #if IS_ENABLED(CONFIG_I2C) | ||
790 | i2c_del_driver(&cs4271_i2c_driver); | ||
791 | #endif | ||
792 | } | 673 | } |
793 | module_exit(cs4271_modexit); | 674 | EXPORT_SYMBOL_GPL(cs4271_probe); |
794 | 675 | ||
795 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | 676 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); |
796 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); | 677 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); |
diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h new file mode 100644 index 000000000000..9adad8eefdc9 --- /dev/null +++ b/sound/soc/codecs/cs4271.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifndef _CS4271_PRIV_H | ||
2 | #define _CS4271_PRIV_H | ||
3 | |||
4 | #include <linux/regmap.h> | ||
5 | |||
6 | extern const struct of_device_id cs4271_dt_ids[]; | ||
7 | extern const struct regmap_config cs4271_regmap_config; | ||
8 | |||
9 | int cs4271_probe(struct device *dev, struct regmap *regmap); | ||
10 | |||
11 | #endif | ||
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 669c38fc3034..b3951524339f 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = { | |||
153 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, | 153 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, |
154 | struct snd_kcontrol *kcontrol, int event) | 154 | struct snd_kcontrol *kcontrol, int event) |
155 | { | 155 | { |
156 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
157 | |||
156 | switch (event) { | 158 | switch (event) { |
157 | case SND_SOC_DAPM_PRE_PMD: | 159 | case SND_SOC_DAPM_PRE_PMD: |
158 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | 160 | snd_soc_update_bits(codec, CS42L51_POWER_CTL1, |
159 | CS42L51_POWER_CTL1_PDN, | 161 | CS42L51_POWER_CTL1_PDN, |
160 | CS42L51_POWER_CTL1_PDN); | 162 | CS42L51_POWER_CTL1_PDN); |
161 | break; | 163 | break; |
162 | default: | 164 | default: |
163 | case SND_SOC_DAPM_POST_PMD: | 165 | case SND_SOC_DAPM_POST_PMD: |
164 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | 166 | snd_soc_update_bits(codec, CS42L51_POWER_CTL1, |
165 | CS42L51_POWER_CTL1_PDN, 0); | 167 | CS42L51_POWER_CTL1_PDN, 0); |
166 | break; | 168 | break; |
167 | } | 169 | } |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 2f8b94683e83..7c55537c69cf 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { | |||
584 | static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, | 584 | static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, |
585 | struct snd_kcontrol *kcontrol, int event) | 585 | struct snd_kcontrol *kcontrol, int event) |
586 | { | 586 | { |
587 | struct snd_soc_codec *codec = w->codec; | 587 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
588 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 588 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
589 | switch (event) { | 589 | switch (event) { |
590 | case SND_SOC_DAPM_POST_PMD: | 590 | case SND_SOC_DAPM_POST_PMD: |
@@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w, | |||
600 | static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, | 600 | static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, |
601 | struct snd_kcontrol *kcontrol, int event) | 601 | struct snd_kcontrol *kcontrol, int event) |
602 | { | 602 | { |
603 | struct snd_soc_codec *codec = w->codec; | 603 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
604 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 604 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
605 | switch (event) { | 605 | switch (event) { |
606 | case SND_SOC_DAPM_POST_PMD: | 606 | case SND_SOC_DAPM_POST_PMD: |
@@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w, | |||
618 | static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, | 618 | static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w, |
619 | struct snd_kcontrol *kcontrol, int event) | 619 | struct snd_kcontrol *kcontrol, int event) |
620 | { | 620 | { |
621 | struct snd_soc_codec *codec = w->codec; | 621 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
622 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); | 622 | struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec); |
623 | switch (event) { | 623 | switch (event) { |
624 | case SND_SOC_DAPM_POST_PMD: | 624 | case SND_SOC_DAPM_POST_PMD: |
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c index 1087fd5f9917..1391ad50f95d 100644 --- a/sound/soc/codecs/hdmi.c +++ b/sound/soc/codecs/hdmi.c | |||
@@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = { | |||
47 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, | 47 | SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, |
48 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | 48 | .formats = SNDRV_PCM_FMTBIT_S16_LE | |
49 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, | 49 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE, |
50 | .sig_bits = 24, | ||
50 | }, | 51 | }, |
51 | .capture = { | 52 | .capture = { |
52 | .stream_name = "Capture", | 53 | .stream_name = "Capture", |
@@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = { | |||
75 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), | 76 | .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), |
76 | .dapm_routes = hdmi_routes, | 77 | .dapm_routes = hdmi_routes, |
77 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), | 78 | .num_dapm_routes = ARRAY_SIZE(hdmi_routes), |
79 | .ignore_pmdown_time = true, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static int hdmi_codec_probe(struct platform_device *pdev) | 82 | static int hdmi_codec_probe(struct platform_device *pdev) |
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index c1ae5764983f..c4dfde9bdf1c 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = { | |||
1395 | }, | 1395 | }, |
1396 | }; | 1396 | }; |
1397 | 1397 | ||
1398 | /* power down chip */ | ||
1399 | static int lm49453_remove(struct snd_soc_codec *codec) | ||
1400 | { | ||
1401 | lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1402 | return 0; | ||
1403 | } | ||
1404 | |||
1405 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { | 1398 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { |
1406 | .remove = lm49453_remove, | ||
1407 | .set_bias_level = lm49453_set_bias_level, | 1399 | .set_bias_level = lm49453_set_bias_level, |
1408 | .controls = lm49453_snd_controls, | 1400 | .controls = lm49453_snd_controls, |
1409 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), | 1401 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), |
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 2cd3e5427441..805b3f8cd39d 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = { | |||
875 | static int max98088_mic_event(struct snd_soc_dapm_widget *w, | 875 | static int max98088_mic_event(struct snd_soc_dapm_widget *w, |
876 | struct snd_kcontrol *kcontrol, int event) | 876 | struct snd_kcontrol *kcontrol, int event) |
877 | { | 877 | { |
878 | struct snd_soc_codec *codec = w->codec; | 878 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
879 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 879 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
880 | 880 | ||
881 | switch (event) { | 881 | switch (event) { |
@@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w, | |||
905 | static int max98088_line_pga(struct snd_soc_dapm_widget *w, | 905 | static int max98088_line_pga(struct snd_soc_dapm_widget *w, |
906 | int event, int line, u8 channel) | 906 | int event, int line, u8 channel) |
907 | { | 907 | { |
908 | struct snd_soc_codec *codec = w->codec; | 908 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
909 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 909 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
910 | u8 *state; | 910 | u8 *state; |
911 | 911 | ||
@@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec) | |||
1887 | max98088_handle_eq_pdata(codec); | 1887 | max98088_handle_eq_pdata(codec); |
1888 | } | 1888 | } |
1889 | 1889 | ||
1890 | #ifdef CONFIG_PM | ||
1891 | static int max98088_suspend(struct snd_soc_codec *codec) | ||
1892 | { | ||
1893 | max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1894 | |||
1895 | return 0; | ||
1896 | } | ||
1897 | |||
1898 | static int max98088_resume(struct snd_soc_codec *codec) | ||
1899 | { | ||
1900 | max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1901 | |||
1902 | return 0; | ||
1903 | } | ||
1904 | #else | ||
1905 | #define max98088_suspend NULL | ||
1906 | #define max98088_resume NULL | ||
1907 | #endif | ||
1908 | |||
1909 | static int max98088_probe(struct snd_soc_codec *codec) | 1890 | static int max98088_probe(struct snd_soc_codec *codec) |
1910 | { | 1891 | { |
1911 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 1892 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
@@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec) | |||
1946 | 1927 | ||
1947 | snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); | 1928 | snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); |
1948 | 1929 | ||
1949 | /* initialize registers cache to hardware default */ | ||
1950 | max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1951 | |||
1952 | snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00); | 1930 | snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00); |
1953 | 1931 | ||
1954 | snd_soc_write(codec, M98088_REG_22_MIX_DAC, | 1932 | snd_soc_write(codec, M98088_REG_22_MIX_DAC, |
@@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec) | |||
1974 | { | 1952 | { |
1975 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); | 1953 | struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); |
1976 | 1954 | ||
1977 | max98088_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1978 | kfree(max98088->eq_texts); | 1955 | kfree(max98088->eq_texts); |
1979 | 1956 | ||
1980 | return 0; | 1957 | return 0; |
@@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec) | |||
1983 | static struct snd_soc_codec_driver soc_codec_dev_max98088 = { | 1960 | static struct snd_soc_codec_driver soc_codec_dev_max98088 = { |
1984 | .probe = max98088_probe, | 1961 | .probe = max98088_probe, |
1985 | .remove = max98088_remove, | 1962 | .remove = max98088_remove, |
1986 | .suspend = max98088_suspend, | ||
1987 | .resume = max98088_resume, | ||
1988 | .set_bias_level = max98088_set_bias_level, | 1963 | .set_bias_level = max98088_set_bias_level, |
1964 | .suspend_bias_off = true, | ||
1965 | |||
1989 | .controls = max98088_snd_controls, | 1966 | .controls = max98088_snd_controls, |
1990 | .num_controls = ARRAY_SIZE(max98088_snd_controls), | 1967 | .num_controls = ARRAY_SIZE(max98088_snd_controls), |
1991 | .dapm_widgets = max98088_dapm_widgets, | 1968 | .dapm_widgets = max98088_dapm_widgets, |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 1229554f1464..151f718241ea 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = { | |||
806 | static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | 806 | static int max98090_micinput_event(struct snd_soc_dapm_widget *w, |
807 | struct snd_kcontrol *kcontrol, int event) | 807 | struct snd_kcontrol *kcontrol, int event) |
808 | { | 808 | { |
809 | struct snd_soc_codec *codec = w->codec; | 809 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
810 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 810 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
811 | 811 | ||
812 | unsigned int val = snd_soc_read(codec, w->reg); | 812 | unsigned int val = snd_soc_read(codec, w->reg); |
@@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1311 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
1312 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
1313 | 1313 | ||
1314 | {"DMICL", NULL, "DMICL_ENA"}, | ||
1315 | {"DMICL", NULL, "DMICR_ENA"}, | ||
1316 | {"DMICR", NULL, "DMICL_ENA"}, | ||
1317 | {"DMICR", NULL, "DMICR_ENA"}, | ||
1314 | {"DMICL", NULL, "AHPF"}, | 1318 | {"DMICL", NULL, "AHPF"}, |
1315 | {"DMICR", NULL, "AHPF"}, | 1319 | {"DMICR", NULL, "AHPF"}, |
1316 | 1320 | ||
@@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1368 | {"DMIC Mux", "ADC", "ADCR"}, | 1372 | {"DMIC Mux", "ADC", "ADCR"}, |
1369 | {"DMIC Mux", "DMIC", "DMICL"}, | 1373 | {"DMIC Mux", "DMIC", "DMICL"}, |
1370 | {"DMIC Mux", "DMIC", "DMICR"}, | 1374 | {"DMIC Mux", "DMIC", "DMICR"}, |
1371 | {"DMIC Mux", "DMIC", "DMICL_ENA"}, | ||
1372 | {"DMIC Mux", "DMIC", "DMICR_ENA"}, | ||
1373 | 1375 | ||
1374 | {"LBENL Mux", "Normal", "DMIC Mux"}, | 1376 | {"LBENL Mux", "Normal", "DMIC Mux"}, |
1375 | {"LBENL Mux", "Loopback", "LTENL Mux"}, | 1377 | {"LBENL Mux", "Loopback", "LTENL Mux"}, |
@@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1395 | {"STENL Mux", "Sidetone Left", "DMICL"}, | 1397 | {"STENL Mux", "Sidetone Left", "DMICL"}, |
1396 | {"STENR Mux", "Sidetone Right", "ADCR"}, | 1398 | {"STENR Mux", "Sidetone Right", "ADCR"}, |
1397 | {"STENR Mux", "Sidetone Right", "DMICR"}, | 1399 | {"STENR Mux", "Sidetone Right", "DMICR"}, |
1398 | {"DACL", "NULL", "STENL Mux"}, | 1400 | {"DACL", NULL, "STENL Mux"}, |
1399 | {"DACR", "NULL", "STENL Mux"}, | 1401 | {"DACR", NULL, "STENR Mux"}, |
1400 | 1402 | ||
1401 | {"AIFINL", NULL, "SHDN"}, | 1403 | {"AIFINL", NULL, "SHDN"}, |
1402 | {"AIFINR", NULL, "SHDN"}, | 1404 | {"AIFINR", NULL, "SHDN"}, |
@@ -1826,27 +1828,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1826 | return 0; | 1828 | return 0; |
1827 | } | 1829 | } |
1828 | 1830 | ||
1829 | static const int comp_pclk_rates[] = { | 1831 | static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 }; |
1830 | 11289600, 12288000, 12000000, 13000000, 19200000 | ||
1831 | }; | ||
1832 | |||
1833 | static const int dmic_micclk[] = { | ||
1834 | 2, 2, 2, 2, 4, 2 | ||
1835 | }; | ||
1836 | 1832 | ||
1837 | static const int comp_lrclk_rates[] = { | 1833 | static const int comp_lrclk_rates[] = { |
1838 | 8000, 16000, 32000, 44100, 48000, 96000 | 1834 | 8000, 16000, 32000, 44100, 48000, 96000 |
1839 | }; | 1835 | }; |
1840 | 1836 | ||
1841 | static const int dmic_comp[6][6] = { | 1837 | struct dmic_table { |
1842 | {7, 8, 3, 3, 3, 3}, | 1838 | int pclk; |
1843 | {7, 8, 3, 3, 3, 3}, | 1839 | struct { |
1844 | {7, 8, 3, 3, 3, 3}, | 1840 | int freq; |
1845 | {7, 8, 3, 1, 1, 1}, | 1841 | int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */ |
1846 | {7, 8, 3, 1, 2, 2}, | 1842 | } settings[6]; /* One for each dmic divisor. */ |
1847 | {7, 8, 3, 3, 3, 3} | ||
1848 | }; | 1843 | }; |
1849 | 1844 | ||
1845 | static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */ | ||
1846 | { | ||
1847 | .pclk = 11289600, | ||
1848 | .settings = { | ||
1849 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1850 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1851 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1852 | { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, | ||
1853 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1854 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1855 | }, | ||
1856 | }, | ||
1857 | { | ||
1858 | .pclk = 12000000, | ||
1859 | .settings = { | ||
1860 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1861 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1862 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1863 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1864 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1865 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1866 | } | ||
1867 | }, | ||
1868 | { | ||
1869 | .pclk = 12288000, | ||
1870 | .settings = { | ||
1871 | { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1872 | { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } }, | ||
1873 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1874 | { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } }, | ||
1875 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1876 | { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } }, | ||
1877 | } | ||
1878 | }, | ||
1879 | { | ||
1880 | .pclk = 13000000, | ||
1881 | .settings = { | ||
1882 | { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1883 | { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } }, | ||
1884 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1885 | { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } }, | ||
1886 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1887 | { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1888 | } | ||
1889 | }, | ||
1890 | { | ||
1891 | .pclk = 19200000, | ||
1892 | .settings = { | ||
1893 | { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } }, | ||
1894 | { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } }, | ||
1895 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1896 | { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } }, | ||
1897 | { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } }, | ||
1898 | { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } }, | ||
1899 | } | ||
1900 | }, | ||
1901 | }; | ||
1902 | |||
1903 | static int max98090_find_divisor(int target_freq, int pclk) | ||
1904 | { | ||
1905 | int current_diff = INT_MAX; | ||
1906 | int test_diff = INT_MAX; | ||
1907 | int divisor_index = 0; | ||
1908 | int i; | ||
1909 | |||
1910 | for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) { | ||
1911 | test_diff = abs(target_freq - (pclk / dmic_divisors[i])); | ||
1912 | if (test_diff < current_diff) { | ||
1913 | current_diff = test_diff; | ||
1914 | divisor_index = i; | ||
1915 | } | ||
1916 | } | ||
1917 | |||
1918 | return divisor_index; | ||
1919 | } | ||
1920 | |||
1921 | static int max98090_find_closest_pclk(int pclk) | ||
1922 | { | ||
1923 | int m1; | ||
1924 | int m2; | ||
1925 | int i; | ||
1926 | |||
1927 | for (i = 0; i < ARRAY_SIZE(dmic_table); i++) { | ||
1928 | if (pclk == dmic_table[i].pclk) | ||
1929 | return i; | ||
1930 | if (pclk < dmic_table[i].pclk) { | ||
1931 | if (i == 0) | ||
1932 | return i; | ||
1933 | m1 = pclk - dmic_table[i-1].pclk; | ||
1934 | m2 = dmic_table[i].pclk - pclk; | ||
1935 | if (m1 < m2) | ||
1936 | return i - 1; | ||
1937 | else | ||
1938 | return i; | ||
1939 | } | ||
1940 | } | ||
1941 | |||
1942 | return -EINVAL; | ||
1943 | } | ||
1944 | |||
1945 | static int max98090_configure_dmic(struct max98090_priv *max98090, | ||
1946 | int target_dmic_clk, int pclk, int fs) | ||
1947 | { | ||
1948 | int micclk_index; | ||
1949 | int pclk_index; | ||
1950 | int dmic_freq; | ||
1951 | int dmic_comp; | ||
1952 | int i; | ||
1953 | |||
1954 | pclk_index = max98090_find_closest_pclk(pclk); | ||
1955 | if (pclk_index < 0) | ||
1956 | return pclk_index; | ||
1957 | |||
1958 | micclk_index = max98090_find_divisor(target_dmic_clk, pclk); | ||
1959 | |||
1960 | for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { | ||
1961 | if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2) | ||
1962 | break; | ||
1963 | } | ||
1964 | |||
1965 | dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq; | ||
1966 | dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i]; | ||
1967 | |||
1968 | regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE, | ||
1969 | M98090_MICCLK_MASK, | ||
1970 | micclk_index << M98090_MICCLK_SHIFT); | ||
1971 | |||
1972 | regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG, | ||
1973 | M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK, | ||
1974 | dmic_comp << M98090_DMIC_COMP_SHIFT | | ||
1975 | dmic_freq << M98090_DMIC_FREQ_SHIFT); | ||
1976 | |||
1977 | return 0; | ||
1978 | } | ||
1979 | |||
1850 | static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | 1980 | static int max98090_dai_hw_params(struct snd_pcm_substream *substream, |
1851 | struct snd_pcm_hw_params *params, | 1981 | struct snd_pcm_hw_params *params, |
1852 | struct snd_soc_dai *dai) | 1982 | struct snd_soc_dai *dai) |
@@ -1854,7 +1984,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | |||
1854 | struct snd_soc_codec *codec = dai->codec; | 1984 | struct snd_soc_codec *codec = dai->codec; |
1855 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 1985 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
1856 | struct max98090_cdata *cdata; | 1986 | struct max98090_cdata *cdata; |
1857 | int i, j; | ||
1858 | 1987 | ||
1859 | cdata = &max98090->dai[0]; | 1988 | cdata = &max98090->dai[0]; |
1860 | max98090->bclk = snd_soc_params_to_bclk(params); | 1989 | max98090->bclk = snd_soc_params_to_bclk(params); |
@@ -1893,27 +2022,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream, | |||
1893 | snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, | 2022 | snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG, |
1894 | M98090_DHF_MASK, M98090_DHF_MASK); | 2023 | M98090_DHF_MASK, M98090_DHF_MASK); |
1895 | 2024 | ||
1896 | /* Check for supported PCLK to LRCLK ratios */ | 2025 | max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk, |
1897 | for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) { | 2026 | max98090->lrclk); |
1898 | if (comp_pclk_rates[j] == max98090->sysclk) { | ||
1899 | break; | ||
1900 | } | ||
1901 | } | ||
1902 | |||
1903 | for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) { | ||
1904 | if (max98090->lrclk <= (comp_lrclk_rates[i] + | ||
1905 | comp_lrclk_rates[i + 1]) / 2) { | ||
1906 | break; | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE, | ||
1911 | M98090_MICCLK_MASK, | ||
1912 | dmic_micclk[j] << M98090_MICCLK_SHIFT); | ||
1913 | |||
1914 | snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG, | ||
1915 | M98090_DMIC_COMP_MASK, | ||
1916 | dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT); | ||
1917 | 2027 | ||
1918 | return 0; | 2028 | return 0; |
1919 | } | 2029 | } |
@@ -1944,12 +2054,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai, | |||
1944 | if ((freq >= 10000000) && (freq <= 20000000)) { | 2054 | if ((freq >= 10000000) && (freq <= 20000000)) { |
1945 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2055 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1946 | M98090_PSCLK_DIV1); | 2056 | M98090_PSCLK_DIV1); |
2057 | max98090->pclk = freq; | ||
1947 | } else if ((freq > 20000000) && (freq <= 40000000)) { | 2058 | } else if ((freq > 20000000) && (freq <= 40000000)) { |
1948 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2059 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1949 | M98090_PSCLK_DIV2); | 2060 | M98090_PSCLK_DIV2); |
2061 | max98090->pclk = freq >> 1; | ||
1950 | } else if ((freq > 40000000) && (freq <= 60000000)) { | 2062 | } else if ((freq > 40000000) && (freq <= 60000000)) { |
1951 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, | 2063 | snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK, |
1952 | M98090_PSCLK_DIV4); | 2064 | M98090_PSCLK_DIV4); |
2065 | max98090->pclk = freq >> 2; | ||
1953 | } else { | 2066 | } else { |
1954 | dev_err(codec->dev, "Invalid master clock frequency\n"); | 2067 | dev_err(codec->dev, "Invalid master clock frequency\n"); |
1955 | return -EINVAL; | 2068 | return -EINVAL; |
@@ -2324,6 +2437,7 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2324 | /* Initialize private data */ | 2437 | /* Initialize private data */ |
2325 | 2438 | ||
2326 | max98090->sysclk = (unsigned)-1; | 2439 | max98090->sysclk = (unsigned)-1; |
2440 | max98090->pclk = (unsigned)-1; | ||
2327 | max98090->master = false; | 2441 | max98090->master = false; |
2328 | 2442 | ||
2329 | cdata = &max98090->dai[0]; | 2443 | cdata = &max98090->dai[0]; |
@@ -2463,6 +2577,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c, | |||
2463 | i2c_set_clientdata(i2c, max98090); | 2577 | i2c_set_clientdata(i2c, max98090); |
2464 | max98090->pdata = i2c->dev.platform_data; | 2578 | max98090->pdata = i2c->dev.platform_data; |
2465 | 2579 | ||
2580 | ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq", | ||
2581 | &max98090->dmic_freq); | ||
2582 | if (ret < 0) | ||
2583 | max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ; | ||
2584 | |||
2466 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); | 2585 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); |
2467 | if (IS_ERR(max98090->regmap)) { | 2586 | if (IS_ERR(max98090->regmap)) { |
2468 | ret = PTR_ERR(max98090->regmap); | 2587 | ret = PTR_ERR(max98090->regmap); |
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index a5f6bada06da..21ff743f5af2 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h | |||
@@ -12,6 +12,12 @@ | |||
12 | #define _MAX98090_H | 12 | #define _MAX98090_H |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * The default operating frequency for a DMIC attached to the codec. | ||
16 | * This can be overridden by a device tree property. | ||
17 | */ | ||
18 | #define MAX98090_DEFAULT_DMIC_FREQ 2500000 | ||
19 | |||
20 | /* | ||
15 | * MAX98090 Register Definitions | 21 | * MAX98090 Register Definitions |
16 | */ | 22 | */ |
17 | 23 | ||
@@ -1518,8 +1524,10 @@ struct max98090_priv { | |||
1518 | struct max98090_pdata *pdata; | 1524 | struct max98090_pdata *pdata; |
1519 | struct clk *mclk; | 1525 | struct clk *mclk; |
1520 | unsigned int sysclk; | 1526 | unsigned int sysclk; |
1527 | unsigned int pclk; | ||
1521 | unsigned int bclk; | 1528 | unsigned int bclk; |
1522 | unsigned int lrclk; | 1529 | unsigned int lrclk; |
1530 | u32 dmic_freq; | ||
1523 | struct max98090_cdata dai[1]; | 1531 | struct max98090_cdata dai[1]; |
1524 | int jack_state; | 1532 | int jack_state; |
1525 | struct delayed_work jack_work; | 1533 | struct delayed_work jack_work; |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 0ee6797d5083..8fba0c3db798 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/mutex.h> | ||
19 | #include <sound/core.h> | 20 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
21 | #include <sound/pcm_params.h> | 22 | #include <sound/pcm_params.h> |
@@ -57,6 +58,7 @@ struct max98095_priv { | |||
57 | unsigned int mic2pre; | 58 | unsigned int mic2pre; |
58 | struct snd_soc_jack *headphone_jack; | 59 | struct snd_soc_jack *headphone_jack; |
59 | struct snd_soc_jack *mic_jack; | 60 | struct snd_soc_jack *mic_jack; |
61 | struct mutex lock; | ||
60 | }; | 62 | }; |
61 | 63 | ||
62 | static const struct reg_default max98095_reg_def[] = { | 64 | static const struct reg_default max98095_reg_def[] = { |
@@ -864,7 +866,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = { | |||
864 | static int max98095_mic_event(struct snd_soc_dapm_widget *w, | 866 | static int max98095_mic_event(struct snd_soc_dapm_widget *w, |
865 | struct snd_kcontrol *kcontrol, int event) | 867 | struct snd_kcontrol *kcontrol, int event) |
866 | { | 868 | { |
867 | struct snd_soc_codec *codec = w->codec; | 869 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
868 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 870 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
869 | 871 | ||
870 | switch (event) { | 872 | switch (event) { |
@@ -894,7 +896,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w, | |||
894 | static int max98095_line_pga(struct snd_soc_dapm_widget *w, | 896 | static int max98095_line_pga(struct snd_soc_dapm_widget *w, |
895 | int event, u8 channel) | 897 | int event, u8 channel) |
896 | { | 898 | { |
897 | struct snd_soc_codec *codec = w->codec; | 899 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
898 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 900 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
899 | u8 *state; | 901 | u8 *state; |
900 | 902 | ||
@@ -942,7 +944,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w, | |||
942 | static int max98095_lineout_event(struct snd_soc_dapm_widget *w, | 944 | static int max98095_lineout_event(struct snd_soc_dapm_widget *w, |
943 | struct snd_kcontrol *kcontrol, int event) | 945 | struct snd_kcontrol *kcontrol, int event) |
944 | { | 946 | { |
945 | struct snd_soc_codec *codec = w->codec; | 947 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
946 | 948 | ||
947 | switch (event) { | 949 | switch (event) { |
948 | case SND_SOC_DAPM_POST_PMU: | 950 | case SND_SOC_DAPM_POST_PMU: |
@@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, | |||
1803 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); | 1805 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); |
1804 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); | 1806 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); |
1805 | 1807 | ||
1806 | mutex_lock(&codec->mutex); | 1808 | mutex_lock(&max98095->lock); |
1807 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); | 1809 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); |
1808 | m98095_eq_band(codec, channel, 0, coef_set->band1); | 1810 | m98095_eq_band(codec, channel, 0, coef_set->band1); |
1809 | m98095_eq_band(codec, channel, 1, coef_set->band2); | 1811 | m98095_eq_band(codec, channel, 1, coef_set->band2); |
@@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol, | |||
1811 | m98095_eq_band(codec, channel, 3, coef_set->band4); | 1813 | m98095_eq_band(codec, channel, 3, coef_set->band4); |
1812 | m98095_eq_band(codec, channel, 4, coef_set->band5); | 1814 | m98095_eq_band(codec, channel, 4, coef_set->band5); |
1813 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); | 1815 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); |
1814 | mutex_unlock(&codec->mutex); | 1816 | mutex_unlock(&max98095->lock); |
1815 | 1817 | ||
1816 | /* Restore the original on/off state */ | 1818 | /* Restore the original on/off state */ |
1817 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); | 1819 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); |
@@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol, | |||
1957 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); | 1959 | regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL); |
1958 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); | 1960 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0); |
1959 | 1961 | ||
1960 | mutex_lock(&codec->mutex); | 1962 | mutex_lock(&max98095->lock); |
1961 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); | 1963 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG); |
1962 | m98095_biquad_band(codec, channel, 0, coef_set->band1); | 1964 | m98095_biquad_band(codec, channel, 0, coef_set->band1); |
1963 | m98095_biquad_band(codec, channel, 1, coef_set->band2); | 1965 | m98095_biquad_band(codec, channel, 1, coef_set->band2); |
1964 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); | 1966 | snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0); |
1965 | mutex_unlock(&codec->mutex); | 1967 | mutex_unlock(&max98095->lock); |
1966 | 1968 | ||
1967 | /* Restore the original on/off state */ | 1969 | /* Restore the original on/off state */ |
1968 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); | 1970 | snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave); |
@@ -2317,9 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec) | |||
2317 | 2319 | ||
2318 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); | 2320 | snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV); |
2319 | 2321 | ||
2320 | /* initialize registers cache to hardware default */ | ||
2321 | max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2322 | |||
2323 | snd_soc_write(codec, M98095_048_MIX_DAC_LR, | 2322 | snd_soc_write(codec, M98095_048_MIX_DAC_LR, |
2324 | M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); | 2323 | M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR); |
2325 | 2324 | ||
@@ -2359,8 +2358,6 @@ static int max98095_remove(struct snd_soc_codec *codec) | |||
2359 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 2358 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
2360 | struct i2c_client *client = to_i2c_client(codec->dev); | 2359 | struct i2c_client *client = to_i2c_client(codec->dev); |
2361 | 2360 | ||
2362 | max98095_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2363 | |||
2364 | if (max98095->headphone_jack || max98095->mic_jack) | 2361 | if (max98095->headphone_jack || max98095->mic_jack) |
2365 | max98095_jack_detect_disable(codec); | 2362 | max98095_jack_detect_disable(codec); |
2366 | 2363 | ||
@@ -2395,6 +2392,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c, | |||
2395 | if (max98095 == NULL) | 2392 | if (max98095 == NULL) |
2396 | return -ENOMEM; | 2393 | return -ENOMEM; |
2397 | 2394 | ||
2395 | mutex_init(&max98095->lock); | ||
2396 | |||
2398 | max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); | 2397 | max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap); |
2399 | if (IS_ERR(max98095->regmap)) { | 2398 | if (IS_ERR(max98095->regmap)) { |
2400 | ret = PTR_ERR(max98095->regmap); | 2399 | ret = PTR_ERR(max98095->regmap); |
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 4fdf5aaa236f..10f8e47ce2c2 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c | |||
@@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = { | |||
291 | .ops = &max9850_dai_ops, | 291 | .ops = &max9850_dai_ops, |
292 | }; | 292 | }; |
293 | 293 | ||
294 | #ifdef CONFIG_PM | ||
295 | static int max9850_suspend(struct snd_soc_codec *codec) | ||
296 | { | ||
297 | max9850_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int max9850_resume(struct snd_soc_codec *codec) | ||
303 | { | ||
304 | max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | #else | ||
309 | #define max9850_suspend NULL | ||
310 | #define max9850_resume NULL | ||
311 | #endif | ||
312 | |||
313 | static int max9850_probe(struct snd_soc_codec *codec) | 294 | static int max9850_probe(struct snd_soc_codec *codec) |
314 | { | 295 | { |
315 | /* enable zero-detect */ | 296 | /* enable zero-detect */ |
@@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec) | |||
324 | 305 | ||
325 | static struct snd_soc_codec_driver soc_codec_dev_max9850 = { | 306 | static struct snd_soc_codec_driver soc_codec_dev_max9850 = { |
326 | .probe = max9850_probe, | 307 | .probe = max9850_probe, |
327 | .suspend = max9850_suspend, | ||
328 | .resume = max9850_resume, | ||
329 | .set_bias_level = max9850_set_bias_level, | 308 | .set_bias_level = max9850_set_bias_level, |
309 | .suspend_bias_off = true, | ||
330 | 310 | ||
331 | .controls = max9850_controls, | 311 | .controls = max9850_controls, |
332 | .num_controls = ARRAY_SIZE(max9850_controls), | 312 | .num_controls = ARRAY_SIZE(max9850_controls), |
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 4aa555cbcca8..2cd4fe463102 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/dmi.h> | ||
20 | #include <linux/acpi.h> | 21 | #include <linux/acpi.h> |
21 | #include <sound/core.h> | 22 | #include <sound/core.h> |
22 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
@@ -36,11 +37,13 @@ | |||
36 | 37 | ||
37 | struct rt286_priv { | 38 | struct rt286_priv { |
38 | struct regmap *regmap; | 39 | struct regmap *regmap; |
40 | struct snd_soc_codec *codec; | ||
39 | struct rt286_platform_data pdata; | 41 | struct rt286_platform_data pdata; |
40 | struct i2c_client *i2c; | 42 | struct i2c_client *i2c; |
41 | struct snd_soc_jack *jack; | 43 | struct snd_soc_jack *jack; |
42 | struct delayed_work jack_detect_work; | 44 | struct delayed_work jack_detect_work; |
43 | int sys_clk; | 45 | int sys_clk; |
46 | int clk_id; | ||
44 | struct reg_default *index_cache; | 47 | struct reg_default *index_cache; |
45 | }; | 48 | }; |
46 | 49 | ||
@@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | |||
188 | u8 data[4]; | 191 | u8 data[4]; |
189 | int ret, i; | 192 | int ret, i; |
190 | 193 | ||
191 | /*handle index registers*/ | 194 | /* handle index registers */ |
192 | if (reg <= 0xff) { | 195 | if (reg <= 0xff) { |
193 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | 196 | rt286_hw_write(client, RT286_COEF_INDEX, reg); |
194 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | 197 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { |
@@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | |||
231 | __be32 be_reg; | 234 | __be32 be_reg; |
232 | unsigned int index, vid, buf = 0x0; | 235 | unsigned int index, vid, buf = 0x0; |
233 | 236 | ||
234 | /*handle index registers*/ | 237 | /* handle index registers */ |
235 | if (reg <= 0xff) { | 238 | if (reg <= 0xff) { |
236 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | 239 | rt286_hw_write(client, RT286_COEF_INDEX, reg); |
237 | reg = RT286_PROC_COEF; | 240 | reg = RT286_PROC_COEF; |
@@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = { | |||
298 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | 301 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) |
299 | { | 302 | { |
300 | unsigned int val, buf; | 303 | unsigned int val, buf; |
301 | int i; | ||
302 | 304 | ||
303 | *hp = false; | 305 | *hp = false; |
304 | *mic = false; | 306 | *mic = false; |
@@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
309 | if (*hp) { | 311 | if (*hp) { |
310 | /* power on HV,VERF */ | 312 | /* power on HV,VERF */ |
311 | regmap_update_bits(rt286->regmap, | 313 | regmap_update_bits(rt286->regmap, |
312 | RT286_POWER_CTRL1, 0x1001, 0x0); | 314 | RT286_DC_GAIN, 0x200, 0x200); |
315 | |||
316 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | ||
317 | "HV"); | ||
318 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, | ||
319 | "VREF"); | ||
313 | /* power LDO1 */ | 320 | /* power LDO1 */ |
314 | regmap_update_bits(rt286->regmap, | 321 | snd_soc_dapm_force_enable_pin(&rt286->codec->dapm, |
315 | RT286_POWER_CTRL2, 0x4, 0x4); | 322 | "LDO1"); |
316 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); | 323 | snd_soc_dapm_sync(&rt286->codec->dapm); |
317 | regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); | ||
318 | 324 | ||
319 | msleep(200); | 325 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); |
320 | i = 40; | 326 | msleep(50); |
321 | while (((val & 0x0800) == 0) && (i > 0)) { | ||
322 | regmap_read(rt286->regmap, | ||
323 | RT286_CBJ_CTRL2, &val); | ||
324 | i--; | ||
325 | msleep(20); | ||
326 | } | ||
327 | 327 | ||
328 | if (0x0400 == (val & 0x0700)) { | 328 | regmap_update_bits(rt286->regmap, |
329 | *mic = false; | 329 | RT286_CBJ_CTRL1, 0xfcc0, 0xd400); |
330 | msleep(300); | ||
331 | regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); | ||
330 | 332 | ||
331 | regmap_write(rt286->regmap, | 333 | if (0x0070 == (val & 0x0070)) { |
332 | RT286_SET_MIC1, 0x20); | ||
333 | /* power off HV,VERF */ | ||
334 | regmap_update_bits(rt286->regmap, | ||
335 | RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
336 | regmap_update_bits(rt286->regmap, | ||
337 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
338 | regmap_update_bits(rt286->regmap, | ||
339 | RT286_CBJ_CTRL1, 0x0030, 0x0000); | ||
340 | regmap_update_bits(rt286->regmap, | ||
341 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
342 | } else if ((0x0200 == (val & 0x0700)) || | ||
343 | (0x0100 == (val & 0x0700))) { | ||
344 | *mic = true; | 334 | *mic = true; |
345 | regmap_update_bits(rt286->regmap, | ||
346 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
347 | regmap_update_bits(rt286->regmap, | ||
348 | RT286_CBJ_CTRL1, 0x0030, 0x0020); | ||
349 | regmap_update_bits(rt286->regmap, | ||
350 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
351 | } else { | 335 | } else { |
352 | *mic = false; | 336 | regmap_update_bits(rt286->regmap, |
337 | RT286_CBJ_CTRL1, 0xfcc0, 0xe400); | ||
338 | msleep(300); | ||
339 | regmap_read(rt286->regmap, | ||
340 | RT286_CBJ_CTRL2, &val); | ||
341 | if (0x0070 == (val & 0x0070)) | ||
342 | *mic = true; | ||
343 | else | ||
344 | *mic = false; | ||
353 | } | 345 | } |
354 | |||
355 | regmap_update_bits(rt286->regmap, | ||
356 | RT286_MISC_CTRL1, | ||
357 | 0x0060, 0x0000); | ||
358 | } else { | ||
359 | regmap_update_bits(rt286->regmap, | ||
360 | RT286_MISC_CTRL1, | ||
361 | 0x0060, 0x0020); | ||
362 | regmap_update_bits(rt286->regmap, | 346 | regmap_update_bits(rt286->regmap, |
363 | RT286_A_BIAS_CTRL3, | 347 | RT286_DC_GAIN, 0x200, 0x0); |
364 | 0xc000, 0x8000); | ||
365 | regmap_update_bits(rt286->regmap, | ||
366 | RT286_CBJ_CTRL1, | ||
367 | 0x0030, 0x0020); | ||
368 | regmap_update_bits(rt286->regmap, | ||
369 | RT286_A_BIAS_CTRL2, | ||
370 | 0xc000, 0x8000); | ||
371 | 348 | ||
349 | } else { | ||
372 | *mic = false; | 350 | *mic = false; |
351 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20); | ||
373 | } | 352 | } |
374 | } else { | 353 | } else { |
375 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); | 354 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); |
@@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) | |||
378 | *mic = buf & 0x80000000; | 357 | *mic = buf & 0x80000000; |
379 | } | 358 | } |
380 | 359 | ||
360 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV"); | ||
361 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF"); | ||
362 | if (!*hp) | ||
363 | snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1"); | ||
364 | snd_soc_dapm_sync(&rt286->codec->dapm); | ||
365 | |||
381 | return 0; | 366 | return 0; |
382 | } | 367 | } |
383 | 368 | ||
@@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
415 | } | 400 | } |
416 | EXPORT_SYMBOL_GPL(rt286_mic_detect); | 401 | EXPORT_SYMBOL_GPL(rt286_mic_detect); |
417 | 402 | ||
403 | static int is_mclk_mode(struct snd_soc_dapm_widget *source, | ||
404 | struct snd_soc_dapm_widget *sink) | ||
405 | { | ||
406 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec); | ||
407 | |||
408 | if (rt286->clk_id == RT286_SCLK_S_MCLK) | ||
409 | return 1; | ||
410 | else | ||
411 | return 0; | ||
412 | } | ||
413 | |||
418 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); | 414 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); |
419 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); | 415 | static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); |
420 | 416 | ||
@@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w, | |||
568 | return 0; | 564 | return 0; |
569 | } | 565 | } |
570 | 566 | ||
567 | static int rt286_vref_event(struct snd_soc_dapm_widget *w, | ||
568 | struct snd_kcontrol *kcontrol, int event) | ||
569 | { | ||
570 | struct snd_soc_codec *codec = w->codec; | ||
571 | |||
572 | switch (event) { | ||
573 | case SND_SOC_DAPM_PRE_PMU: | ||
574 | snd_soc_update_bits(codec, | ||
575 | RT286_CBJ_CTRL1, 0x0400, 0x0000); | ||
576 | mdelay(50); | ||
577 | break; | ||
578 | default: | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int rt286_ldo2_event(struct snd_soc_dapm_widget *w, | ||
586 | struct snd_kcontrol *kcontrol, int event) | ||
587 | { | ||
588 | struct snd_soc_codec *codec = w->codec; | ||
589 | |||
590 | switch (event) { | ||
591 | case SND_SOC_DAPM_POST_PMU: | ||
592 | snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08); | ||
593 | break; | ||
594 | case SND_SOC_DAPM_PRE_PMD: | ||
595 | snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30); | ||
596 | break; | ||
597 | default: | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | static int rt286_mic1_event(struct snd_soc_dapm_widget *w, | ||
605 | struct snd_kcontrol *kcontrol, int event) | ||
606 | { | ||
607 | struct snd_soc_codec *codec = w->codec; | ||
608 | |||
609 | switch (event) { | ||
610 | case SND_SOC_DAPM_PRE_PMU: | ||
611 | snd_soc_update_bits(codec, | ||
612 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | ||
613 | snd_soc_update_bits(codec, | ||
614 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | ||
615 | break; | ||
616 | case SND_SOC_DAPM_POST_PMD: | ||
617 | snd_soc_update_bits(codec, | ||
618 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | ||
619 | snd_soc_update_bits(codec, | ||
620 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | ||
621 | break; | ||
622 | default: | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
571 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | 629 | static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { |
630 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1, | ||
631 | 12, 1, NULL, 0), | ||
632 | SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1, | ||
633 | 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU), | ||
634 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2, | ||
635 | 2, 0, NULL, 0), | ||
636 | SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1, | ||
637 | 13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD | | ||
638 | SND_SOC_DAPM_POST_PMU), | ||
639 | SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1, | ||
640 | 5, 0, NULL, 0), | ||
641 | SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM, | ||
642 | 0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU | | ||
643 | SND_SOC_DAPM_POST_PMD), | ||
644 | |||
572 | /* Input Lines */ | 645 | /* Input Lines */ |
573 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), | 646 | SND_SOC_DAPM_INPUT("DMIC1 Pin"), |
574 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), | 647 | SND_SOC_DAPM_INPUT("DMIC2 Pin"), |
@@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = { | |||
642 | }; | 715 | }; |
643 | 716 | ||
644 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { | 717 | static const struct snd_soc_dapm_route rt286_dapm_routes[] = { |
718 | {"ADC 0", NULL, "MCLK MODE", is_mclk_mode}, | ||
719 | {"ADC 1", NULL, "MCLK MODE", is_mclk_mode}, | ||
720 | {"Front", NULL, "MCLK MODE", is_mclk_mode}, | ||
721 | {"Surround", NULL, "MCLK MODE", is_mclk_mode}, | ||
722 | |||
723 | {"HP Power", NULL, "LDO1"}, | ||
724 | {"HP Power", NULL, "LDO2"}, | ||
725 | |||
726 | {"MIC1", NULL, "LDO1"}, | ||
727 | {"MIC1", NULL, "LDO2"}, | ||
728 | {"MIC1", NULL, "HV"}, | ||
729 | {"MIC1", NULL, "VREF"}, | ||
730 | {"MIC1", NULL, "MIC1 Input Buffer"}, | ||
731 | |||
732 | {"SPO", NULL, "LDO1"}, | ||
733 | {"SPO", NULL, "LDO2"}, | ||
734 | {"SPO", NULL, "HV"}, | ||
735 | {"SPO", NULL, "VREF"}, | ||
736 | |||
645 | {"DMIC1", NULL, "DMIC1 Pin"}, | 737 | {"DMIC1", NULL, "DMIC1 Pin"}, |
646 | {"DMIC2", NULL, "DMIC2 Pin"}, | 738 | {"DMIC2", NULL, "DMIC2 Pin"}, |
647 | {"DMIC1", NULL, "DMIC Receiver"}, | 739 | {"DMIC1", NULL, "DMIC Receiver"}, |
@@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai, | |||
880 | } | 972 | } |
881 | 973 | ||
882 | rt286->sys_clk = freq; | 974 | rt286->sys_clk = freq; |
975 | rt286->clk_id = clk_id; | ||
883 | 976 | ||
884 | return 0; | 977 | return 0; |
885 | } | 978 | } |
@@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec, | |||
915 | 1008 | ||
916 | case SND_SOC_BIAS_ON: | 1009 | case SND_SOC_BIAS_ON: |
917 | mdelay(10); | 1010 | mdelay(10); |
1011 | snd_soc_update_bits(codec, | ||
1012 | RT286_CBJ_CTRL1, 0x0400, 0x0400); | ||
1013 | snd_soc_update_bits(codec, | ||
1014 | RT286_DC_GAIN, 0x200, 0x0); | ||
1015 | |||
918 | break; | 1016 | break; |
919 | 1017 | ||
920 | case SND_SOC_BIAS_STANDBY: | 1018 | case SND_SOC_BIAS_STANDBY: |
921 | snd_soc_write(codec, | 1019 | snd_soc_write(codec, |
922 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); | 1020 | RT286_SET_AUDIO_POWER, AC_PWRST_D3); |
923 | snd_soc_update_bits(codec, | 1021 | snd_soc_update_bits(codec, |
924 | RT286_DC_GAIN, 0x200, 0x0); | 1022 | RT286_CBJ_CTRL1, 0x0400, 0x0000); |
925 | break; | 1023 | break; |
926 | 1024 | ||
927 | default: | 1025 | default: |
@@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec) | |||
962 | { | 1060 | { |
963 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | 1061 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); |
964 | 1062 | ||
1063 | rt286->codec = codec; | ||
965 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 1064 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
966 | 1065 | ||
967 | if (rt286->i2c->irq) { | 1066 | if (rt286->i2c->irq) { |
@@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = { | |||
1107 | }; | 1206 | }; |
1108 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); | 1207 | MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); |
1109 | 1208 | ||
1209 | static struct dmi_system_id force_combo_jack_table[] = { | ||
1210 | { | ||
1211 | .ident = "Intel Wilson Beach", | ||
1212 | .matches = { | ||
1213 | DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS") | ||
1214 | } | ||
1215 | }, | ||
1216 | { } | ||
1217 | }; | ||
1218 | |||
1110 | static int rt286_i2c_probe(struct i2c_client *i2c, | 1219 | static int rt286_i2c_probe(struct i2c_client *i2c, |
1111 | const struct i2c_device_id *id) | 1220 | const struct i2c_device_id *id) |
1112 | { | 1221 | { |
@@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1142 | if (pdata) | 1251 | if (pdata) |
1143 | rt286->pdata = *pdata; | 1252 | rt286->pdata = *pdata; |
1144 | 1253 | ||
1254 | if (dmi_check_system(force_combo_jack_table)) | ||
1255 | rt286->pdata.cbj_en = true; | ||
1256 | |||
1145 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); | 1257 | regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3); |
1146 | 1258 | ||
1147 | for (i = 0; i < RT286_POWER_REG_LEN; i++) | 1259 | for (i = 0; i < RT286_POWER_REG_LEN; i++) |
@@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1152 | if (!rt286->pdata.cbj_en) { | 1264 | if (!rt286->pdata.cbj_en) { |
1153 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); | 1265 | regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000); |
1154 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); | 1266 | regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816); |
1155 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); | ||
1156 | regmap_update_bits(rt286->regmap, | 1267 | regmap_update_bits(rt286->regmap, |
1157 | RT286_CBJ_CTRL1, 0xf000, 0xb000); | 1268 | RT286_CBJ_CTRL1, 0xf000, 0xb000); |
1158 | } else { | 1269 | } else { |
@@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
1169 | 1280 | ||
1170 | mdelay(10); | 1281 | mdelay(10); |
1171 | 1282 | ||
1172 | /*Power down LDO2*/ | 1283 | regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000); |
1173 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0); | 1284 | /* Power down LDO, VREF */ |
1285 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0); | ||
1286 | regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001); | ||
1174 | 1287 | ||
1175 | /*Set depop parameter*/ | 1288 | /* Set depop parameter */ |
1176 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); | 1289 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a); |
1177 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); | 1290 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737); |
1178 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); | 1291 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); |
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 1ba27db660a6..6d7b7ca7d530 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c | |||
@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec) | |||
1612 | return 0; | 1612 | return 0; |
1613 | } | 1613 | } |
1614 | 1614 | ||
1615 | static int rt5631_remove(struct snd_soc_codec *codec) | ||
1616 | { | ||
1617 | rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1618 | return 0; | ||
1619 | } | ||
1620 | |||
1621 | #ifdef CONFIG_PM | ||
1622 | static int rt5631_suspend(struct snd_soc_codec *codec) | ||
1623 | { | ||
1624 | rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | static int rt5631_resume(struct snd_soc_codec *codec) | ||
1629 | { | ||
1630 | rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1631 | return 0; | ||
1632 | } | ||
1633 | #else | ||
1634 | #define rt5631_suspend NULL | ||
1635 | #define rt5631_resume NULL | ||
1636 | #endif | ||
1637 | |||
1638 | #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 | 1615 | #define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000 |
1639 | #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ | 1616 | #define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ |
1640 | SNDRV_PCM_FMTBIT_S20_3LE | \ | 1617 | SNDRV_PCM_FMTBIT_S20_3LE | \ |
@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = { | |||
1672 | 1649 | ||
1673 | static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { | 1650 | static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { |
1674 | .probe = rt5631_probe, | 1651 | .probe = rt5631_probe, |
1675 | .remove = rt5631_remove, | ||
1676 | .suspend = rt5631_suspend, | ||
1677 | .resume = rt5631_resume, | ||
1678 | .set_bias_level = rt5631_set_bias_level, | 1652 | .set_bias_level = rt5631_set_bias_level, |
1653 | .suspend_bias_off = true, | ||
1679 | .controls = rt5631_snd_controls, | 1654 | .controls = rt5631_snd_controls, |
1680 | .num_controls = ARRAY_SIZE(rt5631_snd_controls), | 1655 | .num_controls = ARRAY_SIZE(rt5631_snd_controls), |
1681 | .dapm_widgets = rt5631_dapm_widgets, | 1656 | .dapm_widgets = rt5631_dapm_widgets, |
@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = { | |||
1686 | 1661 | ||
1687 | static const struct i2c_device_id rt5631_i2c_id[] = { | 1662 | static const struct i2c_device_id rt5631_i2c_id[] = { |
1688 | { "rt5631", 0 }, | 1663 | { "rt5631", 0 }, |
1664 | { "alc5631", 0 }, | ||
1689 | { } | 1665 | { } |
1690 | }; | 1666 | }; |
1691 | MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); | 1667 | MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id); |
1692 | 1668 | ||
1669 | #ifdef CONFIG_OF | ||
1670 | static struct of_device_id rt5631_i2c_dt_ids[] = { | ||
1671 | { .compatible = "realtek,rt5631"}, | ||
1672 | { .compatible = "realtek,alc5631"}, | ||
1673 | { } | ||
1674 | }; | ||
1675 | MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids); | ||
1676 | #endif | ||
1677 | |||
1693 | static const struct regmap_config rt5631_regmap_config = { | 1678 | static const struct regmap_config rt5631_regmap_config = { |
1694 | .reg_bits = 8, | 1679 | .reg_bits = 8, |
1695 | .val_bits = 16, | 1680 | .val_bits = 16, |
@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = { | |||
1734 | .driver = { | 1719 | .driver = { |
1735 | .name = "rt5631", | 1720 | .name = "rt5631", |
1736 | .owner = THIS_MODULE, | 1721 | .owner = THIS_MODULE, |
1722 | .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), | ||
1737 | }, | 1723 | }, |
1738 | .probe = rt5631_i2c_probe, | 1724 | .probe = rt5631_i2c_probe, |
1739 | .remove = rt5631_i2c_remove, | 1725 | .remove = rt5631_i2c_remove, |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d16331e0b64d..a7789a8726e3 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | |||
554 | return 0; | 554 | return 0; |
555 | } | 555 | } |
556 | 556 | ||
557 | static int is_using_asrc(struct snd_soc_dapm_widget *source, | ||
558 | struct snd_soc_dapm_widget *sink) | ||
559 | { | ||
560 | unsigned int reg, shift, val; | ||
561 | |||
562 | switch (source->shift) { | ||
563 | case 0: | ||
564 | reg = RT5645_ASRC_3; | ||
565 | shift = 0; | ||
566 | break; | ||
567 | case 1: | ||
568 | reg = RT5645_ASRC_3; | ||
569 | shift = 4; | ||
570 | break; | ||
571 | case 3: | ||
572 | reg = RT5645_ASRC_2; | ||
573 | shift = 0; | ||
574 | break; | ||
575 | case 8: | ||
576 | reg = RT5645_ASRC_2; | ||
577 | shift = 4; | ||
578 | break; | ||
579 | case 9: | ||
580 | reg = RT5645_ASRC_2; | ||
581 | shift = 8; | ||
582 | break; | ||
583 | case 10: | ||
584 | reg = RT5645_ASRC_2; | ||
585 | shift = 12; | ||
586 | break; | ||
587 | default: | ||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | val = (snd_soc_read(source->codec, reg) >> shift) & 0xf; | ||
592 | switch (val) { | ||
593 | case 1: | ||
594 | case 2: | ||
595 | case 3: | ||
596 | case 4: | ||
597 | return 1; | ||
598 | default: | ||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | } | ||
603 | |||
557 | /* Digital Mixer */ | 604 | /* Digital Mixer */ |
558 | static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { | 605 | static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = { |
559 | SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, | 606 | SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER, |
@@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { | |||
1246 | SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, | 1293 | SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL, |
1247 | RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), | 1294 | RT5645_PWR_MIC_DET_BIT, 0, NULL, 0), |
1248 | 1295 | ||
1296 | /* ASRC */ | ||
1297 | SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1, | ||
1298 | 11, 0, NULL, 0), | ||
1299 | SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1, | ||
1300 | 12, 0, NULL, 0), | ||
1301 | SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1, | ||
1302 | 10, 0, NULL, 0), | ||
1303 | SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1304 | 9, 0, NULL, 0), | ||
1305 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1306 | 8, 0, NULL, 0), | ||
1307 | SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1, | ||
1308 | 7, 0, NULL, 0), | ||
1309 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1310 | 5, 0, NULL, 0), | ||
1311 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1312 | 4, 0, NULL, 0), | ||
1313 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1, | ||
1314 | 3, 0, NULL, 0), | ||
1315 | SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1, | ||
1316 | 1, 0, NULL, 0), | ||
1317 | SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1, | ||
1318 | 0, 0, NULL, 0), | ||
1319 | |||
1249 | /* Input Side */ | 1320 | /* Input Side */ |
1250 | /* micbias */ | 1321 | /* micbias */ |
1251 | SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, | 1322 | SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2, |
@@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { | |||
1504 | }; | 1575 | }; |
1505 | 1576 | ||
1506 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | 1577 | static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { |
1578 | { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc }, | ||
1579 | { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc }, | ||
1580 | { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc }, | ||
1581 | { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc }, | ||
1582 | { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc }, | ||
1583 | { "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc }, | ||
1584 | { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc }, | ||
1585 | |||
1586 | { "I2S1", NULL, "I2S1 ASRC" }, | ||
1587 | { "I2S2", NULL, "I2S2 ASRC" }, | ||
1588 | |||
1507 | { "IN1P", NULL, "LDO2" }, | 1589 | { "IN1P", NULL, "LDO2" }, |
1508 | { "IN2P", NULL, "LDO2" }, | 1590 | { "IN2P", NULL, "LDO2" }, |
1509 | 1591 | ||
@@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = { | |||
1550 | 1632 | ||
1551 | { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, | 1633 | { "Stereo1 DMIC Mux", "DMIC1", "DMIC1" }, |
1552 | { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, | 1634 | { "Stereo1 DMIC Mux", "DMIC2", "DMIC2" }, |
1635 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" }, | ||
1553 | 1636 | ||
1554 | { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, | 1637 | { "Mono DMIC L Mux", "DMIC1", "DMIC L1" }, |
1555 | { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, | 1638 | { "Mono DMIC L Mux", "DMIC2", "DMIC L2" }, |
1639 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" }, | ||
1556 | 1640 | ||
1557 | { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, | 1641 | { "Mono DMIC R Mux", "DMIC1", "DMIC R1" }, |
1558 | { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, | 1642 | { "Mono DMIC R Mux", "DMIC2", "DMIC R2" }, |
1643 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" }, | ||
1559 | 1644 | ||
1560 | { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, | 1645 | { "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" }, |
1561 | { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, | 1646 | { "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" }, |
@@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
2029 | struct snd_soc_codec *codec = dai->codec; | 2114 | struct snd_soc_codec *codec = dai->codec; |
2030 | unsigned int val = 0; | 2115 | unsigned int val = 0; |
2031 | 2116 | ||
2032 | if (rx_mask || tx_mask) | 2117 | if (rx_mask || tx_mask) { |
2033 | val |= (1 << 14); | 2118 | val |= (1 << 14); |
2119 | snd_soc_update_bits(codec, RT5645_BASS_BACK, | ||
2120 | RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB); | ||
2121 | } | ||
2034 | 2122 | ||
2035 | switch (slots) { | 2123 | switch (slots) { |
2036 | case 4: | 2124 | case 4: |
@@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2071 | enum snd_soc_bias_level level) | 2159 | enum snd_soc_bias_level level) |
2072 | { | 2160 | { |
2073 | switch (level) { | 2161 | switch (level) { |
2074 | case SND_SOC_BIAS_STANDBY: | 2162 | case SND_SOC_BIAS_PREPARE: |
2075 | if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) { | 2163 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { |
2076 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | 2164 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
2077 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | 2165 | RT5645_PWR_VREF1 | RT5645_PWR_MB | |
2078 | RT5645_PWR_BG | RT5645_PWR_VREF2, | 2166 | RT5645_PWR_BG | RT5645_PWR_VREF2, |
@@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2087 | } | 2175 | } |
2088 | break; | 2176 | break; |
2089 | 2177 | ||
2178 | case SND_SOC_BIAS_STANDBY: | ||
2179 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
2180 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | ||
2181 | RT5645_PWR_BG | RT5645_PWR_VREF2, | ||
2182 | RT5645_PWR_VREF1 | RT5645_PWR_MB | | ||
2183 | RT5645_PWR_BG | RT5645_PWR_VREF2); | ||
2184 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, | ||
2185 | RT5645_PWR_FV1 | RT5645_PWR_FV2, | ||
2186 | RT5645_PWR_FV1 | RT5645_PWR_FV2); | ||
2187 | break; | ||
2188 | |||
2090 | case SND_SOC_BIAS_OFF: | 2189 | case SND_SOC_BIAS_OFF: |
2091 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); | 2190 | snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100); |
2092 | snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); | 2191 | snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128); |
2093 | snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000); | 2192 | snd_soc_update_bits(codec, RT5645_PWR_ANLG1, |
2094 | snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000); | 2193 | RT5645_PWR_VREF1 | RT5645_PWR_MB | |
2095 | snd_soc_write(codec, RT5645_PWR_VOL, 0x0000); | 2194 | RT5645_PWR_BG | RT5645_PWR_VREF2 | |
2096 | snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000); | 2195 | RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0); |
2097 | snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000); | ||
2098 | snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000); | ||
2099 | break; | 2196 | break; |
2100 | 2197 | ||
2101 | default: | 2198 | default: |
@@ -2106,8 +2203,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2106 | return 0; | 2203 | return 0; |
2107 | } | 2204 | } |
2108 | 2205 | ||
2109 | static int rt5645_jack_detect(struct snd_soc_codec *codec, | 2206 | static int rt5645_jack_detect(struct snd_soc_codec *codec) |
2110 | struct snd_soc_jack *jack) | ||
2111 | { | 2207 | { |
2112 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2208 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
2113 | int gpio_state, jack_type = 0; | 2209 | int gpio_state, jack_type = 0; |
@@ -2145,34 +2241,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, | |||
2145 | 2241 | ||
2146 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); | 2242 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); |
2147 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); | 2243 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); |
2148 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | 2244 | if (rt5645->pdata.jd_mode == 0) |
2245 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | ||
2149 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | 2246 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); |
2150 | snd_soc_dapm_sync(&codec->dapm); | 2247 | snd_soc_dapm_sync(&codec->dapm); |
2151 | } | 2248 | } |
2152 | 2249 | ||
2153 | snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); | 2250 | snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE); |
2154 | 2251 | snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE); | |
2155 | return 0; | 2252 | return 0; |
2156 | } | 2253 | } |
2157 | 2254 | ||
2158 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2255 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2159 | struct snd_soc_jack *jack) | 2256 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack) |
2160 | { | 2257 | { |
2161 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2258 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
2162 | 2259 | ||
2163 | rt5645->jack = jack; | 2260 | rt5645->hp_jack = hp_jack; |
2164 | 2261 | rt5645->mic_jack = mic_jack; | |
2165 | rt5645_jack_detect(codec, rt5645->jack); | 2262 | rt5645_jack_detect(codec); |
2166 | 2263 | ||
2167 | return 0; | 2264 | return 0; |
2168 | } | 2265 | } |
2169 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); | 2266 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); |
2170 | 2267 | ||
2268 | static void rt5645_jack_detect_work(struct work_struct *work) | ||
2269 | { | ||
2270 | struct rt5645_priv *rt5645 = | ||
2271 | container_of(work, struct rt5645_priv, jack_detect_work.work); | ||
2272 | |||
2273 | rt5645_jack_detect(rt5645->codec); | ||
2274 | } | ||
2275 | |||
2171 | static irqreturn_t rt5645_irq(int irq, void *data) | 2276 | static irqreturn_t rt5645_irq(int irq, void *data) |
2172 | { | 2277 | { |
2173 | struct rt5645_priv *rt5645 = data; | 2278 | struct rt5645_priv *rt5645 = data; |
2174 | 2279 | ||
2175 | rt5645_jack_detect(rt5645->codec, rt5645->jack); | 2280 | queue_delayed_work(system_power_efficient_wq, |
2281 | &rt5645->jack_detect_work, msecs_to_jiffies(250)); | ||
2176 | 2282 | ||
2177 | return IRQ_HANDLED; | 2283 | return IRQ_HANDLED; |
2178 | } | 2284 | } |
@@ -2187,6 +2293,13 @@ static int rt5645_probe(struct snd_soc_codec *codec) | |||
2187 | 2293 | ||
2188 | snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); | 2294 | snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); |
2189 | 2295 | ||
2296 | /* for JD function */ | ||
2297 | if (rt5645->pdata.en_jd_func) { | ||
2298 | snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); | ||
2299 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | ||
2300 | snd_soc_dapm_sync(&codec->dapm); | ||
2301 | } | ||
2302 | |||
2190 | return 0; | 2303 | return 0; |
2191 | } | 2304 | } |
2192 | 2305 | ||
@@ -2420,6 +2533,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2420 | 2533 | ||
2421 | } | 2534 | } |
2422 | 2535 | ||
2536 | if (rt5645->pdata.en_jd_func) { | ||
2537 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | ||
2538 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU, | ||
2539 | RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU); | ||
2540 | regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, | ||
2541 | RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); | ||
2542 | regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3, | ||
2543 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL, | ||
2544 | RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL); | ||
2545 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, | ||
2546 | RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); | ||
2547 | } | ||
2548 | |||
2549 | if (rt5645->pdata.jd_mode) { | ||
2550 | regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, | ||
2551 | RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN); | ||
2552 | regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, | ||
2553 | RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE); | ||
2554 | regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER, | ||
2555 | RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE); | ||
2556 | regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, | ||
2557 | RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN); | ||
2558 | regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1, | ||
2559 | RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ); | ||
2560 | switch (rt5645->pdata.jd_mode) { | ||
2561 | case 1: | ||
2562 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2563 | RT5645_JD1_MODE_MASK, | ||
2564 | RT5645_JD1_MODE_0); | ||
2565 | break; | ||
2566 | case 2: | ||
2567 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2568 | RT5645_JD1_MODE_MASK, | ||
2569 | RT5645_JD1_MODE_1); | ||
2570 | break; | ||
2571 | case 3: | ||
2572 | regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1, | ||
2573 | RT5645_JD1_MODE_MASK, | ||
2574 | RT5645_JD1_MODE_2); | ||
2575 | break; | ||
2576 | default: | ||
2577 | break; | ||
2578 | } | ||
2579 | } | ||
2580 | |||
2423 | if (rt5645->i2c->irq) { | 2581 | if (rt5645->i2c->irq) { |
2424 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, | 2582 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, |
2425 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | 2583 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
@@ -2438,6 +2596,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2438 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); | 2596 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); |
2439 | } | 2597 | } |
2440 | 2598 | ||
2599 | INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work); | ||
2600 | |||
2441 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 2601 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
2442 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 2602 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
2443 | } | 2603 | } |
@@ -2449,6 +2609,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) | |||
2449 | if (i2c->irq) | 2609 | if (i2c->irq) |
2450 | free_irq(i2c->irq, rt5645); | 2610 | free_irq(i2c->irq, rt5645); |
2451 | 2611 | ||
2612 | cancel_delayed_work_sync(&rt5645->jack_detect_work); | ||
2613 | |||
2452 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) | 2614 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) |
2453 | gpio_free(rt5645->pdata.hp_det_gpio); | 2615 | gpio_free(rt5645->pdata.hp_det_gpio); |
2454 | 2616 | ||
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 50c62c5668ea..a815e36a2bdb 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h | |||
@@ -594,6 +594,7 @@ | |||
594 | #define RT5645_M_DAC1_HM_SFT 14 | 594 | #define RT5645_M_DAC1_HM_SFT 14 |
595 | #define RT5645_M_HPVOL_HM (0x1 << 13) | 595 | #define RT5645_M_HPVOL_HM (0x1 << 13) |
596 | #define RT5645_M_HPVOL_HM_SFT 13 | 596 | #define RT5645_M_HPVOL_HM_SFT 13 |
597 | #define RT5645_IRQ_PSV_MODE (0x1 << 12) | ||
597 | 598 | ||
598 | /* SPK Left Mixer Control (0x46) */ | 599 | /* SPK Left Mixer Control (0x46) */ |
599 | #define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) | 600 | #define RT5645_G_RM_L_SM_L_MASK (0x3 << 14) |
@@ -1348,6 +1349,12 @@ | |||
1348 | #define RT5645_PWR_CLK25M_SFT 4 | 1349 | #define RT5645_PWR_CLK25M_SFT 4 |
1349 | #define RT5645_PWR_CLK25M_PD (0x0 << 4) | 1350 | #define RT5645_PWR_CLK25M_PD (0x0 << 4) |
1350 | #define RT5645_PWR_CLK25M_PU (0x1 << 4) | 1351 | #define RT5645_PWR_CLK25M_PU (0x1 << 4) |
1352 | #define RT5645_IRQ_CLK_MCLK (0x0 << 3) | ||
1353 | #define RT5645_IRQ_CLK_INT (0x1 << 3) | ||
1354 | #define RT5645_JD1_MODE_MASK (0x3 << 0) | ||
1355 | #define RT5645_JD1_MODE_0 (0x0 << 0) | ||
1356 | #define RT5645_JD1_MODE_1 (0x1 << 0) | ||
1357 | #define RT5645_JD1_MODE_2 (0x2 << 0) | ||
1351 | 1358 | ||
1352 | /* VAD Control 4 (0x9d) */ | 1359 | /* VAD Control 4 (0x9d) */ |
1353 | #define RT5645_VAD_SEL_MASK (0x3 << 8) | 1360 | #define RT5645_VAD_SEL_MASK (0x3 << 8) |
@@ -1636,6 +1643,7 @@ | |||
1636 | #define RT5645_OT_P_SFT 10 | 1643 | #define RT5645_OT_P_SFT 10 |
1637 | #define RT5645_OT_P_NOR (0x0 << 10) | 1644 | #define RT5645_OT_P_NOR (0x0 << 10) |
1638 | #define RT5645_OT_P_INV (0x1 << 10) | 1645 | #define RT5645_OT_P_INV (0x1 << 10) |
1646 | #define RT5645_IRQ_JD_1_1_EN (0x1 << 9) | ||
1639 | 1647 | ||
1640 | /* IRQ Control 2 (0xbe) */ | 1648 | /* IRQ Control 2 (0xbe) */ |
1641 | #define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) | 1649 | #define RT5645_IRQ_MB1_OC_MASK (0x1 << 15) |
@@ -1853,6 +1861,7 @@ | |||
1853 | #define RT5645_M_BB_HPF_R_SFT 6 | 1861 | #define RT5645_M_BB_HPF_R_SFT 6 |
1854 | #define RT5645_G_BB_BST_MASK (0x3f) | 1862 | #define RT5645_G_BB_BST_MASK (0x3f) |
1855 | #define RT5645_G_BB_BST_SFT 0 | 1863 | #define RT5645_G_BB_BST_SFT 0 |
1864 | #define RT5645_G_BB_BST_25DB 0x14 | ||
1856 | 1865 | ||
1857 | /* MP3 Plus Control 1 (0xd0) */ | 1866 | /* MP3 Plus Control 1 (0xd0) */ |
1858 | #define RT5645_M_MP3_L_MASK (0x1 << 15) | 1867 | #define RT5645_M_MP3_L_MASK (0x1 << 15) |
@@ -2116,6 +2125,10 @@ enum { | |||
2116 | #define RT5645_RXDP2_SEL_ADC (0x1 << 3) | 2125 | #define RT5645_RXDP2_SEL_ADC (0x1 << 3) |
2117 | #define RT5645_RXDP2_SEL_SFT (3) | 2126 | #define RT5645_RXDP2_SEL_SFT (3) |
2118 | 2127 | ||
2128 | /* General Control3 (0xfc) */ | ||
2129 | #define RT5645_JD_PSV_MODE (0x1 << 12) | ||
2130 | #define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) | ||
2131 | #define RT5645_MICINDET_MANU (0x1 << 7) | ||
2119 | 2132 | ||
2120 | /* Vendor ID (0xfd) */ | 2133 | /* Vendor ID (0xfd) */ |
2121 | #define RT5645_VER_C 0x2 | 2134 | #define RT5645_VER_C 0x2 |
@@ -2167,7 +2180,9 @@ struct rt5645_priv { | |||
2167 | struct rt5645_platform_data pdata; | 2180 | struct rt5645_platform_data pdata; |
2168 | struct regmap *regmap; | 2181 | struct regmap *regmap; |
2169 | struct i2c_client *i2c; | 2182 | struct i2c_client *i2c; |
2170 | struct snd_soc_jack *jack; | 2183 | struct snd_soc_jack *hp_jack; |
2184 | struct snd_soc_jack *mic_jack; | ||
2185 | struct delayed_work jack_detect_work; | ||
2171 | 2186 | ||
2172 | int sysclk; | 2187 | int sysclk; |
2173 | int sysclk_src; | 2188 | int sysclk_src; |
@@ -2181,6 +2196,6 @@ struct rt5645_priv { | |||
2181 | }; | 2196 | }; |
2182 | 2197 | ||
2183 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | 2198 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, |
2184 | struct snd_soc_jack *jack); | 2199 | struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack); |
2185 | 2200 | ||
2186 | #endif /* __RT5645_H__ */ | 2201 | #endif /* __RT5645_H__ */ |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 9bd8b4f63303..8a0833de1665 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/acpi.h> | ||
19 | #include <linux/spi/spi.h> | 20 | #include <linux/spi/spi.h> |
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
@@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source, | |||
575 | 576 | ||
576 | } | 577 | } |
577 | 578 | ||
579 | static int can_use_asrc(struct snd_soc_dapm_widget *source, | ||
580 | struct snd_soc_dapm_widget *sink) | ||
581 | { | ||
582 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); | ||
583 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
584 | |||
585 | if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384) | ||
586 | return 1; | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
578 | /* Digital Mixer */ | 591 | /* Digital Mixer */ |
579 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { | 592 | static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = { |
580 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, | 593 | SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER, |
@@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { | |||
1281 | 9, 0, NULL, 0), | 1294 | 9, 0, NULL, 0), |
1282 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, | 1295 | SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1, |
1283 | 8, 0, NULL, 0), | 1296 | 8, 0, NULL, 0), |
1297 | SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1, | ||
1298 | 7, 0, NULL, 0), | ||
1299 | SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1, | ||
1300 | 6, 0, NULL, 0), | ||
1301 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1, | ||
1302 | 5, 0, NULL, 0), | ||
1303 | SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1, | ||
1304 | 4, 0, NULL, 0), | ||
1284 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, | 1305 | SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1, |
1285 | 3, 0, NULL, 0), | 1306 | 3, 0, NULL, 0), |
1286 | SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, | 1307 | SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1, |
@@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = { | |||
1595 | /* PDM */ | 1616 | /* PDM */ |
1596 | SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, | 1617 | SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2, |
1597 | RT5670_PWR_PDM1_BIT, 0, NULL, 0), | 1618 | RT5670_PWR_PDM1_BIT, 0, NULL, 0), |
1598 | SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, | ||
1599 | RT5670_PWR_PDM2_BIT, 0, NULL, 0), | ||
1600 | 1619 | ||
1601 | SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, | 1620 | SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL, |
1602 | RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), | 1621 | RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux), |
1603 | SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, | 1622 | SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL, |
1604 | RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), | 1623 | RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux), |
1605 | SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, | ||
1606 | RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), | ||
1607 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, | ||
1608 | RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), | ||
1609 | 1624 | ||
1610 | /* Output Lines */ | 1625 | /* Output Lines */ |
1611 | SND_SOC_DAPM_OUTPUT("HPOL"), | 1626 | SND_SOC_DAPM_OUTPUT("HPOL"), |
1612 | SND_SOC_DAPM_OUTPUT("HPOR"), | 1627 | SND_SOC_DAPM_OUTPUT("HPOR"), |
1613 | SND_SOC_DAPM_OUTPUT("LOUTL"), | 1628 | SND_SOC_DAPM_OUTPUT("LOUTL"), |
1614 | SND_SOC_DAPM_OUTPUT("LOUTR"), | 1629 | SND_SOC_DAPM_OUTPUT("LOUTR"), |
1630 | }; | ||
1631 | |||
1632 | static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = { | ||
1633 | SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2, | ||
1634 | RT5670_PWR_PDM2_BIT, 0, NULL, 0), | ||
1635 | SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL, | ||
1636 | RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux), | ||
1637 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL, | ||
1638 | RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux), | ||
1615 | SND_SOC_DAPM_OUTPUT("PDM1L"), | 1639 | SND_SOC_DAPM_OUTPUT("PDM1L"), |
1616 | SND_SOC_DAPM_OUTPUT("PDM1R"), | 1640 | SND_SOC_DAPM_OUTPUT("PDM1R"), |
1617 | SND_SOC_DAPM_OUTPUT("PDM2L"), | 1641 | SND_SOC_DAPM_OUTPUT("PDM2L"), |
1618 | SND_SOC_DAPM_OUTPUT("PDM2R"), | 1642 | SND_SOC_DAPM_OUTPUT("PDM2R"), |
1619 | }; | 1643 | }; |
1620 | 1644 | ||
1645 | static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = { | ||
1646 | SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1647 | SND_SOC_DAPM_OUTPUT("SPOLP"), | ||
1648 | SND_SOC_DAPM_OUTPUT("SPOLN"), | ||
1649 | SND_SOC_DAPM_OUTPUT("SPORP"), | ||
1650 | SND_SOC_DAPM_OUTPUT("SPORN"), | ||
1651 | }; | ||
1652 | |||
1621 | static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | 1653 | static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { |
1622 | { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, | 1654 | { "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc }, |
1623 | { "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc }, | 1655 | { "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc }, |
@@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1626 | { "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc }, | 1658 | { "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc }, |
1627 | { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, | 1659 | { "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc }, |
1628 | { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, | 1660 | { "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc }, |
1661 | { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc }, | ||
1662 | { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc }, | ||
1663 | { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc }, | ||
1664 | { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc }, | ||
1629 | 1665 | ||
1630 | { "I2S1", NULL, "I2S1 ASRC" }, | 1666 | { "I2S1", NULL, "I2S1 ASRC", can_use_asrc}, |
1631 | { "I2S2", NULL, "I2S2 ASRC" }, | 1667 | { "I2S2", NULL, "I2S2 ASRC", can_use_asrc}, |
1632 | 1668 | ||
1633 | { "DMIC1", NULL, "DMIC L1" }, | 1669 | { "DMIC1", NULL, "DMIC L1" }, |
1634 | { "DMIC1", NULL, "DMIC R1" }, | 1670 | { "DMIC1", NULL, "DMIC R1" }, |
@@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1970 | { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | 2006 | { "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, |
1971 | { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, | 2007 | { "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" }, |
1972 | { "PDM1 R Mux", NULL, "PDM1 Power" }, | 2008 | { "PDM1 R Mux", NULL, "PDM1 Power" }, |
1973 | { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, | ||
1974 | { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, | ||
1975 | { "PDM2 L Mux", NULL, "PDM2 Power" }, | ||
1976 | { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | ||
1977 | { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, | ||
1978 | { "PDM2 R Mux", NULL, "PDM2 Power" }, | ||
1979 | 2009 | ||
1980 | { "HP Amp", NULL, "HPO MIX" }, | 2010 | { "HP Amp", NULL, "HPO MIX" }, |
1981 | { "HP Amp", NULL, "Mic Det Power" }, | 2011 | { "HP Amp", NULL, "Mic Det Power" }, |
@@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = { | |||
1993 | { "LOUTR", NULL, "LOUT R Playback" }, | 2023 | { "LOUTR", NULL, "LOUT R Playback" }, |
1994 | { "LOUTL", NULL, "Improve HP Amp Drv" }, | 2024 | { "LOUTL", NULL, "Improve HP Amp Drv" }, |
1995 | { "LOUTR", NULL, "Improve HP Amp Drv" }, | 2025 | { "LOUTR", NULL, "Improve HP Amp Drv" }, |
2026 | }; | ||
1996 | 2027 | ||
2028 | static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = { | ||
2029 | { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" }, | ||
2030 | { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" }, | ||
2031 | { "PDM2 L Mux", NULL, "PDM2 Power" }, | ||
2032 | { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" }, | ||
2033 | { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" }, | ||
2034 | { "PDM2 R Mux", NULL, "PDM2 Power" }, | ||
1997 | { "PDM1L", NULL, "PDM1 L Mux" }, | 2035 | { "PDM1L", NULL, "PDM1 L Mux" }, |
1998 | { "PDM1R", NULL, "PDM1 R Mux" }, | 2036 | { "PDM1R", NULL, "PDM1 R Mux" }, |
1999 | { "PDM2L", NULL, "PDM2 L Mux" }, | 2037 | { "PDM2L", NULL, "PDM2 L Mux" }, |
2000 | { "PDM2R", NULL, "PDM2 R Mux" }, | 2038 | { "PDM2R", NULL, "PDM2 R Mux" }, |
2001 | }; | 2039 | }; |
2002 | 2040 | ||
2041 | static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = { | ||
2042 | { "SPO Amp", NULL, "PDM1 L Mux" }, | ||
2043 | { "SPO Amp", NULL, "PDM1 R Mux" }, | ||
2044 | { "SPOLP", NULL, "SPO Amp" }, | ||
2045 | { "SPOLN", NULL, "SPO Amp" }, | ||
2046 | { "SPORP", NULL, "SPO Amp" }, | ||
2047 | { "SPORN", NULL, "SPO Amp" }, | ||
2048 | }; | ||
2049 | |||
2003 | static int rt5670_hw_params(struct snd_pcm_substream *substream, | 2050 | static int rt5670_hw_params(struct snd_pcm_substream *substream, |
2004 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 2051 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
2005 | { | 2052 | { |
@@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
2287 | static int rt5670_set_bias_level(struct snd_soc_codec *codec, | 2334 | static int rt5670_set_bias_level(struct snd_soc_codec *codec, |
2288 | enum snd_soc_bias_level level) | 2335 | enum snd_soc_bias_level level) |
2289 | { | 2336 | { |
2337 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | ||
2338 | |||
2290 | switch (level) { | 2339 | switch (level) { |
2291 | case SND_SOC_BIAS_PREPARE: | 2340 | case SND_SOC_BIAS_PREPARE: |
2292 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { | 2341 | if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { |
@@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec, | |||
2308 | } | 2357 | } |
2309 | break; | 2358 | break; |
2310 | case SND_SOC_BIAS_STANDBY: | 2359 | case SND_SOC_BIAS_STANDBY: |
2311 | snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000); | 2360 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, |
2312 | snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001); | 2361 | RT5670_PWR_VREF1 | RT5670_PWR_VREF2 | |
2313 | snd_soc_write(codec, RT5670_PWR_VOL, 0x0000); | 2362 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); |
2314 | snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001); | ||
2315 | snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800); | ||
2316 | snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004); | ||
2317 | snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); | ||
2318 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | 2363 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, |
2319 | RT5670_LDO_SEL_MASK, 0x1); | 2364 | RT5670_LDO_SEL_MASK, 0x1); |
2320 | break; | 2365 | break; |
2366 | case SND_SOC_BIAS_OFF: | ||
2367 | if (rt5670->pdata.jd_mode) | ||
2368 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | ||
2369 | RT5670_PWR_VREF1 | RT5670_PWR_MB | | ||
2370 | RT5670_PWR_BG | RT5670_PWR_VREF2 | | ||
2371 | RT5670_PWR_FV1 | RT5670_PWR_FV2, | ||
2372 | RT5670_PWR_MB | RT5670_PWR_BG); | ||
2373 | else | ||
2374 | snd_soc_update_bits(codec, RT5670_PWR_ANLG1, | ||
2375 | RT5670_PWR_VREF1 | RT5670_PWR_MB | | ||
2376 | RT5670_PWR_BG | RT5670_PWR_VREF2 | | ||
2377 | RT5670_PWR_FV1 | RT5670_PWR_FV2, 0); | ||
2378 | |||
2379 | snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0); | ||
2380 | break; | ||
2321 | 2381 | ||
2322 | default: | 2382 | default: |
2323 | break; | 2383 | break; |
@@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec) | |||
2331 | { | 2391 | { |
2332 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); | 2392 | struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec); |
2333 | 2393 | ||
2394 | switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) { | ||
2395 | case RT5670_ID_5670: | ||
2396 | case RT5670_ID_5671: | ||
2397 | snd_soc_dapm_new_controls(&codec->dapm, | ||
2398 | rt5670_specific_dapm_widgets, | ||
2399 | ARRAY_SIZE(rt5670_specific_dapm_widgets)); | ||
2400 | snd_soc_dapm_add_routes(&codec->dapm, | ||
2401 | rt5670_specific_dapm_routes, | ||
2402 | ARRAY_SIZE(rt5670_specific_dapm_routes)); | ||
2403 | break; | ||
2404 | case RT5670_ID_5672: | ||
2405 | snd_soc_dapm_new_controls(&codec->dapm, | ||
2406 | rt5672_specific_dapm_widgets, | ||
2407 | ARRAY_SIZE(rt5672_specific_dapm_widgets)); | ||
2408 | snd_soc_dapm_add_routes(&codec->dapm, | ||
2409 | rt5672_specific_dapm_routes, | ||
2410 | ARRAY_SIZE(rt5672_specific_dapm_routes)); | ||
2411 | break; | ||
2412 | default: | ||
2413 | dev_err(codec->dev, | ||
2414 | "The driver is for RT5670 RT5671 or RT5672 only\n"); | ||
2415 | return -ENODEV; | ||
2416 | } | ||
2334 | rt5670->codec = codec; | 2417 | rt5670->codec = codec; |
2335 | 2418 | ||
2336 | return 0; | 2419 | return 0; |
@@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = { | |||
2452 | 2535 | ||
2453 | static const struct i2c_device_id rt5670_i2c_id[] = { | 2536 | static const struct i2c_device_id rt5670_i2c_id[] = { |
2454 | { "rt5670", 0 }, | 2537 | { "rt5670", 0 }, |
2538 | { "rt5671", 0 }, | ||
2539 | { "rt5672", 0 }, | ||
2455 | { } | 2540 | { } |
2456 | }; | 2541 | }; |
2457 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); | 2542 | MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); |
2458 | 2543 | ||
2544 | #ifdef CONFIG_ACPI | ||
2545 | static struct acpi_device_id rt5670_acpi_match[] = { | ||
2546 | { "10EC5670", 0}, | ||
2547 | { }, | ||
2548 | }; | ||
2549 | MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); | ||
2550 | #endif | ||
2551 | |||
2459 | static int rt5670_i2c_probe(struct i2c_client *i2c, | 2552 | static int rt5670_i2c_probe(struct i2c_client *i2c, |
2460 | const struct i2c_device_id *id) | 2553 | const struct i2c_device_id *id) |
2461 | { | 2554 | { |
@@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = { | |||
2644 | .driver = { | 2737 | .driver = { |
2645 | .name = "rt5670", | 2738 | .name = "rt5670", |
2646 | .owner = THIS_MODULE, | 2739 | .owner = THIS_MODULE, |
2740 | .acpi_match_table = ACPI_PTR(rt5670_acpi_match), | ||
2647 | }, | 2741 | }, |
2648 | .probe = rt5670_i2c_probe, | 2742 | .probe = rt5670_i2c_probe, |
2649 | .remove = rt5670_i2c_remove, | 2743 | .remove = rt5670_i2c_remove, |
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h index a0b5c855b492..d11b9c207e26 100644 --- a/sound/soc/codecs/rt5670.h +++ b/sound/soc/codecs/rt5670.h | |||
@@ -228,6 +228,12 @@ | |||
228 | #define RT5670_R_VOL_MASK (0x3f) | 228 | #define RT5670_R_VOL_MASK (0x3f) |
229 | #define RT5670_R_VOL_SFT 0 | 229 | #define RT5670_R_VOL_SFT 0 |
230 | 230 | ||
231 | /* SW Reset & Device ID (0x00) */ | ||
232 | #define RT5670_ID_MASK (0x3 << 1) | ||
233 | #define RT5670_ID_5670 (0x0 << 1) | ||
234 | #define RT5670_ID_5672 (0x1 << 1) | ||
235 | #define RT5670_ID_5671 (0x2 << 1) | ||
236 | |||
231 | /* Combo Jack Control 1 (0x0a) */ | 237 | /* Combo Jack Control 1 (0x0a) */ |
232 | #define RT5670_CBJ_BST1_MASK (0xf << 12) | 238 | #define RT5670_CBJ_BST1_MASK (0xf << 12) |
233 | #define RT5670_CBJ_BST1_SFT (12) | 239 | #define RT5670_CBJ_BST1_SFT (12) |
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c new file mode 100644 index 000000000000..ef6348cb9157 --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.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 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/input.h> | ||
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/kthread.h> | ||
24 | #include <linux/uaccess.h> | ||
25 | #include <linux/miscdevice.h> | ||
26 | #include <linux/regulator/consumer.h> | ||
27 | #include <linux/pm_qos.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | #include <linux/clk.h> | ||
30 | #include <linux/firmware.h> | ||
31 | |||
32 | #include "rt5677-spi.h" | ||
33 | |||
34 | static struct spi_device *g_spi; | ||
35 | |||
36 | /** | ||
37 | * rt5677_spi_write - Write data to SPI. | ||
38 | * @txbuf: Data Buffer for writing. | ||
39 | * @len: Data length. | ||
40 | * | ||
41 | * | ||
42 | * Returns true for success. | ||
43 | */ | ||
44 | int rt5677_spi_write(u8 *txbuf, size_t len) | ||
45 | { | ||
46 | int status; | ||
47 | |||
48 | status = spi_write(g_spi, txbuf, len); | ||
49 | |||
50 | if (status) | ||
51 | dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); | ||
52 | |||
53 | return status; | ||
54 | } | ||
55 | EXPORT_SYMBOL_GPL(rt5677_spi_write); | ||
56 | |||
57 | /** | ||
58 | * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. | ||
59 | * @addr: Start address. | ||
60 | * @txbuf: Data Buffer for writng. | ||
61 | * @len: Data length, it must be a multiple of 8. | ||
62 | * | ||
63 | * | ||
64 | * Returns true for success. | ||
65 | */ | ||
66 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) | ||
67 | { | ||
68 | u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; | ||
69 | u8 *write_buf; | ||
70 | unsigned int i, end, offset = 0; | ||
71 | |||
72 | write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); | ||
73 | |||
74 | if (write_buf == NULL) | ||
75 | return -ENOMEM; | ||
76 | |||
77 | while (offset < fw->size) { | ||
78 | if (offset + RT5677_SPI_BUF_LEN <= fw->size) | ||
79 | end = RT5677_SPI_BUF_LEN; | ||
80 | else | ||
81 | end = fw->size % RT5677_SPI_BUF_LEN; | ||
82 | |||
83 | write_buf[0] = spi_cmd; | ||
84 | write_buf[1] = ((addr + offset) & 0xff000000) >> 24; | ||
85 | write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; | ||
86 | write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; | ||
87 | write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; | ||
88 | |||
89 | for (i = 0; i < end; i += 8) { | ||
90 | write_buf[i + 12] = fw->data[offset + i + 0]; | ||
91 | write_buf[i + 11] = fw->data[offset + i + 1]; | ||
92 | write_buf[i + 10] = fw->data[offset + i + 2]; | ||
93 | write_buf[i + 9] = fw->data[offset + i + 3]; | ||
94 | write_buf[i + 8] = fw->data[offset + i + 4]; | ||
95 | write_buf[i + 7] = fw->data[offset + i + 5]; | ||
96 | write_buf[i + 6] = fw->data[offset + i + 6]; | ||
97 | write_buf[i + 5] = fw->data[offset + i + 7]; | ||
98 | } | ||
99 | |||
100 | write_buf[end + 5] = spi_cmd; | ||
101 | |||
102 | rt5677_spi_write(write_buf, end + 6); | ||
103 | |||
104 | offset += RT5677_SPI_BUF_LEN; | ||
105 | } | ||
106 | |||
107 | kfree(write_buf); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); | ||
112 | |||
113 | static int rt5677_spi_probe(struct spi_device *spi) | ||
114 | { | ||
115 | g_spi = spi; | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static struct spi_driver rt5677_spi_driver = { | ||
120 | .driver = { | ||
121 | .name = "rt5677", | ||
122 | .owner = THIS_MODULE, | ||
123 | }, | ||
124 | .probe = rt5677_spi_probe, | ||
125 | }; | ||
126 | module_spi_driver(rt5677_spi_driver); | ||
127 | |||
128 | MODULE_DESCRIPTION("ASoC RT5677 SPI driver"); | ||
129 | MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); | ||
130 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h new file mode 100644 index 000000000000..ec41b2b3b2ca --- /dev/null +++ b/sound/soc/codecs/rt5677-spi.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * rt5677-spi.h -- RT5677 ALSA SoC audio codec driver | ||
3 | * | ||
4 | * Copyright 2013 Realtek Semiconductor Corp. | ||
5 | * Author: Oder Chiou <oder_chiou@realtek.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 | |||
12 | #ifndef __RT5677_SPI_H__ | ||
13 | #define __RT5677_SPI_H__ | ||
14 | |||
15 | #define RT5677_SPI_BUF_LEN 240 | ||
16 | #define RT5677_SPI_CMD_BURST_WRITE 0x05 | ||
17 | |||
18 | int rt5677_spi_write(u8 *txbuf, size_t len); | ||
19 | int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); | ||
20 | |||
21 | #endif /* __RT5677_SPI_H__ */ | ||
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 16aa4d99a713..81fe1464d268 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
22 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
23 | #include <linux/firmware.h> | ||
23 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
24 | #include <sound/core.h> | 25 | #include <sound/core.h> |
25 | #include <sound/pcm.h> | 26 | #include <sound/pcm.h> |
@@ -31,6 +32,7 @@ | |||
31 | 32 | ||
32 | #include "rl6231.h" | 33 | #include "rl6231.h" |
33 | #include "rt5677.h" | 34 | #include "rt5677.h" |
35 | #include "rt5677-spi.h" | ||
34 | 36 | ||
35 | #define RT5677_DEVICE_ID 0x6327 | 37 | #define RT5677_DEVICE_ID 0x6327 |
36 | 38 | ||
@@ -53,12 +55,13 @@ static const struct regmap_range_cfg rt5677_ranges[] = { | |||
53 | }; | 55 | }; |
54 | 56 | ||
55 | static const struct reg_default init_list[] = { | 57 | static const struct reg_default init_list[] = { |
58 | {RT5677_ASRC_12, 0x0018}, | ||
56 | {RT5677_PR_BASE + 0x3d, 0x364d}, | 59 | {RT5677_PR_BASE + 0x3d, 0x364d}, |
57 | {RT5677_PR_BASE + 0x17, 0x4fc0}, | 60 | {RT5677_PR_BASE + 0x17, 0x4fc0}, |
58 | {RT5677_PR_BASE + 0x13, 0x0312}, | 61 | {RT5677_PR_BASE + 0x13, 0x0312}, |
59 | {RT5677_PR_BASE + 0x1e, 0x0000}, | 62 | {RT5677_PR_BASE + 0x1e, 0x0000}, |
60 | {RT5677_PR_BASE + 0x12, 0x0eaa}, | 63 | {RT5677_PR_BASE + 0x12, 0x0eaa}, |
61 | {RT5677_PR_BASE + 0x14, 0x018a}, | 64 | {RT5677_PR_BASE + 0x14, 0x018a}, |
62 | }; | 65 | }; |
63 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) | 66 | #define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list) |
64 | 67 | ||
@@ -171,7 +174,7 @@ static const struct reg_default rt5677_reg[] = { | |||
171 | {RT5677_ASRC_9 , 0x0000}, | 174 | {RT5677_ASRC_9 , 0x0000}, |
172 | {RT5677_ASRC_10 , 0x0000}, | 175 | {RT5677_ASRC_10 , 0x0000}, |
173 | {RT5677_ASRC_11 , 0x0000}, | 176 | {RT5677_ASRC_11 , 0x0000}, |
174 | {RT5677_ASRC_12 , 0x0008}, | 177 | {RT5677_ASRC_12 , 0x0018}, |
175 | {RT5677_ASRC_13 , 0x0000}, | 178 | {RT5677_ASRC_13 , 0x0000}, |
176 | {RT5677_ASRC_14 , 0x0000}, | 179 | {RT5677_ASRC_14 , 0x0000}, |
177 | {RT5677_ASRC_15 , 0x0000}, | 180 | {RT5677_ASRC_15 , 0x0000}, |
@@ -537,10 +540,232 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg) | |||
537 | } | 540 | } |
538 | } | 541 | } |
539 | 542 | ||
543 | /** | ||
544 | * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode. | ||
545 | * @rt5677: Private Data. | ||
546 | * @addr: Address index. | ||
547 | * @value: Address data. | ||
548 | * | ||
549 | * | ||
550 | * Returns 0 for success or negative error code. | ||
551 | */ | ||
552 | static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677, | ||
553 | unsigned int addr, unsigned int value, unsigned int opcode) | ||
554 | { | ||
555 | struct snd_soc_codec *codec = rt5677->codec; | ||
556 | int ret; | ||
557 | |||
558 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
559 | |||
560 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, | ||
561 | addr >> 16); | ||
562 | if (ret < 0) { | ||
563 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
564 | goto err; | ||
565 | } | ||
566 | |||
567 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, | ||
568 | addr & 0xffff); | ||
569 | if (ret < 0) { | ||
570 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
571 | goto err; | ||
572 | } | ||
573 | |||
574 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, | ||
575 | value >> 16); | ||
576 | if (ret < 0) { | ||
577 | dev_err(codec->dev, "Failed to set data msb value: %d\n", ret); | ||
578 | goto err; | ||
579 | } | ||
580 | |||
581 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, | ||
582 | value & 0xffff); | ||
583 | if (ret < 0) { | ||
584 | dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret); | ||
585 | goto err; | ||
586 | } | ||
587 | |||
588 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, | ||
589 | opcode); | ||
590 | if (ret < 0) { | ||
591 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
592 | goto err; | ||
593 | } | ||
594 | |||
595 | err: | ||
596 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
597 | |||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode. | ||
603 | * rt5677: Private Data. | ||
604 | * @addr: Address index. | ||
605 | * @value: Address data. | ||
606 | * | ||
607 | * | ||
608 | * Returns 0 for success or negative error code. | ||
609 | */ | ||
610 | static int rt5677_dsp_mode_i2c_read_addr( | ||
611 | struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value) | ||
612 | { | ||
613 | struct snd_soc_codec *codec = rt5677->codec; | ||
614 | int ret; | ||
615 | unsigned int msb, lsb; | ||
616 | |||
617 | mutex_lock(&rt5677->dsp_cmd_lock); | ||
618 | |||
619 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB, | ||
620 | addr >> 16); | ||
621 | if (ret < 0) { | ||
622 | dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret); | ||
623 | goto err; | ||
624 | } | ||
625 | |||
626 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB, | ||
627 | addr & 0xffff); | ||
628 | if (ret < 0) { | ||
629 | dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret); | ||
630 | goto err; | ||
631 | } | ||
632 | |||
633 | ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE, | ||
634 | 0x0002); | ||
635 | if (ret < 0) { | ||
636 | dev_err(codec->dev, "Failed to set op code value: %d\n", ret); | ||
637 | goto err; | ||
638 | } | ||
639 | |||
640 | regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb); | ||
641 | regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb); | ||
642 | *value = (msb << 16) | lsb; | ||
643 | |||
644 | err: | ||
645 | mutex_unlock(&rt5677->dsp_cmd_lock); | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * rt5677_dsp_mode_i2c_write - Write register on DSP mode. | ||
652 | * rt5677: Private Data. | ||
653 | * @reg: Register index. | ||
654 | * @value: Register data. | ||
655 | * | ||
656 | * | ||
657 | * Returns 0 for success or negative error code. | ||
658 | */ | ||
659 | static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677, | ||
660 | unsigned int reg, unsigned int value) | ||
661 | { | ||
662 | return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2, | ||
663 | value, 0x0001); | ||
664 | } | ||
665 | |||
666 | /** | ||
667 | * rt5677_dsp_mode_i2c_read - Read register on DSP mode. | ||
668 | * @codec: SoC audio codec device. | ||
669 | * @reg: Register index. | ||
670 | * @value: Register data. | ||
671 | * | ||
672 | * | ||
673 | * Returns 0 for success or negative error code. | ||
674 | */ | ||
675 | static int rt5677_dsp_mode_i2c_read( | ||
676 | struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value) | ||
677 | { | ||
678 | int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2, | ||
679 | value); | ||
680 | |||
681 | *value &= 0xffff; | ||
682 | |||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on) | ||
687 | { | ||
688 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
689 | |||
690 | if (on) { | ||
691 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2); | ||
692 | rt5677->is_dsp_mode = true; | ||
693 | } else { | ||
694 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0); | ||
695 | rt5677->is_dsp_mode = false; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) | ||
700 | { | ||
701 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
702 | static bool activity; | ||
703 | int ret; | ||
704 | |||
705 | if (on && !activity) { | ||
706 | activity = true; | ||
707 | |||
708 | regcache_cache_only(rt5677->regmap, false); | ||
709 | regcache_cache_bypass(rt5677->regmap, true); | ||
710 | |||
711 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1); | ||
712 | regmap_update_bits(rt5677->regmap, | ||
713 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00); | ||
714 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
715 | RT5677_LDO1_SEL_MASK, 0x0); | ||
716 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, | ||
717 | RT5677_PWR_LDO1, RT5677_PWR_LDO1); | ||
718 | regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1, | ||
719 | RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC); | ||
720 | regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2, | ||
721 | RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK, | ||
722 | RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS); | ||
723 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff); | ||
724 | regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd); | ||
725 | rt5677_set_dsp_mode(codec, true); | ||
726 | |||
727 | ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, | ||
728 | codec->dev); | ||
729 | if (ret == 0) { | ||
730 | rt5677_spi_burst_write(0x50000000, rt5677->fw1); | ||
731 | release_firmware(rt5677->fw1); | ||
732 | } | ||
733 | |||
734 | ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, | ||
735 | codec->dev); | ||
736 | if (ret == 0) { | ||
737 | rt5677_spi_burst_write(0x60000000, rt5677->fw2); | ||
738 | release_firmware(rt5677->fw2); | ||
739 | } | ||
740 | |||
741 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0); | ||
742 | |||
743 | regcache_cache_bypass(rt5677->regmap, false); | ||
744 | regcache_cache_only(rt5677->regmap, true); | ||
745 | } else if (!on && activity) { | ||
746 | activity = false; | ||
747 | |||
748 | regcache_cache_only(rt5677->regmap, false); | ||
749 | regcache_cache_bypass(rt5677->regmap, true); | ||
750 | |||
751 | regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1); | ||
752 | rt5677_set_dsp_mode(codec, false); | ||
753 | regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001); | ||
754 | |||
755 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); | ||
756 | |||
757 | regcache_cache_bypass(rt5677->regmap, false); | ||
758 | regcache_mark_dirty(rt5677->regmap); | ||
759 | regcache_sync(rt5677->regmap); | ||
760 | } | ||
761 | |||
762 | return 0; | ||
763 | } | ||
764 | |||
540 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); | 765 | static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0); |
541 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | 766 | static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0); |
542 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 767 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
543 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); | 768 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0); |
544 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); | 769 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); |
545 | static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); | 770 | static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); |
546 | 771 | ||
@@ -556,6 +781,31 @@ static unsigned int bst_tlv[] = { | |||
556 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), | 781 | 8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0), |
557 | }; | 782 | }; |
558 | 783 | ||
784 | static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol, | ||
785 | struct snd_ctl_elem_value *ucontrol) | ||
786 | { | ||
787 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
788 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
789 | |||
790 | ucontrol->value.integer.value[0] = rt5677->dsp_vad_en; | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol, | ||
796 | struct snd_ctl_elem_value *ucontrol) | ||
797 | { | ||
798 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
799 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
800 | |||
801 | rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0]; | ||
802 | |||
803 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
804 | rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en); | ||
805 | |||
806 | return 0; | ||
807 | } | ||
808 | |||
559 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { | 809 | static const struct snd_kcontrol_new rt5677_snd_controls[] = { |
560 | /* OUTPUT Control */ | 810 | /* OUTPUT Control */ |
561 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, | 811 | SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1, |
@@ -567,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
567 | 817 | ||
568 | /* DAC Digital Volume */ | 818 | /* DAC Digital Volume */ |
569 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, | 819 | SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL, |
570 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 820 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
571 | SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, | 821 | SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL, |
572 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 822 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
573 | SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, | 823 | SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL, |
574 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 824 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
575 | SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, | 825 | SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL, |
576 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv), | 826 | RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv), |
577 | 827 | ||
578 | /* IN1/IN2 Control */ | 828 | /* IN1/IN2 Control */ |
579 | SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), | 829 | SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv), |
@@ -592,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
592 | RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), | 842 | RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1), |
593 | 843 | ||
594 | SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, | 844 | SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL, |
595 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 845 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
596 | adc_vol_tlv), | 846 | adc_vol_tlv), |
597 | SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, | 847 | SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL, |
598 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 848 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
599 | adc_vol_tlv), | 849 | adc_vol_tlv), |
600 | SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, | 850 | SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL, |
601 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 851 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
602 | adc_vol_tlv), | 852 | adc_vol_tlv), |
603 | SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, | 853 | SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL, |
604 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0, | 854 | RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0, |
605 | adc_vol_tlv), | 855 | adc_vol_tlv), |
606 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, | 856 | SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL, |
607 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, | 857 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0, |
608 | adc_vol_tlv), | 858 | adc_vol_tlv), |
609 | 859 | ||
610 | /* Sidetone Control */ | 860 | /* Sidetone Control */ |
@@ -627,6 +877,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
627 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, | 877 | SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2, |
628 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, | 878 | RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0, |
629 | adc_bst_tlv), | 879 | adc_bst_tlv), |
880 | |||
881 | SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0, | ||
882 | rt5677_dsp_vad_get, rt5677_dsp_vad_put), | ||
630 | }; | 883 | }; |
631 | 884 | ||
632 | /** | 885 | /** |
@@ -1086,7 +1339,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1086 | static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = | 1339 | static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux = |
1087 | SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); | 1340 | SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum); |
1088 | 1341 | ||
1089 | /* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ | 1342 | /* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */ |
1090 | static const char * const rt5677_stereo_adc2_src[] = { | 1343 | static const char * const rt5677_stereo_adc2_src[] = { |
1091 | "DD MIX1", "DMIC", "Stereo DAC MIX" | 1344 | "DD MIX1", "DMIC", "Stereo DAC MIX" |
1092 | }; | 1345 | }; |
@@ -1171,7 +1424,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1171 | static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = | 1424 | static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux = |
1172 | SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum); | 1425 | SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum); |
1173 | 1426 | ||
1174 | /* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ | 1427 | /* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */ |
1175 | static const char * const rt5677_stereo_adc1_src[] = { | 1428 | static const char * const rt5677_stereo_adc1_src[] = { |
1176 | "DD MIX1", "ADC1/2", "Stereo DAC MIX" | 1429 | "DD MIX1", "ADC1/2", "Stereo DAC MIX" |
1177 | }; | 1430 | }; |
@@ -1443,7 +1696,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1443 | static const struct snd_kcontrol_new rt5677_pdm2_r_mux = | 1696 | static const struct snd_kcontrol_new rt5677_pdm2_r_mux = |
1444 | SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum); | 1697 | SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum); |
1445 | 1698 | ||
1446 | /* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/ | 1699 | /* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */ |
1447 | static const char * const rt5677_if12_adc1_src[] = { | 1700 | static const char * const rt5677_if12_adc1_src[] = { |
1448 | "STO1 ADC MIX", "OB01", "VAD ADC" | 1701 | "STO1 ADC MIX", "OB01", "VAD ADC" |
1449 | }; | 1702 | }; |
@@ -1521,7 +1774,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1521 | static const struct snd_kcontrol_new rt5677_slb_adc3_mux = | 1774 | static const struct snd_kcontrol_new rt5677_slb_adc3_mux = |
1522 | SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum); | 1775 | SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum); |
1523 | 1776 | ||
1524 | /* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ | 1777 | /* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */ |
1525 | static const char * const rt5677_if12_adc4_src[] = { | 1778 | static const char * const rt5677_if12_adc4_src[] = { |
1526 | "STO4 ADC MIX", "OB67", "OB01" | 1779 | "STO4 ADC MIX", "OB67", "OB01" |
1527 | }; | 1780 | }; |
@@ -1547,7 +1800,7 @@ static SOC_ENUM_SINGLE_DECL( | |||
1547 | static const struct snd_kcontrol_new rt5677_slb_adc4_mux = | 1800 | static const struct snd_kcontrol_new rt5677_slb_adc4_mux = |
1548 | SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum); | 1801 | SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum); |
1549 | 1802 | ||
1550 | /* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/ | 1803 | /* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */ |
1551 | static const char * const rt5677_if34_adc_src[] = { | 1804 | static const char * const rt5677_if34_adc_src[] = { |
1552 | "STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", | 1805 | "STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX", |
1553 | "MONO ADC MIX", "OB01", "OB23", "VAD ADC" | 1806 | "MONO ADC MIX", "OB01", "OB23", "VAD ADC" |
@@ -1567,6 +1820,213 @@ static SOC_ENUM_SINGLE_DECL( | |||
1567 | static const struct snd_kcontrol_new rt5677_if4_adc_mux = | 1820 | static const struct snd_kcontrol_new rt5677_if4_adc_mux = |
1568 | SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum); | 1821 | SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum); |
1569 | 1822 | ||
1823 | /* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */ | ||
1824 | static const char * const rt5677_if12_adc_swap_src[] = { | ||
1825 | "L/R", "R/L", "L/L", "R/R" | ||
1826 | }; | ||
1827 | |||
1828 | static SOC_ENUM_SINGLE_DECL( | ||
1829 | rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1, | ||
1830 | RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1831 | |||
1832 | static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux = | ||
1833 | SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum); | ||
1834 | |||
1835 | static SOC_ENUM_SINGLE_DECL( | ||
1836 | rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1, | ||
1837 | RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1838 | |||
1839 | static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux = | ||
1840 | SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum); | ||
1841 | |||
1842 | static SOC_ENUM_SINGLE_DECL( | ||
1843 | rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1, | ||
1844 | RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1845 | |||
1846 | static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux = | ||
1847 | SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum); | ||
1848 | |||
1849 | static SOC_ENUM_SINGLE_DECL( | ||
1850 | rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1, | ||
1851 | RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1852 | |||
1853 | static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux = | ||
1854 | SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum); | ||
1855 | |||
1856 | static SOC_ENUM_SINGLE_DECL( | ||
1857 | rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1, | ||
1858 | RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1859 | |||
1860 | static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux = | ||
1861 | SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum); | ||
1862 | |||
1863 | static SOC_ENUM_SINGLE_DECL( | ||
1864 | rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1, | ||
1865 | RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1866 | |||
1867 | static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux = | ||
1868 | SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum); | ||
1869 | |||
1870 | static SOC_ENUM_SINGLE_DECL( | ||
1871 | rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1, | ||
1872 | RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1873 | |||
1874 | static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux = | ||
1875 | SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum); | ||
1876 | |||
1877 | static SOC_ENUM_SINGLE_DECL( | ||
1878 | rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1, | ||
1879 | RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src); | ||
1880 | |||
1881 | static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux = | ||
1882 | SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum); | ||
1883 | |||
1884 | /* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */ | ||
1885 | static const char * const rt5677_if1_adc_tdm_swap_src[] = { | ||
1886 | "1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", | ||
1887 | "3/1/2/4", "3/4/1/2" | ||
1888 | }; | ||
1889 | |||
1890 | static SOC_ENUM_SINGLE_DECL( | ||
1891 | rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2, | ||
1892 | RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src); | ||
1893 | |||
1894 | static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux = | ||
1895 | SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum); | ||
1896 | |||
1897 | /* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */ | ||
1898 | static const char * const rt5677_if2_adc_tdm_swap_src[] = { | ||
1899 | "1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3", | ||
1900 | "2/3/1/4", "3/4/1/2" | ||
1901 | }; | ||
1902 | |||
1903 | static SOC_ENUM_SINGLE_DECL( | ||
1904 | rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2, | ||
1905 | RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src); | ||
1906 | |||
1907 | static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux = | ||
1908 | SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum); | ||
1909 | |||
1910 | /* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0] | ||
1911 | MX-3F[14:12][10:8][6:4][2:0] | ||
1912 | MX-43[14:12][10:8][6:4][2:0] | ||
1913 | MX-44[14:12][10:8][6:4][2:0] */ | ||
1914 | static const char * const rt5677_if12_dac_tdm_sel_src[] = { | ||
1915 | "Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7" | ||
1916 | }; | ||
1917 | |||
1918 | static SOC_ENUM_SINGLE_DECL( | ||
1919 | rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1920 | RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1921 | |||
1922 | static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux = | ||
1923 | SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum); | ||
1924 | |||
1925 | static SOC_ENUM_SINGLE_DECL( | ||
1926 | rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1927 | RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1928 | |||
1929 | static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux = | ||
1930 | SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum); | ||
1931 | |||
1932 | static SOC_ENUM_SINGLE_DECL( | ||
1933 | rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1934 | RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1935 | |||
1936 | static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux = | ||
1937 | SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum); | ||
1938 | |||
1939 | static SOC_ENUM_SINGLE_DECL( | ||
1940 | rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4, | ||
1941 | RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1942 | |||
1943 | static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux = | ||
1944 | SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum); | ||
1945 | |||
1946 | static SOC_ENUM_SINGLE_DECL( | ||
1947 | rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1948 | RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1949 | |||
1950 | static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux = | ||
1951 | SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum); | ||
1952 | |||
1953 | static SOC_ENUM_SINGLE_DECL( | ||
1954 | rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1955 | RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1956 | |||
1957 | static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux = | ||
1958 | SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum); | ||
1959 | |||
1960 | static SOC_ENUM_SINGLE_DECL( | ||
1961 | rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1962 | RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1963 | |||
1964 | static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux = | ||
1965 | SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum); | ||
1966 | |||
1967 | static SOC_ENUM_SINGLE_DECL( | ||
1968 | rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5, | ||
1969 | RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1970 | |||
1971 | static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux = | ||
1972 | SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum); | ||
1973 | |||
1974 | static SOC_ENUM_SINGLE_DECL( | ||
1975 | rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1976 | RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1977 | |||
1978 | static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux = | ||
1979 | SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum); | ||
1980 | |||
1981 | static SOC_ENUM_SINGLE_DECL( | ||
1982 | rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1983 | RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1984 | |||
1985 | static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux = | ||
1986 | SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum); | ||
1987 | |||
1988 | static SOC_ENUM_SINGLE_DECL( | ||
1989 | rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1990 | RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1991 | |||
1992 | static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux = | ||
1993 | SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum); | ||
1994 | |||
1995 | static SOC_ENUM_SINGLE_DECL( | ||
1996 | rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4, | ||
1997 | RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src); | ||
1998 | |||
1999 | static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux = | ||
2000 | SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum); | ||
2001 | |||
2002 | static SOC_ENUM_SINGLE_DECL( | ||
2003 | rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2004 | RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2005 | |||
2006 | static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux = | ||
2007 | SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum); | ||
2008 | |||
2009 | static SOC_ENUM_SINGLE_DECL( | ||
2010 | rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2011 | RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2012 | |||
2013 | static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux = | ||
2014 | SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum); | ||
2015 | |||
2016 | static SOC_ENUM_SINGLE_DECL( | ||
2017 | rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2018 | RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2019 | |||
2020 | static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux = | ||
2021 | SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum); | ||
2022 | |||
2023 | static SOC_ENUM_SINGLE_DECL( | ||
2024 | rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5, | ||
2025 | RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src); | ||
2026 | |||
2027 | static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux = | ||
2028 | SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum); | ||
2029 | |||
1570 | static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, | 2030 | static int rt5677_bst1_event(struct snd_soc_dapm_widget *w, |
1571 | struct snd_kcontrol *kcontrol, int event) | 2031 | struct snd_kcontrol *kcontrol, int event) |
1572 | { | 2032 | { |
@@ -1678,6 +2138,77 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w, | |||
1678 | return 0; | 2138 | return 0; |
1679 | } | 2139 | } |
1680 | 2140 | ||
2141 | static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w, | ||
2142 | struct snd_kcontrol *kcontrol, int event) | ||
2143 | { | ||
2144 | struct snd_soc_codec *codec = w->codec; | ||
2145 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2146 | unsigned int value; | ||
2147 | |||
2148 | switch (event) { | ||
2149 | case SND_SOC_DAPM_PRE_PMU: | ||
2150 | regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value); | ||
2151 | if (value & RT5677_IF1_ADC_CTRL_MASK) | ||
2152 | regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1, | ||
2153 | RT5677_IF1_ADC_MODE_MASK, | ||
2154 | RT5677_IF1_ADC_MODE_TDM); | ||
2155 | break; | ||
2156 | |||
2157 | default: | ||
2158 | return 0; | ||
2159 | } | ||
2160 | |||
2161 | return 0; | ||
2162 | } | ||
2163 | |||
2164 | static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w, | ||
2165 | struct snd_kcontrol *kcontrol, int event) | ||
2166 | { | ||
2167 | struct snd_soc_codec *codec = w->codec; | ||
2168 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2169 | unsigned int value; | ||
2170 | |||
2171 | switch (event) { | ||
2172 | case SND_SOC_DAPM_PRE_PMU: | ||
2173 | regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value); | ||
2174 | if (value & RT5677_IF2_ADC_CTRL_MASK) | ||
2175 | regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1, | ||
2176 | RT5677_IF2_ADC_MODE_MASK, | ||
2177 | RT5677_IF2_ADC_MODE_TDM); | ||
2178 | break; | ||
2179 | |||
2180 | default: | ||
2181 | return 0; | ||
2182 | } | ||
2183 | |||
2184 | return 0; | ||
2185 | } | ||
2186 | |||
2187 | static int rt5677_vref_event(struct snd_soc_dapm_widget *w, | ||
2188 | struct snd_kcontrol *kcontrol, int event) | ||
2189 | { | ||
2190 | struct snd_soc_codec *codec = w->codec; | ||
2191 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | ||
2192 | |||
2193 | switch (event) { | ||
2194 | case SND_SOC_DAPM_POST_PMU: | ||
2195 | if (codec->dapm.bias_level != SND_SOC_BIAS_ON && | ||
2196 | !rt5677->is_vref_slow) { | ||
2197 | mdelay(20); | ||
2198 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
2199 | RT5677_PWR_FV1 | RT5677_PWR_FV2, | ||
2200 | RT5677_PWR_FV1 | RT5677_PWR_FV2); | ||
2201 | rt5677->is_vref_slow = true; | ||
2202 | } | ||
2203 | break; | ||
2204 | |||
2205 | default: | ||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | return 0; | ||
2210 | } | ||
2211 | |||
1681 | static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | 2212 | static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { |
1682 | SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, | 2213 | SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT, |
1683 | 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), | 2214 | 0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU), |
@@ -1837,10 +2368,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1837 | SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2368 | SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1838 | SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2369 | SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1839 | SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), | 2370 | SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0), |
1840 | SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0), | 2371 | SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), |
1841 | SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0), | 2372 | SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), |
1842 | SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1843 | SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
1844 | 2373 | ||
1845 | /* DSP */ | 2374 | /* DSP */ |
1846 | SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, | 2375 | SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0, |
@@ -1963,6 +2492,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1963 | &rt5677_if1_adc3_mux), | 2492 | &rt5677_if1_adc3_mux), |
1964 | SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2493 | SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1965 | &rt5677_if1_adc4_mux), | 2494 | &rt5677_if1_adc4_mux), |
2495 | SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2496 | &rt5677_if1_adc1_swap_mux), | ||
2497 | SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2498 | &rt5677_if1_adc2_swap_mux), | ||
2499 | SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2500 | &rt5677_if1_adc3_swap_mux), | ||
2501 | SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2502 | &rt5677_if1_adc4_swap_mux), | ||
2503 | SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2504 | &rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event, | ||
2505 | SND_SOC_DAPM_PRE_PMU), | ||
1966 | SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, | 2506 | SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0, |
1967 | &rt5677_if2_adc1_mux), | 2507 | &rt5677_if2_adc1_mux), |
1968 | SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, | 2508 | SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0, |
@@ -1971,6 +2511,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1971 | &rt5677_if2_adc3_mux), | 2511 | &rt5677_if2_adc3_mux), |
1972 | SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2512 | SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1973 | &rt5677_if2_adc4_mux), | 2513 | &rt5677_if2_adc4_mux), |
2514 | SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2515 | &rt5677_if2_adc1_swap_mux), | ||
2516 | SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2517 | &rt5677_if2_adc2_swap_mux), | ||
2518 | SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2519 | &rt5677_if2_adc3_swap_mux), | ||
2520 | SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2521 | &rt5677_if2_adc4_swap_mux), | ||
2522 | SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0, | ||
2523 | &rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event, | ||
2524 | SND_SOC_DAPM_PRE_PMU), | ||
1974 | SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, | 2525 | SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0, |
1975 | &rt5677_if3_adc_mux), | 2526 | &rt5677_if3_adc_mux), |
1976 | SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, | 2527 | SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0, |
@@ -1984,6 +2535,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1984 | SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, | 2535 | SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0, |
1985 | &rt5677_slb_adc4_mux), | 2536 | &rt5677_slb_adc4_mux), |
1986 | 2537 | ||
2538 | SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0, | ||
2539 | &rt5677_if1_dac0_tdm_sel_mux), | ||
2540 | SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0, | ||
2541 | &rt5677_if1_dac1_tdm_sel_mux), | ||
2542 | SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0, | ||
2543 | &rt5677_if1_dac2_tdm_sel_mux), | ||
2544 | SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0, | ||
2545 | &rt5677_if1_dac3_tdm_sel_mux), | ||
2546 | SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0, | ||
2547 | &rt5677_if1_dac4_tdm_sel_mux), | ||
2548 | SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0, | ||
2549 | &rt5677_if1_dac5_tdm_sel_mux), | ||
2550 | SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0, | ||
2551 | &rt5677_if1_dac6_tdm_sel_mux), | ||
2552 | SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0, | ||
2553 | &rt5677_if1_dac7_tdm_sel_mux), | ||
2554 | |||
2555 | SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0, | ||
2556 | &rt5677_if2_dac0_tdm_sel_mux), | ||
2557 | SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0, | ||
2558 | &rt5677_if2_dac1_tdm_sel_mux), | ||
2559 | SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0, | ||
2560 | &rt5677_if2_dac2_tdm_sel_mux), | ||
2561 | SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0, | ||
2562 | &rt5677_if2_dac3_tdm_sel_mux), | ||
2563 | SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0, | ||
2564 | &rt5677_if2_dac4_tdm_sel_mux), | ||
2565 | SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0, | ||
2566 | &rt5677_if2_dac5_tdm_sel_mux), | ||
2567 | SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0, | ||
2568 | &rt5677_if2_dac6_tdm_sel_mux), | ||
2569 | SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0, | ||
2570 | &rt5677_if2_dac7_tdm_sel_mux), | ||
2571 | |||
1987 | /* Audio Interface */ | 2572 | /* Audio Interface */ |
1988 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), | 2573 | SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), |
1989 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), | 2574 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), |
@@ -2022,7 +2607,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2022 | rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), | 2607 | rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)), |
2023 | 2608 | ||
2024 | /* Output Side */ | 2609 | /* Output Side */ |
2025 | /* DAC mixer before sound effect */ | 2610 | /* DAC mixer before sound effect */ |
2026 | SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, | 2611 | SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0, |
2027 | rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), | 2612 | rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)), |
2028 | SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, | 2613 | SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0, |
@@ -2109,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2109 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, | 2694 | SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT, |
2110 | 1, &rt5677_pdm2_r_mux), | 2695 | 1, &rt5677_pdm2_r_mux), |
2111 | 2696 | ||
2112 | SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, | 2697 | SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT, |
2113 | 0, NULL, 0), | 2698 | 0, NULL, 0), |
2114 | SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, | 2699 | SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT, |
2115 | 0, NULL, 0), | 2700 | 0, NULL, 0), |
2116 | SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, | 2701 | SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT, |
2117 | 0, NULL, 0), | 2702 | 0, NULL, 0), |
2118 | 2703 | ||
2704 | SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2705 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2706 | SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2707 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2708 | SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0, | ||
2709 | rt5677_vref_event, SND_SOC_DAPM_POST_PMU), | ||
2710 | |||
2119 | /* Output Lines */ | 2711 | /* Output Lines */ |
2120 | SND_SOC_DAPM_OUTPUT("LOUT1"), | 2712 | SND_SOC_DAPM_OUTPUT("LOUT1"), |
2121 | SND_SOC_DAPM_OUTPUT("LOUT2"), | 2713 | SND_SOC_DAPM_OUTPUT("LOUT2"), |
@@ -2124,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
2124 | SND_SOC_DAPM_OUTPUT("PDM1R"), | 2716 | SND_SOC_DAPM_OUTPUT("PDM1R"), |
2125 | SND_SOC_DAPM_OUTPUT("PDM2L"), | 2717 | SND_SOC_DAPM_OUTPUT("PDM2L"), |
2126 | SND_SOC_DAPM_OUTPUT("PDM2R"), | 2718 | SND_SOC_DAPM_OUTPUT("PDM2R"), |
2719 | |||
2720 | SND_SOC_DAPM_POST("vref", rt5677_vref_event), | ||
2127 | }; | 2721 | }; |
2128 | 2722 | ||
2129 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | 2723 | static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { |
@@ -2354,11 +2948,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2354 | { "IF1 ADC4 Mux", "OB67", "OB67" }, | 2948 | { "IF1 ADC4 Mux", "OB67", "OB67" }, |
2355 | { "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, | 2949 | { "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, |
2356 | 2950 | ||
2951 | { "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" }, | ||
2952 | { "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" }, | ||
2953 | { "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" }, | ||
2954 | { "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" }, | ||
2955 | |||
2956 | { "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" }, | ||
2957 | { "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" }, | ||
2958 | { "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" }, | ||
2959 | { "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" }, | ||
2960 | |||
2961 | { "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" }, | ||
2962 | { "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" }, | ||
2963 | { "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" }, | ||
2964 | { "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" }, | ||
2965 | |||
2966 | { "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" }, | ||
2967 | { "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" }, | ||
2968 | { "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" }, | ||
2969 | { "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" }, | ||
2970 | |||
2971 | { "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" }, | ||
2972 | { "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" }, | ||
2973 | { "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" }, | ||
2974 | { "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" }, | ||
2975 | |||
2976 | { "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" }, | ||
2977 | { "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" }, | ||
2978 | { "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" }, | ||
2979 | { "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" }, | ||
2980 | { "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" }, | ||
2981 | { "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" }, | ||
2982 | { "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" }, | ||
2983 | { "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" }, | ||
2984 | |||
2357 | { "AIF1TX", NULL, "I2S1" }, | 2985 | { "AIF1TX", NULL, "I2S1" }, |
2358 | { "AIF1TX", NULL, "IF1 ADC1 Mux" }, | 2986 | { "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" }, |
2359 | { "AIF1TX", NULL, "IF1 ADC2 Mux" }, | ||
2360 | { "AIF1TX", NULL, "IF1 ADC3 Mux" }, | ||
2361 | { "AIF1TX", NULL, "IF1 ADC4 Mux" }, | ||
2362 | 2987 | ||
2363 | { "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, | 2988 | { "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, |
2364 | { "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, | 2989 | { "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" }, |
@@ -2375,11 +3000,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2375 | { "IF2 ADC4 Mux", "OB67", "OB67" }, | 3000 | { "IF2 ADC4 Mux", "OB67", "OB67" }, |
2376 | { "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, | 3001 | { "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" }, |
2377 | 3002 | ||
3003 | { "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" }, | ||
3004 | { "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" }, | ||
3005 | { "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" }, | ||
3006 | { "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" }, | ||
3007 | |||
3008 | { "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" }, | ||
3009 | { "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" }, | ||
3010 | { "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" }, | ||
3011 | { "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" }, | ||
3012 | |||
3013 | { "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" }, | ||
3014 | { "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" }, | ||
3015 | { "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" }, | ||
3016 | { "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" }, | ||
3017 | |||
3018 | { "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" }, | ||
3019 | { "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" }, | ||
3020 | { "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" }, | ||
3021 | { "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" }, | ||
3022 | |||
3023 | { "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" }, | ||
3024 | { "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" }, | ||
3025 | { "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" }, | ||
3026 | { "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" }, | ||
3027 | |||
3028 | { "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" }, | ||
3029 | { "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" }, | ||
3030 | { "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" }, | ||
3031 | { "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" }, | ||
3032 | { "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" }, | ||
3033 | { "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" }, | ||
3034 | { "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" }, | ||
3035 | { "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" }, | ||
3036 | |||
2378 | { "AIF2TX", NULL, "I2S2" }, | 3037 | { "AIF2TX", NULL, "I2S2" }, |
2379 | { "AIF2TX", NULL, "IF2 ADC1 Mux" }, | 3038 | { "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" }, |
2380 | { "AIF2TX", NULL, "IF2 ADC2 Mux" }, | ||
2381 | { "AIF2TX", NULL, "IF2 ADC3 Mux" }, | ||
2382 | { "AIF2TX", NULL, "IF2 ADC4 Mux" }, | ||
2383 | 3039 | ||
2384 | { "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, | 3040 | { "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" }, |
2385 | { "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, | 3041 | { "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" }, |
@@ -2569,14 +3225,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2569 | { "IF1 DAC6", NULL, "I2S1" }, | 3225 | { "IF1 DAC6", NULL, "I2S1" }, |
2570 | { "IF1 DAC7", NULL, "I2S1" }, | 3226 | { "IF1 DAC7", NULL, "I2S1" }, |
2571 | 3227 | ||
2572 | { "IF1 DAC01", NULL, "IF1 DAC0" }, | 3228 | { "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" }, |
2573 | { "IF1 DAC01", NULL, "IF1 DAC1" }, | 3229 | { "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" }, |
2574 | { "IF1 DAC23", NULL, "IF1 DAC2" }, | 3230 | { "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" }, |
2575 | { "IF1 DAC23", NULL, "IF1 DAC3" }, | 3231 | { "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" }, |
2576 | { "IF1 DAC45", NULL, "IF1 DAC4" }, | 3232 | { "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" }, |
2577 | { "IF1 DAC45", NULL, "IF1 DAC5" }, | 3233 | { "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" }, |
2578 | { "IF1 DAC67", NULL, "IF1 DAC6" }, | 3234 | { "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" }, |
2579 | { "IF1 DAC67", NULL, "IF1 DAC7" }, | 3235 | { "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" }, |
3236 | |||
3237 | { "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" }, | ||
3238 | { "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" }, | ||
3239 | { "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" }, | ||
3240 | { "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" }, | ||
3241 | { "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" }, | ||
3242 | { "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" }, | ||
3243 | { "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" }, | ||
3244 | { "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" }, | ||
3245 | |||
3246 | { "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" }, | ||
3247 | { "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" }, | ||
3248 | { "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" }, | ||
3249 | { "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" }, | ||
3250 | { "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" }, | ||
3251 | { "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" }, | ||
3252 | { "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" }, | ||
3253 | { "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" }, | ||
3254 | |||
3255 | { "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" }, | ||
3256 | { "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" }, | ||
3257 | { "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" }, | ||
3258 | { "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" }, | ||
3259 | { "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" }, | ||
3260 | { "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" }, | ||
3261 | { "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" }, | ||
3262 | { "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" }, | ||
3263 | |||
3264 | { "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" }, | ||
3265 | { "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" }, | ||
3266 | { "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" }, | ||
3267 | { "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" }, | ||
3268 | { "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" }, | ||
3269 | { "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" }, | ||
3270 | { "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" }, | ||
3271 | { "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" }, | ||
3272 | |||
3273 | { "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" }, | ||
3274 | { "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" }, | ||
3275 | { "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" }, | ||
3276 | { "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" }, | ||
3277 | { "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" }, | ||
3278 | { "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" }, | ||
3279 | { "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" }, | ||
3280 | { "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" }, | ||
3281 | |||
3282 | { "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" }, | ||
3283 | { "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" }, | ||
3284 | { "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" }, | ||
3285 | { "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" }, | ||
3286 | { "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" }, | ||
3287 | { "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" }, | ||
3288 | { "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" }, | ||
3289 | { "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" }, | ||
3290 | |||
3291 | { "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" }, | ||
3292 | { "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" }, | ||
3293 | { "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" }, | ||
3294 | { "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" }, | ||
3295 | { "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" }, | ||
3296 | { "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" }, | ||
3297 | { "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" }, | ||
3298 | { "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" }, | ||
3299 | |||
3300 | { "IF1 DAC01", NULL, "IF1 DAC0 Mux" }, | ||
3301 | { "IF1 DAC01", NULL, "IF1 DAC1 Mux" }, | ||
3302 | { "IF1 DAC23", NULL, "IF1 DAC2 Mux" }, | ||
3303 | { "IF1 DAC23", NULL, "IF1 DAC3 Mux" }, | ||
3304 | { "IF1 DAC45", NULL, "IF1 DAC4 Mux" }, | ||
3305 | { "IF1 DAC45", NULL, "IF1 DAC5 Mux" }, | ||
3306 | { "IF1 DAC67", NULL, "IF1 DAC6 Mux" }, | ||
3307 | { "IF1 DAC67", NULL, "IF1 DAC7 Mux" }, | ||
2580 | 3308 | ||
2581 | { "IF2 DAC0", NULL, "AIF2RX" }, | 3309 | { "IF2 DAC0", NULL, "AIF2RX" }, |
2582 | { "IF2 DAC1", NULL, "AIF2RX" }, | 3310 | { "IF2 DAC1", NULL, "AIF2RX" }, |
@@ -2595,14 +3323,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2595 | { "IF2 DAC6", NULL, "I2S2" }, | 3323 | { "IF2 DAC6", NULL, "I2S2" }, |
2596 | { "IF2 DAC7", NULL, "I2S2" }, | 3324 | { "IF2 DAC7", NULL, "I2S2" }, |
2597 | 3325 | ||
2598 | { "IF2 DAC01", NULL, "IF2 DAC0" }, | 3326 | { "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" }, |
2599 | { "IF2 DAC01", NULL, "IF2 DAC1" }, | 3327 | { "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" }, |
2600 | { "IF2 DAC23", NULL, "IF2 DAC2" }, | 3328 | { "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" }, |
2601 | { "IF2 DAC23", NULL, "IF2 DAC3" }, | 3329 | { "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" }, |
2602 | { "IF2 DAC45", NULL, "IF2 DAC4" }, | 3330 | { "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" }, |
2603 | { "IF2 DAC45", NULL, "IF2 DAC5" }, | 3331 | { "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" }, |
2604 | { "IF2 DAC67", NULL, "IF2 DAC6" }, | 3332 | { "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" }, |
2605 | { "IF2 DAC67", NULL, "IF2 DAC7" }, | 3333 | { "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" }, |
3334 | |||
3335 | { "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" }, | ||
3336 | { "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" }, | ||
3337 | { "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" }, | ||
3338 | { "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" }, | ||
3339 | { "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" }, | ||
3340 | { "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" }, | ||
3341 | { "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" }, | ||
3342 | { "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" }, | ||
3343 | |||
3344 | { "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" }, | ||
3345 | { "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" }, | ||
3346 | { "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" }, | ||
3347 | { "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" }, | ||
3348 | { "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" }, | ||
3349 | { "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" }, | ||
3350 | { "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" }, | ||
3351 | { "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" }, | ||
3352 | |||
3353 | { "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" }, | ||
3354 | { "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" }, | ||
3355 | { "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" }, | ||
3356 | { "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" }, | ||
3357 | { "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" }, | ||
3358 | { "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" }, | ||
3359 | { "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" }, | ||
3360 | { "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" }, | ||
3361 | |||
3362 | { "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" }, | ||
3363 | { "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" }, | ||
3364 | { "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" }, | ||
3365 | { "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" }, | ||
3366 | { "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" }, | ||
3367 | { "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" }, | ||
3368 | { "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" }, | ||
3369 | { "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" }, | ||
3370 | |||
3371 | { "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" }, | ||
3372 | { "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" }, | ||
3373 | { "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" }, | ||
3374 | { "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" }, | ||
3375 | { "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" }, | ||
3376 | { "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" }, | ||
3377 | { "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" }, | ||
3378 | { "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" }, | ||
3379 | |||
3380 | { "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" }, | ||
3381 | { "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" }, | ||
3382 | { "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" }, | ||
3383 | { "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" }, | ||
3384 | { "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" }, | ||
3385 | { "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" }, | ||
3386 | { "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" }, | ||
3387 | { "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" }, | ||
3388 | |||
3389 | { "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" }, | ||
3390 | { "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" }, | ||
3391 | { "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" }, | ||
3392 | { "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" }, | ||
3393 | { "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" }, | ||
3394 | { "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" }, | ||
3395 | { "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" }, | ||
3396 | { "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" }, | ||
3397 | |||
3398 | { "IF2 DAC01", NULL, "IF2 DAC0 Mux" }, | ||
3399 | { "IF2 DAC01", NULL, "IF2 DAC1 Mux" }, | ||
3400 | { "IF2 DAC23", NULL, "IF2 DAC2 Mux" }, | ||
3401 | { "IF2 DAC23", NULL, "IF2 DAC3 Mux" }, | ||
3402 | { "IF2 DAC45", NULL, "IF2 DAC4 Mux" }, | ||
3403 | { "IF2 DAC45", NULL, "IF2 DAC5 Mux" }, | ||
3404 | { "IF2 DAC67", NULL, "IF2 DAC6 Mux" }, | ||
3405 | { "IF2 DAC67", NULL, "IF2 DAC7 Mux" }, | ||
2606 | 3406 | ||
2607 | { "IF3 DAC", NULL, "AIF3RX" }, | 3407 | { "IF3 DAC", NULL, "AIF3RX" }, |
2608 | { "IF3 DAC", NULL, "I2S3" }, | 3408 | { "IF3 DAC", NULL, "I2S3" }, |
@@ -2806,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2806 | { "LOUT2 amp", NULL, "DAC 2" }, | 3606 | { "LOUT2 amp", NULL, "DAC 2" }, |
2807 | { "LOUT3 amp", NULL, "DAC 3" }, | 3607 | { "LOUT3 amp", NULL, "DAC 3" }, |
2808 | 3608 | ||
2809 | { "LOUT1", NULL, "LOUT1 amp" }, | 3609 | { "LOUT1 vref", NULL, "LOUT1 amp" }, |
2810 | { "LOUT2", NULL, "LOUT2 amp" }, | 3610 | { "LOUT2 vref", NULL, "LOUT2 amp" }, |
2811 | { "LOUT3", NULL, "LOUT3 amp" }, | 3611 | { "LOUT3 vref", NULL, "LOUT3 amp" }, |
3612 | |||
3613 | { "LOUT1", NULL, "LOUT1 vref" }, | ||
3614 | { "LOUT2", NULL, "LOUT2 vref" }, | ||
3615 | { "LOUT3", NULL, "LOUT3 vref" }, | ||
2812 | 3616 | ||
2813 | { "PDM1L", NULL, "PDM1 L Mux" }, | 3617 | { "PDM1L", NULL, "PDM1 L Mux" }, |
2814 | { "PDM1R", NULL, "PDM1 R Mux" }, | 3618 | { "PDM1R", NULL, "PDM1 R Mux" }, |
@@ -2837,7 +3641,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream, | |||
2837 | rt5677->lrck[dai->id] = params_rate(params); | 3641 | rt5677->lrck[dai->id] = params_rate(params); |
2838 | pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); | 3642 | pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]); |
2839 | if (pre_div < 0) { | 3643 | if (pre_div < 0) { |
2840 | dev_err(codec->dev, "Unsupported clock setting\n"); | 3644 | dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n", |
3645 | rt5677->sysclk, rt5677->lrck[dai->id]); | ||
2841 | return -EINVAL; | 3646 | return -EINVAL; |
2842 | } | 3647 | } |
2843 | frame_size = snd_soc_params_to_frame_size(params); | 3648 | frame_size = snd_soc_params_to_frame_size(params); |
@@ -3181,6 +3986,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3181 | 3986 | ||
3182 | case SND_SOC_BIAS_PREPARE: | 3987 | case SND_SOC_BIAS_PREPARE: |
3183 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | 3988 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { |
3989 | rt5677_set_dsp_vad(codec, false); | ||
3990 | |||
3184 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 3991 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
3185 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, | 3992 | RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK, |
3186 | 0x0055); | 3993 | 0x0055); |
@@ -3188,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3188 | RT5677_PR_BASE + RT5677_BIAS_CUR4, | 3995 | RT5677_PR_BASE + RT5677_BIAS_CUR4, |
3189 | 0x0f00, 0x0f00); | 3996 | 0x0f00, 0x0f00); |
3190 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | 3997 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, |
3998 | RT5677_PWR_FV1 | RT5677_PWR_FV2 | | ||
3191 | RT5677_PWR_VREF1 | RT5677_PWR_MB | | 3999 | RT5677_PWR_VREF1 | RT5677_PWR_MB | |
3192 | RT5677_PWR_BG | RT5677_PWR_VREF2, | 4000 | RT5677_PWR_BG | RT5677_PWR_VREF2, |
3193 | RT5677_PWR_VREF1 | RT5677_PWR_MB | | 4001 | RT5677_PWR_VREF1 | RT5677_PWR_MB | |
3194 | RT5677_PWR_BG | RT5677_PWR_VREF2); | 4002 | RT5677_PWR_BG | RT5677_PWR_VREF2); |
3195 | mdelay(20); | 4003 | rt5677->is_vref_slow = false; |
3196 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1, | ||
3197 | RT5677_PWR_FV1 | RT5677_PWR_FV2, | ||
3198 | RT5677_PWR_FV1 | RT5677_PWR_FV2); | ||
3199 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, | 4004 | regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2, |
3200 | RT5677_PWR_CORE, RT5677_PWR_CORE); | 4005 | RT5677_PWR_CORE, RT5677_PWR_CORE); |
3201 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, | 4006 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, |
@@ -3214,6 +4019,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3214 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); | 4019 | regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000); |
3215 | regmap_update_bits(rt5677->regmap, | 4020 | regmap_update_bits(rt5677->regmap, |
3216 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); | 4021 | RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000); |
4022 | |||
4023 | if (rt5677->dsp_vad_en) | ||
4024 | rt5677_set_dsp_vad(codec, true); | ||
3217 | break; | 4025 | break; |
3218 | 4026 | ||
3219 | default: | 4027 | default: |
@@ -3309,6 +4117,78 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | |||
3309 | return 0; | 4117 | return 0; |
3310 | } | 4118 | } |
3311 | 4119 | ||
4120 | /** Configures the gpio as | ||
4121 | * 0 - floating | ||
4122 | * 1 - pull down | ||
4123 | * 2 - pull up | ||
4124 | */ | ||
4125 | static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, | ||
4126 | int value) | ||
4127 | { | ||
4128 | int shift; | ||
4129 | |||
4130 | switch (offset) { | ||
4131 | case RT5677_GPIO1 ... RT5677_GPIO2: | ||
4132 | shift = 2 * (1 - offset); | ||
4133 | regmap_update_bits(rt5677->regmap, | ||
4134 | RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2, | ||
4135 | 0x3 << shift, | ||
4136 | (value & 0x3) << shift); | ||
4137 | break; | ||
4138 | |||
4139 | case RT5677_GPIO3 ... RT5677_GPIO6: | ||
4140 | shift = 2 * (9 - offset); | ||
4141 | regmap_update_bits(rt5677->regmap, | ||
4142 | RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3, | ||
4143 | 0x3 << shift, | ||
4144 | (value & 0x3) << shift); | ||
4145 | break; | ||
4146 | |||
4147 | default: | ||
4148 | break; | ||
4149 | } | ||
4150 | } | ||
4151 | |||
4152 | static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset) | ||
4153 | { | ||
4154 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
4155 | struct regmap_irq_chip_data *data = rt5677->irq_data; | ||
4156 | int irq; | ||
4157 | |||
4158 | if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) { | ||
4159 | if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) || | ||
4160 | (rt5677->pdata.jd1_gpio == 2 && | ||
4161 | offset == RT5677_GPIO2) || | ||
4162 | (rt5677->pdata.jd1_gpio == 3 && | ||
4163 | offset == RT5677_GPIO3)) { | ||
4164 | irq = RT5677_IRQ_JD1; | ||
4165 | } else { | ||
4166 | return -ENXIO; | ||
4167 | } | ||
4168 | } | ||
4169 | |||
4170 | if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) { | ||
4171 | if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) || | ||
4172 | (rt5677->pdata.jd2_gpio == 2 && | ||
4173 | offset == RT5677_GPIO5) || | ||
4174 | (rt5677->pdata.jd2_gpio == 3 && | ||
4175 | offset == RT5677_GPIO6)) { | ||
4176 | irq = RT5677_IRQ_JD2; | ||
4177 | } else if ((rt5677->pdata.jd3_gpio == 1 && | ||
4178 | offset == RT5677_GPIO4) || | ||
4179 | (rt5677->pdata.jd3_gpio == 2 && | ||
4180 | offset == RT5677_GPIO5) || | ||
4181 | (rt5677->pdata.jd3_gpio == 3 && | ||
4182 | offset == RT5677_GPIO6)) { | ||
4183 | irq = RT5677_IRQ_JD3; | ||
4184 | } else { | ||
4185 | return -ENXIO; | ||
4186 | } | ||
4187 | } | ||
4188 | |||
4189 | return regmap_irq_get_virq(data, irq); | ||
4190 | } | ||
4191 | |||
3312 | static struct gpio_chip rt5677_template_chip = { | 4192 | static struct gpio_chip rt5677_template_chip = { |
3313 | .label = "rt5677", | 4193 | .label = "rt5677", |
3314 | .owner = THIS_MODULE, | 4194 | .owner = THIS_MODULE, |
@@ -3316,6 +4196,7 @@ static struct gpio_chip rt5677_template_chip = { | |||
3316 | .set = rt5677_gpio_set, | 4196 | .set = rt5677_gpio_set, |
3317 | .direction_input = rt5677_gpio_direction_in, | 4197 | .direction_input = rt5677_gpio_direction_in, |
3318 | .get = rt5677_gpio_get, | 4198 | .get = rt5677_gpio_get, |
4199 | .to_irq = rt5677_to_irq, | ||
3319 | .can_sleep = 1, | 4200 | .can_sleep = 1, |
3320 | }; | 4201 | }; |
3321 | 4202 | ||
@@ -3341,6 +4222,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c) | |||
3341 | gpiochip_remove(&rt5677->gpio_chip); | 4222 | gpiochip_remove(&rt5677->gpio_chip); |
3342 | } | 4223 | } |
3343 | #else | 4224 | #else |
4225 | static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset, | ||
4226 | int value) | ||
4227 | { | ||
4228 | } | ||
4229 | |||
3344 | static void rt5677_init_gpio(struct i2c_client *i2c) | 4230 | static void rt5677_init_gpio(struct i2c_client *i2c) |
3345 | { | 4231 | { |
3346 | } | 4232 | } |
@@ -3353,6 +4239,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c) | |||
3353 | static int rt5677_probe(struct snd_soc_codec *codec) | 4239 | static int rt5677_probe(struct snd_soc_codec *codec) |
3354 | { | 4240 | { |
3355 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4241 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
4242 | int i; | ||
3356 | 4243 | ||
3357 | rt5677->codec = codec; | 4244 | rt5677->codec = codec; |
3358 | 4245 | ||
@@ -3371,6 +4258,37 @@ static int rt5677_probe(struct snd_soc_codec *codec) | |||
3371 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); | 4258 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); |
3372 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); | 4259 | regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00); |
3373 | 4260 | ||
4261 | for (i = 0; i < RT5677_GPIO_NUM; i++) | ||
4262 | rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]); | ||
4263 | |||
4264 | if (rt5677->irq_data) { | ||
4265 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000, | ||
4266 | 0x8000); | ||
4267 | regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018, | ||
4268 | 0x0008); | ||
4269 | |||
4270 | if (rt5677->pdata.jd1_gpio) | ||
4271 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4272 | RT5677_SEL_GPIO_JD1_MASK, | ||
4273 | rt5677->pdata.jd1_gpio << | ||
4274 | RT5677_SEL_GPIO_JD1_SFT); | ||
4275 | |||
4276 | if (rt5677->pdata.jd2_gpio) | ||
4277 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4278 | RT5677_SEL_GPIO_JD2_MASK, | ||
4279 | rt5677->pdata.jd2_gpio << | ||
4280 | RT5677_SEL_GPIO_JD2_SFT); | ||
4281 | |||
4282 | if (rt5677->pdata.jd3_gpio) | ||
4283 | regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1, | ||
4284 | RT5677_SEL_GPIO_JD3_MASK, | ||
4285 | rt5677->pdata.jd3_gpio << | ||
4286 | RT5677_SEL_GPIO_JD3_SFT); | ||
4287 | } | ||
4288 | |||
4289 | mutex_init(&rt5677->dsp_cmd_lock); | ||
4290 | mutex_init(&rt5677->dsp_pri_lock); | ||
4291 | |||
3374 | return 0; | 4292 | return 0; |
3375 | } | 4293 | } |
3376 | 4294 | ||
@@ -3390,8 +4308,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec) | |||
3390 | { | 4308 | { |
3391 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 4309 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3392 | 4310 | ||
3393 | regcache_cache_only(rt5677->regmap, true); | 4311 | if (!rt5677->dsp_vad_en) { |
3394 | regcache_mark_dirty(rt5677->regmap); | 4312 | regcache_cache_only(rt5677->regmap, true); |
4313 | regcache_mark_dirty(rt5677->regmap); | ||
4314 | } | ||
4315 | |||
3395 | if (gpio_is_valid(rt5677->pow_ldo2)) | 4316 | if (gpio_is_valid(rt5677->pow_ldo2)) |
3396 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | 4317 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); |
3397 | 4318 | ||
@@ -3406,8 +4327,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3406 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); | 4327 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); |
3407 | msleep(10); | 4328 | msleep(10); |
3408 | } | 4329 | } |
3409 | regcache_cache_only(rt5677->regmap, false); | 4330 | |
3410 | regcache_sync(rt5677->regmap); | 4331 | if (!rt5677->dsp_vad_en) { |
4332 | regcache_cache_only(rt5677->regmap, false); | ||
4333 | regcache_sync(rt5677->regmap); | ||
4334 | } | ||
3411 | 4335 | ||
3412 | return 0; | 4336 | return 0; |
3413 | } | 4337 | } |
@@ -3416,6 +4340,51 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3416 | #define rt5677_resume NULL | 4340 | #define rt5677_resume NULL |
3417 | #endif | 4341 | #endif |
3418 | 4342 | ||
4343 | static int rt5677_read(void *context, unsigned int reg, unsigned int *val) | ||
4344 | { | ||
4345 | struct i2c_client *client = context; | ||
4346 | struct rt5677_priv *rt5677 = i2c_get_clientdata(client); | ||
4347 | |||
4348 | if (rt5677->is_dsp_mode) { | ||
4349 | if (reg > 0xff) { | ||
4350 | mutex_lock(&rt5677->dsp_pri_lock); | ||
4351 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, | ||
4352 | reg & 0xff); | ||
4353 | rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val); | ||
4354 | mutex_unlock(&rt5677->dsp_pri_lock); | ||
4355 | } else { | ||
4356 | rt5677_dsp_mode_i2c_read(rt5677, reg, val); | ||
4357 | } | ||
4358 | } else { | ||
4359 | regmap_read(rt5677->regmap_physical, reg, val); | ||
4360 | } | ||
4361 | |||
4362 | return 0; | ||
4363 | } | ||
4364 | |||
4365 | static int rt5677_write(void *context, unsigned int reg, unsigned int val) | ||
4366 | { | ||
4367 | struct i2c_client *client = context; | ||
4368 | struct rt5677_priv *rt5677 = i2c_get_clientdata(client); | ||
4369 | |||
4370 | if (rt5677->is_dsp_mode) { | ||
4371 | if (reg > 0xff) { | ||
4372 | mutex_lock(&rt5677->dsp_pri_lock); | ||
4373 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX, | ||
4374 | reg & 0xff); | ||
4375 | rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA, | ||
4376 | val); | ||
4377 | mutex_unlock(&rt5677->dsp_pri_lock); | ||
4378 | } else { | ||
4379 | rt5677_dsp_mode_i2c_write(rt5677, reg, val); | ||
4380 | } | ||
4381 | } else { | ||
4382 | regmap_write(rt5677->regmap_physical, reg, val); | ||
4383 | } | ||
4384 | |||
4385 | return 0; | ||
4386 | } | ||
4387 | |||
3419 | #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 | 4388 | #define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000 |
3420 | #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | 4389 | #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ |
3421 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) | 4390 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) |
@@ -3541,6 +4510,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = { | |||
3541 | .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), | 4510 | .num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes), |
3542 | }; | 4511 | }; |
3543 | 4512 | ||
4513 | static const struct regmap_config rt5677_regmap_physical = { | ||
4514 | .name = "physical", | ||
4515 | .reg_bits = 8, | ||
4516 | .val_bits = 16, | ||
4517 | |||
4518 | .max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) * | ||
4519 | RT5677_PR_SPACING), | ||
4520 | .readable_reg = rt5677_readable_register, | ||
4521 | |||
4522 | .cache_type = REGCACHE_NONE, | ||
4523 | .ranges = rt5677_ranges, | ||
4524 | .num_ranges = ARRAY_SIZE(rt5677_ranges), | ||
4525 | }; | ||
4526 | |||
3544 | static const struct regmap_config rt5677_regmap = { | 4527 | static const struct regmap_config rt5677_regmap = { |
3545 | .reg_bits = 8, | 4528 | .reg_bits = 8, |
3546 | .val_bits = 16, | 4529 | .val_bits = 16, |
@@ -3550,6 +4533,8 @@ static const struct regmap_config rt5677_regmap = { | |||
3550 | 4533 | ||
3551 | .volatile_reg = rt5677_volatile_register, | 4534 | .volatile_reg = rt5677_volatile_register, |
3552 | .readable_reg = rt5677_readable_register, | 4535 | .readable_reg = rt5677_readable_register, |
4536 | .reg_read = rt5677_read, | ||
4537 | .reg_write = rt5677_write, | ||
3553 | 4538 | ||
3554 | .cache_type = REGCACHE_RBTREE, | 4539 | .cache_type = REGCACHE_RBTREE, |
3555 | .reg_defaults = rt5677_reg, | 4540 | .reg_defaults = rt5677_reg, |
@@ -3590,9 +4575,77 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) | |||
3590 | (rt5677->pow_ldo2 != -ENOENT)) | 4575 | (rt5677->pow_ldo2 != -ENOENT)) |
3591 | return rt5677->pow_ldo2; | 4576 | return rt5677->pow_ldo2; |
3592 | 4577 | ||
4578 | of_property_read_u8_array(np, "realtek,gpio-config", | ||
4579 | rt5677->pdata.gpio_config, RT5677_GPIO_NUM); | ||
4580 | |||
4581 | of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); | ||
4582 | of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); | ||
4583 | of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); | ||
4584 | |||
4585 | return 0; | ||
4586 | } | ||
4587 | |||
4588 | static struct regmap_irq rt5677_irqs[] = { | ||
4589 | [RT5677_IRQ_JD1] = { | ||
4590 | .reg_offset = 0, | ||
4591 | .mask = RT5677_EN_IRQ_GPIO_JD1, | ||
4592 | }, | ||
4593 | [RT5677_IRQ_JD2] = { | ||
4594 | .reg_offset = 0, | ||
4595 | .mask = RT5677_EN_IRQ_GPIO_JD2, | ||
4596 | }, | ||
4597 | [RT5677_IRQ_JD3] = { | ||
4598 | .reg_offset = 0, | ||
4599 | .mask = RT5677_EN_IRQ_GPIO_JD3, | ||
4600 | }, | ||
4601 | }; | ||
4602 | |||
4603 | static struct regmap_irq_chip rt5677_irq_chip = { | ||
4604 | .name = "rt5677", | ||
4605 | .irqs = rt5677_irqs, | ||
4606 | .num_irqs = ARRAY_SIZE(rt5677_irqs), | ||
4607 | |||
4608 | .num_regs = 1, | ||
4609 | .status_base = RT5677_IRQ_CTRL1, | ||
4610 | .mask_base = RT5677_IRQ_CTRL1, | ||
4611 | .mask_invert = 1, | ||
4612 | }; | ||
4613 | |||
4614 | static int rt5677_init_irq(struct i2c_client *i2c) | ||
4615 | { | ||
4616 | int ret; | ||
4617 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
4618 | |||
4619 | if (!rt5677->pdata.jd1_gpio && | ||
4620 | !rt5677->pdata.jd2_gpio && | ||
4621 | !rt5677->pdata.jd3_gpio) | ||
4622 | return 0; | ||
4623 | |||
4624 | if (!i2c->irq) { | ||
4625 | dev_err(&i2c->dev, "No interrupt specified\n"); | ||
4626 | return -EINVAL; | ||
4627 | } | ||
4628 | |||
4629 | ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq, | ||
4630 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0, | ||
4631 | &rt5677_irq_chip, &rt5677->irq_data); | ||
4632 | |||
4633 | if (ret != 0) { | ||
4634 | dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret); | ||
4635 | return ret; | ||
4636 | } | ||
4637 | |||
3593 | return 0; | 4638 | return 0; |
3594 | } | 4639 | } |
3595 | 4640 | ||
4641 | static void rt5677_free_irq(struct i2c_client *i2c) | ||
4642 | { | ||
4643 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
4644 | |||
4645 | if (rt5677->irq_data) | ||
4646 | regmap_del_irq_chip(i2c->irq, rt5677->irq_data); | ||
4647 | } | ||
4648 | |||
3596 | static int rt5677_i2c_probe(struct i2c_client *i2c, | 4649 | static int rt5677_i2c_probe(struct i2c_client *i2c, |
3597 | const struct i2c_device_id *id) | 4650 | const struct i2c_device_id *id) |
3598 | { | 4651 | { |
@@ -3638,7 +4691,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3638 | msleep(10); | 4691 | msleep(10); |
3639 | } | 4692 | } |
3640 | 4693 | ||
3641 | rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); | 4694 | rt5677->regmap_physical = devm_regmap_init_i2c(i2c, |
4695 | &rt5677_regmap_physical); | ||
4696 | if (IS_ERR(rt5677->regmap_physical)) { | ||
4697 | ret = PTR_ERR(rt5677->regmap_physical); | ||
4698 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
4699 | ret); | ||
4700 | return ret; | ||
4701 | } | ||
4702 | |||
4703 | rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap); | ||
3642 | if (IS_ERR(rt5677->regmap)) { | 4704 | if (IS_ERR(rt5677->regmap)) { |
3643 | ret = PTR_ERR(rt5677->regmap); | 4705 | ret = PTR_ERR(rt5677->regmap); |
3644 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 4706 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
@@ -3690,6 +4752,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3690 | } | 4752 | } |
3691 | 4753 | ||
3692 | rt5677_init_gpio(i2c); | 4754 | rt5677_init_gpio(i2c); |
4755 | rt5677_init_irq(i2c); | ||
3693 | 4756 | ||
3694 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, | 4757 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, |
3695 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); | 4758 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); |
@@ -3698,6 +4761,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3698 | static int rt5677_i2c_remove(struct i2c_client *i2c) | 4761 | static int rt5677_i2c_remove(struct i2c_client *i2c) |
3699 | { | 4762 | { |
3700 | snd_soc_unregister_codec(&i2c->dev); | 4763 | snd_soc_unregister_codec(&i2c->dev); |
4764 | rt5677_free_irq(i2c); | ||
3701 | rt5677_free_gpio(i2c); | 4765 | rt5677_free_gpio(i2c); |
3702 | 4766 | ||
3703 | return 0; | 4767 | return 0; |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index d4eb6d5e6746..c0a625f290cc 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #define __RT5677_H__ | 13 | #define __RT5677_H__ |
14 | 14 | ||
15 | #include <sound/rt5677.h> | 15 | #include <sound/rt5677.h> |
16 | #include <linux/gpio/driver.h> | ||
16 | 17 | ||
17 | /* Info */ | 18 | /* Info */ |
18 | #define RT5677_RESET 0x00 | 19 | #define RT5677_RESET 0x00 |
@@ -305,10 +306,10 @@ | |||
305 | #define RT5677_R_MUTE_SFT 7 | 306 | #define RT5677_R_MUTE_SFT 7 |
306 | #define RT5677_VOL_R_MUTE (0x1 << 6) | 307 | #define RT5677_VOL_R_MUTE (0x1 << 6) |
307 | #define RT5677_VOL_R_SFT 6 | 308 | #define RT5677_VOL_R_SFT 6 |
308 | #define RT5677_L_VOL_MASK (0x3f << 8) | 309 | #define RT5677_L_VOL_MASK (0x7f << 9) |
309 | #define RT5677_L_VOL_SFT 8 | 310 | #define RT5677_L_VOL_SFT 9 |
310 | #define RT5677_R_VOL_MASK (0x3f) | 311 | #define RT5677_R_VOL_MASK (0x7f << 1) |
311 | #define RT5677_R_VOL_SFT 0 | 312 | #define RT5677_R_VOL_SFT 1 |
312 | 313 | ||
313 | /* LOUT1 Control (0x01) */ | 314 | /* LOUT1 Control (0x01) */ |
314 | #define RT5677_LOUT1_L_MUTE (0x1 << 15) | 315 | #define RT5677_LOUT1_L_MUTE (0x1 << 15) |
@@ -446,16 +447,16 @@ | |||
446 | #define RT5677_SEL_DAC2_R_SRC_SFT 0 | 447 | #define RT5677_SEL_DAC2_R_SRC_SFT 0 |
447 | 448 | ||
448 | /* Stereo1 ADC Digital Volume Control (0x1c) */ | 449 | /* Stereo1 ADC Digital Volume Control (0x1c) */ |
449 | #define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8) | 450 | #define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9) |
450 | #define RT5677_STO1_ADC_L_VOL_SFT 8 | 451 | #define RT5677_STO1_ADC_L_VOL_SFT 9 |
451 | #define RT5677_STO1_ADC_R_VOL_MASK (0x7f) | 452 | #define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1) |
452 | #define RT5677_STO1_ADC_R_VOL_SFT 0 | 453 | #define RT5677_STO1_ADC_R_VOL_SFT 1 |
453 | 454 | ||
454 | /* Mono ADC Digital Volume Control (0x1d) */ | 455 | /* Mono ADC Digital Volume Control (0x1d) */ |
455 | #define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8) | 456 | #define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9) |
456 | #define RT5677_MONO_ADC_L_VOL_SFT 8 | 457 | #define RT5677_MONO_ADC_L_VOL_SFT 9 |
457 | #define RT5677_MONO_ADC_R_VOL_MASK (0x7f) | 458 | #define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1) |
458 | #define RT5677_MONO_ADC_R_VOL_SFT 0 | 459 | #define RT5677_MONO_ADC_R_VOL_SFT 1 |
459 | 460 | ||
460 | /* Stereo 1/2 ADC Boost Gain Control (0x1e) */ | 461 | /* Stereo 1/2 ADC Boost Gain Control (0x1e) */ |
461 | #define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14) | 462 | #define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14) |
@@ -798,7 +799,21 @@ | |||
798 | #define RT5677_PDM2_I2C_EXE (0x1 << 1) | 799 | #define RT5677_PDM2_I2C_EXE (0x1 << 1) |
799 | #define RT5677_PDM2_I2C_BUSY (0x1 << 0) | 800 | #define RT5677_PDM2_I2C_BUSY (0x1 << 0) |
800 | 801 | ||
801 | /* MX3C TDM1 control 1 (0x3c) */ | 802 | /* TDM1 control 1 (0x3b) */ |
803 | #define RT5677_IF1_ADC_MODE_MASK (0x1 << 12) | ||
804 | #define RT5677_IF1_ADC_MODE_SFT 12 | ||
805 | #define RT5677_IF1_ADC_MODE_I2S (0x0 << 12) | ||
806 | #define RT5677_IF1_ADC_MODE_TDM (0x1 << 12) | ||
807 | #define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6) | ||
808 | #define RT5677_IF1_ADC1_SWAP_SFT 6 | ||
809 | #define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4) | ||
810 | #define RT5677_IF1_ADC2_SWAP_SFT 4 | ||
811 | #define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2) | ||
812 | #define RT5677_IF1_ADC3_SWAP_SFT 2 | ||
813 | #define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0) | ||
814 | #define RT5677_IF1_ADC4_SWAP_SFT 0 | ||
815 | |||
816 | /* TDM1 control 2 (0x3c) */ | ||
802 | #define RT5677_IF1_ADC4_MASK (0x3 << 10) | 817 | #define RT5677_IF1_ADC4_MASK (0x3 << 10) |
803 | #define RT5677_IF1_ADC4_SFT 10 | 818 | #define RT5677_IF1_ADC4_SFT 10 |
804 | #define RT5677_IF1_ADC3_MASK (0x3 << 8) | 819 | #define RT5677_IF1_ADC3_MASK (0x3 << 8) |
@@ -807,8 +822,44 @@ | |||
807 | #define RT5677_IF1_ADC2_SFT 6 | 822 | #define RT5677_IF1_ADC2_SFT 6 |
808 | #define RT5677_IF1_ADC1_MASK (0x3 << 4) | 823 | #define RT5677_IF1_ADC1_MASK (0x3 << 4) |
809 | #define RT5677_IF1_ADC1_SFT 4 | 824 | #define RT5677_IF1_ADC1_SFT 4 |
810 | 825 | #define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0) | |
811 | /* MX41 TDM2 control 1 (0x41) */ | 826 | #define RT5677_IF1_ADC_CTRL_SFT 0 |
827 | |||
828 | /* TDM1 control 4 (0x3e) */ | ||
829 | #define RT5677_IF1_DAC0_MASK (0x7 << 12) | ||
830 | #define RT5677_IF1_DAC0_SFT 12 | ||
831 | #define RT5677_IF1_DAC1_MASK (0x7 << 8) | ||
832 | #define RT5677_IF1_DAC1_SFT 8 | ||
833 | #define RT5677_IF1_DAC2_MASK (0x7 << 4) | ||
834 | #define RT5677_IF1_DAC2_SFT 4 | ||
835 | #define RT5677_IF1_DAC3_MASK (0x7 << 0) | ||
836 | #define RT5677_IF1_DAC3_SFT 0 | ||
837 | |||
838 | /* TDM1 control 5 (0x3f) */ | ||
839 | #define RT5677_IF1_DAC4_MASK (0x7 << 12) | ||
840 | #define RT5677_IF1_DAC4_SFT 12 | ||
841 | #define RT5677_IF1_DAC5_MASK (0x7 << 8) | ||
842 | #define RT5677_IF1_DAC5_SFT 8 | ||
843 | #define RT5677_IF1_DAC6_MASK (0x7 << 4) | ||
844 | #define RT5677_IF1_DAC6_SFT 4 | ||
845 | #define RT5677_IF1_DAC7_MASK (0x7 << 0) | ||
846 | #define RT5677_IF1_DAC7_SFT 0 | ||
847 | |||
848 | /* TDM2 control 1 (0x40) */ | ||
849 | #define RT5677_IF2_ADC_MODE_MASK (0x1 << 12) | ||
850 | #define RT5677_IF2_ADC_MODE_SFT 12 | ||
851 | #define RT5677_IF2_ADC_MODE_I2S (0x0 << 12) | ||
852 | #define RT5677_IF2_ADC_MODE_TDM (0x1 << 12) | ||
853 | #define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6) | ||
854 | #define RT5677_IF2_ADC1_SWAP_SFT 6 | ||
855 | #define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4) | ||
856 | #define RT5677_IF2_ADC2_SWAP_SFT 4 | ||
857 | #define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2) | ||
858 | #define RT5677_IF2_ADC3_SWAP_SFT 2 | ||
859 | #define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0) | ||
860 | #define RT5677_IF2_ADC4_SWAP_SFT 0 | ||
861 | |||
862 | /* TDM2 control 2 (0x41) */ | ||
812 | #define RT5677_IF2_ADC4_MASK (0x3 << 10) | 863 | #define RT5677_IF2_ADC4_MASK (0x3 << 10) |
813 | #define RT5677_IF2_ADC4_SFT 10 | 864 | #define RT5677_IF2_ADC4_SFT 10 |
814 | #define RT5677_IF2_ADC3_MASK (0x3 << 8) | 865 | #define RT5677_IF2_ADC3_MASK (0x3 << 8) |
@@ -817,6 +868,28 @@ | |||
817 | #define RT5677_IF2_ADC2_SFT 6 | 868 | #define RT5677_IF2_ADC2_SFT 6 |
818 | #define RT5677_IF2_ADC1_MASK (0x3 << 4) | 869 | #define RT5677_IF2_ADC1_MASK (0x3 << 4) |
819 | #define RT5677_IF2_ADC1_SFT 4 | 870 | #define RT5677_IF2_ADC1_SFT 4 |
871 | #define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0) | ||
872 | #define RT5677_IF2_ADC_CTRL_SFT 0 | ||
873 | |||
874 | /* TDM2 control 4 (0x43) */ | ||
875 | #define RT5677_IF2_DAC0_MASK (0x7 << 12) | ||
876 | #define RT5677_IF2_DAC0_SFT 12 | ||
877 | #define RT5677_IF2_DAC1_MASK (0x7 << 8) | ||
878 | #define RT5677_IF2_DAC1_SFT 8 | ||
879 | #define RT5677_IF2_DAC2_MASK (0x7 << 4) | ||
880 | #define RT5677_IF2_DAC2_SFT 4 | ||
881 | #define RT5677_IF2_DAC3_MASK (0x7 << 0) | ||
882 | #define RT5677_IF2_DAC3_SFT 0 | ||
883 | |||
884 | /* TDM2 control 5 (0x44) */ | ||
885 | #define RT5677_IF2_DAC4_MASK (0x7 << 12) | ||
886 | #define RT5677_IF2_DAC4_SFT 12 | ||
887 | #define RT5677_IF2_DAC5_MASK (0x7 << 8) | ||
888 | #define RT5677_IF2_DAC5_SFT 8 | ||
889 | #define RT5677_IF2_DAC6_MASK (0x7 << 4) | ||
890 | #define RT5677_IF2_DAC6_SFT 4 | ||
891 | #define RT5677_IF2_DAC7_MASK (0x7 << 0) | ||
892 | #define RT5677_IF2_DAC7_SFT 0 | ||
820 | 893 | ||
821 | /* Digital Microphone Control 1 (0x50) */ | 894 | /* Digital Microphone Control 1 (0x50) */ |
822 | #define RT5677_DMIC_1_EN_MASK (0x1 << 15) | 895 | #define RT5677_DMIC_1_EN_MASK (0x1 << 15) |
@@ -1367,6 +1440,48 @@ | |||
1367 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) | 1440 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) |
1368 | #define RT5677_SEL_SRC_IB01_SFT 0 | 1441 | #define RT5677_SEL_SRC_IB01_SFT 0 |
1369 | 1442 | ||
1443 | /* Jack Detect Control 1 (0xb5) */ | ||
1444 | #define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14) | ||
1445 | #define RT5677_SEL_GPIO_JD1_SFT 14 | ||
1446 | #define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12) | ||
1447 | #define RT5677_SEL_GPIO_JD2_SFT 12 | ||
1448 | #define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10) | ||
1449 | #define RT5677_SEL_GPIO_JD3_SFT 10 | ||
1450 | |||
1451 | /* IRQ Control 1 (0xbd) */ | ||
1452 | #define RT5677_STA_GPIO_JD1 (0x1 << 15) | ||
1453 | #define RT5677_STA_GPIO_JD1_SFT 15 | ||
1454 | #define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14) | ||
1455 | #define RT5677_EN_IRQ_GPIO_JD1_SFT 14 | ||
1456 | #define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13) | ||
1457 | #define RT5677_EN_GPIO_JD1_STICKY_SFT 13 | ||
1458 | #define RT5677_INV_GPIO_JD1 (0x1 << 12) | ||
1459 | #define RT5677_INV_GPIO_JD1_SFT 12 | ||
1460 | #define RT5677_STA_GPIO_JD2 (0x1 << 11) | ||
1461 | #define RT5677_STA_GPIO_JD2_SFT 11 | ||
1462 | #define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10) | ||
1463 | #define RT5677_EN_IRQ_GPIO_JD2_SFT 10 | ||
1464 | #define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9) | ||
1465 | #define RT5677_EN_GPIO_JD2_STICKY_SFT 9 | ||
1466 | #define RT5677_INV_GPIO_JD2 (0x1 << 8) | ||
1467 | #define RT5677_INV_GPIO_JD2_SFT 8 | ||
1468 | #define RT5677_STA_MICBIAS1_OVCD (0x1 << 7) | ||
1469 | #define RT5677_STA_MICBIAS1_OVCD_SFT 7 | ||
1470 | #define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6) | ||
1471 | #define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6 | ||
1472 | #define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5) | ||
1473 | #define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5 | ||
1474 | #define RT5677_INV_MICBIAS1_OVCD (0x1 << 4) | ||
1475 | #define RT5677_INV_MICBIAS1_OVCD_SFT 4 | ||
1476 | #define RT5677_STA_GPIO_JD3 (0x1 << 3) | ||
1477 | #define RT5677_STA_GPIO_JD3_SFT 3 | ||
1478 | #define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2) | ||
1479 | #define RT5677_EN_IRQ_GPIO_JD3_SFT 2 | ||
1480 | #define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1) | ||
1481 | #define RT5677_EN_GPIO_JD3_STICKY_SFT 1 | ||
1482 | #define RT5677_INV_GPIO_JD3 (0x1 << 0) | ||
1483 | #define RT5677_INV_GPIO_JD3_SFT 0 | ||
1484 | |||
1370 | /* GPIO status (0xbf) */ | 1485 | /* GPIO status (0xbf) */ |
1371 | #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) | 1486 | #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) |
1372 | #define RT5677_GPIO6_STATUS_SFT 5 | 1487 | #define RT5677_GPIO6_STATUS_SFT 5 |
@@ -1506,6 +1621,9 @@ | |||
1506 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) | 1621 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) |
1507 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) | 1622 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) |
1508 | 1623 | ||
1624 | #define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin" | ||
1625 | #define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin" | ||
1626 | |||
1509 | /* System Clock Source */ | 1627 | /* System Clock Source */ |
1510 | enum { | 1628 | enum { |
1511 | RT5677_SCLK_S_MCLK, | 1629 | RT5677_SCLK_S_MCLK, |
@@ -1541,10 +1659,18 @@ enum { | |||
1541 | RT5677_GPIO_NUM, | 1659 | RT5677_GPIO_NUM, |
1542 | }; | 1660 | }; |
1543 | 1661 | ||
1662 | enum { | ||
1663 | RT5677_IRQ_JD1, | ||
1664 | RT5677_IRQ_JD2, | ||
1665 | RT5677_IRQ_JD3, | ||
1666 | }; | ||
1667 | |||
1544 | struct rt5677_priv { | 1668 | struct rt5677_priv { |
1545 | struct snd_soc_codec *codec; | 1669 | struct snd_soc_codec *codec; |
1546 | struct rt5677_platform_data pdata; | 1670 | struct rt5677_platform_data pdata; |
1547 | struct regmap *regmap; | 1671 | struct regmap *regmap, *regmap_physical; |
1672 | const struct firmware *fw1, *fw2; | ||
1673 | struct mutex dsp_cmd_lock, dsp_pri_lock; | ||
1548 | 1674 | ||
1549 | int sysclk; | 1675 | int sysclk; |
1550 | int sysclk_src; | 1676 | int sysclk_src; |
@@ -1558,6 +1684,10 @@ struct rt5677_priv { | |||
1558 | #ifdef CONFIG_GPIOLIB | 1684 | #ifdef CONFIG_GPIOLIB |
1559 | struct gpio_chip gpio_chip; | 1685 | struct gpio_chip gpio_chip; |
1560 | #endif | 1686 | #endif |
1687 | bool dsp_vad_en; | ||
1688 | struct regmap_irq_chip_data *irq_data; | ||
1689 | bool is_dsp_mode; | ||
1690 | bool is_vref_slow; | ||
1561 | }; | 1691 | }; |
1562 | 1692 | ||
1563 | #endif /* __RT5677_H__ */ | 1693 | #endif /* __RT5677_H__ */ |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index dab9b15304af..29cf7ce610f4 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/pm.h> | 16 | #include <linux/pm.h> |
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/log2.h> | ||
19 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
20 | #include <linux/regulator/driver.h> | 21 | #include <linux/regulator/driver.h> |
21 | #include <linux/regulator/machine.h> | 22 | #include <linux/regulator/machine.h> |
@@ -121,6 +122,13 @@ struct ldo_regulator { | |||
121 | bool enabled; | 122 | bool enabled; |
122 | }; | 123 | }; |
123 | 124 | ||
125 | enum sgtl5000_micbias_resistor { | ||
126 | SGTL5000_MICBIAS_OFF = 0, | ||
127 | SGTL5000_MICBIAS_2K = 2, | ||
128 | SGTL5000_MICBIAS_4K = 4, | ||
129 | SGTL5000_MICBIAS_8K = 8, | ||
130 | }; | ||
131 | |||
124 | /* sgtl5000 private structure in codec */ | 132 | /* sgtl5000 private structure in codec */ |
125 | struct sgtl5000_priv { | 133 | struct sgtl5000_priv { |
126 | int sysclk; /* sysclk rate */ | 134 | int sysclk; /* sysclk rate */ |
@@ -131,6 +139,8 @@ struct sgtl5000_priv { | |||
131 | struct regmap *regmap; | 139 | struct regmap *regmap; |
132 | struct clk *mclk; | 140 | struct clk *mclk; |
133 | int revision; | 141 | int revision; |
142 | u8 micbias_resistor; | ||
143 | u8 micbias_voltage; | ||
134 | }; | 144 | }; |
135 | 145 | ||
136 | /* | 146 | /* |
@@ -145,12 +155,14 @@ struct sgtl5000_priv { | |||
145 | static int mic_bias_event(struct snd_soc_dapm_widget *w, | 155 | static int mic_bias_event(struct snd_soc_dapm_widget *w, |
146 | struct snd_kcontrol *kcontrol, int event) | 156 | struct snd_kcontrol *kcontrol, int event) |
147 | { | 157 | { |
158 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec); | ||
159 | |||
148 | switch (event) { | 160 | switch (event) { |
149 | case SND_SOC_DAPM_POST_PMU: | 161 | case SND_SOC_DAPM_POST_PMU: |
150 | /* change mic bias resistor to 4Kohm */ | 162 | /* change mic bias resistor */ |
151 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, | 163 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, |
152 | SGTL5000_BIAS_R_MASK, | 164 | SGTL5000_BIAS_R_MASK, |
153 | SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT); | 165 | sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); |
154 | break; | 166 | break; |
155 | 167 | ||
156 | case SND_SOC_DAPM_PRE_PMD: | 168 | case SND_SOC_DAPM_PRE_PMD: |
@@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
530 | 542 | ||
531 | /* | 543 | /* |
532 | * set clock according to i2s frame clock, | 544 | * set clock according to i2s frame clock, |
533 | * sgtl5000 provide 2 clock sources. | 545 | * sgtl5000 provides 2 clock sources: |
534 | * 1. sys_mclk. sample freq can only configure to | 546 | * 1. sys_mclk: sample freq can only be configured to |
535 | * 1/256, 1/384, 1/512 of sys_mclk. | 547 | * 1/256, 1/384, 1/512 of sys_mclk. |
536 | * 2. pll. can derive any audio clocks. | 548 | * 2. pll: can derive any audio clocks. |
537 | * | 549 | * |
538 | * clock setting rules: | 550 | * clock setting rules: |
539 | * 1. in slave mode, only sys_mclk can use. | 551 | * 1. in slave mode, only sys_mclk can be used |
540 | * 2. as constraint by sys_mclk, sample freq should | 552 | * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz |
541 | * set to 32k, 44.1k and above. | 553 | * and above. |
542 | * 3. using sys_mclk prefer to pll to save power. | 554 | * 3. usage of sys_mclk is preferred over pll to save power. |
543 | */ | 555 | */ |
544 | static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | 556 | static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) |
545 | { | 557 | { |
@@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
549 | 561 | ||
550 | /* | 562 | /* |
551 | * sample freq should be divided by frame clock, | 563 | * sample freq should be divided by frame clock, |
552 | * if frame clock lower than 44.1khz, sample feq should set to | 564 | * if frame clock is lower than 44.1 kHz, sample freq should be set to |
553 | * 32khz or 44.1khz. | 565 | * 32 kHz or 44.1 kHz. |
554 | */ | 566 | */ |
555 | switch (frame_rate) { | 567 | switch (frame_rate) { |
556 | case 8000: | 568 | case 8000: |
@@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
603 | 615 | ||
604 | /* | 616 | /* |
605 | * calculate the divider of mclk/sample_freq, | 617 | * calculate the divider of mclk/sample_freq, |
606 | * factor of freq =96k can only be 256, since mclk in range (12m,27m) | 618 | * factor of freq = 96 kHz can only be 256, since mclk is in the range |
619 | * of 8 MHz - 27 MHz | ||
607 | */ | 620 | */ |
608 | switch (sgtl5000->sysclk / sys_fs) { | 621 | switch (sgtl5000->sysclk / frame_rate) { |
609 | case 256: | 622 | case 256: |
610 | clk_ctl |= SGTL5000_MCLK_FREQ_256FS << | 623 | clk_ctl |= SGTL5000_MCLK_FREQ_256FS << |
611 | SGTL5000_MCLK_FREQ_SHIFT; | 624 | SGTL5000_MCLK_FREQ_SHIFT; |
@@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
619 | SGTL5000_MCLK_FREQ_SHIFT; | 632 | SGTL5000_MCLK_FREQ_SHIFT; |
620 | break; | 633 | break; |
621 | default: | 634 | default: |
622 | /* if mclk not satisify the divider, use pll */ | 635 | /* if mclk does not satisfy the divider, use pll */ |
623 | if (sgtl5000->master) { | 636 | if (sgtl5000->master) { |
624 | clk_ctl |= SGTL5000_MCLK_FREQ_PLL << | 637 | clk_ctl |= SGTL5000_MCLK_FREQ_PLL << |
625 | SGTL5000_MCLK_FREQ_SHIFT; | 638 | SGTL5000_MCLK_FREQ_SHIFT; |
@@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
628 | "PLL not supported in slave mode\n"); | 641 | "PLL not supported in slave mode\n"); |
629 | dev_err(codec->dev, "%d ratio is not supported. " | 642 | dev_err(codec->dev, "%d ratio is not supported. " |
630 | "SYS_MCLK needs to be 256, 384 or 512 * fs\n", | 643 | "SYS_MCLK needs to be 256, 384 or 512 * fs\n", |
631 | sgtl5000->sysclk / sys_fs); | 644 | sgtl5000->sysclk / frame_rate); |
632 | return -EINVAL; | 645 | return -EINVAL; |
633 | } | 646 | } |
634 | } | 647 | } |
@@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev) | |||
795 | SGTL5000_LINEREG_D_POWERUP, | 808 | SGTL5000_LINEREG_D_POWERUP, |
796 | SGTL5000_LINEREG_D_POWERUP); | 809 | SGTL5000_LINEREG_D_POWERUP); |
797 | 810 | ||
798 | /* when internal ldo enabled, simple digital power can be disabled */ | 811 | /* when internal ldo is enabled, simple digital power can be disabled */ |
799 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | 812 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
800 | SGTL5000_LINREG_SIMPLE_POWERUP, | 813 | SGTL5000_LINREG_SIMPLE_POWERUP, |
801 | 0); | 814 | 0); |
@@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) | |||
1079 | /* | 1092 | /* |
1080 | * sgtl5000 has 3 internal power supplies: | 1093 | * sgtl5000 has 3 internal power supplies: |
1081 | * 1. VAG, normally set to vdda/2 | 1094 | * 1. VAG, normally set to vdda/2 |
1082 | * 2. chargepump, set to different value | 1095 | * 2. charge pump, set to different value |
1083 | * according to voltage of vdda and vddio | 1096 | * according to voltage of vdda and vddio |
1084 | * 3. line out VAG, normally set to vddio/2 | 1097 | * 3. line out VAG, normally set to vddio/2 |
1085 | * | 1098 | * |
@@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1325 | SGTL5000_HP_ZCD_EN | | 1338 | SGTL5000_HP_ZCD_EN | |
1326 | SGTL5000_ADC_ZCD_EN); | 1339 | SGTL5000_ADC_ZCD_EN); |
1327 | 1340 | ||
1328 | snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2); | 1341 | snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, |
1342 | SGTL5000_BIAS_R_MASK, | ||
1343 | sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT); | ||
1329 | 1344 | ||
1345 | snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL, | ||
1346 | SGTL5000_BIAS_R_MASK, | ||
1347 | sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT); | ||
1330 | /* | 1348 | /* |
1331 | * disable DAP | 1349 | * disable DAP |
1332 | * TODO: | 1350 | * TODO: |
@@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1416 | { | 1434 | { |
1417 | struct sgtl5000_priv *sgtl5000; | 1435 | struct sgtl5000_priv *sgtl5000; |
1418 | int ret, reg, rev; | 1436 | int ret, reg, rev; |
1419 | unsigned int mclk; | 1437 | struct device_node *np = client->dev.of_node; |
1438 | u32 value; | ||
1420 | 1439 | ||
1421 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), | 1440 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL); |
1422 | GFP_KERNEL); | ||
1423 | if (!sgtl5000) | 1441 | if (!sgtl5000) |
1424 | return -ENOMEM; | 1442 | return -ENOMEM; |
1425 | 1443 | ||
@@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1440 | return ret; | 1458 | return ret; |
1441 | } | 1459 | } |
1442 | 1460 | ||
1443 | /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */ | ||
1444 | mclk = clk_get_rate(sgtl5000->mclk); | ||
1445 | if (mclk < 8000000 || mclk > 27000000) { | ||
1446 | dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n", | ||
1447 | mclk / 1000000, mclk / 1000 % 1000); | ||
1448 | return -EINVAL; | ||
1449 | } | ||
1450 | |||
1451 | ret = clk_prepare_enable(sgtl5000->mclk); | 1461 | ret = clk_prepare_enable(sgtl5000->mclk); |
1452 | if (ret) | 1462 | if (ret) |
1453 | return ret; | 1463 | return ret; |
@@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1469 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); | 1479 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); |
1470 | sgtl5000->revision = rev; | 1480 | sgtl5000->revision = rev; |
1471 | 1481 | ||
1482 | if (np) { | ||
1483 | if (!of_property_read_u32(np, | ||
1484 | "micbias-resistor-k-ohms", &value)) { | ||
1485 | switch (value) { | ||
1486 | case SGTL5000_MICBIAS_OFF: | ||
1487 | sgtl5000->micbias_resistor = 0; | ||
1488 | break; | ||
1489 | case SGTL5000_MICBIAS_2K: | ||
1490 | sgtl5000->micbias_resistor = 1; | ||
1491 | break; | ||
1492 | case SGTL5000_MICBIAS_4K: | ||
1493 | sgtl5000->micbias_resistor = 2; | ||
1494 | break; | ||
1495 | case SGTL5000_MICBIAS_8K: | ||
1496 | sgtl5000->micbias_resistor = 3; | ||
1497 | break; | ||
1498 | default: | ||
1499 | sgtl5000->micbias_resistor = 2; | ||
1500 | dev_err(&client->dev, | ||
1501 | "Unsuitable MicBias resistor\n"); | ||
1502 | } | ||
1503 | } else { | ||
1504 | /* default is 4Kohms */ | ||
1505 | sgtl5000->micbias_resistor = 2; | ||
1506 | } | ||
1507 | if (!of_property_read_u32(np, | ||
1508 | "micbias-voltage-m-volts", &value)) { | ||
1509 | /* 1250mV => 0 */ | ||
1510 | /* steps of 250mV */ | ||
1511 | if ((value >= 1250) && (value <= 3000)) | ||
1512 | sgtl5000->micbias_voltage = (value / 250) - 5; | ||
1513 | else { | ||
1514 | sgtl5000->micbias_voltage = 0; | ||
1515 | dev_err(&client->dev, | ||
1516 | "Unsuitable MicBias resistor\n"); | ||
1517 | } | ||
1518 | } else { | ||
1519 | sgtl5000->micbias_voltage = 0; | ||
1520 | } | ||
1521 | } | ||
1522 | |||
1472 | i2c_set_clientdata(client, sgtl5000); | 1523 | i2c_set_clientdata(client, sgtl5000); |
1473 | 1524 | ||
1474 | /* Ensure sgtl5000 will start with sane register values */ | 1525 | /* Ensure sgtl5000 will start with sane register values */ |
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c index 246081aae8ca..21ca3a5e9f66 100644 --- a/sound/soc/codecs/sigmadsp-i2c.c +++ b/sound/soc/codecs/sigmadsp-i2c.c | |||
@@ -6,29 +6,88 @@ | |||
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/i2c.h> | ||
10 | #include <linux/export.h> | 9 | #include <linux/export.h> |
10 | #include <linux/i2c.h> | ||
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/slab.h> | ||
13 | #include <asm/unaligned.h> | ||
12 | 14 | ||
13 | #include "sigmadsp.h" | 15 | #include "sigmadsp.h" |
14 | 16 | ||
15 | static int sigma_action_write_i2c(void *control_data, | 17 | static int sigmadsp_write_i2c(void *control_data, |
16 | const struct sigma_action *sa, size_t len) | 18 | unsigned int addr, const uint8_t data[], size_t len) |
19 | { | ||
20 | uint8_t *buf; | ||
21 | int ret; | ||
22 | |||
23 | buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA); | ||
24 | if (!buf) | ||
25 | return -ENOMEM; | ||
26 | |||
27 | put_unaligned_be16(addr, buf); | ||
28 | memcpy(buf + 2, data, len); | ||
29 | |||
30 | ret = i2c_master_send(control_data, buf, len + 2); | ||
31 | |||
32 | kfree(buf); | ||
33 | |||
34 | return ret; | ||
35 | } | ||
36 | |||
37 | static int sigmadsp_read_i2c(void *control_data, | ||
38 | unsigned int addr, uint8_t data[], size_t len) | ||
17 | { | 39 | { |
18 | return i2c_master_send(control_data, (const unsigned char *)&sa->addr, | 40 | struct i2c_client *client = control_data; |
19 | len); | 41 | struct i2c_msg msgs[2]; |
42 | uint8_t buf[2]; | ||
43 | int ret; | ||
44 | |||
45 | put_unaligned_be16(addr, buf); | ||
46 | |||
47 | msgs[0].addr = client->addr; | ||
48 | msgs[0].len = sizeof(buf); | ||
49 | msgs[0].buf = buf; | ||
50 | msgs[0].flags = 0; | ||
51 | |||
52 | msgs[1].addr = client->addr; | ||
53 | msgs[1].len = len; | ||
54 | msgs[1].buf = data; | ||
55 | msgs[1].flags = I2C_M_RD; | ||
56 | |||
57 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
58 | if (ret < 0) | ||
59 | return ret; | ||
60 | else if (ret != ARRAY_SIZE(msgs)) | ||
61 | return -EIO; | ||
62 | return 0; | ||
20 | } | 63 | } |
21 | 64 | ||
22 | int process_sigma_firmware(struct i2c_client *client, const char *name) | 65 | /** |
66 | * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance | ||
67 | * @client: The parent I2C device | ||
68 | * @ops: The sigmadsp_ops to use for this instance | ||
69 | * @firmware_name: Name of the firmware file to load | ||
70 | * | ||
71 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
72 | * | ||
73 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
74 | */ | ||
75 | struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, | ||
76 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
23 | { | 77 | { |
24 | struct sigma_firmware ssfw; | 78 | struct sigmadsp *sigmadsp; |
79 | |||
80 | sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name); | ||
81 | if (IS_ERR(sigmadsp)) | ||
82 | return sigmadsp; | ||
25 | 83 | ||
26 | ssfw.control_data = client; | 84 | sigmadsp->control_data = client; |
27 | ssfw.write = sigma_action_write_i2c; | 85 | sigmadsp->write = sigmadsp_write_i2c; |
86 | sigmadsp->read = sigmadsp_read_i2c; | ||
28 | 87 | ||
29 | return _process_sigma_firmware(&client->dev, &ssfw, name); | 88 | return sigmadsp; |
30 | } | 89 | } |
31 | EXPORT_SYMBOL(process_sigma_firmware); | 90 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c); |
32 | 91 | ||
33 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 92 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
34 | MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); | 93 | MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); |
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c index f78ed8d2cfb2..912861be5b87 100644 --- a/sound/soc/codecs/sigmadsp-regmap.c +++ b/sound/soc/codecs/sigmadsp-regmap.c | |||
@@ -12,24 +12,48 @@ | |||
12 | 12 | ||
13 | #include "sigmadsp.h" | 13 | #include "sigmadsp.h" |
14 | 14 | ||
15 | static int sigma_action_write_regmap(void *control_data, | 15 | static int sigmadsp_write_regmap(void *control_data, |
16 | const struct sigma_action *sa, size_t len) | 16 | unsigned int addr, const uint8_t data[], size_t len) |
17 | { | 17 | { |
18 | return regmap_raw_write(control_data, be16_to_cpu(sa->addr), | 18 | return regmap_raw_write(control_data, addr, |
19 | sa->payload, len - 2); | 19 | data, len); |
20 | } | 20 | } |
21 | 21 | ||
22 | int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap, | 22 | static int sigmadsp_read_regmap(void *control_data, |
23 | const char *name) | 23 | unsigned int addr, uint8_t data[], size_t len) |
24 | { | 24 | { |
25 | struct sigma_firmware ssfw; | 25 | return regmap_raw_read(control_data, addr, |
26 | data, len); | ||
27 | } | ||
28 | |||
29 | /** | ||
30 | * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance | ||
31 | * @dev: The parent device | ||
32 | * @regmap: Regmap instance to use | ||
33 | * @ops: The sigmadsp_ops to use for this instance | ||
34 | * @firmware_name: Name of the firmware file to load | ||
35 | * | ||
36 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
37 | * | ||
38 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
39 | */ | ||
40 | struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, | ||
41 | struct regmap *regmap, const struct sigmadsp_ops *ops, | ||
42 | const char *firmware_name) | ||
43 | { | ||
44 | struct sigmadsp *sigmadsp; | ||
45 | |||
46 | sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name); | ||
47 | if (IS_ERR(sigmadsp)) | ||
48 | return sigmadsp; | ||
26 | 49 | ||
27 | ssfw.control_data = regmap; | 50 | sigmadsp->control_data = regmap; |
28 | ssfw.write = sigma_action_write_regmap; | 51 | sigmadsp->write = sigmadsp_write_regmap; |
52 | sigmadsp->read = sigmadsp_read_regmap; | ||
29 | 53 | ||
30 | return _process_sigma_firmware(dev, &ssfw, name); | 54 | return sigmadsp; |
31 | } | 55 | } |
32 | EXPORT_SYMBOL(process_sigma_firmware_regmap); | 56 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap); |
33 | 57 | ||
34 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 58 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
35 | MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); | 59 | MODULE_DESCRIPTION("SigmaDSP regmap firmware loader"); |
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c index f2de7e049bc6..d53680ac78e4 100644 --- a/sound/soc/codecs/sigmadsp.c +++ b/sound/soc/codecs/sigmadsp.c | |||
@@ -1,23 +1,74 @@ | |||
1 | /* | 1 | /* |
2 | * Load Analog Devices SigmaStudio firmware files | 2 | * Load Analog Devices SigmaStudio firmware files |
3 | * | 3 | * |
4 | * Copyright 2009-2011 Analog Devices Inc. | 4 | * Copyright 2009-2014 Analog Devices Inc. |
5 | * | 5 | * |
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/crc32.h> | 9 | #include <linux/crc32.h> |
10 | #include <linux/delay.h> | ||
11 | #include <linux/firmware.h> | 10 | #include <linux/firmware.h> |
12 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
13 | #include <linux/i2c.h> | 12 | #include <linux/i2c.h> |
14 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
15 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/slab.h> | ||
16 | |||
17 | #include <sound/control.h> | ||
18 | #include <sound/soc.h> | ||
16 | 19 | ||
17 | #include "sigmadsp.h" | 20 | #include "sigmadsp.h" |
18 | 21 | ||
19 | #define SIGMA_MAGIC "ADISIGM" | 22 | #define SIGMA_MAGIC "ADISIGM" |
20 | 23 | ||
24 | #define SIGMA_FW_CHUNK_TYPE_DATA 0 | ||
25 | #define SIGMA_FW_CHUNK_TYPE_CONTROL 1 | ||
26 | #define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2 | ||
27 | |||
28 | struct sigmadsp_control { | ||
29 | struct list_head head; | ||
30 | uint32_t samplerates; | ||
31 | unsigned int addr; | ||
32 | unsigned int num_bytes; | ||
33 | const char *name; | ||
34 | struct snd_kcontrol *kcontrol; | ||
35 | bool cached; | ||
36 | uint8_t cache[]; | ||
37 | }; | ||
38 | |||
39 | struct sigmadsp_data { | ||
40 | struct list_head head; | ||
41 | uint32_t samplerates; | ||
42 | unsigned int addr; | ||
43 | unsigned int length; | ||
44 | uint8_t data[]; | ||
45 | }; | ||
46 | |||
47 | struct sigma_fw_chunk { | ||
48 | __le32 length; | ||
49 | __le32 tag; | ||
50 | __le32 samplerates; | ||
51 | } __packed; | ||
52 | |||
53 | struct sigma_fw_chunk_data { | ||
54 | struct sigma_fw_chunk chunk; | ||
55 | __le16 addr; | ||
56 | uint8_t data[]; | ||
57 | } __packed; | ||
58 | |||
59 | struct sigma_fw_chunk_control { | ||
60 | struct sigma_fw_chunk chunk; | ||
61 | __le16 type; | ||
62 | __le16 addr; | ||
63 | __le16 num_bytes; | ||
64 | const char name[]; | ||
65 | } __packed; | ||
66 | |||
67 | struct sigma_fw_chunk_samplerate { | ||
68 | struct sigma_fw_chunk chunk; | ||
69 | __le32 samplerates[]; | ||
70 | } __packed; | ||
71 | |||
21 | struct sigma_firmware_header { | 72 | struct sigma_firmware_header { |
22 | unsigned char magic[7]; | 73 | unsigned char magic[7]; |
23 | u8 version; | 74 | u8 version; |
@@ -28,12 +79,286 @@ enum { | |||
28 | SIGMA_ACTION_WRITEXBYTES = 0, | 79 | SIGMA_ACTION_WRITEXBYTES = 0, |
29 | SIGMA_ACTION_WRITESINGLE, | 80 | SIGMA_ACTION_WRITESINGLE, |
30 | SIGMA_ACTION_WRITESAFELOAD, | 81 | SIGMA_ACTION_WRITESAFELOAD, |
31 | SIGMA_ACTION_DELAY, | ||
32 | SIGMA_ACTION_PLLWAIT, | ||
33 | SIGMA_ACTION_NOOP, | ||
34 | SIGMA_ACTION_END, | 82 | SIGMA_ACTION_END, |
35 | }; | 83 | }; |
36 | 84 | ||
85 | struct sigma_action { | ||
86 | u8 instr; | ||
87 | u8 len_hi; | ||
88 | __le16 len; | ||
89 | __be16 addr; | ||
90 | unsigned char payload[]; | ||
91 | } __packed; | ||
92 | |||
93 | static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr, | ||
94 | const uint8_t data[], size_t len) | ||
95 | { | ||
96 | return sigmadsp->write(sigmadsp->control_data, addr, data, len); | ||
97 | } | ||
98 | |||
99 | static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr, | ||
100 | uint8_t data[], size_t len) | ||
101 | { | ||
102 | return sigmadsp->read(sigmadsp->control_data, addr, data, len); | ||
103 | } | ||
104 | |||
105 | static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol, | ||
106 | struct snd_ctl_elem_info *info) | ||
107 | { | ||
108 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
109 | |||
110 | info->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
111 | info->count = ctrl->num_bytes; | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp, | ||
117 | struct sigmadsp_control *ctrl, void *data) | ||
118 | { | ||
119 | /* safeload loads up to 20 bytes in a atomic operation */ | ||
120 | if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops && | ||
121 | sigmadsp->ops->safeload) | ||
122 | return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data, | ||
123 | ctrl->num_bytes); | ||
124 | else | ||
125 | return sigmadsp_write(sigmadsp, ctrl->addr, data, | ||
126 | ctrl->num_bytes); | ||
127 | } | ||
128 | |||
129 | static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol, | ||
130 | struct snd_ctl_elem_value *ucontrol) | ||
131 | { | ||
132 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
133 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | ||
134 | uint8_t *data; | ||
135 | int ret = 0; | ||
136 | |||
137 | mutex_lock(&sigmadsp->lock); | ||
138 | |||
139 | data = ucontrol->value.bytes.data; | ||
140 | |||
141 | if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) | ||
142 | ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data); | ||
143 | |||
144 | if (ret == 0) { | ||
145 | memcpy(ctrl->cache, data, ctrl->num_bytes); | ||
146 | ctrl->cached = true; | ||
147 | } | ||
148 | |||
149 | mutex_unlock(&sigmadsp->lock); | ||
150 | |||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol, | ||
155 | struct snd_ctl_elem_value *ucontrol) | ||
156 | { | ||
157 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
158 | struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol); | ||
159 | int ret = 0; | ||
160 | |||
161 | mutex_lock(&sigmadsp->lock); | ||
162 | |||
163 | if (!ctrl->cached) { | ||
164 | ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache, | ||
165 | ctrl->num_bytes); | ||
166 | } | ||
167 | |||
168 | if (ret == 0) { | ||
169 | ctrl->cached = true; | ||
170 | memcpy(ucontrol->value.bytes.data, ctrl->cache, | ||
171 | ctrl->num_bytes); | ||
172 | } | ||
173 | |||
174 | mutex_unlock(&sigmadsp->lock); | ||
175 | |||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static void sigmadsp_control_free(struct snd_kcontrol *kcontrol) | ||
180 | { | ||
181 | struct sigmadsp_control *ctrl = (void *)kcontrol->private_value; | ||
182 | |||
183 | ctrl->kcontrol = NULL; | ||
184 | } | ||
185 | |||
186 | static bool sigma_fw_validate_control_name(const char *name, unsigned int len) | ||
187 | { | ||
188 | unsigned int i; | ||
189 | |||
190 | for (i = 0; i < len; i++) { | ||
191 | /* Normal ASCII characters are valid */ | ||
192 | if (name[i] < ' ' || name[i] > '~') | ||
193 | return false; | ||
194 | } | ||
195 | |||
196 | return true; | ||
197 | } | ||
198 | |||
199 | static int sigma_fw_load_control(struct sigmadsp *sigmadsp, | ||
200 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
201 | { | ||
202 | const struct sigma_fw_chunk_control *ctrl_chunk; | ||
203 | struct sigmadsp_control *ctrl; | ||
204 | unsigned int num_bytes; | ||
205 | size_t name_len; | ||
206 | char *name; | ||
207 | int ret; | ||
208 | |||
209 | if (length <= sizeof(*ctrl_chunk)) | ||
210 | return -EINVAL; | ||
211 | |||
212 | ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk; | ||
213 | |||
214 | name_len = length - sizeof(*ctrl_chunk); | ||
215 | if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN) | ||
216 | name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1; | ||
217 | |||
218 | /* Make sure there are no non-displayable characaters in the string */ | ||
219 | if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len)) | ||
220 | return -EINVAL; | ||
221 | |||
222 | num_bytes = le16_to_cpu(ctrl_chunk->num_bytes); | ||
223 | ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL); | ||
224 | if (!ctrl) | ||
225 | return -ENOMEM; | ||
226 | |||
227 | name = kzalloc(name_len + 1, GFP_KERNEL); | ||
228 | if (!name) { | ||
229 | ret = -ENOMEM; | ||
230 | goto err_free_ctrl; | ||
231 | } | ||
232 | memcpy(name, ctrl_chunk->name, name_len); | ||
233 | name[name_len] = '\0'; | ||
234 | ctrl->name = name; | ||
235 | |||
236 | ctrl->addr = le16_to_cpu(ctrl_chunk->addr); | ||
237 | ctrl->num_bytes = num_bytes; | ||
238 | ctrl->samplerates = le32_to_cpu(chunk->samplerates); | ||
239 | |||
240 | list_add_tail(&ctrl->head, &sigmadsp->ctrl_list); | ||
241 | |||
242 | return 0; | ||
243 | |||
244 | err_free_ctrl: | ||
245 | kfree(ctrl); | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static int sigma_fw_load_data(struct sigmadsp *sigmadsp, | ||
251 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
252 | { | ||
253 | const struct sigma_fw_chunk_data *data_chunk; | ||
254 | struct sigmadsp_data *data; | ||
255 | |||
256 | if (length <= sizeof(*data_chunk)) | ||
257 | return -EINVAL; | ||
258 | |||
259 | data_chunk = (struct sigma_fw_chunk_data *)chunk; | ||
260 | |||
261 | length -= sizeof(*data_chunk); | ||
262 | |||
263 | data = kzalloc(sizeof(*data) + length, GFP_KERNEL); | ||
264 | if (!data) | ||
265 | return -ENOMEM; | ||
266 | |||
267 | data->addr = le16_to_cpu(data_chunk->addr); | ||
268 | data->length = length; | ||
269 | data->samplerates = le32_to_cpu(chunk->samplerates); | ||
270 | memcpy(data->data, data_chunk->data, length); | ||
271 | list_add_tail(&data->head, &sigmadsp->data_list); | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp, | ||
277 | const struct sigma_fw_chunk *chunk, unsigned int length) | ||
278 | { | ||
279 | const struct sigma_fw_chunk_samplerate *rate_chunk; | ||
280 | unsigned int num_rates; | ||
281 | unsigned int *rates; | ||
282 | unsigned int i; | ||
283 | |||
284 | rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk; | ||
285 | |||
286 | num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32); | ||
287 | |||
288 | if (num_rates > 32 || num_rates == 0) | ||
289 | return -EINVAL; | ||
290 | |||
291 | /* We only allow one samplerates block per file */ | ||
292 | if (sigmadsp->rate_constraints.count) | ||
293 | return -EINVAL; | ||
294 | |||
295 | rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL); | ||
296 | if (!rates) | ||
297 | return -ENOMEM; | ||
298 | |||
299 | for (i = 0; i < num_rates; i++) | ||
300 | rates[i] = le32_to_cpu(rate_chunk->samplerates[i]); | ||
301 | |||
302 | sigmadsp->rate_constraints.count = num_rates; | ||
303 | sigmadsp->rate_constraints.list = rates; | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp, | ||
309 | const struct firmware *fw) | ||
310 | { | ||
311 | struct sigma_fw_chunk *chunk; | ||
312 | unsigned int length, pos; | ||
313 | int ret; | ||
314 | |||
315 | /* | ||
316 | * Make sure that there is at least one chunk to avoid integer | ||
317 | * underflows later on. Empty firmware is still valid though. | ||
318 | */ | ||
319 | if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header)) | ||
320 | return 0; | ||
321 | |||
322 | pos = sizeof(struct sigma_firmware_header); | ||
323 | |||
324 | while (pos < fw->size - sizeof(*chunk)) { | ||
325 | chunk = (struct sigma_fw_chunk *)(fw->data + pos); | ||
326 | |||
327 | length = le32_to_cpu(chunk->length); | ||
328 | |||
329 | if (length > fw->size - pos || length < sizeof(*chunk)) | ||
330 | return -EINVAL; | ||
331 | |||
332 | switch (le32_to_cpu(chunk->tag)) { | ||
333 | case SIGMA_FW_CHUNK_TYPE_DATA: | ||
334 | ret = sigma_fw_load_data(sigmadsp, chunk, length); | ||
335 | break; | ||
336 | case SIGMA_FW_CHUNK_TYPE_CONTROL: | ||
337 | ret = sigma_fw_load_control(sigmadsp, chunk, length); | ||
338 | break; | ||
339 | case SIGMA_FW_CHUNK_TYPE_SAMPLERATES: | ||
340 | ret = sigma_fw_load_samplerates(sigmadsp, chunk, length); | ||
341 | break; | ||
342 | default: | ||
343 | dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n", | ||
344 | chunk->tag); | ||
345 | ret = 0; | ||
346 | break; | ||
347 | } | ||
348 | |||
349 | if (ret) | ||
350 | return ret; | ||
351 | |||
352 | /* | ||
353 | * This can not overflow since if length is larger than the | ||
354 | * maximum firmware size (0x4000000) we'll error out earilier. | ||
355 | */ | ||
356 | pos += ALIGN(length, sizeof(__le32)); | ||
357 | } | ||
358 | |||
359 | return 0; | ||
360 | } | ||
361 | |||
37 | static inline u32 sigma_action_len(struct sigma_action *sa) | 362 | static inline u32 sigma_action_len(struct sigma_action *sa) |
38 | { | 363 | { |
39 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); | 364 | return (sa->len_hi << 16) | le16_to_cpu(sa->len); |
@@ -62,11 +387,11 @@ static size_t sigma_action_size(struct sigma_action *sa) | |||
62 | * Returns a negative error value in case of an error, 0 if processing of | 387 | * Returns a negative error value in case of an error, 0 if processing of |
63 | * the firmware should be stopped after this action, 1 otherwise. | 388 | * the firmware should be stopped after this action, 1 otherwise. |
64 | */ | 389 | */ |
65 | static int | 390 | static int process_sigma_action(struct sigmadsp *sigmadsp, |
66 | process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | 391 | struct sigma_action *sa) |
67 | { | 392 | { |
68 | size_t len = sigma_action_len(sa); | 393 | size_t len = sigma_action_len(sa); |
69 | int ret; | 394 | struct sigmadsp_data *data; |
70 | 395 | ||
71 | pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, | 396 | pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__, |
72 | sa->instr, sa->addr, len); | 397 | sa->instr, sa->addr, len); |
@@ -75,13 +400,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | |||
75 | case SIGMA_ACTION_WRITEXBYTES: | 400 | case SIGMA_ACTION_WRITEXBYTES: |
76 | case SIGMA_ACTION_WRITESINGLE: | 401 | case SIGMA_ACTION_WRITESINGLE: |
77 | case SIGMA_ACTION_WRITESAFELOAD: | 402 | case SIGMA_ACTION_WRITESAFELOAD: |
78 | ret = ssfw->write(ssfw->control_data, sa, len); | 403 | if (len < 3) |
79 | if (ret < 0) | ||
80 | return -EINVAL; | 404 | return -EINVAL; |
81 | break; | 405 | |
82 | case SIGMA_ACTION_DELAY: | 406 | data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL); |
83 | udelay(len); | 407 | if (!data) |
84 | len = 0; | 408 | return -ENOMEM; |
409 | |||
410 | data->addr = be16_to_cpu(sa->addr); | ||
411 | data->length = len - 2; | ||
412 | memcpy(data->data, sa->payload, data->length); | ||
413 | list_add_tail(&data->head, &sigmadsp->data_list); | ||
85 | break; | 414 | break; |
86 | case SIGMA_ACTION_END: | 415 | case SIGMA_ACTION_END: |
87 | return 0; | 416 | return 0; |
@@ -92,22 +421,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa) | |||
92 | return 1; | 421 | return 1; |
93 | } | 422 | } |
94 | 423 | ||
95 | static int | 424 | static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp, |
96 | process_sigma_actions(struct sigma_firmware *ssfw) | 425 | const struct firmware *fw) |
97 | { | 426 | { |
98 | struct sigma_action *sa; | 427 | struct sigma_action *sa; |
99 | size_t size; | 428 | size_t size, pos; |
100 | int ret; | 429 | int ret; |
101 | 430 | ||
102 | while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) { | 431 | pos = sizeof(struct sigma_firmware_header); |
103 | sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos); | 432 | |
433 | while (pos + sizeof(*sa) <= fw->size) { | ||
434 | sa = (struct sigma_action *)(fw->data + pos); | ||
104 | 435 | ||
105 | size = sigma_action_size(sa); | 436 | size = sigma_action_size(sa); |
106 | ssfw->pos += size; | 437 | pos += size; |
107 | if (ssfw->pos > ssfw->fw->size || size == 0) | 438 | if (pos > fw->size || size == 0) |
108 | break; | 439 | break; |
109 | 440 | ||
110 | ret = process_sigma_action(ssfw, sa); | 441 | ret = process_sigma_action(sigmadsp, sa); |
111 | 442 | ||
112 | pr_debug("%s: action returned %i\n", __func__, ret); | 443 | pr_debug("%s: action returned %i\n", __func__, ret); |
113 | 444 | ||
@@ -115,29 +446,47 @@ process_sigma_actions(struct sigma_firmware *ssfw) | |||
115 | return ret; | 446 | return ret; |
116 | } | 447 | } |
117 | 448 | ||
118 | if (ssfw->pos != ssfw->fw->size) | 449 | if (pos != fw->size) |
119 | return -EINVAL; | 450 | return -EINVAL; |
120 | 451 | ||
121 | return 0; | 452 | return 0; |
122 | } | 453 | } |
123 | 454 | ||
124 | int _process_sigma_firmware(struct device *dev, | 455 | static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp) |
125 | struct sigma_firmware *ssfw, const char *name) | ||
126 | { | 456 | { |
127 | int ret; | 457 | struct sigmadsp_control *ctrl, *_ctrl; |
128 | struct sigma_firmware_header *ssfw_head; | 458 | struct sigmadsp_data *data, *_data; |
459 | |||
460 | list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) { | ||
461 | kfree(ctrl->name); | ||
462 | kfree(ctrl); | ||
463 | } | ||
464 | |||
465 | list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head) | ||
466 | kfree(data); | ||
467 | |||
468 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); | ||
469 | INIT_LIST_HEAD(&sigmadsp->data_list); | ||
470 | } | ||
471 | |||
472 | static void devm_sigmadsp_release(struct device *dev, void *res) | ||
473 | { | ||
474 | sigmadsp_firmware_release((struct sigmadsp *)res); | ||
475 | } | ||
476 | |||
477 | static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name) | ||
478 | { | ||
479 | const struct sigma_firmware_header *ssfw_head; | ||
129 | const struct firmware *fw; | 480 | const struct firmware *fw; |
481 | int ret; | ||
130 | u32 crc; | 482 | u32 crc; |
131 | 483 | ||
132 | pr_debug("%s: loading firmware %s\n", __func__, name); | ||
133 | |||
134 | /* first load the blob */ | 484 | /* first load the blob */ |
135 | ret = request_firmware(&fw, name, dev); | 485 | ret = request_firmware(&fw, name, sigmadsp->dev); |
136 | if (ret) { | 486 | if (ret) { |
137 | pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); | 487 | pr_debug("%s: request_firmware() failed with %i\n", __func__, ret); |
138 | return ret; | 488 | goto done; |
139 | } | 489 | } |
140 | ssfw->fw = fw; | ||
141 | 490 | ||
142 | /* then verify the header */ | 491 | /* then verify the header */ |
143 | ret = -EINVAL; | 492 | ret = -EINVAL; |
@@ -149,13 +498,13 @@ int _process_sigma_firmware(struct device *dev, | |||
149 | * overflows later in the loading process. | 498 | * overflows later in the loading process. |
150 | */ | 499 | */ |
151 | if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { | 500 | if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) { |
152 | dev_err(dev, "Failed to load firmware: Invalid size\n"); | 501 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n"); |
153 | goto done; | 502 | goto done; |
154 | } | 503 | } |
155 | 504 | ||
156 | ssfw_head = (void *)fw->data; | 505 | ssfw_head = (void *)fw->data; |
157 | if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { | 506 | if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) { |
158 | dev_err(dev, "Failed to load firmware: Invalid magic\n"); | 507 | dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n"); |
159 | goto done; | 508 | goto done; |
160 | } | 509 | } |
161 | 510 | ||
@@ -163,23 +512,303 @@ int _process_sigma_firmware(struct device *dev, | |||
163 | fw->size - sizeof(*ssfw_head)); | 512 | fw->size - sizeof(*ssfw_head)); |
164 | pr_debug("%s: crc=%x\n", __func__, crc); | 513 | pr_debug("%s: crc=%x\n", __func__, crc); |
165 | if (crc != le32_to_cpu(ssfw_head->crc)) { | 514 | if (crc != le32_to_cpu(ssfw_head->crc)) { |
166 | dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", | 515 | dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n", |
167 | le32_to_cpu(ssfw_head->crc), crc); | 516 | le32_to_cpu(ssfw_head->crc), crc); |
168 | goto done; | 517 | goto done; |
169 | } | 518 | } |
170 | 519 | ||
171 | ssfw->pos = sizeof(*ssfw_head); | 520 | switch (ssfw_head->version) { |
521 | case 1: | ||
522 | ret = sigmadsp_fw_load_v1(sigmadsp, fw); | ||
523 | break; | ||
524 | case 2: | ||
525 | ret = sigmadsp_fw_load_v2(sigmadsp, fw); | ||
526 | break; | ||
527 | default: | ||
528 | dev_err(sigmadsp->dev, | ||
529 | "Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n", | ||
530 | ssfw_head->version); | ||
531 | ret = -EINVAL; | ||
532 | break; | ||
533 | } | ||
172 | 534 | ||
173 | /* finally process all of the actions */ | 535 | if (ret) |
174 | ret = process_sigma_actions(ssfw); | 536 | sigmadsp_firmware_release(sigmadsp); |
175 | 537 | ||
176 | done: | 538 | done: |
177 | release_firmware(fw); | 539 | release_firmware(fw); |
178 | 540 | ||
179 | pr_debug("%s: loaded %s\n", __func__, name); | 541 | return ret; |
542 | } | ||
543 | |||
544 | static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev, | ||
545 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
546 | { | ||
547 | sigmadsp->ops = ops; | ||
548 | sigmadsp->dev = dev; | ||
549 | |||
550 | INIT_LIST_HEAD(&sigmadsp->ctrl_list); | ||
551 | INIT_LIST_HEAD(&sigmadsp->data_list); | ||
552 | mutex_init(&sigmadsp->lock); | ||
553 | |||
554 | return sigmadsp_firmware_load(sigmadsp, firmware_name); | ||
555 | } | ||
556 | |||
557 | /** | ||
558 | * devm_sigmadsp_init() - Initialize SigmaDSP instance | ||
559 | * @dev: The parent device | ||
560 | * @ops: The sigmadsp_ops to use for this instance | ||
561 | * @firmware_name: Name of the firmware file to load | ||
562 | * | ||
563 | * Allocates a SigmaDSP instance and loads the specified firmware file. | ||
564 | * | ||
565 | * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. | ||
566 | */ | ||
567 | struct sigmadsp *devm_sigmadsp_init(struct device *dev, | ||
568 | const struct sigmadsp_ops *ops, const char *firmware_name) | ||
569 | { | ||
570 | struct sigmadsp *sigmadsp; | ||
571 | int ret; | ||
572 | |||
573 | sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp), | ||
574 | GFP_KERNEL); | ||
575 | if (!sigmadsp) | ||
576 | return ERR_PTR(-ENOMEM); | ||
577 | |||
578 | ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name); | ||
579 | if (ret) { | ||
580 | devres_free(sigmadsp); | ||
581 | return ERR_PTR(ret); | ||
582 | } | ||
583 | |||
584 | devres_add(dev, sigmadsp); | ||
585 | |||
586 | return sigmadsp; | ||
587 | } | ||
588 | EXPORT_SYMBOL_GPL(devm_sigmadsp_init); | ||
589 | |||
590 | static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate) | ||
591 | { | ||
592 | unsigned int i; | ||
593 | |||
594 | for (i = 0; i < sigmadsp->rate_constraints.count; i++) { | ||
595 | if (sigmadsp->rate_constraints.list[i] == rate) | ||
596 | return i; | ||
597 | } | ||
598 | |||
599 | return -EINVAL; | ||
600 | } | ||
601 | |||
602 | static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp, | ||
603 | unsigned int samplerate) | ||
604 | { | ||
605 | int samplerate_index; | ||
606 | |||
607 | if (samplerate == 0) | ||
608 | return 0; | ||
609 | |||
610 | if (sigmadsp->rate_constraints.count) { | ||
611 | samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate); | ||
612 | if (samplerate_index < 0) | ||
613 | return 0; | ||
614 | |||
615 | return BIT(samplerate_index); | ||
616 | } else { | ||
617 | return ~0; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | static bool sigmadsp_samplerate_valid(unsigned int supported, | ||
622 | unsigned int requested) | ||
623 | { | ||
624 | /* All samplerates are supported */ | ||
625 | if (!supported) | ||
626 | return true; | ||
627 | |||
628 | return supported & requested; | ||
629 | } | ||
630 | |||
631 | static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp, | ||
632 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | ||
633 | { | ||
634 | struct snd_kcontrol_new template; | ||
635 | struct snd_kcontrol *kcontrol; | ||
636 | |||
637 | memset(&template, 0, sizeof(template)); | ||
638 | template.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
639 | template.name = ctrl->name; | ||
640 | template.info = sigmadsp_ctrl_info; | ||
641 | template.get = sigmadsp_ctrl_get; | ||
642 | template.put = sigmadsp_ctrl_put; | ||
643 | template.private_value = (unsigned long)ctrl; | ||
644 | template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
645 | if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask)) | ||
646 | template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
647 | |||
648 | kcontrol = snd_ctl_new1(&template, sigmadsp); | ||
649 | if (!kcontrol) | ||
650 | return -ENOMEM; | ||
651 | |||
652 | kcontrol->private_free = sigmadsp_control_free; | ||
653 | ctrl->kcontrol = kcontrol; | ||
654 | |||
655 | return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol); | ||
656 | } | ||
657 | |||
658 | static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp, | ||
659 | struct sigmadsp_control *ctrl, unsigned int samplerate_mask) | ||
660 | { | ||
661 | struct snd_card *card = sigmadsp->component->card->snd_card; | ||
662 | struct snd_kcontrol_volatile *vd; | ||
663 | struct snd_ctl_elem_id id; | ||
664 | bool active; | ||
665 | bool changed = false; | ||
666 | |||
667 | active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask); | ||
668 | |||
669 | down_write(&card->controls_rwsem); | ||
670 | if (!ctrl->kcontrol) { | ||
671 | up_write(&card->controls_rwsem); | ||
672 | return; | ||
673 | } | ||
674 | |||
675 | id = ctrl->kcontrol->id; | ||
676 | vd = &ctrl->kcontrol->vd[0]; | ||
677 | if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) { | ||
678 | vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
679 | changed = true; | ||
680 | } | ||
681 | up_write(&card->controls_rwsem); | ||
682 | |||
683 | if (active && changed) { | ||
684 | mutex_lock(&sigmadsp->lock); | ||
685 | if (ctrl->cached) | ||
686 | sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache); | ||
687 | mutex_unlock(&sigmadsp->lock); | ||
688 | } | ||
689 | |||
690 | if (changed) | ||
691 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id); | ||
692 | } | ||
693 | |||
694 | /** | ||
695 | * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component | ||
696 | * @sigmadsp: The sigmadsp instance to attach | ||
697 | * @component: The component to attach to | ||
698 | * | ||
699 | * Typically called in the components probe callback. | ||
700 | * | ||
701 | * Note, once this function has been called the firmware must not be released | ||
702 | * until after the ALSA snd_card that the component belongs to has been | ||
703 | * disconnected, even if sigmadsp_attach() returns an error. | ||
704 | */ | ||
705 | int sigmadsp_attach(struct sigmadsp *sigmadsp, | ||
706 | struct snd_soc_component *component) | ||
707 | { | ||
708 | struct sigmadsp_control *ctrl; | ||
709 | unsigned int samplerate_mask; | ||
710 | int ret; | ||
711 | |||
712 | sigmadsp->component = component; | ||
713 | |||
714 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, | ||
715 | sigmadsp->current_samplerate); | ||
716 | |||
717 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) { | ||
718 | ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask); | ||
719 | if (ret) | ||
720 | return ret; | ||
721 | } | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | EXPORT_SYMBOL_GPL(sigmadsp_attach); | ||
726 | |||
727 | /** | ||
728 | * sigmadsp_setup() - Setup the DSP for the specified samplerate | ||
729 | * @sigmadsp: The sigmadsp instance to configure | ||
730 | * @samplerate: The samplerate the DSP should be configured for | ||
731 | * | ||
732 | * Loads the appropriate firmware program and parameter memory (if not already | ||
733 | * loaded) and enables the controls for the specified samplerate. Any control | ||
734 | * parameter changes that have been made previously will be restored. | ||
735 | * | ||
736 | * Returns 0 on success, a negative error code otherwise. | ||
737 | */ | ||
738 | int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate) | ||
739 | { | ||
740 | struct sigmadsp_control *ctrl; | ||
741 | unsigned int samplerate_mask; | ||
742 | struct sigmadsp_data *data; | ||
743 | int ret; | ||
744 | |||
745 | if (sigmadsp->current_samplerate == samplerate) | ||
746 | return 0; | ||
747 | |||
748 | samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate); | ||
749 | if (samplerate_mask == 0) | ||
750 | return -EINVAL; | ||
751 | |||
752 | list_for_each_entry(data, &sigmadsp->data_list, head) { | ||
753 | if (!sigmadsp_samplerate_valid(data->samplerates, | ||
754 | samplerate_mask)) | ||
755 | continue; | ||
756 | ret = sigmadsp_write(sigmadsp, data->addr, data->data, | ||
757 | data->length); | ||
758 | if (ret) | ||
759 | goto err; | ||
760 | } | ||
761 | |||
762 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) | ||
763 | sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask); | ||
764 | |||
765 | sigmadsp->current_samplerate = samplerate; | ||
766 | |||
767 | return 0; | ||
768 | err: | ||
769 | sigmadsp_reset(sigmadsp); | ||
180 | 770 | ||
181 | return ret; | 771 | return ret; |
182 | } | 772 | } |
183 | EXPORT_SYMBOL_GPL(_process_sigma_firmware); | 773 | EXPORT_SYMBOL_GPL(sigmadsp_setup); |
774 | |||
775 | /** | ||
776 | * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset | ||
777 | * @sigmadsp: The sigmadsp instance to reset | ||
778 | * | ||
779 | * Should be called whenever the DSP has been reset and parameter and program | ||
780 | * memory need to be re-loaded. | ||
781 | */ | ||
782 | void sigmadsp_reset(struct sigmadsp *sigmadsp) | ||
783 | { | ||
784 | struct sigmadsp_control *ctrl; | ||
785 | |||
786 | list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) | ||
787 | sigmadsp_activate_ctrl(sigmadsp, ctrl, false); | ||
788 | |||
789 | sigmadsp->current_samplerate = 0; | ||
790 | } | ||
791 | EXPORT_SYMBOL_GPL(sigmadsp_reset); | ||
792 | |||
793 | /** | ||
794 | * sigmadsp_restrict_params() - Applies DSP firmware specific constraints | ||
795 | * @sigmadsp: The sigmadsp instance | ||
796 | * @substream: The substream to restrict | ||
797 | * | ||
798 | * Applies samplerate constraints that may be required by the firmware Should | ||
799 | * typically be called from the CODEC/component drivers startup callback. | ||
800 | * | ||
801 | * Returns 0 on success, a negative error code otherwise. | ||
802 | */ | ||
803 | int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, | ||
804 | struct snd_pcm_substream *substream) | ||
805 | { | ||
806 | if (sigmadsp->rate_constraints.count == 0) | ||
807 | return 0; | ||
808 | |||
809 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
810 | SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints); | ||
811 | } | ||
812 | EXPORT_SYMBOL_GPL(sigmadsp_restrict_params); | ||
184 | 813 | ||
185 | MODULE_LICENSE("GPL"); | 814 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h index c47cd23e9827..614475cbb823 100644 --- a/sound/soc/codecs/sigmadsp.h +++ b/sound/soc/codecs/sigmadsp.h | |||
@@ -11,31 +11,56 @@ | |||
11 | 11 | ||
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/regmap.h> | 13 | #include <linux/regmap.h> |
14 | #include <linux/list.h> | ||
14 | 15 | ||
15 | struct sigma_action { | 16 | #include <sound/pcm.h> |
16 | u8 instr; | ||
17 | u8 len_hi; | ||
18 | __le16 len; | ||
19 | __be16 addr; | ||
20 | unsigned char payload[]; | ||
21 | } __packed; | ||
22 | 17 | ||
23 | struct sigma_firmware { | 18 | struct sigmadsp; |
24 | const struct firmware *fw; | 19 | struct snd_soc_component; |
25 | size_t pos; | 20 | struct snd_pcm_substream; |
21 | |||
22 | struct sigmadsp_ops { | ||
23 | int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr, | ||
24 | const uint8_t *data, size_t len); | ||
25 | }; | ||
26 | |||
27 | struct sigmadsp { | ||
28 | const struct sigmadsp_ops *ops; | ||
29 | |||
30 | struct list_head ctrl_list; | ||
31 | struct list_head data_list; | ||
32 | |||
33 | struct snd_pcm_hw_constraint_list rate_constraints; | ||
34 | |||
35 | unsigned int current_samplerate; | ||
36 | struct snd_soc_component *component; | ||
37 | struct device *dev; | ||
38 | |||
39 | struct mutex lock; | ||
26 | 40 | ||
27 | void *control_data; | 41 | void *control_data; |
28 | int (*write)(void *control_data, const struct sigma_action *sa, | 42 | int (*write)(void *, unsigned int, const uint8_t *, size_t); |
29 | size_t len); | 43 | int (*read)(void *, unsigned int, uint8_t *, size_t); |
30 | }; | 44 | }; |
31 | 45 | ||
32 | int _process_sigma_firmware(struct device *dev, | 46 | struct sigmadsp *devm_sigmadsp_init(struct device *dev, |
33 | struct sigma_firmware *ssfw, const char *name); | 47 | const struct sigmadsp_ops *ops, const char *firmware_name); |
48 | void sigmadsp_reset(struct sigmadsp *sigmadsp); | ||
49 | |||
50 | int sigmadsp_restrict_params(struct sigmadsp *sigmadsp, | ||
51 | struct snd_pcm_substream *substream); | ||
34 | 52 | ||
35 | struct i2c_client; | 53 | struct i2c_client; |
36 | 54 | ||
37 | extern int process_sigma_firmware(struct i2c_client *client, const char *name); | 55 | struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev, |
38 | extern int process_sigma_firmware_regmap(struct device *dev, | 56 | struct regmap *regmap, const struct sigmadsp_ops *ops, |
39 | struct regmap *regmap, const char *name); | 57 | const char *firmware_name); |
58 | struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, | ||
59 | const struct sigmadsp_ops *ops, const char *firmware_name); | ||
60 | |||
61 | int sigmadsp_attach(struct sigmadsp *sigmadsp, | ||
62 | struct snd_soc_component *component); | ||
63 | int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate); | ||
64 | void sigmadsp_reset(struct sigmadsp *sigmadsp); | ||
40 | 65 | ||
41 | #endif | 66 | #endif |
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 06ba4923fd5a..07eea20e6645 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c | |||
@@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | |||
120 | { | 120 | { |
121 | #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) | 121 | #define ATLAS6_CODEC_ENABLE_BITS (1 << 29) |
122 | #define ATLAS6_CODEC_RESET_BITS (1 << 28) | 122 | #define ATLAS6_CODEC_RESET_BITS (1 << 28) |
123 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | 123 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
124 | struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); | ||
124 | switch (event) { | 125 | switch (event) { |
125 | case SND_SOC_DAPM_PRE_PMU: | 126 | case SND_SOC_DAPM_PRE_PMU: |
126 | enable_and_reset_codec(sirf_audio_codec->regmap, | 127 | enable_and_reset_codec(sirf_audio_codec->regmap, |
@@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w, | |||
142 | { | 143 | { |
143 | #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) | 144 | #define PRIMA2_CODEC_ENABLE_BITS (1 << 27) |
144 | #define PRIMA2_CODEC_RESET_BITS (1 << 26) | 145 | #define PRIMA2_CODEC_RESET_BITS (1 << 26) |
145 | struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev); | 146 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
147 | struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec); | ||
146 | switch (event) { | 148 | switch (event) { |
147 | case SND_SOC_DAPM_POST_PMU: | 149 | case SND_SOC_DAPM_POST_PMU: |
148 | enable_and_reset_codec(sirf_audio_codec->regmap, | 150 | enable_and_reset_codec(sirf_audio_codec->regmap, |
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c index cf8fa40662f0..31d97cd5e59b 100644 --- a/sound/soc/codecs/sn95031.c +++ b/sound/soc/codecs/sn95031.c | |||
@@ -867,25 +867,16 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec) | |||
867 | snd_soc_write(codec, SN95031_SSR2, 0x10); | 867 | snd_soc_write(codec, SN95031_SSR2, 0x10); |
868 | snd_soc_write(codec, SN95031_SSR3, 0x40); | 868 | snd_soc_write(codec, SN95031_SSR3, 0x40); |
869 | 869 | ||
870 | snd_soc_add_codec_controls(codec, sn95031_snd_controls, | ||
871 | ARRAY_SIZE(sn95031_snd_controls)); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int sn95031_codec_remove(struct snd_soc_codec *codec) | ||
877 | { | ||
878 | pr_debug("codec_remove called\n"); | ||
879 | sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF); | ||
880 | |||
881 | return 0; | 870 | return 0; |
882 | } | 871 | } |
883 | 872 | ||
884 | static struct snd_soc_codec_driver sn95031_codec = { | 873 | static struct snd_soc_codec_driver sn95031_codec = { |
885 | .probe = sn95031_codec_probe, | 874 | .probe = sn95031_codec_probe, |
886 | .remove = sn95031_codec_remove, | ||
887 | .set_bias_level = sn95031_set_vaud_bias, | 875 | .set_bias_level = sn95031_set_vaud_bias, |
888 | .idle_bias_off = true, | 876 | .idle_bias_off = true, |
877 | |||
878 | .controls = sn95031_snd_controls, | ||
879 | .num_controls = ARRAY_SIZE(sn95031_snd_controls), | ||
889 | .dapm_widgets = sn95031_dapm_widgets, | 880 | .dapm_widgets = sn95031_dapm_widgets, |
890 | .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), | 881 | .num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets), |
891 | .dapm_routes = sn95031_audio_map, | 882 | .dapm_routes = sn95031_audio_map, |
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 4b5c17f8507e..a984485108cd 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c | |||
@@ -69,6 +69,22 @@ | |||
69 | #define SSM4567_DAC_FS_64000_96000 0x3 | 69 | #define SSM4567_DAC_FS_64000_96000 0x3 |
70 | #define SSM4567_DAC_FS_128000_192000 0x4 | 70 | #define SSM4567_DAC_FS_128000_192000 0x4 |
71 | 71 | ||
72 | /* SAI_CTRL_1 */ | ||
73 | #define SSM4567_SAI_CTRL_1_BCLK BIT(6) | ||
74 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK (0x3 << 4) | ||
75 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_32 (0x0 << 4) | ||
76 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_48 (0x1 << 4) | ||
77 | #define SSM4567_SAI_CTRL_1_TDM_BLCKS_64 (0x2 << 4) | ||
78 | #define SSM4567_SAI_CTRL_1_FSYNC BIT(3) | ||
79 | #define SSM4567_SAI_CTRL_1_LJ BIT(2) | ||
80 | #define SSM4567_SAI_CTRL_1_TDM BIT(1) | ||
81 | #define SSM4567_SAI_CTRL_1_PDM BIT(0) | ||
82 | |||
83 | /* SAI_CTRL_2 */ | ||
84 | #define SSM4567_SAI_CTRL_2_AUTO_SLOT BIT(3) | ||
85 | #define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK 0x7 | ||
86 | #define SSM4567_SAI_CTRL_2_TDM_SLOT(x) (x) | ||
87 | |||
72 | struct ssm4567 { | 88 | struct ssm4567 { |
73 | struct regmap *regmap; | 89 | struct regmap *regmap; |
74 | }; | 90 | }; |
@@ -145,15 +161,24 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = { | |||
145 | SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, | 161 | SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, |
146 | 0xff, 1, ssm4567_vol_tlv), | 162 | 0xff, 1, ssm4567_vol_tlv), |
147 | SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), | 163 | SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), |
164 | SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL, | ||
165 | 5, 1, 0), | ||
148 | }; | 166 | }; |
149 | 167 | ||
168 | static const struct snd_kcontrol_new ssm4567_amplifier_boost_control = | ||
169 | SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1); | ||
170 | |||
150 | static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { | 171 | static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { |
151 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), | 172 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), |
173 | SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1, | ||
174 | &ssm4567_amplifier_boost_control), | ||
152 | 175 | ||
153 | SND_SOC_DAPM_OUTPUT("OUT"), | 176 | SND_SOC_DAPM_OUTPUT("OUT"), |
154 | }; | 177 | }; |
155 | 178 | ||
156 | static const struct snd_soc_dapm_route ssm4567_routes[] = { | 179 | static const struct snd_soc_dapm_route ssm4567_routes[] = { |
180 | { "OUT", NULL, "Amplifier Boost" }, | ||
181 | { "Amplifier Boost", "Switch", "DAC" }, | ||
157 | { "OUT", NULL, "DAC" }, | 182 | { "OUT", NULL, "DAC" }, |
158 | }; | 183 | }; |
159 | 184 | ||
@@ -192,6 +217,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute) | |||
192 | SSM4567_DAC_MUTE, val); | 217 | SSM4567_DAC_MUTE, val); |
193 | } | 218 | } |
194 | 219 | ||
220 | static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
221 | unsigned int rx_mask, int slots, int width) | ||
222 | { | ||
223 | struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); | ||
224 | unsigned int blcks; | ||
225 | int slot; | ||
226 | int ret; | ||
227 | |||
228 | if (tx_mask == 0) | ||
229 | return -EINVAL; | ||
230 | |||
231 | if (rx_mask && rx_mask != tx_mask) | ||
232 | return -EINVAL; | ||
233 | |||
234 | slot = __ffs(tx_mask); | ||
235 | if (tx_mask != BIT(slot)) | ||
236 | return -EINVAL; | ||
237 | |||
238 | switch (width) { | ||
239 | case 32: | ||
240 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32; | ||
241 | break; | ||
242 | case 48: | ||
243 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48; | ||
244 | break; | ||
245 | case 64: | ||
246 | blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64; | ||
247 | break; | ||
248 | default: | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2, | ||
253 | SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK, | ||
254 | SSM4567_SAI_CTRL_2_TDM_SLOT(slot)); | ||
255 | if (ret) | ||
256 | return ret; | ||
257 | |||
258 | return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, | ||
259 | SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks); | ||
260 | } | ||
261 | |||
262 | static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
263 | { | ||
264 | struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai); | ||
265 | unsigned int ctrl1 = 0; | ||
266 | bool invert_fclk; | ||
267 | |||
268 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
269 | case SND_SOC_DAIFMT_CBS_CFS: | ||
270 | break; | ||
271 | default: | ||
272 | return -EINVAL; | ||
273 | } | ||
274 | |||
275 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
276 | case SND_SOC_DAIFMT_NB_NF: | ||
277 | invert_fclk = false; | ||
278 | break; | ||
279 | case SND_SOC_DAIFMT_IB_NF: | ||
280 | ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; | ||
281 | invert_fclk = false; | ||
282 | break; | ||
283 | case SND_SOC_DAIFMT_NB_IF: | ||
284 | ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; | ||
285 | invert_fclk = true; | ||
286 | break; | ||
287 | case SND_SOC_DAIFMT_IB_IF: | ||
288 | ctrl1 |= SSM4567_SAI_CTRL_1_BCLK; | ||
289 | invert_fclk = true; | ||
290 | break; | ||
291 | default: | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | |||
295 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
296 | case SND_SOC_DAIFMT_I2S: | ||
297 | break; | ||
298 | case SND_SOC_DAIFMT_LEFT_J: | ||
299 | ctrl1 |= SSM4567_SAI_CTRL_1_LJ; | ||
300 | invert_fclk = !invert_fclk; | ||
301 | break; | ||
302 | case SND_SOC_DAIFMT_DSP_A: | ||
303 | ctrl1 |= SSM4567_SAI_CTRL_1_TDM; | ||
304 | break; | ||
305 | case SND_SOC_DAIFMT_DSP_B: | ||
306 | ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ; | ||
307 | break; | ||
308 | case SND_SOC_DAIFMT_PDM: | ||
309 | ctrl1 |= SSM4567_SAI_CTRL_1_PDM; | ||
310 | break; | ||
311 | default: | ||
312 | return -EINVAL; | ||
313 | } | ||
314 | |||
315 | if (invert_fclk) | ||
316 | ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC; | ||
317 | |||
318 | return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1); | ||
319 | } | ||
320 | |||
195 | static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) | 321 | static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) |
196 | { | 322 | { |
197 | int ret = 0; | 323 | int ret = 0; |
@@ -246,6 +372,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec, | |||
246 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { | 372 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { |
247 | .hw_params = ssm4567_hw_params, | 373 | .hw_params = ssm4567_hw_params, |
248 | .digital_mute = ssm4567_mute, | 374 | .digital_mute = ssm4567_mute, |
375 | .set_fmt = ssm4567_set_dai_fmt, | ||
376 | .set_tdm_slot = ssm4567_set_tdm_slot, | ||
249 | }; | 377 | }; |
250 | 378 | ||
251 | static struct snd_soc_dai_driver ssm4567_dai = { | 379 | static struct snd_soc_dai_driver ssm4567_dai = { |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 48740855566d..7e18200dd6a9 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -833,23 +833,6 @@ static struct snd_soc_dai_driver sta32x_dai = { | |||
833 | .ops = &sta32x_dai_ops, | 833 | .ops = &sta32x_dai_ops, |
834 | }; | 834 | }; |
835 | 835 | ||
836 | #ifdef CONFIG_PM | ||
837 | static int sta32x_suspend(struct snd_soc_codec *codec) | ||
838 | { | ||
839 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | static int sta32x_resume(struct snd_soc_codec *codec) | ||
844 | { | ||
845 | sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
846 | return 0; | ||
847 | } | ||
848 | #else | ||
849 | #define sta32x_suspend NULL | ||
850 | #define sta32x_resume NULL | ||
851 | #endif | ||
852 | |||
853 | static int sta32x_probe(struct snd_soc_codec *codec) | 836 | static int sta32x_probe(struct snd_soc_codec *codec) |
854 | { | 837 | { |
855 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | 838 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); |
@@ -936,7 +919,6 @@ static int sta32x_remove(struct snd_soc_codec *codec) | |||
936 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); | 919 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); |
937 | 920 | ||
938 | sta32x_watchdog_stop(sta32x); | 921 | sta32x_watchdog_stop(sta32x); |
939 | sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
940 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); | 922 | regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies); |
941 | 923 | ||
942 | return 0; | 924 | return 0; |
@@ -955,9 +937,8 @@ static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg) | |||
955 | static const struct snd_soc_codec_driver sta32x_codec = { | 937 | static const struct snd_soc_codec_driver sta32x_codec = { |
956 | .probe = sta32x_probe, | 938 | .probe = sta32x_probe, |
957 | .remove = sta32x_remove, | 939 | .remove = sta32x_remove, |
958 | .suspend = sta32x_suspend, | ||
959 | .resume = sta32x_resume, | ||
960 | .set_bias_level = sta32x_set_bias_level, | 940 | .set_bias_level = sta32x_set_bias_level, |
941 | .suspend_bias_off = true, | ||
961 | .controls = sta32x_snd_controls, | 942 | .controls = sta32x_snd_controls, |
962 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), | 943 | .num_controls = ARRAY_SIZE(sta32x_snd_controls), |
963 | .dapm_widgets = sta32x_dapm_widgets, | 944 | .dapm_widgets = sta32x_dapm_widgets, |
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index cc97dd52aa9c..bda2ee18769e 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c | |||
@@ -912,23 +912,6 @@ static struct snd_soc_dai_driver sta350_dai = { | |||
912 | .ops = &sta350_dai_ops, | 912 | .ops = &sta350_dai_ops, |
913 | }; | 913 | }; |
914 | 914 | ||
915 | #ifdef CONFIG_PM | ||
916 | static int sta350_suspend(struct snd_soc_codec *codec) | ||
917 | { | ||
918 | sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static int sta350_resume(struct snd_soc_codec *codec) | ||
923 | { | ||
924 | sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
925 | return 0; | ||
926 | } | ||
927 | #else | ||
928 | #define sta350_suspend NULL | ||
929 | #define sta350_resume NULL | ||
930 | #endif | ||
931 | |||
932 | static int sta350_probe(struct snd_soc_codec *codec) | 915 | static int sta350_probe(struct snd_soc_codec *codec) |
933 | { | 916 | { |
934 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); | 917 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); |
@@ -1065,7 +1048,6 @@ static int sta350_remove(struct snd_soc_codec *codec) | |||
1065 | { | 1048 | { |
1066 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); | 1049 | struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec); |
1067 | 1050 | ||
1068 | sta350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1069 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); | 1051 | regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies); |
1070 | 1052 | ||
1071 | return 0; | 1053 | return 0; |
@@ -1074,9 +1056,8 @@ static int sta350_remove(struct snd_soc_codec *codec) | |||
1074 | static const struct snd_soc_codec_driver sta350_codec = { | 1056 | static const struct snd_soc_codec_driver sta350_codec = { |
1075 | .probe = sta350_probe, | 1057 | .probe = sta350_probe, |
1076 | .remove = sta350_remove, | 1058 | .remove = sta350_remove, |
1077 | .suspend = sta350_suspend, | ||
1078 | .resume = sta350_resume, | ||
1079 | .set_bias_level = sta350_set_bias_level, | 1059 | .set_bias_level = sta350_set_bias_level, |
1060 | .suspend_bias_off = true, | ||
1080 | .controls = sta350_snd_controls, | 1061 | .controls = sta350_snd_controls, |
1081 | .num_controls = ARRAY_SIZE(sta350_snd_controls), | 1062 | .num_controls = ARRAY_SIZE(sta350_snd_controls), |
1082 | .dapm_widgets = sta350_dapm_widgets, | 1063 | .dapm_widgets = sta350_dapm_widgets, |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 89c748dd3d6e..b0f436d10125 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -319,41 +319,10 @@ static struct snd_soc_dai_driver sta529_dai = { | |||
319 | .ops = &sta529_dai_ops, | 319 | .ops = &sta529_dai_ops, |
320 | }; | 320 | }; |
321 | 321 | ||
322 | static int sta529_probe(struct snd_soc_codec *codec) | ||
323 | { | ||
324 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | /* power down chip */ | ||
330 | static int sta529_remove(struct snd_soc_codec *codec) | ||
331 | { | ||
332 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int sta529_suspend(struct snd_soc_codec *codec) | ||
338 | { | ||
339 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
340 | |||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static int sta529_resume(struct snd_soc_codec *codec) | ||
345 | { | ||
346 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static const struct snd_soc_codec_driver sta529_codec_driver = { | 322 | static const struct snd_soc_codec_driver sta529_codec_driver = { |
352 | .probe = sta529_probe, | ||
353 | .remove = sta529_remove, | ||
354 | .set_bias_level = sta529_set_bias_level, | 323 | .set_bias_level = sta529_set_bias_level, |
355 | .suspend = sta529_suspend, | 324 | .suspend_bias_off = true, |
356 | .resume = sta529_resume, | 325 | |
357 | .controls = sta529_snd_controls, | 326 | .controls = sta529_snd_controls, |
358 | .num_controls = ARRAY_SIZE(sta529_snd_controls), | 327 | .num_controls = ARRAY_SIZE(sta529_snd_controls), |
359 | }; | 328 | }; |
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 53b810d23fea..dbff0c89be48 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c | |||
@@ -139,18 +139,19 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = { | |||
139 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 139 | static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
140 | unsigned int val) | 140 | unsigned int val) |
141 | { | 141 | { |
142 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
142 | u16 *cache = codec->reg_cache; | 143 | u16 *cache = codec->reg_cache; |
143 | 144 | ||
144 | if (reg > AC97_STAC_PAGE0) { | 145 | if (reg > AC97_STAC_PAGE0) { |
145 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 146 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
146 | soc_ac97_ops->write(codec->ac97, reg, val); | 147 | soc_ac97_ops->write(ac97, reg, val); |
147 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 148 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
148 | return 0; | 149 | return 0; |
149 | } | 150 | } |
150 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) | 151 | if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) |
151 | return -EIO; | 152 | return -EIO; |
152 | 153 | ||
153 | soc_ac97_ops->write(codec->ac97, reg, val); | 154 | soc_ac97_ops->write(ac97, reg, val); |
154 | cache[reg / 2] = val; | 155 | cache[reg / 2] = val; |
155 | return 0; | 156 | return 0; |
156 | } | 157 | } |
@@ -158,11 +159,12 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, | |||
158 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | 159 | static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, |
159 | unsigned int reg) | 160 | unsigned int reg) |
160 | { | 161 | { |
162 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
161 | u16 val = 0, *cache = codec->reg_cache; | 163 | u16 val = 0, *cache = codec->reg_cache; |
162 | 164 | ||
163 | if (reg > AC97_STAC_PAGE0) { | 165 | if (reg > AC97_STAC_PAGE0) { |
164 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); | 166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 0); |
165 | val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0); | 167 | val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0); |
166 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); | 168 | stac9766_ac97_write(codec, AC97_INT_PAGING, 1); |
167 | return val; | 169 | return val; |
168 | } | 170 | } |
@@ -173,7 +175,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, | |||
173 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || | 175 | reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || |
174 | reg == AC97_VENDOR_ID2) { | 176 | reg == AC97_VENDOR_ID2) { |
175 | 177 | ||
176 | val = soc_ac97_ops->read(codec->ac97, reg); | 178 | val = soc_ac97_ops->read(ac97, reg); |
177 | return val; | 179 | return val; |
178 | } | 180 | } |
179 | return cache[reg / 2]; | 181 | return cache[reg / 2]; |
@@ -240,45 +242,41 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, | |||
240 | 242 | ||
241 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) | 243 | static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) |
242 | { | 244 | { |
245 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
246 | |||
243 | if (try_warm && soc_ac97_ops->warm_reset) { | 247 | if (try_warm && soc_ac97_ops->warm_reset) { |
244 | soc_ac97_ops->warm_reset(codec->ac97); | 248 | soc_ac97_ops->warm_reset(ac97); |
245 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) | 249 | if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) |
246 | return 1; | 250 | return 1; |
247 | } | 251 | } |
248 | 252 | ||
249 | soc_ac97_ops->reset(codec->ac97); | 253 | soc_ac97_ops->reset(ac97); |
250 | if (soc_ac97_ops->warm_reset) | 254 | if (soc_ac97_ops->warm_reset) |
251 | soc_ac97_ops->warm_reset(codec->ac97); | 255 | soc_ac97_ops->warm_reset(ac97); |
252 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) | 256 | if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) |
253 | return -EIO; | 257 | return -EIO; |
254 | return 0; | 258 | return 0; |
255 | } | 259 | } |
256 | 260 | ||
257 | static int stac9766_codec_suspend(struct snd_soc_codec *codec) | ||
258 | { | ||
259 | stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static int stac9766_codec_resume(struct snd_soc_codec *codec) | 261 | static int stac9766_codec_resume(struct snd_soc_codec *codec) |
264 | { | 262 | { |
263 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
265 | u16 id, reset; | 264 | u16 id, reset; |
266 | 265 | ||
267 | reset = 0; | 266 | reset = 0; |
268 | /* give the codec an AC97 warm reset to start the link */ | 267 | /* give the codec an AC97 warm reset to start the link */ |
269 | reset: | 268 | reset: |
270 | if (reset > 5) { | 269 | if (reset > 5) { |
271 | printk(KERN_ERR "stac9766 failed to resume"); | 270 | dev_err(codec->dev, "Failed to resume\n"); |
272 | return -EIO; | 271 | return -EIO; |
273 | } | 272 | } |
274 | codec->ac97->bus->ops->warm_reset(codec->ac97); | 273 | ac97->bus->ops->warm_reset(ac97); |
275 | id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2); | 274 | id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2); |
276 | if (id != 0x4c13) { | 275 | if (id != 0x4c13) { |
277 | stac9766_reset(codec, 0); | 276 | stac9766_reset(codec, 0); |
278 | reset++; | 277 | reset++; |
279 | goto reset; | 278 | goto reset; |
280 | } | 279 | } |
281 | stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
282 | 280 | ||
283 | return 0; | 281 | return 0; |
284 | } | 282 | } |
@@ -294,7 +292,6 @@ static const struct snd_soc_dai_ops stac9766_dai_ops_digital = { | |||
294 | static struct snd_soc_dai_driver stac9766_dai[] = { | 292 | static struct snd_soc_dai_driver stac9766_dai[] = { |
295 | { | 293 | { |
296 | .name = "stac9766-hifi-analog", | 294 | .name = "stac9766-hifi-analog", |
297 | .ac97_control = 1, | ||
298 | 295 | ||
299 | /* stream cababilities */ | 296 | /* stream cababilities */ |
300 | .playback = { | 297 | .playback = { |
@@ -316,7 +313,6 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
316 | }, | 313 | }, |
317 | { | 314 | { |
318 | .name = "stac9766-hifi-IEC958", | 315 | .name = "stac9766-hifi-IEC958", |
319 | .ac97_control = 1, | ||
320 | 316 | ||
321 | /* stream cababilities */ | 317 | /* stream cababilities */ |
322 | .playback = { | 318 | .playback = { |
@@ -334,46 +330,48 @@ static struct snd_soc_dai_driver stac9766_dai[] = { | |||
334 | 330 | ||
335 | static int stac9766_codec_probe(struct snd_soc_codec *codec) | 331 | static int stac9766_codec_probe(struct snd_soc_codec *codec) |
336 | { | 332 | { |
333 | struct snd_ac97 *ac97; | ||
337 | int ret = 0; | 334 | int ret = 0; |
338 | 335 | ||
339 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 336 | ac97 = snd_soc_new_ac97_codec(codec); |
340 | if (ret < 0) | 337 | if (IS_ERR(ac97)) |
341 | goto codec_err; | 338 | return PTR_ERR(ac97); |
339 | |||
340 | snd_soc_codec_set_drvdata(codec, ac97); | ||
342 | 341 | ||
343 | /* do a cold reset for the controller and then try | 342 | /* do a cold reset for the controller and then try |
344 | * a warm reset followed by an optional cold reset for codec */ | 343 | * a warm reset followed by an optional cold reset for codec */ |
345 | stac9766_reset(codec, 0); | 344 | stac9766_reset(codec, 0); |
346 | ret = stac9766_reset(codec, 1); | 345 | ret = stac9766_reset(codec, 1); |
347 | if (ret < 0) { | 346 | if (ret < 0) { |
348 | printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n"); | 347 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
349 | goto codec_err; | 348 | goto codec_err; |
350 | } | 349 | } |
351 | 350 | ||
352 | stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
353 | |||
354 | snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls, | ||
355 | ARRAY_SIZE(stac9766_snd_ac97_controls)); | ||
356 | |||
357 | return 0; | 351 | return 0; |
358 | 352 | ||
359 | codec_err: | 353 | codec_err: |
360 | snd_soc_free_ac97_codec(codec); | 354 | snd_soc_free_ac97_codec(ac97); |
361 | return ret; | 355 | return ret; |
362 | } | 356 | } |
363 | 357 | ||
364 | static int stac9766_codec_remove(struct snd_soc_codec *codec) | 358 | static int stac9766_codec_remove(struct snd_soc_codec *codec) |
365 | { | 359 | { |
366 | snd_soc_free_ac97_codec(codec); | 360 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
361 | |||
362 | snd_soc_free_ac97_codec(ac97); | ||
367 | return 0; | 363 | return 0; |
368 | } | 364 | } |
369 | 365 | ||
370 | static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { | 366 | static struct snd_soc_codec_driver soc_codec_dev_stac9766 = { |
367 | .controls = stac9766_snd_ac97_controls, | ||
368 | .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls), | ||
371 | .write = stac9766_ac97_write, | 369 | .write = stac9766_ac97_write, |
372 | .read = stac9766_ac97_read, | 370 | .read = stac9766_ac97_read, |
373 | .set_bias_level = stac9766_set_bias_level, | 371 | .set_bias_level = stac9766_set_bias_level, |
372 | .suspend_bias_off = true, | ||
374 | .probe = stac9766_codec_probe, | 373 | .probe = stac9766_codec_probe, |
375 | .remove = stac9766_codec_remove, | 374 | .remove = stac9766_codec_remove, |
376 | .suspend = stac9766_codec_suspend, | ||
377 | .resume = stac9766_codec_resume, | 375 | .resume = stac9766_codec_resume, |
378 | .reg_cache_size = ARRAY_SIZE(stac9766_reg), | 376 | .reg_cache_size = ARRAY_SIZE(stac9766_reg), |
379 | .reg_word_size = sizeof(u16), | 377 | .reg_word_size = sizeof(u16), |
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index f039dc825971..b505212019e2 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c | |||
@@ -345,7 +345,6 @@ static const struct reg_default tas2552_init_regs[] = { | |||
345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) | 345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) |
346 | { | 346 | { |
347 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); | 347 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); |
348 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
349 | int ret; | 348 | int ret; |
350 | 349 | ||
351 | tas2552->codec = codec; | 350 | tas2552->codec = codec; |
@@ -390,11 +389,6 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) | |||
390 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | | 389 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | |
391 | TAS2552_APT_EN | TAS2552_LIM_EN); | 390 | TAS2552_APT_EN | TAS2552_LIM_EN); |
392 | 391 | ||
393 | snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, | ||
394 | ARRAY_SIZE(tas2552_dapm_widgets)); | ||
395 | snd_soc_dapm_add_routes(dapm, tas2552_audio_map, | ||
396 | ARRAY_SIZE(tas2552_audio_map)); | ||
397 | |||
398 | return 0; | 392 | return 0; |
399 | 393 | ||
400 | patch_fail: | 394 | patch_fail: |
@@ -462,6 +456,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { | |||
462 | .resume = tas2552_resume, | 456 | .resume = tas2552_resume, |
463 | .controls = tas2552_snd_controls, | 457 | .controls = tas2552_snd_controls, |
464 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), | 458 | .num_controls = ARRAY_SIZE(tas2552_snd_controls), |
459 | .dapm_widgets = tas2552_dapm_widgets, | ||
460 | .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets), | ||
461 | .dapm_routes = tas2552_audio_map, | ||
462 | .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map), | ||
465 | }; | 463 | }; |
466 | 464 | ||
467 | static const struct regmap_config tas2552_regmap_config = { | 465 | static const struct regmap_config tas2552_regmap_config = { |
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c new file mode 100644 index 000000000000..16f1b71edb55 --- /dev/null +++ b/sound/soc/codecs/tfa9879.c | |||
@@ -0,0 +1,328 @@ | |||
1 | /* | ||
2 | * tfa9879.c -- driver for NXP Semiconductors TFA9879 | ||
3 | * | ||
4 | * Copyright (C) 2014 Axentia Technologies AB | ||
5 | * Author: Peter Rosin <peda@axentia.se> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/regmap.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/tlv.h> | ||
20 | #include <sound/pcm_params.h> | ||
21 | |||
22 | #include "tfa9879.h" | ||
23 | |||
24 | struct tfa9879_priv { | ||
25 | struct regmap *regmap; | ||
26 | int lsb_justified; | ||
27 | }; | ||
28 | |||
29 | static int tfa9879_hw_params(struct snd_pcm_substream *substream, | ||
30 | struct snd_pcm_hw_params *params, | ||
31 | struct snd_soc_dai *dai) | ||
32 | { | ||
33 | struct snd_soc_codec *codec = dai->codec; | ||
34 | struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); | ||
35 | int fs; | ||
36 | int i2s_set = 0; | ||
37 | |||
38 | switch (params_rate(params)) { | ||
39 | case 8000: | ||
40 | fs = TFA9879_I2S_FS_8000; | ||
41 | break; | ||
42 | case 11025: | ||
43 | fs = TFA9879_I2S_FS_11025; | ||
44 | break; | ||
45 | case 12000: | ||
46 | fs = TFA9879_I2S_FS_12000; | ||
47 | break; | ||
48 | case 16000: | ||
49 | fs = TFA9879_I2S_FS_16000; | ||
50 | break; | ||
51 | case 22050: | ||
52 | fs = TFA9879_I2S_FS_22050; | ||
53 | break; | ||
54 | case 24000: | ||
55 | fs = TFA9879_I2S_FS_24000; | ||
56 | break; | ||
57 | case 32000: | ||
58 | fs = TFA9879_I2S_FS_32000; | ||
59 | break; | ||
60 | case 44100: | ||
61 | fs = TFA9879_I2S_FS_44100; | ||
62 | break; | ||
63 | case 48000: | ||
64 | fs = TFA9879_I2S_FS_48000; | ||
65 | break; | ||
66 | case 64000: | ||
67 | fs = TFA9879_I2S_FS_64000; | ||
68 | break; | ||
69 | case 88200: | ||
70 | fs = TFA9879_I2S_FS_88200; | ||
71 | break; | ||
72 | case 96000: | ||
73 | fs = TFA9879_I2S_FS_96000; | ||
74 | break; | ||
75 | default: | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | |||
79 | switch (params_width(params)) { | ||
80 | case 16: | ||
81 | i2s_set = TFA9879_I2S_SET_LSB_J_16; | ||
82 | break; | ||
83 | case 24: | ||
84 | i2s_set = TFA9879_I2S_SET_LSB_J_24; | ||
85 | break; | ||
86 | default: | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | |||
90 | if (tfa9879->lsb_justified) | ||
91 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
92 | TFA9879_I2S_SET_MASK, | ||
93 | i2s_set << TFA9879_I2S_SET_SHIFT); | ||
94 | |||
95 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
96 | TFA9879_I2S_FS_MASK, | ||
97 | fs << TFA9879_I2S_FS_SHIFT); | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute) | ||
102 | { | ||
103 | struct snd_soc_codec *codec = dai->codec; | ||
104 | |||
105 | snd_soc_update_bits(codec, TFA9879_MISC_CONTROL, | ||
106 | TFA9879_S_MUTE_MASK, | ||
107 | !!mute << TFA9879_S_MUTE_SHIFT); | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
113 | { | ||
114 | struct snd_soc_codec *codec = dai->codec; | ||
115 | struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec); | ||
116 | int i2s_set; | ||
117 | int sck_pol; | ||
118 | |||
119 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
120 | case SND_SOC_DAIFMT_CBS_CFS: | ||
121 | break; | ||
122 | default: | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
127 | case SND_SOC_DAIFMT_NB_NF: | ||
128 | sck_pol = TFA9879_SCK_POL_NORMAL; | ||
129 | break; | ||
130 | case SND_SOC_DAIFMT_IB_NF: | ||
131 | sck_pol = TFA9879_SCK_POL_INVERSE; | ||
132 | break; | ||
133 | default: | ||
134 | return -EINVAL; | ||
135 | } | ||
136 | |||
137 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
138 | case SND_SOC_DAIFMT_I2S: | ||
139 | tfa9879->lsb_justified = 0; | ||
140 | i2s_set = TFA9879_I2S_SET_I2S_24; | ||
141 | break; | ||
142 | case SND_SOC_DAIFMT_LEFT_J: | ||
143 | tfa9879->lsb_justified = 0; | ||
144 | i2s_set = TFA9879_I2S_SET_MSB_J_24; | ||
145 | break; | ||
146 | case SND_SOC_DAIFMT_RIGHT_J: | ||
147 | tfa9879->lsb_justified = 1; | ||
148 | i2s_set = TFA9879_I2S_SET_LSB_J_24; | ||
149 | break; | ||
150 | default: | ||
151 | return -EINVAL; | ||
152 | } | ||
153 | |||
154 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
155 | TFA9879_SCK_POL_MASK, | ||
156 | sck_pol << TFA9879_SCK_POL_SHIFT); | ||
157 | snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1, | ||
158 | TFA9879_I2S_SET_MASK, | ||
159 | i2s_set << TFA9879_I2S_SET_SHIFT); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static struct reg_default tfa9879_regs[] = { | ||
164 | { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */ | ||
165 | { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */ | ||
166 | { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */ | ||
167 | { TFA9879_SERIAL_INTERFACE_2, 0x0a18 }, /* 0x03 */ | ||
168 | { TFA9879_PCM_IOM2_FORMAT_2, 0x0007 }, /* 0x04 */ | ||
169 | { TFA9879_EQUALIZER_A1, 0x59dd }, /* 0x05 */ | ||
170 | { TFA9879_EQUALIZER_A2, 0xc63e }, /* 0x06 */ | ||
171 | { TFA9879_EQUALIZER_B1, 0x651a }, /* 0x07 */ | ||
172 | { TFA9879_EQUALIZER_B2, 0xe53e }, /* 0x08 */ | ||
173 | { TFA9879_EQUALIZER_C1, 0x4616 }, /* 0x09 */ | ||
174 | { TFA9879_EQUALIZER_C2, 0xd33e }, /* 0x0a */ | ||
175 | { TFA9879_EQUALIZER_D1, 0x4df3 }, /* 0x0b */ | ||
176 | { TFA9879_EQUALIZER_D2, 0xea3e }, /* 0x0c */ | ||
177 | { TFA9879_EQUALIZER_E1, 0x5ee0 }, /* 0x0d */ | ||
178 | { TFA9879_EQUALIZER_E2, 0xf93e }, /* 0x0e */ | ||
179 | { TFA9879_BYPASS_CONTROL, 0x0093 }, /* 0x0f */ | ||
180 | { TFA9879_DYNAMIC_RANGE_COMPR, 0x92ba }, /* 0x10 */ | ||
181 | { TFA9879_BASS_TREBLE, 0x12a5 }, /* 0x11 */ | ||
182 | { TFA9879_HIGH_PASS_FILTER, 0x0004 }, /* 0x12 */ | ||
183 | { TFA9879_VOLUME_CONTROL, 0x10bd }, /* 0x13 */ | ||
184 | { TFA9879_MISC_CONTROL, 0x0000 }, /* 0x14 */ | ||
185 | }; | ||
186 | |||
187 | static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg) | ||
188 | { | ||
189 | return reg == TFA9879_MISC_STATUS; | ||
190 | } | ||
191 | |||
192 | static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1); | ||
193 | static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0); | ||
194 | static const char * const tb_freq_text[] = { | ||
195 | "Low", "Mid", "High" | ||
196 | }; | ||
197 | static const struct soc_enum treble_freq_enum = | ||
198 | SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT, | ||
199 | ARRAY_SIZE(tb_freq_text), tb_freq_text); | ||
200 | static const struct soc_enum bass_freq_enum = | ||
201 | SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT, | ||
202 | ARRAY_SIZE(tb_freq_text), tb_freq_text); | ||
203 | |||
204 | static const struct snd_kcontrol_new tfa9879_controls[] = { | ||
205 | SOC_SINGLE_TLV("PCM Playback Volume", TFA9879_VOLUME_CONTROL, | ||
206 | TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv), | ||
207 | SOC_SINGLE_TLV("Treble Volume", TFA9879_BASS_TREBLE, | ||
208 | TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv), | ||
209 | SOC_SINGLE_TLV("Bass Volume", TFA9879_BASS_TREBLE, | ||
210 | TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv), | ||
211 | SOC_ENUM("Treble Corner Freq", treble_freq_enum), | ||
212 | SOC_ENUM("Bass Corner Freq", bass_freq_enum), | ||
213 | }; | ||
214 | |||
215 | static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = { | ||
216 | SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
217 | SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), | ||
218 | SND_SOC_DAPM_DAC("DAC", NULL, TFA9879_DEVICE_CONTROL, TFA9879_OPMODE_SHIFT, 0), | ||
219 | SND_SOC_DAPM_OUTPUT("LINEOUT"), | ||
220 | SND_SOC_DAPM_SUPPLY("POWER", TFA9879_DEVICE_CONTROL, TFA9879_POWERUP_SHIFT, 0, | ||
221 | NULL, 0), | ||
222 | }; | ||
223 | |||
224 | static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = { | ||
225 | { "DAC", NULL, "AIFINL" }, | ||
226 | { "DAC", NULL, "AIFINR" }, | ||
227 | |||
228 | { "LINEOUT", NULL, "DAC" }, | ||
229 | |||
230 | { "DAC", NULL, "POWER" }, | ||
231 | }; | ||
232 | |||
233 | static const struct snd_soc_codec_driver tfa9879_codec = { | ||
234 | .controls = tfa9879_controls, | ||
235 | .num_controls = ARRAY_SIZE(tfa9879_controls), | ||
236 | |||
237 | .dapm_widgets = tfa9879_dapm_widgets, | ||
238 | .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets), | ||
239 | .dapm_routes = tfa9879_dapm_routes, | ||
240 | .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes), | ||
241 | }; | ||
242 | |||
243 | static const struct regmap_config tfa9879_regmap = { | ||
244 | .reg_bits = 8, | ||
245 | .val_bits = 16, | ||
246 | |||
247 | .volatile_reg = tfa9879_volatile_reg, | ||
248 | .max_register = TFA9879_MISC_STATUS, | ||
249 | .reg_defaults = tfa9879_regs, | ||
250 | .num_reg_defaults = ARRAY_SIZE(tfa9879_regs), | ||
251 | .cache_type = REGCACHE_RBTREE, | ||
252 | }; | ||
253 | |||
254 | static const struct snd_soc_dai_ops tfa9879_dai_ops = { | ||
255 | .hw_params = tfa9879_hw_params, | ||
256 | .digital_mute = tfa9879_digital_mute, | ||
257 | .set_fmt = tfa9879_set_fmt, | ||
258 | }; | ||
259 | |||
260 | #define TFA9879_RATES SNDRV_PCM_RATE_8000_96000 | ||
261 | |||
262 | #define TFA9879_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
263 | SNDRV_PCM_FMTBIT_S24_LE) | ||
264 | |||
265 | static struct snd_soc_dai_driver tfa9879_dai = { | ||
266 | .name = "tfa9879-hifi", | ||
267 | .playback = { | ||
268 | .stream_name = "Playback", | ||
269 | .channels_min = 2, | ||
270 | .channels_max = 2, | ||
271 | .rates = TFA9879_RATES, | ||
272 | .formats = TFA9879_FORMATS, }, | ||
273 | .ops = &tfa9879_dai_ops, | ||
274 | }; | ||
275 | |||
276 | static int tfa9879_i2c_probe(struct i2c_client *i2c, | ||
277 | const struct i2c_device_id *id) | ||
278 | { | ||
279 | struct tfa9879_priv *tfa9879; | ||
280 | int i; | ||
281 | |||
282 | tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL); | ||
283 | if (IS_ERR(tfa9879)) | ||
284 | return PTR_ERR(tfa9879); | ||
285 | |||
286 | i2c_set_clientdata(i2c, tfa9879); | ||
287 | |||
288 | tfa9879->regmap = devm_regmap_init_i2c(i2c, &tfa9879_regmap); | ||
289 | if (IS_ERR(tfa9879->regmap)) | ||
290 | return PTR_ERR(tfa9879->regmap); | ||
291 | |||
292 | /* Ensure the device is in reset state */ | ||
293 | for (i = 0; i < ARRAY_SIZE(tfa9879_regs); i++) | ||
294 | regmap_write(tfa9879->regmap, | ||
295 | tfa9879_regs[i].reg, tfa9879_regs[i].def); | ||
296 | |||
297 | return snd_soc_register_codec(&i2c->dev, &tfa9879_codec, | ||
298 | &tfa9879_dai, 1); | ||
299 | } | ||
300 | |||
301 | static int tfa9879_i2c_remove(struct i2c_client *client) | ||
302 | { | ||
303 | snd_soc_unregister_codec(&client->dev); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static const struct i2c_device_id tfa9879_i2c_id[] = { | ||
309 | { "tfa9879", 0 }, | ||
310 | { } | ||
311 | }; | ||
312 | MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id); | ||
313 | |||
314 | static struct i2c_driver tfa9879_i2c_driver = { | ||
315 | .driver = { | ||
316 | .name = "tfa9879", | ||
317 | .owner = THIS_MODULE, | ||
318 | }, | ||
319 | .probe = tfa9879_i2c_probe, | ||
320 | .remove = tfa9879_i2c_remove, | ||
321 | .id_table = tfa9879_i2c_id, | ||
322 | }; | ||
323 | |||
324 | module_i2c_driver(tfa9879_i2c_driver); | ||
325 | |||
326 | MODULE_DESCRIPTION("ASoC NXP Semiconductors TFA9879 driver"); | ||
327 | MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); | ||
328 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h new file mode 100644 index 000000000000..3408c90c4628 --- /dev/null +++ b/sound/soc/codecs/tfa9879.h | |||
@@ -0,0 +1,202 @@ | |||
1 | /* | ||
2 | * tfa9879.h -- driver for NXP Semiconductors TFA9879 | ||
3 | * | ||
4 | * Copyright (C) 2014 Axentia Technologies AB | ||
5 | * Author: Peter Rosin <peda@axentia.se> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _TFA9879_H | ||
15 | #define _TFA9879_H | ||
16 | |||
17 | #define TFA9879_DEVICE_CONTROL 0x00 | ||
18 | #define TFA9879_SERIAL_INTERFACE_1 0x01 | ||
19 | #define TFA9879_PCM_IOM2_FORMAT_1 0x02 | ||
20 | #define TFA9879_SERIAL_INTERFACE_2 0x03 | ||
21 | #define TFA9879_PCM_IOM2_FORMAT_2 0x04 | ||
22 | #define TFA9879_EQUALIZER_A1 0x05 | ||
23 | #define TFA9879_EQUALIZER_A2 0x06 | ||
24 | #define TFA9879_EQUALIZER_B1 0x07 | ||
25 | #define TFA9879_EQUALIZER_B2 0x08 | ||
26 | #define TFA9879_EQUALIZER_C1 0x09 | ||
27 | #define TFA9879_EQUALIZER_C2 0x0a | ||
28 | #define TFA9879_EQUALIZER_D1 0x0b | ||
29 | #define TFA9879_EQUALIZER_D2 0x0c | ||
30 | #define TFA9879_EQUALIZER_E1 0x0d | ||
31 | #define TFA9879_EQUALIZER_E2 0x0e | ||
32 | #define TFA9879_BYPASS_CONTROL 0x0f | ||
33 | #define TFA9879_DYNAMIC_RANGE_COMPR 0x10 | ||
34 | #define TFA9879_BASS_TREBLE 0x11 | ||
35 | #define TFA9879_HIGH_PASS_FILTER 0x12 | ||
36 | #define TFA9879_VOLUME_CONTROL 0x13 | ||
37 | #define TFA9879_MISC_CONTROL 0x14 | ||
38 | #define TFA9879_MISC_STATUS 0x15 | ||
39 | |||
40 | /* TFA9879_DEVICE_CONTROL */ | ||
41 | #define TFA9879_INPUT_SEL_MASK 0x0010 | ||
42 | #define TFA9879_INPUT_SEL_SHIFT 4 | ||
43 | #define TFA9879_OPMODE_MASK 0x0008 | ||
44 | #define TFA9879_OPMODE_SHIFT 3 | ||
45 | #define TFA9879_RESET_MASK 0x0002 | ||
46 | #define TFA9879_RESET_SHIFT 1 | ||
47 | #define TFA9879_POWERUP_MASK 0x0001 | ||
48 | #define TFA9879_POWERUP_SHIFT 0 | ||
49 | |||
50 | /* TFA9879_SERIAL_INTERFACE */ | ||
51 | #define TFA9879_MONO_SEL_MASK 0x0c00 | ||
52 | #define TFA9879_MONO_SEL_SHIFT 10 | ||
53 | #define TFA9879_MONO_SEL_LEFT 0 | ||
54 | #define TFA9879_MONO_SEL_RIGHT 1 | ||
55 | #define TFA9879_MONO_SEL_BOTH 2 | ||
56 | #define TFA9879_I2S_FS_MASK 0x03c0 | ||
57 | #define TFA9879_I2S_FS_SHIFT 6 | ||
58 | #define TFA9879_I2S_FS_8000 0 | ||
59 | #define TFA9879_I2S_FS_11025 1 | ||
60 | #define TFA9879_I2S_FS_12000 2 | ||
61 | #define TFA9879_I2S_FS_16000 3 | ||
62 | #define TFA9879_I2S_FS_22050 4 | ||
63 | #define TFA9879_I2S_FS_24000 5 | ||
64 | #define TFA9879_I2S_FS_32000 6 | ||
65 | #define TFA9879_I2S_FS_44100 7 | ||
66 | #define TFA9879_I2S_FS_48000 8 | ||
67 | #define TFA9879_I2S_FS_64000 9 | ||
68 | #define TFA9879_I2S_FS_88200 10 | ||
69 | #define TFA9879_I2S_FS_96000 11 | ||
70 | #define TFA9879_I2S_SET_MASK 0x0038 | ||
71 | #define TFA9879_I2S_SET_SHIFT 3 | ||
72 | #define TFA9879_I2S_SET_MSB_J_24 2 | ||
73 | #define TFA9879_I2S_SET_I2S_24 3 | ||
74 | #define TFA9879_I2S_SET_LSB_J_16 4 | ||
75 | #define TFA9879_I2S_SET_LSB_J_18 5 | ||
76 | #define TFA9879_I2S_SET_LSB_J_20 6 | ||
77 | #define TFA9879_I2S_SET_LSB_J_24 7 | ||
78 | #define TFA9879_SCK_POL_MASK 0x0004 | ||
79 | #define TFA9879_SCK_POL_SHIFT 2 | ||
80 | #define TFA9879_SCK_POL_NORMAL 0 | ||
81 | #define TFA9879_SCK_POL_INVERSE 1 | ||
82 | #define TFA9879_I_MODE_MASK 0x0003 | ||
83 | #define TFA9879_I_MODE_SHIFT 0 | ||
84 | #define TFA9879_I_MODE_I2S 0 | ||
85 | #define TFA9879_I_MODE_PCM_IOM2_SHORT 1 | ||
86 | #define TFA9879_I_MODE_PCM_IOM2_LONG 2 | ||
87 | |||
88 | /* TFA9879_PCM_IOM2_FORMAT */ | ||
89 | #define TFA9879_PCM_FS_MASK 0x0800 | ||
90 | #define TFA9879_PCM_FS_SHIFT 11 | ||
91 | #define TFA9879_A_LAW_MASK 0x0400 | ||
92 | #define TFA9879_A_LAW_SHIFT 10 | ||
93 | #define TFA9879_PCM_COMP_MASK 0x0200 | ||
94 | #define TFA9879_PCM_COMP_SHIFT 9 | ||
95 | #define TFA9879_PCM_DL_MASK 0x0100 | ||
96 | #define TFA9879_PCM_DL_SHIFT 8 | ||
97 | #define TFA9879_D1_SLOT_MASK 0x00f0 | ||
98 | #define TFA9879_D1_SLOT_SHIFT 4 | ||
99 | #define TFA9879_D2_SLOT_MASK 0x000f | ||
100 | #define TFA9879_D2_SLOT_SHIFT 0 | ||
101 | |||
102 | /* TFA9879_EQUALIZER_X1 */ | ||
103 | #define TFA9879_T1_MASK 0x8000 | ||
104 | #define TFA9879_T1_SHIFT 15 | ||
105 | #define TFA9879_K1M_MASK 0x7ff0 | ||
106 | #define TFA9879_K1M_SHIFT 4 | ||
107 | #define TFA9879_K1E_MASK 0x000f | ||
108 | #define TFA9879_K1E_SHIFT 0 | ||
109 | |||
110 | /* TFA9879_EQUALIZER_X2 */ | ||
111 | #define TFA9879_T2_MASK 0x8000 | ||
112 | #define TFA9879_T2_SHIFT 15 | ||
113 | #define TFA9879_K2M_MASK 0x7800 | ||
114 | #define TFA9879_K2M_SHIFT 11 | ||
115 | #define TFA9879_K2E_MASK 0x0700 | ||
116 | #define TFA9879_K2E_SHIFT 8 | ||
117 | #define TFA9879_K0_MASK 0x00fe | ||
118 | #define TFA9879_K0_SHIFT 1 | ||
119 | #define TFA9879_S_MASK 0x0001 | ||
120 | #define TFA9879_S_SHIFT 0 | ||
121 | |||
122 | /* TFA9879_BYPASS_CONTROL */ | ||
123 | #define TFA9879_L_OCP_MASK 0x00c0 | ||
124 | #define TFA9879_L_OCP_SHIFT 6 | ||
125 | #define TFA9879_L_OTP_MASK 0x0030 | ||
126 | #define TFA9879_L_OTP_SHIFT 4 | ||
127 | #define TFA9879_CLIPCTRL_MASK 0x0008 | ||
128 | #define TFA9879_CLIPCTRL_SHIFT 3 | ||
129 | #define TFA9879_HPF_BP_MASK 0x0004 | ||
130 | #define TFA9879_HPF_BP_SHIFT 2 | ||
131 | #define TFA9879_DRC_BP_MASK 0x0002 | ||
132 | #define TFA9879_DRC_BP_SHIFT 1 | ||
133 | #define TFA9879_EQ_BP_MASK 0x0001 | ||
134 | #define TFA9879_EQ_BP_SHIFT 0 | ||
135 | |||
136 | /* TFA9879_DYNAMIC_RANGE_COMPR */ | ||
137 | #define TFA9879_AT_LVL_MASK 0xf000 | ||
138 | #define TFA9879_AT_LVL_SHIFT 12 | ||
139 | #define TFA9879_AT_RATE_MASK 0x0f00 | ||
140 | #define TFA9879_AT_RATE_SHIFT 8 | ||
141 | #define TFA9879_RL_LVL_MASK 0x00f0 | ||
142 | #define TFA9879_RL_LVL_SHIFT 4 | ||
143 | #define TFA9879_RL_RATE_MASK 0x000f | ||
144 | #define TFA9879_RL_RATE_SHIFT 0 | ||
145 | |||
146 | /* TFA9879_BASS_TREBLE */ | ||
147 | #define TFA9879_G_TRBLE_MASK 0x3e00 | ||
148 | #define TFA9879_G_TRBLE_SHIFT 9 | ||
149 | #define TFA9879_F_TRBLE_MASK 0x0180 | ||
150 | #define TFA9879_F_TRBLE_SHIFT 7 | ||
151 | #define TFA9879_G_BASS_MASK 0x007c | ||
152 | #define TFA9879_G_BASS_SHIFT 2 | ||
153 | #define TFA9879_F_BASS_MASK 0x0003 | ||
154 | #define TFA9879_F_BASS_SHIFT 0 | ||
155 | |||
156 | /* TFA9879_HIGH_PASS_FILTER */ | ||
157 | #define TFA9879_HP_CTRL_MASK 0x00ff | ||
158 | #define TFA9879_HP_CTRL_SHIFT 0 | ||
159 | |||
160 | /* TFA9879_VOLUME_CONTROL */ | ||
161 | #define TFA9879_ZR_CRSS_MASK 0x1000 | ||
162 | #define TFA9879_ZR_CRSS_SHIFT 12 | ||
163 | #define TFA9879_VOL_MASK 0x00ff | ||
164 | #define TFA9879_VOL_SHIFT 0 | ||
165 | |||
166 | /* TFA9879_MISC_CONTROL */ | ||
167 | #define TFA9879_DE_PHAS_MASK 0x0c00 | ||
168 | #define TFA9879_DE_PHAS_SHIFT 10 | ||
169 | #define TFA9879_H_MUTE_MASK 0x0200 | ||
170 | #define TFA9879_H_MUTE_SHIFT 9 | ||
171 | #define TFA9879_S_MUTE_MASK 0x0100 | ||
172 | #define TFA9879_S_MUTE_SHIFT 8 | ||
173 | #define TFA9879_P_LIM_MASK 0x00ff | ||
174 | #define TFA9879_P_LIM_SHIFT 0 | ||
175 | |||
176 | /* TFA9879_MISC_STATUS */ | ||
177 | #define TFA9879_PS_MASK 0x4000 | ||
178 | #define TFA9879_PS_SHIFT 14 | ||
179 | #define TFA9879_PORA_MASK 0x2000 | ||
180 | #define TFA9879_PORA_SHIFT 13 | ||
181 | #define TFA9879_AMP_MASK 0x0600 | ||
182 | #define TFA9879_AMP_SHIFT 9 | ||
183 | #define TFA9879_IBP_2_MASK 0x0100 | ||
184 | #define TFA9879_IBP_2_SHIFT 8 | ||
185 | #define TFA9879_OFP_2_MASK 0x0080 | ||
186 | #define TFA9879_OFP_2_SHIFT 7 | ||
187 | #define TFA9879_UFP_2_MASK 0x0040 | ||
188 | #define TFA9879_UFP_2_SHIFT 6 | ||
189 | #define TFA9879_IBP_1_MASK 0x0020 | ||
190 | #define TFA9879_IBP_1_SHIFT 5 | ||
191 | #define TFA9879_OFP_1_MASK 0x0010 | ||
192 | #define TFA9879_OFP_1_SHIFT 4 | ||
193 | #define TFA9879_UFP_1_MASK 0x0008 | ||
194 | #define TFA9879_UFP_1_SHIFT 3 | ||
195 | #define TFA9879_OCPOKA_MASK 0x0004 | ||
196 | #define TFA9879_OCPOKA_SHIFT 2 | ||
197 | #define TFA9879_OCPOKB_MASK 0x0002 | ||
198 | #define TFA9879_OCPOKB_SHIFT 1 | ||
199 | #define TFA9879_OTPOK_MASK 0x0001 | ||
200 | #define TFA9879_OTPOK_SHIFT 0 | ||
201 | |||
202 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index d67167920c2f..cc17e7e5126e 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -540,19 +540,11 @@ static struct snd_soc_dai_driver tlv320aic23_dai = { | |||
540 | .ops = &tlv320aic23_dai_ops, | 540 | .ops = &tlv320aic23_dai_ops, |
541 | }; | 541 | }; |
542 | 542 | ||
543 | static int tlv320aic23_suspend(struct snd_soc_codec *codec) | ||
544 | { | ||
545 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int tlv320aic23_resume(struct snd_soc_codec *codec) | 543 | static int tlv320aic23_resume(struct snd_soc_codec *codec) |
551 | { | 544 | { |
552 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | 545 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
553 | regcache_mark_dirty(aic23->regmap); | 546 | regcache_mark_dirty(aic23->regmap); |
554 | regcache_sync(aic23->regmap); | 547 | regcache_sync(aic23->regmap); |
555 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
556 | 548 | ||
557 | return 0; | 549 | return 0; |
558 | } | 550 | } |
@@ -562,9 +554,6 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) | |||
562 | /* Reset codec */ | 554 | /* Reset codec */ |
563 | snd_soc_write(codec, TLV320AIC23_RESET, 0); | 555 | snd_soc_write(codec, TLV320AIC23_RESET, 0); |
564 | 556 | ||
565 | /* power on device */ | ||
566 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
567 | |||
568 | snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); | 557 | snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); |
569 | 558 | ||
570 | /* Unmute input */ | 559 | /* Unmute input */ |
@@ -589,18 +578,12 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) | |||
589 | return 0; | 578 | return 0; |
590 | } | 579 | } |
591 | 580 | ||
592 | static int tlv320aic23_remove(struct snd_soc_codec *codec) | ||
593 | { | ||
594 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
595 | return 0; | ||
596 | } | ||
597 | |||
598 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | 581 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { |
599 | .probe = tlv320aic23_codec_probe, | 582 | .probe = tlv320aic23_codec_probe, |
600 | .remove = tlv320aic23_remove, | ||
601 | .suspend = tlv320aic23_suspend, | ||
602 | .resume = tlv320aic23_resume, | 583 | .resume = tlv320aic23_resume, |
603 | .set_bias_level = tlv320aic23_set_bias_level, | 584 | .set_bias_level = tlv320aic23_set_bias_level, |
585 | .suspend_bias_off = true, | ||
586 | |||
604 | .controls = tlv320aic23_snd_controls, | 587 | .controls = tlv320aic23_snd_controls, |
605 | .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), | 588 | .num_controls = ARRAY_SIZE(tlv320aic23_snd_controls), |
606 | .dapm_widgets = tlv320aic23_dapm_widgets, | 589 | .dapm_widgets = tlv320aic23_dapm_widgets, |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 145fe5b253d4..dc3223d6eca1 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -911,12 +911,13 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
911 | } | 911 | } |
912 | aic31xx->p_div = i; | 912 | aic31xx->p_div = i; |
913 | 913 | ||
914 | for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { | 914 | for (i = 0; i < ARRAY_SIZE(aic31xx_divs) && |
915 | if (i == ARRAY_SIZE(aic31xx_divs)) { | 915 | aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) |
916 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", | 916 | ; |
917 | __func__, freq); | 917 | if (i == ARRAY_SIZE(aic31xx_divs)) { |
918 | return -EINVAL; | 918 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", |
919 | } | 919 | __func__, freq); |
920 | return -EINVAL; | ||
920 | } | 921 | } |
921 | 922 | ||
922 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ | 923 | /* set clock on MCLK, BCLK, or GPIO1 as PLL input */ |
@@ -1056,18 +1057,6 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, | |||
1056 | return 0; | 1057 | return 0; |
1057 | } | 1058 | } |
1058 | 1059 | ||
1059 | static int aic31xx_suspend(struct snd_soc_codec *codec) | ||
1060 | { | ||
1061 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | static int aic31xx_resume(struct snd_soc_codec *codec) | ||
1066 | { | ||
1067 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int aic31xx_codec_probe(struct snd_soc_codec *codec) | 1060 | static int aic31xx_codec_probe(struct snd_soc_codec *codec) |
1072 | { | 1061 | { |
1073 | int ret = 0; | 1062 | int ret = 0; |
@@ -1110,8 +1099,6 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) | |||
1110 | { | 1099 | { |
1111 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); | 1100 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); |
1112 | int i; | 1101 | int i; |
1113 | /* power down chip */ | ||
1114 | aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1115 | 1102 | ||
1116 | for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) | 1103 | for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) |
1117 | regulator_unregister_notifier(aic31xx->supplies[i].consumer, | 1104 | regulator_unregister_notifier(aic31xx->supplies[i].consumer, |
@@ -1123,9 +1110,9 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec) | |||
1123 | static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { | 1110 | static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { |
1124 | .probe = aic31xx_codec_probe, | 1111 | .probe = aic31xx_codec_probe, |
1125 | .remove = aic31xx_codec_remove, | 1112 | .remove = aic31xx_codec_remove, |
1126 | .suspend = aic31xx_suspend, | ||
1127 | .resume = aic31xx_resume, | ||
1128 | .set_bias_level = aic31xx_set_bias_level, | 1113 | .set_bias_level = aic31xx_set_bias_level, |
1114 | .suspend_bias_off = true, | ||
1115 | |||
1129 | .controls = aic31xx_snd_controls, | 1116 | .controls = aic31xx_snd_controls, |
1130 | .num_controls = ARRAY_SIZE(aic31xx_snd_controls), | 1117 | .num_controls = ARRAY_SIZE(aic31xx_snd_controls), |
1131 | .dapm_widgets = aic31xx_dapm_widgets, | 1118 | .dapm_widgets = aic31xx_dapm_widgets, |
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 6ea662db2410..015467ed606b 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -597,18 +597,6 @@ static struct snd_soc_dai_driver aic32x4_dai = { | |||
597 | .symmetric_rates = 1, | 597 | .symmetric_rates = 1, |
598 | }; | 598 | }; |
599 | 599 | ||
600 | static int aic32x4_suspend(struct snd_soc_codec *codec) | ||
601 | { | ||
602 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
603 | return 0; | ||
604 | } | ||
605 | |||
606 | static int aic32x4_resume(struct snd_soc_codec *codec) | ||
607 | { | ||
608 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int aic32x4_probe(struct snd_soc_codec *codec) | 600 | static int aic32x4_probe(struct snd_soc_codec *codec) |
613 | { | 601 | { |
614 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | 602 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); |
@@ -654,8 +642,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
654 | snd_soc_write(codec, AIC32X4_RMICPGANIN, | 642 | snd_soc_write(codec, AIC32X4_RMICPGANIN, |
655 | AIC32X4_RMICPGANIN_CM1R_10K); | 643 | AIC32X4_RMICPGANIN_CM1R_10K); |
656 | 644 | ||
657 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
658 | |||
659 | /* | 645 | /* |
660 | * Workaround: for an unknown reason, the ADC needs to be powered up | 646 | * Workaround: for an unknown reason, the ADC needs to be powered up |
661 | * and down for the first capture to work properly. It seems related to | 647 | * and down for the first capture to work properly. It seems related to |
@@ -669,18 +655,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
669 | return 0; | 655 | return 0; |
670 | } | 656 | } |
671 | 657 | ||
672 | static int aic32x4_remove(struct snd_soc_codec *codec) | ||
673 | { | ||
674 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | 658 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { |
679 | .probe = aic32x4_probe, | 659 | .probe = aic32x4_probe, |
680 | .remove = aic32x4_remove, | ||
681 | .suspend = aic32x4_suspend, | ||
682 | .resume = aic32x4_resume, | ||
683 | .set_bias_level = aic32x4_set_bias_level, | 660 | .set_bias_level = aic32x4_set_bias_level, |
661 | .suspend_bias_off = true, | ||
684 | 662 | ||
685 | .controls = aic32x4_snd_controls, | 663 | .controls = aic32x4_snd_controls, |
686 | .num_controls = ARRAY_SIZE(aic32x4_snd_controls), | 664 | .num_controls = ARRAY_SIZE(aic32x4_snd_controls), |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index f7c2a575a892..b7ebce054b4e 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -78,6 +78,8 @@ struct aic3x_priv { | |||
78 | struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; | 78 | struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; |
79 | struct aic3x_setup_data *setup; | 79 | struct aic3x_setup_data *setup; |
80 | unsigned int sysclk; | 80 | unsigned int sysclk; |
81 | unsigned int dai_fmt; | ||
82 | unsigned int tdm_delay; | ||
81 | struct list_head list; | 83 | struct list_head list; |
82 | int master; | 84 | int master; |
83 | int gpio_reset; | 85 | int gpio_reset; |
@@ -214,61 +216,78 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, | |||
214 | return 0; | 216 | return 0; |
215 | } | 217 | } |
216 | 218 | ||
217 | static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" }; | 219 | static const char * const aic3x_left_dac_mux[] = { |
218 | static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" }; | 220 | "DAC_L1", "DAC_L3", "DAC_L2" }; |
219 | static const char *aic3x_left_hpcom_mux[] = | 221 | static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6, |
220 | { "differential of HPLOUT", "constant VCM", "single-ended" }; | 222 | aic3x_left_dac_mux); |
221 | static const char *aic3x_right_hpcom_mux[] = | 223 | |
222 | { "differential of HPROUT", "constant VCM", "single-ended", | 224 | static const char * const aic3x_right_dac_mux[] = { |
223 | "differential of HPLCOM", "external feedback" }; | 225 | "DAC_R1", "DAC_R3", "DAC_R2" }; |
224 | static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" }; | 226 | static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4, |
225 | static const char *aic3x_adc_hpf[] = | 227 | aic3x_right_dac_mux); |
226 | { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; | 228 | |
227 | 229 | static const char * const aic3x_left_hpcom_mux[] = { | |
228 | #define LDAC_ENUM 0 | 230 | "differential of HPLOUT", "constant VCM", "single-ended" }; |
229 | #define RDAC_ENUM 1 | 231 | static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4, |
230 | #define LHPCOM_ENUM 2 | 232 | aic3x_left_hpcom_mux); |
231 | #define RHPCOM_ENUM 3 | 233 | |
232 | #define LINE1L_2_L_ENUM 4 | 234 | static const char * const aic3x_right_hpcom_mux[] = { |
233 | #define LINE1L_2_R_ENUM 5 | 235 | "differential of HPROUT", "constant VCM", "single-ended", |
234 | #define LINE1R_2_L_ENUM 6 | 236 | "differential of HPLCOM", "external feedback" }; |
235 | #define LINE1R_2_R_ENUM 7 | 237 | static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3, |
236 | #define LINE2L_ENUM 8 | 238 | aic3x_right_hpcom_mux); |
237 | #define LINE2R_ENUM 9 | 239 | |
238 | #define ADC_HPF_ENUM 10 | 240 | static const char * const aic3x_linein_mode_mux[] = { |
239 | 241 | "single-ended", "differential" }; | |
240 | static const struct soc_enum aic3x_enum[] = { | 242 | static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7, |
241 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux), | 243 | aic3x_linein_mode_mux); |
242 | SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux), | 244 | static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7, |
243 | SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux), | 245 | aic3x_linein_mode_mux); |
244 | SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux), | 246 | static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7, |
245 | SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 247 | aic3x_linein_mode_mux); |
246 | SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 248 | static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7, |
247 | SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 249 | aic3x_linein_mode_mux); |
248 | SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 250 | static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7, |
249 | SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 251 | aic3x_linein_mode_mux); |
250 | SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux), | 252 | static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7, |
251 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | 253 | aic3x_linein_mode_mux); |
252 | }; | 254 | |
253 | 255 | static const char * const aic3x_adc_hpf[] = { | |
254 | static const char *aic3x_agc_level[] = | 256 | "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" }; |
255 | { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" }; | 257 | static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4, |
256 | static const struct soc_enum aic3x_agc_level_enum[] = { | 258 | aic3x_adc_hpf); |
257 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level), | 259 | |
258 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level), | 260 | static const char * const aic3x_agc_level[] = { |
259 | }; | 261 | "-5.5dB", "-8dB", "-10dB", "-12dB", |
260 | 262 | "-14dB", "-17dB", "-20dB", "-24dB" }; | |
261 | static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" }; | 263 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4, |
262 | static const struct soc_enum aic3x_agc_attack_enum[] = { | 264 | aic3x_agc_level); |
263 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack), | 265 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4, |
264 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack), | 266 | aic3x_agc_level); |
265 | }; | 267 | |
266 | 268 | static const char * const aic3x_agc_attack[] = { | |
267 | static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" }; | 269 | "8ms", "11ms", "16ms", "20ms" }; |
268 | static const struct soc_enum aic3x_agc_decay_enum[] = { | 270 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2, |
269 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay), | 271 | aic3x_agc_attack); |
270 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), | 272 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2, |
271 | }; | 273 | aic3x_agc_attack); |
274 | |||
275 | static const char * const aic3x_agc_decay[] = { | ||
276 | "100ms", "200ms", "400ms", "500ms" }; | ||
277 | static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0, | ||
278 | aic3x_agc_decay); | ||
279 | static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0, | ||
280 | aic3x_agc_decay); | ||
281 | |||
282 | static const char * const aic3x_poweron_time[] = { | ||
283 | "0us", "10us", "100us", "1ms", "10ms", "50ms", | ||
284 | "100ms", "200ms", "400ms", "800ms", "2s", "4s" }; | ||
285 | static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4, | ||
286 | aic3x_poweron_time); | ||
287 | |||
288 | static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" }; | ||
289 | static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2, | ||
290 | aic3x_rampup_step); | ||
272 | 291 | ||
273 | /* | 292 | /* |
274 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps | 293 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps |
@@ -383,12 +402,12 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
383 | * adjust PGA to max value when ADC is on and will never go back. | 402 | * adjust PGA to max value when ADC is on and will never go back. |
384 | */ | 403 | */ |
385 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | 404 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), |
386 | SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]), | 405 | SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum), |
387 | SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]), | 406 | SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum), |
388 | SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]), | 407 | SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum), |
389 | SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]), | 408 | SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum), |
390 | SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]), | 409 | SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum), |
391 | SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]), | 410 | SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum), |
392 | 411 | ||
393 | /* De-emphasis */ | 412 | /* De-emphasis */ |
394 | SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), | 413 | SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), |
@@ -398,7 +417,11 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
398 | 0, 119, 0, adc_tlv), | 417 | 0, 119, 0, adc_tlv), |
399 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), | 418 | SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1), |
400 | 419 | ||
401 | SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]), | 420 | SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum), |
421 | |||
422 | /* Pop reduction */ | ||
423 | SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum), | ||
424 | SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum), | ||
402 | }; | 425 | }; |
403 | 426 | ||
404 | static const struct snd_kcontrol_new aic3x_mono_controls[] = { | 427 | static const struct snd_kcontrol_new aic3x_mono_controls[] = { |
@@ -425,19 +448,19 @@ static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = | |||
425 | 448 | ||
426 | /* Left DAC Mux */ | 449 | /* Left DAC Mux */ |
427 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 450 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
428 | SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]); | 451 | SOC_DAPM_ENUM("Route", aic3x_left_dac_enum); |
429 | 452 | ||
430 | /* Right DAC Mux */ | 453 | /* Right DAC Mux */ |
431 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = | 454 | static const struct snd_kcontrol_new aic3x_right_dac_mux_controls = |
432 | SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]); | 455 | SOC_DAPM_ENUM("Route", aic3x_right_dac_enum); |
433 | 456 | ||
434 | /* Left HPCOM Mux */ | 457 | /* Left HPCOM Mux */ |
435 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = | 458 | static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls = |
436 | SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]); | 459 | SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum); |
437 | 460 | ||
438 | /* Right HPCOM Mux */ | 461 | /* Right HPCOM Mux */ |
439 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = | 462 | static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls = |
440 | SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]); | 463 | SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum); |
441 | 464 | ||
442 | /* Left Line Mixer */ | 465 | /* Left Line Mixer */ |
443 | static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { | 466 | static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = { |
@@ -529,23 +552,23 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = { | |||
529 | 552 | ||
530 | /* Left Line1 Mux */ | 553 | /* Left Line1 Mux */ |
531 | static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = | 554 | static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls = |
532 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]); | 555 | SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum); |
533 | static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = | 556 | static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls = |
534 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]); | 557 | SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum); |
535 | 558 | ||
536 | /* Right Line1 Mux */ | 559 | /* Right Line1 Mux */ |
537 | static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = | 560 | static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls = |
538 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]); | 561 | SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum); |
539 | static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = | 562 | static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls = |
540 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]); | 563 | SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum); |
541 | 564 | ||
542 | /* Left Line2 Mux */ | 565 | /* Left Line2 Mux */ |
543 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = | 566 | static const struct snd_kcontrol_new aic3x_left_line2_mux_controls = |
544 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]); | 567 | SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum); |
545 | 568 | ||
546 | /* Right Line2 Mux */ | 569 | /* Right Line2 Mux */ |
547 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = | 570 | static const struct snd_kcontrol_new aic3x_right_line2_mux_controls = |
548 | SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]); | 571 | SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum); |
549 | 572 | ||
550 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { | 573 | static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = { |
551 | /* Left DAC to Left Outputs */ | 574 | /* Left DAC to Left Outputs */ |
@@ -1009,6 +1032,25 @@ found: | |||
1009 | return 0; | 1032 | return 0; |
1010 | } | 1033 | } |
1011 | 1034 | ||
1035 | static int aic3x_prepare(struct snd_pcm_substream *substream, | ||
1036 | struct snd_soc_dai *dai) | ||
1037 | { | ||
1038 | struct snd_soc_codec *codec = dai->codec; | ||
1039 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1040 | int delay = 0; | ||
1041 | |||
1042 | /* TDM slot selection only valid in DSP_A/_B mode */ | ||
1043 | if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A) | ||
1044 | delay += (aic3x->tdm_delay + 1); | ||
1045 | else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B) | ||
1046 | delay += aic3x->tdm_delay; | ||
1047 | |||
1048 | /* Configure data delay */ | ||
1049 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay); | ||
1050 | |||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1012 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) | 1054 | static int aic3x_mute(struct snd_soc_dai *dai, int mute) |
1013 | { | 1055 | { |
1014 | struct snd_soc_codec *codec = dai->codec; | 1056 | struct snd_soc_codec *codec = dai->codec; |
@@ -1048,7 +1090,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1048 | struct snd_soc_codec *codec = codec_dai->codec; | 1090 | struct snd_soc_codec *codec = codec_dai->codec; |
1049 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1091 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1050 | u8 iface_areg, iface_breg; | 1092 | u8 iface_areg, iface_breg; |
1051 | int delay = 0; | ||
1052 | 1093 | ||
1053 | iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; | 1094 | iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f; |
1054 | iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; | 1095 | iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f; |
@@ -1076,7 +1117,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1076 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): | 1117 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): |
1077 | break; | 1118 | break; |
1078 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): | 1119 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF): |
1079 | delay = 1; | ||
1080 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): | 1120 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF): |
1081 | iface_breg |= (0x01 << 6); | 1121 | iface_breg |= (0x01 << 6); |
1082 | break; | 1122 | break; |
@@ -1090,10 +1130,45 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1090 | return -EINVAL; | 1130 | return -EINVAL; |
1091 | } | 1131 | } |
1092 | 1132 | ||
1133 | aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
1134 | |||
1093 | /* set iface */ | 1135 | /* set iface */ |
1094 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); | 1136 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg); |
1095 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); | 1137 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg); |
1096 | snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay); | 1138 | |
1139 | return 0; | ||
1140 | } | ||
1141 | |||
1142 | static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai, | ||
1143 | unsigned int tx_mask, unsigned int rx_mask, | ||
1144 | int slots, int slot_width) | ||
1145 | { | ||
1146 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1147 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | ||
1148 | unsigned int lsb; | ||
1149 | |||
1150 | if (tx_mask != rx_mask) { | ||
1151 | dev_err(codec->dev, "tx and rx masks must be symmetric\n"); | ||
1152 | return -EINVAL; | ||
1153 | } | ||
1154 | |||
1155 | if (unlikely(!tx_mask)) { | ||
1156 | dev_err(codec->dev, "tx and rx masks need to be non 0\n"); | ||
1157 | return -EINVAL; | ||
1158 | } | ||
1159 | |||
1160 | /* TDM based on DSP mode requires slots to be adjacent */ | ||
1161 | lsb = __ffs(tx_mask); | ||
1162 | if ((lsb + 1) != __fls(tx_mask)) { | ||
1163 | dev_err(codec->dev, "Invalid mask, slots must be adjacent\n"); | ||
1164 | return -EINVAL; | ||
1165 | } | ||
1166 | |||
1167 | aic3x->tdm_delay = lsb * slot_width; | ||
1168 | |||
1169 | /* DOUT in high-impedance on inactive bit clocks */ | ||
1170 | snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA, | ||
1171 | DOUT_TRISTATE, DOUT_TRISTATE); | ||
1097 | 1172 | ||
1098 | return 0; | 1173 | return 0; |
1099 | } | 1174 | } |
@@ -1212,9 +1287,11 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec, | |||
1212 | 1287 | ||
1213 | static const struct snd_soc_dai_ops aic3x_dai_ops = { | 1288 | static const struct snd_soc_dai_ops aic3x_dai_ops = { |
1214 | .hw_params = aic3x_hw_params, | 1289 | .hw_params = aic3x_hw_params, |
1290 | .prepare = aic3x_prepare, | ||
1215 | .digital_mute = aic3x_mute, | 1291 | .digital_mute = aic3x_mute, |
1216 | .set_sysclk = aic3x_set_dai_sysclk, | 1292 | .set_sysclk = aic3x_set_dai_sysclk, |
1217 | .set_fmt = aic3x_set_dai_fmt, | 1293 | .set_fmt = aic3x_set_dai_fmt, |
1294 | .set_tdm_slot = aic3x_set_dai_tdm_slot, | ||
1218 | }; | 1295 | }; |
1219 | 1296 | ||
1220 | static struct snd_soc_dai_driver aic3x_dai = { | 1297 | static struct snd_soc_dai_driver aic3x_dai = { |
@@ -1414,7 +1491,6 @@ static int aic3x_remove(struct snd_soc_codec *codec) | |||
1414 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1491 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
1415 | int i; | 1492 | int i; |
1416 | 1493 | ||
1417 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1418 | list_del(&aic3x->list); | 1494 | list_del(&aic3x->list); |
1419 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) | 1495 | for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++) |
1420 | regulator_unregister_notifier(aic3x->supplies[i].consumer, | 1496 | regulator_unregister_notifier(aic3x->supplies[i].consumer, |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index e521ac3ddde8..89fa692df206 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -169,6 +169,7 @@ | |||
169 | /* Audio serial data interface control register A bits */ | 169 | /* Audio serial data interface control register A bits */ |
170 | #define BIT_CLK_MASTER 0x80 | 170 | #define BIT_CLK_MASTER 0x80 |
171 | #define WORD_CLK_MASTER 0x40 | 171 | #define WORD_CLK_MASTER 0x40 |
172 | #define DOUT_TRISTATE 0x20 | ||
172 | 173 | ||
173 | /* Codec Datapath setup register 7 */ | 174 | /* Codec Datapath setup register 7 */ |
174 | #define FSREF_44100 (1 << 7) | 175 | #define FSREF_44100 (1 << 7) |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index e21ed934bdbf..0fe2ced5b09f 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -1436,8 +1436,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec) | |||
1436 | { | 1436 | { |
1437 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1437 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1438 | 1438 | ||
1439 | dac33_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1440 | |||
1441 | if (dac33->irq >= 0) { | 1439 | if (dac33->irq >= 0) { |
1442 | free_irq(dac33->irq, dac33->codec); | 1440 | free_irq(dac33->irq, dac33->codec); |
1443 | destroy_workqueue(dac33->dac33_wq); | 1441 | destroy_workqueue(dac33->dac33_wq); |
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c new file mode 100644 index 000000000000..1d1205702d23 --- /dev/null +++ b/sound/soc/codecs/ts3a227e.c | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/gpio.h> | ||
12 | #include <linux/i2c.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/input.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_gpio.h> | ||
17 | #include <linux/regmap.h> | ||
18 | |||
19 | #include <sound/core.h> | ||
20 | #include <sound/jack.h> | ||
21 | #include <sound/soc.h> | ||
22 | |||
23 | struct ts3a227e { | ||
24 | struct regmap *regmap; | ||
25 | struct snd_soc_jack *jack; | ||
26 | bool plugged; | ||
27 | bool mic_present; | ||
28 | unsigned int buttons_held; | ||
29 | }; | ||
30 | |||
31 | /* Button values to be reported on the jack */ | ||
32 | static const int ts3a227e_buttons[] = { | ||
33 | SND_JACK_BTN_0, | ||
34 | SND_JACK_BTN_1, | ||
35 | SND_JACK_BTN_2, | ||
36 | SND_JACK_BTN_3, | ||
37 | }; | ||
38 | |||
39 | #define TS3A227E_NUM_BUTTONS 4 | ||
40 | #define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \ | ||
41 | SND_JACK_MICROPHONE | \ | ||
42 | SND_JACK_BTN_0 | \ | ||
43 | SND_JACK_BTN_1 | \ | ||
44 | SND_JACK_BTN_2 | \ | ||
45 | SND_JACK_BTN_3) | ||
46 | |||
47 | /* TS3A227E registers */ | ||
48 | #define TS3A227E_REG_DEVICE_ID 0x00 | ||
49 | #define TS3A227E_REG_INTERRUPT 0x01 | ||
50 | #define TS3A227E_REG_KP_INTERRUPT 0x02 | ||
51 | #define TS3A227E_REG_INTERRUPT_DISABLE 0x03 | ||
52 | #define TS3A227E_REG_SETTING_1 0x04 | ||
53 | #define TS3A227E_REG_SETTING_2 0x05 | ||
54 | #define TS3A227E_REG_SETTING_3 0x06 | ||
55 | #define TS3A227E_REG_SWITCH_CONTROL_1 0x07 | ||
56 | #define TS3A227E_REG_SWITCH_CONTROL_2 0x08 | ||
57 | #define TS3A227E_REG_SWITCH_STATUS_1 0x09 | ||
58 | #define TS3A227E_REG_SWITCH_STATUS_2 0x0a | ||
59 | #define TS3A227E_REG_ACCESSORY_STATUS 0x0b | ||
60 | #define TS3A227E_REG_ADC_OUTPUT 0x0c | ||
61 | #define TS3A227E_REG_KP_THRESHOLD_1 0x0d | ||
62 | #define TS3A227E_REG_KP_THRESHOLD_2 0x0e | ||
63 | #define TS3A227E_REG_KP_THRESHOLD_3 0x0f | ||
64 | |||
65 | /* TS3A227E_REG_INTERRUPT 0x01 */ | ||
66 | #define INS_REM_EVENT 0x01 | ||
67 | #define DETECTION_COMPLETE_EVENT 0x02 | ||
68 | |||
69 | /* TS3A227E_REG_KP_INTERRUPT 0x02 */ | ||
70 | #define PRESS_MASK(idx) (0x01 << (2 * (idx))) | ||
71 | #define RELEASE_MASK(idx) (0x02 << (2 * (idx))) | ||
72 | |||
73 | /* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */ | ||
74 | #define INS_REM_INT_DISABLE 0x01 | ||
75 | #define DETECTION_COMPLETE_INT_DISABLE 0x02 | ||
76 | #define ADC_COMPLETE_INT_DISABLE 0x04 | ||
77 | #define INTB_DISABLE 0x08 | ||
78 | |||
79 | /* TS3A227E_REG_SETTING_2 0x05 */ | ||
80 | #define KP_ENABLE 0x04 | ||
81 | |||
82 | /* TS3A227E_REG_ACCESSORY_STATUS 0x0b */ | ||
83 | #define TYPE_3_POLE 0x01 | ||
84 | #define TYPE_4_POLE_OMTP 0x02 | ||
85 | #define TYPE_4_POLE_STANDARD 0x04 | ||
86 | #define JACK_INSERTED 0x08 | ||
87 | #define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD) | ||
88 | |||
89 | static const struct reg_default ts3a227e_reg_defaults[] = { | ||
90 | { TS3A227E_REG_DEVICE_ID, 0x10 }, | ||
91 | { TS3A227E_REG_INTERRUPT, 0x00 }, | ||
92 | { TS3A227E_REG_KP_INTERRUPT, 0x00 }, | ||
93 | { TS3A227E_REG_INTERRUPT_DISABLE, 0x08 }, | ||
94 | { TS3A227E_REG_SETTING_1, 0x23 }, | ||
95 | { TS3A227E_REG_SETTING_2, 0x00 }, | ||
96 | { TS3A227E_REG_SETTING_3, 0x0e }, | ||
97 | { TS3A227E_REG_SWITCH_CONTROL_1, 0x00 }, | ||
98 | { TS3A227E_REG_SWITCH_CONTROL_2, 0x00 }, | ||
99 | { TS3A227E_REG_SWITCH_STATUS_1, 0x0c }, | ||
100 | { TS3A227E_REG_SWITCH_STATUS_2, 0x00 }, | ||
101 | { TS3A227E_REG_ACCESSORY_STATUS, 0x00 }, | ||
102 | { TS3A227E_REG_ADC_OUTPUT, 0x00 }, | ||
103 | { TS3A227E_REG_KP_THRESHOLD_1, 0x20 }, | ||
104 | { TS3A227E_REG_KP_THRESHOLD_2, 0x40 }, | ||
105 | { TS3A227E_REG_KP_THRESHOLD_3, 0x68 }, | ||
106 | }; | ||
107 | |||
108 | static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg) | ||
109 | { | ||
110 | switch (reg) { | ||
111 | case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3: | ||
112 | return true; | ||
113 | default: | ||
114 | return false; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg) | ||
119 | { | ||
120 | switch (reg) { | ||
121 | case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2: | ||
122 | case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3: | ||
123 | return true; | ||
124 | default: | ||
125 | return false; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg) | ||
130 | { | ||
131 | switch (reg) { | ||
132 | case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE: | ||
133 | case TS3A227E_REG_SETTING_2: | ||
134 | case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT: | ||
135 | return true; | ||
136 | default: | ||
137 | return false; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static void ts3a227e_jack_report(struct ts3a227e *ts3a227e) | ||
142 | { | ||
143 | unsigned int i; | ||
144 | int report = 0; | ||
145 | |||
146 | if (!ts3a227e->jack) | ||
147 | return; | ||
148 | |||
149 | if (ts3a227e->plugged) | ||
150 | report = SND_JACK_HEADPHONE; | ||
151 | if (ts3a227e->mic_present) | ||
152 | report |= SND_JACK_MICROPHONE; | ||
153 | for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { | ||
154 | if (ts3a227e->buttons_held & (1 << i)) | ||
155 | report |= ts3a227e_buttons[i]; | ||
156 | } | ||
157 | snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK); | ||
158 | } | ||
159 | |||
160 | static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg) | ||
161 | { | ||
162 | bool plugged, mic_present; | ||
163 | |||
164 | plugged = !!(acc_reg & JACK_INSERTED); | ||
165 | mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK); | ||
166 | |||
167 | ts3a227e->plugged = plugged; | ||
168 | |||
169 | if (mic_present != ts3a227e->mic_present) { | ||
170 | ts3a227e->mic_present = mic_present; | ||
171 | ts3a227e->buttons_held = 0; | ||
172 | if (mic_present) { | ||
173 | /* Enable key press detection. */ | ||
174 | regmap_update_bits(ts3a227e->regmap, | ||
175 | TS3A227E_REG_SETTING_2, | ||
176 | KP_ENABLE, KP_ENABLE); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | static irqreturn_t ts3a227e_interrupt(int irq, void *data) | ||
182 | { | ||
183 | struct ts3a227e *ts3a227e = (struct ts3a227e *)data; | ||
184 | struct regmap *regmap = ts3a227e->regmap; | ||
185 | unsigned int int_reg, kp_int_reg, acc_reg, i; | ||
186 | |||
187 | /* Check for plug/unplug. */ | ||
188 | regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); | ||
189 | if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { | ||
190 | regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); | ||
191 | ts3a227e_new_jack_state(ts3a227e, acc_reg); | ||
192 | } | ||
193 | |||
194 | /* Report any key events. */ | ||
195 | regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); | ||
196 | for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { | ||
197 | if (kp_int_reg & PRESS_MASK(i)) | ||
198 | ts3a227e->buttons_held |= (1 << i); | ||
199 | if (kp_int_reg & RELEASE_MASK(i)) | ||
200 | ts3a227e->buttons_held &= ~(1 << i); | ||
201 | } | ||
202 | |||
203 | ts3a227e_jack_report(ts3a227e); | ||
204 | |||
205 | return IRQ_HANDLED; | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * ts3a227e_enable_jack_detect - Specify a jack for event reporting | ||
210 | * | ||
211 | * @component: component to register the jack with | ||
212 | * @jack: jack to use to report headset and button events on | ||
213 | * | ||
214 | * After this function has been called the headset insert/remove and button | ||
215 | * events 0-3 will be routed to the given jack. Jack can be null to stop | ||
216 | * reporting. | ||
217 | */ | ||
218 | int ts3a227e_enable_jack_detect(struct snd_soc_component *component, | ||
219 | struct snd_soc_jack *jack) | ||
220 | { | ||
221 | struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component); | ||
222 | |||
223 | snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA); | ||
224 | snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP); | ||
225 | snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN); | ||
226 | snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND); | ||
227 | |||
228 | ts3a227e->jack = jack; | ||
229 | ts3a227e_jack_report(ts3a227e); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect); | ||
234 | |||
235 | static struct snd_soc_component_driver ts3a227e_soc_driver; | ||
236 | |||
237 | static const struct regmap_config ts3a227e_regmap_config = { | ||
238 | .val_bits = 8, | ||
239 | .reg_bits = 8, | ||
240 | |||
241 | .max_register = TS3A227E_REG_KP_THRESHOLD_3, | ||
242 | .readable_reg = ts3a227e_readable_reg, | ||
243 | .writeable_reg = ts3a227e_writeable_reg, | ||
244 | .volatile_reg = ts3a227e_volatile_reg, | ||
245 | |||
246 | .cache_type = REGCACHE_RBTREE, | ||
247 | .reg_defaults = ts3a227e_reg_defaults, | ||
248 | .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults), | ||
249 | }; | ||
250 | |||
251 | static int ts3a227e_i2c_probe(struct i2c_client *i2c, | ||
252 | const struct i2c_device_id *id) | ||
253 | { | ||
254 | struct ts3a227e *ts3a227e; | ||
255 | struct device *dev = &i2c->dev; | ||
256 | int ret; | ||
257 | |||
258 | ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL); | ||
259 | if (ts3a227e == NULL) | ||
260 | return -ENOMEM; | ||
261 | |||
262 | i2c_set_clientdata(i2c, ts3a227e); | ||
263 | |||
264 | ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); | ||
265 | if (IS_ERR(ts3a227e->regmap)) | ||
266 | return PTR_ERR(ts3a227e->regmap); | ||
267 | |||
268 | ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt, | ||
269 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, | ||
270 | "TS3A227E", ts3a227e); | ||
271 | if (ret) { | ||
272 | dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret); | ||
273 | return ret; | ||
274 | } | ||
275 | |||
276 | ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver, | ||
277 | NULL, 0); | ||
278 | if (ret) | ||
279 | return ret; | ||
280 | |||
281 | /* Enable interrupts except for ADC complete. */ | ||
282 | regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE, | ||
283 | INTB_DISABLE | ADC_COMPLETE_INT_DISABLE, | ||
284 | ADC_COMPLETE_INT_DISABLE); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static const struct i2c_device_id ts3a227e_i2c_ids[] = { | ||
290 | { "ts3a227e", 0 }, | ||
291 | { } | ||
292 | }; | ||
293 | MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids); | ||
294 | |||
295 | static const struct of_device_id ts3a227e_of_match[] = { | ||
296 | { .compatible = "ti,ts3a227e", }, | ||
297 | { } | ||
298 | }; | ||
299 | MODULE_DEVICE_TABLE(of, ts3a227e_of_match); | ||
300 | |||
301 | static struct i2c_driver ts3a227e_driver = { | ||
302 | .driver = { | ||
303 | .name = "ts3a227e", | ||
304 | .owner = THIS_MODULE, | ||
305 | .of_match_table = of_match_ptr(ts3a227e_of_match), | ||
306 | }, | ||
307 | .probe = ts3a227e_i2c_probe, | ||
308 | .id_table = ts3a227e_i2c_ids, | ||
309 | }; | ||
310 | module_i2c_driver(ts3a227e_driver); | ||
311 | |||
312 | MODULE_DESCRIPTION("ASoC ts3a227e driver"); | ||
313 | MODULE_AUTHOR("Dylan Reid <dgreid@chromium.org>"); | ||
314 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h new file mode 100644 index 000000000000..e2acf9c5bebe --- /dev/null +++ b/sound/soc/codecs/ts3a227e.h | |||
@@ -0,0 +1,17 @@ | |||
1 | /* | ||
2 | * TS3A227E Autonous Audio Accessory Detection and Configureation Switch | ||
3 | * | ||
4 | * Copyright (C) 2014 Google, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _TS3A227E_H | ||
12 | #define _TS3A227E_H | ||
13 | |||
14 | int ts3a227e_enable_jack_detect(struct snd_soc_component *component, | ||
15 | struct snd_soc_jack *jack); | ||
16 | |||
17 | #endif | ||
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b6b0cb399599..27f3b21effb2 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -2177,8 +2177,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec) | |||
2177 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 2177 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
2178 | struct twl4030_codec_data *pdata = twl4030->pdata; | 2178 | struct twl4030_codec_data *pdata = twl4030->pdata; |
2179 | 2179 | ||
2180 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2181 | |||
2182 | if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) | 2180 | if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio)) |
2183 | gpio_free(pdata->hs_extmute_gpio); | 2181 | gpio_free(pdata->hs_extmute_gpio); |
2184 | 2182 | ||
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 0f6067f04e29..5ff2b1e4638e 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -1095,25 +1095,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = { | |||
1095 | }, | 1095 | }, |
1096 | }; | 1096 | }; |
1097 | 1097 | ||
1098 | #ifdef CONFIG_PM | ||
1099 | static int twl6040_suspend(struct snd_soc_codec *codec) | ||
1100 | { | ||
1101 | twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | static int twl6040_resume(struct snd_soc_codec *codec) | ||
1107 | { | ||
1108 | twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1109 | |||
1110 | return 0; | ||
1111 | } | ||
1112 | #else | ||
1113 | #define twl6040_suspend NULL | ||
1114 | #define twl6040_resume NULL | ||
1115 | #endif | ||
1116 | |||
1117 | static int twl6040_probe(struct snd_soc_codec *codec) | 1098 | static int twl6040_probe(struct snd_soc_codec *codec) |
1118 | { | 1099 | { |
1119 | struct twl6040_data *priv; | 1100 | struct twl6040_data *priv; |
@@ -1160,7 +1141,6 @@ static int twl6040_remove(struct snd_soc_codec *codec) | |||
1160 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 1141 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
1161 | 1142 | ||
1162 | free_irq(priv->plug_irq, codec); | 1143 | free_irq(priv->plug_irq, codec); |
1163 | twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1164 | 1144 | ||
1165 | return 0; | 1145 | return 0; |
1166 | } | 1146 | } |
@@ -1168,11 +1148,10 @@ static int twl6040_remove(struct snd_soc_codec *codec) | |||
1168 | static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { | 1148 | static struct snd_soc_codec_driver soc_codec_dev_twl6040 = { |
1169 | .probe = twl6040_probe, | 1149 | .probe = twl6040_probe, |
1170 | .remove = twl6040_remove, | 1150 | .remove = twl6040_remove, |
1171 | .suspend = twl6040_suspend, | ||
1172 | .resume = twl6040_resume, | ||
1173 | .read = twl6040_read, | 1151 | .read = twl6040_read, |
1174 | .write = twl6040_write, | 1152 | .write = twl6040_write, |
1175 | .set_bias_level = twl6040_set_bias_level, | 1153 | .set_bias_level = twl6040_set_bias_level, |
1154 | .suspend_bias_off = true, | ||
1176 | .ignore_pmdown_time = true, | 1155 | .ignore_pmdown_time = true, |
1177 | 1156 | ||
1178 | .controls = twl6040_snd_controls, | 1157 | .controls = twl6040_snd_controls, |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 32b2f78aa62c..4056260a502e 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -518,11 +518,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) | |||
518 | 518 | ||
519 | uda134x_reset(codec); | 519 | uda134x_reset(codec); |
520 | 520 | ||
521 | if (pd->is_powered_on_standby) | ||
522 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
523 | else | ||
524 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
525 | |||
526 | if (pd->model == UDA134X_UDA1341) { | 521 | if (pd->model == UDA134X_UDA1341) { |
527 | widgets = uda1341_dapm_widgets; | 522 | widgets = uda1341_dapm_widgets; |
528 | num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); | 523 | num_widgets = ARRAY_SIZE(uda1341_dapm_widgets); |
@@ -574,44 +569,21 @@ static int uda134x_soc_remove(struct snd_soc_codec *codec) | |||
574 | { | 569 | { |
575 | struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); | 570 | struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); |
576 | 571 | ||
577 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
578 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
579 | |||
580 | kfree(uda134x); | 572 | kfree(uda134x); |
581 | return 0; | 573 | return 0; |
582 | } | 574 | } |
583 | 575 | ||
584 | #if defined(CONFIG_PM) | ||
585 | static int uda134x_soc_suspend(struct snd_soc_codec *codec) | ||
586 | { | ||
587 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
588 | uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static int uda134x_soc_resume(struct snd_soc_codec *codec) | ||
593 | { | ||
594 | uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE); | ||
595 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
596 | return 0; | ||
597 | } | ||
598 | #else | ||
599 | #define uda134x_soc_suspend NULL | ||
600 | #define uda134x_soc_resume NULL | ||
601 | #endif /* CONFIG_PM */ | ||
602 | |||
603 | static struct snd_soc_codec_driver soc_codec_dev_uda134x = { | 576 | static struct snd_soc_codec_driver soc_codec_dev_uda134x = { |
604 | .probe = uda134x_soc_probe, | 577 | .probe = uda134x_soc_probe, |
605 | .remove = uda134x_soc_remove, | 578 | .remove = uda134x_soc_remove, |
606 | .suspend = uda134x_soc_suspend, | ||
607 | .resume = uda134x_soc_resume, | ||
608 | .reg_cache_size = sizeof(uda134x_reg), | 579 | .reg_cache_size = sizeof(uda134x_reg), |
609 | .reg_word_size = sizeof(u8), | 580 | .reg_word_size = sizeof(u8), |
610 | .reg_cache_default = uda134x_reg, | 581 | .reg_cache_default = uda134x_reg, |
611 | .reg_cache_step = 1, | 582 | .reg_cache_step = 1, |
612 | .read = uda134x_read_reg_cache, | 583 | .read = uda134x_read_reg_cache, |
613 | .write = uda134x_write, | ||
614 | .set_bias_level = uda134x_set_bias_level, | 584 | .set_bias_level = uda134x_set_bias_level, |
585 | .suspend_bias_off = true, | ||
586 | |||
615 | .dapm_widgets = uda134x_dapm_widgets, | 587 | .dapm_widgets = uda134x_dapm_widgets, |
616 | .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), | 588 | .num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets), |
617 | .dapm_routes = uda134x_dapm_routes, | 589 | .dapm_routes = uda134x_dapm_routes, |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index e62e70781ec2..dc7778b6dd7f 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -693,18 +693,6 @@ static struct snd_soc_dai_driver uda1380_dai[] = { | |||
693 | }, | 693 | }, |
694 | }; | 694 | }; |
695 | 695 | ||
696 | static int uda1380_suspend(struct snd_soc_codec *codec) | ||
697 | { | ||
698 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | static int uda1380_resume(struct snd_soc_codec *codec) | ||
703 | { | ||
704 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
705 | return 0; | ||
706 | } | ||
707 | |||
708 | static int uda1380_probe(struct snd_soc_codec *codec) | 696 | static int uda1380_probe(struct snd_soc_codec *codec) |
709 | { | 697 | { |
710 | struct uda1380_platform_data *pdata =codec->dev->platform_data; | 698 | struct uda1380_platform_data *pdata =codec->dev->platform_data; |
@@ -739,8 +727,6 @@ static int uda1380_probe(struct snd_soc_codec *codec) | |||
739 | 727 | ||
740 | INIT_WORK(&uda1380->work, uda1380_flush_work); | 728 | INIT_WORK(&uda1380->work, uda1380_flush_work); |
741 | 729 | ||
742 | /* power on device */ | ||
743 | uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
744 | /* set clock input */ | 730 | /* set clock input */ |
745 | switch (pdata->dac_clk) { | 731 | switch (pdata->dac_clk) { |
746 | case UDA1380_DAC_CLK_SYSCLK: | 732 | case UDA1380_DAC_CLK_SYSCLK: |
@@ -766,8 +752,6 @@ static int uda1380_remove(struct snd_soc_codec *codec) | |||
766 | { | 752 | { |
767 | struct uda1380_platform_data *pdata =codec->dev->platform_data; | 753 | struct uda1380_platform_data *pdata =codec->dev->platform_data; |
768 | 754 | ||
769 | uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
770 | |||
771 | gpio_free(pdata->gpio_reset); | 755 | gpio_free(pdata->gpio_reset); |
772 | gpio_free(pdata->gpio_power); | 756 | gpio_free(pdata->gpio_power); |
773 | 757 | ||
@@ -777,11 +761,11 @@ static int uda1380_remove(struct snd_soc_codec *codec) | |||
777 | static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { | 761 | static struct snd_soc_codec_driver soc_codec_dev_uda1380 = { |
778 | .probe = uda1380_probe, | 762 | .probe = uda1380_probe, |
779 | .remove = uda1380_remove, | 763 | .remove = uda1380_remove, |
780 | .suspend = uda1380_suspend, | ||
781 | .resume = uda1380_resume, | ||
782 | .read = uda1380_read_reg_cache, | 764 | .read = uda1380_read_reg_cache, |
783 | .write = uda1380_write, | 765 | .write = uda1380_write, |
784 | .set_bias_level = uda1380_set_bias_level, | 766 | .set_bias_level = uda1380_set_bias_level, |
767 | .suspend_bias_off = true, | ||
768 | |||
785 | .reg_cache_size = ARRAY_SIZE(uda1380_reg), | 769 | .reg_cache_size = ARRAY_SIZE(uda1380_reg), |
786 | .reg_word_size = sizeof(u16), | 770 | .reg_word_size = sizeof(u16), |
787 | .reg_cache_default = uda1380_reg, | 771 | .reg_cache_default = uda1380_reg, |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index f3d4e88d0b7b..00aea4100bb3 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
@@ -452,7 +452,6 @@ static int wl1273_probe(struct snd_soc_codec *codec) | |||
452 | { | 452 | { |
453 | struct wl1273_core **core = codec->dev->platform_data; | 453 | struct wl1273_core **core = codec->dev->platform_data; |
454 | struct wl1273_priv *wl1273; | 454 | struct wl1273_priv *wl1273; |
455 | int r; | ||
456 | 455 | ||
457 | dev_dbg(codec->dev, "%s.\n", __func__); | 456 | dev_dbg(codec->dev, "%s.\n", __func__); |
458 | 457 | ||
@@ -470,12 +469,7 @@ static int wl1273_probe(struct snd_soc_codec *codec) | |||
470 | 469 | ||
471 | snd_soc_codec_set_drvdata(codec, wl1273); | 470 | snd_soc_codec_set_drvdata(codec, wl1273); |
472 | 471 | ||
473 | r = snd_soc_add_codec_controls(codec, wl1273_controls, | 472 | return 0; |
474 | ARRAY_SIZE(wl1273_controls)); | ||
475 | if (r) | ||
476 | kfree(wl1273); | ||
477 | |||
478 | return r; | ||
479 | } | 473 | } |
480 | 474 | ||
481 | static int wl1273_remove(struct snd_soc_codec *codec) | 475 | static int wl1273_remove(struct snd_soc_codec *codec) |
@@ -492,6 +486,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = { | |||
492 | .probe = wl1273_probe, | 486 | .probe = wl1273_probe, |
493 | .remove = wl1273_remove, | 487 | .remove = wl1273_remove, |
494 | 488 | ||
489 | .controls = wl1273_controls, | ||
490 | .num_controls = ARRAY_SIZE(wl1273_controls), | ||
495 | .dapm_widgets = wl1273_dapm_widgets, | 491 | .dapm_widgets = wl1273_dapm_widgets, |
496 | .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), | 492 | .num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets), |
497 | .dapm_routes = wl1273_dapm_routes, | 493 | .dapm_routes = wl1273_dapm_routes, |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index f60234962527..d78fb8dffc8c 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -619,10 +619,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol, | |||
619 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 619 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
620 | uint16_t data; | 620 | uint16_t data; |
621 | 621 | ||
622 | mutex_lock(&codec->mutex); | 622 | mutex_lock(&arizona->dac_comp_lock); |
623 | data = cpu_to_be16(arizona->dac_comp_coeff); | 623 | data = cpu_to_be16(arizona->dac_comp_coeff); |
624 | memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); | 624 | memcpy(ucontrol->value.bytes.data, &data, sizeof(data)); |
625 | mutex_unlock(&codec->mutex); | 625 | mutex_unlock(&arizona->dac_comp_lock); |
626 | 626 | ||
627 | return 0; | 627 | return 0; |
628 | } | 628 | } |
@@ -633,11 +633,11 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol, | |||
633 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 633 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
634 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 634 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
635 | 635 | ||
636 | mutex_lock(&codec->mutex); | 636 | mutex_lock(&arizona->dac_comp_lock); |
637 | memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, | 637 | memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data, |
638 | sizeof(arizona->dac_comp_coeff)); | 638 | sizeof(arizona->dac_comp_coeff)); |
639 | arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); | 639 | arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff); |
640 | mutex_unlock(&codec->mutex); | 640 | mutex_unlock(&arizona->dac_comp_lock); |
641 | 641 | ||
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
@@ -648,9 +648,9 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol, | |||
648 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 648 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
649 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 649 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
650 | 650 | ||
651 | mutex_lock(&codec->mutex); | 651 | mutex_lock(&arizona->dac_comp_lock); |
652 | ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; | 652 | ucontrol->value.integer.value[0] = arizona->dac_comp_enabled; |
653 | mutex_unlock(&codec->mutex); | 653 | mutex_unlock(&arizona->dac_comp_lock); |
654 | 654 | ||
655 | return 0; | 655 | return 0; |
656 | } | 656 | } |
@@ -661,9 +661,9 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol, | |||
661 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | 661 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); |
662 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 662 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
663 | 663 | ||
664 | mutex_lock(&codec->mutex); | 664 | mutex_lock(&arizona->dac_comp_lock); |
665 | arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; | 665 | arizona->dac_comp_enabled = ucontrol->value.integer.value[0]; |
666 | mutex_unlock(&codec->mutex); | 666 | mutex_unlock(&arizona->dac_comp_lock); |
667 | 667 | ||
668 | return 0; | 668 | return 0; |
669 | } | 669 | } |
@@ -1900,6 +1900,8 @@ static int wm5102_probe(struct platform_device *pdev) | |||
1900 | return -ENOMEM; | 1900 | return -ENOMEM; |
1901 | platform_set_drvdata(pdev, wm5102); | 1901 | platform_set_drvdata(pdev, wm5102); |
1902 | 1902 | ||
1903 | mutex_init(&arizona->dac_comp_lock); | ||
1904 | |||
1903 | wm5102->core.arizona = arizona; | 1905 | wm5102->core.arizona = arizona; |
1904 | wm5102->core.num_inputs = 6; | 1906 | wm5102->core.num_inputs = 6; |
1905 | 1907 | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 628ec774cf22..87f664b9cc7d 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1242,19 +1242,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec, | |||
1242 | return 0; | 1242 | return 0; |
1243 | } | 1243 | } |
1244 | 1244 | ||
1245 | static int wm8350_suspend(struct snd_soc_codec *codec) | ||
1246 | { | ||
1247 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | static int wm8350_resume(struct snd_soc_codec *codec) | ||
1252 | { | ||
1253 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1254 | |||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | static void wm8350_hp_work(struct wm8350_data *priv, | 1245 | static void wm8350_hp_work(struct wm8350_data *priv, |
1259 | struct wm8350_jack_data *jack, | 1246 | struct wm8350_jack_data *jack, |
1260 | u16 mask) | 1247 | u16 mask) |
@@ -1565,9 +1552,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) | |||
1565 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, | 1552 | wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD, |
1566 | wm8350_mic_handler, 0, "Microphone detect", priv); | 1553 | wm8350_mic_handler, 0, "Microphone detect", priv); |
1567 | 1554 | ||
1568 | |||
1569 | wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1570 | |||
1571 | return 0; | 1555 | return 0; |
1572 | } | 1556 | } |
1573 | 1557 | ||
@@ -1596,8 +1580,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec) | |||
1596 | * wait for its completion */ | 1580 | * wait for its completion */ |
1597 | flush_delayed_work(&codec->dapm.delayed_work); | 1581 | flush_delayed_work(&codec->dapm.delayed_work); |
1598 | 1582 | ||
1599 | wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1600 | |||
1601 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1583 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
1602 | 1584 | ||
1603 | return 0; | 1585 | return 0; |
@@ -1613,10 +1595,9 @@ static struct regmap *wm8350_get_regmap(struct device *dev) | |||
1613 | static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { | 1595 | static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { |
1614 | .probe = wm8350_codec_probe, | 1596 | .probe = wm8350_codec_probe, |
1615 | .remove = wm8350_codec_remove, | 1597 | .remove = wm8350_codec_remove, |
1616 | .suspend = wm8350_suspend, | ||
1617 | .resume = wm8350_resume, | ||
1618 | .get_regmap = wm8350_get_regmap, | 1598 | .get_regmap = wm8350_get_regmap, |
1619 | .set_bias_level = wm8350_set_bias_level, | 1599 | .set_bias_level = wm8350_set_bias_level, |
1600 | .suspend_bias_off = true, | ||
1620 | 1601 | ||
1621 | .controls = wm8350_snd_controls, | 1602 | .controls = wm8350_snd_controls, |
1622 | .num_controls = ARRAY_SIZE(wm8350_snd_controls), | 1603 | .num_controls = ARRAY_SIZE(wm8350_snd_controls), |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 72471bef2e9a..385894f6e264 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -58,12 +58,10 @@ static struct regulator_bulk_data power[] = { | |||
58 | 58 | ||
59 | /* codec private data */ | 59 | /* codec private data */ |
60 | struct wm8400_priv { | 60 | struct wm8400_priv { |
61 | struct snd_soc_codec *codec; | ||
62 | struct wm8400 *wm8400; | 61 | struct wm8400 *wm8400; |
63 | u16 fake_register; | 62 | u16 fake_register; |
64 | unsigned int sysclk; | 63 | unsigned int sysclk; |
65 | unsigned int pcmclk; | 64 | unsigned int pcmclk; |
66 | struct work_struct work; | ||
67 | int fll_in, fll_out; | 65 | int fll_in, fll_out; |
68 | }; | 66 | }; |
69 | 67 | ||
@@ -1278,30 +1276,6 @@ static struct snd_soc_dai_driver wm8400_dai = { | |||
1278 | .ops = &wm8400_dai_ops, | 1276 | .ops = &wm8400_dai_ops, |
1279 | }; | 1277 | }; |
1280 | 1278 | ||
1281 | static int wm8400_suspend(struct snd_soc_codec *codec) | ||
1282 | { | ||
1283 | wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1284 | |||
1285 | return 0; | ||
1286 | } | ||
1287 | |||
1288 | static int wm8400_resume(struct snd_soc_codec *codec) | ||
1289 | { | ||
1290 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1294 | |||
1295 | static void wm8400_probe_deferred(struct work_struct *work) | ||
1296 | { | ||
1297 | struct wm8400_priv *priv = container_of(work, struct wm8400_priv, | ||
1298 | work); | ||
1299 | struct snd_soc_codec *codec = priv->codec; | ||
1300 | |||
1301 | /* charge output caps */ | ||
1302 | wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1303 | } | ||
1304 | |||
1305 | static int wm8400_codec_probe(struct snd_soc_codec *codec) | 1279 | static int wm8400_codec_probe(struct snd_soc_codec *codec) |
1306 | { | 1280 | { |
1307 | struct wm8400 *wm8400 = dev_get_platdata(codec->dev); | 1281 | struct wm8400 *wm8400 = dev_get_platdata(codec->dev); |
@@ -1316,7 +1290,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1316 | 1290 | ||
1317 | snd_soc_codec_set_drvdata(codec, priv); | 1291 | snd_soc_codec_set_drvdata(codec, priv); |
1318 | priv->wm8400 = wm8400; | 1292 | priv->wm8400 = wm8400; |
1319 | priv->codec = codec; | ||
1320 | 1293 | ||
1321 | ret = devm_regulator_bulk_get(wm8400->dev, | 1294 | ret = devm_regulator_bulk_get(wm8400->dev, |
1322 | ARRAY_SIZE(power), &power[0]); | 1295 | ARRAY_SIZE(power), &power[0]); |
@@ -1325,8 +1298,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1325 | return ret; | 1298 | return ret; |
1326 | } | 1299 | } |
1327 | 1300 | ||
1328 | INIT_WORK(&priv->work, wm8400_probe_deferred); | ||
1329 | |||
1330 | wm8400_codec_reset(codec); | 1301 | wm8400_codec_reset(codec); |
1331 | 1302 | ||
1332 | reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1); | 1303 | reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1); |
@@ -1343,8 +1314,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec) | |||
1343 | snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1314 | snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1344 | snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | 1315 | snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); |
1345 | 1316 | ||
1346 | if (!schedule_work(&priv->work)) | ||
1347 | return -EINVAL; | ||
1348 | return 0; | 1317 | return 0; |
1349 | } | 1318 | } |
1350 | 1319 | ||
@@ -1369,10 +1338,9 @@ static struct regmap *wm8400_get_regmap(struct device *dev) | |||
1369 | static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { | 1338 | static struct snd_soc_codec_driver soc_codec_dev_wm8400 = { |
1370 | .probe = wm8400_codec_probe, | 1339 | .probe = wm8400_codec_probe, |
1371 | .remove = wm8400_codec_remove, | 1340 | .remove = wm8400_codec_remove, |
1372 | .suspend = wm8400_suspend, | ||
1373 | .resume = wm8400_resume, | ||
1374 | .get_regmap = wm8400_get_regmap, | 1341 | .get_regmap = wm8400_get_regmap, |
1375 | .set_bias_level = wm8400_set_bias_level, | 1342 | .set_bias_level = wm8400_set_bias_level, |
1343 | .suspend_bias_off = true, | ||
1376 | 1344 | ||
1377 | .controls = wm8400_snd_controls, | 1345 | .controls = wm8400_snd_controls, |
1378 | .num_controls = ARRAY_SIZE(wm8400_snd_controls), | 1346 | .num_controls = ARRAY_SIZE(wm8400_snd_controls), |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index e11127f9069e..8736ad094b24 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -575,41 +575,17 @@ static struct snd_soc_dai_driver wm8510_dai = { | |||
575 | .symmetric_rates = 1, | 575 | .symmetric_rates = 1, |
576 | }; | 576 | }; |
577 | 577 | ||
578 | static int wm8510_suspend(struct snd_soc_codec *codec) | ||
579 | { | ||
580 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
581 | return 0; | ||
582 | } | ||
583 | |||
584 | static int wm8510_resume(struct snd_soc_codec *codec) | ||
585 | { | ||
586 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
587 | return 0; | ||
588 | } | ||
589 | |||
590 | static int wm8510_probe(struct snd_soc_codec *codec) | 578 | static int wm8510_probe(struct snd_soc_codec *codec) |
591 | { | 579 | { |
592 | wm8510_reset(codec); | 580 | wm8510_reset(codec); |
593 | 581 | ||
594 | /* power on device */ | ||
595 | wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
596 | |||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | /* power down chip */ | ||
601 | static int wm8510_remove(struct snd_soc_codec *codec) | ||
602 | { | ||
603 | wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
604 | return 0; | 582 | return 0; |
605 | } | 583 | } |
606 | 584 | ||
607 | static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { | 585 | static struct snd_soc_codec_driver soc_codec_dev_wm8510 = { |
608 | .probe = wm8510_probe, | 586 | .probe = wm8510_probe, |
609 | .remove = wm8510_remove, | ||
610 | .suspend = wm8510_suspend, | ||
611 | .resume = wm8510_resume, | ||
612 | .set_bias_level = wm8510_set_bias_level, | 587 | .set_bias_level = wm8510_set_bias_level, |
588 | .suspend_bias_off = true, | ||
613 | 589 | ||
614 | .controls = wm8510_snd_controls, | 590 | .controls = wm8510_snd_controls, |
615 | .num_controls = ARRAY_SIZE(wm8510_snd_controls), | 591 | .num_controls = ARRAY_SIZE(wm8510_snd_controls), |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index ec1f5740dbd0..b1cc94f5fc4b 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -372,23 +372,6 @@ static struct snd_soc_dai_driver wm8523_dai = { | |||
372 | .ops = &wm8523_dai_ops, | 372 | .ops = &wm8523_dai_ops, |
373 | }; | 373 | }; |
374 | 374 | ||
375 | #ifdef CONFIG_PM | ||
376 | static int wm8523_suspend(struct snd_soc_codec *codec) | ||
377 | { | ||
378 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static int wm8523_resume(struct snd_soc_codec *codec) | ||
383 | { | ||
384 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
385 | return 0; | ||
386 | } | ||
387 | #else | ||
388 | #define wm8523_suspend NULL | ||
389 | #define wm8523_resume NULL | ||
390 | #endif | ||
391 | |||
392 | static int wm8523_probe(struct snd_soc_codec *codec) | 375 | static int wm8523_probe(struct snd_soc_codec *codec) |
393 | { | 376 | { |
394 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); | 377 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
@@ -402,23 +385,13 @@ static int wm8523_probe(struct snd_soc_codec *codec) | |||
402 | WM8523_DACR_VU, WM8523_DACR_VU); | 385 | WM8523_DACR_VU, WM8523_DACR_VU); |
403 | snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); | 386 | snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); |
404 | 387 | ||
405 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int wm8523_remove(struct snd_soc_codec *codec) | ||
411 | { | ||
412 | wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
413 | return 0; | 388 | return 0; |
414 | } | 389 | } |
415 | 390 | ||
416 | static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { | 391 | static struct snd_soc_codec_driver soc_codec_dev_wm8523 = { |
417 | .probe = wm8523_probe, | 392 | .probe = wm8523_probe, |
418 | .remove = wm8523_remove, | ||
419 | .suspend = wm8523_suspend, | ||
420 | .resume = wm8523_resume, | ||
421 | .set_bias_level = wm8523_set_bias_level, | 393 | .set_bias_level = wm8523_set_bias_level, |
394 | .suspend_bias_off = true, | ||
422 | 395 | ||
423 | .controls = wm8523_controls, | 396 | .controls = wm8523_controls, |
424 | .num_controls = ARRAY_SIZE(wm8523_controls), | 397 | .num_controls = ARRAY_SIZE(wm8523_controls), |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 911605ee25b0..0a887c5ec83a 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -882,8 +882,6 @@ static int wm8580_probe(struct snd_soc_codec *codec) | |||
882 | goto err_regulator_enable; | 882 | goto err_regulator_enable; |
883 | } | 883 | } |
884 | 884 | ||
885 | wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
886 | |||
887 | return 0; | 885 | return 0; |
888 | 886 | ||
889 | err_regulator_enable: | 887 | err_regulator_enable: |
@@ -897,8 +895,6 @@ static int wm8580_remove(struct snd_soc_codec *codec) | |||
897 | { | 895 | { |
898 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); | 896 | struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec); |
899 | 897 | ||
900 | wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
901 | |||
902 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); | 898 | regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies); |
903 | 899 | ||
904 | return 0; | 900 | return 0; |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index 32187e739b4f..121e46d53779 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -350,19 +350,6 @@ static struct snd_soc_dai_driver wm8711_dai = { | |||
350 | .ops = &wm8711_ops, | 350 | .ops = &wm8711_ops, |
351 | }; | 351 | }; |
352 | 352 | ||
353 | static int wm8711_suspend(struct snd_soc_codec *codec) | ||
354 | { | ||
355 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | ||
356 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
357 | return 0; | ||
358 | } | ||
359 | |||
360 | static int wm8711_resume(struct snd_soc_codec *codec) | ||
361 | { | ||
362 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int wm8711_probe(struct snd_soc_codec *codec) | 353 | static int wm8711_probe(struct snd_soc_codec *codec) |
367 | { | 354 | { |
368 | int ret; | 355 | int ret; |
@@ -373,8 +360,6 @@ static int wm8711_probe(struct snd_soc_codec *codec) | |||
373 | return ret; | 360 | return ret; |
374 | } | 361 | } |
375 | 362 | ||
376 | wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
377 | |||
378 | /* Latch the update bits */ | 363 | /* Latch the update bits */ |
379 | snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100); | 364 | snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100); |
380 | snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100); | 365 | snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100); |
@@ -383,19 +368,11 @@ static int wm8711_probe(struct snd_soc_codec *codec) | |||
383 | 368 | ||
384 | } | 369 | } |
385 | 370 | ||
386 | /* power down chip */ | ||
387 | static int wm8711_remove(struct snd_soc_codec *codec) | ||
388 | { | ||
389 | wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
390 | return 0; | ||
391 | } | ||
392 | |||
393 | static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { | 371 | static struct snd_soc_codec_driver soc_codec_dev_wm8711 = { |
394 | .probe = wm8711_probe, | 372 | .probe = wm8711_probe, |
395 | .remove = wm8711_remove, | ||
396 | .suspend = wm8711_suspend, | ||
397 | .resume = wm8711_resume, | ||
398 | .set_bias_level = wm8711_set_bias_level, | 373 | .set_bias_level = wm8711_set_bias_level, |
374 | .suspend_bias_off = true, | ||
375 | |||
399 | .controls = wm8711_snd_controls, | 376 | .controls = wm8711_snd_controls, |
400 | .num_controls = ARRAY_SIZE(wm8711_snd_controls), | 377 | .num_controls = ARRAY_SIZE(wm8711_snd_controls), |
401 | .dapm_widgets = wm8711_dapm_widgets, | 378 | .dapm_widgets = wm8711_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 38ff826f589a..55c7fb4fc786 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c | |||
@@ -212,40 +212,10 @@ static struct snd_soc_dai_driver wm8728_dai = { | |||
212 | .ops = &wm8728_dai_ops, | 212 | .ops = &wm8728_dai_ops, |
213 | }; | 213 | }; |
214 | 214 | ||
215 | static int wm8728_suspend(struct snd_soc_codec *codec) | ||
216 | { | ||
217 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int wm8728_resume(struct snd_soc_codec *codec) | ||
223 | { | ||
224 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int wm8728_probe(struct snd_soc_codec *codec) | ||
230 | { | ||
231 | /* power on device */ | ||
232 | wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int wm8728_remove(struct snd_soc_codec *codec) | ||
238 | { | ||
239 | wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { | 215 | static struct snd_soc_codec_driver soc_codec_dev_wm8728 = { |
244 | .probe = wm8728_probe, | ||
245 | .remove = wm8728_remove, | ||
246 | .suspend = wm8728_suspend, | ||
247 | .resume = wm8728_resume, | ||
248 | .set_bias_level = wm8728_set_bias_level, | 216 | .set_bias_level = wm8728_set_bias_level, |
217 | .suspend_bias_off = true, | ||
218 | |||
249 | .controls = wm8728_snd_controls, | 219 | .controls = wm8728_snd_controls, |
250 | .num_controls = ARRAY_SIZE(wm8728_snd_controls), | 220 | .num_controls = ARRAY_SIZE(wm8728_snd_controls), |
251 | .dapm_widgets = wm8728_dapm_widgets, | 221 | .dapm_widgets = wm8728_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index eebb3280bfad..b9211b42f6e9 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/regulator/consumer.h> | 24 | #include <linux/regulator/consumer.h> |
25 | #include <linux/spi/spi.h> | 25 | #include <linux/spi/spi.h> |
26 | #include <linux/of_device.h> | 26 | #include <linux/of_device.h> |
27 | #include <linux/mutex.h> | ||
27 | #include <sound/core.h> | 28 | #include <sound/core.h> |
28 | #include <sound/pcm.h> | 29 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 30 | #include <sound/pcm_params.h> |
@@ -50,6 +51,8 @@ struct wm8731_priv { | |||
50 | int sysclk_type; | 51 | int sysclk_type; |
51 | int playback_fs; | 52 | int playback_fs; |
52 | bool deemph; | 53 | bool deemph; |
54 | |||
55 | struct mutex lock; | ||
53 | }; | 56 | }; |
54 | 57 | ||
55 | 58 | ||
@@ -138,7 +141,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, | |||
138 | if (deemph > 1) | 141 | if (deemph > 1) |
139 | return -EINVAL; | 142 | return -EINVAL; |
140 | 143 | ||
141 | mutex_lock(&codec->mutex); | 144 | mutex_lock(&wm8731->lock); |
142 | if (wm8731->deemph != deemph) { | 145 | if (wm8731->deemph != deemph) { |
143 | wm8731->deemph = deemph; | 146 | wm8731->deemph = deemph; |
144 | 147 | ||
@@ -146,7 +149,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol, | |||
146 | 149 | ||
147 | ret = 1; | 150 | ret = 1; |
148 | } | 151 | } |
149 | mutex_unlock(&codec->mutex); | 152 | mutex_unlock(&wm8731->lock); |
150 | 153 | ||
151 | return ret; | 154 | return ret; |
152 | } | 155 | } |
@@ -559,25 +562,6 @@ static struct snd_soc_dai_driver wm8731_dai = { | |||
559 | .symmetric_rates = 1, | 562 | .symmetric_rates = 1, |
560 | }; | 563 | }; |
561 | 564 | ||
562 | #ifdef CONFIG_PM | ||
563 | static int wm8731_suspend(struct snd_soc_codec *codec) | ||
564 | { | ||
565 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
566 | |||
567 | return 0; | ||
568 | } | ||
569 | |||
570 | static int wm8731_resume(struct snd_soc_codec *codec) | ||
571 | { | ||
572 | wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | #else | ||
577 | #define wm8731_suspend NULL | ||
578 | #define wm8731_resume NULL | ||
579 | #endif | ||
580 | |||
581 | static int wm8731_probe(struct snd_soc_codec *codec) | 565 | static int wm8731_probe(struct snd_soc_codec *codec) |
582 | { | 566 | { |
583 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); | 567 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); |
@@ -633,8 +617,6 @@ static int wm8731_remove(struct snd_soc_codec *codec) | |||
633 | { | 617 | { |
634 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); | 618 | struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); |
635 | 619 | ||
636 | wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
637 | |||
638 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); | 620 | regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); |
639 | 621 | ||
640 | return 0; | 622 | return 0; |
@@ -643,9 +625,9 @@ static int wm8731_remove(struct snd_soc_codec *codec) | |||
643 | static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { | 625 | static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { |
644 | .probe = wm8731_probe, | 626 | .probe = wm8731_probe, |
645 | .remove = wm8731_remove, | 627 | .remove = wm8731_remove, |
646 | .suspend = wm8731_suspend, | ||
647 | .resume = wm8731_resume, | ||
648 | .set_bias_level = wm8731_set_bias_level, | 628 | .set_bias_level = wm8731_set_bias_level, |
629 | .suspend_bias_off = true, | ||
630 | |||
649 | .dapm_widgets = wm8731_dapm_widgets, | 631 | .dapm_widgets = wm8731_dapm_widgets, |
650 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), | 632 | .num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets), |
651 | .dapm_routes = wm8731_intercon, | 633 | .dapm_routes = wm8731_intercon, |
@@ -680,11 +662,12 @@ static int wm8731_spi_probe(struct spi_device *spi) | |||
680 | struct wm8731_priv *wm8731; | 662 | struct wm8731_priv *wm8731; |
681 | int ret; | 663 | int ret; |
682 | 664 | ||
683 | wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv), | 665 | wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL); |
684 | GFP_KERNEL); | ||
685 | if (wm8731 == NULL) | 666 | if (wm8731 == NULL) |
686 | return -ENOMEM; | 667 | return -ENOMEM; |
687 | 668 | ||
669 | mutex_init(&wm8731->lock); | ||
670 | |||
688 | wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); | 671 | wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); |
689 | if (IS_ERR(wm8731->regmap)) { | 672 | if (IS_ERR(wm8731->regmap)) { |
690 | ret = PTR_ERR(wm8731->regmap); | 673 | ret = PTR_ERR(wm8731->regmap); |
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 744a422ecb05..ada9ac1ba2c6 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c | |||
@@ -277,17 +277,6 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
277 | { "AIF", NULL, "ADCR" }, | 277 | { "AIF", NULL, "ADCR" }, |
278 | }; | 278 | }; |
279 | 279 | ||
280 | static int wm8737_add_widgets(struct snd_soc_codec *codec) | ||
281 | { | ||
282 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
283 | |||
284 | snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets, | ||
285 | ARRAY_SIZE(wm8737_dapm_widgets)); | ||
286 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* codec mclk clock divider coefficients */ | 280 | /* codec mclk clock divider coefficients */ |
292 | static const struct { | 281 | static const struct { |
293 | u32 mclk; | 282 | u32 mclk; |
@@ -548,23 +537,6 @@ static struct snd_soc_dai_driver wm8737_dai = { | |||
548 | .ops = &wm8737_dai_ops, | 537 | .ops = &wm8737_dai_ops, |
549 | }; | 538 | }; |
550 | 539 | ||
551 | #ifdef CONFIG_PM | ||
552 | static int wm8737_suspend(struct snd_soc_codec *codec) | ||
553 | { | ||
554 | wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int wm8737_resume(struct snd_soc_codec *codec) | ||
559 | { | ||
560 | wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
561 | return 0; | ||
562 | } | ||
563 | #else | ||
564 | #define wm8737_suspend NULL | ||
565 | #define wm8737_resume NULL | ||
566 | #endif | ||
567 | |||
568 | static int wm8737_probe(struct snd_soc_codec *codec) | 540 | static int wm8737_probe(struct snd_soc_codec *codec) |
569 | { | 541 | { |
570 | struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); | 542 | struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec); |
@@ -593,10 +565,6 @@ static int wm8737_probe(struct snd_soc_codec *codec) | |||
593 | /* Bias level configuration will have done an extra enable */ | 565 | /* Bias level configuration will have done an extra enable */ |
594 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); | 566 | regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies); |
595 | 567 | ||
596 | snd_soc_add_codec_controls(codec, wm8737_snd_controls, | ||
597 | ARRAY_SIZE(wm8737_snd_controls)); | ||
598 | wm8737_add_widgets(codec); | ||
599 | |||
600 | return 0; | 568 | return 0; |
601 | 569 | ||
602 | err_enable: | 570 | err_enable: |
@@ -605,18 +573,17 @@ err_get: | |||
605 | return ret; | 573 | return ret; |
606 | } | 574 | } |
607 | 575 | ||
608 | static int wm8737_remove(struct snd_soc_codec *codec) | ||
609 | { | ||
610 | wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { | 576 | static struct snd_soc_codec_driver soc_codec_dev_wm8737 = { |
615 | .probe = wm8737_probe, | 577 | .probe = wm8737_probe, |
616 | .remove = wm8737_remove, | ||
617 | .suspend = wm8737_suspend, | ||
618 | .resume = wm8737_resume, | ||
619 | .set_bias_level = wm8737_set_bias_level, | 578 | .set_bias_level = wm8737_set_bias_level, |
579 | .suspend_bias_off = true, | ||
580 | |||
581 | .controls = wm8737_snd_controls, | ||
582 | .num_controls = ARRAY_SIZE(wm8737_snd_controls), | ||
583 | .dapm_widgets = wm8737_dapm_widgets, | ||
584 | .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets), | ||
585 | .dapm_routes = intercon, | ||
586 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
620 | }; | 587 | }; |
621 | 588 | ||
622 | static const struct of_device_id wm8737_of_match[] = { | 589 | static const struct of_device_id wm8737_of_match[] = { |
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 67653a2db223..f6847fdd6ddd 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -686,18 +686,6 @@ static struct snd_soc_dai_driver wm8750_dai = { | |||
686 | .ops = &wm8750_dai_ops, | 686 | .ops = &wm8750_dai_ops, |
687 | }; | 687 | }; |
688 | 688 | ||
689 | static int wm8750_suspend(struct snd_soc_codec *codec) | ||
690 | { | ||
691 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | static int wm8750_resume(struct snd_soc_codec *codec) | ||
696 | { | ||
697 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | static int wm8750_probe(struct snd_soc_codec *codec) | 689 | static int wm8750_probe(struct snd_soc_codec *codec) |
702 | { | 690 | { |
703 | int ret; | 691 | int ret; |
@@ -708,9 +696,6 @@ static int wm8750_probe(struct snd_soc_codec *codec) | |||
708 | return ret; | 696 | return ret; |
709 | } | 697 | } |
710 | 698 | ||
711 | /* charge output caps */ | ||
712 | wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
713 | |||
714 | /* set the update bits */ | 699 | /* set the update bits */ |
715 | snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); | 700 | snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100); |
716 | snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); | 701 | snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100); |
@@ -724,18 +709,10 @@ static int wm8750_probe(struct snd_soc_codec *codec) | |||
724 | return ret; | 709 | return ret; |
725 | } | 710 | } |
726 | 711 | ||
727 | static int wm8750_remove(struct snd_soc_codec *codec) | ||
728 | { | ||
729 | wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { | 712 | static struct snd_soc_codec_driver soc_codec_dev_wm8750 = { |
734 | .probe = wm8750_probe, | 713 | .probe = wm8750_probe, |
735 | .remove = wm8750_remove, | ||
736 | .suspend = wm8750_suspend, | ||
737 | .resume = wm8750_resume, | ||
738 | .set_bias_level = wm8750_set_bias_level, | 714 | .set_bias_level = wm8750_set_bias_level, |
715 | .suspend_bias_off = true, | ||
739 | 716 | ||
740 | .controls = wm8750_snd_controls, | 717 | .controls = wm8750_snd_controls, |
741 | .num_controls = ARRAY_SIZE(wm8750_snd_controls), | 718 | .num_controls = ARRAY_SIZE(wm8750_snd_controls), |
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 70952ceb278b..c13050b77931 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -408,24 +408,6 @@ static struct snd_soc_dai_driver wm8776_dai[] = { | |||
408 | }, | 408 | }, |
409 | }; | 409 | }; |
410 | 410 | ||
411 | #ifdef CONFIG_PM | ||
412 | static int wm8776_suspend(struct snd_soc_codec *codec) | ||
413 | { | ||
414 | wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int wm8776_resume(struct snd_soc_codec *codec) | ||
420 | { | ||
421 | wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
422 | return 0; | ||
423 | } | ||
424 | #else | ||
425 | #define wm8776_suspend NULL | ||
426 | #define wm8776_resume NULL | ||
427 | #endif | ||
428 | |||
429 | static int wm8776_probe(struct snd_soc_codec *codec) | 411 | static int wm8776_probe(struct snd_soc_codec *codec) |
430 | { | 412 | { |
431 | int ret = 0; | 413 | int ret = 0; |
@@ -436,8 +418,6 @@ static int wm8776_probe(struct snd_soc_codec *codec) | |||
436 | return ret; | 418 | return ret; |
437 | } | 419 | } |
438 | 420 | ||
439 | wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
440 | |||
441 | /* Latch the update bits; right channel only since we always | 421 | /* Latch the update bits; right channel only since we always |
442 | * update both. */ | 422 | * update both. */ |
443 | snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); | 423 | snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100); |
@@ -446,19 +426,10 @@ static int wm8776_probe(struct snd_soc_codec *codec) | |||
446 | return ret; | 426 | return ret; |
447 | } | 427 | } |
448 | 428 | ||
449 | /* power down chip */ | ||
450 | static int wm8776_remove(struct snd_soc_codec *codec) | ||
451 | { | ||
452 | wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
453 | return 0; | ||
454 | } | ||
455 | |||
456 | static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { | 429 | static struct snd_soc_codec_driver soc_codec_dev_wm8776 = { |
457 | .probe = wm8776_probe, | 430 | .probe = wm8776_probe, |
458 | .remove = wm8776_remove, | ||
459 | .suspend = wm8776_suspend, | ||
460 | .resume = wm8776_resume, | ||
461 | .set_bias_level = wm8776_set_bias_level, | 431 | .set_bias_level = wm8776_set_bias_level, |
432 | .suspend_bias_off = true, | ||
462 | 433 | ||
463 | .controls = wm8776_snd_controls, | 434 | .controls = wm8776_snd_controls, |
464 | .num_controls = ARRAY_SIZE(wm8776_snd_controls), | 435 | .num_controls = ARRAY_SIZE(wm8776_snd_controls), |
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 3addc5fe5cb2..1315f7642503 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -524,7 +524,6 @@ static int wm8804_remove(struct snd_soc_codec *codec) | |||
524 | int i; | 524 | int i; |
525 | 525 | ||
526 | wm8804 = snd_soc_codec_get_drvdata(codec); | 526 | wm8804 = snd_soc_codec_get_drvdata(codec); |
527 | wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
528 | 527 | ||
529 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) | 528 | for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i) |
530 | regulator_unregister_notifier(wm8804->supplies[i].consumer, | 529 | regulator_unregister_notifier(wm8804->supplies[i].consumer, |
@@ -606,8 +605,6 @@ static int wm8804_probe(struct snd_soc_codec *codec) | |||
606 | goto err_reg_enable; | 605 | goto err_reg_enable; |
607 | } | 606 | } |
608 | 607 | ||
609 | wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
610 | |||
611 | return 0; | 608 | return 0; |
612 | 609 | ||
613 | err_reg_enable: | 610 | err_reg_enable: |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 44a5f1511f0f..3a0d4b7d692f 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -1209,16 +1209,8 @@ static int wm8900_probe(struct snd_soc_codec *codec) | |||
1209 | return 0; | 1209 | return 0; |
1210 | } | 1210 | } |
1211 | 1211 | ||
1212 | /* power down chip */ | ||
1213 | static int wm8900_remove(struct snd_soc_codec *codec) | ||
1214 | { | ||
1215 | wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1216 | return 0; | ||
1217 | } | ||
1218 | |||
1219 | static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { | 1212 | static struct snd_soc_codec_driver soc_codec_dev_wm8900 = { |
1220 | .probe = wm8900_probe, | 1213 | .probe = wm8900_probe, |
1221 | .remove = wm8900_remove, | ||
1222 | .suspend = wm8900_suspend, | 1214 | .suspend = wm8900_suspend, |
1223 | .resume = wm8900_resume, | 1215 | .resume = wm8900_resume, |
1224 | .set_bias_level = wm8900_set_bias_level, | 1216 | .set_bias_level = wm8900_set_bias_level, |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c038b3e04398..cc6b0ef98a34 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/irq.h> | 28 | #include <linux/irq.h> |
29 | #include <linux/mutex.h> | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/jack.h> | 31 | #include <sound/jack.h> |
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
@@ -117,12 +118,12 @@ static const struct reg_default wm8903_reg_defaults[] = { | |||
117 | struct wm8903_priv { | 118 | struct wm8903_priv { |
118 | struct wm8903_platform_data *pdata; | 119 | struct wm8903_platform_data *pdata; |
119 | struct device *dev; | 120 | struct device *dev; |
120 | struct snd_soc_codec *codec; | ||
121 | struct regmap *regmap; | 121 | struct regmap *regmap; |
122 | 122 | ||
123 | int sysclk; | 123 | int sysclk; |
124 | int irq; | 124 | int irq; |
125 | 125 | ||
126 | struct mutex lock; | ||
126 | int fs; | 127 | int fs; |
127 | int deemph; | 128 | int deemph; |
128 | 129 | ||
@@ -457,7 +458,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, | |||
457 | if (deemph > 1) | 458 | if (deemph > 1) |
458 | return -EINVAL; | 459 | return -EINVAL; |
459 | 460 | ||
460 | mutex_lock(&codec->mutex); | 461 | mutex_lock(&wm8903->lock); |
461 | if (wm8903->deemph != deemph) { | 462 | if (wm8903->deemph != deemph) { |
462 | wm8903->deemph = deemph; | 463 | wm8903->deemph = deemph; |
463 | 464 | ||
@@ -465,7 +466,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol, | |||
465 | 466 | ||
466 | ret = 1; | 467 | ret = 1; |
467 | } | 468 | } |
468 | mutex_unlock(&codec->mutex); | 469 | mutex_unlock(&wm8903->lock); |
469 | 470 | ||
470 | return ret; | 471 | return ret; |
471 | } | 472 | } |
@@ -1757,21 +1758,12 @@ static struct snd_soc_dai_driver wm8903_dai = { | |||
1757 | .symmetric_rates = 1, | 1758 | .symmetric_rates = 1, |
1758 | }; | 1759 | }; |
1759 | 1760 | ||
1760 | static int wm8903_suspend(struct snd_soc_codec *codec) | ||
1761 | { | ||
1762 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1763 | |||
1764 | return 0; | ||
1765 | } | ||
1766 | |||
1767 | static int wm8903_resume(struct snd_soc_codec *codec) | 1761 | static int wm8903_resume(struct snd_soc_codec *codec) |
1768 | { | 1762 | { |
1769 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 1763 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
1770 | 1764 | ||
1771 | regcache_sync(wm8903->regmap); | 1765 | regcache_sync(wm8903->regmap); |
1772 | 1766 | ||
1773 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1774 | |||
1775 | return 0; | 1767 | return 0; |
1776 | } | 1768 | } |
1777 | 1769 | ||
@@ -1889,33 +1881,12 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903) | |||
1889 | } | 1881 | } |
1890 | #endif | 1882 | #endif |
1891 | 1883 | ||
1892 | static int wm8903_probe(struct snd_soc_codec *codec) | ||
1893 | { | ||
1894 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1895 | |||
1896 | wm8903->codec = codec; | ||
1897 | |||
1898 | /* power on device */ | ||
1899 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1900 | |||
1901 | return 0; | ||
1902 | } | ||
1903 | |||
1904 | /* power down chip */ | ||
1905 | static int wm8903_remove(struct snd_soc_codec *codec) | ||
1906 | { | ||
1907 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1908 | |||
1909 | return 0; | ||
1910 | } | ||
1911 | |||
1912 | static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { | 1884 | static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { |
1913 | .probe = wm8903_probe, | ||
1914 | .remove = wm8903_remove, | ||
1915 | .suspend = wm8903_suspend, | ||
1916 | .resume = wm8903_resume, | 1885 | .resume = wm8903_resume, |
1917 | .set_bias_level = wm8903_set_bias_level, | 1886 | .set_bias_level = wm8903_set_bias_level, |
1918 | .seq_notifier = wm8903_seq_notifier, | 1887 | .seq_notifier = wm8903_seq_notifier, |
1888 | .suspend_bias_off = true, | ||
1889 | |||
1919 | .controls = wm8903_snd_controls, | 1890 | .controls = wm8903_snd_controls, |
1920 | .num_controls = ARRAY_SIZE(wm8903_snd_controls), | 1891 | .num_controls = ARRAY_SIZE(wm8903_snd_controls), |
1921 | .dapm_widgets = wm8903_dapm_widgets, | 1892 | .dapm_widgets = wm8903_dapm_widgets, |
@@ -2023,6 +1994,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2023 | GFP_KERNEL); | 1994 | GFP_KERNEL); |
2024 | if (wm8903 == NULL) | 1995 | if (wm8903 == NULL) |
2025 | return -ENOMEM; | 1996 | return -ENOMEM; |
1997 | |||
1998 | mutex_init(&wm8903->lock); | ||
2026 | wm8903->dev = &i2c->dev; | 1999 | wm8903->dev = &i2c->dev; |
2027 | 2000 | ||
2028 | wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); | 2001 | wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 52011043e54c..e4142b4309eb 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -695,17 +695,6 @@ static struct snd_soc_dai_driver wm8940_dai = { | |||
695 | .symmetric_rates = 1, | 695 | .symmetric_rates = 1, |
696 | }; | 696 | }; |
697 | 697 | ||
698 | static int wm8940_suspend(struct snd_soc_codec *codec) | ||
699 | { | ||
700 | return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
701 | } | ||
702 | |||
703 | static int wm8940_resume(struct snd_soc_codec *codec) | ||
704 | { | ||
705 | wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static int wm8940_probe(struct snd_soc_codec *codec) | 698 | static int wm8940_probe(struct snd_soc_codec *codec) |
710 | { | 699 | { |
711 | struct wm8940_setup_data *pdata = codec->dev->platform_data; | 700 | struct wm8940_setup_data *pdata = codec->dev->platform_data; |
@@ -736,18 +725,11 @@ static int wm8940_probe(struct snd_soc_codec *codec) | |||
736 | return ret; | 725 | return ret; |
737 | } | 726 | } |
738 | 727 | ||
739 | static int wm8940_remove(struct snd_soc_codec *codec) | ||
740 | { | ||
741 | wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
742 | return 0; | ||
743 | } | ||
744 | |||
745 | static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { | 728 | static struct snd_soc_codec_driver soc_codec_dev_wm8940 = { |
746 | .probe = wm8940_probe, | 729 | .probe = wm8940_probe, |
747 | .remove = wm8940_remove, | ||
748 | .suspend = wm8940_suspend, | ||
749 | .resume = wm8940_resume, | ||
750 | .set_bias_level = wm8940_set_bias_level, | 730 | .set_bias_level = wm8940_set_bias_level, |
731 | .suspend_bias_off = true, | ||
732 | |||
751 | .controls = wm8940_snd_controls, | 733 | .controls = wm8940_snd_controls, |
752 | .num_controls = ARRAY_SIZE(wm8940_snd_controls), | 734 | .num_controls = ARRAY_SIZE(wm8940_snd_controls), |
753 | .dapm_widgets = wm8940_dapm_widgets, | 735 | .dapm_widgets = wm8940_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 09d91d9dc4ee..1173f7fef5a7 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -866,29 +866,6 @@ static struct snd_soc_dai_driver wm8955_dai = { | |||
866 | .ops = &wm8955_dai_ops, | 866 | .ops = &wm8955_dai_ops, |
867 | }; | 867 | }; |
868 | 868 | ||
869 | #ifdef CONFIG_PM | ||
870 | static int wm8955_suspend(struct snd_soc_codec *codec) | ||
871 | { | ||
872 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | ||
873 | |||
874 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
875 | |||
876 | regcache_mark_dirty(wm8955->regmap); | ||
877 | |||
878 | return 0; | ||
879 | } | ||
880 | |||
881 | static int wm8955_resume(struct snd_soc_codec *codec) | ||
882 | { | ||
883 | wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | #else | ||
888 | #define wm8955_suspend NULL | ||
889 | #define wm8955_resume NULL | ||
890 | #endif | ||
891 | |||
892 | static int wm8955_probe(struct snd_soc_codec *codec) | 869 | static int wm8955_probe(struct snd_soc_codec *codec) |
893 | { | 870 | { |
894 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); | 871 | struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec); |
@@ -964,18 +941,10 @@ err_enable: | |||
964 | return ret; | 941 | return ret; |
965 | } | 942 | } |
966 | 943 | ||
967 | static int wm8955_remove(struct snd_soc_codec *codec) | ||
968 | { | ||
969 | wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { | 944 | static struct snd_soc_codec_driver soc_codec_dev_wm8955 = { |
974 | .probe = wm8955_probe, | 945 | .probe = wm8955_probe, |
975 | .remove = wm8955_remove, | ||
976 | .suspend = wm8955_suspend, | ||
977 | .resume = wm8955_resume, | ||
978 | .set_bias_level = wm8955_set_bias_level, | 946 | .set_bias_level = wm8955_set_bias_level, |
947 | .suspend_bias_off = true, | ||
979 | 948 | ||
980 | .controls = wm8955_snd_controls, | 949 | .controls = wm8955_snd_controls, |
981 | .num_controls = ARRAY_SIZE(wm8955_snd_controls), | 950 | .num_controls = ARRAY_SIZE(wm8955_snd_controls), |
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index 0dada7f0105e..3cbc82b33292 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c | |||
@@ -867,9 +867,9 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context) | |||
867 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 867 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
868 | 868 | ||
869 | if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { | 869 | if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) { |
870 | mutex_lock(&codec->mutex); | 870 | mutex_lock(&wm8994->fw_lock); |
871 | wm8994->enh_eq = fw; | 871 | wm8994->enh_eq = fw; |
872 | mutex_unlock(&codec->mutex); | 872 | mutex_unlock(&wm8994->fw_lock); |
873 | } | 873 | } |
874 | } | 874 | } |
875 | 875 | ||
@@ -879,9 +879,9 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context) | |||
879 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 879 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
880 | 880 | ||
881 | if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { | 881 | if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) { |
882 | mutex_lock(&codec->mutex); | 882 | mutex_lock(&wm8994->fw_lock); |
883 | wm8994->mbc_vss = fw; | 883 | wm8994->mbc_vss = fw; |
884 | mutex_unlock(&codec->mutex); | 884 | mutex_unlock(&wm8994->fw_lock); |
885 | } | 885 | } |
886 | } | 886 | } |
887 | 887 | ||
@@ -891,9 +891,9 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context) | |||
891 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 891 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
892 | 892 | ||
893 | if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { | 893 | if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) { |
894 | mutex_lock(&codec->mutex); | 894 | mutex_lock(&wm8994->fw_lock); |
895 | wm8994->mbc = fw; | 895 | wm8994->mbc = fw; |
896 | mutex_unlock(&codec->mutex); | 896 | mutex_unlock(&wm8994->fw_lock); |
897 | } | 897 | } |
898 | } | 898 | } |
899 | 899 | ||
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 4dc4e85116cd..031a1ae71d94 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -125,9 +125,10 @@ struct wm8960_priv { | |||
125 | struct snd_soc_dapm_widget *out3; | 125 | struct snd_soc_dapm_widget *out3; |
126 | bool deemph; | 126 | bool deemph; |
127 | int playback_fs; | 127 | int playback_fs; |
128 | struct wm8960_data pdata; | ||
128 | }; | 129 | }; |
129 | 130 | ||
130 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) | 131 | #define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0) |
131 | 132 | ||
132 | /* enumerated controls */ | 133 | /* enumerated controls */ |
133 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", | 134 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", |
@@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = { | |||
440 | 441 | ||
441 | static int wm8960_add_widgets(struct snd_soc_codec *codec) | 442 | static int wm8960_add_widgets(struct snd_soc_codec *codec) |
442 | { | 443 | { |
443 | struct wm8960_data *pdata = codec->dev->platform_data; | ||
444 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 444 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
445 | struct wm8960_data *pdata = &wm8960->pdata; | ||
445 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 446 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
446 | struct snd_soc_dapm_widget *w; | 447 | struct snd_soc_dapm_widget *w; |
447 | 448 | ||
@@ -942,56 +943,15 @@ static struct snd_soc_dai_driver wm8960_dai = { | |||
942 | .symmetric_rates = 1, | 943 | .symmetric_rates = 1, |
943 | }; | 944 | }; |
944 | 945 | ||
945 | static int wm8960_suspend(struct snd_soc_codec *codec) | ||
946 | { | ||
947 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
948 | |||
949 | wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static int wm8960_resume(struct snd_soc_codec *codec) | ||
954 | { | ||
955 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
956 | |||
957 | wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | static int wm8960_probe(struct snd_soc_codec *codec) | 946 | static int wm8960_probe(struct snd_soc_codec *codec) |
962 | { | 947 | { |
963 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | 948 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); |
964 | struct wm8960_data *pdata = dev_get_platdata(codec->dev); | 949 | struct wm8960_data *pdata = &wm8960->pdata; |
965 | int ret; | ||
966 | |||
967 | wm8960->set_bias_level = wm8960_set_bias_level_out3; | ||
968 | |||
969 | if (!pdata) { | ||
970 | dev_warn(codec->dev, "No platform data supplied\n"); | ||
971 | } else { | ||
972 | if (pdata->capless) | ||
973 | wm8960->set_bias_level = wm8960_set_bias_level_capless; | ||
974 | } | ||
975 | |||
976 | ret = wm8960_reset(codec); | ||
977 | if (ret < 0) { | ||
978 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
979 | return ret; | ||
980 | } | ||
981 | |||
982 | wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
983 | 950 | ||
984 | /* Latch the update bits */ | 951 | if (pdata->capless) |
985 | snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100); | 952 | wm8960->set_bias_level = wm8960_set_bias_level_capless; |
986 | snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100); | 953 | else |
987 | snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100); | 954 | wm8960->set_bias_level = wm8960_set_bias_level_out3; |
988 | snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100); | ||
989 | snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100); | ||
990 | snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100); | ||
991 | snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100); | ||
992 | snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100); | ||
993 | snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100); | ||
994 | snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100); | ||
995 | 955 | ||
996 | snd_soc_add_codec_controls(codec, wm8960_snd_controls, | 956 | snd_soc_add_codec_controls(codec, wm8960_snd_controls, |
997 | ARRAY_SIZE(wm8960_snd_controls)); | 957 | ARRAY_SIZE(wm8960_snd_controls)); |
@@ -1000,21 +960,10 @@ static int wm8960_probe(struct snd_soc_codec *codec) | |||
1000 | return 0; | 960 | return 0; |
1001 | } | 961 | } |
1002 | 962 | ||
1003 | /* power down chip */ | ||
1004 | static int wm8960_remove(struct snd_soc_codec *codec) | ||
1005 | { | ||
1006 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
1007 | |||
1008 | wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { | 963 | static struct snd_soc_codec_driver soc_codec_dev_wm8960 = { |
1013 | .probe = wm8960_probe, | 964 | .probe = wm8960_probe, |
1014 | .remove = wm8960_remove, | ||
1015 | .suspend = wm8960_suspend, | ||
1016 | .resume = wm8960_resume, | ||
1017 | .set_bias_level = wm8960_set_bias_level, | 965 | .set_bias_level = wm8960_set_bias_level, |
966 | .suspend_bias_off = true, | ||
1018 | }; | 967 | }; |
1019 | 968 | ||
1020 | static const struct regmap_config wm8960_regmap = { | 969 | static const struct regmap_config wm8960_regmap = { |
@@ -1029,6 +978,18 @@ static const struct regmap_config wm8960_regmap = { | |||
1029 | .volatile_reg = wm8960_volatile, | 978 | .volatile_reg = wm8960_volatile, |
1030 | }; | 979 | }; |
1031 | 980 | ||
981 | static void wm8960_set_pdata_from_of(struct i2c_client *i2c, | ||
982 | struct wm8960_data *pdata) | ||
983 | { | ||
984 | const struct device_node *np = i2c->dev.of_node; | ||
985 | |||
986 | if (of_property_read_bool(np, "wlf,capless")) | ||
987 | pdata->capless = true; | ||
988 | |||
989 | if (of_property_read_bool(np, "wlf,shared-lrclk")) | ||
990 | pdata->shared_lrclk = true; | ||
991 | } | ||
992 | |||
1032 | static int wm8960_i2c_probe(struct i2c_client *i2c, | 993 | static int wm8960_i2c_probe(struct i2c_client *i2c, |
1033 | const struct i2c_device_id *id) | 994 | const struct i2c_device_id *id) |
1034 | { | 995 | { |
@@ -1045,7 +1006,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, | |||
1045 | if (IS_ERR(wm8960->regmap)) | 1006 | if (IS_ERR(wm8960->regmap)) |
1046 | return PTR_ERR(wm8960->regmap); | 1007 | return PTR_ERR(wm8960->regmap); |
1047 | 1008 | ||
1048 | if (pdata && pdata->shared_lrclk) { | 1009 | if (pdata) |
1010 | memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data)); | ||
1011 | else if (i2c->dev.of_node) | ||
1012 | wm8960_set_pdata_from_of(i2c, &wm8960->pdata); | ||
1013 | |||
1014 | ret = wm8960_reset(wm8960->regmap); | ||
1015 | if (ret != 0) { | ||
1016 | dev_err(&i2c->dev, "Failed to issue reset\n"); | ||
1017 | return ret; | ||
1018 | } | ||
1019 | |||
1020 | if (wm8960->pdata.shared_lrclk) { | ||
1049 | ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, | 1021 | ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2, |
1050 | 0x4, 0x4); | 1022 | 0x4, 0x4); |
1051 | if (ret != 0) { | 1023 | if (ret != 0) { |
@@ -1055,6 +1027,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, | |||
1055 | } | 1027 | } |
1056 | } | 1028 | } |
1057 | 1029 | ||
1030 | /* Latch the update bits */ | ||
1031 | regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100); | ||
1032 | regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100); | ||
1033 | regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100); | ||
1034 | regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100); | ||
1035 | regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100); | ||
1036 | regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100); | ||
1037 | regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100); | ||
1038 | regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100); | ||
1039 | regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100); | ||
1040 | regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100); | ||
1041 | |||
1058 | i2c_set_clientdata(i2c, wm8960); | 1042 | i2c_set_clientdata(i2c, wm8960); |
1059 | 1043 | ||
1060 | ret = snd_soc_register_codec(&i2c->dev, | 1044 | ret = snd_soc_register_codec(&i2c->dev, |
@@ -1075,10 +1059,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = { | |||
1075 | }; | 1059 | }; |
1076 | MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); | 1060 | MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id); |
1077 | 1061 | ||
1062 | static const struct of_device_id wm8960_of_match[] = { | ||
1063 | { .compatible = "wlf,wm8960", }, | ||
1064 | { } | ||
1065 | }; | ||
1066 | MODULE_DEVICE_TABLE(of, wm8960_of_match); | ||
1067 | |||
1078 | static struct i2c_driver wm8960_i2c_driver = { | 1068 | static struct i2c_driver wm8960_i2c_driver = { |
1079 | .driver = { | 1069 | .driver = { |
1080 | .name = "wm8960", | 1070 | .name = "wm8960", |
1081 | .owner = THIS_MODULE, | 1071 | .owner = THIS_MODULE, |
1072 | .of_match_table = wm8960_of_match, | ||
1082 | }, | 1073 | }, |
1083 | .probe = wm8960_i2c_probe, | 1074 | .probe = wm8960_i2c_probe, |
1084 | .remove = wm8960_i2c_remove, | 1075 | .remove = wm8960_i2c_remove, |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 41d23e920ad5..eeffd05384b4 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -835,7 +835,6 @@ static struct snd_soc_dai_driver wm8961_dai = { | |||
835 | 835 | ||
836 | static int wm8961_probe(struct snd_soc_codec *codec) | 836 | static int wm8961_probe(struct snd_soc_codec *codec) |
837 | { | 837 | { |
838 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
839 | u16 reg; | 838 | u16 reg; |
840 | 839 | ||
841 | /* Enable class W */ | 840 | /* Enable class W */ |
@@ -871,50 +870,33 @@ static int wm8961_probe(struct snd_soc_codec *codec) | |||
871 | reg &= ~WM8961_MANUAL_MODE; | 870 | reg &= ~WM8961_MANUAL_MODE; |
872 | snd_soc_write(codec, WM8961_CLOCKING_3, reg); | 871 | snd_soc_write(codec, WM8961_CLOCKING_3, reg); |
873 | 872 | ||
874 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
875 | |||
876 | snd_soc_add_codec_controls(codec, wm8961_snd_controls, | ||
877 | ARRAY_SIZE(wm8961_snd_controls)); | ||
878 | snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets, | ||
879 | ARRAY_SIZE(wm8961_dapm_widgets)); | ||
880 | snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int wm8961_remove(struct snd_soc_codec *codec) | ||
886 | { | ||
887 | wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
888 | return 0; | 873 | return 0; |
889 | } | 874 | } |
890 | 875 | ||
891 | #ifdef CONFIG_PM | 876 | #ifdef CONFIG_PM |
892 | static int wm8961_suspend(struct snd_soc_codec *codec) | ||
893 | { | ||
894 | wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
895 | |||
896 | return 0; | ||
897 | } | ||
898 | 877 | ||
899 | static int wm8961_resume(struct snd_soc_codec *codec) | 878 | static int wm8961_resume(struct snd_soc_codec *codec) |
900 | { | 879 | { |
901 | snd_soc_cache_sync(codec); | 880 | snd_soc_cache_sync(codec); |
902 | 881 | ||
903 | wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
904 | |||
905 | return 0; | 882 | return 0; |
906 | } | 883 | } |
907 | #else | 884 | #else |
908 | #define wm8961_suspend NULL | ||
909 | #define wm8961_resume NULL | 885 | #define wm8961_resume NULL |
910 | #endif | 886 | #endif |
911 | 887 | ||
912 | static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { | 888 | static struct snd_soc_codec_driver soc_codec_dev_wm8961 = { |
913 | .probe = wm8961_probe, | 889 | .probe = wm8961_probe, |
914 | .remove = wm8961_remove, | ||
915 | .suspend = wm8961_suspend, | ||
916 | .resume = wm8961_resume, | 890 | .resume = wm8961_resume, |
917 | .set_bias_level = wm8961_set_bias_level, | 891 | .set_bias_level = wm8961_set_bias_level, |
892 | .suspend_bias_off = true, | ||
893 | |||
894 | .controls = wm8961_snd_controls, | ||
895 | .num_controls = ARRAY_SIZE(wm8961_snd_controls), | ||
896 | .dapm_widgets = wm8961_dapm_widgets, | ||
897 | .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets), | ||
898 | .dapm_routes = audio_paths, | ||
899 | .num_dapm_routes = ARRAY_SIZE(audio_paths), | ||
918 | }; | 900 | }; |
919 | 901 | ||
920 | static const struct regmap_config wm8961_regmap = { | 902 | static const struct regmap_config wm8961_regmap = { |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 9077411e62ce..1534d88a66e9 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/regulator/consumer.h> | 26 | #include <linux/regulator/consumer.h> |
27 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/mutex.h> | ||
29 | #include <sound/core.h> | 30 | #include <sound/core.h> |
30 | #include <sound/jack.h> | 31 | #include <sound/jack.h> |
31 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
@@ -67,6 +68,7 @@ struct wm8962_priv { | |||
67 | int fll_fref; | 68 | int fll_fref; |
68 | int fll_fout; | 69 | int fll_fout; |
69 | 70 | ||
71 | struct mutex dsp2_ena_lock; | ||
70 | u16 dsp2_ena; | 72 | u16 dsp2_ena; |
71 | 73 | ||
72 | struct delayed_work mic_work; | 74 | struct delayed_work mic_work; |
@@ -1570,7 +1572,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, | |||
1570 | int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & | 1572 | int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) & |
1571 | WM8962_DSP2_ENA; | 1573 | WM8962_DSP2_ENA; |
1572 | 1574 | ||
1573 | mutex_lock(&codec->mutex); | 1575 | mutex_lock(&wm8962->dsp2_ena_lock); |
1574 | 1576 | ||
1575 | if (ucontrol->value.integer.value[0]) | 1577 | if (ucontrol->value.integer.value[0]) |
1576 | wm8962->dsp2_ena |= 1 << shift; | 1578 | wm8962->dsp2_ena |= 1 << shift; |
@@ -1590,7 +1592,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol, | |||
1590 | } | 1592 | } |
1591 | 1593 | ||
1592 | out: | 1594 | out: |
1593 | mutex_unlock(&codec->mutex); | 1595 | mutex_unlock(&wm8962->dsp2_ena_lock); |
1594 | 1596 | ||
1595 | return ret; | 1597 | return ret; |
1596 | } | 1598 | } |
@@ -3552,11 +3554,12 @@ static int wm8962_i2c_probe(struct i2c_client *i2c, | |||
3552 | unsigned int reg; | 3554 | unsigned int reg; |
3553 | int ret, i, irq_pol, trigger; | 3555 | int ret, i, irq_pol, trigger; |
3554 | 3556 | ||
3555 | wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv), | 3557 | wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL); |
3556 | GFP_KERNEL); | ||
3557 | if (wm8962 == NULL) | 3558 | if (wm8962 == NULL) |
3558 | return -ENOMEM; | 3559 | return -ENOMEM; |
3559 | 3560 | ||
3561 | mutex_init(&wm8962->dsp2_ena_lock); | ||
3562 | |||
3560 | i2c_set_clientdata(i2c, wm8962); | 3563 | i2c_set_clientdata(i2c, wm8962); |
3561 | 3564 | ||
3562 | INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); | 3565 | INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work); |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 682e9eda1019..ff0e4646b934 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -568,18 +568,6 @@ static struct snd_soc_dai_driver wm8974_dai = { | |||
568 | .symmetric_rates = 1, | 568 | .symmetric_rates = 1, |
569 | }; | 569 | }; |
570 | 570 | ||
571 | static int wm8974_suspend(struct snd_soc_codec *codec) | ||
572 | { | ||
573 | wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | static int wm8974_resume(struct snd_soc_codec *codec) | ||
578 | { | ||
579 | wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static const struct regmap_config wm8974_regmap = { | 571 | static const struct regmap_config wm8974_regmap = { |
584 | .reg_bits = 7, | 572 | .reg_bits = 7, |
585 | .val_bits = 9, | 573 | .val_bits = 9, |
@@ -599,24 +587,13 @@ static int wm8974_probe(struct snd_soc_codec *codec) | |||
599 | return ret; | 587 | return ret; |
600 | } | 588 | } |
601 | 589 | ||
602 | wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
603 | |||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | /* power down chip */ | ||
608 | static int wm8974_remove(struct snd_soc_codec *codec) | ||
609 | { | ||
610 | wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
611 | return 0; | 590 | return 0; |
612 | } | 591 | } |
613 | 592 | ||
614 | static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { | 593 | static struct snd_soc_codec_driver soc_codec_dev_wm8974 = { |
615 | .probe = wm8974_probe, | 594 | .probe = wm8974_probe, |
616 | .remove = wm8974_remove, | ||
617 | .suspend = wm8974_suspend, | ||
618 | .resume = wm8974_resume, | ||
619 | .set_bias_level = wm8974_set_bias_level, | 595 | .set_bias_level = wm8974_set_bias_level, |
596 | .suspend_bias_off = true, | ||
620 | 597 | ||
621 | .controls = wm8974_snd_controls, | 598 | .controls = wm8974_snd_controls, |
622 | .num_controls = ARRAY_SIZE(wm8974_snd_controls), | 599 | .num_controls = ARRAY_SIZE(wm8974_snd_controls), |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index ee2ba574952b..cf7032911721 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -991,21 +991,11 @@ static int wm8978_probe(struct snd_soc_codec *codec) | |||
991 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) | 991 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) |
992 | snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); | 992 | snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); |
993 | 993 | ||
994 | wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | /* power down chip */ | ||
1000 | static int wm8978_remove(struct snd_soc_codec *codec) | ||
1001 | { | ||
1002 | wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1003 | return 0; | 994 | return 0; |
1004 | } | 995 | } |
1005 | 996 | ||
1006 | static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { | 997 | static struct snd_soc_codec_driver soc_codec_dev_wm8978 = { |
1007 | .probe = wm8978_probe, | 998 | .probe = wm8978_probe, |
1008 | .remove = wm8978_remove, | ||
1009 | .suspend = wm8978_suspend, | 999 | .suspend = wm8978_suspend, |
1010 | .resume = wm8978_resume, | 1000 | .resume = wm8978_resume, |
1011 | .set_bias_level = wm8978_set_bias_level, | 1001 | .set_bias_level = wm8978_set_bias_level, |
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index ac5defda8824..5d1cf08a72b8 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c | |||
@@ -967,29 +967,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec, | |||
967 | return 0; | 967 | return 0; |
968 | } | 968 | } |
969 | 969 | ||
970 | #ifdef CONFIG_PM | ||
971 | static int wm8983_suspend(struct snd_soc_codec *codec) | ||
972 | { | ||
973 | wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | static int wm8983_resume(struct snd_soc_codec *codec) | ||
978 | { | ||
979 | wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
980 | return 0; | ||
981 | } | ||
982 | #else | ||
983 | #define wm8983_suspend NULL | ||
984 | #define wm8983_resume NULL | ||
985 | #endif | ||
986 | |||
987 | static int wm8983_remove(struct snd_soc_codec *codec) | ||
988 | { | ||
989 | wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int wm8983_probe(struct snd_soc_codec *codec) | 970 | static int wm8983_probe(struct snd_soc_codec *codec) |
994 | { | 971 | { |
995 | int ret; | 972 | int ret; |
@@ -1055,10 +1032,8 @@ static struct snd_soc_dai_driver wm8983_dai = { | |||
1055 | 1032 | ||
1056 | static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { | 1033 | static struct snd_soc_codec_driver soc_codec_dev_wm8983 = { |
1057 | .probe = wm8983_probe, | 1034 | .probe = wm8983_probe, |
1058 | .remove = wm8983_remove, | ||
1059 | .suspend = wm8983_suspend, | ||
1060 | .resume = wm8983_resume, | ||
1061 | .set_bias_level = wm8983_set_bias_level, | 1035 | .set_bias_level = wm8983_set_bias_level, |
1036 | .suspend_bias_off = true, | ||
1062 | .controls = wm8983_snd_controls, | 1037 | .controls = wm8983_snd_controls, |
1063 | .num_controls = ARRAY_SIZE(wm8983_snd_controls), | 1038 | .num_controls = ARRAY_SIZE(wm8983_snd_controls), |
1064 | .dapm_widgets = wm8983_dapm_widgets, | 1039 | .dapm_widgets = wm8983_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index ee380190399f..0b3b54c9971d 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
@@ -961,29 +961,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec, | |||
961 | return 0; | 961 | return 0; |
962 | } | 962 | } |
963 | 963 | ||
964 | #ifdef CONFIG_PM | ||
965 | static int wm8985_suspend(struct snd_soc_codec *codec) | ||
966 | { | ||
967 | wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static int wm8985_resume(struct snd_soc_codec *codec) | ||
972 | { | ||
973 | wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
974 | return 0; | ||
975 | } | ||
976 | #else | ||
977 | #define wm8985_suspend NULL | ||
978 | #define wm8985_resume NULL | ||
979 | #endif | ||
980 | |||
981 | static int wm8985_remove(struct snd_soc_codec *codec) | ||
982 | { | ||
983 | wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int wm8985_probe(struct snd_soc_codec *codec) | 964 | static int wm8985_probe(struct snd_soc_codec *codec) |
988 | { | 965 | { |
989 | size_t i; | 966 | size_t i; |
@@ -1023,7 +1000,6 @@ static int wm8985_probe(struct snd_soc_codec *codec) | |||
1023 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, | 1000 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, |
1024 | WM8985_BIASCUT); | 1001 | WM8985_BIASCUT); |
1025 | 1002 | ||
1026 | wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1027 | return 0; | 1003 | return 0; |
1028 | 1004 | ||
1029 | err_reg_enable: | 1005 | err_reg_enable: |
@@ -1064,10 +1040,8 @@ static struct snd_soc_dai_driver wm8985_dai = { | |||
1064 | 1040 | ||
1065 | static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { | 1041 | static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { |
1066 | .probe = wm8985_probe, | 1042 | .probe = wm8985_probe, |
1067 | .remove = wm8985_remove, | ||
1068 | .suspend = wm8985_suspend, | ||
1069 | .resume = wm8985_resume, | ||
1070 | .set_bias_level = wm8985_set_bias_level, | 1043 | .set_bias_level = wm8985_set_bias_level, |
1044 | .suspend_bias_off = true, | ||
1071 | 1045 | ||
1072 | .controls = wm8985_snd_controls, | 1046 | .controls = wm8985_snd_controls, |
1073 | .num_controls = ARRAY_SIZE(wm8985_snd_controls), | 1047 | .num_controls = ARRAY_SIZE(wm8985_snd_controls), |
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index a5130d965146..e418199155a8 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c | |||
@@ -793,21 +793,6 @@ static struct snd_soc_dai_driver wm8988_dai = { | |||
793 | .symmetric_rates = 1, | 793 | .symmetric_rates = 1, |
794 | }; | 794 | }; |
795 | 795 | ||
796 | static int wm8988_suspend(struct snd_soc_codec *codec) | ||
797 | { | ||
798 | struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); | ||
799 | |||
800 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
801 | regcache_mark_dirty(wm8988->regmap); | ||
802 | return 0; | ||
803 | } | ||
804 | |||
805 | static int wm8988_resume(struct snd_soc_codec *codec) | ||
806 | { | ||
807 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | static int wm8988_probe(struct snd_soc_codec *codec) | 796 | static int wm8988_probe(struct snd_soc_codec *codec) |
812 | { | 797 | { |
813 | int ret = 0; | 798 | int ret = 0; |
@@ -825,23 +810,13 @@ static int wm8988_probe(struct snd_soc_codec *codec) | |||
825 | snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100); | 810 | snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100); |
826 | snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100); | 811 | snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100); |
827 | 812 | ||
828 | wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int wm8988_remove(struct snd_soc_codec *codec) | ||
834 | { | ||
835 | wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
836 | return 0; | 813 | return 0; |
837 | } | 814 | } |
838 | 815 | ||
839 | static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { | 816 | static struct snd_soc_codec_driver soc_codec_dev_wm8988 = { |
840 | .probe = wm8988_probe, | 817 | .probe = wm8988_probe, |
841 | .remove = wm8988_remove, | ||
842 | .suspend = wm8988_suspend, | ||
843 | .resume = wm8988_resume, | ||
844 | .set_bias_level = wm8988_set_bias_level, | 818 | .set_bias_level = wm8988_set_bias_level, |
819 | .suspend_bias_off = true, | ||
845 | 820 | ||
846 | .controls = wm8988_snd_controls, | 821 | .controls = wm8988_snd_controls, |
847 | .num_controls = ARRAY_SIZE(wm8988_snd_controls), | 822 | .num_controls = ARRAY_SIZE(wm8988_snd_controls), |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 03e43e3f395e..8a584229310a 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -1271,18 +1271,6 @@ static struct snd_soc_dai_driver wm8990_dai = { | |||
1271 | .ops = &wm8990_dai_ops, | 1271 | .ops = &wm8990_dai_ops, |
1272 | }; | 1272 | }; |
1273 | 1273 | ||
1274 | static int wm8990_suspend(struct snd_soc_codec *codec) | ||
1275 | { | ||
1276 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | static int wm8990_resume(struct snd_soc_codec *codec) | ||
1281 | { | ||
1282 | wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | /* | 1274 | /* |
1287 | * initialise the WM8990 driver | 1275 | * initialise the WM8990 driver |
1288 | * register the mixer and dsp interfaces with the kernel | 1276 | * register the mixer and dsp interfaces with the kernel |
@@ -1309,19 +1297,11 @@ static int wm8990_probe(struct snd_soc_codec *codec) | |||
1309 | return 0; | 1297 | return 0; |
1310 | } | 1298 | } |
1311 | 1299 | ||
1312 | /* power down chip */ | ||
1313 | static int wm8990_remove(struct snd_soc_codec *codec) | ||
1314 | { | ||
1315 | wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { | 1300 | static struct snd_soc_codec_driver soc_codec_dev_wm8990 = { |
1320 | .probe = wm8990_probe, | 1301 | .probe = wm8990_probe, |
1321 | .remove = wm8990_remove, | ||
1322 | .suspend = wm8990_suspend, | ||
1323 | .resume = wm8990_resume, | ||
1324 | .set_bias_level = wm8990_set_bias_level, | 1302 | .set_bias_level = wm8990_set_bias_level, |
1303 | .suspend_bias_off = true, | ||
1304 | |||
1325 | .controls = wm8990_snd_controls, | 1305 | .controls = wm8990_snd_controls, |
1326 | .num_controls = ARRAY_SIZE(wm8990_snd_controls), | 1306 | .num_controls = ARRAY_SIZE(wm8990_snd_controls), |
1327 | .dapm_widgets = wm8990_dapm_widgets, | 1307 | .dapm_widgets = wm8990_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index d0be89731cdb..b0ac2c3e31b9 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c | |||
@@ -1227,32 +1227,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec, | |||
1227 | return 0; | 1227 | return 0; |
1228 | } | 1228 | } |
1229 | 1229 | ||
1230 | static int wm8991_suspend(struct snd_soc_codec *codec) | ||
1231 | { | ||
1232 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1233 | return 0; | ||
1234 | } | ||
1235 | |||
1236 | static int wm8991_resume(struct snd_soc_codec *codec) | ||
1237 | { | ||
1238 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1239 | return 0; | ||
1240 | } | ||
1241 | |||
1242 | /* power down chip */ | ||
1243 | static int wm8991_remove(struct snd_soc_codec *codec) | ||
1244 | { | ||
1245 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | static int wm8991_probe(struct snd_soc_codec *codec) | ||
1250 | { | ||
1251 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1252 | |||
1253 | return 0; | ||
1254 | } | ||
1255 | |||
1256 | #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1230 | #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1257 | SNDRV_PCM_FMTBIT_S24_LE) | 1231 | SNDRV_PCM_FMTBIT_S24_LE) |
1258 | 1232 | ||
@@ -1293,11 +1267,9 @@ static struct snd_soc_dai_driver wm8991_dai = { | |||
1293 | }; | 1267 | }; |
1294 | 1268 | ||
1295 | static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { | 1269 | static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { |
1296 | .probe = wm8991_probe, | ||
1297 | .remove = wm8991_remove, | ||
1298 | .suspend = wm8991_suspend, | ||
1299 | .resume = wm8991_resume, | ||
1300 | .set_bias_level = wm8991_set_bias_level, | 1270 | .set_bias_level = wm8991_set_bias_level, |
1271 | .suspend_bias_off = true, | ||
1272 | |||
1301 | .controls = wm8991_snd_controls, | 1273 | .controls = wm8991_snd_controls, |
1302 | .num_controls = ARRAY_SIZE(wm8991_snd_controls), | 1274 | .num_controls = ARRAY_SIZE(wm8991_snd_controls), |
1303 | .dapm_widgets = wm8991_dapm_widgets, | 1275 | .dapm_widgets = wm8991_dapm_widgets, |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1fcb9f3f3097..36b767fa37a6 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -4391,8 +4391,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
4391 | struct wm8994 *control = wm8994->wm8994; | 4391 | struct wm8994 *control = wm8994->wm8994; |
4392 | int i; | 4392 | int i; |
4393 | 4393 | ||
4394 | wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
4395 | |||
4396 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) | 4394 | for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++) |
4397 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, | 4395 | wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i, |
4398 | &wm8994->fll_locked[i]); | 4396 | &wm8994->fll_locked[i]); |
@@ -4457,6 +4455,8 @@ static int wm8994_probe(struct platform_device *pdev) | |||
4457 | return -ENOMEM; | 4455 | return -ENOMEM; |
4458 | platform_set_drvdata(pdev, wm8994); | 4456 | platform_set_drvdata(pdev, wm8994); |
4459 | 4457 | ||
4458 | mutex_init(&wm8994->fw_lock); | ||
4459 | |||
4460 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); | 4460 | wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent); |
4461 | 4461 | ||
4462 | pm_runtime_enable(&pdev->dev); | 4462 | pm_runtime_enable(&pdev->dev); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 6536f8d45ac6..dd73387b1cc4 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/firmware.h> | 13 | #include <linux/firmware.h> |
14 | #include <linux/completion.h> | 14 | #include <linux/completion.h> |
15 | #include <linux/workqueue.h> | 15 | #include <linux/workqueue.h> |
16 | #include <linux/mutex.h> | ||
16 | 17 | ||
17 | #include "wm_hubs.h" | 18 | #include "wm_hubs.h" |
18 | 19 | ||
@@ -156,6 +157,7 @@ struct wm8994_priv { | |||
156 | unsigned int aif1clk_disable:1; | 157 | unsigned int aif1clk_disable:1; |
157 | unsigned int aif2clk_disable:1; | 158 | unsigned int aif2clk_disable:1; |
158 | 159 | ||
160 | struct mutex fw_lock; | ||
159 | int dsp_active; | 161 | int dsp_active; |
160 | const struct firmware *cur_fw; | 162 | const struct firmware *cur_fw; |
161 | const struct firmware *mbc; | 163 | const struct firmware *mbc; |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 1288edeb8c7d..c280f0a3a424 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -2004,7 +2004,6 @@ static int wm8995_remove(struct snd_soc_codec *codec) | |||
2004 | int i; | 2004 | int i; |
2005 | 2005 | ||
2006 | wm8995 = snd_soc_codec_get_drvdata(codec); | 2006 | wm8995 = snd_soc_codec_get_drvdata(codec); |
2007 | wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2008 | 2007 | ||
2009 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) | 2008 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i) |
2010 | regulator_unregister_notifier(wm8995->supplies[i].consumer, | 2009 | regulator_unregister_notifier(wm8995->supplies[i].consumer, |
@@ -2078,8 +2077,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
2078 | goto err_reg_enable; | 2077 | goto err_reg_enable; |
2079 | } | 2078 | } |
2080 | 2079 | ||
2081 | wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2082 | |||
2083 | /* Latch volume updates (right only; we always do left then right). */ | 2080 | /* Latch volume updates (right only; we always do left then right). */ |
2084 | snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME, | 2081 | snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME, |
2085 | WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU); | 2082 | WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU); |
@@ -2102,13 +2099,6 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
2102 | 2099 | ||
2103 | wm8995_update_class_w(codec); | 2100 | wm8995_update_class_w(codec); |
2104 | 2101 | ||
2105 | snd_soc_add_codec_controls(codec, wm8995_snd_controls, | ||
2106 | ARRAY_SIZE(wm8995_snd_controls)); | ||
2107 | snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets, | ||
2108 | ARRAY_SIZE(wm8995_dapm_widgets)); | ||
2109 | snd_soc_dapm_add_routes(&codec->dapm, wm8995_intercon, | ||
2110 | ARRAY_SIZE(wm8995_intercon)); | ||
2111 | |||
2112 | return 0; | 2102 | return 0; |
2113 | 2103 | ||
2114 | err_reg_enable: | 2104 | err_reg_enable: |
@@ -2205,6 +2195,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { | |||
2205 | .remove = wm8995_remove, | 2195 | .remove = wm8995_remove, |
2206 | .set_bias_level = wm8995_set_bias_level, | 2196 | .set_bias_level = wm8995_set_bias_level, |
2207 | .idle_bias_off = true, | 2197 | .idle_bias_off = true, |
2198 | |||
2199 | .controls = wm8995_snd_controls, | ||
2200 | .num_controls = ARRAY_SIZE(wm8995_snd_controls), | ||
2201 | .dapm_widgets = wm8995_dapm_widgets, | ||
2202 | .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets), | ||
2203 | .dapm_routes = wm8995_intercon, | ||
2204 | .num_dapm_routes = ARRAY_SIZE(wm8995_intercon), | ||
2208 | }; | 2205 | }; |
2209 | 2206 | ||
2210 | static struct regmap_config wm8995_regmap = { | 2207 | static struct regmap_config wm8995_regmap = { |
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 0cdc9e2184ab..b1d946facd57 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -1277,15 +1277,8 @@ static int wm9081_probe(struct snd_soc_codec *codec) | |||
1277 | return 0; | 1277 | return 0; |
1278 | } | 1278 | } |
1279 | 1279 | ||
1280 | static int wm9081_remove(struct snd_soc_codec *codec) | ||
1281 | { | ||
1282 | wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1283 | return 0; | ||
1284 | } | ||
1285 | |||
1286 | static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { | 1280 | static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { |
1287 | .probe = wm9081_probe, | 1281 | .probe = wm9081_probe, |
1288 | .remove = wm9081_remove, | ||
1289 | 1282 | ||
1290 | .set_sysclk = wm9081_set_sysclk, | 1283 | .set_sysclk = wm9081_set_sysclk, |
1291 | .set_bias_level = wm9081_set_bias_level, | 1284 | .set_bias_level = wm9081_set_bias_level, |
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index c0b7f45dfa37..d3a800fa6f06 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
@@ -203,13 +203,14 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = { | |||
203 | /* We use a register cache to enhance read performance. */ | 203 | /* We use a register cache to enhance read performance. */ |
204 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | 204 | static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) |
205 | { | 205 | { |
206 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
206 | u16 *cache = codec->reg_cache; | 207 | u16 *cache = codec->reg_cache; |
207 | 208 | ||
208 | switch (reg) { | 209 | switch (reg) { |
209 | case AC97_RESET: | 210 | case AC97_RESET: |
210 | case AC97_VENDOR_ID1: | 211 | case AC97_VENDOR_ID1: |
211 | case AC97_VENDOR_ID2: | 212 | case AC97_VENDOR_ID2: |
212 | return soc_ac97_ops->read(codec->ac97, reg); | 213 | return soc_ac97_ops->read(ac97, reg); |
213 | default: | 214 | default: |
214 | reg = reg >> 1; | 215 | reg = reg >> 1; |
215 | 216 | ||
@@ -223,9 +224,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) | |||
223 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 224 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
224 | unsigned int val) | 225 | unsigned int val) |
225 | { | 226 | { |
227 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
226 | u16 *cache = codec->reg_cache; | 228 | u16 *cache = codec->reg_cache; |
227 | 229 | ||
228 | soc_ac97_ops->write(codec->ac97, reg, val); | 230 | soc_ac97_ops->write(ac97, reg, val); |
229 | reg = reg >> 1; | 231 | reg = reg >> 1; |
230 | if (reg < (ARRAY_SIZE(wm9705_reg))) | 232 | if (reg < (ARRAY_SIZE(wm9705_reg))) |
231 | cache[reg] = val; | 233 | cache[reg] = val; |
@@ -263,7 +265,6 @@ static const struct snd_soc_dai_ops wm9705_dai_ops = { | |||
263 | static struct snd_soc_dai_driver wm9705_dai[] = { | 265 | static struct snd_soc_dai_driver wm9705_dai[] = { |
264 | { | 266 | { |
265 | .name = "wm9705-hifi", | 267 | .name = "wm9705-hifi", |
266 | .ac97_control = 1, | ||
267 | .playback = { | 268 | .playback = { |
268 | .stream_name = "HiFi Playback", | 269 | .stream_name = "HiFi Playback", |
269 | .channels_min = 1, | 270 | .channels_min = 1, |
@@ -294,36 +295,41 @@ static struct snd_soc_dai_driver wm9705_dai[] = { | |||
294 | 295 | ||
295 | static int wm9705_reset(struct snd_soc_codec *codec) | 296 | static int wm9705_reset(struct snd_soc_codec *codec) |
296 | { | 297 | { |
298 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
299 | |||
297 | if (soc_ac97_ops->reset) { | 300 | if (soc_ac97_ops->reset) { |
298 | soc_ac97_ops->reset(codec->ac97); | 301 | soc_ac97_ops->reset(ac97); |
299 | if (ac97_read(codec, 0) == wm9705_reg[0]) | 302 | if (ac97_read(codec, 0) == wm9705_reg[0]) |
300 | return 0; /* Success */ | 303 | return 0; /* Success */ |
301 | } | 304 | } |
302 | 305 | ||
306 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); | ||
307 | |||
303 | return -EIO; | 308 | return -EIO; |
304 | } | 309 | } |
305 | 310 | ||
306 | #ifdef CONFIG_PM | 311 | #ifdef CONFIG_PM |
307 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) | 312 | static int wm9705_soc_suspend(struct snd_soc_codec *codec) |
308 | { | 313 | { |
309 | soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff); | 314 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
315 | |||
316 | soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff); | ||
310 | 317 | ||
311 | return 0; | 318 | return 0; |
312 | } | 319 | } |
313 | 320 | ||
314 | static int wm9705_soc_resume(struct snd_soc_codec *codec) | 321 | static int wm9705_soc_resume(struct snd_soc_codec *codec) |
315 | { | 322 | { |
323 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); | ||
316 | int i, ret; | 324 | int i, ret; |
317 | u16 *cache = codec->reg_cache; | 325 | u16 *cache = codec->reg_cache; |
318 | 326 | ||
319 | ret = wm9705_reset(codec); | 327 | ret = wm9705_reset(codec); |
320 | if (ret < 0) { | 328 | if (ret < 0) |
321 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
322 | return ret; | 329 | return ret; |
323 | } | ||
324 | 330 | ||
325 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { | 331 | for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) { |
326 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 332 | soc_ac97_ops->write(ac97, i, cache[i>>1]); |
327 | } | 333 | } |
328 | 334 | ||
329 | return 0; | 335 | return 0; |
@@ -335,31 +341,34 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) | |||
335 | 341 | ||
336 | static int wm9705_soc_probe(struct snd_soc_codec *codec) | 342 | static int wm9705_soc_probe(struct snd_soc_codec *codec) |
337 | { | 343 | { |
344 | struct snd_ac97 *ac97; | ||
338 | int ret = 0; | 345 | int ret = 0; |
339 | 346 | ||
340 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 347 | ac97 = snd_soc_new_ac97_codec(codec); |
341 | if (ret < 0) { | 348 | if (IS_ERR(ac97)) { |
342 | printk(KERN_ERR "wm9705: failed to register AC97 codec\n"); | 349 | ret = PTR_ERR(ac97); |
350 | dev_err(codec->dev, "Failed to register AC97 codec\n"); | ||
343 | return ret; | 351 | return ret; |
344 | } | 352 | } |
345 | 353 | ||
354 | snd_soc_codec_set_drvdata(codec, ac97); | ||
355 | |||
346 | ret = wm9705_reset(codec); | 356 | ret = wm9705_reset(codec); |
347 | if (ret) | 357 | if (ret) |
348 | goto reset_err; | 358 | goto reset_err; |
349 | 359 | ||
350 | snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls, | ||
351 | ARRAY_SIZE(wm9705_snd_ac97_controls)); | ||
352 | |||
353 | return 0; | 360 | return 0; |
354 | 361 | ||
355 | reset_err: | 362 | reset_err: |
356 | snd_soc_free_ac97_codec(codec); | 363 | snd_soc_free_ac97_codec(ac97); |
357 | return ret; | 364 | return ret; |
358 | } | 365 | } |
359 | 366 | ||
360 | static int wm9705_soc_remove(struct snd_soc_codec *codec) | 367 | static int wm9705_soc_remove(struct snd_soc_codec *codec) |
361 | { | 368 | { |
362 | snd_soc_free_ac97_codec(codec); | 369 | struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); |
370 | |||
371 | snd_soc_free_ac97_codec(ac97); | ||
363 | return 0; | 372 | return 0; |
364 | } | 373 | } |
365 | 374 | ||
@@ -374,6 +383,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = { | |||
374 | .reg_word_size = sizeof(u16), | 383 | .reg_word_size = sizeof(u16), |
375 | .reg_cache_step = 2, | 384 | .reg_cache_step = 2, |
376 | .reg_cache_default = wm9705_reg, | 385 | .reg_cache_default = wm9705_reg, |
386 | |||
387 | .controls = wm9705_snd_ac97_controls, | ||
388 | .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls), | ||
377 | .dapm_widgets = wm9705_dapm_widgets, | 389 | .dapm_widgets = wm9705_dapm_widgets, |
378 | .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), | 390 | .num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets), |
379 | .dapm_routes = wm9705_audio_map, | 391 | .dapm_routes = wm9705_audio_map, |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index c5eb746087b4..52a211be5b47 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -23,6 +23,12 @@ | |||
23 | #include <sound/tlv.h> | 23 | #include <sound/tlv.h> |
24 | #include "wm9712.h" | 24 | #include "wm9712.h" |
25 | 25 | ||
26 | struct wm9712_priv { | ||
27 | struct snd_ac97 *ac97; | ||
28 | unsigned int hp_mixer[2]; | ||
29 | struct mutex lock; | ||
30 | }; | ||
31 | |||
26 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 32 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
27 | unsigned int reg); | 33 | unsigned int reg); |
28 | static int ac97_write(struct snd_soc_codec *codec, | 34 | static int ac97_write(struct snd_soc_codec *codec, |
@@ -48,12 +54,10 @@ static const u16 wm9712_reg[] = { | |||
48 | 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ | 54 | 0x0000, 0x0000, 0x0000, 0x0000, /* 6e */ |
49 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ | 55 | 0x0000, 0x0000, 0x0000, 0x0006, /* 76 */ |
50 | 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ | 56 | 0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */ |
51 | 0x0000, 0x0000 /* virtual hp mixers */ | ||
52 | }; | 57 | }; |
53 | 58 | ||
54 | /* virtual HP mixers regs */ | 59 | #define HPL_MIXER 0x0 |
55 | #define HPL_MIXER 0x80 | 60 | #define HPR_MIXER 0x1 |
56 | #define HPR_MIXER 0x82 | ||
57 | 61 | ||
58 | static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; | 62 | static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"}; |
59 | static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; | 63 | static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"}; |
@@ -157,75 +161,108 @@ SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv), | |||
157 | SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), | 161 | SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv), |
158 | }; | 162 | }; |
159 | 163 | ||
164 | static const unsigned int wm9712_mixer_mute_regs[] = { | ||
165 | AC97_VIDEO, | ||
166 | AC97_PCM, | ||
167 | AC97_LINE, | ||
168 | AC97_PHONE, | ||
169 | AC97_CD, | ||
170 | AC97_PC_BEEP, | ||
171 | }; | ||
172 | |||
160 | /* We have to create a fake left and right HP mixers because | 173 | /* We have to create a fake left and right HP mixers because |
161 | * the codec only has a single control that is shared by both channels. | 174 | * the codec only has a single control that is shared by both channels. |
162 | * This makes it impossible to determine the audio path. | 175 | * This makes it impossible to determine the audio path. |
163 | */ | 176 | */ |
164 | static int mixer_event(struct snd_soc_dapm_widget *w, | 177 | static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol, |
165 | struct snd_kcontrol *k, int event) | 178 | struct snd_ctl_elem_value *ucontrol) |
166 | { | 179 | { |
167 | u16 l, r, beep, line, phone, mic, pcm, aux; | 180 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
168 | 181 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | |
169 | l = ac97_read(w->codec, HPL_MIXER); | 182 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
170 | r = ac97_read(w->codec, HPR_MIXER); | 183 | unsigned int val = ucontrol->value.enumerated.item[0]; |
171 | beep = ac97_read(w->codec, AC97_PC_BEEP); | 184 | struct soc_mixer_control *mc = |
172 | mic = ac97_read(w->codec, AC97_VIDEO); | 185 | (struct soc_mixer_control *)kcontrol->private_value; |
173 | phone = ac97_read(w->codec, AC97_PHONE); | 186 | unsigned int mixer, mask, shift, old; |
174 | line = ac97_read(w->codec, AC97_LINE); | 187 | struct snd_soc_dapm_update update; |
175 | pcm = ac97_read(w->codec, AC97_PCM); | 188 | bool change; |
176 | aux = ac97_read(w->codec, AC97_CD); | 189 | |
177 | 190 | mixer = mc->shift >> 8; | |
178 | if (l & 0x1 || r & 0x1) | 191 | shift = mc->shift & 0xff; |
179 | ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff); | 192 | mask = 1 << shift; |
193 | |||
194 | mutex_lock(&wm9712->lock); | ||
195 | old = wm9712->hp_mixer[mixer]; | ||
196 | if (ucontrol->value.enumerated.item[0]) | ||
197 | wm9712->hp_mixer[mixer] |= mask; | ||
180 | else | 198 | else |
181 | ac97_write(w->codec, AC97_VIDEO, mic | 0x8000); | 199 | wm9712->hp_mixer[mixer] &= ~mask; |
200 | |||
201 | change = old != wm9712->hp_mixer[mixer]; | ||
202 | if (change) { | ||
203 | update.kcontrol = kcontrol; | ||
204 | update.reg = wm9712_mixer_mute_regs[shift]; | ||
205 | update.mask = 0x8000; | ||
206 | if ((wm9712->hp_mixer[0] & mask) || | ||
207 | (wm9712->hp_mixer[1] & mask)) | ||
208 | update.val = 0x0; | ||
209 | else | ||
210 | update.val = 0x8000; | ||
211 | |||
212 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, | ||
213 | &update); | ||
214 | } | ||
182 | 215 | ||
183 | if (l & 0x2 || r & 0x2) | 216 | mutex_unlock(&wm9712->lock); |
184 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | ||
185 | else | ||
186 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
187 | 217 | ||
188 | if (l & 0x4 || r & 0x4) | 218 | return change; |
189 | ac97_write(w->codec, AC97_LINE, line & 0x7fff); | 219 | } |
190 | else | ||
191 | ac97_write(w->codec, AC97_LINE, line | 0x8000); | ||
192 | 220 | ||
193 | if (l & 0x8 || r & 0x8) | 221 | static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol, |
194 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | 222 | struct snd_ctl_elem_value *ucontrol) |
195 | else | 223 | { |
196 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | 224 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
225 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
226 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
227 | struct soc_mixer_control *mc = | ||
228 | (struct soc_mixer_control *)kcontrol->private_value; | ||
229 | unsigned int shift, mixer; | ||
197 | 230 | ||
198 | if (l & 0x10 || r & 0x10) | 231 | mixer = mc->shift >> 8; |
199 | ac97_write(w->codec, AC97_CD, aux & 0x7fff); | 232 | shift = mc->shift & 0xff; |
200 | else | ||
201 | ac97_write(w->codec, AC97_CD, aux | 0x8000); | ||
202 | 233 | ||
203 | if (l & 0x20 || r & 0x20) | 234 | ucontrol->value.enumerated.item[0] = |
204 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | 235 | (wm9712->hp_mixer[mixer] >> shift) & 1; |
205 | else | ||
206 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | ||
207 | 236 | ||
208 | return 0; | 237 | return 0; |
209 | } | 238 | } |
210 | 239 | ||
240 | #define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \ | ||
241 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
242 | .info = snd_soc_info_volsw, \ | ||
243 | .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \ | ||
244 | .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \ | ||
245 | (xmixer << 8) | xshift, 1, 0, 0) \ | ||
246 | } | ||
247 | |||
211 | /* Left Headphone Mixers */ | 248 | /* Left Headphone Mixers */ |
212 | static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { | 249 | static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { |
213 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0), | 250 | WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5), |
214 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0), | 251 | WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4), |
215 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0), | 252 | WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3), |
216 | SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0), | 253 | WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2), |
217 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0), | 254 | WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1), |
218 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0), | 255 | WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0), |
219 | }; | 256 | }; |
220 | 257 | ||
221 | /* Right Headphone Mixers */ | 258 | /* Right Headphone Mixers */ |
222 | static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { | 259 | static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = { |
223 | SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0), | 260 | WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5), |
224 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0), | 261 | WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4), |
225 | SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0), | 262 | WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3), |
226 | SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0), | 263 | WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2), |
227 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0), | 264 | WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1), |
228 | SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0), | 265 | WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0), |
229 | }; | 266 | }; |
230 | 267 | ||
231 | /* Speaker Mixer */ | 268 | /* Speaker Mixer */ |
@@ -299,12 +336,10 @@ SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0, | |||
299 | SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, | 336 | SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0, |
300 | &wm9712_diff_sel_controls), | 337 | &wm9712_diff_sel_controls), |
301 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), | 338 | SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0), |
302 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1, | 339 | SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1, |
303 | &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls), | 340 | &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)), |
304 | mixer_event, SND_SOC_DAPM_POST_REG), | 341 | SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1, |
305 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1, | 342 | &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)), |
306 | &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls), | ||
307 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
308 | SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, | 343 | SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1, |
309 | &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), | 344 | &wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)), |
310 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, | 345 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1, |
@@ -450,12 +485,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = { | |||
450 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 485 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
451 | unsigned int reg) | 486 | unsigned int reg) |
452 | { | 487 | { |
488 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
453 | u16 *cache = codec->reg_cache; | 489 | u16 *cache = codec->reg_cache; |
454 | 490 | ||
455 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 491 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
456 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 492 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
457 | reg == AC97_REC_GAIN) | 493 | reg == AC97_REC_GAIN) |
458 | return soc_ac97_ops->read(codec->ac97, reg); | 494 | return soc_ac97_ops->read(wm9712->ac97, reg); |
459 | else { | 495 | else { |
460 | reg = reg >> 1; | 496 | reg = reg >> 1; |
461 | 497 | ||
@@ -469,10 +505,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
469 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 505 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
470 | unsigned int val) | 506 | unsigned int val) |
471 | { | 507 | { |
508 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
472 | u16 *cache = codec->reg_cache; | 509 | u16 *cache = codec->reg_cache; |
473 | 510 | ||
474 | if (reg < 0x7c) | 511 | soc_ac97_ops->write(wm9712->ac97, reg, val); |
475 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
476 | reg = reg >> 1; | 512 | reg = reg >> 1; |
477 | if (reg < (ARRAY_SIZE(wm9712_reg))) | 513 | if (reg < (ARRAY_SIZE(wm9712_reg))) |
478 | cache[reg] = val; | 514 | cache[reg] = val; |
@@ -532,7 +568,6 @@ static const struct snd_soc_dai_ops wm9712_dai_ops_aux = { | |||
532 | static struct snd_soc_dai_driver wm9712_dai[] = { | 568 | static struct snd_soc_dai_driver wm9712_dai[] = { |
533 | { | 569 | { |
534 | .name = "wm9712-hifi", | 570 | .name = "wm9712-hifi", |
535 | .ac97_control = 1, | ||
536 | .playback = { | 571 | .playback = { |
537 | .stream_name = "HiFi Playback", | 572 | .stream_name = "HiFi Playback", |
538 | .channels_min = 1, | 573 | .channels_min = 1, |
@@ -581,21 +616,23 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, | |||
581 | 616 | ||
582 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) | 617 | static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) |
583 | { | 618 | { |
619 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
620 | |||
584 | if (try_warm && soc_ac97_ops->warm_reset) { | 621 | if (try_warm && soc_ac97_ops->warm_reset) { |
585 | soc_ac97_ops->warm_reset(codec->ac97); | 622 | soc_ac97_ops->warm_reset(wm9712->ac97); |
586 | if (ac97_read(codec, 0) == wm9712_reg[0]) | 623 | if (ac97_read(codec, 0) == wm9712_reg[0]) |
587 | return 1; | 624 | return 1; |
588 | } | 625 | } |
589 | 626 | ||
590 | soc_ac97_ops->reset(codec->ac97); | 627 | soc_ac97_ops->reset(wm9712->ac97); |
591 | if (soc_ac97_ops->warm_reset) | 628 | if (soc_ac97_ops->warm_reset) |
592 | soc_ac97_ops->warm_reset(codec->ac97); | 629 | soc_ac97_ops->warm_reset(wm9712->ac97); |
593 | if (ac97_read(codec, 0) != wm9712_reg[0]) | 630 | if (ac97_read(codec, 0) != wm9712_reg[0]) |
594 | goto err; | 631 | goto err; |
595 | return 0; | 632 | return 0; |
596 | 633 | ||
597 | err: | 634 | err: |
598 | printk(KERN_ERR "WM9712 AC97 reset failed\n"); | 635 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); |
599 | return -EIO; | 636 | return -EIO; |
600 | } | 637 | } |
601 | 638 | ||
@@ -607,14 +644,13 @@ static int wm9712_soc_suspend(struct snd_soc_codec *codec) | |||
607 | 644 | ||
608 | static int wm9712_soc_resume(struct snd_soc_codec *codec) | 645 | static int wm9712_soc_resume(struct snd_soc_codec *codec) |
609 | { | 646 | { |
647 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
610 | int i, ret; | 648 | int i, ret; |
611 | u16 *cache = codec->reg_cache; | 649 | u16 *cache = codec->reg_cache; |
612 | 650 | ||
613 | ret = wm9712_reset(codec, 1); | 651 | ret = wm9712_reset(codec, 1); |
614 | if (ret < 0) { | 652 | if (ret < 0) |
615 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
616 | return ret; | 653 | return ret; |
617 | } | ||
618 | 654 | ||
619 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 655 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
620 | 656 | ||
@@ -624,7 +660,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
624 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || | 660 | if (i == AC97_INT_PAGING || i == AC97_POWERDOWN || |
625 | (i > 0x58 && i != 0x5c)) | 661 | (i > 0x58 && i != 0x5c)) |
626 | continue; | 662 | continue; |
627 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 663 | soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]); |
628 | } | 664 | } |
629 | } | 665 | } |
630 | 666 | ||
@@ -633,37 +669,37 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) | |||
633 | 669 | ||
634 | static int wm9712_soc_probe(struct snd_soc_codec *codec) | 670 | static int wm9712_soc_probe(struct snd_soc_codec *codec) |
635 | { | 671 | { |
672 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); | ||
636 | int ret = 0; | 673 | int ret = 0; |
637 | 674 | ||
638 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | 675 | wm9712->ac97 = snd_soc_new_ac97_codec(codec); |
639 | if (ret < 0) { | 676 | if (IS_ERR(wm9712->ac97)) { |
640 | printk(KERN_ERR "wm9712: failed to register AC97 codec\n"); | 677 | ret = PTR_ERR(wm9712->ac97); |
678 | dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); | ||
641 | return ret; | 679 | return ret; |
642 | } | 680 | } |
643 | 681 | ||
644 | ret = wm9712_reset(codec, 0); | 682 | ret = wm9712_reset(codec, 0); |
645 | if (ret < 0) { | 683 | if (ret < 0) |
646 | printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n"); | ||
647 | goto reset_err; | 684 | goto reset_err; |
648 | } | ||
649 | 685 | ||
650 | /* set alc mux to none */ | 686 | /* set alc mux to none */ |
651 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); | 687 | ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); |
652 | 688 | ||
653 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 689 | wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
654 | snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls, | ||
655 | ARRAY_SIZE(wm9712_snd_ac97_controls)); | ||
656 | 690 | ||
657 | return 0; | 691 | return 0; |
658 | 692 | ||
659 | reset_err: | 693 | reset_err: |
660 | snd_soc_free_ac97_codec(codec); | 694 | snd_soc_free_ac97_codec(wm9712->ac97); |
661 | return ret; | 695 | return ret; |
662 | } | 696 | } |
663 | 697 | ||
664 | static int wm9712_soc_remove(struct snd_soc_codec *codec) | 698 | static int wm9712_soc_remove(struct snd_soc_codec *codec) |
665 | { | 699 | { |
666 | snd_soc_free_ac97_codec(codec); | 700 | struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); |
701 | |||
702 | snd_soc_free_ac97_codec(wm9712->ac97); | ||
667 | return 0; | 703 | return 0; |
668 | } | 704 | } |
669 | 705 | ||
@@ -679,6 +715,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { | |||
679 | .reg_word_size = sizeof(u16), | 715 | .reg_word_size = sizeof(u16), |
680 | .reg_cache_step = 2, | 716 | .reg_cache_step = 2, |
681 | .reg_cache_default = wm9712_reg, | 717 | .reg_cache_default = wm9712_reg, |
718 | |||
719 | .controls = wm9712_snd_ac97_controls, | ||
720 | .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls), | ||
682 | .dapm_widgets = wm9712_dapm_widgets, | 721 | .dapm_widgets = wm9712_dapm_widgets, |
683 | .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), | 722 | .num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets), |
684 | .dapm_routes = wm9712_audio_map, | 723 | .dapm_routes = wm9712_audio_map, |
@@ -687,6 +726,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = { | |||
687 | 726 | ||
688 | static int wm9712_probe(struct platform_device *pdev) | 727 | static int wm9712_probe(struct platform_device *pdev) |
689 | { | 728 | { |
729 | struct wm9712_priv *wm9712; | ||
730 | |||
731 | wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL); | ||
732 | if (wm9712 == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | mutex_init(&wm9712->lock); | ||
736 | |||
737 | platform_set_drvdata(pdev, wm9712); | ||
738 | |||
690 | return snd_soc_register_codec(&pdev->dev, | 739 | return snd_soc_register_codec(&pdev->dev, |
691 | &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); | 740 | &soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai)); |
692 | } | 741 | } |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index bddee30a4bc7..6c95d98b0eb1 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -30,7 +30,10 @@ | |||
30 | #include "wm9713.h" | 30 | #include "wm9713.h" |
31 | 31 | ||
32 | struct wm9713_priv { | 32 | struct wm9713_priv { |
33 | struct snd_ac97 *ac97; | ||
33 | u32 pll_in; /* PLL input frequency */ | 34 | u32 pll_in; /* PLL input frequency */ |
35 | unsigned int hp_mixer[2]; | ||
36 | struct mutex lock; | ||
34 | }; | 37 | }; |
35 | 38 | ||
36 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 39 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
@@ -59,13 +62,10 @@ static const u16 wm9713_reg[] = { | |||
59 | 0x0000, 0x0000, 0x0000, 0x0000, | 62 | 0x0000, 0x0000, 0x0000, 0x0000, |
60 | 0x0000, 0x0000, 0x0000, 0x0006, | 63 | 0x0000, 0x0000, 0x0000, 0x0006, |
61 | 0x0001, 0x0000, 0x574d, 0x4c13, | 64 | 0x0001, 0x0000, 0x574d, 0x4c13, |
62 | 0x0000, 0x0000, 0x0000 | ||
63 | }; | 65 | }; |
64 | 66 | ||
65 | /* virtual HP mixers regs */ | 67 | #define HPL_MIXER 0 |
66 | #define HPL_MIXER 0x80 | 68 | #define HPR_MIXER 1 |
67 | #define HPR_MIXER 0x82 | ||
68 | #define MICB_MUX 0x82 | ||
69 | 69 | ||
70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; | 70 | static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"}; |
71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; | 71 | static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"}; |
@@ -110,7 +110,7 @@ SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */ | |||
110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ | 110 | SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */ |
111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ | 111 | SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */ |
112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ | 112 | SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */ |
113 | SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */ | 113 | SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */ |
114 | }; | 114 | }; |
115 | 115 | ||
116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); | 116 | static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0); |
@@ -234,6 +234,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
234 | return 0; | 234 | return 0; |
235 | } | 235 | } |
236 | 236 | ||
237 | static const unsigned int wm9713_mixer_mute_regs[] = { | ||
238 | AC97_PC_BEEP, | ||
239 | AC97_MASTER_TONE, | ||
240 | AC97_PHONE, | ||
241 | AC97_REC_SEL, | ||
242 | AC97_PCM, | ||
243 | AC97_AUX, | ||
244 | }; | ||
237 | 245 | ||
238 | /* We have to create a fake left and right HP mixers because | 246 | /* We have to create a fake left and right HP mixers because |
239 | * the codec only has a single control that is shared by both channels. | 247 | * the codec only has a single control that is shared by both channels. |
@@ -241,73 +249,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w, | |||
241 | * register map, thus we add a new (virtual) register to help determine the | 249 | * register map, thus we add a new (virtual) register to help determine the |
242 | * audio route within the device. | 250 | * audio route within the device. |
243 | */ | 251 | */ |
244 | static int mixer_event(struct snd_soc_dapm_widget *w, | 252 | static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol, |
245 | struct snd_kcontrol *kcontrol, int event) | 253 | struct snd_ctl_elem_value *ucontrol) |
246 | { | 254 | { |
247 | u16 l, r, beep, tone, phone, rec, pcm, aux; | 255 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
248 | 256 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | |
249 | l = ac97_read(w->codec, HPL_MIXER); | 257 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
250 | r = ac97_read(w->codec, HPR_MIXER); | 258 | unsigned int val = ucontrol->value.enumerated.item[0]; |
251 | beep = ac97_read(w->codec, AC97_PC_BEEP); | 259 | struct soc_mixer_control *mc = |
252 | tone = ac97_read(w->codec, AC97_MASTER_TONE); | 260 | (struct soc_mixer_control *)kcontrol->private_value; |
253 | phone = ac97_read(w->codec, AC97_PHONE); | 261 | unsigned int mixer, mask, shift, old; |
254 | rec = ac97_read(w->codec, AC97_REC_SEL); | 262 | struct snd_soc_dapm_update update; |
255 | pcm = ac97_read(w->codec, AC97_PCM); | 263 | bool change; |
256 | aux = ac97_read(w->codec, AC97_AUX); | 264 | |
257 | 265 | mixer = mc->shift >> 8; | |
258 | if (event & SND_SOC_DAPM_PRE_REG) | 266 | shift = mc->shift & 0xff; |
259 | return 0; | 267 | mask = (1 << shift); |
260 | if ((l & 0x1) || (r & 0x1)) | 268 | |
261 | ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff); | 269 | mutex_lock(&wm9713->lock); |
270 | old = wm9713->hp_mixer[mixer]; | ||
271 | if (ucontrol->value.enumerated.item[0]) | ||
272 | wm9713->hp_mixer[mixer] |= mask; | ||
262 | else | 273 | else |
263 | ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000); | 274 | wm9713->hp_mixer[mixer] &= ~mask; |
275 | |||
276 | change = old != wm9713->hp_mixer[mixer]; | ||
277 | if (change) { | ||
278 | update.kcontrol = kcontrol; | ||
279 | update.reg = wm9713_mixer_mute_regs[shift]; | ||
280 | update.mask = 0x8000; | ||
281 | if ((wm9713->hp_mixer[0] & mask) || | ||
282 | (wm9713->hp_mixer[1] & mask)) | ||
283 | update.val = 0x0; | ||
284 | else | ||
285 | update.val = 0x8000; | ||
286 | |||
287 | snd_soc_dapm_mixer_update_power(dapm, kcontrol, val, | ||
288 | &update); | ||
289 | } | ||
264 | 290 | ||
265 | if ((l & 0x2) || (r & 0x2)) | 291 | mutex_unlock(&wm9713->lock); |
266 | ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff); | ||
267 | else | ||
268 | ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000); | ||
269 | 292 | ||
270 | if ((l & 0x4) || (r & 0x4)) | 293 | return change; |
271 | ac97_write(w->codec, AC97_PHONE, phone & 0x7fff); | 294 | } |
272 | else | ||
273 | ac97_write(w->codec, AC97_PHONE, phone | 0x8000); | ||
274 | 295 | ||
275 | if ((l & 0x8) || (r & 0x8)) | 296 | static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, |
276 | ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff); | 297 | struct snd_ctl_elem_value *ucontrol) |
277 | else | 298 | { |
278 | ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000); | 299 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
300 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); | ||
301 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
302 | struct soc_mixer_control *mc = | ||
303 | (struct soc_mixer_control *)kcontrol->private_value; | ||
304 | unsigned int mixer, shift; | ||
279 | 305 | ||
280 | if ((l & 0x10) || (r & 0x10)) | 306 | mixer = mc->shift >> 8; |
281 | ac97_write(w->codec, AC97_PCM, pcm & 0x7fff); | 307 | shift = mc->shift & 0xff; |
282 | else | ||
283 | ac97_write(w->codec, AC97_PCM, pcm | 0x8000); | ||
284 | 308 | ||
285 | if ((l & 0x20) || (r & 0x20)) | 309 | ucontrol->value.enumerated.item[0] = |
286 | ac97_write(w->codec, AC97_AUX, aux & 0x7fff); | 310 | (wm9713->hp_mixer[mixer] >> shift) & 1; |
287 | else | ||
288 | ac97_write(w->codec, AC97_AUX, aux | 0x8000); | ||
289 | 311 | ||
290 | return 0; | 312 | return 0; |
291 | } | 313 | } |
292 | 314 | ||
315 | #define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \ | ||
316 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
317 | .info = snd_soc_info_volsw, \ | ||
318 | .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \ | ||
319 | .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \ | ||
320 | xshift, xmixer, 1, 0, 0) \ | ||
321 | } | ||
322 | |||
293 | /* Left Headphone Mixers */ | 323 | /* Left Headphone Mixers */ |
294 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { | 324 | static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { |
295 | SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), | 325 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5), |
296 | SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), | 326 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4), |
297 | SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), | 327 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3), |
298 | SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), | 328 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2), |
299 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0), | 329 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1), |
300 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), | 330 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0), |
301 | }; | 331 | }; |
302 | 332 | ||
303 | /* Right Headphone Mixers */ | 333 | /* Right Headphone Mixers */ |
304 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { | 334 | static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { |
305 | SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), | 335 | WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5), |
306 | SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), | 336 | WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4), |
307 | SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), | 337 | WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3), |
308 | SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), | 338 | WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2), |
309 | SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0), | 339 | WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1), |
310 | SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0), | 340 | WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0), |
311 | }; | 341 | }; |
312 | 342 | ||
313 | /* headphone capture mux */ | 343 | /* headphone capture mux */ |
@@ -429,12 +459,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0, | |||
429 | &wm9713_mic_sel_mux_controls), | 459 | &wm9713_mic_sel_mux_controls), |
430 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, | 460 | SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0, |
431 | &wm9713_micb_sel_mux_controls), | 461 | &wm9713_micb_sel_mux_controls), |
432 | SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, | 462 | SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1, |
433 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls), | 463 | &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)), |
434 | mixer_event, SND_SOC_DAPM_POST_REG), | 464 | SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, |
435 | SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1, | 465 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)), |
436 | &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls), | ||
437 | mixer_event, SND_SOC_DAPM_POST_REG), | ||
438 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, | 466 | SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1, |
439 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), | 467 | &wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)), |
440 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, | 468 | SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1, |
@@ -647,12 +675,13 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = { | |||
647 | static unsigned int ac97_read(struct snd_soc_codec *codec, | 675 | static unsigned int ac97_read(struct snd_soc_codec *codec, |
648 | unsigned int reg) | 676 | unsigned int reg) |
649 | { | 677 | { |
678 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
650 | u16 *cache = codec->reg_cache; | 679 | u16 *cache = codec->reg_cache; |
651 | 680 | ||
652 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || | 681 | if (reg == AC97_RESET || reg == AC97_GPIO_STATUS || |
653 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || | 682 | reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 || |
654 | reg == AC97_CD) | 683 | reg == AC97_CD) |
655 | return soc_ac97_ops->read(codec->ac97, reg); | 684 | return soc_ac97_ops->read(wm9713->ac97, reg); |
656 | else { | 685 | else { |
657 | reg = reg >> 1; | 686 | reg = reg >> 1; |
658 | 687 | ||
@@ -666,9 +695,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, | |||
666 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | 695 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, |
667 | unsigned int val) | 696 | unsigned int val) |
668 | { | 697 | { |
698 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
699 | |||
669 | u16 *cache = codec->reg_cache; | 700 | u16 *cache = codec->reg_cache; |
670 | if (reg < 0x7c) | 701 | soc_ac97_ops->write(wm9713->ac97, reg, val); |
671 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
672 | reg = reg >> 1; | 702 | reg = reg >> 1; |
673 | if (reg < (ARRAY_SIZE(wm9713_reg))) | 703 | if (reg < (ARRAY_SIZE(wm9713_reg))) |
674 | cache[reg] = val; | 704 | cache[reg] = val; |
@@ -689,7 +719,8 @@ struct _pll_div { | |||
689 | * to allow rounding later */ | 719 | * to allow rounding later */ |
690 | #define FIXED_PLL_SIZE ((1 << 22) * 10) | 720 | #define FIXED_PLL_SIZE ((1 << 22) * 10) |
691 | 721 | ||
692 | static void pll_factors(struct _pll_div *pll_div, unsigned int source) | 722 | static void pll_factors(struct snd_soc_codec *codec, |
723 | struct _pll_div *pll_div, unsigned int source) | ||
693 | { | 724 | { |
694 | u64 Kpart; | 725 | u64 Kpart; |
695 | unsigned int K, Ndiv, Nmod, target; | 726 | unsigned int K, Ndiv, Nmod, target; |
@@ -724,7 +755,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source) | |||
724 | 755 | ||
725 | Ndiv = target / source; | 756 | Ndiv = target / source; |
726 | if ((Ndiv < 5) || (Ndiv > 12)) | 757 | if ((Ndiv < 5) || (Ndiv > 12)) |
727 | printk(KERN_WARNING | 758 | dev_warn(codec->dev, |
728 | "WM9713 PLL N value %u out of recommended range!\n", | 759 | "WM9713 PLL N value %u out of recommended range!\n", |
729 | Ndiv); | 760 | Ndiv); |
730 | 761 | ||
@@ -768,7 +799,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
768 | return 0; | 799 | return 0; |
769 | } | 800 | } |
770 | 801 | ||
771 | pll_factors(&pll_div, freq_in); | 802 | pll_factors(codec, &pll_div, freq_in); |
772 | 803 | ||
773 | if (pll_div.k == 0) { | 804 | if (pll_div.k == 0) { |
774 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | | 805 | reg = (pll_div.n << 12) | (pll_div.lf << 11) | |
@@ -1049,7 +1080,6 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = { | |||
1049 | static struct snd_soc_dai_driver wm9713_dai[] = { | 1080 | static struct snd_soc_dai_driver wm9713_dai[] = { |
1050 | { | 1081 | { |
1051 | .name = "wm9713-hifi", | 1082 | .name = "wm9713-hifi", |
1052 | .ac97_control = 1, | ||
1053 | .playback = { | 1083 | .playback = { |
1054 | .stream_name = "HiFi Playback", | 1084 | .stream_name = "HiFi Playback", |
1055 | .channels_min = 1, | 1085 | .channels_min = 1, |
@@ -1095,17 +1125,22 @@ static struct snd_soc_dai_driver wm9713_dai[] = { | |||
1095 | 1125 | ||
1096 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) | 1126 | int wm9713_reset(struct snd_soc_codec *codec, int try_warm) |
1097 | { | 1127 | { |
1128 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | ||
1129 | |||
1098 | if (try_warm && soc_ac97_ops->warm_reset) { | 1130 | if (try_warm && soc_ac97_ops->warm_reset) { |
1099 | soc_ac97_ops->warm_reset(codec->ac97); | 1131 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1100 | if (ac97_read(codec, 0) == wm9713_reg[0]) | 1132 | if (ac97_read(codec, 0) == wm9713_reg[0]) |
1101 | return 1; | 1133 | return 1; |
1102 | } | 1134 | } |
1103 | 1135 | ||
1104 | soc_ac97_ops->reset(codec->ac97); | 1136 | soc_ac97_ops->reset(wm9713->ac97); |
1105 | if (soc_ac97_ops->warm_reset) | 1137 | if (soc_ac97_ops->warm_reset) |
1106 | soc_ac97_ops->warm_reset(codec->ac97); | 1138 | soc_ac97_ops->warm_reset(wm9713->ac97); |
1107 | if (ac97_read(codec, 0) != wm9713_reg[0]) | 1139 | if (ac97_read(codec, 0) != wm9713_reg[0]) { |
1140 | dev_err(codec->dev, "Failed to reset: AC97 link error\n"); | ||
1108 | return -EIO; | 1141 | return -EIO; |
1142 | } | ||
1143 | |||
1109 | return 0; | 1144 | return 0; |
1110 | } | 1145 | } |
1111 | EXPORT_SYMBOL_GPL(wm9713_reset); | 1146 | EXPORT_SYMBOL_GPL(wm9713_reset); |
@@ -1163,10 +1198,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1163 | u16 *cache = codec->reg_cache; | 1198 | u16 *cache = codec->reg_cache; |
1164 | 1199 | ||
1165 | ret = wm9713_reset(codec, 1); | 1200 | ret = wm9713_reset(codec, 1); |
1166 | if (ret < 0) { | 1201 | if (ret < 0) |
1167 | printk(KERN_ERR "could not reset AC97 codec\n"); | ||
1168 | return ret; | 1202 | return ret; |
1169 | } | ||
1170 | 1203 | ||
1171 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1204 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1172 | 1205 | ||
@@ -1180,7 +1213,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1180 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || | 1213 | if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID || |
1181 | i == AC97_EXTENDED_MSTATUS || i > 0x66) | 1214 | i == AC97_EXTENDED_MSTATUS || i > 0x66) |
1182 | continue; | 1215 | continue; |
1183 | soc_ac97_ops->write(codec->ac97, i, cache[i>>1]); | 1216 | soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]); |
1184 | } | 1217 | } |
1185 | } | 1218 | } |
1186 | 1219 | ||
@@ -1189,26 +1222,19 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) | |||
1189 | 1222 | ||
1190 | static int wm9713_soc_probe(struct snd_soc_codec *codec) | 1223 | static int wm9713_soc_probe(struct snd_soc_codec *codec) |
1191 | { | 1224 | { |
1192 | struct wm9713_priv *wm9713; | 1225 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1193 | int ret = 0, reg; | 1226 | int ret = 0, reg; |
1194 | 1227 | ||
1195 | wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL); | 1228 | wm9713->ac97 = snd_soc_new_ac97_codec(codec); |
1196 | if (wm9713 == NULL) | 1229 | if (IS_ERR(wm9713->ac97)) |
1197 | return -ENOMEM; | 1230 | return PTR_ERR(wm9713->ac97); |
1198 | snd_soc_codec_set_drvdata(codec, wm9713); | ||
1199 | |||
1200 | ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); | ||
1201 | if (ret < 0) | ||
1202 | goto codec_err; | ||
1203 | 1231 | ||
1204 | /* do a cold reset for the controller and then try | 1232 | /* do a cold reset for the controller and then try |
1205 | * a warm reset followed by an optional cold reset for codec */ | 1233 | * a warm reset followed by an optional cold reset for codec */ |
1206 | wm9713_reset(codec, 0); | 1234 | wm9713_reset(codec, 0); |
1207 | ret = wm9713_reset(codec, 1); | 1235 | ret = wm9713_reset(codec, 1); |
1208 | if (ret < 0) { | 1236 | if (ret < 0) |
1209 | printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n"); | ||
1210 | goto reset_err; | 1237 | goto reset_err; |
1211 | } | ||
1212 | 1238 | ||
1213 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1239 | wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1214 | 1240 | ||
@@ -1216,23 +1242,18 @@ static int wm9713_soc_probe(struct snd_soc_codec *codec) | |||
1216 | reg = ac97_read(codec, AC97_CD) & 0x7fff; | 1242 | reg = ac97_read(codec, AC97_CD) & 0x7fff; |
1217 | ac97_write(codec, AC97_CD, reg); | 1243 | ac97_write(codec, AC97_CD, reg); |
1218 | 1244 | ||
1219 | snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls, | ||
1220 | ARRAY_SIZE(wm9713_snd_ac97_controls)); | ||
1221 | |||
1222 | return 0; | 1245 | return 0; |
1223 | 1246 | ||
1224 | reset_err: | 1247 | reset_err: |
1225 | snd_soc_free_ac97_codec(codec); | 1248 | snd_soc_free_ac97_codec(wm9713->ac97); |
1226 | codec_err: | ||
1227 | kfree(wm9713); | ||
1228 | return ret; | 1249 | return ret; |
1229 | } | 1250 | } |
1230 | 1251 | ||
1231 | static int wm9713_soc_remove(struct snd_soc_codec *codec) | 1252 | static int wm9713_soc_remove(struct snd_soc_codec *codec) |
1232 | { | 1253 | { |
1233 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); | 1254 | struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); |
1234 | snd_soc_free_ac97_codec(codec); | 1255 | |
1235 | kfree(wm9713); | 1256 | snd_soc_free_ac97_codec(wm9713->ac97); |
1236 | return 0; | 1257 | return 0; |
1237 | } | 1258 | } |
1238 | 1259 | ||
@@ -1248,6 +1269,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1248 | .reg_word_size = sizeof(u16), | 1269 | .reg_word_size = sizeof(u16), |
1249 | .reg_cache_step = 2, | 1270 | .reg_cache_step = 2, |
1250 | .reg_cache_default = wm9713_reg, | 1271 | .reg_cache_default = wm9713_reg, |
1272 | |||
1273 | .controls = wm9713_snd_ac97_controls, | ||
1274 | .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls), | ||
1251 | .dapm_widgets = wm9713_dapm_widgets, | 1275 | .dapm_widgets = wm9713_dapm_widgets, |
1252 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), | 1276 | .num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets), |
1253 | .dapm_routes = wm9713_audio_map, | 1277 | .dapm_routes = wm9713_audio_map, |
@@ -1256,6 +1280,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = { | |||
1256 | 1280 | ||
1257 | static int wm9713_probe(struct platform_device *pdev) | 1281 | static int wm9713_probe(struct platform_device *pdev) |
1258 | { | 1282 | { |
1283 | struct wm9713_priv *wm9713; | ||
1284 | |||
1285 | wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL); | ||
1286 | if (wm9713 == NULL) | ||
1287 | return -ENOMEM; | ||
1288 | |||
1289 | mutex_init(&wm9713->lock); | ||
1290 | |||
1291 | platform_set_drvdata(pdev, wm9713); | ||
1292 | |||
1259 | return snd_soc_register_codec(&pdev->dev, | 1293 | return snd_soc_register_codec(&pdev->dev, |
1260 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); | 1294 | &soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai)); |
1261 | } | 1295 | } |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 67124783558a..720d6e852986 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/regmap.h> | 21 | #include <linux/regmap.h> |
22 | #include <linux/regulator/consumer.h> | 22 | #include <linux/regulator/consumer.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <linux/vmalloc.h> | ||
24 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
25 | #include <sound/core.h> | 26 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -169,11 +170,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, | |||
169 | if (buf == NULL) | 170 | if (buf == NULL) |
170 | return NULL; | 171 | return NULL; |
171 | 172 | ||
172 | buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); | 173 | buf->buf = vmalloc(len); |
173 | if (!buf->buf) { | 174 | if (!buf->buf) { |
174 | kfree(buf); | 175 | vfree(buf); |
175 | return NULL; | 176 | return NULL; |
176 | } | 177 | } |
178 | memcpy(buf->buf, src, len); | ||
177 | 179 | ||
178 | if (list) | 180 | if (list) |
179 | list_add_tail(&buf->list, list); | 181 | list_add_tail(&buf->list, list); |
@@ -188,7 +190,7 @@ static void wm_adsp_buf_free(struct list_head *list) | |||
188 | struct wm_adsp_buf, | 190 | struct wm_adsp_buf, |
189 | list); | 191 | list); |
190 | list_del(&buf->list); | 192 | list_del(&buf->list); |
191 | kfree(buf->buf); | 193 | vfree(buf->buf); |
192 | kfree(buf); | 194 | kfree(buf); |
193 | } | 195 | } |
194 | } | 196 | } |
@@ -684,38 +686,24 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
684 | } | 686 | } |
685 | 687 | ||
686 | if (reg) { | 688 | if (reg) { |
687 | size_t to_write = PAGE_SIZE; | 689 | buf = wm_adsp_buf_alloc(region->data, |
688 | size_t remain = le32_to_cpu(region->len); | 690 | le32_to_cpu(region->len), |
689 | const u8 *data = region->data; | 691 | &buf_list); |
690 | 692 | if (!buf) { | |
691 | while (remain > 0) { | 693 | adsp_err(dsp, "Out of memory\n"); |
692 | if (remain < PAGE_SIZE) | 694 | ret = -ENOMEM; |
693 | to_write = remain; | 695 | goto out_fw; |
694 | 696 | } | |
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 | } | ||
703 | |||
704 | ret = regmap_raw_write_async(regmap, reg, | ||
705 | buf->buf, | ||
706 | to_write); | ||
707 | if (ret != 0) { | ||
708 | adsp_err(dsp, | ||
709 | "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", | ||
710 | file, regions, | ||
711 | to_write, offset, | ||
712 | region_name, ret); | ||
713 | goto out_fw; | ||
714 | } | ||
715 | 697 | ||
716 | data += to_write; | 698 | ret = regmap_raw_write_async(regmap, reg, buf->buf, |
717 | reg += to_write / 2; | 699 | le32_to_cpu(region->len)); |
718 | remain -= to_write; | 700 | if (ret != 0) { |
701 | adsp_err(dsp, | ||
702 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | ||
703 | file, regions, | ||
704 | le32_to_cpu(region->len), offset, | ||
705 | region_name, ret); | ||
706 | goto out_fw; | ||
719 | } | 707 | } |
720 | } | 708 | } |
721 | 709 | ||
@@ -1065,8 +1053,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1065 | be32_to_cpu(adsp1_alg[i].zm)); | 1053 | be32_to_cpu(adsp1_alg[i].zm)); |
1066 | 1054 | ||
1067 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1055 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1068 | if (!region) | 1056 | if (!region) { |
1069 | return -ENOMEM; | 1057 | ret = -ENOMEM; |
1058 | goto out; | ||
1059 | } | ||
1070 | region->type = WMFW_ADSP1_DM; | 1060 | region->type = WMFW_ADSP1_DM; |
1071 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1061 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
1072 | region->base = be32_to_cpu(adsp1_alg[i].dm); | 1062 | region->base = be32_to_cpu(adsp1_alg[i].dm); |
@@ -1083,8 +1073,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1083 | } | 1073 | } |
1084 | 1074 | ||
1085 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1075 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1086 | if (!region) | 1076 | if (!region) { |
1087 | return -ENOMEM; | 1077 | ret = -ENOMEM; |
1078 | goto out; | ||
1079 | } | ||
1088 | region->type = WMFW_ADSP1_ZM; | 1080 | region->type = WMFW_ADSP1_ZM; |
1089 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); | 1081 | region->alg = be32_to_cpu(adsp1_alg[i].alg.id); |
1090 | region->base = be32_to_cpu(adsp1_alg[i].zm); | 1082 | region->base = be32_to_cpu(adsp1_alg[i].zm); |
@@ -1113,8 +1105,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1113 | be32_to_cpu(adsp2_alg[i].zm)); | 1105 | be32_to_cpu(adsp2_alg[i].zm)); |
1114 | 1106 | ||
1115 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1107 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1116 | if (!region) | 1108 | if (!region) { |
1117 | return -ENOMEM; | 1109 | ret = -ENOMEM; |
1110 | goto out; | ||
1111 | } | ||
1118 | region->type = WMFW_ADSP2_XM; | 1112 | region->type = WMFW_ADSP2_XM; |
1119 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1113 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1120 | region->base = be32_to_cpu(adsp2_alg[i].xm); | 1114 | region->base = be32_to_cpu(adsp2_alg[i].xm); |
@@ -1131,8 +1125,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1131 | } | 1125 | } |
1132 | 1126 | ||
1133 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1127 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1134 | if (!region) | 1128 | if (!region) { |
1135 | return -ENOMEM; | 1129 | ret = -ENOMEM; |
1130 | goto out; | ||
1131 | } | ||
1136 | region->type = WMFW_ADSP2_YM; | 1132 | region->type = WMFW_ADSP2_YM; |
1137 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1133 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1138 | region->base = be32_to_cpu(adsp2_alg[i].ym); | 1134 | region->base = be32_to_cpu(adsp2_alg[i].ym); |
@@ -1149,8 +1145,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp) | |||
1149 | } | 1145 | } |
1150 | 1146 | ||
1151 | region = kzalloc(sizeof(*region), GFP_KERNEL); | 1147 | region = kzalloc(sizeof(*region), GFP_KERNEL); |
1152 | if (!region) | 1148 | if (!region) { |
1153 | return -ENOMEM; | 1149 | ret = -ENOMEM; |
1150 | goto out; | ||
1151 | } | ||
1154 | region->type = WMFW_ADSP2_ZM; | 1152 | region->type = WMFW_ADSP2_ZM; |
1155 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); | 1153 | region->alg = be32_to_cpu(adsp2_alg[i].alg.id); |
1156 | region->base = be32_to_cpu(adsp2_alg[i].zm); | 1154 | region->base = be32_to_cpu(adsp2_alg[i].zm); |
@@ -1595,13 +1593,6 @@ static void wm_adsp2_boot_work(struct work_struct *work) | |||
1595 | if (ret != 0) | 1593 | if (ret != 0) |
1596 | goto err; | 1594 | goto err; |
1597 | 1595 | ||
1598 | ret = regmap_update_bits_async(dsp->regmap, | ||
1599 | dsp->base + ADSP2_CONTROL, | ||
1600 | ADSP2_CORE_ENA, | ||
1601 | ADSP2_CORE_ENA); | ||
1602 | if (ret != 0) | ||
1603 | goto err; | ||
1604 | |||
1605 | dsp->running = true; | 1596 | dsp->running = true; |
1606 | 1597 | ||
1607 | return; | 1598 | return; |
@@ -1651,8 +1642,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1651 | 1642 | ||
1652 | ret = regmap_update_bits(dsp->regmap, | 1643 | ret = regmap_update_bits(dsp->regmap, |
1653 | dsp->base + ADSP2_CONTROL, | 1644 | dsp->base + ADSP2_CONTROL, |
1654 | ADSP2_START, | 1645 | ADSP2_CORE_ENA | ADSP2_START, |
1655 | ADSP2_START); | 1646 | ADSP2_CORE_ENA | ADSP2_START); |
1656 | if (ret != 0) | 1647 | if (ret != 0) |
1657 | goto err; | 1648 | goto err; |
1658 | break; | 1649 | break; |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 0eed9b1b24e1..0dab382ba147 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -70,6 +70,7 @@ struct davinci_mcasp { | |||
70 | void __iomem *base; | 70 | void __iomem *base; |
71 | u32 fifo_base; | 71 | u32 fifo_base; |
72 | struct device *dev; | 72 | struct device *dev; |
73 | struct snd_pcm_substream *substreams[2]; | ||
73 | 74 | ||
74 | /* McASP specific data */ | 75 | /* McASP specific data */ |
75 | int tdm_slots; | 76 | int tdm_slots; |
@@ -80,6 +81,7 @@ struct davinci_mcasp { | |||
80 | u8 bclk_div; | 81 | u8 bclk_div; |
81 | u16 bclk_lrclk_ratio; | 82 | u16 bclk_lrclk_ratio; |
82 | int streams; | 83 | int streams; |
84 | u32 irq_request[2]; | ||
83 | 85 | ||
84 | int sysclk_freq; | 86 | int sysclk_freq; |
85 | bool bclk_master; | 87 | bool bclk_master; |
@@ -90,6 +92,9 @@ struct davinci_mcasp { | |||
90 | 92 | ||
91 | bool dat_port; | 93 | bool dat_port; |
92 | 94 | ||
95 | /* Used for comstraint setting on the second stream */ | ||
96 | u32 channels; | ||
97 | |||
93 | #ifdef CONFIG_PM_SLEEP | 98 | #ifdef CONFIG_PM_SLEEP |
94 | struct davinci_mcasp_context context; | 99 | struct davinci_mcasp_context context; |
95 | #endif | 100 | #endif |
@@ -154,9 +159,16 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp) | |||
154 | 159 | ||
155 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) | 160 | static void mcasp_start_rx(struct davinci_mcasp *mcasp) |
156 | { | 161 | { |
162 | if (mcasp->rxnumevt) { /* enable FIFO */ | ||
163 | u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
164 | |||
165 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
166 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
167 | } | ||
168 | |||
169 | /* Start clocks */ | ||
157 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); | 170 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST); |
158 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); | 171 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST); |
159 | |||
160 | /* | 172 | /* |
161 | * When ASYNC == 0 the transmit and receive sections operate | 173 | * When ASYNC == 0 the transmit and receive sections operate |
162 | * synchronously from the transmit clock and frame sync. We need to make | 174 | * synchronously from the transmit clock and frame sync. We need to make |
@@ -167,74 +179,69 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) | |||
167 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 179 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
168 | } | 180 | } |
169 | 181 | ||
182 | /* Activate serializer(s) */ | ||
170 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); | 183 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR); |
171 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | 184 | /* Release RX state machine */ |
172 | |||
173 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | ||
174 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | ||
175 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0); | ||
176 | |||
177 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); | 185 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST); |
186 | /* Release Frame Sync generator */ | ||
178 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 187 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); |
179 | |||
180 | if (mcasp_is_synchronous(mcasp)) | 188 | if (mcasp_is_synchronous(mcasp)) |
181 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); |
190 | |||
191 | /* enable receive IRQs */ | ||
192 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
193 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
182 | } | 194 | } |
183 | 195 | ||
184 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 196 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) |
185 | { | 197 | { |
186 | u8 offset = 0, i; | ||
187 | u32 cnt; | 198 | u32 cnt; |
188 | 199 | ||
200 | if (mcasp->txnumevt) { /* enable FIFO */ | ||
201 | u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
202 | |||
203 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
204 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
205 | } | ||
206 | |||
207 | /* Start clocks */ | ||
189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); | 208 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST); |
190 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); | 209 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST); |
210 | /* Activate serializer(s) */ | ||
191 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); | 211 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR); |
192 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
193 | 212 | ||
194 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 213 | /* wait for XDATA to be cleared */ |
195 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
196 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | ||
197 | for (i = 0; i < mcasp->num_serializer; i++) { | ||
198 | if (mcasp->serial_dir[i] == TX_MODE) { | ||
199 | offset = i; | ||
200 | break; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /* wait for TX ready */ | ||
205 | cnt = 0; | 214 | cnt = 0; |
206 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) & | 215 | while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) & |
207 | TXSTATE) && (cnt < 100000)) | 216 | ~XRDATA) && (cnt < 100000)) |
208 | cnt++; | 217 | cnt++; |
209 | 218 | ||
210 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0); | 219 | /* Release TX state machine */ |
220 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | ||
221 | /* Release Frame Sync generator */ | ||
222 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | ||
223 | |||
224 | /* enable transmit IRQs */ | ||
225 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
226 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
211 | } | 227 | } |
212 | 228 | ||
213 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | 229 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) |
214 | { | 230 | { |
215 | u32 reg; | ||
216 | |||
217 | mcasp->streams++; | 231 | mcasp->streams++; |
218 | 232 | ||
219 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 233 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
220 | if (mcasp->txnumevt) { /* enable FIFO */ | ||
221 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
222 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
223 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
224 | } | ||
225 | mcasp_start_tx(mcasp); | 234 | mcasp_start_tx(mcasp); |
226 | } else { | 235 | else |
227 | if (mcasp->rxnumevt) { /* enable FIFO */ | ||
228 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
229 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
230 | mcasp_set_bits(mcasp, reg, FIFO_ENABLE); | ||
231 | } | ||
232 | mcasp_start_rx(mcasp); | 236 | mcasp_start_rx(mcasp); |
233 | } | ||
234 | } | 237 | } |
235 | 238 | ||
236 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | 239 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) |
237 | { | 240 | { |
241 | /* disable IRQ sources */ | ||
242 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
243 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
244 | |||
238 | /* | 245 | /* |
239 | * In synchronous mode stop the TX clocks if no other stream is | 246 | * In synchronous mode stop the TX clocks if no other stream is |
240 | * running | 247 | * running |
@@ -244,12 +251,22 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | |||
244 | 251 | ||
245 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); | 252 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0); |
246 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); | 253 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF); |
254 | |||
255 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
256 | u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
257 | |||
258 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
259 | } | ||
247 | } | 260 | } |
248 | 261 | ||
249 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | 262 | static void mcasp_stop_tx(struct davinci_mcasp *mcasp) |
250 | { | 263 | { |
251 | u32 val = 0; | 264 | u32 val = 0; |
252 | 265 | ||
266 | /* disable IRQ sources */ | ||
267 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
268 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
269 | |||
253 | /* | 270 | /* |
254 | * In synchronous mode keep TX clocks running if the capture stream is | 271 | * In synchronous mode keep TX clocks running if the capture stream is |
255 | * still running. | 272 | * still running. |
@@ -259,27 +276,92 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
259 | 276 | ||
260 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); | 277 | mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val); |
261 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); | 278 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF); |
279 | |||
280 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
281 | u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
282 | |||
283 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
284 | } | ||
262 | } | 285 | } |
263 | 286 | ||
264 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | 287 | static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) |
265 | { | 288 | { |
266 | u32 reg; | ||
267 | |||
268 | mcasp->streams--; | 289 | mcasp->streams--; |
269 | 290 | ||
270 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 291 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
271 | if (mcasp->txnumevt) { /* disable FIFO */ | ||
272 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
273 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
274 | } | ||
275 | mcasp_stop_tx(mcasp); | 292 | mcasp_stop_tx(mcasp); |
276 | } else { | 293 | else |
277 | if (mcasp->rxnumevt) { /* disable FIFO */ | ||
278 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
279 | mcasp_clr_bits(mcasp, reg, FIFO_ENABLE); | ||
280 | } | ||
281 | mcasp_stop_rx(mcasp); | 294 | mcasp_stop_rx(mcasp); |
295 | } | ||
296 | |||
297 | static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) | ||
298 | { | ||
299 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
300 | struct snd_pcm_substream *substream; | ||
301 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; | ||
302 | u32 handled_mask = 0; | ||
303 | u32 stat; | ||
304 | |||
305 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); | ||
306 | if (stat & XUNDRN & irq_mask) { | ||
307 | dev_warn(mcasp->dev, "Transmit buffer underflow\n"); | ||
308 | handled_mask |= XUNDRN; | ||
309 | |||
310 | substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; | ||
311 | if (substream) { | ||
312 | snd_pcm_stream_lock_irq(substream); | ||
313 | if (snd_pcm_running(substream)) | ||
314 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
315 | snd_pcm_stream_unlock_irq(substream); | ||
316 | } | ||
282 | } | 317 | } |
318 | |||
319 | if (!handled_mask) | ||
320 | dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", | ||
321 | stat); | ||
322 | |||
323 | if (stat & XRERR) | ||
324 | handled_mask |= XRERR; | ||
325 | |||
326 | /* Ack the handled event only */ | ||
327 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); | ||
328 | |||
329 | return IRQ_RETVAL(handled_mask); | ||
330 | } | ||
331 | |||
332 | static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) | ||
333 | { | ||
334 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
335 | struct snd_pcm_substream *substream; | ||
336 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; | ||
337 | u32 handled_mask = 0; | ||
338 | u32 stat; | ||
339 | |||
340 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); | ||
341 | if (stat & ROVRN & irq_mask) { | ||
342 | dev_warn(mcasp->dev, "Receive buffer overflow\n"); | ||
343 | handled_mask |= ROVRN; | ||
344 | |||
345 | substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; | ||
346 | if (substream) { | ||
347 | snd_pcm_stream_lock_irq(substream); | ||
348 | if (snd_pcm_running(substream)) | ||
349 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
350 | snd_pcm_stream_unlock_irq(substream); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | if (!handled_mask) | ||
355 | dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", | ||
356 | stat); | ||
357 | |||
358 | if (stat & XRERR) | ||
359 | handled_mask |= XRERR; | ||
360 | |||
361 | /* Ack the handled event only */ | ||
362 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); | ||
363 | |||
364 | return IRQ_RETVAL(handled_mask); | ||
283 | } | 365 | } |
284 | 366 | ||
285 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 367 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
@@ -500,8 +582,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
500 | * both left and right channels), so it has to be divided by number of | 582 | * both left and right channels), so it has to be divided by number of |
501 | * tdm-slots (for I2S - divided by 2). | 583 | * tdm-slots (for I2S - divided by 2). |
502 | */ | 584 | */ |
503 | if (mcasp->bclk_lrclk_ratio) | 585 | if (mcasp->bclk_lrclk_ratio) { |
504 | word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; | 586 | u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots; |
587 | |||
588 | /* | ||
589 | * When we have more bclk then it is needed for the data, we | ||
590 | * need to use the rotation to move the received samples to have | ||
591 | * correct alignment. | ||
592 | */ | ||
593 | rx_rotate = (slot_length - word_length) / 4; | ||
594 | word_length = slot_length; | ||
595 | } | ||
505 | 596 | ||
506 | /* mapping of the XSSZ bit-field as described in the datasheet */ | 597 | /* mapping of the XSSZ bit-field as described in the datasheet */ |
507 | fmt = (word_length >> 1) - 1; | 598 | fmt = (word_length >> 1) - 1; |
@@ -635,19 +726,29 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, | |||
635 | return 0; | 726 | return 0; |
636 | } | 727 | } |
637 | 728 | ||
638 | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | 729 | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream, |
730 | int channels) | ||
639 | { | 731 | { |
640 | int i, active_slots; | 732 | int i, active_slots; |
733 | int total_slots; | ||
734 | int active_serializers; | ||
641 | u32 mask = 0; | 735 | u32 mask = 0; |
642 | u32 busel = 0; | 736 | u32 busel = 0; |
643 | 737 | ||
644 | if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { | 738 | total_slots = mcasp->tdm_slots; |
645 | dev_err(mcasp->dev, "tdm slot %d not supported\n", | 739 | |
646 | mcasp->tdm_slots); | 740 | /* |
647 | return -EINVAL; | 741 | * If more than one serializer is needed, then use them with |
648 | } | 742 | * their specified tdm_slots count. Otherwise, one serializer |
743 | * can cope with the transaction using as many slots as channels | ||
744 | * in the stream, requires channels symmetry | ||
745 | */ | ||
746 | active_serializers = (channels + total_slots - 1) / total_slots; | ||
747 | if (active_serializers == 1) | ||
748 | active_slots = channels; | ||
749 | else | ||
750 | active_slots = total_slots; | ||
649 | 751 | ||
650 | active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; | ||
651 | for (i = 0; i < active_slots; i++) | 752 | for (i = 0; i < active_slots; i++) |
652 | mask |= (1 << i); | 753 | mask |= (1 << i); |
653 | 754 | ||
@@ -659,12 +760,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) | |||
659 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); | 760 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); |
660 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); | 761 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); |
661 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, | 762 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, |
662 | FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); | 763 | FSXMOD(total_slots), FSXMOD(0x1FF)); |
663 | 764 | ||
664 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | 765 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); |
665 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); | 766 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); |
666 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, | 767 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, |
667 | FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); | 768 | FSRMOD(total_slots), FSRMOD(0x1FF)); |
668 | 769 | ||
669 | return 0; | 770 | return 0; |
670 | } | 771 | } |
@@ -778,7 +879,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
778 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 879 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
779 | ret = mcasp_dit_hw_param(mcasp, params_rate(params)); | 880 | ret = mcasp_dit_hw_param(mcasp, params_rate(params)); |
780 | else | 881 | else |
781 | ret = mcasp_i2s_hw_param(mcasp, substream->stream); | 882 | ret = mcasp_i2s_hw_param(mcasp, substream->stream, |
883 | channels); | ||
782 | 884 | ||
783 | if (ret) | 885 | if (ret) |
784 | return ret; | 886 | return ret; |
@@ -826,6 +928,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
826 | 928 | ||
827 | davinci_config_channel_size(mcasp, word_length); | 929 | davinci_config_channel_size(mcasp, word_length); |
828 | 930 | ||
931 | if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) | ||
932 | mcasp->channels = channels; | ||
933 | |||
829 | return 0; | 934 | return 0; |
830 | } | 935 | } |
831 | 936 | ||
@@ -854,7 +959,65 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | |||
854 | return ret; | 959 | return ret; |
855 | } | 960 | } |
856 | 961 | ||
962 | static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | ||
963 | struct snd_soc_dai *cpu_dai) | ||
964 | { | ||
965 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | ||
966 | u32 max_channels = 0; | ||
967 | int i, dir; | ||
968 | |||
969 | mcasp->substreams[substream->stream] = substream; | ||
970 | |||
971 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | ||
972 | return 0; | ||
973 | |||
974 | /* | ||
975 | * Limit the maximum allowed channels for the first stream: | ||
976 | * number of serializers for the direction * tdm slots per serializer | ||
977 | */ | ||
978 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
979 | dir = TX_MODE; | ||
980 | else | ||
981 | dir = RX_MODE; | ||
982 | |||
983 | for (i = 0; i < mcasp->num_serializer; i++) { | ||
984 | if (mcasp->serial_dir[i] == dir) | ||
985 | max_channels++; | ||
986 | } | ||
987 | max_channels *= mcasp->tdm_slots; | ||
988 | /* | ||
989 | * If the already active stream has less channels than the calculated | ||
990 | * limnit based on the seirializers * tdm_slots, we need to use that as | ||
991 | * a constraint for the second stream. | ||
992 | * Otherwise (first stream or less allowed channels) we use the | ||
993 | * calculated constraint. | ||
994 | */ | ||
995 | if (mcasp->channels && mcasp->channels < max_channels) | ||
996 | max_channels = mcasp->channels; | ||
997 | |||
998 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
999 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1000 | 2, max_channels); | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, | ||
1005 | struct snd_soc_dai *cpu_dai) | ||
1006 | { | ||
1007 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | ||
1008 | |||
1009 | mcasp->substreams[substream->stream] = NULL; | ||
1010 | |||
1011 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | ||
1012 | return; | ||
1013 | |||
1014 | if (!cpu_dai->active) | ||
1015 | mcasp->channels = 0; | ||
1016 | } | ||
1017 | |||
857 | static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | 1018 | static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { |
1019 | .startup = davinci_mcasp_startup, | ||
1020 | .shutdown = davinci_mcasp_shutdown, | ||
858 | .trigger = davinci_mcasp_trigger, | 1021 | .trigger = davinci_mcasp_trigger, |
859 | .hw_params = davinci_mcasp_hw_params, | 1022 | .hw_params = davinci_mcasp_hw_params, |
860 | .set_fmt = davinci_mcasp_set_dai_fmt, | 1023 | .set_fmt = davinci_mcasp_set_dai_fmt, |
@@ -971,6 +1134,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | |||
971 | }, | 1134 | }, |
972 | .ops = &davinci_mcasp_dai_ops, | 1135 | .ops = &davinci_mcasp_dai_ops, |
973 | 1136 | ||
1137 | .symmetric_samplebits = 1, | ||
974 | }, | 1138 | }, |
975 | { | 1139 | { |
976 | .name = "davinci-mcasp.1", | 1140 | .name = "davinci-mcasp.1", |
@@ -1194,6 +1358,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1194 | struct resource *mem, *ioarea, *res, *dat; | 1358 | struct resource *mem, *ioarea, *res, *dat; |
1195 | struct davinci_mcasp_pdata *pdata; | 1359 | struct davinci_mcasp_pdata *pdata; |
1196 | struct davinci_mcasp *mcasp; | 1360 | struct davinci_mcasp *mcasp; |
1361 | char *irq_name; | ||
1362 | int irq; | ||
1197 | int ret; | 1363 | int ret; |
1198 | 1364 | ||
1199 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { | 1365 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { |
@@ -1235,6 +1401,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1235 | ret = pm_runtime_get_sync(&pdev->dev); | 1401 | ret = pm_runtime_get_sync(&pdev->dev); |
1236 | if (IS_ERR_VALUE(ret)) { | 1402 | if (IS_ERR_VALUE(ret)) { |
1237 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); | 1403 | dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n"); |
1404 | pm_runtime_disable(&pdev->dev); | ||
1238 | return ret; | 1405 | return ret; |
1239 | } | 1406 | } |
1240 | 1407 | ||
@@ -1246,7 +1413,21 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1246 | } | 1413 | } |
1247 | 1414 | ||
1248 | mcasp->op_mode = pdata->op_mode; | 1415 | mcasp->op_mode = pdata->op_mode; |
1249 | mcasp->tdm_slots = pdata->tdm_slots; | 1416 | /* sanity check for tdm slots parameter */ |
1417 | if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { | ||
1418 | if (pdata->tdm_slots < 2) { | ||
1419 | dev_err(&pdev->dev, "invalid tdm slots: %d\n", | ||
1420 | pdata->tdm_slots); | ||
1421 | mcasp->tdm_slots = 2; | ||
1422 | } else if (pdata->tdm_slots > 32) { | ||
1423 | dev_err(&pdev->dev, "invalid tdm slots: %d\n", | ||
1424 | pdata->tdm_slots); | ||
1425 | mcasp->tdm_slots = 32; | ||
1426 | } else { | ||
1427 | mcasp->tdm_slots = pdata->tdm_slots; | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1250 | mcasp->num_serializer = pdata->num_serializer; | 1431 | mcasp->num_serializer = pdata->num_serializer; |
1251 | #ifdef CONFIG_PM_SLEEP | 1432 | #ifdef CONFIG_PM_SLEEP |
1252 | mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, | 1433 | mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, |
@@ -1260,6 +1441,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1260 | 1441 | ||
1261 | mcasp->dev = &pdev->dev; | 1442 | mcasp->dev = &pdev->dev; |
1262 | 1443 | ||
1444 | irq = platform_get_irq_byname(pdev, "rx"); | ||
1445 | if (irq >= 0) { | ||
1446 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", | ||
1447 | dev_name(&pdev->dev)); | ||
1448 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1449 | davinci_mcasp_rx_irq_handler, | ||
1450 | IRQF_ONESHOT, irq_name, mcasp); | ||
1451 | if (ret) { | ||
1452 | dev_err(&pdev->dev, "RX IRQ request failed\n"); | ||
1453 | goto err; | ||
1454 | } | ||
1455 | |||
1456 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; | ||
1457 | } | ||
1458 | |||
1459 | irq = platform_get_irq_byname(pdev, "tx"); | ||
1460 | if (irq >= 0) { | ||
1461 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n", | ||
1462 | dev_name(&pdev->dev)); | ||
1463 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1464 | davinci_mcasp_tx_irq_handler, | ||
1465 | IRQF_ONESHOT, irq_name, mcasp); | ||
1466 | if (ret) { | ||
1467 | dev_err(&pdev->dev, "TX IRQ request failed\n"); | ||
1468 | goto err; | ||
1469 | } | ||
1470 | |||
1471 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; | ||
1472 | } | ||
1473 | |||
1263 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); | 1474 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); |
1264 | if (dat) | 1475 | if (dat) |
1265 | mcasp->dat_port = true; | 1476 | mcasp->dat_port = true; |
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 98fbc451892a..79dc511180bf 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -253,6 +253,13 @@ | |||
253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ | 253 | #define TXFSRST BIT(12) /* Frame Sync Generator Reset */ |
254 | 254 | ||
255 | /* | 255 | /* |
256 | * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits | ||
257 | * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits | ||
258 | */ | ||
259 | #define XRERR BIT(8) /* Transmit/Receive error */ | ||
260 | #define XRDATA BIT(5) /* Transmit/Receive data ready */ | ||
261 | |||
262 | /* | ||
256 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits | 263 | * DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits |
257 | */ | 264 | */ |
258 | #define MUTENA(val) (val) | 265 | #define MUTENA(val) (val) |
@@ -279,6 +286,16 @@ | |||
279 | #define TXDATADMADIS BIT(0) | 286 | #define TXDATADMADIS BIT(0) |
280 | 287 | ||
281 | /* | 288 | /* |
289 | * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits | ||
290 | */ | ||
291 | #define ROVRN BIT(0) | ||
292 | |||
293 | /* | ||
294 | * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits | ||
295 | */ | ||
296 | #define XUNDRN BIT(0) | ||
297 | |||
298 | /* | ||
282 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits | 299 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits |
283 | */ | 300 | */ |
284 | #define FIFO_ENABLE BIT(16) | 301 | #define FIFO_ENABLE BIT(16) |
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index e961388e6e9c..08f0229f8d68 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -338,31 +338,34 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
338 | return -EINVAL; | 338 | return -EINVAL; |
339 | } | 339 | } |
340 | 340 | ||
341 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
342 | if (!res) { | ||
343 | dev_err(&pdev->dev, "no i2s resource defined\n"); | ||
344 | return -ENODEV; | ||
345 | } | ||
346 | |||
347 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
348 | resource_size(res), pdev->name)) { | ||
349 | dev_err(&pdev->dev, "i2s region already claimed\n"); | ||
350 | return -EBUSY; | ||
351 | } | ||
352 | |||
353 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | 341 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); |
354 | if (!dev) { | 342 | if (!dev) { |
355 | dev_warn(&pdev->dev, "kzalloc fail\n"); | 343 | dev_warn(&pdev->dev, "kzalloc fail\n"); |
356 | return -ENOMEM; | 344 | return -ENOMEM; |
357 | } | 345 | } |
358 | 346 | ||
359 | dev->i2s_base = devm_ioremap(&pdev->dev, res->start, | 347 | dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); |
360 | resource_size(res)); | 348 | if (!dw_i2s_dai) { |
361 | if (!dev->i2s_base) { | 349 | dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); |
362 | dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); | ||
363 | return -ENOMEM; | 350 | return -ENOMEM; |
364 | } | 351 | } |
365 | 352 | ||
353 | dw_i2s_dai->ops = &dw_i2s_dai_ops; | ||
354 | dw_i2s_dai->suspend = dw_i2s_suspend; | ||
355 | dw_i2s_dai->resume = dw_i2s_resume; | ||
356 | |||
357 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
358 | if (!res) { | ||
359 | dev_err(&pdev->dev, "no i2s resource defined\n"); | ||
360 | return -ENODEV; | ||
361 | } | ||
362 | |||
363 | dev->i2s_base = devm_ioremap_resource(&pdev->dev, res); | ||
364 | if (IS_ERR(dev->i2s_base)) { | ||
365 | dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); | ||
366 | return PTR_ERR(dev->i2s_base); | ||
367 | } | ||
368 | |||
366 | cap = pdata->cap; | 369 | cap = pdata->cap; |
367 | dev->capability = cap; | 370 | dev->capability = cap; |
368 | dev->i2s_clk_cfg = pdata->i2s_clk_cfg; | 371 | dev->i2s_clk_cfg = pdata->i2s_clk_cfg; |
@@ -388,13 +391,6 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
388 | if (ret < 0) | 391 | if (ret < 0) |
389 | goto err_clk_put; | 392 | goto err_clk_put; |
390 | 393 | ||
391 | dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); | ||
392 | if (!dw_i2s_dai) { | ||
393 | dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); | ||
394 | ret = -ENOMEM; | ||
395 | goto err_clk_disable; | ||
396 | } | ||
397 | |||
398 | if (cap & DWC_I2S_PLAY) { | 394 | if (cap & DWC_I2S_PLAY) { |
399 | dev_dbg(&pdev->dev, " designware: play supported\n"); | 395 | dev_dbg(&pdev->dev, " designware: play supported\n"); |
400 | dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; | 396 | dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; |
@@ -411,10 +407,6 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
411 | dw_i2s_dai->capture.rates = pdata->snd_rates; | 407 | dw_i2s_dai->capture.rates = pdata->snd_rates; |
412 | } | 408 | } |
413 | 409 | ||
414 | dw_i2s_dai->ops = &dw_i2s_dai_ops; | ||
415 | dw_i2s_dai->suspend = dw_i2s_suspend; | ||
416 | dw_i2s_dai->resume = dw_i2s_resume; | ||
417 | |||
418 | dev->dev = &pdev->dev; | 410 | dev->dev = &pdev->dev; |
419 | dev_set_drvdata(&pdev->dev, dev); | 411 | dev_set_drvdata(&pdev->dev, dev); |
420 | ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, | 412 | ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component, |
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index eb093d5b85c4..b175b0145a42 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c | |||
@@ -105,7 +105,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
105 | int ret; | 105 | int ret; |
106 | int int_port = 0, ext_port; | 106 | int int_port = 0, ext_port; |
107 | struct device_node *np = pdev->dev.of_node; | 107 | struct device_node *np = pdev->dev.of_node; |
108 | struct device_node *ssi_np, *codec_np; | 108 | struct device_node *ssi_np = NULL, *codec_np = NULL; |
109 | 109 | ||
110 | eukrea_tlv320.dev = &pdev->dev; | 110 | eukrea_tlv320.dev = &pdev->dev; |
111 | if (np) { | 111 | if (np) { |
@@ -217,8 +217,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
217 | err: | 217 | err: |
218 | if (ret) | 218 | if (ret) |
219 | 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) | 220 | of_node_put(ssi_np); |
221 | of_node_put(ssi_np); | ||
222 | 221 | ||
223 | return ret; | 222 | return ret; |
224 | } | 223 | } |
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 007c772f3cef..3f6959c8e2f7 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c | |||
@@ -51,6 +51,7 @@ struct codec_priv { | |||
51 | * @sysclk_freq[2]: SYSCLK rates for set_sysclk() | 51 | * @sysclk_freq[2]: SYSCLK rates for set_sysclk() |
52 | * @sysclk_dir[2]: SYSCLK directions for set_sysclk() | 52 | * @sysclk_dir[2]: SYSCLK directions for set_sysclk() |
53 | * @sysclk_id[2]: SYSCLK ids for set_sysclk() | 53 | * @sysclk_id[2]: SYSCLK ids for set_sysclk() |
54 | * @slot_width: Slot width of each frame | ||
54 | * | 55 | * |
55 | * Note: [1] for tx and [0] for rx | 56 | * Note: [1] for tx and [0] for rx |
56 | */ | 57 | */ |
@@ -58,6 +59,7 @@ struct cpu_priv { | |||
58 | unsigned long sysclk_freq[2]; | 59 | unsigned long sysclk_freq[2]; |
59 | u32 sysclk_dir[2]; | 60 | u32 sysclk_dir[2]; |
60 | u32 sysclk_id[2]; | 61 | u32 sysclk_id[2]; |
62 | u32 slot_width; | ||
61 | }; | 63 | }; |
62 | 64 | ||
63 | /** | 65 | /** |
@@ -125,7 +127,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, | |||
125 | priv->sample_rate = params_rate(params); | 127 | priv->sample_rate = params_rate(params); |
126 | priv->sample_format = params_format(params); | 128 | priv->sample_format = params_format(params); |
127 | 129 | ||
128 | if (priv->card.set_bias_level) | 130 | /* |
131 | * If codec-dai is DAI Master and all configurations are already in the | ||
132 | * set_bias_level(), bypass the remaining settings in hw_params(). | ||
133 | * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS. | ||
134 | */ | ||
135 | if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM) | ||
129 | return 0; | 136 | return 0; |
130 | 137 | ||
131 | /* Specific configurations of DAIs starts from here */ | 138 | /* Specific configurations of DAIs starts from here */ |
@@ -137,6 +144,15 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, | |||
137 | return ret; | 144 | return ret; |
138 | } | 145 | } |
139 | 146 | ||
147 | if (cpu_priv->slot_width) { | ||
148 | ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2, | ||
149 | cpu_priv->slot_width); | ||
150 | if (ret) { | ||
151 | dev_err(dev, "failed to set TDM slot for cpu dai\n"); | ||
152 | return ret; | ||
153 | } | ||
154 | } | ||
155 | |||
140 | return 0; | 156 | return 0; |
141 | } | 157 | } |
142 | 158 | ||
@@ -448,6 +464,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) | |||
448 | priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; | 464 | priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; |
449 | priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; | 465 | priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; |
450 | priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; | 466 | priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; |
467 | priv->cpu_priv.slot_width = 32; | ||
451 | priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; | 468 | priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; |
452 | } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { | 469 | } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { |
453 | priv->codec_priv.mclk_id = SGTL5000_SYSCLK; | 470 | priv->codec_priv.mclk_id = SGTL5000_SYSCLK; |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index a645e296199e..ca319d59f843 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -513,10 +513,15 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
513 | u32 width = snd_pcm_format_width(params_format(params)); | 513 | u32 width = snd_pcm_format_width(params_format(params)); |
514 | u32 channels = params_channels(params); | 514 | u32 channels = params_channels(params); |
515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); | 515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); |
516 | u32 slot_width = width; | ||
516 | u32 bclk, mask, val; | 517 | u32 bclk, mask, val; |
517 | int ret; | 518 | int ret; |
518 | 519 | ||
519 | bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; | 520 | /* Override slot_width if being specifially set */ |
521 | if (esai_priv->slot_width) | ||
522 | slot_width = esai_priv->slot_width; | ||
523 | |||
524 | bclk = params_rate(params) * slot_width * esai_priv->slots; | ||
520 | 525 | ||
521 | ret = fsl_esai_set_bclk(dai, tx, bclk); | 526 | ret = fsl_esai_set_bclk(dai, tx, bclk); |
522 | if (ret) | 527 | if (ret) |
@@ -538,7 +543,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
538 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); | 543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); |
539 | 544 | ||
540 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); | 545 | mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0); |
541 | val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0); | 546 | val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0); |
542 | 547 | ||
543 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); | 548 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val); |
544 | 549 | ||
@@ -780,9 +785,6 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
780 | return ret; | 785 | return ret; |
781 | } | 786 | } |
782 | 787 | ||
783 | /* Set a default slot size */ | ||
784 | esai_priv->slot_width = 32; | ||
785 | |||
786 | /* Set a default slot number */ | 788 | /* Set a default slot number */ |
787 | esai_priv->slots = 2; | 789 | esai_priv->slots = 2; |
788 | 790 | ||
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index e6955170dc42..b6b0d25f6ace 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -67,8 +67,6 @@ | |||
67 | /** | 67 | /** |
68 | * FSLSSI_I2S_FORMATS: audio formats supported by the SSI | 68 | * FSLSSI_I2S_FORMATS: audio formats supported by the SSI |
69 | * | 69 | * |
70 | * This driver currently only supports the SSI running in I2S slave mode. | ||
71 | * | ||
72 | * The SSI has a limitation in that the samples must be in the same byte | 70 | * The SSI has a limitation in that the samples must be in the same byte |
73 | * order as the host CPU. This is because when multiple bytes are written | 71 | * order as the host CPU. This is because when multiple bytes are written |
74 | * to the STX register, the bytes and bits must be written in the same | 72 | * to the STX register, the bytes and bits must be written in the same |
@@ -1099,7 +1097,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = { | |||
1099 | }; | 1097 | }; |
1100 | 1098 | ||
1101 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { | 1099 | static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { |
1102 | .ac97_control = 1, | 1100 | .bus_control = true, |
1103 | .playback = { | 1101 | .playback = { |
1104 | .stream_name = "AC97 Playback", | 1102 | .stream_name = "AC97 Playback", |
1105 | .channels_min = 2, | 1103 | .channels_min = 2, |
@@ -1363,7 +1361,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1363 | return PTR_ERR(ssi_private->regs); | 1361 | return PTR_ERR(ssi_private->regs); |
1364 | } | 1362 | } |
1365 | 1363 | ||
1366 | ssi_private->irq = irq_of_parse_and_map(np, 0); | 1364 | ssi_private->irq = platform_get_irq(pdev, 0); |
1367 | if (!ssi_private->irq) { | 1365 | if (!ssi_private->irq) { |
1368 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); | 1366 | dev_err(&pdev->dev, "no irq for node %s\n", np->full_name); |
1369 | return -ENXIO; | 1367 | return -ENXIO; |
@@ -1389,7 +1387,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1389 | if (ssi_private->soc->imx) { | 1387 | if (ssi_private->soc->imx) { |
1390 | ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem); | 1388 | ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem); |
1391 | if (ret) | 1389 | if (ret) |
1392 | goto error_irqmap; | 1390 | return ret; |
1393 | } | 1391 | } |
1394 | 1392 | ||
1395 | ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, | 1393 | ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component, |
@@ -1412,7 +1410,7 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1412 | 1410 | ||
1413 | ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev); | 1411 | ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev); |
1414 | if (ret) | 1412 | if (ret) |
1415 | goto error_asoc_register; | 1413 | goto error_irq; |
1416 | 1414 | ||
1417 | /* | 1415 | /* |
1418 | * If codec-handle property is missing from SSI node, we assume | 1416 | * If codec-handle property is missing from SSI node, we assume |
@@ -1460,10 +1458,6 @@ error_asoc_register: | |||
1460 | if (ssi_private->soc->imx) | 1458 | if (ssi_private->soc->imx) |
1461 | fsl_ssi_imx_clean(pdev, ssi_private); | 1459 | fsl_ssi_imx_clean(pdev, ssi_private); |
1462 | 1460 | ||
1463 | error_irqmap: | ||
1464 | if (ssi_private->use_dma) | ||
1465 | irq_dispose_mapping(ssi_private->irq); | ||
1466 | |||
1467 | return ret; | 1461 | return ret; |
1468 | } | 1462 | } |
1469 | 1463 | ||
@@ -1480,9 +1474,6 @@ static int fsl_ssi_remove(struct platform_device *pdev) | |||
1480 | if (ssi_private->soc->imx) | 1474 | if (ssi_private->soc->imx) |
1481 | fsl_ssi_imx_clean(pdev, ssi_private); | 1475 | fsl_ssi_imx_clean(pdev, ssi_private); |
1482 | 1476 | ||
1483 | if (ssi_private->use_dma) | ||
1484 | irq_dispose_mapping(ssi_private->irq); | ||
1485 | |||
1486 | return 0; | 1477 | return 0; |
1487 | } | 1478 | } |
1488 | 1479 | ||
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 1cb22dd034eb..1dab963a59f7 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c | |||
@@ -175,10 +175,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) | |||
175 | fail: | 175 | fail: |
176 | if (data && !IS_ERR(data->codec_clk)) | 176 | if (data && !IS_ERR(data->codec_clk)) |
177 | clk_put(data->codec_clk); | 177 | clk_put(data->codec_clk); |
178 | if (ssi_np) | 178 | of_node_put(ssi_np); |
179 | of_node_put(ssi_np); | 179 | of_node_put(codec_np); |
180 | if (codec_np) | ||
181 | of_node_put(codec_np); | ||
182 | 180 | ||
183 | return ret; | 181 | return ret; |
184 | } | 182 | } |
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c index e1dc40143600..0c9068ebe1e7 100644 --- a/sound/soc/fsl/imx-spdif.c +++ b/sound/soc/fsl/imx-spdif.c | |||
@@ -74,8 +74,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev) | |||
74 | platform_set_drvdata(pdev, data); | 74 | platform_set_drvdata(pdev, data); |
75 | 75 | ||
76 | end: | 76 | end: |
77 | if (spdif_np) | 77 | of_node_put(spdif_np); |
78 | of_node_put(spdif_np); | ||
79 | 78 | ||
80 | return ret; | 79 | return ret; |
81 | } | 80 | } |
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index ab2fdd76b693..60b0a5b1f1f1 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c | |||
@@ -382,7 +382,7 @@ static struct snd_soc_dai_driver imx_ssi_dai = { | |||
382 | 382 | ||
383 | static struct snd_soc_dai_driver imx_ac97_dai = { | 383 | static struct snd_soc_dai_driver imx_ac97_dai = { |
384 | .probe = imx_ssi_dai_probe, | 384 | .probe = imx_ssi_dai_probe, |
385 | .ac97_control = 1, | 385 | .bus_control = true, |
386 | .playback = { | 386 | .playback = { |
387 | .stream_name = "AC97 Playback", | 387 | .stream_name = "AC97 Playback", |
388 | .channels_min = 2, | 388 | .channels_min = 2, |
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3a3d17ce6ba4..48179ffe1543 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c | |||
@@ -281,10 +281,8 @@ static int imx_wm8962_probe(struct platform_device *pdev) | |||
281 | clk_fail: | 281 | clk_fail: |
282 | clk_disable_unprepare(data->codec_clk); | 282 | clk_disable_unprepare(data->codec_clk); |
283 | fail: | 283 | fail: |
284 | if (ssi_np) | 284 | of_node_put(ssi_np); |
285 | of_node_put(ssi_np); | 285 | of_node_put(codec_np); |
286 | if (codec_np) | ||
287 | of_node_put(codec_np); | ||
288 | 286 | ||
289 | return ret; | 287 | return ret; |
290 | } | 288 | } |
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index f2b5d756b1f3..0b82e209b6e3 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c | |||
@@ -327,9 +327,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd) | |||
327 | goto capture_alloc_err; | 327 | goto capture_alloc_err; |
328 | } | 328 | } |
329 | 329 | ||
330 | if (rtd->codec->ac97) | ||
331 | rtd->codec->ac97->private_data = psc_dma; | ||
332 | |||
333 | return 0; | 330 | return 0; |
334 | 331 | ||
335 | capture_alloc_err: | 332 | capture_alloc_err: |
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c index 24eafa2cfbf4..c6ed6ba965a9 100644 --- a/sound/soc/fsl/mpc5200_psc_ac97.c +++ b/sound/soc/fsl/mpc5200_psc_ac97.c | |||
@@ -237,7 +237,7 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = { | |||
237 | static struct snd_soc_dai_driver psc_ac97_dai[] = { | 237 | static struct snd_soc_dai_driver psc_ac97_dai[] = { |
238 | { | 238 | { |
239 | .name = "mpc5200-psc-ac97.0", | 239 | .name = "mpc5200-psc-ac97.0", |
240 | .ac97_control = 1, | 240 | .bus_control = true, |
241 | .probe = psc_ac97_probe, | 241 | .probe = psc_ac97_probe, |
242 | .playback = { | 242 | .playback = { |
243 | .stream_name = "AC97 Playback", | 243 | .stream_name = "AC97 Playback", |
@@ -257,7 +257,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = { | |||
257 | }, | 257 | }, |
258 | { | 258 | { |
259 | .name = "mpc5200-psc-ac97.1", | 259 | .name = "mpc5200-psc-ac97.1", |
260 | .ac97_control = 1, | 260 | .bus_control = true, |
261 | .playback = { | 261 | .playback = { |
262 | .stream_name = "AC97 SPDIF", | 262 | .stream_name = "AC97 SPDIF", |
263 | .channels_min = 1, | 263 | .channels_min = 1, |
@@ -282,7 +282,6 @@ static const struct snd_soc_component_driver psc_ac97_component = { | |||
282 | static int psc_ac97_of_probe(struct platform_device *op) | 282 | static int psc_ac97_of_probe(struct platform_device *op) |
283 | { | 283 | { |
284 | int rc; | 284 | int rc; |
285 | struct snd_ac97 ac97; | ||
286 | struct mpc52xx_psc __iomem *regs; | 285 | struct mpc52xx_psc __iomem *regs; |
287 | 286 | ||
288 | rc = mpc5200_audio_dma_create(op); | 287 | rc = mpc5200_audio_dma_create(op); |
@@ -304,7 +303,6 @@ static int psc_ac97_of_probe(struct platform_device *op) | |||
304 | 303 | ||
305 | psc_dma = dev_get_drvdata(&op->dev); | 304 | psc_dma = dev_get_drvdata(&op->dev); |
306 | regs = psc_dma->psc_regs; | 305 | regs = psc_dma->psc_regs; |
307 | ac97.private_data = psc_dma; | ||
308 | 306 | ||
309 | psc_dma->imr = 0; | 307 | psc_dma->imr = 0; |
310 | out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); | 308 | out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr); |
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d1b7293c133e..ece22d55ba82 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -29,7 +29,9 @@ struct simple_card_data { | |||
29 | } *dai_props; | 29 | } *dai_props; |
30 | unsigned int mclk_fs; | 30 | unsigned int mclk_fs; |
31 | int gpio_hp_det; | 31 | int gpio_hp_det; |
32 | int gpio_hp_det_invert; | ||
32 | int gpio_mic_det; | 33 | int gpio_mic_det; |
34 | int gpio_mic_det_invert; | ||
33 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ | 35 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ |
34 | }; | 36 | }; |
35 | 37 | ||
@@ -148,6 +150,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
148 | simple_card_hp_jack_pins); | 150 | simple_card_hp_jack_pins); |
149 | 151 | ||
150 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; | 152 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; |
153 | simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; | ||
151 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, | 154 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, |
152 | &simple_card_hp_jack_gpio); | 155 | &simple_card_hp_jack_gpio); |
153 | } | 156 | } |
@@ -159,6 +162,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
159 | ARRAY_SIZE(simple_card_mic_jack_pins), | 162 | ARRAY_SIZE(simple_card_mic_jack_pins), |
160 | simple_card_mic_jack_pins); | 163 | simple_card_mic_jack_pins); |
161 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; | 164 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; |
165 | simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; | ||
162 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, | 166 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, |
163 | &simple_card_mic_jack_gpio); | 167 | &simple_card_mic_jack_gpio); |
164 | } | 168 | } |
@@ -226,6 +230,52 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
226 | return 0; | 230 | return 0; |
227 | } | 231 | } |
228 | 232 | ||
233 | static int asoc_simple_card_parse_daifmt(struct device_node *node, | ||
234 | struct simple_card_data *priv, | ||
235 | struct device_node *codec, | ||
236 | char *prefix, int idx) | ||
237 | { | ||
238 | struct device *dev = simple_priv_to_dev(priv); | ||
239 | struct device_node *bitclkmaster = NULL; | ||
240 | struct device_node *framemaster = NULL; | ||
241 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | ||
242 | struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai; | ||
243 | struct asoc_simple_dai *codec_dai = &dai_props->codec_dai; | ||
244 | unsigned int daifmt; | ||
245 | |||
246 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
247 | &bitclkmaster, &framemaster); | ||
248 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
249 | |||
250 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | ||
251 | /* | ||
252 | * No dai-link level and master setting was not found from | ||
253 | * sound node level, revert back to legacy DT parsing and | ||
254 | * take the settings from codec node. | ||
255 | */ | ||
256 | dev_dbg(dev, "Revert to legacy daifmt parsing\n"); | ||
257 | |||
258 | cpu_dai->fmt = codec_dai->fmt = | ||
259 | snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | | ||
260 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
261 | } else { | ||
262 | if (codec == bitclkmaster) | ||
263 | daifmt |= (codec == framemaster) ? | ||
264 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
265 | else | ||
266 | daifmt |= (codec == framemaster) ? | ||
267 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
268 | |||
269 | cpu_dai->fmt = daifmt; | ||
270 | codec_dai->fmt = daifmt; | ||
271 | } | ||
272 | |||
273 | of_node_put(bitclkmaster); | ||
274 | of_node_put(framemaster); | ||
275 | |||
276 | return 0; | ||
277 | } | ||
278 | |||
229 | static int asoc_simple_card_dai_link_of(struct device_node *node, | 279 | static int asoc_simple_card_dai_link_of(struct device_node *node, |
230 | struct simple_card_data *priv, | 280 | struct simple_card_data *priv, |
231 | int idx, | 281 | int idx, |
@@ -234,10 +284,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
234 | struct device *dev = simple_priv_to_dev(priv); | 284 | struct device *dev = simple_priv_to_dev(priv); |
235 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | 285 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); |
236 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | 286 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); |
237 | struct device_node *np = NULL; | 287 | struct device_node *cpu = NULL; |
238 | struct device_node *bitclkmaster = NULL; | 288 | struct device_node *codec = NULL; |
239 | struct device_node *framemaster = NULL; | ||
240 | unsigned int daifmt; | ||
241 | char *name; | 289 | char *name; |
242 | char prop[128]; | 290 | char prop[128]; |
243 | char *prefix = ""; | 291 | char *prefix = ""; |
@@ -247,85 +295,36 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
247 | if (is_top_level_node) | 295 | if (is_top_level_node) |
248 | prefix = "simple-audio-card,"; | 296 | prefix = "simple-audio-card,"; |
249 | 297 | ||
250 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
251 | &bitclkmaster, &framemaster); | ||
252 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
253 | |||
254 | snprintf(prop, sizeof(prop), "%scpu", prefix); | 298 | snprintf(prop, sizeof(prop), "%scpu", prefix); |
255 | np = of_get_child_by_name(node, prop); | 299 | cpu = of_get_child_by_name(node, prop); |
256 | if (!np) { | 300 | |
301 | snprintf(prop, sizeof(prop), "%scodec", prefix); | ||
302 | codec = of_get_child_by_name(node, prop); | ||
303 | |||
304 | if (!cpu || !codec) { | ||
257 | ret = -EINVAL; | 305 | ret = -EINVAL; |
258 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | 306 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); |
259 | goto dai_link_of_err; | 307 | goto dai_link_of_err; |
260 | } | 308 | } |
261 | 309 | ||
262 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, | 310 | ret = asoc_simple_card_parse_daifmt(node, priv, |
311 | codec, prefix, idx); | ||
312 | if (ret < 0) | ||
313 | goto dai_link_of_err; | ||
314 | |||
315 | ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai, | ||
263 | &dai_link->cpu_of_node, | 316 | &dai_link->cpu_of_node, |
264 | &dai_link->cpu_dai_name, | 317 | &dai_link->cpu_dai_name, |
265 | &cpu_args); | 318 | &cpu_args); |
266 | if (ret < 0) | 319 | if (ret < 0) |
267 | goto dai_link_of_err; | 320 | goto dai_link_of_err; |
268 | 321 | ||
269 | dai_props->cpu_dai.fmt = daifmt; | 322 | ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai, |
270 | switch (((np == bitclkmaster) << 4) | (np == framemaster)) { | ||
271 | case 0x11: | ||
272 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
273 | break; | ||
274 | case 0x10: | ||
275 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; | ||
276 | break; | ||
277 | case 0x01: | ||
278 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; | ||
279 | break; | ||
280 | default: | ||
281 | dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
282 | break; | ||
283 | } | ||
284 | |||
285 | of_node_put(np); | ||
286 | snprintf(prop, sizeof(prop), "%scodec", prefix); | ||
287 | np = of_get_child_by_name(node, prop); | ||
288 | if (!np) { | ||
289 | ret = -EINVAL; | ||
290 | dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop); | ||
291 | goto dai_link_of_err; | ||
292 | } | ||
293 | |||
294 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, | ||
295 | &dai_link->codec_of_node, | 323 | &dai_link->codec_of_node, |
296 | &dai_link->codec_dai_name, NULL); | 324 | &dai_link->codec_dai_name, NULL); |
297 | if (ret < 0) | 325 | if (ret < 0) |
298 | goto dai_link_of_err; | 326 | goto dai_link_of_err; |
299 | 327 | ||
300 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | ||
301 | /* | ||
302 | * No DAI link level and master setting was found | ||
303 | * from sound node level, revert back to legacy DT | ||
304 | * parsing and take the settings from codec node. | ||
305 | */ | ||
306 | dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", | ||
307 | __func__); | ||
308 | dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = | ||
309 | snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) | | ||
310 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
311 | } else { | ||
312 | dai_props->codec_dai.fmt = daifmt; | ||
313 | switch (((np == bitclkmaster) << 4) | (np == framemaster)) { | ||
314 | case 0x11: | ||
315 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
316 | break; | ||
317 | case 0x10: | ||
318 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS; | ||
319 | break; | ||
320 | case 0x01: | ||
321 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM; | ||
322 | break; | ||
323 | default: | ||
324 | dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
325 | break; | ||
326 | } | ||
327 | } | ||
328 | |||
329 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | 328 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { |
330 | ret = -EINVAL; | 329 | ret = -EINVAL; |
331 | goto dai_link_of_err; | 330 | goto dai_link_of_err; |
@@ -368,12 +367,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
368 | dai_link->cpu_dai_name = NULL; | 367 | dai_link->cpu_dai_name = NULL; |
369 | 368 | ||
370 | dai_link_of_err: | 369 | dai_link_of_err: |
371 | if (np) | 370 | of_node_put(cpu); |
372 | of_node_put(np); | 371 | of_node_put(codec); |
373 | if (bitclkmaster) | 372 | |
374 | of_node_put(bitclkmaster); | ||
375 | if (framemaster) | ||
376 | of_node_put(framemaster); | ||
377 | return ret; | 373 | return ret; |
378 | } | 374 | } |
379 | 375 | ||
@@ -381,6 +377,7 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
381 | struct simple_card_data *priv) | 377 | struct simple_card_data *priv) |
382 | { | 378 | { |
383 | struct device *dev = simple_priv_to_dev(priv); | 379 | struct device *dev = simple_priv_to_dev(priv); |
380 | enum of_gpio_flags flags; | ||
384 | u32 val; | 381 | u32 val; |
385 | int ret; | 382 | int ret; |
386 | 383 | ||
@@ -436,13 +433,15 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
436 | return ret; | 433 | return ret; |
437 | } | 434 | } |
438 | 435 | ||
439 | priv->gpio_hp_det = of_get_named_gpio(node, | 436 | priv->gpio_hp_det = of_get_named_gpio_flags(node, |
440 | "simple-audio-card,hp-det-gpio", 0); | 437 | "simple-audio-card,hp-det-gpio", 0, &flags); |
438 | priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
441 | if (priv->gpio_hp_det == -EPROBE_DEFER) | 439 | if (priv->gpio_hp_det == -EPROBE_DEFER) |
442 | return -EPROBE_DEFER; | 440 | return -EPROBE_DEFER; |
443 | 441 | ||
444 | priv->gpio_mic_det = of_get_named_gpio(node, | 442 | priv->gpio_mic_det = of_get_named_gpio_flags(node, |
445 | "simple-audio-card,mic-det-gpio", 0); | 443 | "simple-audio-card,mic-det-gpio", 0, &flags); |
444 | priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
446 | if (priv->gpio_mic_det == -EPROBE_DEFER) | 445 | if (priv->gpio_mic_det == -EPROBE_DEFER) |
447 | return -EPROBE_DEFER; | 446 | return -EPROBE_DEFER; |
448 | 447 | ||
@@ -457,18 +456,13 @@ static int asoc_simple_card_unref(struct platform_device *pdev) | |||
457 | { | 456 | { |
458 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 457 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
459 | struct snd_soc_dai_link *dai_link; | 458 | struct snd_soc_dai_link *dai_link; |
460 | struct device_node *np; | ||
461 | int num_links; | 459 | int num_links; |
462 | 460 | ||
463 | for (num_links = 0, dai_link = card->dai_link; | 461 | for (num_links = 0, dai_link = card->dai_link; |
464 | num_links < card->num_links; | 462 | num_links < card->num_links; |
465 | num_links++, dai_link++) { | 463 | num_links++, dai_link++) { |
466 | np = (struct device_node *) dai_link->cpu_of_node; | 464 | of_node_put(dai_link->cpu_of_node); |
467 | if (np) | 465 | of_node_put(dai_link->codec_of_node); |
468 | of_node_put(np); | ||
469 | np = (struct device_node *) dai_link->codec_of_node; | ||
470 | if (np) | ||
471 | of_node_put(np); | ||
472 | } | 466 | } |
473 | return 0; | 467 | return 0; |
474 | } | 468 | } |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f5b4a9c79cdf..e989ecf046c9 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -3,6 +3,7 @@ config SND_MFLD_MACHINE | |||
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_MFLD_PLATFORM | 5 | select SND_SST_MFLD_PLATFORM |
6 | select SND_SST_IPC_PCI | ||
6 | help | 7 | help |
7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform | 8 | 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 | 9 | used as alsa device in audio substem in Intel(R) MID devices |
@@ -12,10 +13,23 @@ config SND_MFLD_MACHINE | |||
12 | config SND_SST_MFLD_PLATFORM | 13 | config SND_SST_MFLD_PLATFORM |
13 | tristate | 14 | tristate |
14 | 15 | ||
16 | config SND_SST_IPC | ||
17 | tristate | ||
18 | |||
19 | config SND_SST_IPC_PCI | ||
20 | tristate | ||
21 | select SND_SST_IPC | ||
22 | |||
23 | config SND_SST_IPC_ACPI | ||
24 | tristate | ||
25 | select SND_SST_IPC | ||
26 | depends on ACPI | ||
27 | |||
15 | config SND_SOC_INTEL_SST | 28 | config SND_SOC_INTEL_SST |
16 | tristate "ASoC support for Intel(R) Smart Sound Technology" | 29 | tristate "ASoC support for Intel(R) Smart Sound Technology" |
17 | select SND_SOC_INTEL_SST_ACPI if ACPI | 30 | select SND_SOC_INTEL_SST_ACPI if ACPI |
18 | depends on (X86 || COMPILE_TEST) | 31 | depends on (X86 || COMPILE_TEST) |
32 | depends on DW_DMAC_CORE | ||
19 | help | 33 | help |
20 | This adds support for Intel(R) Smart Sound Technology (SST). | 34 | This adds support for Intel(R) Smart Sound Technology (SST). |
21 | Say Y if you have such a device | 35 | Say Y if you have such a device |
@@ -32,7 +46,8 @@ config SND_SOC_INTEL_BAYTRAIL | |||
32 | 46 | ||
33 | config SND_SOC_INTEL_HASWELL_MACH | 47 | config SND_SOC_INTEL_HASWELL_MACH |
34 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | 48 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" |
35 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C | 49 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\ |
50 | I2C_DESIGNWARE_PLATFORM | ||
36 | select SND_SOC_INTEL_HASWELL | 51 | select SND_SOC_INTEL_HASWELL |
37 | select SND_SOC_RT5640 | 52 | select SND_SOC_RT5640 |
38 | help | 53 | help |
@@ -61,7 +76,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH | |||
61 | 76 | ||
62 | config SND_SOC_INTEL_BROADWELL_MACH | 77 | config SND_SOC_INTEL_BROADWELL_MACH |
63 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | 78 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" |
64 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC | 79 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\ |
80 | I2C_DESIGNWARE_PLATFORM | ||
65 | select SND_SOC_INTEL_HASWELL | 81 | select SND_SOC_INTEL_HASWELL |
66 | select SND_COMPRESS_OFFLOAD | 82 | select SND_COMPRESS_OFFLOAD |
67 | select SND_SOC_RT286 | 83 | select SND_SOC_RT286 |
@@ -70,3 +86,27 @@ config SND_SOC_INTEL_BROADWELL_MACH | |||
70 | Ultrabook platforms. | 86 | Ultrabook platforms. |
71 | Say Y if you have such a device | 87 | Say Y if you have such a device |
72 | If unsure select "N". | 88 | If unsure select "N". |
89 | |||
90 | config SND_SOC_INTEL_BYTCR_RT5640_MACH | ||
91 | tristate "ASoC Audio DSP Support for MID BYT Platform" | ||
92 | depends on X86 | ||
93 | select SND_SOC_RT5640 | ||
94 | select SND_SST_MFLD_PLATFORM | ||
95 | select SND_SST_IPC_ACPI | ||
96 | help | ||
97 | This adds support for ASoC machine driver for Intel(R) MID Baytrail platform | ||
98 | used as alsa device in audio substem in Intel(R) MID devices | ||
99 | Say Y if you have such a device | ||
100 | If unsure select "N". | ||
101 | |||
102 | config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | ||
103 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" | ||
104 | depends on X86_INTEL_LPSS | ||
105 | select SND_SOC_RT5670 | ||
106 | select SND_SST_MFLD_PLATFORM | ||
107 | select SND_SST_IPC_ACPI | ||
108 | help | ||
109 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | ||
110 | platforms with RT5672 audio codec. | ||
111 | Say Y if you have such a device | ||
112 | If unsure select "N". | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index f841786dad15..e928ec385300 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -26,8 +26,15 @@ snd-soc-sst-haswell-objs := haswell.o | |||
26 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 26 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
27 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 27 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
28 | snd-soc-sst-broadwell-objs := broadwell.o | 28 | snd-soc-sst-broadwell-objs := broadwell.o |
29 | snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o | ||
30 | snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o | ||
29 | 31 | ||
30 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 32 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
31 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 33 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
32 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 34 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
33 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 35 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
36 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o | ||
37 | obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o | ||
38 | |||
39 | # DSP driver | ||
40 | obj-$(CONFIG_SND_SST_IPC) += sst/ | ||
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c index 0e550f14028f..c256764e3c4b 100644 --- a/sound/soc/intel/broadwell.c +++ b/sound/soc/intel/broadwell.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <sound/core.h> | 19 | #include <sound/core.h> |
20 | #include <sound/pcm.h> | 20 | #include <sound/pcm.h> |
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | #include <sound/jack.h> | ||
22 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
23 | 24 | ||
24 | #include "sst-dsp.h" | 25 | #include "sst-dsp.h" |
@@ -26,8 +27,26 @@ | |||
26 | 27 | ||
27 | #include "../codecs/rt286.h" | 28 | #include "../codecs/rt286.h" |
28 | 29 | ||
30 | static struct snd_soc_jack broadwell_headset; | ||
31 | /* Headset jack detection DAPM pins */ | ||
32 | static struct snd_soc_jack_pin broadwell_headset_pins[] = { | ||
33 | { | ||
34 | .pin = "Mic Jack", | ||
35 | .mask = SND_JACK_MICROPHONE, | ||
36 | }, | ||
37 | { | ||
38 | .pin = "Headphone Jack", | ||
39 | .mask = SND_JACK_HEADPHONE, | ||
40 | }, | ||
41 | }; | ||
42 | |||
43 | static const struct snd_kcontrol_new broadwell_controls[] = { | ||
44 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
45 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
46 | }; | ||
47 | |||
29 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { | 48 | static const struct snd_soc_dapm_widget broadwell_widgets[] = { |
30 | SND_SOC_DAPM_HP("Headphones", NULL), | 49 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
31 | SND_SOC_DAPM_SPK("Speaker", NULL), | 50 | SND_SOC_DAPM_SPK("Speaker", NULL), |
32 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | 51 | SND_SOC_DAPM_MIC("Mic Jack", NULL), |
33 | SND_SOC_DAPM_MIC("DMIC1", NULL), | 52 | SND_SOC_DAPM_MIC("DMIC1", NULL), |
@@ -42,7 +61,7 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | |||
42 | {"Speaker", NULL, "SPOL"}, | 61 | {"Speaker", NULL, "SPOL"}, |
43 | 62 | ||
44 | /* HP jack connectors - unknown if we have jack deteck */ | 63 | /* HP jack connectors - unknown if we have jack deteck */ |
45 | {"Headphones", NULL, "HPO Pin"}, | 64 | {"Headphone Jack", NULL, "HPO Pin"}, |
46 | 65 | ||
47 | /* other jacks */ | 66 | /* other jacks */ |
48 | {"MIC1", NULL, "Mic Jack"}, | 67 | {"MIC1", NULL, "Mic Jack"}, |
@@ -57,6 +76,27 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = { | |||
57 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | 76 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, |
58 | }; | 77 | }; |
59 | 78 | ||
79 | static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
80 | { | ||
81 | struct snd_soc_codec *codec = rtd->codec; | ||
82 | int ret = 0; | ||
83 | ret = snd_soc_jack_new(codec, "Headset", | ||
84 | SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset); | ||
85 | |||
86 | if (ret) | ||
87 | return ret; | ||
88 | |||
89 | ret = snd_soc_jack_add_pins(&broadwell_headset, | ||
90 | ARRAY_SIZE(broadwell_headset_pins), | ||
91 | broadwell_headset_pins); | ||
92 | if (ret) | ||
93 | return ret; | ||
94 | |||
95 | rt286_mic_detect(codec, &broadwell_headset); | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | |||
60 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | 100 | static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, |
61 | struct snd_pcm_hw_params *params) | 101 | struct snd_pcm_hw_params *params) |
62 | { | 102 | { |
@@ -116,7 +156,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd) | |||
116 | } | 156 | } |
117 | 157 | ||
118 | /* always connected - check HP for jack detect */ | 158 | /* always connected - check HP for jack detect */ |
119 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | 159 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); |
120 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 160 | snd_soc_dapm_enable_pin(dapm, "Speaker"); |
121 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 161 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); |
122 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 162 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); |
@@ -131,7 +171,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
131 | /* Front End DAI links */ | 171 | /* Front End DAI links */ |
132 | { | 172 | { |
133 | .name = "System PCM", | 173 | .name = "System PCM", |
134 | .stream_name = "System Playback", | 174 | .stream_name = "System Playback/Capture", |
135 | .cpu_dai_name = "System Pin", | 175 | .cpu_dai_name = "System Pin", |
136 | .platform_name = "haswell-pcm-audio", | 176 | .platform_name = "haswell-pcm-audio", |
137 | .dynamic = 1, | 177 | .dynamic = 1, |
@@ -140,6 +180,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
140 | .init = broadwell_rtd_init, | 180 | .init = broadwell_rtd_init, |
141 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 181 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
142 | .dpcm_playback = 1, | 182 | .dpcm_playback = 1, |
183 | .dpcm_capture = 1, | ||
143 | }, | 184 | }, |
144 | { | 185 | { |
145 | .name = "Offload0", | 186 | .name = "Offload0", |
@@ -174,18 +215,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
174 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 215 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
175 | .dpcm_capture = 1, | 216 | .dpcm_capture = 1, |
176 | }, | 217 | }, |
177 | { | ||
178 | .name = "Capture PCM", | ||
179 | .stream_name = "Capture", | ||
180 | .cpu_dai_name = "Capture Pin", | ||
181 | .platform_name = "haswell-pcm-audio", | ||
182 | .dynamic = 1, | ||
183 | .codec_name = "snd-soc-dummy", | ||
184 | .codec_dai_name = "snd-soc-dummy-dai", | ||
185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
186 | .dpcm_capture = 1, | ||
187 | }, | ||
188 | |||
189 | /* Back End DAI links */ | 218 | /* Back End DAI links */ |
190 | { | 219 | { |
191 | /* SSP0 - Codec */ | 220 | /* SSP0 - Codec */ |
@@ -196,6 +225,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = { | |||
196 | .no_pcm = 1, | 225 | .no_pcm = 1, |
197 | .codec_name = "i2c-INT343A:00", | 226 | .codec_name = "i2c-INT343A:00", |
198 | .codec_dai_name = "rt286-aif1", | 227 | .codec_dai_name = "rt286-aif1", |
228 | .init = broadwell_rt286_codec_init, | ||
199 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 229 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
200 | SND_SOC_DAIFMT_CBS_CFS, | 230 | SND_SOC_DAIFMT_CBS_CFS, |
201 | .ignore_suspend = 1, | 231 | .ignore_suspend = 1, |
@@ -213,6 +243,8 @@ static struct snd_soc_card broadwell_rt286 = { | |||
213 | .owner = THIS_MODULE, | 243 | .owner = THIS_MODULE, |
214 | .dai_link = broadwell_rt286_dais, | 244 | .dai_link = broadwell_rt286_dais, |
215 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), | 245 | .num_links = ARRAY_SIZE(broadwell_rt286_dais), |
246 | .controls = broadwell_controls, | ||
247 | .num_controls = ARRAY_SIZE(broadwell_controls), | ||
216 | .dapm_widgets = broadwell_widgets, | 248 | .dapm_widgets = broadwell_widgets, |
217 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), | 249 | .num_dapm_widgets = ARRAY_SIZE(broadwell_widgets), |
218 | .dapm_routes = broadwell_rt286_map, | 250 | .dapm_routes = broadwell_rt286_map, |
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c new file mode 100644 index 000000000000..f5d0fc1ab10c --- /dev/null +++ b/sound/soc/intel/bytcr_dpcm_rt5640.c | |||
@@ -0,0 +1,230 @@ | |||
1 | /* | ||
2 | * byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform | ||
3 | * | ||
4 | * Copyright (C) 2014 Intel Corp | ||
5 | * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> | ||
6 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; version 2 of the License. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | * | ||
17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
18 | */ | ||
19 | |||
20 | #include <linux/init.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/device.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/input.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include "../codecs/rt5640.h" | ||
30 | #include "sst-atom-controls.h" | ||
31 | |||
32 | static const struct snd_soc_dapm_widget byt_dapm_widgets[] = { | ||
33 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
34 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
35 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
36 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
37 | }; | ||
38 | |||
39 | static const struct snd_soc_dapm_route byt_audio_map[] = { | ||
40 | {"IN2P", NULL, "Headset Mic"}, | ||
41 | {"IN2N", NULL, "Headset Mic"}, | ||
42 | {"Headset Mic", NULL, "MICBIAS1"}, | ||
43 | {"IN1P", NULL, "MICBIAS1"}, | ||
44 | {"LDO2", NULL, "Int Mic"}, | ||
45 | {"Headphone", NULL, "HPOL"}, | ||
46 | {"Headphone", NULL, "HPOR"}, | ||
47 | {"Ext Spk", NULL, "SPOLP"}, | ||
48 | {"Ext Spk", NULL, "SPOLN"}, | ||
49 | {"Ext Spk", NULL, "SPORP"}, | ||
50 | {"Ext Spk", NULL, "SPORN"}, | ||
51 | |||
52 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
53 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
54 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
55 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
56 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
57 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
58 | }; | ||
59 | |||
60 | static const struct snd_kcontrol_new byt_mc_controls[] = { | ||
61 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
62 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
63 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
64 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
65 | }; | ||
66 | |||
67 | static int byt_aif1_hw_params(struct snd_pcm_substream *substream, | ||
68 | struct snd_pcm_hw_params *params) | ||
69 | { | ||
70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
71 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
72 | int ret; | ||
73 | |||
74 | snd_soc_dai_set_bclk_ratio(codec_dai, 50); | ||
75 | |||
76 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | ||
77 | params_rate(params) * 512, | ||
78 | SND_SOC_CLOCK_IN); | ||
79 | if (ret < 0) { | ||
80 | dev_err(rtd->dev, "can't set codec clock %d\n", ret); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, | ||
85 | params_rate(params) * 50, | ||
86 | params_rate(params) * 512); | ||
87 | if (ret < 0) { | ||
88 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static const struct snd_soc_pcm_stream byt_dai_params = { | ||
96 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
97 | .rate_min = 48000, | ||
98 | .rate_max = 48000, | ||
99 | .channels_min = 2, | ||
100 | .channels_max = 2, | ||
101 | }; | ||
102 | |||
103 | static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
104 | struct snd_pcm_hw_params *params) | ||
105 | { | ||
106 | struct snd_interval *rate = hw_param_interval(params, | ||
107 | SNDRV_PCM_HW_PARAM_RATE); | ||
108 | struct snd_interval *channels = hw_param_interval(params, | ||
109 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
110 | |||
111 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
112 | rate->min = rate->max = 48000; | ||
113 | channels->min = channels->max = 2; | ||
114 | |||
115 | /* set SSP2 to 24-bit */ | ||
116 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
117 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
118 | SNDRV_PCM_FORMAT_S24_LE); | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static unsigned int rates_48000[] = { | ||
123 | 48000, | ||
124 | }; | ||
125 | |||
126 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
127 | .count = ARRAY_SIZE(rates_48000), | ||
128 | .list = rates_48000, | ||
129 | }; | ||
130 | |||
131 | static int byt_aif1_startup(struct snd_pcm_substream *substream) | ||
132 | { | ||
133 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
134 | SNDRV_PCM_HW_PARAM_RATE, | ||
135 | &constraints_48000); | ||
136 | } | ||
137 | |||
138 | static struct snd_soc_ops byt_aif1_ops = { | ||
139 | .startup = byt_aif1_startup, | ||
140 | }; | ||
141 | |||
142 | static struct snd_soc_ops byt_be_ssp2_ops = { | ||
143 | .hw_params = byt_aif1_hw_params, | ||
144 | }; | ||
145 | |||
146 | static struct snd_soc_dai_link byt_dailink[] = { | ||
147 | [MERR_DPCM_AUDIO] = { | ||
148 | .name = "Baytrail Audio Port", | ||
149 | .stream_name = "Baytrail Audio", | ||
150 | .cpu_dai_name = "media-cpu-dai", | ||
151 | .codec_dai_name = "snd-soc-dummy-dai", | ||
152 | .codec_name = "snd-soc-dummy", | ||
153 | .platform_name = "sst-mfld-platform", | ||
154 | .ignore_suspend = 1, | ||
155 | .dynamic = 1, | ||
156 | .dpcm_playback = 1, | ||
157 | .dpcm_capture = 1, | ||
158 | .ops = &byt_aif1_ops, | ||
159 | }, | ||
160 | [MERR_DPCM_COMPR] = { | ||
161 | .name = "Baytrail Compressed Port", | ||
162 | .stream_name = "Baytrail Compress", | ||
163 | .cpu_dai_name = "compress-cpu-dai", | ||
164 | .codec_dai_name = "snd-soc-dummy-dai", | ||
165 | .codec_name = "snd-soc-dummy", | ||
166 | .platform_name = "sst-mfld-platform", | ||
167 | }, | ||
168 | /* back ends */ | ||
169 | { | ||
170 | .name = "SSP2-Codec", | ||
171 | .be_id = 1, | ||
172 | .cpu_dai_name = "ssp2-port", | ||
173 | .platform_name = "sst-mfld-platform", | ||
174 | .no_pcm = 1, | ||
175 | .codec_dai_name = "rt5640-aif1", | ||
176 | .codec_name = "i2c-10EC5640:00", | ||
177 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | ||
178 | | SND_SOC_DAIFMT_CBS_CFS, | ||
179 | .be_hw_params_fixup = byt_codec_fixup, | ||
180 | .ignore_suspend = 1, | ||
181 | .dpcm_playback = 1, | ||
182 | .dpcm_capture = 1, | ||
183 | .ops = &byt_be_ssp2_ops, | ||
184 | }, | ||
185 | }; | ||
186 | |||
187 | /* SoC card */ | ||
188 | static struct snd_soc_card snd_soc_card_byt = { | ||
189 | .name = "baytrailcraudio", | ||
190 | .dai_link = byt_dailink, | ||
191 | .num_links = ARRAY_SIZE(byt_dailink), | ||
192 | .dapm_widgets = byt_dapm_widgets, | ||
193 | .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets), | ||
194 | .dapm_routes = byt_audio_map, | ||
195 | .num_dapm_routes = ARRAY_SIZE(byt_audio_map), | ||
196 | .controls = byt_mc_controls, | ||
197 | .num_controls = ARRAY_SIZE(byt_mc_controls), | ||
198 | }; | ||
199 | |||
200 | static int snd_byt_mc_probe(struct platform_device *pdev) | ||
201 | { | ||
202 | int ret_val = 0; | ||
203 | |||
204 | /* register the soc card */ | ||
205 | snd_soc_card_byt.dev = &pdev->dev; | ||
206 | |||
207 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt); | ||
208 | if (ret_val) { | ||
209 | dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val); | ||
210 | return ret_val; | ||
211 | } | ||
212 | platform_set_drvdata(pdev, &snd_soc_card_byt); | ||
213 | return ret_val; | ||
214 | } | ||
215 | |||
216 | static struct platform_driver snd_byt_mc_driver = { | ||
217 | .driver = { | ||
218 | .owner = THIS_MODULE, | ||
219 | .name = "bytt100_rt5640", | ||
220 | .pm = &snd_soc_pm_ops, | ||
221 | }, | ||
222 | .probe = snd_byt_mc_probe, | ||
223 | }; | ||
224 | |||
225 | module_platform_driver(snd_byt_mc_driver); | ||
226 | |||
227 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); | ||
228 | MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>"); | ||
229 | MODULE_LICENSE("GPL v2"); | ||
230 | MODULE_ALIAS("platform:bytrt5640-audio"); | ||
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c new file mode 100644 index 000000000000..9b8b561171b7 --- /dev/null +++ b/sound/soc/intel/cht_bsw_rt5672.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /* | ||
2 | * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms | ||
3 | * Cherrytrail and Braswell, with RT5672 codec. | ||
4 | * | ||
5 | * Copyright (C) 2014 Intel Corp | ||
6 | * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com> | ||
7 | * Mengdong Lin <mengdong.lin@intel.com> | ||
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 as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include "../codecs/rt5670.h" | ||
26 | #include "sst-atom-controls.h" | ||
27 | |||
28 | /* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */ | ||
29 | #define CHT_PLAT_CLK_3_HZ 19200000 | ||
30 | #define CHT_CODEC_DAI "rt5670-aif1" | ||
31 | |||
32 | static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card) | ||
33 | { | ||
34 | int i; | ||
35 | |||
36 | for (i = 0; i < card->num_rtd; i++) { | ||
37 | struct snd_soc_pcm_runtime *rtd; | ||
38 | |||
39 | rtd = card->rtd + i; | ||
40 | if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI, | ||
41 | strlen(CHT_CODEC_DAI))) | ||
42 | return rtd->codec_dai; | ||
43 | } | ||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static int platform_clock_control(struct snd_soc_dapm_widget *w, | ||
48 | struct snd_kcontrol *k, int event) | ||
49 | { | ||
50 | struct snd_soc_dapm_context *dapm = w->dapm; | ||
51 | struct snd_soc_card *card = dapm->card; | ||
52 | struct snd_soc_dai *codec_dai; | ||
53 | |||
54 | codec_dai = cht_get_codec_dai(card); | ||
55 | if (!codec_dai) { | ||
56 | dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n"); | ||
57 | return -EIO; | ||
58 | } | ||
59 | |||
60 | if (!SND_SOC_DAPM_EVENT_OFF(event)) | ||
61 | return 0; | ||
62 | |||
63 | /* Set codec sysclk source to its internal clock because codec PLL will | ||
64 | * be off when idle and MCLK will also be off by ACPI when codec is | ||
65 | * runtime suspended. Codec needs clock for jack detection and button | ||
66 | * press. | ||
67 | */ | ||
68 | snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK, | ||
69 | 0, SND_SOC_CLOCK_IN); | ||
70 | |||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static const struct snd_soc_dapm_widget cht_dapm_widgets[] = { | ||
75 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
76 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
77 | SND_SOC_DAPM_MIC("Int Mic", NULL), | ||
78 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
79 | SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0, | ||
80 | platform_clock_control, SND_SOC_DAPM_POST_PMD), | ||
81 | }; | ||
82 | |||
83 | static const struct snd_soc_dapm_route cht_audio_map[] = { | ||
84 | {"IN1P", NULL, "Headset Mic"}, | ||
85 | {"IN1N", NULL, "Headset Mic"}, | ||
86 | {"DMIC L1", NULL, "Int Mic"}, | ||
87 | {"DMIC R1", NULL, "Int Mic"}, | ||
88 | {"Headphone", NULL, "HPOL"}, | ||
89 | {"Headphone", NULL, "HPOR"}, | ||
90 | {"Ext Spk", NULL, "SPOLP"}, | ||
91 | {"Ext Spk", NULL, "SPOLN"}, | ||
92 | {"Ext Spk", NULL, "SPORP"}, | ||
93 | {"Ext Spk", NULL, "SPORN"}, | ||
94 | {"AIF1 Playback", NULL, "ssp2 Tx"}, | ||
95 | {"ssp2 Tx", NULL, "codec_out0"}, | ||
96 | {"ssp2 Tx", NULL, "codec_out1"}, | ||
97 | {"codec_in0", NULL, "ssp2 Rx"}, | ||
98 | {"codec_in1", NULL, "ssp2 Rx"}, | ||
99 | {"ssp2 Rx", NULL, "AIF1 Capture"}, | ||
100 | {"Headphone", NULL, "Platform Clock"}, | ||
101 | {"Headset Mic", NULL, "Platform Clock"}, | ||
102 | {"Int Mic", NULL, "Platform Clock"}, | ||
103 | {"Ext Spk", NULL, "Platform Clock"}, | ||
104 | }; | ||
105 | |||
106 | static const struct snd_kcontrol_new cht_mc_controls[] = { | ||
107 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
108 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
109 | SOC_DAPM_PIN_SWITCH("Int Mic"), | ||
110 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
111 | }; | ||
112 | |||
113 | static int cht_aif1_hw_params(struct snd_pcm_substream *substream, | ||
114 | struct snd_pcm_hw_params *params) | ||
115 | { | ||
116 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
117 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
118 | int ret; | ||
119 | |||
120 | /* set codec PLL source to the 19.2MHz platform clock (MCLK) */ | ||
121 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK, | ||
122 | CHT_PLAT_CLK_3_HZ, params_rate(params) * 512); | ||
123 | if (ret < 0) { | ||
124 | dev_err(rtd->dev, "can't set codec pll: %d\n", ret); | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | /* set codec sysclk source to PLL */ | ||
129 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1, | ||
130 | params_rate(params) * 512, | ||
131 | SND_SOC_CLOCK_IN); | ||
132 | if (ret < 0) { | ||
133 | dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret); | ||
134 | return ret; | ||
135 | } | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int cht_codec_init(struct snd_soc_pcm_runtime *runtime) | ||
140 | { | ||
141 | int ret; | ||
142 | struct snd_soc_dai *codec_dai = runtime->codec_dai; | ||
143 | |||
144 | /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */ | ||
145 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24); | ||
146 | if (ret < 0) { | ||
147 | dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret); | ||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | return 0; | ||
152 | } | ||
153 | |||
154 | static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd, | ||
155 | struct snd_pcm_hw_params *params) | ||
156 | { | ||
157 | struct snd_interval *rate = hw_param_interval(params, | ||
158 | SNDRV_PCM_HW_PARAM_RATE); | ||
159 | struct snd_interval *channels = hw_param_interval(params, | ||
160 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
161 | |||
162 | /* The DSP will covert the FE rate to 48k, stereo, 24bits */ | ||
163 | rate->min = rate->max = 48000; | ||
164 | channels->min = channels->max = 2; | ||
165 | |||
166 | /* set SSP2 to 24-bit */ | ||
167 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
168 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
169 | SNDRV_PCM_FORMAT_S24_LE); | ||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static unsigned int rates_48000[] = { | ||
174 | 48000, | ||
175 | }; | ||
176 | |||
177 | static struct snd_pcm_hw_constraint_list constraints_48000 = { | ||
178 | .count = ARRAY_SIZE(rates_48000), | ||
179 | .list = rates_48000, | ||
180 | }; | ||
181 | |||
182 | static int cht_aif1_startup(struct snd_pcm_substream *substream) | ||
183 | { | ||
184 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
185 | SNDRV_PCM_HW_PARAM_RATE, | ||
186 | &constraints_48000); | ||
187 | } | ||
188 | |||
189 | static struct snd_soc_ops cht_aif1_ops = { | ||
190 | .startup = cht_aif1_startup, | ||
191 | }; | ||
192 | |||
193 | static struct snd_soc_ops cht_be_ssp2_ops = { | ||
194 | .hw_params = cht_aif1_hw_params, | ||
195 | }; | ||
196 | |||
197 | static struct snd_soc_dai_link cht_dailink[] = { | ||
198 | /* Front End DAI links */ | ||
199 | [MERR_DPCM_AUDIO] = { | ||
200 | .name = "Audio Port", | ||
201 | .stream_name = "Audio", | ||
202 | .cpu_dai_name = "media-cpu-dai", | ||
203 | .codec_dai_name = "snd-soc-dummy-dai", | ||
204 | .codec_name = "snd-soc-dummy", | ||
205 | .platform_name = "sst-mfld-platform", | ||
206 | .ignore_suspend = 1, | ||
207 | .dynamic = 1, | ||
208 | .dpcm_playback = 1, | ||
209 | .dpcm_capture = 1, | ||
210 | .ops = &cht_aif1_ops, | ||
211 | }, | ||
212 | [MERR_DPCM_COMPR] = { | ||
213 | .name = "Compressed Port", | ||
214 | .stream_name = "Compress", | ||
215 | .cpu_dai_name = "compress-cpu-dai", | ||
216 | .codec_dai_name = "snd-soc-dummy-dai", | ||
217 | .codec_name = "snd-soc-dummy", | ||
218 | .platform_name = "sst-mfld-platform", | ||
219 | }, | ||
220 | |||
221 | /* Back End DAI links */ | ||
222 | { | ||
223 | /* SSP2 - Codec */ | ||
224 | .name = "SSP2-Codec", | ||
225 | .be_id = 1, | ||
226 | .cpu_dai_name = "ssp2-port", | ||
227 | .platform_name = "sst-mfld-platform", | ||
228 | .no_pcm = 1, | ||
229 | .codec_dai_name = "rt5670-aif1", | ||
230 | .codec_name = "i2c-10EC5670:00", | ||
231 | .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | ||
232 | | SND_SOC_DAIFMT_CBS_CFS, | ||
233 | .init = cht_codec_init, | ||
234 | .be_hw_params_fixup = cht_codec_fixup, | ||
235 | .ignore_suspend = 1, | ||
236 | .dpcm_playback = 1, | ||
237 | .dpcm_capture = 1, | ||
238 | .ops = &cht_be_ssp2_ops, | ||
239 | }, | ||
240 | }; | ||
241 | |||
242 | /* SoC card */ | ||
243 | static struct snd_soc_card snd_soc_card_cht = { | ||
244 | .name = "cherrytrailcraudio", | ||
245 | .dai_link = cht_dailink, | ||
246 | .num_links = ARRAY_SIZE(cht_dailink), | ||
247 | .dapm_widgets = cht_dapm_widgets, | ||
248 | .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets), | ||
249 | .dapm_routes = cht_audio_map, | ||
250 | .num_dapm_routes = ARRAY_SIZE(cht_audio_map), | ||
251 | .controls = cht_mc_controls, | ||
252 | .num_controls = ARRAY_SIZE(cht_mc_controls), | ||
253 | }; | ||
254 | |||
255 | static int snd_cht_mc_probe(struct platform_device *pdev) | ||
256 | { | ||
257 | int ret_val = 0; | ||
258 | |||
259 | /* register the soc card */ | ||
260 | snd_soc_card_cht.dev = &pdev->dev; | ||
261 | ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht); | ||
262 | if (ret_val) { | ||
263 | dev_err(&pdev->dev, | ||
264 | "snd_soc_register_card failed %d\n", ret_val); | ||
265 | return ret_val; | ||
266 | } | ||
267 | platform_set_drvdata(pdev, &snd_soc_card_cht); | ||
268 | return ret_val; | ||
269 | } | ||
270 | |||
271 | static struct platform_driver snd_cht_mc_driver = { | ||
272 | .driver = { | ||
273 | .owner = THIS_MODULE, | ||
274 | .name = "cht-bsw-rt5672", | ||
275 | .pm = &snd_soc_pm_ops, | ||
276 | }, | ||
277 | .probe = snd_cht_mc_probe, | ||
278 | }; | ||
279 | |||
280 | module_platform_driver(snd_cht_mc_driver); | ||
281 | |||
282 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver"); | ||
283 | MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin"); | ||
284 | MODULE_LICENSE("GPL v2"); | ||
285 | MODULE_ALIAS("platform:cht-bsw-rt5672"); | ||
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c index 3981982674ac..cb8a482b5f30 100644 --- a/sound/soc/intel/haswell.c +++ b/sound/soc/intel/haswell.c | |||
@@ -109,7 +109,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
109 | /* Front End DAI links */ | 109 | /* Front End DAI links */ |
110 | { | 110 | { |
111 | .name = "System", | 111 | .name = "System", |
112 | .stream_name = "System Playback", | 112 | .stream_name = "System Playback/Capture", |
113 | .cpu_dai_name = "System Pin", | 113 | .cpu_dai_name = "System Pin", |
114 | .platform_name = "haswell-pcm-audio", | 114 | .platform_name = "haswell-pcm-audio", |
115 | .dynamic = 1, | 115 | .dynamic = 1, |
@@ -118,6 +118,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
118 | .init = haswell_rtd_init, | 118 | .init = haswell_rtd_init, |
119 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 119 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
120 | .dpcm_playback = 1, | 120 | .dpcm_playback = 1, |
121 | .dpcm_capture = 1, | ||
121 | }, | 122 | }, |
122 | { | 123 | { |
123 | .name = "Offload0", | 124 | .name = "Offload0", |
@@ -152,17 +153,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = { | |||
152 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 153 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
153 | .dpcm_capture = 1, | 154 | .dpcm_capture = 1, |
154 | }, | 155 | }, |
155 | { | ||
156 | .name = "Capture", | ||
157 | .stream_name = "Capture", | ||
158 | .cpu_dai_name = "Capture Pin", | ||
159 | .platform_name = "haswell-pcm-audio", | ||
160 | .dynamic = 1, | ||
161 | .codec_name = "snd-soc-dummy", | ||
162 | .codec_dai_name = "snd-soc-dummy-dai", | ||
163 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
164 | .dpcm_capture = 1, | ||
165 | }, | ||
166 | 156 | ||
167 | /* Back End DAI links */ | 157 | /* Back End DAI links */ |
168 | { | 158 | { |
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c index 7104a34181a9..90aa5c0476f3 100644 --- a/sound/soc/intel/sst-atom-controls.c +++ b/sound/soc/intel/sst-atom-controls.c | |||
@@ -15,6 +15,9 @@ | |||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * General Public License for more details. | 16 | * General Public License for more details. |
17 | * | 17 | * |
18 | * In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active | ||
19 | * we forward the settings and parameters, rest we keep the values in | ||
20 | * driver and forward when DAPM enables them | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 21 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
19 | */ | 22 | */ |
20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 23 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
@@ -81,6 +84,183 @@ static int sst_fill_and_send_cmd(struct sst_data *drv, | |||
81 | return ret; | 84 | return ret; |
82 | } | 85 | } |
83 | 86 | ||
87 | /** | ||
88 | * tx map value is a bitfield where each bit represents a FW channel | ||
89 | * | ||
90 | * 3 2 1 0 # 0 = codec0, 1 = codec1 | ||
91 | * RLRLRLRL # 3, 4 = reserved | ||
92 | * | ||
93 | * e.g. slot 0 rx map = 00001100b -> data from slot 0 goes into codec_in1 L,R | ||
94 | */ | ||
95 | static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = { | ||
96 | 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */ | ||
97 | }; | ||
98 | |||
99 | /** | ||
100 | * rx map value is a bitfield where each bit represents a slot | ||
101 | * | ||
102 | * 76543210 # 0 = slot 0, 1 = slot 1 | ||
103 | * | ||
104 | * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2 | ||
105 | */ | ||
106 | static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = { | ||
107 | 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */ | ||
108 | }; | ||
109 | |||
110 | /** | ||
111 | * NOTE: this is invoked with lock held | ||
112 | */ | ||
113 | static int sst_send_slot_map(struct sst_data *drv) | ||
114 | { | ||
115 | struct sst_param_sba_ssp_slot_map cmd; | ||
116 | |||
117 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
118 | cmd.header.command_id = SBA_SET_SSP_SLOT_MAP; | ||
119 | cmd.header.length = sizeof(struct sst_param_sba_ssp_slot_map) | ||
120 | - sizeof(struct sst_dsp_header); | ||
121 | |||
122 | cmd.param_id = SBA_SET_SSP_SLOT_MAP; | ||
123 | cmd.param_len = sizeof(cmd.rx_slot_map) + sizeof(cmd.tx_slot_map) | ||
124 | + sizeof(cmd.ssp_index); | ||
125 | cmd.ssp_index = SSP_CODEC; | ||
126 | |||
127 | memcpy(cmd.rx_slot_map, &sst_ssp_tx_map[0], sizeof(cmd.rx_slot_map)); | ||
128 | memcpy(cmd.tx_slot_map, &sst_ssp_rx_map[0], sizeof(cmd.tx_slot_map)); | ||
129 | |||
130 | return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, | ||
131 | SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, | ||
132 | sizeof(cmd.header) + cmd.header.length); | ||
133 | } | ||
134 | |||
135 | int sst_slot_enum_info(struct snd_kcontrol *kcontrol, | ||
136 | struct snd_ctl_elem_info *uinfo) | ||
137 | { | ||
138 | struct sst_enum *e = (struct sst_enum *)kcontrol->private_value; | ||
139 | |||
140 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
141 | uinfo->count = 1; | ||
142 | uinfo->value.enumerated.items = e->max; | ||
143 | |||
144 | if (uinfo->value.enumerated.item > e->max - 1) | ||
145 | uinfo->value.enumerated.item = e->max - 1; | ||
146 | strcpy(uinfo->value.enumerated.name, | ||
147 | e->texts[uinfo->value.enumerated.item]); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | /** | ||
153 | * sst_slot_get - get the status of the interleaver/deinterleaver control | ||
154 | * | ||
155 | * Searches the map where the control status is stored, and gets the | ||
156 | * channel/slot which is currently set for this enumerated control. Since it is | ||
157 | * an enumerated control, there is only one possible value. | ||
158 | */ | ||
159 | static int sst_slot_get(struct snd_kcontrol *kcontrol, | ||
160 | struct snd_ctl_elem_value *ucontrol) | ||
161 | { | ||
162 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
163 | struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); | ||
164 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
165 | unsigned int ctl_no = e->reg; | ||
166 | unsigned int is_tx = e->tx; | ||
167 | unsigned int val, mux; | ||
168 | u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; | ||
169 | |||
170 | mutex_lock(&drv->lock); | ||
171 | val = 1 << ctl_no; | ||
172 | /* search which slot/channel has this bit set - there should be only one */ | ||
173 | for (mux = e->max; mux > 0; mux--) | ||
174 | if (map[mux - 1] & val) | ||
175 | break; | ||
176 | |||
177 | ucontrol->value.enumerated.item[0] = mux; | ||
178 | mutex_unlock(&drv->lock); | ||
179 | |||
180 | dev_dbg(c->dev, "%s - %s map = %#x\n", | ||
181 | is_tx ? "tx channel" : "rx slot", | ||
182 | e->texts[mux], mux ? map[mux - 1] : -1); | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | /* sst_check_and_send_slot_map - helper for checking power state and sending | ||
187 | * slot map cmd | ||
188 | * | ||
189 | * called with lock held | ||
190 | */ | ||
191 | static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol *kcontrol) | ||
192 | { | ||
193 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
194 | int ret = 0; | ||
195 | |||
196 | if (e->w && e->w->power) | ||
197 | ret = sst_send_slot_map(drv); | ||
198 | else | ||
199 | dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n", | ||
200 | kcontrol->id.name); | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /** | ||
205 | * sst_slot_put - set the status of interleaver/deinterleaver control | ||
206 | * | ||
207 | * (de)interleaver controls are defined in opposite sense to be user-friendly | ||
208 | * | ||
209 | * Instead of the enum value being the value written to the register, it is the | ||
210 | * register address; and the kcontrol number (register num) is the value written | ||
211 | * to the register. This is so that there can be only one value for each | ||
212 | * slot/channel since there is only one control for each slot/channel. | ||
213 | * | ||
214 | * This means that whenever an enum is set, we need to clear the bit | ||
215 | * for that kcontrol_no for all the interleaver OR deinterleaver registers | ||
216 | */ | ||
217 | static int sst_slot_put(struct snd_kcontrol *kcontrol, | ||
218 | struct snd_ctl_elem_value *ucontrol) | ||
219 | { | ||
220 | struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); | ||
221 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
222 | struct sst_enum *e = (void *)kcontrol->private_value; | ||
223 | int i, ret = 0; | ||
224 | unsigned int ctl_no = e->reg; | ||
225 | unsigned int is_tx = e->tx; | ||
226 | unsigned int slot_channel_no; | ||
227 | unsigned int val, mux; | ||
228 | u8 *map; | ||
229 | |||
230 | map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map; | ||
231 | |||
232 | val = 1 << ctl_no; | ||
233 | mux = ucontrol->value.enumerated.item[0]; | ||
234 | if (mux > e->max - 1) | ||
235 | return -EINVAL; | ||
236 | |||
237 | mutex_lock(&drv->lock); | ||
238 | /* first clear all registers of this bit */ | ||
239 | for (i = 0; i < e->max; i++) | ||
240 | map[i] &= ~val; | ||
241 | |||
242 | if (mux == 0) { | ||
243 | /* kctl set to 'none' and we reset the bits so send IPC */ | ||
244 | ret = sst_check_and_send_slot_map(drv, kcontrol); | ||
245 | |||
246 | mutex_unlock(&drv->lock); | ||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | /* offset by one to take "None" into account */ | ||
251 | slot_channel_no = mux - 1; | ||
252 | map[slot_channel_no] |= val; | ||
253 | |||
254 | dev_dbg(c->dev, "%s %s map = %#x\n", | ||
255 | is_tx ? "tx channel" : "rx slot", | ||
256 | e->texts[mux], map[slot_channel_no]); | ||
257 | |||
258 | ret = sst_check_and_send_slot_map(drv, kcontrol); | ||
259 | |||
260 | mutex_unlock(&drv->lock); | ||
261 | return ret; | ||
262 | } | ||
263 | |||
84 | static int sst_send_algo_cmd(struct sst_data *drv, | 264 | static int sst_send_algo_cmd(struct sst_data *drv, |
85 | struct sst_algo_control *bc) | 265 | struct sst_algo_control *bc) |
86 | { | 266 | { |
@@ -104,6 +284,34 @@ static int sst_send_algo_cmd(struct sst_data *drv, | |||
104 | return ret; | 284 | return ret; |
105 | } | 285 | } |
106 | 286 | ||
287 | /** | ||
288 | * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe | ||
289 | * | ||
290 | * The algos which are in each pipeline are sent to the firmware one by one | ||
291 | * | ||
292 | * Called with lock held | ||
293 | */ | ||
294 | static int sst_find_and_send_pipe_algo(struct sst_data *drv, | ||
295 | const char *pipe, struct sst_ids *ids) | ||
296 | { | ||
297 | int ret = 0; | ||
298 | struct sst_algo_control *bc; | ||
299 | struct sst_module *algo = NULL; | ||
300 | |||
301 | dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe); | ||
302 | |||
303 | list_for_each_entry(algo, &ids->algo_list, node) { | ||
304 | bc = (void *)algo->kctl->private_value; | ||
305 | |||
306 | dev_dbg(&drv->pdev->dev, "Found algo control name=%s pipe=%s\n", | ||
307 | algo->kctl->id.name, pipe); | ||
308 | ret = sst_send_algo_cmd(drv, bc); | ||
309 | if (ret) | ||
310 | return ret; | ||
311 | } | ||
312 | return ret; | ||
313 | } | ||
314 | |||
107 | static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, | 315 | static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, |
108 | struct snd_ctl_elem_info *uinfo) | 316 | struct snd_ctl_elem_info *uinfo) |
109 | { | 317 | { |
@@ -162,6 +370,743 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol, | |||
162 | return ret; | 370 | return ret; |
163 | } | 371 | } |
164 | 372 | ||
373 | static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol, | ||
374 | struct snd_ctl_elem_info *uinfo) | ||
375 | { | ||
376 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
377 | |||
378 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
379 | uinfo->count = mc->stereo ? 2 : 1; | ||
380 | uinfo->value.integer.min = mc->min; | ||
381 | uinfo->value.integer.max = mc->max; | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * sst_send_gain_cmd - send the gain algorithm IPC to the FW | ||
388 | * @gv: the stored value of gain (also contains rampduration) | ||
389 | * @mute: flag that indicates whether this was called from the | ||
390 | * digital_mute callback or directly. If called from the | ||
391 | * digital_mute callback, module will be muted/unmuted based on this | ||
392 | * flag. The flag is always 0 if called directly. | ||
393 | * | ||
394 | * Called with sst_data.lock held | ||
395 | * | ||
396 | * The user-set gain value is sent only if the user-controllable 'mute' control | ||
397 | * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is | ||
398 | * sent. | ||
399 | */ | ||
400 | static int sst_send_gain_cmd(struct sst_data *drv, struct sst_gain_value *gv, | ||
401 | u16 task_id, u16 loc_id, u16 module_id, int mute) | ||
402 | { | ||
403 | struct sst_cmd_set_gain_dual cmd; | ||
404 | |||
405 | dev_dbg(&drv->pdev->dev, "Enter\n"); | ||
406 | |||
407 | cmd.header.command_id = MMX_SET_GAIN; | ||
408 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
409 | cmd.gain_cell_num = 1; | ||
410 | |||
411 | if (mute || gv->mute) { | ||
412 | cmd.cell_gains[0].cell_gain_left = SST_GAIN_MIN_VALUE; | ||
413 | cmd.cell_gains[0].cell_gain_right = SST_GAIN_MIN_VALUE; | ||
414 | } else { | ||
415 | cmd.cell_gains[0].cell_gain_left = gv->l_gain; | ||
416 | cmd.cell_gains[0].cell_gain_right = gv->r_gain; | ||
417 | } | ||
418 | |||
419 | SST_FILL_DESTINATION(2, cmd.cell_gains[0].dest, | ||
420 | loc_id, module_id); | ||
421 | cmd.cell_gains[0].gain_time_constant = gv->ramp_duration; | ||
422 | |||
423 | cmd.header.length = sizeof(struct sst_cmd_set_gain_dual) | ||
424 | - sizeof(struct sst_dsp_header); | ||
425 | |||
426 | /* we are with lock held, so call the unlocked api to send */ | ||
427 | return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, | ||
428 | SST_FLAG_BLOCKED, task_id, 0, &cmd, | ||
429 | sizeof(cmd.header) + cmd.header.length); | ||
430 | } | ||
431 | |||
432 | static int sst_gain_get(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_value *ucontrol) | ||
434 | { | ||
435 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
436 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
437 | struct sst_gain_value *gv = mc->gain_val; | ||
438 | |||
439 | switch (mc->type) { | ||
440 | case SST_GAIN_TLV: | ||
441 | ucontrol->value.integer.value[0] = gv->l_gain; | ||
442 | ucontrol->value.integer.value[1] = gv->r_gain; | ||
443 | break; | ||
444 | |||
445 | case SST_GAIN_MUTE: | ||
446 | ucontrol->value.integer.value[0] = gv->mute ? 1 : 0; | ||
447 | break; | ||
448 | |||
449 | case SST_GAIN_RAMP_DURATION: | ||
450 | ucontrol->value.integer.value[0] = gv->ramp_duration; | ||
451 | break; | ||
452 | |||
453 | default: | ||
454 | dev_err(component->dev, "Invalid Input- gain type:%d\n", | ||
455 | mc->type); | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int sst_gain_put(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | int ret = 0; | ||
466 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | ||
467 | struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); | ||
468 | struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value; | ||
469 | struct sst_gain_value *gv = mc->gain_val; | ||
470 | |||
471 | mutex_lock(&drv->lock); | ||
472 | |||
473 | switch (mc->type) { | ||
474 | case SST_GAIN_TLV: | ||
475 | gv->l_gain = ucontrol->value.integer.value[0]; | ||
476 | gv->r_gain = ucontrol->value.integer.value[1]; | ||
477 | dev_dbg(cmpnt->dev, "%s: Volume %d, %d\n", | ||
478 | mc->pname, gv->l_gain, gv->r_gain); | ||
479 | break; | ||
480 | |||
481 | case SST_GAIN_MUTE: | ||
482 | gv->mute = !!ucontrol->value.integer.value[0]; | ||
483 | dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute); | ||
484 | break; | ||
485 | |||
486 | case SST_GAIN_RAMP_DURATION: | ||
487 | gv->ramp_duration = ucontrol->value.integer.value[0]; | ||
488 | dev_dbg(cmpnt->dev, "%s: Ramp Delay%d\n", | ||
489 | mc->pname, gv->ramp_duration); | ||
490 | break; | ||
491 | |||
492 | default: | ||
493 | mutex_unlock(&drv->lock); | ||
494 | dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n", | ||
495 | mc->type); | ||
496 | return -EINVAL; | ||
497 | } | ||
498 | |||
499 | if (mc->w && mc->w->power) | ||
500 | ret = sst_send_gain_cmd(drv, gv, mc->task_id, | ||
501 | mc->pipe_id | mc->instance_id, mc->module_id, 0); | ||
502 | mutex_unlock(&drv->lock); | ||
503 | |||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | static int sst_set_pipe_gain(struct sst_ids *ids, | ||
508 | struct sst_data *drv, int mute); | ||
509 | |||
510 | static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w, | ||
511 | struct snd_kcontrol *kcontrol) | ||
512 | { | ||
513 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
514 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
515 | struct sst_ids *ids = w->priv; | ||
516 | |||
517 | mutex_lock(&drv->lock); | ||
518 | sst_find_and_send_pipe_algo(drv, w->name, ids); | ||
519 | sst_set_pipe_gain(ids, drv, 0); | ||
520 | mutex_unlock(&drv->lock); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int sst_generic_modules_event(struct snd_soc_dapm_widget *w, | ||
526 | struct snd_kcontrol *k, int event) | ||
527 | { | ||
528 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
529 | return sst_send_pipe_module_params(w, k); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, 10, 0); | ||
534 | |||
535 | /* Look up table to convert MIXER SW bit regs to SWM inputs */ | ||
536 | static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = { | ||
537 | [SST_IP_CODEC0] = SST_SWM_IN_CODEC0, | ||
538 | [SST_IP_CODEC1] = SST_SWM_IN_CODEC1, | ||
539 | [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP, | ||
540 | [SST_IP_LOOP1] = SST_SWM_IN_MEDIA_LOOP1, | ||
541 | [SST_IP_LOOP2] = SST_SWM_IN_MEDIA_LOOP2, | ||
542 | [SST_IP_PCM0] = SST_SWM_IN_PCM0, | ||
543 | [SST_IP_PCM1] = SST_SWM_IN_PCM1, | ||
544 | [SST_IP_MEDIA0] = SST_SWM_IN_MEDIA0, | ||
545 | [SST_IP_MEDIA1] = SST_SWM_IN_MEDIA1, | ||
546 | [SST_IP_MEDIA2] = SST_SWM_IN_MEDIA2, | ||
547 | [SST_IP_MEDIA3] = SST_SWM_IN_MEDIA3, | ||
548 | }; | ||
549 | |||
550 | /** | ||
551 | * fill_swm_input - fill in the SWM input ids given the register | ||
552 | * | ||
553 | * The register value is a bit-field inicated which mixer inputs are ON. Use the | ||
554 | * lookup table to get the input-id and fill it in the structure. | ||
555 | */ | ||
556 | static int fill_swm_input(struct snd_soc_component *cmpnt, | ||
557 | struct swm_input_ids *swm_input, unsigned int reg) | ||
558 | { | ||
559 | uint i, is_set, nb_inputs = 0; | ||
560 | u16 input_loc_id; | ||
561 | |||
562 | dev_dbg(cmpnt->dev, "reg: %#x\n", reg); | ||
563 | for (i = 0; i < SST_SWM_INPUT_COUNT; i++) { | ||
564 | is_set = reg & BIT(i); | ||
565 | if (!is_set) | ||
566 | continue; | ||
567 | |||
568 | input_loc_id = swm_mixer_input_ids[i]; | ||
569 | SST_FILL_DESTINATION(2, swm_input->input_id, | ||
570 | input_loc_id, SST_DEFAULT_MODULE_ID); | ||
571 | nb_inputs++; | ||
572 | swm_input++; | ||
573 | dev_dbg(cmpnt->dev, "input id: %#x, nb_inputs: %d\n", | ||
574 | input_loc_id, nb_inputs); | ||
575 | |||
576 | if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) { | ||
577 | dev_warn(cmpnt->dev, "SET_SWM cmd max inputs reached"); | ||
578 | break; | ||
579 | } | ||
580 | } | ||
581 | return nb_inputs; | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * called with lock held | ||
587 | */ | ||
588 | static int sst_set_pipe_gain(struct sst_ids *ids, | ||
589 | struct sst_data *drv, int mute) | ||
590 | { | ||
591 | int ret = 0; | ||
592 | struct sst_gain_mixer_control *mc; | ||
593 | struct sst_gain_value *gv; | ||
594 | struct sst_module *gain = NULL; | ||
595 | |||
596 | list_for_each_entry(gain, &ids->gain_list, node) { | ||
597 | struct snd_kcontrol *kctl = gain->kctl; | ||
598 | |||
599 | dev_dbg(&drv->pdev->dev, "control name=%s\n", kctl->id.name); | ||
600 | mc = (void *)kctl->private_value; | ||
601 | gv = mc->gain_val; | ||
602 | |||
603 | ret = sst_send_gain_cmd(drv, gv, mc->task_id, | ||
604 | mc->pipe_id | mc->instance_id, mc->module_id, mute); | ||
605 | if (ret) | ||
606 | return ret; | ||
607 | } | ||
608 | return ret; | ||
609 | } | ||
610 | |||
611 | static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w, | ||
612 | struct snd_kcontrol *k, int event) | ||
613 | { | ||
614 | struct sst_cmd_set_swm cmd; | ||
615 | struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); | ||
616 | struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); | ||
617 | struct sst_ids *ids = w->priv; | ||
618 | bool set_mixer = false; | ||
619 | struct soc_mixer_control *mc; | ||
620 | int val = 0; | ||
621 | int i = 0; | ||
622 | |||
623 | dev_dbg(cmpnt->dev, "widget = %s\n", w->name); | ||
624 | /* | ||
625 | * Identify which mixer input is on and send the bitmap of the | ||
626 | * inputs as an IPC to the DSP. | ||
627 | */ | ||
628 | for (i = 0; i < w->num_kcontrols; i++) { | ||
629 | if (dapm_kcontrol_get_value(w->kcontrols[i])) { | ||
630 | mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value; | ||
631 | val |= 1 << mc->shift; | ||
632 | } | ||
633 | } | ||
634 | dev_dbg(cmpnt->dev, "val = %#x\n", val); | ||
635 | |||
636 | switch (event) { | ||
637 | case SND_SOC_DAPM_PRE_PMU: | ||
638 | case SND_SOC_DAPM_POST_PMD: | ||
639 | set_mixer = true; | ||
640 | break; | ||
641 | case SND_SOC_DAPM_POST_REG: | ||
642 | if (w->power) | ||
643 | set_mixer = true; | ||
644 | break; | ||
645 | default: | ||
646 | set_mixer = false; | ||
647 | } | ||
648 | |||
649 | if (set_mixer == false) | ||
650 | return 0; | ||
651 | |||
652 | if (SND_SOC_DAPM_EVENT_ON(event) || | ||
653 | event == SND_SOC_DAPM_POST_REG) | ||
654 | cmd.switch_state = SST_SWM_ON; | ||
655 | else | ||
656 | cmd.switch_state = SST_SWM_OFF; | ||
657 | |||
658 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
659 | /* MMX_SET_SWM == SBA_SET_SWM */ | ||
660 | cmd.header.command_id = SBA_SET_SWM; | ||
661 | |||
662 | SST_FILL_DESTINATION(2, cmd.output_id, | ||
663 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
664 | cmd.nb_inputs = fill_swm_input(cmpnt, &cmd.input[0], val); | ||
665 | cmd.header.length = offsetof(struct sst_cmd_set_swm, input) | ||
666 | - sizeof(struct sst_dsp_header) | ||
667 | + (cmd.nb_inputs * sizeof(cmd.input[0])); | ||
668 | |||
669 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
670 | ids->task_id, 0, &cmd, | ||
671 | sizeof(cmd.header) + cmd.header.length); | ||
672 | } | ||
673 | |||
674 | /* SBA mixers - 16 inputs */ | ||
675 | #define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \ | ||
676 | static const struct snd_kcontrol_new kctl_name[] = { \ | ||
677 | SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \ | ||
678 | SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \ | ||
679 | SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \ | ||
680 | SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0), \ | ||
681 | SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0), \ | ||
682 | SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0), \ | ||
683 | SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0), \ | ||
684 | } | ||
685 | |||
686 | #define SST_SBA_MIXER_GRAPH_MAP(mix_name) \ | ||
687 | { mix_name, "codec_in0 Switch", "codec_in0" }, \ | ||
688 | { mix_name, "codec_in1 Switch", "codec_in1" }, \ | ||
689 | { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \ | ||
690 | { mix_name, "media_loop1_in Switch", "media_loop1_in" }, \ | ||
691 | { mix_name, "media_loop2_in Switch", "media_loop2_in" }, \ | ||
692 | { mix_name, "pcm0_in Switch", "pcm0_in" }, \ | ||
693 | { mix_name, "pcm1_in Switch", "pcm1_in" } | ||
694 | |||
695 | #define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name) \ | ||
696 | static const struct snd_kcontrol_new kctl_name[] = { \ | ||
697 | SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \ | ||
698 | SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \ | ||
699 | SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \ | ||
700 | SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \ | ||
701 | } | ||
702 | |||
703 | SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls); | ||
704 | SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls); | ||
705 | |||
706 | /* 18 SBA mixers */ | ||
707 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls); | ||
708 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls); | ||
709 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls); | ||
710 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls); | ||
711 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls); | ||
712 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls); | ||
713 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls); | ||
714 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls); | ||
715 | SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls); | ||
716 | |||
717 | /* | ||
718 | * sst_handle_vb_timer - Start/Stop the DSP scheduler | ||
719 | * | ||
720 | * The DSP expects first cmd to be SBA_VB_START, so at first startup send | ||
721 | * that. | ||
722 | * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that. | ||
723 | * | ||
724 | * Do refcount internally so that we send command only at first start | ||
725 | * and last end. Since SST driver does its own ref count, invoke sst's | ||
726 | * power ops always! | ||
727 | */ | ||
728 | int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable) | ||
729 | { | ||
730 | int ret = 0; | ||
731 | struct sst_cmd_generic cmd; | ||
732 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
733 | static int timer_usage; | ||
734 | |||
735 | if (enable) | ||
736 | cmd.header.command_id = SBA_VB_START; | ||
737 | else | ||
738 | cmd.header.command_id = SBA_IDLE; | ||
739 | dev_dbg(dai->dev, "enable=%u, usage=%d\n", enable, timer_usage); | ||
740 | |||
741 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
742 | cmd.header.length = 0; | ||
743 | |||
744 | if (enable) { | ||
745 | ret = sst->ops->power(sst->dev, true); | ||
746 | if (ret < 0) | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | mutex_lock(&drv->lock); | ||
751 | if (enable) | ||
752 | timer_usage++; | ||
753 | else | ||
754 | timer_usage--; | ||
755 | |||
756 | /* | ||
757 | * Send the command only if this call is the first enable or last | ||
758 | * disable | ||
759 | */ | ||
760 | if ((enable && (timer_usage == 1)) || | ||
761 | (!enable && (timer_usage == 0))) { | ||
762 | ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD, | ||
763 | SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd, | ||
764 | sizeof(cmd.header) + cmd.header.length); | ||
765 | if (ret && enable) { | ||
766 | timer_usage--; | ||
767 | enable = false; | ||
768 | } | ||
769 | } | ||
770 | mutex_unlock(&drv->lock); | ||
771 | |||
772 | if (!enable) | ||
773 | sst->ops->power(sst->dev, false); | ||
774 | return ret; | ||
775 | } | ||
776 | |||
777 | /** | ||
778 | * sst_ssp_config - contains SSP configuration for media UC | ||
779 | */ | ||
780 | static const struct sst_ssp_config sst_ssp_configs = { | ||
781 | .ssp_id = SSP_CODEC, | ||
782 | .bits_per_slot = 24, | ||
783 | .slots = 4, | ||
784 | .ssp_mode = SSP_MODE_MASTER, | ||
785 | .pcm_mode = SSP_PCM_MODE_NETWORK, | ||
786 | .duplex = SSP_DUPLEX, | ||
787 | .ssp_protocol = SSP_MODE_PCM, | ||
788 | .fs_width = 1, | ||
789 | .fs_frequency = SSP_FS_48_KHZ, | ||
790 | .active_slot_map = 0xF, | ||
791 | .start_delay = 0, | ||
792 | }; | ||
793 | |||
794 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable) | ||
795 | { | ||
796 | struct sst_cmd_sba_hw_set_ssp cmd; | ||
797 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
798 | const struct sst_ssp_config *config; | ||
799 | |||
800 | dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id); | ||
801 | |||
802 | SST_FILL_DEFAULT_DESTINATION(cmd.header.dst); | ||
803 | cmd.header.command_id = SBA_HW_SET_SSP; | ||
804 | cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp) | ||
805 | - sizeof(struct sst_dsp_header); | ||
806 | |||
807 | config = &sst_ssp_configs; | ||
808 | dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id); | ||
809 | |||
810 | if (enable) | ||
811 | cmd.switch_state = SST_SWITCH_ON; | ||
812 | else | ||
813 | cmd.switch_state = SST_SWITCH_OFF; | ||
814 | |||
815 | cmd.selection = config->ssp_id; | ||
816 | cmd.nb_bits_per_slots = config->bits_per_slot; | ||
817 | cmd.nb_slots = config->slots; | ||
818 | cmd.mode = config->ssp_mode | (config->pcm_mode << 1); | ||
819 | cmd.duplex = config->duplex; | ||
820 | cmd.active_tx_slot_map = config->active_slot_map; | ||
821 | cmd.active_rx_slot_map = config->active_slot_map; | ||
822 | cmd.frame_sync_frequency = config->fs_frequency; | ||
823 | cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH; | ||
824 | cmd.data_polarity = 1; | ||
825 | cmd.frame_sync_width = config->fs_width; | ||
826 | cmd.ssp_protocol = config->ssp_protocol; | ||
827 | cmd.start_delay = config->start_delay; | ||
828 | cmd.reserved1 = cmd.reserved2 = 0xFF; | ||
829 | |||
830 | return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
831 | SST_TASK_SBA, 0, &cmd, | ||
832 | sizeof(cmd.header) + cmd.header.length); | ||
833 | } | ||
834 | |||
835 | static int sst_set_be_modules(struct snd_soc_dapm_widget *w, | ||
836 | struct snd_kcontrol *k, int event) | ||
837 | { | ||
838 | int ret = 0; | ||
839 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
840 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
841 | |||
842 | dev_dbg(c->dev, "Enter: widget=%s\n", w->name); | ||
843 | |||
844 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
845 | ret = sst_send_slot_map(drv); | ||
846 | if (ret) | ||
847 | return ret; | ||
848 | ret = sst_send_pipe_module_params(w, k); | ||
849 | } | ||
850 | return ret; | ||
851 | } | ||
852 | |||
853 | static int sst_set_media_path(struct snd_soc_dapm_widget *w, | ||
854 | struct snd_kcontrol *k, int event) | ||
855 | { | ||
856 | int ret = 0; | ||
857 | struct sst_cmd_set_media_path cmd; | ||
858 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
859 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
860 | struct sst_ids *ids = w->priv; | ||
861 | |||
862 | dev_dbg(c->dev, "widget=%s\n", w->name); | ||
863 | dev_dbg(c->dev, "task=%u, location=%#x\n", | ||
864 | ids->task_id, ids->location_id); | ||
865 | |||
866 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
867 | cmd.switch_state = SST_PATH_ON; | ||
868 | else | ||
869 | cmd.switch_state = SST_PATH_OFF; | ||
870 | |||
871 | SST_FILL_DESTINATION(2, cmd.header.dst, | ||
872 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
873 | |||
874 | /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */ | ||
875 | cmd.header.command_id = MMX_SET_MEDIA_PATH; | ||
876 | cmd.header.length = sizeof(struct sst_cmd_set_media_path) | ||
877 | - sizeof(struct sst_dsp_header); | ||
878 | |||
879 | ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
880 | ids->task_id, 0, &cmd, | ||
881 | sizeof(cmd.header) + cmd.header.length); | ||
882 | if (ret) | ||
883 | return ret; | ||
884 | |||
885 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
886 | ret = sst_send_pipe_module_params(w, k); | ||
887 | return ret; | ||
888 | } | ||
889 | |||
890 | static int sst_set_media_loop(struct snd_soc_dapm_widget *w, | ||
891 | struct snd_kcontrol *k, int event) | ||
892 | { | ||
893 | int ret = 0; | ||
894 | struct sst_cmd_sba_set_media_loop_map cmd; | ||
895 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
896 | struct sst_data *drv = snd_soc_component_get_drvdata(c); | ||
897 | struct sst_ids *ids = w->priv; | ||
898 | |||
899 | dev_dbg(c->dev, "Enter:widget=%s\n", w->name); | ||
900 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
901 | cmd.switch_state = SST_SWITCH_ON; | ||
902 | else | ||
903 | cmd.switch_state = SST_SWITCH_OFF; | ||
904 | |||
905 | SST_FILL_DESTINATION(2, cmd.header.dst, | ||
906 | ids->location_id, SST_DEFAULT_MODULE_ID); | ||
907 | |||
908 | cmd.header.command_id = SBA_SET_MEDIA_LOOP_MAP; | ||
909 | cmd.header.length = sizeof(struct sst_cmd_sba_set_media_loop_map) | ||
910 | - sizeof(struct sst_dsp_header); | ||
911 | cmd.param.part.cfg.rate = 2; /* 48khz */ | ||
912 | |||
913 | cmd.param.part.cfg.format = ids->format; /* stereo/Mono */ | ||
914 | cmd.param.part.cfg.s_length = 1; /* 24bit left justified */ | ||
915 | cmd.map = 0; /* Algo sequence: Gain - DRP - FIR - IIR */ | ||
916 | |||
917 | ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED, | ||
918 | SST_TASK_SBA, 0, &cmd, | ||
919 | sizeof(cmd.header) + cmd.header.length); | ||
920 | if (ret) | ||
921 | return ret; | ||
922 | |||
923 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
924 | ret = sst_send_pipe_module_params(w, k); | ||
925 | return ret; | ||
926 | } | ||
927 | |||
928 | static const struct snd_soc_dapm_widget sst_dapm_widgets[] = { | ||
929 | SST_AIF_IN("codec_in0", sst_set_be_modules), | ||
930 | SST_AIF_IN("codec_in1", sst_set_be_modules), | ||
931 | SST_AIF_OUT("codec_out0", sst_set_be_modules), | ||
932 | SST_AIF_OUT("codec_out1", sst_set_be_modules), | ||
933 | |||
934 | /* Media Paths */ | ||
935 | /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */ | ||
936 | SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event), | ||
937 | SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL), | ||
938 | SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path), | ||
939 | SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL), | ||
940 | SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path), | ||
941 | SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path), | ||
942 | |||
943 | /* SBA PCM Paths */ | ||
944 | SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path), | ||
945 | SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path), | ||
946 | SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path), | ||
947 | SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path), | ||
948 | SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path), | ||
949 | |||
950 | /* SBA Loops */ | ||
951 | SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL), | ||
952 | SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL), | ||
953 | SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL), | ||
954 | SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop), | ||
955 | SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop), | ||
956 | SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop), | ||
957 | |||
958 | /* Media Mixers */ | ||
959 | SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA0, | ||
960 | sst_mix_media0_controls, sst_swm_mixer_event), | ||
961 | SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA1, | ||
962 | sst_mix_media1_controls, sst_swm_mixer_event), | ||
963 | |||
964 | /* SBA PCM mixers */ | ||
965 | SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM0, | ||
966 | sst_mix_pcm0_controls, sst_swm_mixer_event), | ||
967 | SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM1, | ||
968 | sst_mix_pcm1_controls, sst_swm_mixer_event), | ||
969 | SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM2, | ||
970 | sst_mix_pcm2_controls, sst_swm_mixer_event), | ||
971 | |||
972 | /* SBA Loop mixers */ | ||
973 | SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, | ||
974 | sst_mix_sprot_l0_controls, sst_swm_mixer_event), | ||
975 | SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, | ||
976 | sst_mix_media_l1_controls, sst_swm_mixer_event), | ||
977 | SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, | ||
978 | sst_mix_media_l2_controls, sst_swm_mixer_event), | ||
979 | |||
980 | /* SBA Backend mixers */ | ||
981 | SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC0, | ||
982 | sst_mix_codec0_controls, sst_swm_mixer_event), | ||
983 | SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1, | ||
984 | sst_mix_codec1_controls, sst_swm_mixer_event), | ||
985 | }; | ||
986 | |||
987 | static const struct snd_soc_dapm_route intercon[] = { | ||
988 | {"media0_in", NULL, "Compress Playback"}, | ||
989 | {"media1_in", NULL, "Headset Playback"}, | ||
990 | {"media2_in", NULL, "pcm0_out"}, | ||
991 | |||
992 | {"media0_out mix 0", "media0_in Switch", "media0_in"}, | ||
993 | {"media0_out mix 0", "media1_in Switch", "media1_in"}, | ||
994 | {"media0_out mix 0", "media2_in Switch", "media2_in"}, | ||
995 | {"media0_out mix 0", "media3_in Switch", "media3_in"}, | ||
996 | {"media1_out mix 0", "media0_in Switch", "media0_in"}, | ||
997 | {"media1_out mix 0", "media1_in Switch", "media1_in"}, | ||
998 | {"media1_out mix 0", "media2_in Switch", "media2_in"}, | ||
999 | {"media1_out mix 0", "media3_in Switch", "media3_in"}, | ||
1000 | |||
1001 | {"media0_out", NULL, "media0_out mix 0"}, | ||
1002 | {"media1_out", NULL, "media1_out mix 0"}, | ||
1003 | {"pcm0_in", NULL, "media0_out"}, | ||
1004 | {"pcm1_in", NULL, "media1_out"}, | ||
1005 | |||
1006 | {"Headset Capture", NULL, "pcm1_out"}, | ||
1007 | {"Headset Capture", NULL, "pcm2_out"}, | ||
1008 | {"pcm0_out", NULL, "pcm0_out mix 0"}, | ||
1009 | SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"), | ||
1010 | {"pcm1_out", NULL, "pcm1_out mix 0"}, | ||
1011 | SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"), | ||
1012 | {"pcm2_out", NULL, "pcm2_out mix 0"}, | ||
1013 | SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"), | ||
1014 | |||
1015 | {"media_loop1_in", NULL, "media_loop1_out"}, | ||
1016 | {"media_loop1_out", NULL, "media_loop1_out mix 0"}, | ||
1017 | SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"), | ||
1018 | {"media_loop2_in", NULL, "media_loop2_out"}, | ||
1019 | {"media_loop2_out", NULL, "media_loop2_out mix 0"}, | ||
1020 | SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"), | ||
1021 | {"sprot_loop_in", NULL, "sprot_loop_out"}, | ||
1022 | {"sprot_loop_out", NULL, "sprot_loop_out mix 0"}, | ||
1023 | SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"), | ||
1024 | |||
1025 | {"codec_out0", NULL, "codec_out0 mix 0"}, | ||
1026 | SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"), | ||
1027 | {"codec_out1", NULL, "codec_out1 mix 0"}, | ||
1028 | SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"), | ||
1029 | |||
1030 | }; | ||
1031 | static const char * const slot_names[] = { | ||
1032 | "none", | ||
1033 | "slot 0", "slot 1", "slot 2", "slot 3", | ||
1034 | "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */ | ||
1035 | }; | ||
1036 | |||
1037 | static const char * const channel_names[] = { | ||
1038 | "none", | ||
1039 | "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1", | ||
1040 | "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */ | ||
1041 | }; | ||
1042 | |||
1043 | #define SST_INTERLEAVER(xpname, slot_name, slotno) \ | ||
1044 | SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \ | ||
1045 | channel_names, sst_slot_get, sst_slot_put) | ||
1046 | |||
1047 | #define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \ | ||
1048 | SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \ | ||
1049 | slot_names, sst_slot_get, sst_slot_put) | ||
1050 | |||
1051 | static const struct snd_kcontrol_new sst_slot_controls[] = { | ||
1052 | SST_INTERLEAVER("codec_out", "slot 0", 0), | ||
1053 | SST_INTERLEAVER("codec_out", "slot 1", 1), | ||
1054 | SST_INTERLEAVER("codec_out", "slot 2", 2), | ||
1055 | SST_INTERLEAVER("codec_out", "slot 3", 3), | ||
1056 | SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0), | ||
1057 | SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1), | ||
1058 | SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2), | ||
1059 | SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3), | ||
1060 | }; | ||
1061 | |||
1062 | /* Gain helper with min/max set */ | ||
1063 | #define SST_GAIN(name, path_id, task_id, instance, gain_var) \ | ||
1064 | SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \ | ||
1065 | SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \ | ||
1066 | sst_gain_get, sst_gain_put, \ | ||
1067 | SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id, \ | ||
1068 | sst_gain_tlv_common, gain_var) | ||
1069 | |||
1070 | #define SST_VOLUME(name, path_id, task_id, instance, gain_var) \ | ||
1071 | SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \ | ||
1072 | SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \ | ||
1073 | sst_gain_get, sst_gain_put, \ | ||
1074 | SST_MODULE_ID_VOLUME, path_id, instance, task_id, \ | ||
1075 | sst_gain_tlv_common, gain_var) | ||
1076 | |||
1077 | static struct sst_gain_value sst_gains[]; | ||
1078 | |||
1079 | static const struct snd_kcontrol_new sst_gain_controls[] = { | ||
1080 | SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[0]), | ||
1081 | SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN, SST_TASK_MMX, 0, &sst_gains[1]), | ||
1082 | SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN, SST_TASK_MMX, 0, &sst_gains[2]), | ||
1083 | SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN, SST_TASK_MMX, 0, &sst_gains[3]), | ||
1084 | |||
1085 | SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN, SST_TASK_SBA, 0, &sst_gains[4]), | ||
1086 | SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN, SST_TASK_SBA, 0, &sst_gains[5]), | ||
1087 | SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT, SST_TASK_SBA, 0, &sst_gains[6]), | ||
1088 | SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT, SST_TASK_SBA, 0, &sst_gains[7]), | ||
1089 | |||
1090 | SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0, SST_TASK_SBA, 0, &sst_gains[8]), | ||
1091 | SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1, SST_TASK_SBA, 0, &sst_gains[9]), | ||
1092 | SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0, SST_TASK_SBA, 0, &sst_gains[10]), | ||
1093 | SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1, SST_TASK_SBA, 0, &sst_gains[11]), | ||
1094 | SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT, SST_TASK_SBA, 0, &sst_gains[12]), | ||
1095 | SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]), | ||
1096 | SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]), | ||
1097 | SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]), | ||
1098 | }; | ||
1099 | |||
1100 | #define SST_GAIN_NUM_CONTROLS 3 | ||
1101 | /* the SST_GAIN macro above will create three alsa controls for each | ||
1102 | * instance invoked, gain, mute and ramp duration, which use the same gain | ||
1103 | * cell sst_gain to keep track of data | ||
1104 | * To calculate number of gain cell instances we need to device by 3 in | ||
1105 | * below caulcation for gain cell memory. | ||
1106 | * This gets rid of static number and issues while adding new controls | ||
1107 | */ | ||
1108 | static struct sst_gain_value sst_gains[ARRAY_SIZE(sst_gain_controls)/SST_GAIN_NUM_CONTROLS]; | ||
1109 | |||
165 | static const struct snd_kcontrol_new sst_algo_controls[] = { | 1110 | static const struct snd_kcontrol_new sst_algo_controls[] = { |
166 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, | 1111 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, |
167 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), | 1112 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), |
@@ -198,21 +1143,280 @@ static int sst_algo_control_init(struct device *dev) | |||
198 | return 0; | 1143 | return 0; |
199 | } | 1144 | } |
200 | 1145 | ||
201 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) | 1146 | static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w) |
1147 | { | ||
1148 | switch (w->id) { | ||
1149 | case snd_soc_dapm_pga: | ||
1150 | case snd_soc_dapm_aif_in: | ||
1151 | case snd_soc_dapm_aif_out: | ||
1152 | case snd_soc_dapm_input: | ||
1153 | case snd_soc_dapm_output: | ||
1154 | case snd_soc_dapm_mixer: | ||
1155 | return true; | ||
1156 | default: | ||
1157 | return false; | ||
1158 | } | ||
1159 | } | ||
1160 | |||
1161 | /** | ||
1162 | * sst_send_pipe_gains - send gains for the front-end DAIs | ||
1163 | * | ||
1164 | * The gains in the pipes connected to the front-ends are muted/unmuted | ||
1165 | * automatically via the digital_mute() DAPM callback. This function sends the | ||
1166 | * gains for the front-end pipes. | ||
1167 | */ | ||
1168 | int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute) | ||
1169 | { | ||
1170 | struct sst_data *drv = snd_soc_dai_get_drvdata(dai); | ||
1171 | struct snd_soc_dapm_widget *w; | ||
1172 | struct snd_soc_dapm_path *p = NULL; | ||
1173 | |||
1174 | dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream); | ||
1175 | |||
1176 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1177 | dev_dbg(dai->dev, "Stream name=%s\n", | ||
1178 | dai->playback_widget->name); | ||
1179 | w = dai->playback_widget; | ||
1180 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1181 | if (p->connected && !p->connected(w, p->sink)) | ||
1182 | continue; | ||
1183 | |||
1184 | if (p->connect && p->sink->power && | ||
1185 | is_sst_dapm_widget(p->sink)) { | ||
1186 | struct sst_ids *ids = p->sink->priv; | ||
1187 | |||
1188 | dev_dbg(dai->dev, "send gains for widget=%s\n", | ||
1189 | p->sink->name); | ||
1190 | mutex_lock(&drv->lock); | ||
1191 | sst_set_pipe_gain(ids, drv, mute); | ||
1192 | mutex_unlock(&drv->lock); | ||
1193 | } | ||
1194 | } | ||
1195 | } else { | ||
1196 | dev_dbg(dai->dev, "Stream name=%s\n", | ||
1197 | dai->capture_widget->name); | ||
1198 | w = dai->capture_widget; | ||
1199 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1200 | if (p->connected && !p->connected(w, p->sink)) | ||
1201 | continue; | ||
1202 | |||
1203 | if (p->connect && p->source->power && | ||
1204 | is_sst_dapm_widget(p->source)) { | ||
1205 | struct sst_ids *ids = p->source->priv; | ||
1206 | |||
1207 | dev_dbg(dai->dev, "send gain for widget=%s\n", | ||
1208 | p->source->name); | ||
1209 | mutex_lock(&drv->lock); | ||
1210 | sst_set_pipe_gain(ids, drv, mute); | ||
1211 | mutex_unlock(&drv->lock); | ||
1212 | } | ||
1213 | } | ||
1214 | } | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | /** | ||
1219 | * sst_fill_module_list - populate the list of modules/gains for a pipe | ||
1220 | * | ||
1221 | * | ||
1222 | * Fills the widget pointer in the kcontrol private data, and also fills the | ||
1223 | * kcontrol pointer in the widget private data. | ||
1224 | * | ||
1225 | * Widget pointer is used to send the algo/gain in the .put() handler if the | ||
1226 | * widget is powerd on. | ||
1227 | * | ||
1228 | * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF | ||
1229 | * event handler. Each widget (pipe) has multiple algos stored in the algo_list. | ||
1230 | */ | ||
1231 | static int sst_fill_module_list(struct snd_kcontrol *kctl, | ||
1232 | struct snd_soc_dapm_widget *w, int type) | ||
202 | { | 1233 | { |
1234 | struct sst_module *module = NULL; | ||
1235 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
1236 | struct sst_ids *ids = w->priv; | ||
203 | int ret = 0; | 1237 | int ret = 0; |
1238 | |||
1239 | module = devm_kzalloc(c->dev, sizeof(*module), GFP_KERNEL); | ||
1240 | if (!module) | ||
1241 | return -ENOMEM; | ||
1242 | |||
1243 | if (type == SST_MODULE_GAIN) { | ||
1244 | struct sst_gain_mixer_control *mc = (void *)kctl->private_value; | ||
1245 | |||
1246 | mc->w = w; | ||
1247 | module->kctl = kctl; | ||
1248 | list_add_tail(&module->node, &ids->gain_list); | ||
1249 | } else if (type == SST_MODULE_ALGO) { | ||
1250 | struct sst_algo_control *bc = (void *)kctl->private_value; | ||
1251 | |||
1252 | bc->w = w; | ||
1253 | module->kctl = kctl; | ||
1254 | list_add_tail(&module->node, &ids->algo_list); | ||
1255 | } else { | ||
1256 | dev_err(c->dev, "invoked for unknown type %d module %s", | ||
1257 | type, kctl->id.name); | ||
1258 | ret = -EINVAL; | ||
1259 | } | ||
1260 | |||
1261 | return ret; | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * sst_fill_widget_module_info - fill list of gains/algos for the pipe | ||
1266 | * @widget: pipe modelled as a DAPM widget | ||
1267 | * | ||
1268 | * Fill the list of gains/algos for the widget by looking at all the card | ||
1269 | * controls and comparing the name of the widget with the first part of control | ||
1270 | * name. First part of control name contains the pipe name (widget name). | ||
1271 | */ | ||
1272 | static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, | ||
1273 | struct snd_soc_platform *platform) | ||
1274 | { | ||
1275 | struct snd_kcontrol *kctl; | ||
1276 | int index, ret = 0; | ||
1277 | struct snd_card *card = platform->component.card->snd_card; | ||
1278 | char *idx; | ||
1279 | |||
1280 | down_read(&card->controls_rwsem); | ||
1281 | |||
1282 | list_for_each_entry(kctl, &card->controls, list) { | ||
1283 | idx = strstr(kctl->id.name, " "); | ||
1284 | if (idx == NULL) | ||
1285 | continue; | ||
1286 | index = strlen(kctl->id.name) - strlen(idx); | ||
1287 | |||
1288 | if (strstr(kctl->id.name, "Volume") && | ||
1289 | !strncmp(kctl->id.name, w->name, index)) | ||
1290 | ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN); | ||
1291 | |||
1292 | else if (strstr(kctl->id.name, "params") && | ||
1293 | !strncmp(kctl->id.name, w->name, index)) | ||
1294 | ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO); | ||
1295 | |||
1296 | else if (strstr(kctl->id.name, "Switch") && | ||
1297 | !strncmp(kctl->id.name, w->name, index) && | ||
1298 | strstr(kctl->id.name, "Gain")) { | ||
1299 | struct sst_gain_mixer_control *mc = | ||
1300 | (void *)kctl->private_value; | ||
1301 | |||
1302 | mc->w = w; | ||
1303 | |||
1304 | } else if (strstr(kctl->id.name, "interleaver") && | ||
1305 | !strncmp(kctl->id.name, w->name, index)) { | ||
1306 | struct sst_enum *e = (void *)kctl->private_value; | ||
1307 | |||
1308 | e->w = w; | ||
1309 | |||
1310 | } else if (strstr(kctl->id.name, "deinterleaver") && | ||
1311 | !strncmp(kctl->id.name, w->name, index)) { | ||
1312 | |||
1313 | struct sst_enum *e = (void *)kctl->private_value; | ||
1314 | |||
1315 | e->w = w; | ||
1316 | } | ||
1317 | |||
1318 | if (ret < 0) { | ||
1319 | up_read(&card->controls_rwsem); | ||
1320 | return ret; | ||
1321 | } | ||
1322 | } | ||
1323 | |||
1324 | up_read(&card->controls_rwsem); | ||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | /** | ||
1329 | * sst_fill_linked_widgets - fill the parent pointer for the linked widget | ||
1330 | */ | ||
1331 | static void sst_fill_linked_widgets(struct snd_soc_platform *platform, | ||
1332 | struct sst_ids *ids) | ||
1333 | { | ||
1334 | struct snd_soc_dapm_widget *w; | ||
1335 | unsigned int len = strlen(ids->parent_wname); | ||
1336 | |||
1337 | list_for_each_entry(w, &platform->component.card->widgets, list) { | ||
1338 | if (!strncmp(ids->parent_wname, w->name, len)) { | ||
1339 | ids->parent_w = w; | ||
1340 | break; | ||
1341 | } | ||
1342 | } | ||
1343 | } | ||
1344 | |||
1345 | /** | ||
1346 | * sst_map_modules_to_pipe - fill algo/gains list for all pipes | ||
1347 | */ | ||
1348 | static int sst_map_modules_to_pipe(struct snd_soc_platform *platform) | ||
1349 | { | ||
1350 | struct snd_soc_dapm_widget *w; | ||
1351 | int ret = 0; | ||
1352 | |||
1353 | list_for_each_entry(w, &platform->component.card->widgets, list) { | ||
1354 | if (is_sst_dapm_widget(w) && (w->priv)) { | ||
1355 | struct sst_ids *ids = w->priv; | ||
1356 | |||
1357 | dev_dbg(platform->dev, "widget type=%d name=%s\n", | ||
1358 | w->id, w->name); | ||
1359 | INIT_LIST_HEAD(&ids->algo_list); | ||
1360 | INIT_LIST_HEAD(&ids->gain_list); | ||
1361 | ret = sst_fill_widget_module_info(w, platform); | ||
1362 | |||
1363 | if (ret < 0) | ||
1364 | return ret; | ||
1365 | |||
1366 | /* fill linked widgets */ | ||
1367 | if (ids->parent_wname != NULL) | ||
1368 | sst_fill_linked_widgets(platform, ids); | ||
1369 | } | ||
1370 | } | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) | ||
1375 | { | ||
1376 | int i, ret = 0; | ||
1377 | struct snd_soc_dapm_context *dapm = | ||
1378 | snd_soc_component_get_dapm(&platform->component); | ||
204 | struct sst_data *drv = snd_soc_platform_get_drvdata(platform); | 1379 | struct sst_data *drv = snd_soc_platform_get_drvdata(platform); |
1380 | unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3; | ||
205 | 1381 | ||
206 | drv->byte_stream = devm_kzalloc(platform->dev, | 1382 | drv->byte_stream = devm_kzalloc(platform->dev, |
207 | SST_MAX_BIN_BYTES, GFP_KERNEL); | 1383 | SST_MAX_BIN_BYTES, GFP_KERNEL); |
208 | if (!drv->byte_stream) | 1384 | if (!drv->byte_stream) |
209 | return -ENOMEM; | 1385 | return -ENOMEM; |
210 | 1386 | ||
211 | /*Initialize algo control params*/ | 1387 | snd_soc_dapm_new_controls(dapm, sst_dapm_widgets, |
1388 | ARRAY_SIZE(sst_dapm_widgets)); | ||
1389 | snd_soc_dapm_add_routes(dapm, intercon, | ||
1390 | ARRAY_SIZE(intercon)); | ||
1391 | snd_soc_dapm_new_widgets(dapm->card); | ||
1392 | |||
1393 | for (i = 0; i < gains; i++) { | ||
1394 | sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT; | ||
1395 | sst_gains[i].l_gain = SST_GAIN_VOLUME_DEFAULT; | ||
1396 | sst_gains[i].r_gain = SST_GAIN_VOLUME_DEFAULT; | ||
1397 | sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT; | ||
1398 | } | ||
1399 | |||
1400 | ret = snd_soc_add_platform_controls(platform, sst_gain_controls, | ||
1401 | ARRAY_SIZE(sst_gain_controls)); | ||
1402 | if (ret) | ||
1403 | return ret; | ||
1404 | |||
1405 | /* Initialize algo control params */ | ||
212 | ret = sst_algo_control_init(platform->dev); | 1406 | ret = sst_algo_control_init(platform->dev); |
213 | if (ret) | 1407 | if (ret) |
214 | return ret; | 1408 | return ret; |
215 | ret = snd_soc_add_platform_controls(platform, sst_algo_controls, | 1409 | ret = snd_soc_add_platform_controls(platform, sst_algo_controls, |
216 | ARRAY_SIZE(sst_algo_controls)); | 1410 | ARRAY_SIZE(sst_algo_controls)); |
1411 | if (ret) | ||
1412 | return ret; | ||
1413 | |||
1414 | ret = snd_soc_add_platform_controls(platform, sst_slot_controls, | ||
1415 | ARRAY_SIZE(sst_slot_controls)); | ||
1416 | if (ret) | ||
1417 | return ret; | ||
1418 | |||
1419 | ret = sst_map_modules_to_pipe(platform); | ||
1420 | |||
217 | return ret; | 1421 | return ret; |
218 | } | 1422 | } |
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index a73e894b175c..dfebfdd5eb2a 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h | |||
@@ -23,6 +23,9 @@ | |||
23 | #ifndef __SST_ATOM_CONTROLS_H__ | 23 | #ifndef __SST_ATOM_CONTROLS_H__ |
24 | #define __SST_ATOM_CONTROLS_H__ | 24 | #define __SST_ATOM_CONTROLS_H__ |
25 | 25 | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
26 | enum { | 29 | enum { |
27 | MERR_DPCM_AUDIO = 0, | 30 | MERR_DPCM_AUDIO = 0, |
28 | MERR_DPCM_COMPR, | 31 | MERR_DPCM_COMPR, |
@@ -360,16 +363,416 @@ struct sst_dsp_header { | |||
360 | struct sst_cmd_generic { | 363 | struct sst_cmd_generic { |
361 | struct sst_dsp_header header; | 364 | struct sst_dsp_header header; |
362 | } __packed; | 365 | } __packed; |
366 | |||
367 | struct swm_input_ids { | ||
368 | struct sst_destination_id input_id; | ||
369 | } __packed; | ||
370 | |||
371 | struct sst_cmd_set_swm { | ||
372 | struct sst_dsp_header header; | ||
373 | struct sst_destination_id output_id; | ||
374 | u16 switch_state; | ||
375 | u16 nb_inputs; | ||
376 | struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS]; | ||
377 | } __packed; | ||
378 | |||
379 | struct sst_cmd_set_media_path { | ||
380 | struct sst_dsp_header header; | ||
381 | u16 switch_state; | ||
382 | } __packed; | ||
383 | |||
384 | struct pcm_cfg { | ||
385 | u8 s_length:2; | ||
386 | u8 rate:3; | ||
387 | u8 format:3; | ||
388 | } __packed; | ||
389 | |||
390 | struct sst_cmd_set_speech_path { | ||
391 | struct sst_dsp_header header; | ||
392 | u16 switch_state; | ||
393 | struct { | ||
394 | u16 rsvd:8; | ||
395 | struct pcm_cfg cfg; | ||
396 | } config; | ||
397 | } __packed; | ||
398 | |||
399 | struct gain_cell { | ||
400 | struct sst_destination_id dest; | ||
401 | s16 cell_gain_left; | ||
402 | s16 cell_gain_right; | ||
403 | u16 gain_time_constant; | ||
404 | } __packed; | ||
405 | |||
406 | #define NUM_GAIN_CELLS 1 | ||
407 | struct sst_cmd_set_gain_dual { | ||
408 | struct sst_dsp_header header; | ||
409 | u16 gain_cell_num; | ||
410 | struct gain_cell cell_gains[NUM_GAIN_CELLS]; | ||
411 | } __packed; | ||
363 | struct sst_cmd_set_params { | 412 | struct sst_cmd_set_params { |
364 | struct sst_destination_id dst; | 413 | struct sst_destination_id dst; |
365 | u16 command_id; | 414 | u16 command_id; |
366 | char params[0]; | 415 | char params[0]; |
367 | } __packed; | 416 | } __packed; |
417 | |||
418 | |||
419 | struct sst_cmd_sba_vb_start { | ||
420 | struct sst_dsp_header header; | ||
421 | } __packed; | ||
422 | |||
423 | union sba_media_loop_params { | ||
424 | struct { | ||
425 | u16 rsvd:8; | ||
426 | struct pcm_cfg cfg; | ||
427 | } part; | ||
428 | u16 full; | ||
429 | } __packed; | ||
430 | |||
431 | struct sst_cmd_sba_set_media_loop_map { | ||
432 | struct sst_dsp_header header; | ||
433 | u16 switch_state; | ||
434 | union sba_media_loop_params param; | ||
435 | u16 map; | ||
436 | } __packed; | ||
437 | |||
438 | struct sst_cmd_tone_stop { | ||
439 | struct sst_dsp_header header; | ||
440 | u16 switch_state; | ||
441 | } __packed; | ||
442 | |||
443 | enum sst_ssp_mode { | ||
444 | SSP_MODE_MASTER = 0, | ||
445 | SSP_MODE_SLAVE = 1, | ||
446 | }; | ||
447 | |||
448 | enum sst_ssp_pcm_mode { | ||
449 | SSP_PCM_MODE_NORMAL = 0, | ||
450 | SSP_PCM_MODE_NETWORK = 1, | ||
451 | }; | ||
452 | |||
453 | enum sst_ssp_duplex { | ||
454 | SSP_DUPLEX = 0, | ||
455 | SSP_RX = 1, | ||
456 | SSP_TX = 2, | ||
457 | }; | ||
458 | |||
459 | enum sst_ssp_fs_frequency { | ||
460 | SSP_FS_8_KHZ = 0, | ||
461 | SSP_FS_16_KHZ = 1, | ||
462 | SSP_FS_44_1_KHZ = 2, | ||
463 | SSP_FS_48_KHZ = 3, | ||
464 | }; | ||
465 | |||
466 | enum sst_ssp_fs_polarity { | ||
467 | SSP_FS_ACTIVE_LOW = 0, | ||
468 | SSP_FS_ACTIVE_HIGH = 1, | ||
469 | }; | ||
470 | |||
471 | enum sst_ssp_protocol { | ||
472 | SSP_MODE_PCM = 0, | ||
473 | SSP_MODE_I2S = 1, | ||
474 | }; | ||
475 | |||
476 | enum sst_ssp_port_id { | ||
477 | SSP_MODEM = 0, | ||
478 | SSP_BT = 1, | ||
479 | SSP_FM = 2, | ||
480 | SSP_CODEC = 3, | ||
481 | }; | ||
482 | |||
483 | struct sst_cmd_sba_hw_set_ssp { | ||
484 | struct sst_dsp_header header; | ||
485 | u16 selection; /* 0:SSP0(def), 1:SSP1, 2:SSP2 */ | ||
486 | |||
487 | u16 switch_state; | ||
488 | |||
489 | u16 nb_bits_per_slots:6; /* 0-32 bits, 24 (def) */ | ||
490 | u16 nb_slots:4; /* 0-8: slots per frame */ | ||
491 | u16 mode:3; /* 0:Master, 1: Slave */ | ||
492 | u16 duplex:3; | ||
493 | |||
494 | u16 active_tx_slot_map:8; /* Bit map, 0:off, 1:on */ | ||
495 | u16 reserved1:8; | ||
496 | |||
497 | u16 active_rx_slot_map:8; /* Bit map 0: Off, 1:On */ | ||
498 | u16 reserved2:8; | ||
499 | |||
500 | u16 frame_sync_frequency; | ||
501 | |||
502 | u16 frame_sync_polarity:8; | ||
503 | u16 data_polarity:8; | ||
504 | |||
505 | u16 frame_sync_width; /* 1 to N clocks */ | ||
506 | u16 ssp_protocol:8; | ||
507 | u16 start_delay:8; /* Start delay in terms of clock ticks */ | ||
508 | } __packed; | ||
509 | |||
510 | #define SST_MAX_TDM_SLOTS 8 | ||
511 | |||
512 | struct sst_param_sba_ssp_slot_map { | ||
513 | struct sst_dsp_header header; | ||
514 | |||
515 | u16 param_id; | ||
516 | u16 param_len; | ||
517 | u16 ssp_index; | ||
518 | |||
519 | u8 rx_slot_map[SST_MAX_TDM_SLOTS]; | ||
520 | u8 tx_slot_map[SST_MAX_TDM_SLOTS]; | ||
521 | } __packed; | ||
522 | |||
523 | enum { | ||
524 | SST_PROBE_EXTRACTOR = 0, | ||
525 | SST_PROBE_INJECTOR = 1, | ||
526 | }; | ||
527 | |||
528 | /**** widget defines *****/ | ||
529 | |||
530 | #define SST_MODULE_GAIN 1 | ||
531 | #define SST_MODULE_ALGO 2 | ||
532 | |||
533 | #define SST_FMT_MONO 0 | ||
534 | #define SST_FMT_STEREO 3 | ||
535 | |||
536 | /* physical SSP numbers */ | ||
537 | enum { | ||
538 | SST_SSP0 = 0, | ||
539 | SST_SSP1, | ||
540 | SST_SSP2, | ||
541 | SST_SSP_LAST = SST_SSP2, | ||
542 | }; | ||
543 | |||
544 | #define SST_NUM_SSPS (SST_SSP_LAST + 1) /* physical SSPs */ | ||
545 | #define SST_MAX_SSP_MUX 2 /* single SSP muxed between pipes */ | ||
546 | #define SST_MAX_SSP_DOMAINS 2 /* domains present in each pipe */ | ||
547 | |||
548 | struct sst_module { | ||
549 | struct snd_kcontrol *kctl; | ||
550 | struct list_head node; | ||
551 | }; | ||
552 | |||
553 | struct sst_ssp_config { | ||
554 | u8 ssp_id; | ||
555 | u8 bits_per_slot; | ||
556 | u8 slots; | ||
557 | u8 ssp_mode; | ||
558 | u8 pcm_mode; | ||
559 | u8 duplex; | ||
560 | u8 ssp_protocol; | ||
561 | u8 fs_frequency; | ||
562 | u8 active_slot_map; | ||
563 | u8 start_delay; | ||
564 | u16 fs_width; | ||
565 | }; | ||
566 | |||
567 | struct sst_ssp_cfg { | ||
568 | const u8 ssp_number; | ||
569 | const int *mux_shift; | ||
570 | const int (*domain_shift)[SST_MAX_SSP_MUX]; | ||
571 | const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS]; | ||
572 | }; | ||
573 | |||
574 | struct sst_ids { | ||
575 | u16 location_id; | ||
576 | u16 module_id; | ||
577 | u8 task_id; | ||
578 | u8 format; | ||
579 | u8 reg; | ||
580 | const char *parent_wname; | ||
581 | struct snd_soc_dapm_widget *parent_w; | ||
582 | struct list_head algo_list; | ||
583 | struct list_head gain_list; | ||
584 | const struct sst_pcm_format *pcm_fmt; | ||
585 | }; | ||
586 | |||
587 | |||
588 | #define SST_AIF_IN(wname, wevent) \ | ||
589 | { .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL, \ | ||
590 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
591 | .on_val = 1, .off_val = 0, \ | ||
592 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
593 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
594 | } | ||
595 | |||
596 | #define SST_AIF_OUT(wname, wevent) \ | ||
597 | { .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL, \ | ||
598 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
599 | .on_val = 1, .off_val = 0, \ | ||
600 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
601 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
602 | } | ||
603 | |||
604 | #define SST_INPUT(wname, wevent) \ | ||
605 | { .id = snd_soc_dapm_input, .name = wname, .sname = NULL, \ | ||
606 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
607 | .on_val = 1, .off_val = 0, \ | ||
608 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
609 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
610 | } | ||
611 | |||
612 | #define SST_OUTPUT(wname, wevent) \ | ||
613 | { .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \ | ||
614 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
615 | .on_val = 1, .off_val = 0, \ | ||
616 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
617 | .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \ | ||
618 | } | ||
619 | |||
620 | #define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent) \ | ||
621 | { .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \ | ||
622 | .reg = SND_SOC_NOPM, .shift = 0, \ | ||
623 | .on_val = 1, .off_val = 0, \ | ||
624 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \ | ||
625 | .priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\ | ||
626 | .pcm_fmt = wformat, } \ | ||
627 | } | ||
628 | |||
629 | #define SST_PATH(wname, wtask, wloc_id, wevent, wflags) \ | ||
630 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
631 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
632 | .on_val = 1, .off_val = 0, \ | ||
633 | .event = wevent, .event_flags = wflags, \ | ||
634 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \ | ||
635 | } | ||
636 | |||
637 | #define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags) \ | ||
638 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
639 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
640 | .on_val = 1, .off_val = 0, \ | ||
641 | .event = wevent, .event_flags = wflags, \ | ||
642 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
643 | .parent_wname = linked_wname} \ | ||
644 | } | ||
645 | |||
646 | #define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags) \ | ||
647 | { .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
648 | .kcontrol_news = NULL, .num_kcontrols = 0, \ | ||
649 | .event = wevent, .event_flags = wflags, \ | ||
650 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
651 | .format = wformat,} \ | ||
652 | } | ||
653 | |||
654 | /* output is triggered before input */ | ||
655 | #define SST_PATH_INPUT(name, task_id, loc_id, event) \ | ||
656 | SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) | ||
657 | |||
658 | #define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event) \ | ||
659 | SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \ | ||
660 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) | ||
661 | |||
662 | #define SST_PATH_OUTPUT(name, task_id, loc_id, event) \ | ||
663 | SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
664 | |||
665 | #define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event) \ | ||
666 | SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \ | ||
667 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
668 | |||
669 | #define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event) \ | ||
670 | SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD) | ||
671 | |||
672 | |||
673 | #define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent) \ | ||
674 | { .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \ | ||
675 | .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\ | ||
676 | .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | \ | ||
677 | SND_SOC_DAPM_POST_REG, \ | ||
678 | .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \ | ||
679 | .reg = wreg } \ | ||
680 | } | ||
681 | |||
682 | enum sst_gain_kcontrol_type { | ||
683 | SST_GAIN_TLV, | ||
684 | SST_GAIN_MUTE, | ||
685 | SST_GAIN_RAMP_DURATION, | ||
686 | }; | ||
687 | |||
688 | struct sst_gain_mixer_control { | ||
689 | bool stereo; | ||
690 | enum sst_gain_kcontrol_type type; | ||
691 | struct sst_gain_value *gain_val; | ||
692 | int max; | ||
693 | int min; | ||
694 | u16 instance_id; | ||
695 | u16 module_id; | ||
696 | u16 pipe_id; | ||
697 | u16 task_id; | ||
698 | char pname[44]; | ||
699 | struct snd_soc_dapm_widget *w; | ||
700 | }; | ||
701 | |||
702 | struct sst_gain_value { | ||
703 | u16 ramp_duration; | ||
704 | s16 l_gain; | ||
705 | s16 r_gain; | ||
706 | bool mute; | ||
707 | }; | ||
708 | #define SST_GAIN_VOLUME_DEFAULT (-1440) | ||
709 | #define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */ | ||
710 | #define SST_GAIN_MUTE_DEFAULT true | ||
711 | |||
712 | #define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \ | ||
713 | xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \ | ||
714 | xmin, xmax, xpname) \ | ||
715 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
716 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
717 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
718 | .tlv.p = (tlv_array), \ | ||
719 | .info = sst_gain_ctl_info,\ | ||
720 | .get = xhandler_get, .put = xhandler_put, \ | ||
721 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
722 | { .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \ | ||
723 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
724 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
725 | |||
726 | #define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \ | ||
727 | xmod, xpipe, xinstance, xtask, xtype, xgain_val, \ | ||
728 | xmin, xmax, xpname) \ | ||
729 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
730 | .info = sst_gain_ctl_info, \ | ||
731 | .get = xhandler_get, .put = xhandler_put, \ | ||
732 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
733 | { .stereo = false, .max = xmax, .min = xmin, .type = xtype, \ | ||
734 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
735 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
736 | |||
737 | #define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\ | ||
738 | xmod, xpipe, xinstance, xtask, xgain_val, xpname) \ | ||
739 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
740 | .info = snd_soc_info_bool_ext, \ | ||
741 | .get = xhandler_get, .put = xhandler_put, \ | ||
742 | .private_value = (unsigned long)&(struct sst_gain_mixer_control) \ | ||
743 | { .stereo = false, .type = SST_GAIN_MUTE, \ | ||
744 | .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\ | ||
745 | .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname} | ||
368 | #define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ | 746 | #define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ |
369 | xpname " " xmname " " #xinstance " " xtype | 747 | xpname " " xmname " " #xinstance " " xtype |
370 | 748 | ||
371 | #define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ | 749 | #define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ |
372 | xpname " " xmname " " #xinstance " " xtype " " xsubmodule | 750 | xpname " " xmname " " #xinstance " " xtype " " xsubmodule |
751 | |||
752 | /* | ||
753 | * 3 Controls for each Gain module | ||
754 | * e.g. - pcm0_in Gain 0 Volume | ||
755 | * - pcm0_in Gain 0 Ramp Delay | ||
756 | * - pcm0_in Gain 0 Switch | ||
757 | */ | ||
758 | #define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \ | ||
759 | xhandler_get, xhandler_put, \ | ||
760 | xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \ | ||
761 | { SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \ | ||
762 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \ | ||
763 | xgain_val, xmin_tc, xmax_tc, xpname) }, \ | ||
764 | { SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \ | ||
765 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \ | ||
766 | xgain_val, xpname) } ,\ | ||
767 | { SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \ | ||
768 | xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \ | ||
769 | xgain_val, xmin_gain, xmax_gain, xpname) } | ||
770 | |||
771 | #define SST_GAIN_TC_MIN 5 | ||
772 | #define SST_GAIN_TC_MAX 5000 | ||
773 | #define SST_GAIN_MIN_VALUE -1440 /* in 0.1 DB units */ | ||
774 | #define SST_GAIN_MAX_VALUE 360 | ||
775 | |||
373 | enum sst_algo_kcontrol_type { | 776 | enum sst_algo_kcontrol_type { |
374 | SST_ALGO_PARAMS, | 777 | SST_ALGO_PARAMS, |
375 | SST_ALGO_BYPASS, | 778 | SST_ALGO_BYPASS, |
@@ -439,4 +842,29 @@ struct sst_enum { | |||
439 | struct snd_soc_dapm_widget *w; | 842 | struct snd_soc_dapm_widget *w; |
440 | }; | 843 | }; |
441 | 844 | ||
845 | /* only 4 slots/channels supported atm */ | ||
846 | #define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \ | ||
847 | (struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, } | ||
848 | |||
849 | #define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \ | ||
850 | xpname " " xmname " " s_ch_name | ||
851 | |||
852 | #define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \ | ||
853 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
854 | .name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \ | ||
855 | .info = sst_slot_enum_info, \ | ||
856 | .get = xget, .put = xput, \ | ||
857 | .private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \ | ||
858 | } | ||
859 | |||
860 | #define SST_MUX_CTL_NAME(xpname, xinstance) \ | ||
861 | xpname " " #xinstance | ||
862 | |||
863 | #define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \ | ||
864 | (struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts) | ||
865 | |||
866 | #define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \ | ||
867 | SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \ | ||
868 | SST_SSP_MUX_ENUM(xreg, xshift, xtexts)) | ||
869 | |||
442 | #endif | 870 | #endif |
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c index fc588764ffa3..5a9e56700f31 100644 --- a/sound/soc/intel/sst-baytrail-dsp.c +++ b/sound/soc/intel/sst-baytrail-dsp.c | |||
@@ -67,17 +67,12 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
67 | { | 67 | { |
68 | struct dma_block_info *block; | 68 | struct dma_block_info *block; |
69 | struct sst_module *mod; | 69 | struct sst_module *mod; |
70 | struct sst_module_data block_data; | ||
71 | struct sst_module_template template; | 70 | struct sst_module_template template; |
72 | int count; | 71 | int count; |
73 | 72 | ||
74 | memset(&template, 0, sizeof(template)); | 73 | memset(&template, 0, sizeof(template)); |
75 | template.id = module->type; | 74 | template.id = module->type; |
76 | template.entry = module->entry_point; | 75 | 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 | 76 | ||
82 | mod = sst_module_new(fw, &template, NULL); | 77 | mod = sst_module_new(fw, &template, NULL); |
83 | if (mod == NULL) | 78 | if (mod == NULL) |
@@ -94,19 +89,19 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
94 | 89 | ||
95 | switch (block->type) { | 90 | switch (block->type) { |
96 | case SST_BYT_IRAM: | 91 | case SST_BYT_IRAM: |
97 | block_data.offset = block->ram_offset + | 92 | mod->offset = block->ram_offset + |
98 | dsp->addr.iram_offset; | 93 | dsp->addr.iram_offset; |
99 | block_data.type = SST_MEM_IRAM; | 94 | mod->type = SST_MEM_IRAM; |
100 | break; | 95 | break; |
101 | case SST_BYT_DRAM: | 96 | case SST_BYT_DRAM: |
102 | block_data.offset = block->ram_offset + | 97 | mod->offset = block->ram_offset + |
103 | dsp->addr.dram_offset; | 98 | dsp->addr.dram_offset; |
104 | block_data.type = SST_MEM_DRAM; | 99 | mod->type = SST_MEM_DRAM; |
105 | break; | 100 | break; |
106 | case SST_BYT_CACHE: | 101 | case SST_BYT_CACHE: |
107 | block_data.offset = block->ram_offset + | 102 | mod->offset = block->ram_offset + |
108 | (dsp->addr.fw_ext - dsp->addr.lpe); | 103 | (dsp->addr.fw_ext - dsp->addr.lpe); |
109 | block_data.type = SST_MEM_CACHE; | 104 | mod->type = SST_MEM_CACHE; |
110 | break; | 105 | break; |
111 | default: | 106 | default: |
112 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", | 107 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", |
@@ -114,11 +109,10 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
114 | return -EINVAL; | 109 | return -EINVAL; |
115 | } | 110 | } |
116 | 111 | ||
117 | block_data.size = block->size; | 112 | mod->size = block->size; |
118 | block_data.data_type = SST_DATA_M; | 113 | mod->data = (void *)block + sizeof(*block); |
119 | block_data.data = (void *)block + sizeof(*block); | ||
120 | 114 | ||
121 | sst_module_insert_fixed_block(mod, &block_data); | 115 | sst_module_alloc_blocks(mod); |
122 | 116 | ||
123 | block = (void *)block + sizeof(*block) + block->size; | 117 | block = (void *)block + sizeof(*block) + block->size; |
124 | } | 118 | } |
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h index ffb308bd81ce..b9da030e312d 100644 --- a/sound/soc/intel/sst-dsp-priv.h +++ b/sound/soc/intel/sst-dsp-priv.h | |||
@@ -26,6 +26,9 @@ struct sst_mem_block; | |||
26 | struct sst_module; | 26 | struct sst_module; |
27 | struct sst_fw; | 27 | struct sst_fw; |
28 | 28 | ||
29 | /* do we need to remove or keep */ | ||
30 | #define DSP_DRAM_ADDR_OFFSET 0x400000 | ||
31 | |||
29 | /* | 32 | /* |
30 | * DSP Operations exported by platform Audio DSP driver. | 33 | * DSP Operations exported by platform Audio DSP driver. |
31 | */ | 34 | */ |
@@ -33,6 +36,9 @@ struct sst_ops { | |||
33 | /* DSP core boot / reset */ | 36 | /* DSP core boot / reset */ |
34 | void (*boot)(struct sst_dsp *); | 37 | void (*boot)(struct sst_dsp *); |
35 | void (*reset)(struct sst_dsp *); | 38 | void (*reset)(struct sst_dsp *); |
39 | int (*wake)(struct sst_dsp *); | ||
40 | void (*sleep)(struct sst_dsp *); | ||
41 | void (*stall)(struct sst_dsp *); | ||
36 | 42 | ||
37 | /* Shim IO */ | 43 | /* Shim IO */ |
38 | void (*write)(void __iomem *addr, u32 offset, u32 value); | 44 | void (*write)(void __iomem *addr, u32 offset, u32 value); |
@@ -67,6 +73,8 @@ struct sst_addr { | |||
67 | u32 shim_offset; | 73 | u32 shim_offset; |
68 | u32 iram_offset; | 74 | u32 iram_offset; |
69 | u32 dram_offset; | 75 | u32 dram_offset; |
76 | u32 dsp_iram_offset; | ||
77 | u32 dsp_dram_offset; | ||
70 | void __iomem *lpe; | 78 | void __iomem *lpe; |
71 | void __iomem *shim; | 79 | void __iomem *shim; |
72 | void __iomem *pci_cfg; | 80 | void __iomem *pci_cfg; |
@@ -84,15 +92,6 @@ struct sst_mailbox { | |||
84 | }; | 92 | }; |
85 | 93 | ||
86 | /* | 94 | /* |
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. | 95 | * Audio DSP memory block types. |
97 | */ | 96 | */ |
98 | enum sst_mem_type { | 97 | enum sst_mem_type { |
@@ -125,23 +124,6 @@ struct sst_fw { | |||
125 | }; | 124 | }; |
126 | 125 | ||
127 | /* | 126 | /* |
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 | int32_t 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. | 127 | * Audio DSP Generic Module Template. |
146 | * | 128 | * |
147 | * Used to define and register a new FW module. This data is extracted from | 129 | * Used to define and register a new FW module. This data is extracted from |
@@ -150,15 +132,52 @@ struct sst_module_data { | |||
150 | struct sst_module_template { | 132 | struct sst_module_template { |
151 | u32 id; | 133 | u32 id; |
152 | u32 entry; /* entry point */ | 134 | u32 entry; /* entry point */ |
153 | struct sst_module_data s; /* scratch data */ | 135 | u32 scratch_size; |
154 | struct sst_module_data p; /* peristant data */ | 136 | u32 persistent_size; |
137 | }; | ||
138 | |||
139 | /* | ||
140 | * Block Allocator - Used to allocate blocks of DSP memory. | ||
141 | */ | ||
142 | struct sst_block_allocator { | ||
143 | u32 id; | ||
144 | u32 offset; | ||
145 | int size; | ||
146 | enum sst_mem_type type; | ||
147 | }; | ||
148 | |||
149 | /* | ||
150 | * Runtime Module Instance - A module object can be instanciated multiple | ||
151 | * times within the DSP FW. | ||
152 | */ | ||
153 | struct sst_module_runtime { | ||
154 | struct sst_dsp *dsp; | ||
155 | int id; | ||
156 | struct sst_module *module; /* parent module we belong too */ | ||
157 | |||
158 | u32 persistent_offset; /* private memory offset */ | ||
159 | void *private; | ||
160 | |||
161 | struct list_head list; | ||
162 | struct list_head block_list; /* list of blocks used */ | ||
163 | }; | ||
164 | |||
165 | /* | ||
166 | * Runtime Module Context - The runtime context must be manually stored by the | ||
167 | * driver prior to enter S3 and restored after leaving S3. This should really be | ||
168 | * part of the memory context saved by the enter D3 message IPC ??? | ||
169 | */ | ||
170 | struct sst_module_runtime_context { | ||
171 | dma_addr_t dma_buffer; | ||
172 | u32 *buffer; | ||
155 | }; | 173 | }; |
156 | 174 | ||
157 | /* | 175 | /* |
158 | * Audio DSP Generic Module. | 176 | * Audio DSP Generic Module. |
159 | * | 177 | * |
160 | * Each Firmware file can consist of 1..N modules. A module can span multiple | 178 | * 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. | 179 | * ADSP memory blocks. The simplest FW will be a file with 1 module. A module |
180 | * can be instanciated multiple times in the DSP. | ||
162 | */ | 181 | */ |
163 | struct sst_module { | 182 | struct sst_module { |
164 | struct sst_dsp *dsp; | 183 | struct sst_dsp *dsp; |
@@ -167,10 +186,13 @@ struct sst_module { | |||
167 | /* module configuration */ | 186 | /* module configuration */ |
168 | u32 id; | 187 | u32 id; |
169 | u32 entry; /* module entry point */ | 188 | u32 entry; /* module entry point */ |
170 | u32 offset; /* module offset in firmware file */ | 189 | s32 offset; /* module offset in firmware file */ |
171 | u32 size; /* module size */ | 190 | u32 size; /* module size */ |
172 | struct sst_module_data s; /* scratch data */ | 191 | u32 scratch_size; /* global scratch memory required */ |
173 | struct sst_module_data p; /* peristant data */ | 192 | u32 persistent_size; /* private memory required */ |
193 | enum sst_mem_type type; /* destination memory type */ | ||
194 | u32 data_offset; /* offset in ADSP memory space */ | ||
195 | void *data; /* module data */ | ||
174 | 196 | ||
175 | /* runtime */ | 197 | /* runtime */ |
176 | u32 usage_count; /* can be unloaded if count == 0 */ | 198 | u32 usage_count; /* can be unloaded if count == 0 */ |
@@ -180,6 +202,7 @@ struct sst_module { | |||
180 | struct list_head block_list; /* Module list of blocks in use */ | 202 | struct list_head block_list; /* Module list of blocks in use */ |
181 | struct list_head list; /* DSP list of modules */ | 203 | struct list_head list; /* DSP list of modules */ |
182 | struct list_head list_fw; /* FW list of modules */ | 204 | struct list_head list_fw; /* FW list of modules */ |
205 | struct list_head runtime_list; /* list of runtime module objects*/ | ||
183 | }; | 206 | }; |
184 | 207 | ||
185 | /* | 208 | /* |
@@ -208,7 +231,6 @@ struct sst_mem_block { | |||
208 | struct sst_block_ops *ops; /* block operations, if any */ | 231 | struct sst_block_ops *ops; /* block operations, if any */ |
209 | 232 | ||
210 | /* block status */ | 233 | /* block status */ |
211 | enum sst_data_type data_type; /* data type held in this block */ | ||
212 | u32 bytes_used; /* bytes in use by modules */ | 234 | u32 bytes_used; /* bytes in use by modules */ |
213 | void *private; /* generic core does not touch this */ | 235 | void *private; /* generic core does not touch this */ |
214 | int users; /* number of modules using this block */ | 236 | int users; /* number of modules using this block */ |
@@ -253,6 +275,11 @@ struct sst_dsp { | |||
253 | struct list_head module_list; | 275 | struct list_head module_list; |
254 | struct list_head fw_list; | 276 | struct list_head fw_list; |
255 | 277 | ||
278 | /* scratch buffer */ | ||
279 | struct list_head scratch_block_list; | ||
280 | u32 scratch_offset; | ||
281 | u32 scratch_size; | ||
282 | |||
256 | /* platform data */ | 283 | /* platform data */ |
257 | struct sst_pdata *pdata; | 284 | struct sst_pdata *pdata; |
258 | 285 | ||
@@ -290,18 +317,33 @@ void sst_fw_unload(struct sst_fw *sst_fw); | |||
290 | /* Create/Free firmware modules */ | 317 | /* Create/Free firmware modules */ |
291 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | 318 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, |
292 | struct sst_module_template *template, void *private); | 319 | struct sst_module_template *template, void *private); |
293 | void sst_module_free(struct sst_module *sst_module); | 320 | void sst_module_free(struct sst_module *module); |
294 | int sst_module_insert(struct sst_module *sst_module); | ||
295 | int sst_module_remove(struct sst_module *sst_module); | ||
296 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
297 | struct sst_module_data *data); | ||
298 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); | 321 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); |
299 | 322 | int sst_module_alloc_blocks(struct sst_module *module); | |
300 | /* allocate/free pesistent/scratch memory regions managed by drv */ | 323 | int sst_module_free_blocks(struct sst_module *module); |
301 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp); | 324 | |
302 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | 325 | /* Create/Free firmware module runtime instances */ |
303 | struct sst_module *scratch); | 326 | struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module, |
304 | int sst_block_module_remove(struct sst_module *module); | 327 | int id, void *private); |
328 | void sst_module_runtime_free(struct sst_module_runtime *runtime); | ||
329 | struct sst_module_runtime *sst_module_runtime_get_from_id( | ||
330 | struct sst_module *module, u32 id); | ||
331 | int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, | ||
332 | int offset); | ||
333 | int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime); | ||
334 | int sst_module_runtime_save(struct sst_module_runtime *runtime, | ||
335 | struct sst_module_runtime_context *context); | ||
336 | int sst_module_runtime_restore(struct sst_module_runtime *runtime, | ||
337 | struct sst_module_runtime_context *context); | ||
338 | |||
339 | /* generic block allocation */ | ||
340 | int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba, | ||
341 | struct list_head *block_list); | ||
342 | int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list); | ||
343 | |||
344 | /* scratch allocation */ | ||
345 | int sst_block_alloc_scratch(struct sst_dsp *dsp); | ||
346 | void sst_block_free_scratch(struct sst_dsp *dsp); | ||
305 | 347 | ||
306 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ | 348 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ |
307 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | 349 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, |
@@ -309,4 +351,10 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | |||
309 | void *private); | 351 | void *private); |
310 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); | 352 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); |
311 | 353 | ||
354 | /* Create/Free DMA resources */ | ||
355 | int sst_dma_new(struct sst_dsp *sst); | ||
356 | void sst_dma_free(struct sst_dma *dma); | ||
357 | |||
358 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | ||
359 | enum sst_mem_type type); | ||
312 | #endif | 360 | #endif |
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c index cd23060a0d86..86e410845670 100644 --- a/sound/soc/intel/sst-dsp.c +++ b/sound/soc/intel/sst-dsp.c | |||
@@ -245,6 +245,29 @@ int sst_dsp_boot(struct sst_dsp *sst) | |||
245 | } | 245 | } |
246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | 246 | EXPORT_SYMBOL_GPL(sst_dsp_boot); |
247 | 247 | ||
248 | int sst_dsp_wake(struct sst_dsp *sst) | ||
249 | { | ||
250 | if (sst->ops->wake) | ||
251 | return sst->ops->wake(sst); | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | EXPORT_SYMBOL_GPL(sst_dsp_wake); | ||
256 | |||
257 | void sst_dsp_sleep(struct sst_dsp *sst) | ||
258 | { | ||
259 | if (sst->ops->sleep) | ||
260 | sst->ops->sleep(sst); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(sst_dsp_sleep); | ||
263 | |||
264 | void sst_dsp_stall(struct sst_dsp *sst) | ||
265 | { | ||
266 | if (sst->ops->stall) | ||
267 | sst->ops->stall(sst); | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(sst_dsp_stall); | ||
270 | |||
248 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) | 271 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) |
249 | { | 272 | { |
250 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); | 273 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); |
@@ -352,6 +375,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev, | |||
352 | INIT_LIST_HEAD(&sst->free_block_list); | 375 | INIT_LIST_HEAD(&sst->free_block_list); |
353 | INIT_LIST_HEAD(&sst->module_list); | 376 | INIT_LIST_HEAD(&sst->module_list); |
354 | INIT_LIST_HEAD(&sst->fw_list); | 377 | INIT_LIST_HEAD(&sst->fw_list); |
378 | INIT_LIST_HEAD(&sst->scratch_block_list); | ||
355 | 379 | ||
356 | /* Initialise SST Audio DSP */ | 380 | /* Initialise SST Audio DSP */ |
357 | if (sst->ops->init) { | 381 | if (sst->ops->init) { |
@@ -366,6 +390,10 @@ struct sst_dsp *sst_dsp_new(struct device *dev, | |||
366 | if (err) | 390 | if (err) |
367 | goto irq_err; | 391 | goto irq_err; |
368 | 392 | ||
393 | err = sst_dma_new(sst); | ||
394 | if (err) | ||
395 | dev_warn(dev, "sst_dma_new failed %d\n", err); | ||
396 | |||
369 | return sst; | 397 | return sst; |
370 | 398 | ||
371 | irq_err: | 399 | irq_err: |
@@ -381,6 +409,9 @@ void sst_dsp_free(struct sst_dsp *sst) | |||
381 | free_irq(sst->irq, sst); | 409 | free_irq(sst->irq, sst); |
382 | if (sst->ops->free) | 410 | if (sst->ops->free) |
383 | sst->ops->free(sst); | 411 | sst->ops->free(sst); |
412 | |||
413 | if (sst->dma) | ||
414 | sst_dma_free(sst->dma); | ||
384 | } | 415 | } |
385 | EXPORT_SYMBOL_GPL(sst_dsp_free); | 416 | EXPORT_SYMBOL_GPL(sst_dsp_free); |
386 | 417 | ||
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h index 3165dfa97408..f291e32f0077 100644 --- a/sound/soc/intel/sst-dsp.h +++ b/sound/soc/intel/sst-dsp.h | |||
@@ -30,6 +30,9 @@ | |||
30 | #define SST_DMA_TYPE_DW 1 | 30 | #define SST_DMA_TYPE_DW 1 |
31 | #define SST_DMA_TYPE_MID 2 | 31 | #define SST_DMA_TYPE_MID 2 |
32 | 32 | ||
33 | /* autosuspend delay 5s*/ | ||
34 | #define SST_RUNTIME_SUSPEND_DELAY (5 * 1000) | ||
35 | |||
33 | /* SST Shim register map | 36 | /* SST Shim register map |
34 | * The register naming can differ between products. Some products also | 37 | * The register naming can differ between products. Some products also |
35 | * contain extra functionality. | 38 | * contain extra functionality. |
@@ -156,12 +159,18 @@ | |||
156 | #define SST_VDRTCTL3 0xaC | 159 | #define SST_VDRTCTL3 0xaC |
157 | 160 | ||
158 | /* VDRTCTL0 */ | 161 | /* VDRTCTL0 */ |
159 | #define SST_VDRTCL0_APLLSE_MASK 1 | 162 | #define SST_VDRTCL0_D3PGD (1 << 0) |
160 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | 163 | #define SST_VDRTCL0_D3SRAMPGD (1 << 1) |
161 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | 164 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 12 |
162 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | 165 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT) |
166 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 2 | ||
163 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | 167 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) |
164 | 168 | ||
169 | /* VDRTCTL2 */ | ||
170 | #define SST_VDRTCL2_DCLCGE (1 << 1) | ||
171 | #define SST_VDRTCL2_DTCGE (1 << 10) | ||
172 | #define SST_VDRTCL2_APLLSE_MASK (1 << 31) | ||
173 | |||
165 | /* PMCS */ | 174 | /* PMCS */ |
166 | #define SST_PMCS 0x84 | 175 | #define SST_PMCS 0x84 |
167 | #define SST_PMCS_PS_MASK 0x3 | 176 | #define SST_PMCS_PS_MASK 0x3 |
@@ -245,6 +254,17 @@ void sst_memcpy_fromio_32(struct sst_dsp *sst, | |||
245 | /* DSP reset & boot */ | 254 | /* DSP reset & boot */ |
246 | void sst_dsp_reset(struct sst_dsp *sst); | 255 | void sst_dsp_reset(struct sst_dsp *sst); |
247 | int sst_dsp_boot(struct sst_dsp *sst); | 256 | int sst_dsp_boot(struct sst_dsp *sst); |
257 | int sst_dsp_wake(struct sst_dsp *sst); | ||
258 | void sst_dsp_sleep(struct sst_dsp *sst); | ||
259 | void sst_dsp_stall(struct sst_dsp *sst); | ||
260 | |||
261 | /* DMA */ | ||
262 | int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id); | ||
263 | void sst_dsp_dma_put_channel(struct sst_dsp *dsp); | ||
264 | int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
265 | dma_addr_t src_addr, size_t size); | ||
266 | int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
267 | dma_addr_t src_addr, size_t size); | ||
248 | 268 | ||
249 | /* Msg IO */ | 269 | /* Msg IO */ |
250 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); | 270 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); |
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c index 3bb43dac892d..4a5bde9c686b 100644 --- a/sound/soc/intel/sst-firmware.c +++ b/sound/soc/intel/sst-firmware.c | |||
@@ -23,6 +23,11 @@ | |||
23 | #include <linux/dma-mapping.h> | 23 | #include <linux/dma-mapping.h> |
24 | #include <linux/dmaengine.h> | 24 | #include <linux/dmaengine.h> |
25 | #include <linux/pci.h> | 25 | #include <linux/pci.h> |
26 | #include <linux/acpi.h> | ||
27 | |||
28 | /* supported DMA engine drivers */ | ||
29 | #include <linux/platform_data/dma-dw.h> | ||
30 | #include <linux/dma/dw.h> | ||
26 | 31 | ||
27 | #include <asm/page.h> | 32 | #include <asm/page.h> |
28 | #include <asm/pgtable.h> | 33 | #include <asm/pgtable.h> |
@@ -30,16 +35,301 @@ | |||
30 | #include "sst-dsp.h" | 35 | #include "sst-dsp.h" |
31 | #include "sst-dsp-priv.h" | 36 | #include "sst-dsp-priv.h" |
32 | 37 | ||
33 | static void block_module_remove(struct sst_module *module); | 38 | #define SST_DMA_RESOURCES 2 |
39 | #define SST_DSP_DMA_MAX_BURST 0x3 | ||
40 | #define SST_HSW_BLOCK_ANY 0xffffffff | ||
41 | |||
42 | #define SST_HSW_MASK_DMA_ADDR_DSP 0xfff00000 | ||
43 | |||
44 | struct sst_dma { | ||
45 | struct sst_dsp *sst; | ||
46 | |||
47 | struct dw_dma_chip *chip; | ||
48 | |||
49 | struct dma_async_tx_descriptor *desc; | ||
50 | struct dma_chan *ch; | ||
51 | }; | ||
52 | |||
53 | static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | ||
54 | { | ||
55 | /* __iowrite32_copy use 32bit size values so divide by 4 */ | ||
56 | __iowrite32_copy((void *)dest, src, bytes/4); | ||
57 | } | ||
58 | |||
59 | static void sst_dma_transfer_complete(void *arg) | ||
60 | { | ||
61 | struct sst_dsp *sst = (struct sst_dsp *)arg; | ||
62 | |||
63 | dev_dbg(sst->dev, "DMA: callback\n"); | ||
64 | } | ||
65 | |||
66 | static int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
67 | dma_addr_t src_addr, size_t size) | ||
68 | { | ||
69 | struct dma_async_tx_descriptor *desc; | ||
70 | struct sst_dma *dma = sst->dma; | ||
71 | |||
72 | if (dma->ch == NULL) { | ||
73 | dev_err(sst->dev, "error: no DMA channel\n"); | ||
74 | return -ENODEV; | ||
75 | } | ||
76 | |||
77 | dev_dbg(sst->dev, "DMA: src: 0x%lx dest 0x%lx size %zu\n", | ||
78 | (unsigned long)src_addr, (unsigned long)dest_addr, size); | ||
79 | |||
80 | desc = dma->ch->device->device_prep_dma_memcpy(dma->ch, dest_addr, | ||
81 | src_addr, size, DMA_CTRL_ACK); | ||
82 | if (!desc){ | ||
83 | dev_err(sst->dev, "error: dma prep memcpy failed\n"); | ||
84 | return -EINVAL; | ||
85 | } | ||
86 | |||
87 | desc->callback = sst_dma_transfer_complete; | ||
88 | desc->callback_param = sst; | ||
89 | |||
90 | desc->tx_submit(desc); | ||
91 | dma_wait_for_async_tx(desc); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | /* copy to DSP */ | ||
97 | int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
98 | dma_addr_t src_addr, size_t size) | ||
99 | { | ||
100 | return sst_dsp_dma_copy(sst, dest_addr | SST_HSW_MASK_DMA_ADDR_DSP, | ||
101 | src_addr, size); | ||
102 | } | ||
103 | EXPORT_SYMBOL_GPL(sst_dsp_dma_copyto); | ||
104 | |||
105 | /* copy from DSP */ | ||
106 | int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr, | ||
107 | dma_addr_t src_addr, size_t size) | ||
108 | { | ||
109 | return sst_dsp_dma_copy(sst, dest_addr, | ||
110 | src_addr | SST_HSW_MASK_DMA_ADDR_DSP, size); | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(sst_dsp_dma_copyfrom); | ||
113 | |||
114 | /* remove module from memory - callers hold locks */ | ||
115 | static void block_list_remove(struct sst_dsp *dsp, | ||
116 | struct list_head *block_list) | ||
117 | { | ||
118 | struct sst_mem_block *block, *tmp; | ||
119 | int err; | ||
120 | |||
121 | /* disable each block */ | ||
122 | list_for_each_entry(block, block_list, module_list) { | ||
123 | |||
124 | if (block->ops && block->ops->disable) { | ||
125 | err = block->ops->disable(block); | ||
126 | if (err < 0) | ||
127 | dev_err(dsp->dev, | ||
128 | "error: cant disable block %d:%d\n", | ||
129 | block->type, block->index); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* mark each block as free */ | ||
134 | list_for_each_entry_safe(block, tmp, block_list, module_list) { | ||
135 | list_del(&block->module_list); | ||
136 | list_move(&block->list, &dsp->free_block_list); | ||
137 | dev_dbg(dsp->dev, "block freed %d:%d at offset 0x%x\n", | ||
138 | block->type, block->index, block->offset); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
143 | static int block_list_prepare(struct sst_dsp *dsp, | ||
144 | struct list_head *block_list) | ||
145 | { | ||
146 | struct sst_mem_block *block; | ||
147 | int ret = 0; | ||
148 | |||
149 | /* enable each block so that's it'e ready for data */ | ||
150 | list_for_each_entry(block, block_list, module_list) { | ||
151 | |||
152 | if (block->ops && block->ops->enable && !block->users) { | ||
153 | ret = block->ops->enable(block); | ||
154 | if (ret < 0) { | ||
155 | dev_err(dsp->dev, | ||
156 | "error: cant disable block %d:%d\n", | ||
157 | block->type, block->index); | ||
158 | goto err; | ||
159 | } | ||
160 | } | ||
161 | } | ||
162 | return ret; | ||
163 | |||
164 | err: | ||
165 | list_for_each_entry(block, block_list, module_list) { | ||
166 | if (block->ops && block->ops->disable) | ||
167 | block->ops->disable(block); | ||
168 | } | ||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static struct dw_dma_platform_data dw_pdata = { | ||
173 | .is_private = 1, | ||
174 | .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, | ||
175 | .chan_priority = CHAN_PRIORITY_ASCENDING, | ||
176 | }; | ||
177 | |||
178 | static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem, | ||
179 | int irq) | ||
180 | { | ||
181 | struct dw_dma_chip *chip; | ||
182 | int err; | ||
183 | |||
184 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | ||
185 | if (!chip) | ||
186 | return ERR_PTR(-ENOMEM); | ||
187 | |||
188 | chip->irq = irq; | ||
189 | chip->regs = devm_ioremap_resource(dev, mem); | ||
190 | if (IS_ERR(chip->regs)) | ||
191 | return ERR_CAST(chip->regs); | ||
192 | |||
193 | err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31)); | ||
194 | if (err) | ||
195 | return ERR_PTR(err); | ||
196 | |||
197 | chip->dev = dev; | ||
198 | err = dw_dma_probe(chip, &dw_pdata); | ||
199 | if (err) | ||
200 | return ERR_PTR(err); | ||
201 | |||
202 | return chip; | ||
203 | } | ||
204 | |||
205 | static void dw_remove(struct dw_dma_chip *chip) | ||
206 | { | ||
207 | dw_dma_remove(chip); | ||
208 | } | ||
209 | |||
210 | static bool dma_chan_filter(struct dma_chan *chan, void *param) | ||
211 | { | ||
212 | struct sst_dsp *dsp = (struct sst_dsp *)param; | ||
213 | |||
214 | return chan->device->dev == dsp->dma_dev; | ||
215 | } | ||
34 | 216 | ||
35 | static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | 217 | int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id) |
36 | { | 218 | { |
37 | u32 i; | 219 | struct sst_dma *dma = dsp->dma; |
220 | struct dma_slave_config slave; | ||
221 | dma_cap_mask_t mask; | ||
222 | int ret; | ||
223 | |||
224 | /* The Intel MID DMA engine driver needs the slave config set but | ||
225 | * Synopsis DMA engine driver safely ignores the slave config */ | ||
226 | dma_cap_zero(mask); | ||
227 | dma_cap_set(DMA_SLAVE, mask); | ||
228 | dma_cap_set(DMA_MEMCPY, mask); | ||
229 | |||
230 | dma->ch = dma_request_channel(mask, dma_chan_filter, dsp); | ||
231 | if (dma->ch == NULL) { | ||
232 | dev_err(dsp->dev, "error: DMA request channel failed\n"); | ||
233 | return -EIO; | ||
234 | } | ||
235 | |||
236 | memset(&slave, 0, sizeof(slave)); | ||
237 | slave.direction = DMA_MEM_TO_DEV; | ||
238 | slave.src_addr_width = | ||
239 | slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
240 | slave.src_maxburst = slave.dst_maxburst = SST_DSP_DMA_MAX_BURST; | ||
241 | |||
242 | ret = dmaengine_slave_config(dma->ch, &slave); | ||
243 | if (ret) { | ||
244 | dev_err(dsp->dev, "error: unable to set DMA slave config %d\n", | ||
245 | ret); | ||
246 | dma_release_channel(dma->ch); | ||
247 | dma->ch = NULL; | ||
248 | } | ||
38 | 249 | ||
39 | /* copy one 32 bit word at a time as 64 bit access is not supported */ | 250 | return ret; |
40 | for (i = 0; i < bytes; i += 4) | ||
41 | memcpy_toio(dest + i, src + i, 4); | ||
42 | } | 251 | } |
252 | EXPORT_SYMBOL_GPL(sst_dsp_dma_get_channel); | ||
253 | |||
254 | void sst_dsp_dma_put_channel(struct sst_dsp *dsp) | ||
255 | { | ||
256 | struct sst_dma *dma = dsp->dma; | ||
257 | |||
258 | if (!dma->ch) | ||
259 | return; | ||
260 | |||
261 | dma_release_channel(dma->ch); | ||
262 | dma->ch = NULL; | ||
263 | } | ||
264 | EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel); | ||
265 | |||
266 | int sst_dma_new(struct sst_dsp *sst) | ||
267 | { | ||
268 | struct sst_pdata *sst_pdata = sst->pdata; | ||
269 | struct sst_dma *dma; | ||
270 | struct resource mem; | ||
271 | const char *dma_dev_name; | ||
272 | int ret = 0; | ||
273 | |||
274 | /* configure the correct platform data for whatever DMA engine | ||
275 | * is attached to the ADSP IP. */ | ||
276 | switch (sst->pdata->dma_engine) { | ||
277 | case SST_DMA_TYPE_DW: | ||
278 | dma_dev_name = "dw_dmac"; | ||
279 | break; | ||
280 | case SST_DMA_TYPE_MID: | ||
281 | dma_dev_name = "Intel MID DMA"; | ||
282 | break; | ||
283 | default: | ||
284 | dev_err(sst->dev, "error: invalid DMA engine %d\n", | ||
285 | sst->pdata->dma_engine); | ||
286 | return -EINVAL; | ||
287 | } | ||
288 | |||
289 | dma = devm_kzalloc(sst->dev, sizeof(struct sst_dma), GFP_KERNEL); | ||
290 | if (!dma) | ||
291 | return -ENOMEM; | ||
292 | |||
293 | dma->sst = sst; | ||
294 | |||
295 | memset(&mem, 0, sizeof(mem)); | ||
296 | |||
297 | mem.start = sst->addr.lpe_base + sst_pdata->dma_base; | ||
298 | mem.end = sst->addr.lpe_base + sst_pdata->dma_base + sst_pdata->dma_size - 1; | ||
299 | mem.flags = IORESOURCE_MEM; | ||
300 | |||
301 | /* now register DMA engine device */ | ||
302 | dma->chip = dw_probe(sst->dma_dev, &mem, sst_pdata->irq); | ||
303 | if (IS_ERR(dma->chip)) { | ||
304 | dev_err(sst->dev, "error: DMA device register failed\n"); | ||
305 | ret = PTR_ERR(dma->chip); | ||
306 | goto err_dma_dev; | ||
307 | } | ||
308 | |||
309 | sst->dma = dma; | ||
310 | sst->fw_use_dma = true; | ||
311 | return 0; | ||
312 | |||
313 | err_dma_dev: | ||
314 | devm_kfree(sst->dev, dma); | ||
315 | return ret; | ||
316 | } | ||
317 | EXPORT_SYMBOL(sst_dma_new); | ||
318 | |||
319 | void sst_dma_free(struct sst_dma *dma) | ||
320 | { | ||
321 | |||
322 | if (dma == NULL) | ||
323 | return; | ||
324 | |||
325 | if (dma->ch) | ||
326 | dma_release_channel(dma->ch); | ||
327 | |||
328 | if (dma->chip) | ||
329 | dw_remove(dma->chip); | ||
330 | |||
331 | } | ||
332 | EXPORT_SYMBOL(sst_dma_free); | ||
43 | 333 | ||
44 | /* create new generic firmware object */ | 334 | /* create new generic firmware object */ |
45 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | 335 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, |
@@ -71,6 +361,12 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
71 | /* copy FW data to DMA-able memory */ | 361 | /* copy FW data to DMA-able memory */ |
72 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); | 362 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); |
73 | 363 | ||
364 | if (dsp->fw_use_dma) { | ||
365 | err = sst_dsp_dma_get_channel(dsp, 0); | ||
366 | if (err < 0) | ||
367 | goto chan_err; | ||
368 | } | ||
369 | |||
74 | /* call core specific FW paser to load FW data into DSP */ | 370 | /* call core specific FW paser to load FW data into DSP */ |
75 | err = dsp->ops->parse_fw(sst_fw); | 371 | err = dsp->ops->parse_fw(sst_fw); |
76 | if (err < 0) { | 372 | if (err < 0) { |
@@ -78,6 +374,9 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
78 | goto parse_err; | 374 | goto parse_err; |
79 | } | 375 | } |
80 | 376 | ||
377 | if (dsp->fw_use_dma) | ||
378 | sst_dsp_dma_put_channel(dsp); | ||
379 | |||
81 | mutex_lock(&dsp->mutex); | 380 | mutex_lock(&dsp->mutex); |
82 | list_add(&sst_fw->list, &dsp->fw_list); | 381 | list_add(&sst_fw->list, &dsp->fw_list); |
83 | mutex_unlock(&dsp->mutex); | 382 | mutex_unlock(&dsp->mutex); |
@@ -85,9 +384,13 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | |||
85 | return sst_fw; | 384 | return sst_fw; |
86 | 385 | ||
87 | parse_err: | 386 | parse_err: |
88 | dma_free_coherent(dsp->dev, sst_fw->size, | 387 | if (dsp->fw_use_dma) |
388 | sst_dsp_dma_put_channel(dsp); | ||
389 | chan_err: | ||
390 | dma_free_coherent(dsp->dma_dev, sst_fw->size, | ||
89 | sst_fw->dma_buf, | 391 | sst_fw->dma_buf, |
90 | sst_fw->dmable_fw_paddr); | 392 | sst_fw->dmable_fw_paddr); |
393 | sst_fw->dma_buf = NULL; | ||
91 | kfree(sst_fw); | 394 | kfree(sst_fw); |
92 | return NULL; | 395 | return NULL; |
93 | } | 396 | } |
@@ -111,21 +414,37 @@ EXPORT_SYMBOL_GPL(sst_fw_reload); | |||
111 | 414 | ||
112 | void sst_fw_unload(struct sst_fw *sst_fw) | 415 | void sst_fw_unload(struct sst_fw *sst_fw) |
113 | { | 416 | { |
114 | struct sst_dsp *dsp = sst_fw->dsp; | 417 | struct sst_dsp *dsp = sst_fw->dsp; |
115 | struct sst_module *module, *tmp; | 418 | struct sst_module *module, *mtmp; |
419 | struct sst_module_runtime *runtime, *rtmp; | ||
420 | |||
421 | dev_dbg(dsp->dev, "unloading firmware\n"); | ||
422 | |||
423 | mutex_lock(&dsp->mutex); | ||
424 | |||
425 | /* check module by module */ | ||
426 | list_for_each_entry_safe(module, mtmp, &dsp->module_list, list) { | ||
427 | if (module->sst_fw == sst_fw) { | ||
428 | |||
429 | /* remove runtime modules */ | ||
430 | list_for_each_entry_safe(runtime, rtmp, &module->runtime_list, list) { | ||
116 | 431 | ||
117 | dev_dbg(dsp->dev, "unloading firmware\n"); | 432 | block_list_remove(dsp, &runtime->block_list); |
433 | list_del(&runtime->list); | ||
434 | kfree(runtime); | ||
435 | } | ||
436 | |||
437 | /* now remove the module */ | ||
438 | block_list_remove(dsp, &module->block_list); | ||
439 | list_del(&module->list); | ||
440 | kfree(module); | ||
441 | } | ||
442 | } | ||
118 | 443 | ||
119 | mutex_lock(&dsp->mutex); | 444 | /* remove all scratch blocks */ |
120 | list_for_each_entry_safe(module, tmp, &dsp->module_list, list) { | 445 | block_list_remove(dsp, &dsp->scratch_block_list); |
121 | if (module->sst_fw == sst_fw) { | ||
122 | block_module_remove(module); | ||
123 | list_del(&module->list); | ||
124 | kfree(module); | ||
125 | } | ||
126 | } | ||
127 | 446 | ||
128 | mutex_unlock(&dsp->mutex); | 447 | mutex_unlock(&dsp->mutex); |
129 | } | 448 | } |
130 | EXPORT_SYMBOL_GPL(sst_fw_unload); | 449 | EXPORT_SYMBOL_GPL(sst_fw_unload); |
131 | 450 | ||
@@ -138,7 +457,8 @@ void sst_fw_free(struct sst_fw *sst_fw) | |||
138 | list_del(&sst_fw->list); | 457 | list_del(&sst_fw->list); |
139 | mutex_unlock(&dsp->mutex); | 458 | mutex_unlock(&dsp->mutex); |
140 | 459 | ||
141 | dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, | 460 | if (sst_fw->dma_buf) |
461 | dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf, | ||
142 | sst_fw->dmable_fw_paddr); | 462 | sst_fw->dmable_fw_paddr); |
143 | kfree(sst_fw); | 463 | kfree(sst_fw); |
144 | } | 464 | } |
@@ -175,11 +495,11 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw, | |||
175 | sst_module->id = template->id; | 495 | sst_module->id = template->id; |
176 | sst_module->dsp = dsp; | 496 | sst_module->dsp = dsp; |
177 | sst_module->sst_fw = sst_fw; | 497 | sst_module->sst_fw = sst_fw; |
178 | 498 | sst_module->scratch_size = template->scratch_size; | |
179 | memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data)); | 499 | sst_module->persistent_size = template->persistent_size; |
180 | memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data)); | ||
181 | 500 | ||
182 | INIT_LIST_HEAD(&sst_module->block_list); | 501 | INIT_LIST_HEAD(&sst_module->block_list); |
502 | INIT_LIST_HEAD(&sst_module->runtime_list); | ||
183 | 503 | ||
184 | mutex_lock(&dsp->mutex); | 504 | mutex_lock(&dsp->mutex); |
185 | list_add(&sst_module->list, &dsp->module_list); | 505 | list_add(&sst_module->list, &dsp->module_list); |
@@ -202,73 +522,122 @@ void sst_module_free(struct sst_module *sst_module) | |||
202 | } | 522 | } |
203 | EXPORT_SYMBOL_GPL(sst_module_free); | 523 | EXPORT_SYMBOL_GPL(sst_module_free); |
204 | 524 | ||
205 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type, | 525 | struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module, |
206 | u32 offset) | 526 | int id, void *private) |
527 | { | ||
528 | struct sst_dsp *dsp = module->dsp; | ||
529 | struct sst_module_runtime *runtime; | ||
530 | |||
531 | runtime = kzalloc(sizeof(*runtime), GFP_KERNEL); | ||
532 | if (runtime == NULL) | ||
533 | return NULL; | ||
534 | |||
535 | runtime->id = id; | ||
536 | runtime->dsp = dsp; | ||
537 | runtime->module = module; | ||
538 | INIT_LIST_HEAD(&runtime->block_list); | ||
539 | |||
540 | mutex_lock(&dsp->mutex); | ||
541 | list_add(&runtime->list, &module->runtime_list); | ||
542 | mutex_unlock(&dsp->mutex); | ||
543 | |||
544 | return runtime; | ||
545 | } | ||
546 | EXPORT_SYMBOL_GPL(sst_module_runtime_new); | ||
547 | |||
548 | void sst_module_runtime_free(struct sst_module_runtime *runtime) | ||
549 | { | ||
550 | struct sst_dsp *dsp = runtime->dsp; | ||
551 | |||
552 | mutex_lock(&dsp->mutex); | ||
553 | list_del(&runtime->list); | ||
554 | mutex_unlock(&dsp->mutex); | ||
555 | |||
556 | kfree(runtime); | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(sst_module_runtime_free); | ||
559 | |||
560 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, | ||
561 | struct sst_block_allocator *ba) | ||
207 | { | 562 | { |
208 | struct sst_mem_block *block; | 563 | struct sst_mem_block *block; |
209 | 564 | ||
210 | list_for_each_entry(block, &dsp->free_block_list, list) { | 565 | list_for_each_entry(block, &dsp->free_block_list, list) { |
211 | if (block->type == type && block->offset == offset) | 566 | if (block->type == ba->type && block->offset == ba->offset) |
212 | return block; | 567 | return block; |
213 | } | 568 | } |
214 | 569 | ||
215 | return NULL; | 570 | return NULL; |
216 | } | 571 | } |
217 | 572 | ||
218 | static int block_alloc_contiguous(struct sst_module *module, | 573 | /* Block allocator must be on block boundary */ |
219 | struct sst_module_data *data, u32 offset, int size) | 574 | static int block_alloc_contiguous(struct sst_dsp *dsp, |
575 | struct sst_block_allocator *ba, struct list_head *block_list) | ||
220 | { | 576 | { |
221 | struct list_head tmp = LIST_HEAD_INIT(tmp); | 577 | struct list_head tmp = LIST_HEAD_INIT(tmp); |
222 | struct sst_dsp *dsp = module->dsp; | ||
223 | struct sst_mem_block *block; | 578 | struct sst_mem_block *block; |
579 | u32 block_start = SST_HSW_BLOCK_ANY; | ||
580 | int size = ba->size, offset = ba->offset; | ||
581 | |||
582 | while (ba->size > 0) { | ||
224 | 583 | ||
225 | while (size > 0) { | 584 | block = find_block(dsp, ba); |
226 | block = find_block(dsp, data->type, offset); | ||
227 | if (!block) { | 585 | if (!block) { |
228 | list_splice(&tmp, &dsp->free_block_list); | 586 | list_splice(&tmp, &dsp->free_block_list); |
587 | |||
588 | ba->size = size; | ||
589 | ba->offset = offset; | ||
229 | return -ENOMEM; | 590 | return -ENOMEM; |
230 | } | 591 | } |
231 | 592 | ||
232 | list_move_tail(&block->list, &tmp); | 593 | list_move_tail(&block->list, &tmp); |
233 | offset += block->size; | 594 | ba->offset += block->size; |
234 | size -= block->size; | 595 | ba->size -= block->size; |
235 | } | 596 | } |
597 | ba->size = size; | ||
598 | ba->offset = offset; | ||
599 | |||
600 | list_for_each_entry(block, &tmp, list) { | ||
601 | |||
602 | if (block->offset < block_start) | ||
603 | block_start = block->offset; | ||
236 | 604 | ||
237 | list_for_each_entry(block, &tmp, list) | 605 | list_add(&block->module_list, block_list); |
238 | list_add(&block->module_list, &module->block_list); | 606 | |
607 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", | ||
608 | block->type, block->index, block->offset); | ||
609 | } | ||
239 | 610 | ||
240 | list_splice(&tmp, &dsp->used_block_list); | 611 | list_splice(&tmp, &dsp->used_block_list); |
241 | return 0; | 612 | return 0; |
242 | } | 613 | } |
243 | 614 | ||
244 | /* allocate free DSP blocks for module data - callers hold locks */ | 615 | /* allocate first free DSP blocks for data - callers hold locks */ |
245 | static int block_alloc(struct sst_module *module, | 616 | static int block_alloc(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
246 | struct sst_module_data *data) | 617 | struct list_head *block_list) |
247 | { | 618 | { |
248 | struct sst_dsp *dsp = module->dsp; | ||
249 | struct sst_mem_block *block, *tmp; | 619 | struct sst_mem_block *block, *tmp; |
250 | int ret = 0; | 620 | int ret = 0; |
251 | 621 | ||
252 | if (data->size == 0) | 622 | if (ba->size == 0) |
253 | return 0; | 623 | return 0; |
254 | 624 | ||
255 | /* find first free whole blocks that can hold module */ | 625 | /* find first free whole blocks that can hold module */ |
256 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 626 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
257 | 627 | ||
258 | /* ignore blocks with wrong type */ | 628 | /* ignore blocks with wrong type */ |
259 | if (block->type != data->type) | 629 | if (block->type != ba->type) |
260 | continue; | 630 | continue; |
261 | 631 | ||
262 | if (data->size > block->size) | 632 | if (ba->size > block->size) |
263 | continue; | 633 | continue; |
264 | 634 | ||
265 | data->offset = block->offset; | 635 | ba->offset = block->offset; |
266 | block->data_type = data->data_type; | 636 | block->bytes_used = ba->size % block->size; |
267 | block->bytes_used = data->size % block->size; | 637 | list_add(&block->module_list, block_list); |
268 | list_add(&block->module_list, &module->block_list); | ||
269 | list_move(&block->list, &dsp->used_block_list); | 638 | list_move(&block->list, &dsp->used_block_list); |
270 | dev_dbg(dsp->dev, " *module %d added block %d:%d\n", | 639 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", |
271 | module->id, block->type, block->index); | 640 | block->type, block->index, block->offset); |
272 | return 0; | 641 | return 0; |
273 | } | 642 | } |
274 | 643 | ||
@@ -276,15 +645,19 @@ static int block_alloc(struct sst_module *module, | |||
276 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 645 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
277 | 646 | ||
278 | /* ignore blocks with wrong type */ | 647 | /* ignore blocks with wrong type */ |
279 | if (block->type != data->type) | 648 | if (block->type != ba->type) |
280 | continue; | 649 | continue; |
281 | 650 | ||
282 | /* do we span > 1 blocks */ | 651 | /* do we span > 1 blocks */ |
283 | if (data->size > block->size) { | 652 | if (ba->size > block->size) { |
284 | ret = block_alloc_contiguous(module, data, | 653 | |
285 | block->offset, data->size); | 654 | /* align ba to block boundary */ |
655 | ba->offset = block->offset; | ||
656 | |||
657 | ret = block_alloc_contiguous(dsp, ba, block_list); | ||
286 | if (ret == 0) | 658 | if (ret == 0) |
287 | return ret; | 659 | return ret; |
660 | |||
288 | } | 661 | } |
289 | } | 662 | } |
290 | 663 | ||
@@ -292,93 +665,74 @@ static int block_alloc(struct sst_module *module, | |||
292 | return -ENOMEM; | 665 | return -ENOMEM; |
293 | } | 666 | } |
294 | 667 | ||
295 | /* remove module from memory - callers hold locks */ | 668 | int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
296 | static void block_module_remove(struct sst_module *module) | 669 | struct list_head *block_list) |
297 | { | 670 | { |
298 | struct sst_mem_block *block, *tmp; | 671 | int ret; |
299 | struct sst_dsp *dsp = module->dsp; | ||
300 | int err; | ||
301 | 672 | ||
302 | /* disable each block */ | 673 | dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n", |
303 | list_for_each_entry(block, &module->block_list, module_list) { | 674 | ba->size, ba->offset, ba->type); |
304 | 675 | ||
305 | if (block->ops && block->ops->disable) { | 676 | mutex_lock(&dsp->mutex); |
306 | err = block->ops->disable(block); | ||
307 | if (err < 0) | ||
308 | dev_err(dsp->dev, | ||
309 | "error: cant disable block %d:%d\n", | ||
310 | block->type, block->index); | ||
311 | } | ||
312 | } | ||
313 | 677 | ||
314 | /* mark each block as free */ | 678 | ret = block_alloc(dsp, ba, block_list); |
315 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | 679 | if (ret < 0) { |
316 | list_del(&block->module_list); | 680 | dev_err(dsp->dev, "error: can't alloc blocks %d\n", ret); |
317 | list_move(&block->list, &dsp->free_block_list); | 681 | goto out; |
318 | } | 682 | } |
319 | } | ||
320 | |||
321 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
322 | static int block_module_prepare(struct sst_module *module) | ||
323 | { | ||
324 | struct sst_mem_block *block; | ||
325 | int ret = 0; | ||
326 | 683 | ||
327 | /* enable each block so that's it'e ready for module P/S data */ | 684 | /* prepare DSP blocks for module usage */ |
328 | list_for_each_entry(block, &module->block_list, module_list) { | 685 | ret = block_list_prepare(dsp, block_list); |
686 | if (ret < 0) | ||
687 | dev_err(dsp->dev, "error: prepare failed\n"); | ||
329 | 688 | ||
330 | if (block->ops && block->ops->enable) { | 689 | out: |
331 | ret = block->ops->enable(block); | 690 | mutex_unlock(&dsp->mutex); |
332 | if (ret < 0) { | ||
333 | dev_err(module->dsp->dev, | ||
334 | "error: cant disable block %d:%d\n", | ||
335 | block->type, block->index); | ||
336 | goto err; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | return ret; | 691 | return ret; |
692 | } | ||
693 | EXPORT_SYMBOL_GPL(sst_alloc_blocks); | ||
341 | 694 | ||
342 | err: | 695 | int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list) |
343 | list_for_each_entry(block, &module->block_list, module_list) { | 696 | { |
344 | if (block->ops && block->ops->disable) | 697 | mutex_lock(&dsp->mutex); |
345 | block->ops->disable(block); | 698 | block_list_remove(dsp, block_list); |
346 | } | 699 | mutex_unlock(&dsp->mutex); |
347 | return ret; | 700 | return 0; |
348 | } | 701 | } |
702 | EXPORT_SYMBOL_GPL(sst_free_blocks); | ||
349 | 703 | ||
350 | /* allocate memory blocks for static module addresses - callers hold locks */ | 704 | /* allocate memory blocks for static module addresses - callers hold locks */ |
351 | static int block_alloc_fixed(struct sst_module *module, | 705 | static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba, |
352 | struct sst_module_data *data) | 706 | struct list_head *block_list) |
353 | { | 707 | { |
354 | struct sst_dsp *dsp = module->dsp; | ||
355 | struct sst_mem_block *block, *tmp; | 708 | struct sst_mem_block *block, *tmp; |
356 | u32 end = data->offset + data->size, block_end; | 709 | u32 end = ba->offset + ba->size, block_end; |
357 | int err; | 710 | int err; |
358 | 711 | ||
359 | /* only IRAM/DRAM blocks are managed */ | 712 | /* only IRAM/DRAM blocks are managed */ |
360 | if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM) | 713 | if (ba->type != SST_MEM_IRAM && ba->type != SST_MEM_DRAM) |
361 | return 0; | 714 | return 0; |
362 | 715 | ||
363 | /* are blocks already attached to this module */ | 716 | /* are blocks already attached to this module */ |
364 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | 717 | list_for_each_entry_safe(block, tmp, block_list, module_list) { |
365 | 718 | ||
366 | /* force compacting mem blocks of the same data_type */ | 719 | /* ignore blocks with wrong type */ |
367 | if (block->data_type != data->data_type) | 720 | if (block->type != ba->type) |
368 | continue; | 721 | continue; |
369 | 722 | ||
370 | block_end = block->offset + block->size; | 723 | block_end = block->offset + block->size; |
371 | 724 | ||
372 | /* find block that holds section */ | 725 | /* find block that holds section */ |
373 | if (data->offset >= block->offset && end < block_end) | 726 | if (ba->offset >= block->offset && end <= block_end) |
374 | return 0; | 727 | return 0; |
375 | 728 | ||
376 | /* does block span more than 1 section */ | 729 | /* does block span more than 1 section */ |
377 | if (data->offset >= block->offset && data->offset < block_end) { | 730 | if (ba->offset >= block->offset && ba->offset < block_end) { |
378 | 731 | ||
379 | err = block_alloc_contiguous(module, data, | 732 | /* align ba to block boundary */ |
380 | block->offset + block->size, | 733 | ba->size -= block_end - ba->offset; |
381 | data->size - block->size); | 734 | ba->offset = block_end; |
735 | err = block_alloc_contiguous(dsp, ba, block_list); | ||
382 | if (err < 0) | 736 | if (err < 0) |
383 | return -ENOMEM; | 737 | return -ENOMEM; |
384 | 738 | ||
@@ -391,82 +745,270 @@ static int block_alloc_fixed(struct sst_module *module, | |||
391 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | 745 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { |
392 | block_end = block->offset + block->size; | 746 | block_end = block->offset + block->size; |
393 | 747 | ||
748 | /* ignore blocks with wrong type */ | ||
749 | if (block->type != ba->type) | ||
750 | continue; | ||
751 | |||
394 | /* find block that holds section */ | 752 | /* find block that holds section */ |
395 | if (data->offset >= block->offset && end < block_end) { | 753 | if (ba->offset >= block->offset && end <= block_end) { |
396 | 754 | ||
397 | /* add block */ | 755 | /* add block */ |
398 | block->data_type = data->data_type; | ||
399 | list_move(&block->list, &dsp->used_block_list); | 756 | list_move(&block->list, &dsp->used_block_list); |
400 | list_add(&block->module_list, &module->block_list); | 757 | list_add(&block->module_list, block_list); |
758 | dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n", | ||
759 | block->type, block->index, block->offset); | ||
401 | return 0; | 760 | return 0; |
402 | } | 761 | } |
403 | 762 | ||
404 | /* does block span more than 1 section */ | 763 | /* does block span more than 1 section */ |
405 | if (data->offset >= block->offset && data->offset < block_end) { | 764 | if (ba->offset >= block->offset && ba->offset < block_end) { |
406 | 765 | ||
407 | err = block_alloc_contiguous(module, data, | 766 | /* align ba to block boundary */ |
408 | block->offset, data->size); | 767 | ba->offset = block->offset; |
768 | |||
769 | err = block_alloc_contiguous(dsp, ba, block_list); | ||
409 | if (err < 0) | 770 | if (err < 0) |
410 | return -ENOMEM; | 771 | return -ENOMEM; |
411 | 772 | ||
412 | return 0; | 773 | return 0; |
413 | } | 774 | } |
414 | |||
415 | } | 775 | } |
416 | 776 | ||
417 | return -ENOMEM; | 777 | return -ENOMEM; |
418 | } | 778 | } |
419 | 779 | ||
420 | /* Load fixed module data into DSP memory blocks */ | 780 | /* Load fixed module data into DSP memory blocks */ |
421 | int sst_module_insert_fixed_block(struct sst_module *module, | 781 | int sst_module_alloc_blocks(struct sst_module *module) |
422 | struct sst_module_data *data) | ||
423 | { | 782 | { |
424 | struct sst_dsp *dsp = module->dsp; | 783 | struct sst_dsp *dsp = module->dsp; |
784 | struct sst_fw *sst_fw = module->sst_fw; | ||
785 | struct sst_block_allocator ba; | ||
425 | int ret; | 786 | int ret; |
426 | 787 | ||
788 | ba.size = module->size; | ||
789 | ba.type = module->type; | ||
790 | ba.offset = module->offset; | ||
791 | |||
792 | dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n", | ||
793 | ba.size, ba.offset, ba.type); | ||
794 | |||
427 | mutex_lock(&dsp->mutex); | 795 | mutex_lock(&dsp->mutex); |
428 | 796 | ||
429 | /* alloc blocks that includes this section */ | 797 | /* alloc blocks that includes this section */ |
430 | ret = block_alloc_fixed(module, data); | 798 | ret = block_alloc_fixed(dsp, &ba, &module->block_list); |
431 | if (ret < 0) { | 799 | if (ret < 0) { |
432 | dev_err(dsp->dev, | 800 | dev_err(dsp->dev, |
433 | "error: no free blocks for section at offset 0x%x size 0x%x\n", | 801 | "error: no free blocks for section at offset 0x%x size 0x%x\n", |
434 | data->offset, data->size); | 802 | module->offset, module->size); |
435 | mutex_unlock(&dsp->mutex); | 803 | mutex_unlock(&dsp->mutex); |
436 | return -ENOMEM; | 804 | return -ENOMEM; |
437 | } | 805 | } |
438 | 806 | ||
439 | /* prepare DSP blocks for module copy */ | 807 | /* prepare DSP blocks for module copy */ |
440 | ret = block_module_prepare(module); | 808 | ret = block_list_prepare(dsp, &module->block_list); |
441 | if (ret < 0) { | 809 | if (ret < 0) { |
442 | dev_err(dsp->dev, "error: fw module prepare failed\n"); | 810 | dev_err(dsp->dev, "error: fw module prepare failed\n"); |
443 | goto err; | 811 | goto err; |
444 | } | 812 | } |
445 | 813 | ||
446 | /* copy partial module data to blocks */ | 814 | /* copy partial module data to blocks */ |
447 | sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size); | 815 | if (dsp->fw_use_dma) { |
816 | ret = sst_dsp_dma_copyto(dsp, | ||
817 | dsp->addr.lpe_base + module->offset, | ||
818 | sst_fw->dmable_fw_paddr + module->data_offset, | ||
819 | module->size); | ||
820 | if (ret < 0) { | ||
821 | dev_err(dsp->dev, "error: module copy failed\n"); | ||
822 | goto err; | ||
823 | } | ||
824 | } else | ||
825 | sst_memcpy32(dsp->addr.lpe + module->offset, module->data, | ||
826 | module->size); | ||
448 | 827 | ||
449 | mutex_unlock(&dsp->mutex); | 828 | mutex_unlock(&dsp->mutex); |
450 | return ret; | 829 | return ret; |
451 | 830 | ||
452 | err: | 831 | err: |
453 | block_module_remove(module); | 832 | block_list_remove(dsp, &module->block_list); |
454 | mutex_unlock(&dsp->mutex); | 833 | mutex_unlock(&dsp->mutex); |
455 | return ret; | 834 | return ret; |
456 | } | 835 | } |
457 | EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block); | 836 | EXPORT_SYMBOL_GPL(sst_module_alloc_blocks); |
458 | 837 | ||
459 | /* Unload entire module from DSP memory */ | 838 | /* Unload entire module from DSP memory */ |
460 | int sst_block_module_remove(struct sst_module *module) | 839 | int sst_module_free_blocks(struct sst_module *module) |
461 | { | 840 | { |
462 | struct sst_dsp *dsp = module->dsp; | 841 | struct sst_dsp *dsp = module->dsp; |
463 | 842 | ||
464 | mutex_lock(&dsp->mutex); | 843 | mutex_lock(&dsp->mutex); |
465 | block_module_remove(module); | 844 | block_list_remove(dsp, &module->block_list); |
466 | mutex_unlock(&dsp->mutex); | 845 | mutex_unlock(&dsp->mutex); |
467 | return 0; | 846 | return 0; |
468 | } | 847 | } |
469 | EXPORT_SYMBOL_GPL(sst_block_module_remove); | 848 | EXPORT_SYMBOL_GPL(sst_module_free_blocks); |
849 | |||
850 | int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime, | ||
851 | int offset) | ||
852 | { | ||
853 | struct sst_dsp *dsp = runtime->dsp; | ||
854 | struct sst_module *module = runtime->module; | ||
855 | struct sst_block_allocator ba; | ||
856 | int ret; | ||
857 | |||
858 | if (module->persistent_size == 0) | ||
859 | return 0; | ||
860 | |||
861 | ba.size = module->persistent_size; | ||
862 | ba.type = SST_MEM_DRAM; | ||
863 | |||
864 | mutex_lock(&dsp->mutex); | ||
865 | |||
866 | /* do we need to allocate at a fixed address ? */ | ||
867 | if (offset != 0) { | ||
868 | |||
869 | ba.offset = offset; | ||
870 | |||
871 | dev_dbg(dsp->dev, "persistent fixed block request 0x%x bytes type %d offset 0x%x\n", | ||
872 | ba.size, ba.type, ba.offset); | ||
873 | |||
874 | /* alloc blocks that includes this section */ | ||
875 | ret = block_alloc_fixed(dsp, &ba, &runtime->block_list); | ||
876 | |||
877 | } else { | ||
878 | dev_dbg(dsp->dev, "persistent block request 0x%x bytes type %d\n", | ||
879 | ba.size, ba.type); | ||
880 | |||
881 | /* alloc blocks that includes this section */ | ||
882 | ret = block_alloc(dsp, &ba, &runtime->block_list); | ||
883 | } | ||
884 | if (ret < 0) { | ||
885 | dev_err(dsp->dev, | ||
886 | "error: no free blocks for runtime module size 0x%x\n", | ||
887 | module->persistent_size); | ||
888 | mutex_unlock(&dsp->mutex); | ||
889 | return -ENOMEM; | ||
890 | } | ||
891 | runtime->persistent_offset = ba.offset; | ||
892 | |||
893 | /* prepare DSP blocks for module copy */ | ||
894 | ret = block_list_prepare(dsp, &runtime->block_list); | ||
895 | if (ret < 0) { | ||
896 | dev_err(dsp->dev, "error: runtime block prepare failed\n"); | ||
897 | goto err; | ||
898 | } | ||
899 | |||
900 | mutex_unlock(&dsp->mutex); | ||
901 | return ret; | ||
902 | |||
903 | err: | ||
904 | block_list_remove(dsp, &module->block_list); | ||
905 | mutex_unlock(&dsp->mutex); | ||
906 | return ret; | ||
907 | } | ||
908 | EXPORT_SYMBOL_GPL(sst_module_runtime_alloc_blocks); | ||
909 | |||
910 | int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime) | ||
911 | { | ||
912 | struct sst_dsp *dsp = runtime->dsp; | ||
913 | |||
914 | mutex_lock(&dsp->mutex); | ||
915 | block_list_remove(dsp, &runtime->block_list); | ||
916 | mutex_unlock(&dsp->mutex); | ||
917 | return 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL_GPL(sst_module_runtime_free_blocks); | ||
920 | |||
921 | int sst_module_runtime_save(struct sst_module_runtime *runtime, | ||
922 | struct sst_module_runtime_context *context) | ||
923 | { | ||
924 | struct sst_dsp *dsp = runtime->dsp; | ||
925 | struct sst_module *module = runtime->module; | ||
926 | int ret = 0; | ||
927 | |||
928 | dev_dbg(dsp->dev, "saving runtime %d memory at 0x%x size 0x%x\n", | ||
929 | runtime->id, runtime->persistent_offset, | ||
930 | module->persistent_size); | ||
931 | |||
932 | context->buffer = dma_alloc_coherent(dsp->dma_dev, | ||
933 | module->persistent_size, | ||
934 | &context->dma_buffer, GFP_DMA | GFP_KERNEL); | ||
935 | if (!context->buffer) { | ||
936 | dev_err(dsp->dev, "error: DMA context alloc failed\n"); | ||
937 | return -ENOMEM; | ||
938 | } | ||
939 | |||
940 | mutex_lock(&dsp->mutex); | ||
941 | |||
942 | if (dsp->fw_use_dma) { | ||
943 | |||
944 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
945 | if (ret < 0) | ||
946 | goto err; | ||
947 | |||
948 | ret = sst_dsp_dma_copyfrom(dsp, context->dma_buffer, | ||
949 | dsp->addr.lpe_base + runtime->persistent_offset, | ||
950 | module->persistent_size); | ||
951 | sst_dsp_dma_put_channel(dsp); | ||
952 | if (ret < 0) { | ||
953 | dev_err(dsp->dev, "error: context copy failed\n"); | ||
954 | goto err; | ||
955 | } | ||
956 | } else | ||
957 | sst_memcpy32(context->buffer, dsp->addr.lpe + | ||
958 | runtime->persistent_offset, | ||
959 | module->persistent_size); | ||
960 | |||
961 | err: | ||
962 | mutex_unlock(&dsp->mutex); | ||
963 | return ret; | ||
964 | } | ||
965 | EXPORT_SYMBOL_GPL(sst_module_runtime_save); | ||
966 | |||
967 | int sst_module_runtime_restore(struct sst_module_runtime *runtime, | ||
968 | struct sst_module_runtime_context *context) | ||
969 | { | ||
970 | struct sst_dsp *dsp = runtime->dsp; | ||
971 | struct sst_module *module = runtime->module; | ||
972 | int ret = 0; | ||
973 | |||
974 | dev_dbg(dsp->dev, "restoring runtime %d memory at 0x%x size 0x%x\n", | ||
975 | runtime->id, runtime->persistent_offset, | ||
976 | module->persistent_size); | ||
977 | |||
978 | mutex_lock(&dsp->mutex); | ||
979 | |||
980 | if (!context->buffer) { | ||
981 | dev_info(dsp->dev, "no context buffer need to restore!\n"); | ||
982 | goto err; | ||
983 | } | ||
984 | |||
985 | if (dsp->fw_use_dma) { | ||
986 | |||
987 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
988 | if (ret < 0) | ||
989 | goto err; | ||
990 | |||
991 | ret = sst_dsp_dma_copyto(dsp, | ||
992 | dsp->addr.lpe_base + runtime->persistent_offset, | ||
993 | context->dma_buffer, module->persistent_size); | ||
994 | sst_dsp_dma_put_channel(dsp); | ||
995 | if (ret < 0) { | ||
996 | dev_err(dsp->dev, "error: module copy failed\n"); | ||
997 | goto err; | ||
998 | } | ||
999 | } else | ||
1000 | sst_memcpy32(dsp->addr.lpe + runtime->persistent_offset, | ||
1001 | context->buffer, module->persistent_size); | ||
1002 | |||
1003 | dma_free_coherent(dsp->dma_dev, module->persistent_size, | ||
1004 | context->buffer, context->dma_buffer); | ||
1005 | context->buffer = NULL; | ||
1006 | |||
1007 | err: | ||
1008 | mutex_unlock(&dsp->mutex); | ||
1009 | return ret; | ||
1010 | } | ||
1011 | EXPORT_SYMBOL_GPL(sst_module_runtime_restore); | ||
470 | 1012 | ||
471 | /* register a DSP memory block for use with FW based modules */ | 1013 | /* register a DSP memory block for use with FW based modules */ |
472 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | 1014 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, |
@@ -519,80 +1061,84 @@ void sst_mem_block_unregister_all(struct sst_dsp *dsp) | |||
519 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); | 1061 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); |
520 | 1062 | ||
521 | /* allocate scratch buffer blocks */ | 1063 | /* allocate scratch buffer blocks */ |
522 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp) | 1064 | int sst_block_alloc_scratch(struct sst_dsp *dsp) |
523 | { | 1065 | { |
524 | struct sst_module *sst_module, *scratch; | 1066 | struct sst_module *module; |
525 | struct sst_mem_block *block, *tmp; | 1067 | struct sst_block_allocator ba; |
526 | u32 block_size; | 1068 | int ret; |
527 | int ret = 0; | ||
528 | |||
529 | scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL); | ||
530 | if (scratch == NULL) | ||
531 | return NULL; | ||
532 | 1069 | ||
533 | mutex_lock(&dsp->mutex); | 1070 | mutex_lock(&dsp->mutex); |
534 | 1071 | ||
535 | /* calculate required scratch size */ | 1072 | /* calculate required scratch size */ |
536 | list_for_each_entry(sst_module, &dsp->module_list, list) { | 1073 | dsp->scratch_size = 0; |
537 | if (scratch->s.size < sst_module->s.size) | 1074 | list_for_each_entry(module, &dsp->module_list, list) { |
538 | scratch->s.size = sst_module->s.size; | 1075 | dev_dbg(dsp->dev, "module %d scratch req 0x%x bytes\n", |
1076 | module->id, module->scratch_size); | ||
1077 | if (dsp->scratch_size < module->scratch_size) | ||
1078 | dsp->scratch_size = module->scratch_size; | ||
539 | } | 1079 | } |
540 | 1080 | ||
541 | dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n", | 1081 | dev_dbg(dsp->dev, "scratch buffer required is 0x%x bytes\n", |
542 | scratch->s.size); | 1082 | dsp->scratch_size); |
543 | |||
544 | /* init scratch module */ | ||
545 | scratch->dsp = dsp; | ||
546 | scratch->s.type = SST_MEM_DRAM; | ||
547 | scratch->s.data_type = SST_DATA_S; | ||
548 | INIT_LIST_HEAD(&scratch->block_list); | ||
549 | 1083 | ||
550 | /* check free blocks before looking at used blocks for space */ | 1084 | if (dsp->scratch_size == 0) { |
551 | if (!list_empty(&dsp->free_block_list)) | 1085 | dev_info(dsp->dev, "no modules need scratch buffer\n"); |
552 | block = list_first_entry(&dsp->free_block_list, | 1086 | mutex_unlock(&dsp->mutex); |
553 | struct sst_mem_block, list); | 1087 | return 0; |
554 | else | 1088 | } |
555 | block = list_first_entry(&dsp->used_block_list, | ||
556 | struct sst_mem_block, list); | ||
557 | block_size = block->size; | ||
558 | 1089 | ||
559 | /* allocate blocks for module scratch buffers */ | 1090 | /* allocate blocks for module scratch buffers */ |
560 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); | 1091 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); |
561 | ret = block_alloc(scratch, &scratch->s); | 1092 | |
1093 | ba.size = dsp->scratch_size; | ||
1094 | ba.type = SST_MEM_DRAM; | ||
1095 | |||
1096 | /* do we need to allocate at fixed offset */ | ||
1097 | if (dsp->scratch_offset != 0) { | ||
1098 | |||
1099 | dev_dbg(dsp->dev, "block request 0x%x bytes type %d at 0x%x\n", | ||
1100 | ba.size, ba.type, ba.offset); | ||
1101 | |||
1102 | ba.offset = dsp->scratch_offset; | ||
1103 | |||
1104 | /* alloc blocks that includes this section */ | ||
1105 | ret = block_alloc_fixed(dsp, &ba, &dsp->scratch_block_list); | ||
1106 | |||
1107 | } else { | ||
1108 | dev_dbg(dsp->dev, "block request 0x%x bytes type %d\n", | ||
1109 | ba.size, ba.type); | ||
1110 | |||
1111 | ba.offset = 0; | ||
1112 | ret = block_alloc(dsp, &ba, &dsp->scratch_block_list); | ||
1113 | } | ||
562 | if (ret < 0) { | 1114 | if (ret < 0) { |
563 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); | 1115 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); |
564 | goto err; | 1116 | mutex_unlock(&dsp->mutex); |
1117 | return ret; | ||
565 | } | 1118 | } |
566 | 1119 | ||
567 | /* assign the same offset of scratch to each module */ | 1120 | ret = block_list_prepare(dsp, &dsp->scratch_block_list); |
568 | list_for_each_entry(sst_module, &dsp->module_list, list) | 1121 | if (ret < 0) { |
569 | sst_module->s.offset = scratch->s.offset; | 1122 | dev_err(dsp->dev, "error: scratch block prepare failed\n"); |
570 | 1123 | mutex_unlock(&dsp->mutex); | |
571 | mutex_unlock(&dsp->mutex); | 1124 | return ret; |
572 | return scratch; | 1125 | } |
573 | 1126 | ||
574 | err: | 1127 | /* assign the same offset of scratch to each module */ |
575 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | 1128 | dsp->scratch_offset = ba.offset; |
576 | list_del(&block->module_list); | ||
577 | mutex_unlock(&dsp->mutex); | 1129 | mutex_unlock(&dsp->mutex); |
578 | return NULL; | 1130 | return dsp->scratch_size; |
579 | } | 1131 | } |
580 | EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch); | 1132 | EXPORT_SYMBOL_GPL(sst_block_alloc_scratch); |
581 | 1133 | ||
582 | /* free all scratch blocks */ | 1134 | /* free all scratch blocks */ |
583 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | 1135 | void sst_block_free_scratch(struct sst_dsp *dsp) |
584 | struct sst_module *scratch) | ||
585 | { | 1136 | { |
586 | struct sst_mem_block *block, *tmp; | ||
587 | |||
588 | mutex_lock(&dsp->mutex); | 1137 | mutex_lock(&dsp->mutex); |
589 | 1138 | block_list_remove(dsp, &dsp->scratch_block_list); | |
590 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
591 | list_del(&block->module_list); | ||
592 | |||
593 | mutex_unlock(&dsp->mutex); | 1139 | mutex_unlock(&dsp->mutex); |
594 | } | 1140 | } |
595 | EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch); | 1141 | EXPORT_SYMBOL_GPL(sst_block_free_scratch); |
596 | 1142 | ||
597 | /* get a module from it's unique ID */ | 1143 | /* get a module from it's unique ID */ |
598 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | 1144 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) |
@@ -612,3 +1158,40 @@ struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | |||
612 | return NULL; | 1158 | return NULL; |
613 | } | 1159 | } |
614 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); | 1160 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); |
1161 | |||
1162 | struct sst_module_runtime *sst_module_runtime_get_from_id( | ||
1163 | struct sst_module *module, u32 id) | ||
1164 | { | ||
1165 | struct sst_module_runtime *runtime; | ||
1166 | struct sst_dsp *dsp = module->dsp; | ||
1167 | |||
1168 | mutex_lock(&dsp->mutex); | ||
1169 | |||
1170 | list_for_each_entry(runtime, &module->runtime_list, list) { | ||
1171 | if (runtime->id == id) { | ||
1172 | mutex_unlock(&dsp->mutex); | ||
1173 | return runtime; | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | mutex_unlock(&dsp->mutex); | ||
1178 | return NULL; | ||
1179 | } | ||
1180 | EXPORT_SYMBOL_GPL(sst_module_runtime_get_from_id); | ||
1181 | |||
1182 | /* returns block address in DSP address space */ | ||
1183 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | ||
1184 | enum sst_mem_type type) | ||
1185 | { | ||
1186 | switch (type) { | ||
1187 | case SST_MEM_IRAM: | ||
1188 | return offset - dsp->addr.iram_offset + | ||
1189 | dsp->addr.dsp_iram_offset; | ||
1190 | case SST_MEM_DRAM: | ||
1191 | return offset - dsp->addr.dram_offset + | ||
1192 | dsp->addr.dsp_dram_offset; | ||
1193 | default: | ||
1194 | return 0; | ||
1195 | } | ||
1196 | } | ||
1197 | EXPORT_SYMBOL_GPL(sst_dsp_get_offset); | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c index 4b6c163c10ff..57039b00efc2 100644 --- a/sound/soc/intel/sst-haswell-dsp.c +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
@@ -42,6 +42,10 @@ | |||
42 | #define SST_LP_SHIM_OFFSET 0xE7000 | 42 | #define SST_LP_SHIM_OFFSET 0xE7000 |
43 | #define SST_WPT_IRAM_OFFSET 0xA0000 | 43 | #define SST_WPT_IRAM_OFFSET 0xA0000 |
44 | #define SST_LP_IRAM_OFFSET 0x80000 | 44 | #define SST_LP_IRAM_OFFSET 0x80000 |
45 | #define SST_WPT_DSP_DRAM_OFFSET 0x400000 | ||
46 | #define SST_WPT_DSP_IRAM_OFFSET 0x00000 | ||
47 | #define SST_LPT_DSP_DRAM_OFFSET 0x400000 | ||
48 | #define SST_LPT_DSP_IRAM_OFFSET 0x00000 | ||
45 | 49 | ||
46 | #define SST_SHIM_PM_REG 0x84 | 50 | #define SST_SHIM_PM_REG 0x84 |
47 | 51 | ||
@@ -86,9 +90,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
86 | { | 90 | { |
87 | struct dma_block_info *block; | 91 | struct dma_block_info *block; |
88 | struct sst_module *mod; | 92 | struct sst_module *mod; |
89 | struct sst_module_data block_data; | ||
90 | struct sst_module_template template; | 93 | struct sst_module_template template; |
91 | int count; | 94 | int count, ret; |
92 | void __iomem *ram; | 95 | void __iomem *ram; |
93 | 96 | ||
94 | /* TODO: allowed module types need to be configurable */ | 97 | /* TODO: allowed module types need to be configurable */ |
@@ -109,13 +112,9 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
109 | 112 | ||
110 | memset(&template, 0, sizeof(template)); | 113 | memset(&template, 0, sizeof(template)); |
111 | template.id = module->type; | 114 | template.id = module->type; |
112 | template.entry = module->entry_point; | 115 | template.entry = module->entry_point - 4; |
113 | template.p.size = module->info.persistent_size; | 116 | template.persistent_size = module->info.persistent_size; |
114 | template.p.type = SST_MEM_DRAM; | 117 | template.scratch_size = module->info.scratch_size; |
115 | template.p.data_type = SST_DATA_P; | ||
116 | template.s.size = module->info.scratch_size; | ||
117 | template.s.type = SST_MEM_DRAM; | ||
118 | template.s.data_type = SST_DATA_S; | ||
119 | 118 | ||
120 | mod = sst_module_new(fw, &template, NULL); | 119 | mod = sst_module_new(fw, &template, NULL); |
121 | if (mod == NULL) | 120 | if (mod == NULL) |
@@ -135,14 +134,14 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
135 | switch (block->type) { | 134 | switch (block->type) { |
136 | case SST_HSW_IRAM: | 135 | case SST_HSW_IRAM: |
137 | ram = dsp->addr.lpe; | 136 | ram = dsp->addr.lpe; |
138 | block_data.offset = | 137 | mod->offset = |
139 | block->ram_offset + dsp->addr.iram_offset; | 138 | block->ram_offset + dsp->addr.iram_offset; |
140 | block_data.type = SST_MEM_IRAM; | 139 | mod->type = SST_MEM_IRAM; |
141 | break; | 140 | break; |
142 | case SST_HSW_DRAM: | 141 | case SST_HSW_DRAM: |
143 | ram = dsp->addr.lpe; | 142 | ram = dsp->addr.lpe; |
144 | block_data.offset = block->ram_offset; | 143 | mod->offset = block->ram_offset; |
145 | block_data.type = SST_MEM_DRAM; | 144 | mod->type = SST_MEM_DRAM; |
146 | break; | 145 | break; |
147 | default: | 146 | default: |
148 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", | 147 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", |
@@ -151,30 +150,34 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | |||
151 | return -EINVAL; | 150 | return -EINVAL; |
152 | } | 151 | } |
153 | 152 | ||
154 | block_data.size = block->size; | 153 | mod->size = block->size; |
155 | block_data.data_type = SST_DATA_M; | 154 | mod->data = (void *)block + sizeof(*block); |
156 | block_data.data = (void *)block + sizeof(*block); | 155 | mod->data_offset = mod->data - fw->dma_buf; |
157 | block_data.data_offset = block_data.data - fw->dma_buf; | ||
158 | 156 | ||
159 | dev_dbg(dsp->dev, "copy firmware block %d type 0x%x " | 157 | dev_dbg(dsp->dev, "module block %d type 0x%x " |
160 | "size 0x%x ==> ram %p offset 0x%x\n", | 158 | "size 0x%x ==> ram %p offset 0x%x\n", |
161 | count, block->type, block->size, ram, | 159 | count, mod->type, block->size, ram, |
162 | block->ram_offset); | 160 | block->ram_offset); |
163 | 161 | ||
164 | sst_module_insert_fixed_block(mod, &block_data); | 162 | ret = sst_module_alloc_blocks(mod); |
163 | if (ret < 0) { | ||
164 | dev_err(dsp->dev, "error: could not allocate blocks for module %d\n", | ||
165 | count); | ||
166 | sst_module_free(mod); | ||
167 | return ret; | ||
168 | } | ||
165 | 169 | ||
166 | block = (void *)block + sizeof(*block) + block->size; | 170 | block = (void *)block + sizeof(*block) + block->size; |
167 | } | 171 | } |
172 | |||
168 | return 0; | 173 | return 0; |
169 | } | 174 | } |
170 | 175 | ||
171 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) | 176 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) |
172 | { | 177 | { |
173 | struct fw_header *header; | 178 | struct fw_header *header; |
174 | struct sst_module *scratch; | ||
175 | struct fw_module_header *module; | 179 | struct fw_module_header *module; |
176 | struct sst_dsp *dsp = sst_fw->dsp; | 180 | struct sst_dsp *dsp = sst_fw->dsp; |
177 | struct sst_hsw *hsw = sst_fw->private; | ||
178 | int ret, count; | 181 | int ret, count; |
179 | 182 | ||
180 | /* Read the header information from the data pointer */ | 183 | /* Read the header information from the data pointer */ |
@@ -204,12 +207,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw) | |||
204 | module = (void *)module + sizeof(*module) + module->mod_size; | 207 | module = (void *)module + sizeof(*module) + module->mod_size; |
205 | } | 208 | } |
206 | 209 | ||
207 | /* allocate persistent/scratch mem regions */ | 210 | /* allocate scratch mem regions */ |
208 | scratch = sst_mem_block_alloc_scratch(dsp); | 211 | sst_block_alloc_scratch(dsp); |
209 | if (scratch == NULL) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | sst_hsw_set_scratch_module(hsw, scratch); | ||
213 | 212 | ||
214 | return 0; | 213 | return 0; |
215 | } | 214 | } |
@@ -248,8 +247,94 @@ static irqreturn_t hsw_irq(int irq, void *context) | |||
248 | return ret; | 247 | return ret; |
249 | } | 248 | } |
250 | 249 | ||
251 | static void hsw_boot(struct sst_dsp *sst) | 250 | static void hsw_set_dsp_D3(struct sst_dsp *sst) |
251 | { | ||
252 | u32 val; | ||
253 | u32 reg; | ||
254 | |||
255 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
256 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
257 | reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); | ||
258 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
259 | |||
260 | /* enable power gating and switch off DRAM & IRAM blocks */ | ||
261 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
262 | val |= SST_VDRTCL0_DSRAMPGE_MASK | | ||
263 | SST_VDRTCL0_ISRAMPGE_MASK; | ||
264 | val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD); | ||
265 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
266 | |||
267 | /* switch off audio PLL */ | ||
268 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
269 | val |= SST_VDRTCL2_APLLSE_MASK; | ||
270 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
271 | |||
272 | /* disable MCLK(clkctl.smos = 0) */ | ||
273 | sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, | ||
274 | SST_CLKCTL_MASK, 0); | ||
275 | |||
276 | /* Set D3 state, delay 50 us */ | ||
277 | val = readl(sst->addr.pci_cfg + SST_PMCS); | ||
278 | val |= SST_PMCS_PS_MASK; | ||
279 | writel(val, sst->addr.pci_cfg + SST_PMCS); | ||
280 | udelay(50); | ||
281 | |||
282 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
283 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
284 | reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; | ||
285 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
286 | |||
287 | udelay(50); | ||
288 | |||
289 | } | ||
290 | |||
291 | static void hsw_reset(struct sst_dsp *sst) | ||
252 | { | 292 | { |
293 | /* put DSP into reset and stall */ | ||
294 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
295 | SST_CSR_RST | SST_CSR_STALL, | ||
296 | SST_CSR_RST | SST_CSR_STALL); | ||
297 | |||
298 | /* keep in reset for 10ms */ | ||
299 | mdelay(10); | ||
300 | |||
301 | /* take DSP out of reset and keep stalled for FW loading */ | ||
302 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
303 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | ||
304 | } | ||
305 | |||
306 | static int hsw_set_dsp_D0(struct sst_dsp *sst) | ||
307 | { | ||
308 | int tries = 10; | ||
309 | u32 reg; | ||
310 | |||
311 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
312 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
313 | reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE); | ||
314 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
315 | |||
316 | /* Disable D3PG (VDRTCTL0.D3PGD = 1) */ | ||
317 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
318 | reg |= SST_VDRTCL0_D3PGD; | ||
319 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
320 | |||
321 | /* Set D0 state */ | ||
322 | reg = readl(sst->addr.pci_cfg + SST_PMCS); | ||
323 | reg &= ~SST_PMCS_PS_MASK; | ||
324 | writel(reg, sst->addr.pci_cfg + SST_PMCS); | ||
325 | |||
326 | /* check that ADSP shim is enabled */ | ||
327 | while (tries--) { | ||
328 | reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK; | ||
329 | if (reg == 0) | ||
330 | goto finish; | ||
331 | |||
332 | msleep(1); | ||
333 | } | ||
334 | |||
335 | return -ENODEV; | ||
336 | |||
337 | finish: | ||
253 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ | 338 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ |
254 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 339 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, |
255 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); | 340 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); |
@@ -264,34 +349,96 @@ static void hsw_boot(struct sst_dsp *sst) | |||
264 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, | 349 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, |
265 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); | 350 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); |
266 | 351 | ||
352 | /* Stall and reset core, set CSR */ | ||
353 | hsw_reset(sst); | ||
354 | |||
355 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
356 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
357 | reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE; | ||
358 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
359 | |||
360 | udelay(50); | ||
361 | |||
362 | /* switch on audio PLL */ | ||
363 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
364 | reg &= ~SST_VDRTCL2_APLLSE_MASK; | ||
365 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
366 | |||
367 | /* set default power gating control, enable power gating control for all blocks. that is, | ||
368 | can't be accessed, please enable each block before accessing. */ | ||
369 | reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
370 | reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK; | ||
371 | writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
372 | |||
373 | |||
267 | /* disable DMA finish function for SSP0 & SSP1 */ | 374 | /* disable DMA finish function for SSP0 & SSP1 */ |
268 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, | 375 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, |
269 | SST_CSR2_SDFD_SSP1); | 376 | SST_CSR2_SDFD_SSP1); |
270 | 377 | ||
271 | /* enable DMA engine 0,1 all channels to access host memory */ | 378 | /* set on-demond mode on engine 0,1 for all channels */ |
272 | sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC, | 379 | sst_dsp_shim_update_bits(sst, SST_HMDC, |
273 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff), | 380 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, |
274 | SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff)); | 381 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH); |
382 | |||
383 | /* Enable Interrupt from both sides */ | ||
384 | sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE), | ||
385 | 0x0); | ||
386 | sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY | | ||
387 | SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0); | ||
388 | |||
389 | /* clear IPC registers */ | ||
390 | sst_dsp_shim_write(sst, SST_IPCX, 0x0); | ||
391 | sst_dsp_shim_write(sst, SST_IPCD, 0x0); | ||
392 | sst_dsp_shim_write(sst, 0x80, 0x6); | ||
393 | sst_dsp_shim_write(sst, 0xe0, 0x300a); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
275 | 397 | ||
276 | /* disable all clock gating */ | 398 | static void hsw_boot(struct sst_dsp *sst) |
277 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | 399 | { |
400 | /* set oportunistic mode on engine 0,1 for all channels */ | ||
401 | sst_dsp_shim_update_bits(sst, SST_HMDC, | ||
402 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0); | ||
278 | 403 | ||
279 | /* set DSP to RUN */ | 404 | /* set DSP to RUN */ |
280 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); | 405 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); |
281 | } | 406 | } |
282 | 407 | ||
283 | static void hsw_reset(struct sst_dsp *sst) | 408 | static void hsw_stall(struct sst_dsp *sst) |
409 | { | ||
410 | /* stall DSP */ | ||
411 | sst_dsp_shim_update_bits(sst, SST_CSR, | ||
412 | SST_CSR_24MHZ_LPCS | SST_CSR_STALL, | ||
413 | SST_CSR_STALL | SST_CSR_24MHZ_LPCS); | ||
414 | } | ||
415 | |||
416 | static void hsw_sleep(struct sst_dsp *sst) | ||
284 | { | 417 | { |
418 | dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n"); | ||
419 | |||
285 | /* put DSP into reset and stall */ | 420 | /* put DSP into reset and stall */ |
286 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 421 | sst_dsp_shim_update_bits(sst, SST_CSR, |
287 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL); | 422 | SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL, |
423 | SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS); | ||
288 | 424 | ||
289 | /* keep in reset for 10ms */ | 425 | hsw_set_dsp_D3(sst); |
290 | mdelay(10); | 426 | dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n"); |
427 | } | ||
291 | 428 | ||
292 | /* take DSP out of reset and keep stalled for FW loading */ | 429 | static int hsw_wake(struct sst_dsp *sst) |
293 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | 430 | { |
294 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | 431 | int ret; |
432 | |||
433 | dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n"); | ||
434 | |||
435 | ret = hsw_set_dsp_D0(sst); | ||
436 | if (ret < 0) | ||
437 | return ret; | ||
438 | |||
439 | dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n"); | ||
440 | |||
441 | return 0; | ||
295 | } | 442 | } |
296 | 443 | ||
297 | struct sst_adsp_memregion { | 444 | struct sst_adsp_memregion { |
@@ -396,6 +543,11 @@ static int hsw_block_enable(struct sst_mem_block *block) | |||
396 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", | 543 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", |
397 | block->type, block->index, block->offset); | 544 | block->type, block->index, block->offset); |
398 | 545 | ||
546 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
547 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
548 | val &= ~SST_VDRTCL2_DCLCGE; | ||
549 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
550 | |||
399 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 551 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
400 | bit = hsw_block_get_bit(block); | 552 | bit = hsw_block_get_bit(block); |
401 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); | 553 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); |
@@ -403,6 +555,13 @@ static int hsw_block_enable(struct sst_mem_block *block) | |||
403 | /* wait 18 DSP clock ticks */ | 555 | /* wait 18 DSP clock ticks */ |
404 | udelay(10); | 556 | udelay(10); |
405 | 557 | ||
558 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
559 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
560 | val |= SST_VDRTCL2_DCLCGE; | ||
561 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
562 | |||
563 | udelay(50); | ||
564 | |||
406 | /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ | 565 | /*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/ |
407 | sst_mem_block_dummy_read(block); | 566 | sst_mem_block_dummy_read(block); |
408 | return 0; | 567 | return 0; |
@@ -420,10 +579,26 @@ static int hsw_block_disable(struct sst_mem_block *block) | |||
420 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", | 579 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", |
421 | block->type, block->index, block->offset); | 580 | block->type, block->index, block->offset); |
422 | 581 | ||
582 | /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */ | ||
583 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
584 | val &= ~SST_VDRTCL2_DCLCGE; | ||
585 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
586 | |||
587 | |||
423 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | 588 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); |
424 | bit = hsw_block_get_bit(block); | 589 | bit = hsw_block_get_bit(block); |
425 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | 590 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); |
426 | 591 | ||
592 | /* wait 18 DSP clock ticks */ | ||
593 | udelay(10); | ||
594 | |||
595 | /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */ | ||
596 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL2); | ||
597 | val |= SST_VDRTCL2_DCLCGE; | ||
598 | writel(val, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
599 | |||
600 | udelay(50); | ||
601 | |||
427 | return 0; | 602 | return 0; |
428 | } | 603 | } |
429 | 604 | ||
@@ -432,27 +607,6 @@ static struct sst_block_ops sst_hsw_ops = { | |||
432 | .disable = hsw_block_disable, | 607 | .disable = hsw_block_disable, |
433 | }; | 608 | }; |
434 | 609 | ||
435 | static int hsw_enable_shim(struct sst_dsp *sst) | ||
436 | { | ||
437 | int tries = 10; | ||
438 | u32 reg; | ||
439 | |||
440 | /* enable shim */ | ||
441 | reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
442 | writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
443 | |||
444 | /* check that ADSP shim is enabled */ | ||
445 | while (tries--) { | ||
446 | reg = sst_dsp_shim_read_unlocked(sst, SST_CSR); | ||
447 | if (reg != 0xffffffff) | ||
448 | return 0; | ||
449 | |||
450 | msleep(1); | ||
451 | } | ||
452 | |||
453 | return -ENODEV; | ||
454 | } | ||
455 | |||
456 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | 610 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) |
457 | { | 611 | { |
458 | const struct sst_adsp_memregion *region; | 612 | const struct sst_adsp_memregion *region; |
@@ -467,12 +621,16 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
467 | region = lp_region; | 621 | region = lp_region; |
468 | region_count = ARRAY_SIZE(lp_region); | 622 | region_count = ARRAY_SIZE(lp_region); |
469 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; | 623 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; |
624 | sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET; | ||
625 | sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET; | ||
470 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; | 626 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; |
471 | break; | 627 | break; |
472 | case SST_DEV_ID_WILDCAT_POINT: | 628 | case SST_DEV_ID_WILDCAT_POINT: |
473 | region = wpt_region; | 629 | region = wpt_region; |
474 | region_count = ARRAY_SIZE(wpt_region); | 630 | region_count = ARRAY_SIZE(wpt_region); |
475 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; | 631 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; |
632 | sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET; | ||
633 | sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET; | ||
476 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; | 634 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; |
477 | break; | 635 | break; |
478 | default: | 636 | default: |
@@ -487,7 +645,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
487 | } | 645 | } |
488 | 646 | ||
489 | /* enable the DSP SHIM */ | 647 | /* enable the DSP SHIM */ |
490 | ret = hsw_enable_shim(sst); | 648 | ret = hsw_set_dsp_D0(sst); |
491 | if (ret < 0) { | 649 | if (ret < 0) { |
492 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); | 650 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); |
493 | return ret; | 651 | return ret; |
@@ -497,10 +655,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | |||
497 | if (ret) | 655 | if (ret) |
498 | return ret; | 656 | return ret; |
499 | 657 | ||
500 | /* Enable Interrupt from both sides */ | ||
501 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0); | ||
502 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD, | ||
503 | (0x3 | 0x1 << 16 | 0x3 << 21), 0x0); | ||
504 | 658 | ||
505 | /* register DSP memory blocks - ideally we should get this from ACPI */ | 659 | /* register DSP memory blocks - ideally we should get this from ACPI */ |
506 | for (i = 0; i < region_count; i++) { | 660 | for (i = 0; i < region_count; i++) { |
@@ -532,6 +686,9 @@ static void hsw_free(struct sst_dsp *sst) | |||
532 | struct sst_ops haswell_ops = { | 686 | struct sst_ops haswell_ops = { |
533 | .reset = hsw_reset, | 687 | .reset = hsw_reset, |
534 | .boot = hsw_boot, | 688 | .boot = hsw_boot, |
689 | .stall = hsw_stall, | ||
690 | .wake = hsw_wake, | ||
691 | .sleep = hsw_sleep, | ||
535 | .write = sst_shim32_write, | 692 | .write = sst_shim32_write, |
536 | .read = sst_shim32_read, | 693 | .read = sst_shim32_read, |
537 | .write64 = sst_shim32_write64, | 694 | .write64 = sst_shim32_write64, |
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c index b6291516dbbf..3f8c48231364 100644 --- a/sound/soc/intel/sst-haswell-ipc.c +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <linux/firmware.h> | 30 | #include <linux/firmware.h> |
31 | #include <linux/dma-mapping.h> | 31 | #include <linux/dma-mapping.h> |
32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
33 | #include <linux/pm_runtime.h> | ||
33 | 34 | ||
34 | #include "sst-haswell-ipc.h" | 35 | #include "sst-haswell-ipc.h" |
35 | #include "sst-dsp.h" | 36 | #include "sst-dsp.h" |
@@ -276,6 +277,7 @@ struct sst_hsw { | |||
276 | struct sst_hsw_ipc_fw_version version; | 277 | struct sst_hsw_ipc_fw_version version; |
277 | struct sst_module *scratch; | 278 | struct sst_module *scratch; |
278 | bool fw_done; | 279 | bool fw_done; |
280 | struct sst_fw *sst_fw; | ||
279 | 281 | ||
280 | /* stream */ | 282 | /* stream */ |
281 | struct list_head stream_list; | 283 | struct list_head stream_list; |
@@ -289,6 +291,8 @@ struct sst_hsw { | |||
289 | 291 | ||
290 | /* DX */ | 292 | /* DX */ |
291 | struct sst_hsw_ipc_dx_reply dx; | 293 | struct sst_hsw_ipc_dx_reply dx; |
294 | void *dx_context; | ||
295 | dma_addr_t dx_context_paddr; | ||
292 | 296 | ||
293 | /* boot */ | 297 | /* boot */ |
294 | wait_queue_head_t boot_wait; | 298 | wait_queue_head_t boot_wait; |
@@ -1038,14 +1042,9 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1038 | 1042 | ||
1039 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); | 1043 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); |
1040 | 1044 | ||
1041 | if (channel > 1) | 1045 | if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) |
1042 | return -EINVAL; | 1046 | return -EINVAL; |
1043 | 1047 | ||
1044 | if (stream->mute[channel]) { | ||
1045 | stream->mute_volume[channel] = volume; | ||
1046 | return 0; | ||
1047 | } | ||
1048 | |||
1049 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | 1048 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | |
1050 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | 1049 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); |
1051 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | 1050 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); |
@@ -1053,9 +1052,28 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | |||
1053 | header |= (stage_id << IPC_STG_ID_SHIFT); | 1052 | header |= (stage_id << IPC_STG_ID_SHIFT); |
1054 | 1053 | ||
1055 | req = &stream->vol_req; | 1054 | req = &stream->vol_req; |
1056 | req->channel = channel; | ||
1057 | req->target_volume = volume; | 1055 | req->target_volume = volume; |
1058 | 1056 | ||
1057 | /* set both at same time ? */ | ||
1058 | if (channel == SST_HSW_CHANNELS_ALL) { | ||
1059 | if (hsw->mute[0] && hsw->mute[1]) { | ||
1060 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | ||
1061 | return 0; | ||
1062 | } else if (hsw->mute[0]) | ||
1063 | req->channel = 1; | ||
1064 | else if (hsw->mute[1]) | ||
1065 | req->channel = 0; | ||
1066 | else | ||
1067 | req->channel = SST_HSW_CHANNELS_ALL; | ||
1068 | } else { | ||
1069 | /* set only 1 channel */ | ||
1070 | if (hsw->mute[channel]) { | ||
1071 | hsw->mute_volume[channel] = volume; | ||
1072 | return 0; | ||
1073 | } | ||
1074 | req->channel = channel; | ||
1075 | } | ||
1076 | |||
1059 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | 1077 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); |
1060 | if (ret < 0) { | 1078 | if (ret < 0) { |
1061 | dev_err(hsw->dev, "error: set stream volume failed\n"); | 1079 | dev_err(hsw->dev, "error: set stream volume failed\n"); |
@@ -1134,8 +1152,11 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1134 | 1152 | ||
1135 | trace_ipc_request("set mixer volume", volume); | 1153 | trace_ipc_request("set mixer volume", volume); |
1136 | 1154 | ||
1155 | if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL) | ||
1156 | return -EINVAL; | ||
1157 | |||
1137 | /* set both at same time ? */ | 1158 | /* set both at same time ? */ |
1138 | if (channel == 2) { | 1159 | if (channel == SST_HSW_CHANNELS_ALL) { |
1139 | if (hsw->mute[0] && hsw->mute[1]) { | 1160 | if (hsw->mute[0] && hsw->mute[1]) { |
1140 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | 1161 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; |
1141 | return 0; | 1162 | return 0; |
@@ -1144,7 +1165,7 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | |||
1144 | else if (hsw->mute[1]) | 1165 | else if (hsw->mute[1]) |
1145 | req.channel = 0; | 1166 | req.channel = 0; |
1146 | else | 1167 | else |
1147 | req.channel = 0xffffffff; | 1168 | req.channel = SST_HSW_CHANNELS_ALL; |
1148 | } else { | 1169 | } else { |
1149 | /* set only 1 channel */ | 1170 | /* set only 1 channel */ |
1150 | if (hsw->mute[channel]) { | 1171 | if (hsw->mute[channel]) { |
@@ -1256,10 +1277,6 @@ int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | |||
1256 | return -EINVAL; | 1277 | return -EINVAL; |
1257 | } | 1278 | } |
1258 | 1279 | ||
1259 | /* stereo is only supported atm */ | ||
1260 | if (channels != 2) | ||
1261 | return -EINVAL; | ||
1262 | |||
1263 | stream->request.format.ch_num = channels; | 1280 | stream->request.format.ch_num = channels; |
1264 | return 0; | 1281 | return 0; |
1265 | } | 1282 | } |
@@ -1355,10 +1372,11 @@ int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | |||
1355 | } | 1372 | } |
1356 | 1373 | ||
1357 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | 1374 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, |
1358 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | 1375 | struct sst_hsw_stream *stream, struct sst_module_runtime *runtime) |
1359 | u32 entry_point) | ||
1360 | { | 1376 | { |
1361 | struct sst_hsw_module_map *map = &stream->request.map; | 1377 | struct sst_hsw_module_map *map = &stream->request.map; |
1378 | struct sst_dsp *dsp = sst_hsw_get_dsp(hsw); | ||
1379 | struct sst_module *module = runtime->module; | ||
1362 | 1380 | ||
1363 | if (stream->commited) { | 1381 | if (stream->commited) { |
1364 | dev_err(hsw->dev, "error: stream committed for set module\n"); | 1382 | dev_err(hsw->dev, "error: stream committed for set module\n"); |
@@ -1367,36 +1385,25 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | |||
1367 | 1385 | ||
1368 | /* only support initial module atm */ | 1386 | /* only support initial module atm */ |
1369 | map->module_entries_count = 1; | 1387 | map->module_entries_count = 1; |
1370 | map->module_entries[0].module_id = module_id; | 1388 | map->module_entries[0].module_id = module->id; |
1371 | map->module_entries[0].entry_point = entry_point; | 1389 | map->module_entries[0].entry_point = module->entry; |
1372 | 1390 | ||
1373 | return 0; | 1391 | stream->request.persistent_mem.offset = |
1374 | } | 1392 | sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM); |
1375 | 1393 | stream->request.persistent_mem.size = module->persistent_size; | |
1376 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | 1394 | |
1377 | struct sst_hsw_stream *stream, u32 offset, u32 size) | 1395 | stream->request.scratch_mem.offset = |
1378 | { | 1396 | sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM); |
1379 | if (stream->commited) { | 1397 | stream->request.scratch_mem.size = dsp->scratch_size; |
1380 | dev_err(hsw->dev, "error: stream committed for set pmem\n"); | 1398 | |
1381 | return -EINVAL; | 1399 | dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id, |
1382 | } | 1400 | runtime->id); |
1383 | 1401 | dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n", | |
1384 | stream->request.persistent_mem.offset = offset; | 1402 | stream->request.persistent_mem.offset, |
1385 | stream->request.persistent_mem.size = size; | 1403 | stream->request.persistent_mem.size); |
1386 | 1404 | dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n", | |
1387 | return 0; | 1405 | stream->request.scratch_mem.offset, |
1388 | } | 1406 | stream->request.scratch_mem.size); |
1389 | |||
1390 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
1391 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
1392 | { | ||
1393 | if (stream->commited) { | ||
1394 | dev_err(hsw->dev, "error: stream committed for set smem\n"); | ||
1395 | return -EINVAL; | ||
1396 | } | ||
1397 | |||
1398 | stream->request.scratch_mem.offset = offset; | ||
1399 | stream->request.scratch_mem.size = size; | ||
1400 | 1407 | ||
1401 | return 0; | 1408 | return 0; |
1402 | } | 1409 | } |
@@ -1630,6 +1637,10 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw, | |||
1630 | config.clock_frequency = mclk; | 1637 | config.clock_frequency = mclk; |
1631 | config.mode = mode; | 1638 | config.mode = mode; |
1632 | config.clock_divider = clock_divider; | 1639 | config.clock_divider = clock_divider; |
1640 | if (mode == SST_HSW_DEVICE_TDM_CLOCK_MASTER) | ||
1641 | config.channels = 4; | ||
1642 | else | ||
1643 | config.channels = 2; | ||
1633 | 1644 | ||
1634 | trace_hsw_device_config_req(&config); | 1645 | trace_hsw_device_config_req(&config); |
1635 | 1646 | ||
@@ -1673,34 +1684,283 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw, | |||
1673 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | 1684 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", |
1674 | dx->entries_no, state); | 1685 | dx->entries_no, state); |
1675 | 1686 | ||
1676 | memcpy(&hsw->dx, dx, sizeof(*dx)); | 1687 | return ret; |
1677 | return 0; | ||
1678 | } | 1688 | } |
1679 | 1689 | ||
1680 | /* Used to save state into hsw->dx_reply */ | 1690 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, |
1681 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | 1691 | int mod_id, int offset) |
1682 | u32 *offset, u32 *size, u32 *source) | ||
1683 | { | 1692 | { |
1684 | struct sst_hsw_ipc_dx_memory_item *dx_mem; | 1693 | struct sst_dsp *dsp = hsw->dsp; |
1685 | struct sst_hsw_ipc_dx_reply *dx_reply; | 1694 | struct sst_module *module; |
1686 | int entry_no; | 1695 | struct sst_module_runtime *runtime; |
1696 | int err; | ||
1687 | 1697 | ||
1688 | dx_reply = &hsw->dx; | 1698 | module = sst_module_get_from_id(dsp, mod_id); |
1689 | entry_no = dx_reply->entries_no; | 1699 | if (module == NULL) { |
1700 | dev_err(dsp->dev, "error: failed to get module %d for pcm\n", | ||
1701 | mod_id); | ||
1702 | return NULL; | ||
1703 | } | ||
1704 | |||
1705 | runtime = sst_module_runtime_new(module, mod_id, NULL); | ||
1706 | if (runtime == NULL) { | ||
1707 | dev_err(dsp->dev, "error: failed to create module %d runtime\n", | ||
1708 | mod_id); | ||
1709 | return NULL; | ||
1710 | } | ||
1711 | |||
1712 | err = sst_module_runtime_alloc_blocks(runtime, offset); | ||
1713 | if (err < 0) { | ||
1714 | dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n", | ||
1715 | mod_id); | ||
1716 | sst_module_runtime_free(runtime); | ||
1717 | return NULL; | ||
1718 | } | ||
1719 | |||
1720 | dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id, | ||
1721 | mod_id); | ||
1722 | return runtime; | ||
1723 | } | ||
1724 | |||
1725 | void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime) | ||
1726 | { | ||
1727 | sst_module_runtime_free_blocks(runtime); | ||
1728 | sst_module_runtime_free(runtime); | ||
1729 | } | ||
1730 | |||
1731 | #ifdef CONFIG_PM | ||
1732 | static int sst_hsw_dx_state_dump(struct sst_hsw *hsw) | ||
1733 | { | ||
1734 | struct sst_dsp *sst = hsw->dsp; | ||
1735 | u32 item, offset, size; | ||
1736 | int ret = 0; | ||
1690 | 1737 | ||
1691 | trace_ipc_request("PM get Dx state", entry_no); | 1738 | trace_ipc_request("PM state dump. Items #", SST_HSW_MAX_DX_REGIONS); |
1692 | 1739 | ||
1693 | if (item >= entry_no) | 1740 | if (hsw->dx.entries_no > SST_HSW_MAX_DX_REGIONS) { |
1741 | dev_err(hsw->dev, | ||
1742 | "error: number of FW context regions greater than %d\n", | ||
1743 | SST_HSW_MAX_DX_REGIONS); | ||
1744 | memset(&hsw->dx, 0, sizeof(hsw->dx)); | ||
1694 | return -EINVAL; | 1745 | return -EINVAL; |
1746 | } | ||
1747 | |||
1748 | ret = sst_dsp_dma_get_channel(sst, 0); | ||
1749 | if (ret < 0) { | ||
1750 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1751 | return ret; | ||
1752 | } | ||
1753 | |||
1754 | /* set on-demond mode on engine 0 channel 3 */ | ||
1755 | sst_dsp_shim_update_bits(sst, SST_HMDC, | ||
1756 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, | ||
1757 | SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH); | ||
1758 | |||
1759 | for (item = 0; item < hsw->dx.entries_no; item++) { | ||
1760 | if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP | ||
1761 | && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET | ||
1762 | && hsw->dx.mem_info[item].offset < | ||
1763 | DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) { | ||
1764 | |||
1765 | offset = hsw->dx.mem_info[item].offset | ||
1766 | - DSP_DRAM_ADDR_OFFSET; | ||
1767 | size = (hsw->dx.mem_info[item].size + 3) & (~3); | ||
1768 | |||
1769 | ret = sst_dsp_dma_copyfrom(sst, hsw->dx_context_paddr + offset, | ||
1770 | sst->addr.lpe_base + offset, size); | ||
1771 | if (ret < 0) { | ||
1772 | dev_err(hsw->dev, | ||
1773 | "error: FW context dump failed\n"); | ||
1774 | memset(&hsw->dx, 0, sizeof(hsw->dx)); | ||
1775 | goto out; | ||
1776 | } | ||
1777 | } | ||
1778 | } | ||
1779 | |||
1780 | out: | ||
1781 | sst_dsp_dma_put_channel(sst); | ||
1782 | return ret; | ||
1783 | } | ||
1784 | |||
1785 | static int sst_hsw_dx_state_restore(struct sst_hsw *hsw) | ||
1786 | { | ||
1787 | struct sst_dsp *sst = hsw->dsp; | ||
1788 | u32 item, offset, size; | ||
1789 | int ret; | ||
1790 | |||
1791 | for (item = 0; item < hsw->dx.entries_no; item++) { | ||
1792 | if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP | ||
1793 | && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET | ||
1794 | && hsw->dx.mem_info[item].offset < | ||
1795 | DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) { | ||
1796 | |||
1797 | offset = hsw->dx.mem_info[item].offset | ||
1798 | - DSP_DRAM_ADDR_OFFSET; | ||
1799 | size = (hsw->dx.mem_info[item].size + 3) & (~3); | ||
1800 | |||
1801 | ret = sst_dsp_dma_copyto(sst, sst->addr.lpe_base + offset, | ||
1802 | hsw->dx_context_paddr + offset, size); | ||
1803 | if (ret < 0) { | ||
1804 | dev_err(hsw->dev, | ||
1805 | "error: FW context restore failed\n"); | ||
1806 | return ret; | ||
1807 | } | ||
1808 | } | ||
1809 | } | ||
1810 | |||
1811 | return 0; | ||
1812 | } | ||
1813 | |||
1814 | static void sst_hsw_drop_all(struct sst_hsw *hsw) | ||
1815 | { | ||
1816 | struct ipc_message *msg, *tmp; | ||
1817 | unsigned long flags; | ||
1818 | int tx_drop_cnt = 0, rx_drop_cnt = 0; | ||
1695 | 1819 | ||
1696 | dx_mem = &dx_reply->mem_info[item]; | 1820 | /* drop all TX and Rx messages before we stall + reset DSP */ |
1697 | *offset = dx_mem->offset; | 1821 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); |
1698 | *size = dx_mem->size; | 1822 | |
1699 | *source = dx_mem->source; | 1823 | list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) { |
1824 | list_move(&msg->list, &hsw->empty_list); | ||
1825 | tx_drop_cnt++; | ||
1826 | } | ||
1827 | |||
1828 | list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) { | ||
1829 | list_move(&msg->list, &hsw->empty_list); | ||
1830 | rx_drop_cnt++; | ||
1831 | } | ||
1832 | |||
1833 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
1834 | |||
1835 | if (tx_drop_cnt || rx_drop_cnt) | ||
1836 | dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n", | ||
1837 | tx_drop_cnt, rx_drop_cnt); | ||
1838 | } | ||
1839 | |||
1840 | int sst_hsw_dsp_load(struct sst_hsw *hsw) | ||
1841 | { | ||
1842 | struct sst_dsp *dsp = hsw->dsp; | ||
1843 | int ret; | ||
1844 | |||
1845 | dev_dbg(hsw->dev, "loading audio DSP...."); | ||
1846 | |||
1847 | ret = sst_dsp_wake(dsp); | ||
1848 | if (ret < 0) { | ||
1849 | dev_err(hsw->dev, "error: failed to wake audio DSP\n"); | ||
1850 | return -ENODEV; | ||
1851 | } | ||
1852 | |||
1853 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
1854 | if (ret < 0) { | ||
1855 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1856 | return ret; | ||
1857 | } | ||
1858 | |||
1859 | ret = sst_fw_reload(hsw->sst_fw); | ||
1860 | if (ret < 0) { | ||
1861 | dev_err(hsw->dev, "error: SST FW reload failed\n"); | ||
1862 | sst_dsp_dma_put_channel(dsp); | ||
1863 | return -ENOMEM; | ||
1864 | } | ||
1700 | 1865 | ||
1866 | sst_dsp_dma_put_channel(dsp); | ||
1701 | return 0; | 1867 | return 0; |
1702 | } | 1868 | } |
1703 | 1869 | ||
1870 | static int sst_hsw_dsp_restore(struct sst_hsw *hsw) | ||
1871 | { | ||
1872 | struct sst_dsp *dsp = hsw->dsp; | ||
1873 | int ret; | ||
1874 | |||
1875 | dev_dbg(hsw->dev, "restoring audio DSP...."); | ||
1876 | |||
1877 | ret = sst_dsp_dma_get_channel(dsp, 0); | ||
1878 | if (ret < 0) { | ||
1879 | dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret); | ||
1880 | return ret; | ||
1881 | } | ||
1882 | |||
1883 | ret = sst_hsw_dx_state_restore(hsw); | ||
1884 | if (ret < 0) { | ||
1885 | dev_err(hsw->dev, "error: SST FW context restore failed\n"); | ||
1886 | sst_dsp_dma_put_channel(dsp); | ||
1887 | return -ENOMEM; | ||
1888 | } | ||
1889 | sst_dsp_dma_put_channel(dsp); | ||
1890 | |||
1891 | /* wait for DSP boot completion */ | ||
1892 | sst_dsp_boot(dsp); | ||
1893 | |||
1894 | return ret; | ||
1895 | } | ||
1896 | |||
1897 | int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw) | ||
1898 | { | ||
1899 | int ret; | ||
1900 | |||
1901 | dev_dbg(hsw->dev, "audio dsp runtime suspend\n"); | ||
1902 | |||
1903 | ret = sst_hsw_dx_set_state(hsw, SST_HSW_DX_STATE_D3, &hsw->dx); | ||
1904 | if (ret < 0) | ||
1905 | return ret; | ||
1906 | |||
1907 | sst_dsp_stall(hsw->dsp); | ||
1908 | |||
1909 | ret = sst_hsw_dx_state_dump(hsw); | ||
1910 | if (ret < 0) | ||
1911 | return ret; | ||
1912 | |||
1913 | sst_hsw_drop_all(hsw); | ||
1914 | |||
1915 | return 0; | ||
1916 | } | ||
1917 | |||
1918 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw) | ||
1919 | { | ||
1920 | sst_fw_unload(hsw->sst_fw); | ||
1921 | sst_block_free_scratch(hsw->dsp); | ||
1922 | |||
1923 | hsw->boot_complete = false; | ||
1924 | |||
1925 | sst_dsp_sleep(hsw->dsp); | ||
1926 | |||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw) | ||
1931 | { | ||
1932 | struct device *dev = hsw->dev; | ||
1933 | int ret; | ||
1934 | |||
1935 | dev_dbg(dev, "audio dsp runtime resume\n"); | ||
1936 | |||
1937 | if (hsw->boot_complete) | ||
1938 | return 1; /* tell caller no action is required */ | ||
1939 | |||
1940 | ret = sst_hsw_dsp_restore(hsw); | ||
1941 | if (ret < 0) | ||
1942 | dev_err(dev, "error: audio DSP boot failure\n"); | ||
1943 | |||
1944 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | ||
1945 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
1946 | if (ret == 0) { | ||
1947 | dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n", | ||
1948 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD), | ||
1949 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX)); | ||
1950 | return -EIO; | ||
1951 | } | ||
1952 | |||
1953 | /* Set ADSP SSP port settings */ | ||
1954 | ret = sst_hsw_device_set_config(hsw, SST_HSW_DEVICE_SSP_0, | ||
1955 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
1956 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
1957 | if (ret < 0) | ||
1958 | dev_err(dev, "error: SSP re-initialization failed\n"); | ||
1959 | |||
1960 | return ret; | ||
1961 | } | ||
1962 | #endif | ||
1963 | |||
1704 | static int msg_empty_list_init(struct sst_hsw *hsw) | 1964 | static int msg_empty_list_init(struct sst_hsw *hsw) |
1705 | { | 1965 | { |
1706 | int i; | 1966 | int i; |
@@ -1718,12 +1978,6 @@ static int msg_empty_list_init(struct sst_hsw *hsw) | |||
1718 | return 0; | 1978 | return 0; |
1719 | } | 1979 | } |
1720 | 1980 | ||
1721 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
1722 | struct sst_module *scratch) | ||
1723 | { | ||
1724 | hsw->scratch = scratch; | ||
1725 | } | ||
1726 | |||
1727 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | 1981 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) |
1728 | { | 1982 | { |
1729 | return hsw->dsp; | 1983 | return hsw->dsp; |
@@ -1738,7 +1992,6 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1738 | { | 1992 | { |
1739 | struct sst_hsw_ipc_fw_version version; | 1993 | struct sst_hsw_ipc_fw_version version; |
1740 | struct sst_hsw *hsw; | 1994 | struct sst_hsw *hsw; |
1741 | struct sst_fw *hsw_sst_fw; | ||
1742 | int ret; | 1995 | int ret; |
1743 | 1996 | ||
1744 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | 1997 | dev_dbg(dev, "initialising Audio DSP IPC\n"); |
@@ -1780,12 +2033,19 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1780 | goto dsp_err; | 2033 | goto dsp_err; |
1781 | } | 2034 | } |
1782 | 2035 | ||
2036 | /* allocate DMA buffer for context storage */ | ||
2037 | hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev, | ||
2038 | SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL); | ||
2039 | if (hsw->dx_context == NULL) { | ||
2040 | ret = -ENOMEM; | ||
2041 | goto dma_err; | ||
2042 | } | ||
2043 | |||
1783 | /* keep the DSP in reset state for base FW loading */ | 2044 | /* keep the DSP in reset state for base FW loading */ |
1784 | sst_dsp_reset(hsw->dsp); | 2045 | sst_dsp_reset(hsw->dsp); |
1785 | 2046 | ||
1786 | hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | 2047 | hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); |
1787 | 2048 | if (hsw->sst_fw == NULL) { | |
1788 | if (hsw_sst_fw == NULL) { | ||
1789 | ret = -ENODEV; | 2049 | ret = -ENODEV; |
1790 | dev_err(dev, "error: failed to load firmware\n"); | 2050 | dev_err(dev, "error: failed to load firmware\n"); |
1791 | goto fw_err; | 2051 | goto fw_err; |
@@ -1797,7 +2057,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1797 | msecs_to_jiffies(IPC_BOOT_MSECS)); | 2057 | msecs_to_jiffies(IPC_BOOT_MSECS)); |
1798 | if (ret == 0) { | 2058 | if (ret == 0) { |
1799 | ret = -EIO; | 2059 | ret = -EIO; |
1800 | dev_err(hsw->dev, "error: ADSP boot timeout\n"); | 2060 | dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n", |
2061 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD), | ||
2062 | sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX)); | ||
1801 | goto boot_err; | 2063 | goto boot_err; |
1802 | } | 2064 | } |
1803 | 2065 | ||
@@ -1816,8 +2078,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | |||
1816 | 2078 | ||
1817 | boot_err: | 2079 | boot_err: |
1818 | sst_dsp_reset(hsw->dsp); | 2080 | sst_dsp_reset(hsw->dsp); |
1819 | sst_fw_free(hsw_sst_fw); | 2081 | sst_fw_free(hsw->sst_fw); |
1820 | fw_err: | 2082 | fw_err: |
2083 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | ||
2084 | hsw->dx_context, hsw->dx_context_paddr); | ||
2085 | dma_err: | ||
1821 | sst_dsp_free(hsw->dsp); | 2086 | sst_dsp_free(hsw->dsp); |
1822 | dsp_err: | 2087 | dsp_err: |
1823 | kthread_stop(hsw->tx_thread); | 2088 | kthread_stop(hsw->tx_thread); |
@@ -1834,6 +2099,8 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | |||
1834 | 2099 | ||
1835 | sst_dsp_reset(hsw->dsp); | 2100 | sst_dsp_reset(hsw->dsp); |
1836 | sst_fw_free_all(hsw->dsp); | 2101 | sst_fw_free_all(hsw->dsp); |
2102 | dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE, | ||
2103 | hsw->dx_context, hsw->dx_context_paddr); | ||
1837 | sst_dsp_free(hsw->dsp); | 2104 | sst_dsp_free(hsw->dsp); |
1838 | kfree(hsw->scratch); | 2105 | kfree(hsw->scratch); |
1839 | kthread_stop(hsw->tx_thread); | 2106 | kthread_stop(hsw->tx_thread); |
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h index 2ac194a6d04b..138e894ab413 100644 --- a/sound/soc/intel/sst-haswell-ipc.h +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
@@ -21,8 +21,10 @@ | |||
21 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | 23 | ||
24 | #define SST_HSW_NO_CHANNELS 2 | 24 | #define SST_HSW_NO_CHANNELS 4 |
25 | #define SST_HSW_MAX_DX_REGIONS 14 | 25 | #define SST_HSW_MAX_DX_REGIONS 14 |
26 | #define SST_HSW_DX_CONTEXT_SIZE (640 * 1024) | ||
27 | #define SST_HSW_CHANNELS_ALL 0xffffffff | ||
26 | 28 | ||
27 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 | 29 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 |
28 | #define SST_HSW_GLOBAL_LOG 15 | 30 | #define SST_HSW_GLOBAL_LOG 15 |
@@ -40,6 +42,7 @@ struct sst_hsw_stream; | |||
40 | struct sst_hsw_log_stream; | 42 | struct sst_hsw_log_stream; |
41 | struct sst_pdata; | 43 | struct sst_pdata; |
42 | struct sst_module; | 44 | struct sst_module; |
45 | struct sst_module_runtime; | ||
43 | extern struct sst_ops haswell_ops; | 46 | extern struct sst_ops haswell_ops; |
44 | 47 | ||
45 | /* Stream Allocate Path ID */ | 48 | /* Stream Allocate Path ID */ |
@@ -84,6 +87,7 @@ enum sst_hsw_device_mclk { | |||
84 | enum sst_hsw_device_mode { | 87 | enum sst_hsw_device_mode { |
85 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, | 88 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, |
86 | SST_HSW_DEVICE_CLOCK_MASTER = 1, | 89 | SST_HSW_DEVICE_CLOCK_MASTER = 1, |
90 | SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2, | ||
87 | }; | 91 | }; |
88 | 92 | ||
89 | /* DX Power State */ | 93 | /* DX Power State */ |
@@ -295,7 +299,8 @@ struct sst_hsw_ipc_device_config_req { | |||
295 | u32 clock_frequency; | 299 | u32 clock_frequency; |
296 | u32 mode; | 300 | u32 mode; |
297 | u16 clock_divider; | 301 | u16 clock_divider; |
298 | u16 reserved; | 302 | u8 channels; |
303 | u8 reserved; | ||
299 | } __attribute__((packed)); | 304 | } __attribute__((packed)); |
300 | 305 | ||
301 | /* Audio Data formats */ | 306 | /* Audio Data formats */ |
@@ -430,8 +435,7 @@ int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | |||
430 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | 435 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, |
431 | enum sst_hsw_interleaving style); | 436 | enum sst_hsw_interleaving style); |
432 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | 437 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, |
433 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | 438 | struct sst_hsw_stream *stream, struct sst_module_runtime *runtime); |
434 | u32 entry_point); | ||
435 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | 439 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, |
436 | struct sst_hsw_stream *stream, u32 offset, u32 size); | 440 | struct sst_hsw_stream *stream, u32 offset, u32 size); |
437 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | 441 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, |
@@ -484,7 +488,16 @@ int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | |||
484 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | 488 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); |
485 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | 489 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); |
486 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | 490 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); |
487 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | 491 | |
488 | struct sst_module *scratch); | 492 | /* runtime module management */ |
493 | struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw, | ||
494 | int mod_id, int offset); | ||
495 | void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime); | ||
496 | |||
497 | /* PM */ | ||
498 | int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw); | ||
499 | int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw); | ||
500 | int sst_hsw_dsp_load(struct sst_hsw *hsw); | ||
501 | int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw); | ||
489 | 502 | ||
490 | #endif | 503 | #endif |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 4df867cbb92a..0180b386c421 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/pm_runtime.h> | ||
21 | #include <asm/page.h> | 22 | #include <asm/page.h> |
22 | #include <asm/pgtable.h> | 23 | #include <asm/pgtable.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
@@ -73,6 +74,13 @@ static const u32 volume_map[] = { | |||
73 | #define HSW_PCM_PERIODS_MAX 64 | 74 | #define HSW_PCM_PERIODS_MAX 64 |
74 | #define HSW_PCM_PERIODS_MIN 2 | 75 | #define HSW_PCM_PERIODS_MIN 2 |
75 | 76 | ||
77 | #define HSW_PCM_DAI_ID_SYSTEM 0 | ||
78 | #define HSW_PCM_DAI_ID_OFFLOAD0 1 | ||
79 | #define HSW_PCM_DAI_ID_OFFLOAD1 2 | ||
80 | #define HSW_PCM_DAI_ID_LOOPBACK 3 | ||
81 | #define HSW_PCM_DAI_ID_CAPTURE 4 | ||
82 | |||
83 | |||
76 | static const struct snd_pcm_hardware hsw_pcm_hardware = { | 84 | static const struct snd_pcm_hardware hsw_pcm_hardware = { |
77 | .info = SNDRV_PCM_INFO_MMAP | | 85 | .info = SNDRV_PCM_INFO_MMAP | |
78 | SNDRV_PCM_INFO_MMAP_VALID | | 86 | SNDRV_PCM_INFO_MMAP_VALID | |
@@ -89,22 +97,39 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = { | |||
89 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, | 97 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, |
90 | }; | 98 | }; |
91 | 99 | ||
100 | struct hsw_pcm_module_map { | ||
101 | int dai_id; | ||
102 | enum sst_hsw_module_id mod_id; | ||
103 | }; | ||
104 | |||
92 | /* private data for each PCM DSP stream */ | 105 | /* private data for each PCM DSP stream */ |
93 | struct hsw_pcm_data { | 106 | struct hsw_pcm_data { |
94 | int dai_id; | 107 | int dai_id; |
95 | struct sst_hsw_stream *stream; | 108 | struct sst_hsw_stream *stream; |
109 | struct sst_module_runtime *runtime; | ||
110 | struct sst_module_runtime_context context; | ||
111 | struct snd_pcm *hsw_pcm; | ||
96 | u32 volume[2]; | 112 | u32 volume[2]; |
97 | struct snd_pcm_substream *substream; | 113 | struct snd_pcm_substream *substream; |
98 | struct snd_compr_stream *cstream; | 114 | struct snd_compr_stream *cstream; |
99 | unsigned int wpos; | 115 | unsigned int wpos; |
100 | struct mutex mutex; | 116 | struct mutex mutex; |
101 | bool allocated; | 117 | bool allocated; |
118 | int persistent_offset; | ||
119 | }; | ||
120 | |||
121 | enum hsw_pm_state { | ||
122 | HSW_PM_STATE_D3 = 0, | ||
123 | HSW_PM_STATE_D0 = 1, | ||
102 | }; | 124 | }; |
103 | 125 | ||
104 | /* private data for the driver */ | 126 | /* private data for the driver */ |
105 | struct hsw_priv_data { | 127 | struct hsw_priv_data { |
106 | /* runtime DSP */ | 128 | /* runtime DSP */ |
107 | struct sst_hsw *hsw; | 129 | struct sst_hsw *hsw; |
130 | struct device *dev; | ||
131 | enum hsw_pm_state pm_state; | ||
132 | struct snd_soc_card *soc_card; | ||
108 | 133 | ||
109 | /* page tables */ | 134 | /* page tables */ |
110 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; | 135 | struct snd_dma_buffer dmab[HSW_PCM_COUNT][2]; |
@@ -138,21 +163,25 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) | |||
138 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | 163 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, |
139 | struct snd_ctl_elem_value *ucontrol) | 164 | struct snd_ctl_elem_value *ucontrol) |
140 | { | 165 | { |
141 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 166 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
142 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
143 | struct soc_mixer_control *mc = | 167 | struct soc_mixer_control *mc = |
144 | (struct soc_mixer_control *)kcontrol->private_value; | 168 | (struct soc_mixer_control *)kcontrol->private_value; |
169 | struct hsw_priv_data *pdata = | ||
170 | snd_soc_platform_get_drvdata(platform); | ||
145 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 171 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
146 | struct sst_hsw *hsw = pdata->hsw; | 172 | struct sst_hsw *hsw = pdata->hsw; |
147 | u32 volume; | 173 | u32 volume; |
148 | 174 | ||
149 | mutex_lock(&pcm_data->mutex); | 175 | mutex_lock(&pcm_data->mutex); |
176 | pm_runtime_get_sync(pdata->dev); | ||
150 | 177 | ||
151 | if (!pcm_data->stream) { | 178 | if (!pcm_data->stream) { |
152 | pcm_data->volume[0] = | 179 | pcm_data->volume[0] = |
153 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 180 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
154 | pcm_data->volume[1] = | 181 | pcm_data->volume[1] = |
155 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | 182 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); |
183 | pm_runtime_mark_last_busy(pdata->dev); | ||
184 | pm_runtime_put_autosuspend(pdata->dev); | ||
156 | mutex_unlock(&pcm_data->mutex); | 185 | mutex_unlock(&pcm_data->mutex); |
157 | return 0; | 186 | return 0; |
158 | } | 187 | } |
@@ -160,7 +189,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
160 | if (ucontrol->value.integer.value[0] == | 189 | if (ucontrol->value.integer.value[0] == |
161 | ucontrol->value.integer.value[1]) { | 190 | ucontrol->value.integer.value[1]) { |
162 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 191 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
163 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume); | 192 | /* apply volume value to all channels */ |
193 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, SST_HSW_CHANNELS_ALL, volume); | ||
164 | } else { | 194 | } else { |
165 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 195 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
166 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); | 196 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); |
@@ -168,6 +198,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
168 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); | 198 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); |
169 | } | 199 | } |
170 | 200 | ||
201 | pm_runtime_mark_last_busy(pdata->dev); | ||
202 | pm_runtime_put_autosuspend(pdata->dev); | ||
171 | mutex_unlock(&pcm_data->mutex); | 203 | mutex_unlock(&pcm_data->mutex); |
172 | return 0; | 204 | return 0; |
173 | } | 205 | } |
@@ -175,21 +207,25 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
175 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | 207 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, |
176 | struct snd_ctl_elem_value *ucontrol) | 208 | struct snd_ctl_elem_value *ucontrol) |
177 | { | 209 | { |
178 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 210 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
179 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
180 | struct soc_mixer_control *mc = | 211 | struct soc_mixer_control *mc = |
181 | (struct soc_mixer_control *)kcontrol->private_value; | 212 | (struct soc_mixer_control *)kcontrol->private_value; |
213 | struct hsw_priv_data *pdata = | ||
214 | snd_soc_platform_get_drvdata(platform); | ||
182 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 215 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
183 | struct sst_hsw *hsw = pdata->hsw; | 216 | struct sst_hsw *hsw = pdata->hsw; |
184 | u32 volume; | 217 | u32 volume; |
185 | 218 | ||
186 | mutex_lock(&pcm_data->mutex); | 219 | mutex_lock(&pcm_data->mutex); |
220 | pm_runtime_get_sync(pdata->dev); | ||
187 | 221 | ||
188 | if (!pcm_data->stream) { | 222 | if (!pcm_data->stream) { |
189 | ucontrol->value.integer.value[0] = | 223 | ucontrol->value.integer.value[0] = |
190 | hsw_ipc_to_mixer(pcm_data->volume[0]); | 224 | hsw_ipc_to_mixer(pcm_data->volume[0]); |
191 | ucontrol->value.integer.value[1] = | 225 | ucontrol->value.integer.value[1] = |
192 | hsw_ipc_to_mixer(pcm_data->volume[1]); | 226 | hsw_ipc_to_mixer(pcm_data->volume[1]); |
227 | pm_runtime_mark_last_busy(pdata->dev); | ||
228 | pm_runtime_put_autosuspend(pdata->dev); | ||
193 | mutex_unlock(&pcm_data->mutex); | 229 | mutex_unlock(&pcm_data->mutex); |
194 | return 0; | 230 | return 0; |
195 | } | 231 | } |
@@ -198,6 +234,9 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
198 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | 234 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); |
199 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); | 235 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); |
200 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | 236 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); |
237 | |||
238 | pm_runtime_mark_last_busy(pdata->dev); | ||
239 | pm_runtime_put_autosuspend(pdata->dev); | ||
201 | mutex_unlock(&pcm_data->mutex); | 240 | mutex_unlock(&pcm_data->mutex); |
202 | 241 | ||
203 | return 0; | 242 | return 0; |
@@ -206,16 +245,18 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
206 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, | 245 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, |
207 | struct snd_ctl_elem_value *ucontrol) | 246 | struct snd_ctl_elem_value *ucontrol) |
208 | { | 247 | { |
209 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 248 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
210 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | 249 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); |
211 | struct sst_hsw *hsw = pdata->hsw; | 250 | struct sst_hsw *hsw = pdata->hsw; |
212 | u32 volume; | 251 | u32 volume; |
213 | 252 | ||
253 | pm_runtime_get_sync(pdata->dev); | ||
254 | |||
214 | if (ucontrol->value.integer.value[0] == | 255 | if (ucontrol->value.integer.value[0] == |
215 | ucontrol->value.integer.value[1]) { | 256 | ucontrol->value.integer.value[1]) { |
216 | 257 | ||
217 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 258 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
218 | sst_hsw_mixer_set_volume(hsw, 0, 2, volume); | 259 | sst_hsw_mixer_set_volume(hsw, 0, SST_HSW_CHANNELS_ALL, volume); |
219 | 260 | ||
220 | } else { | 261 | } else { |
221 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | 262 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); |
@@ -225,23 +266,28 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, | |||
225 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); | 266 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); |
226 | } | 267 | } |
227 | 268 | ||
269 | pm_runtime_mark_last_busy(pdata->dev); | ||
270 | pm_runtime_put_autosuspend(pdata->dev); | ||
228 | return 0; | 271 | return 0; |
229 | } | 272 | } |
230 | 273 | ||
231 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, | 274 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, |
232 | struct snd_ctl_elem_value *ucontrol) | 275 | struct snd_ctl_elem_value *ucontrol) |
233 | { | 276 | { |
234 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | 277 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); |
235 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | 278 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); |
236 | struct sst_hsw *hsw = pdata->hsw; | 279 | struct sst_hsw *hsw = pdata->hsw; |
237 | unsigned int volume = 0; | 280 | unsigned int volume = 0; |
238 | 281 | ||
282 | pm_runtime_get_sync(pdata->dev); | ||
239 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); | 283 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); |
240 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | 284 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); |
241 | 285 | ||
242 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); | 286 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); |
243 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | 287 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); |
244 | 288 | ||
289 | pm_runtime_mark_last_busy(pdata->dev); | ||
290 | pm_runtime_put_autosuspend(pdata->dev); | ||
245 | return 0; | 291 | return 0; |
246 | } | 292 | } |
247 | 293 | ||
@@ -252,23 +298,19 @@ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | |||
252 | static const struct snd_kcontrol_new hsw_volume_controls[] = { | 298 | static const struct snd_kcontrol_new hsw_volume_controls[] = { |
253 | /* Global DSP volume */ | 299 | /* Global DSP volume */ |
254 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, | 300 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, |
255 | ARRAY_SIZE(volume_map) -1, 0, | 301 | ARRAY_SIZE(volume_map) - 1, 0, |
256 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), | 302 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), |
257 | /* Offload 0 volume */ | 303 | /* Offload 0 volume */ |
258 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, | 304 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, |
259 | ARRAY_SIZE(volume_map), 0, | 305 | ARRAY_SIZE(volume_map) - 1, 0, |
260 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 306 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
261 | /* Offload 1 volume */ | 307 | /* Offload 1 volume */ |
262 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, | 308 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, |
263 | ARRAY_SIZE(volume_map), 0, | 309 | ARRAY_SIZE(volume_map) - 1, 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), | 310 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
269 | /* Mic Capture volume */ | 311 | /* Mic Capture volume */ |
270 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | 312 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8, |
271 | ARRAY_SIZE(volume_map), 0, | 313 | ARRAY_SIZE(volume_map) - 1, 0, |
272 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | 314 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), |
273 | }; | 315 | }; |
274 | 316 | ||
@@ -354,8 +396,14 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
354 | /* DSP stream type depends on DAI ID */ | 396 | /* DSP stream type depends on DAI ID */ |
355 | switch (rtd->cpu_dai->id) { | 397 | switch (rtd->cpu_dai->id) { |
356 | case 0: | 398 | case 0: |
357 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; | 399 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
358 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | 400 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; |
401 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | ||
402 | } | ||
403 | else { | ||
404 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
405 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
406 | } | ||
359 | break; | 407 | break; |
360 | case 1: | 408 | case 1: |
361 | case 2: | 409 | case 2: |
@@ -368,10 +416,6 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
368 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | 416 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; |
369 | module_id = SST_HSW_MODULE_PCM_REFERENCE; | 417 | module_id = SST_HSW_MODULE_PCM_REFERENCE; |
370 | break; | 418 | break; |
371 | case 4: | ||
372 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
373 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
374 | break; | ||
375 | default: | 419 | default: |
376 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", | 420 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", |
377 | rtd->cpu_dai->id); | 421 | rtd->cpu_dai->id); |
@@ -421,13 +465,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
421 | return ret; | 465 | return ret; |
422 | } | 466 | } |
423 | 467 | ||
424 | /* we only support stereo atm */ | ||
425 | channels = params_channels(params); | 468 | channels = params_channels(params); |
426 | if (channels != 2) { | ||
427 | dev_err(rtd->dev, "error: invalid channels %d\n", channels); | ||
428 | return -EINVAL; | ||
429 | } | ||
430 | |||
431 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); | 469 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); |
432 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, | 470 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, |
433 | map, SST_HSW_CHANNEL_CONFIG_STEREO); | 471 | map, SST_HSW_CHANNEL_CONFIG_STEREO); |
@@ -478,35 +516,23 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | |||
478 | return -EINVAL; | 516 | return -EINVAL; |
479 | } | 517 | } |
480 | 518 | ||
481 | /* we use hardcoded memory offsets atm, will be updated for new FW */ | 519 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, |
482 | if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) { | 520 | pcm_data->runtime); |
483 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
484 | SST_HSW_MODULE_PCM_CAPTURE, module_data->entry); | ||
485 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
486 | 0x449400, 0x4000); | ||
487 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
488 | 0x400000, 0); | ||
489 | } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */ | ||
490 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
491 | SST_HSW_MODULE_PCM_SYSTEM, module_data->entry); | ||
492 | |||
493 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
494 | module_data->offset, module_data->size); | ||
495 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
496 | 0x44d400, 0x3800); | ||
497 | |||
498 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
499 | module_data->offset, module_data->size); | ||
500 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
501 | 0x400000, 0); | ||
502 | } | ||
503 | 521 | ||
504 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); | 522 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); |
505 | if (ret < 0) { | 523 | if (ret < 0) { |
506 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); | 524 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); |
507 | return ret; | 525 | return ret; |
508 | } | 526 | } |
509 | pcm_data->allocated = true; | 527 | |
528 | if (!pcm_data->allocated) { | ||
529 | /* Set previous saved volume */ | ||
530 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
531 | 0, pcm_data->volume[0]); | ||
532 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
533 | 1, pcm_data->volume[1]); | ||
534 | pcm_data->allocated = true; | ||
535 | } | ||
510 | 536 | ||
511 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); | 537 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); |
512 | if (ret < 0) | 538 | if (ret < 0) |
@@ -558,7 +584,7 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) | |||
558 | pos = frames_to_bytes(runtime, | 584 | pos = frames_to_bytes(runtime, |
559 | (runtime->control->appl_ptr % runtime->buffer_size)); | 585 | (runtime->control->appl_ptr % runtime->buffer_size)); |
560 | 586 | ||
561 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | 587 | dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); |
562 | 588 | ||
563 | /* let alsa know we have play a period */ | 589 | /* let alsa know we have play a period */ |
564 | snd_pcm_period_elapsed(substream); | 590 | snd_pcm_period_elapsed(substream); |
@@ -580,7 +606,7 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | |||
580 | offset = bytes_to_frames(runtime, position); | 606 | offset = bytes_to_frames(runtime, position); |
581 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); | 607 | ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream); |
582 | 608 | ||
583 | dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", | 609 | dev_vdbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n", |
584 | position, ppos); | 610 | position, ppos); |
585 | return offset; | 611 | return offset; |
586 | } | 612 | } |
@@ -596,6 +622,7 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
596 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | 622 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; |
597 | 623 | ||
598 | mutex_lock(&pcm_data->mutex); | 624 | mutex_lock(&pcm_data->mutex); |
625 | pm_runtime_get_sync(pdata->dev); | ||
599 | 626 | ||
600 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | 627 | snd_soc_pcm_set_drvdata(rtd, pcm_data); |
601 | pcm_data->substream = substream; | 628 | pcm_data->substream = substream; |
@@ -606,16 +633,12 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
606 | hsw_notify_pointer, pcm_data); | 633 | hsw_notify_pointer, pcm_data); |
607 | if (pcm_data->stream == NULL) { | 634 | if (pcm_data->stream == NULL) { |
608 | dev_err(rtd->dev, "error: failed to create stream\n"); | 635 | dev_err(rtd->dev, "error: failed to create stream\n"); |
636 | pm_runtime_mark_last_busy(pdata->dev); | ||
637 | pm_runtime_put_autosuspend(pdata->dev); | ||
609 | mutex_unlock(&pcm_data->mutex); | 638 | mutex_unlock(&pcm_data->mutex); |
610 | return -EINVAL; | 639 | return -EINVAL; |
611 | } | 640 | } |
612 | 641 | ||
613 | /* Set previous saved volume */ | ||
614 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
615 | 0, pcm_data->volume[0]); | ||
616 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
617 | 1, pcm_data->volume[1]); | ||
618 | |||
619 | mutex_unlock(&pcm_data->mutex); | 642 | mutex_unlock(&pcm_data->mutex); |
620 | return 0; | 643 | return 0; |
621 | } | 644 | } |
@@ -645,6 +668,8 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream) | |||
645 | pcm_data->stream = NULL; | 668 | pcm_data->stream = NULL; |
646 | 669 | ||
647 | out: | 670 | out: |
671 | pm_runtime_mark_last_busy(pdata->dev); | ||
672 | pm_runtime_put_autosuspend(pdata->dev); | ||
648 | mutex_unlock(&pcm_data->mutex); | 673 | mutex_unlock(&pcm_data->mutex); |
649 | return ret; | 674 | return ret; |
650 | } | 675 | } |
@@ -660,6 +685,56 @@ static struct snd_pcm_ops hsw_pcm_ops = { | |||
660 | .page = snd_pcm_sgbuf_ops_page, | 685 | .page = snd_pcm_sgbuf_ops_page, |
661 | }; | 686 | }; |
662 | 687 | ||
688 | /* static mappings between PCMs and modules - may be dynamic in future */ | ||
689 | static struct hsw_pcm_module_map mod_map[] = { | ||
690 | {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM}, | ||
691 | {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM}, | ||
692 | {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM}, | ||
693 | {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE}, | ||
694 | {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE}, | ||
695 | }; | ||
696 | |||
697 | static int hsw_pcm_create_modules(struct hsw_priv_data *pdata) | ||
698 | { | ||
699 | struct sst_hsw *hsw = pdata->hsw; | ||
700 | struct hsw_pcm_data *pcm_data; | ||
701 | int i; | ||
702 | |||
703 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | ||
704 | pcm_data = &pdata->pcm[i]; | ||
705 | |||
706 | /* create new runtime module, use same offset if recreated */ | ||
707 | pcm_data->runtime = sst_hsw_runtime_module_create(hsw, | ||
708 | mod_map[i].mod_id, pcm_data->persistent_offset); | ||
709 | if (pcm_data->runtime == NULL) | ||
710 | goto err; | ||
711 | pcm_data->persistent_offset = | ||
712 | pcm_data->runtime->persistent_offset; | ||
713 | } | ||
714 | |||
715 | return 0; | ||
716 | |||
717 | err: | ||
718 | for (--i; i >= 0; i--) { | ||
719 | pcm_data = &pdata->pcm[i]; | ||
720 | sst_hsw_runtime_module_free(pcm_data->runtime); | ||
721 | } | ||
722 | |||
723 | return -ENODEV; | ||
724 | } | ||
725 | |||
726 | static void hsw_pcm_free_modules(struct hsw_priv_data *pdata) | ||
727 | { | ||
728 | struct hsw_pcm_data *pcm_data; | ||
729 | int i; | ||
730 | |||
731 | for (i = 0; i < ARRAY_SIZE(mod_map); i++) { | ||
732 | pcm_data = &pdata->pcm[i]; | ||
733 | |||
734 | sst_hsw_runtime_module_free(pcm_data->runtime); | ||
735 | } | ||
736 | } | ||
737 | |||
663 | static void hsw_pcm_free(struct snd_pcm *pcm) | 738 | static void hsw_pcm_free(struct snd_pcm *pcm) |
664 | { | 739 | { |
665 | snd_pcm_lib_preallocate_free_for_all(pcm); | 740 | snd_pcm_lib_preallocate_free_for_all(pcm); |
@@ -670,6 +745,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
670 | struct snd_pcm *pcm = rtd->pcm; | 745 | struct snd_pcm *pcm = rtd->pcm; |
671 | struct snd_soc_platform *platform = rtd->platform; | 746 | struct snd_soc_platform *platform = rtd->platform; |
672 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 747 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
748 | struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev); | ||
673 | struct device *dev = pdata->dma_dev; | 749 | struct device *dev = pdata->dma_dev; |
674 | int ret = 0; | 750 | int ret = 0; |
675 | 751 | ||
@@ -686,6 +762,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
686 | return ret; | 762 | return ret; |
687 | } | 763 | } |
688 | } | 764 | } |
765 | priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm; | ||
689 | 766 | ||
690 | return ret; | 767 | return ret; |
691 | } | 768 | } |
@@ -696,6 +773,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
696 | static struct snd_soc_dai_driver hsw_dais[] = { | 773 | static struct snd_soc_dai_driver hsw_dais[] = { |
697 | { | 774 | { |
698 | .name = "System Pin", | 775 | .name = "System Pin", |
776 | .id = HSW_PCM_DAI_ID_SYSTEM, | ||
699 | .playback = { | 777 | .playback = { |
700 | .stream_name = "System Playback", | 778 | .stream_name = "System Playback", |
701 | .channels_min = 2, | 779 | .channels_min = 2, |
@@ -703,10 +781,18 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
703 | .rates = SNDRV_PCM_RATE_48000, | 781 | .rates = SNDRV_PCM_RATE_48000, |
704 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | 782 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
705 | }, | 783 | }, |
784 | .capture = { | ||
785 | .stream_name = "Analog Capture", | ||
786 | .channels_min = 2, | ||
787 | .channels_max = 4, | ||
788 | .rates = SNDRV_PCM_RATE_48000, | ||
789 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
790 | }, | ||
706 | }, | 791 | }, |
707 | { | 792 | { |
708 | /* PCM */ | 793 | /* PCM */ |
709 | .name = "Offload0 Pin", | 794 | .name = "Offload0 Pin", |
795 | .id = HSW_PCM_DAI_ID_OFFLOAD0, | ||
710 | .playback = { | 796 | .playback = { |
711 | .stream_name = "Offload0 Playback", | 797 | .stream_name = "Offload0 Playback", |
712 | .channels_min = 2, | 798 | .channels_min = 2, |
@@ -718,6 +804,7 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
718 | { | 804 | { |
719 | /* PCM */ | 805 | /* PCM */ |
720 | .name = "Offload1 Pin", | 806 | .name = "Offload1 Pin", |
807 | .id = HSW_PCM_DAI_ID_OFFLOAD1, | ||
721 | .playback = { | 808 | .playback = { |
722 | .stream_name = "Offload1 Playback", | 809 | .stream_name = "Offload1 Playback", |
723 | .channels_min = 2, | 810 | .channels_min = 2, |
@@ -728,6 +815,7 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
728 | }, | 815 | }, |
729 | { | 816 | { |
730 | .name = "Loopback Pin", | 817 | .name = "Loopback Pin", |
818 | .id = HSW_PCM_DAI_ID_LOOPBACK, | ||
731 | .capture = { | 819 | .capture = { |
732 | .stream_name = "Loopback Capture", | 820 | .stream_name = "Loopback Capture", |
733 | .channels_min = 2, | 821 | .channels_min = 2, |
@@ -736,16 +824,6 @@ static struct snd_soc_dai_driver hsw_dais[] = { | |||
736 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | 824 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, |
737 | }, | 825 | }, |
738 | }, | 826 | }, |
739 | { | ||
740 | .name = "Capture Pin", | ||
741 | .capture = { | ||
742 | .stream_name = "Analog Capture", | ||
743 | .channels_min = 2, | ||
744 | .channels_max = 2, | ||
745 | .rates = SNDRV_PCM_RATE_48000, | ||
746 | .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
747 | }, | ||
748 | }, | ||
749 | }; | 827 | }; |
750 | 828 | ||
751 | static const struct snd_soc_dapm_widget widgets[] = { | 829 | static const struct snd_soc_dapm_widget widgets[] = { |
@@ -776,9 +854,20 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
776 | { | 854 | { |
777 | struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); | 855 | struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); |
778 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 856 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
779 | struct device *dma_dev = pdata->dma_dev; | 857 | struct device *dma_dev, *dev; |
780 | int i, ret = 0; | 858 | int i, ret = 0; |
781 | 859 | ||
860 | if (!pdata) | ||
861 | return -ENODEV; | ||
862 | |||
863 | dev = platform->dev; | ||
864 | dma_dev = pdata->dma_dev; | ||
865 | |||
866 | priv_data->hsw = pdata->dsp; | ||
867 | priv_data->dev = platform->dev; | ||
868 | priv_data->pm_state = HSW_PM_STATE_D0; | ||
869 | priv_data->soc_card = platform->component.card; | ||
870 | |||
782 | /* allocate DSP buffer page tables */ | 871 | /* allocate DSP buffer page tables */ |
783 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 872 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
784 | 873 | ||
@@ -801,6 +890,16 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform) | |||
801 | } | 890 | } |
802 | } | 891 | } |
803 | 892 | ||
893 | /* allocate runtime modules */ | ||
894 | hsw_pcm_create_modules(priv_data); | ||
895 | |||
896 | /* enable runtime PM with auto suspend */ | ||
897 | pm_runtime_set_autosuspend_delay(platform->dev, | ||
898 | SST_RUNTIME_SUSPEND_DELAY); | ||
899 | pm_runtime_use_autosuspend(platform->dev); | ||
900 | pm_runtime_enable(platform->dev); | ||
901 | pm_runtime_idle(platform->dev); | ||
902 | |||
804 | return 0; | 903 | return 0; |
805 | 904 | ||
806 | err: | 905 | err: |
@@ -819,6 +918,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform) | |||
819 | snd_soc_platform_get_drvdata(platform); | 918 | snd_soc_platform_get_drvdata(platform); |
820 | int i; | 919 | int i; |
821 | 920 | ||
921 | pm_runtime_disable(platform->dev); | ||
922 | hsw_pcm_free_modules(priv_data); | ||
923 | |||
822 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 924 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
823 | if (hsw_dais[i].playback.channels_min) | 925 | if (hsw_dais[i].playback.channels_min) |
824 | snd_dma_free_pages(&priv_data->dmab[i][0]); | 926 | snd_dma_free_pages(&priv_data->dmab[i][0]); |
@@ -896,10 +998,181 @@ static int hsw_pcm_dev_remove(struct platform_device *pdev) | |||
896 | return 0; | 998 | return 0; |
897 | } | 999 | } |
898 | 1000 | ||
1001 | #ifdef CONFIG_PM_RUNTIME | ||
1002 | |||
1003 | static int hsw_pcm_runtime_idle(struct device *dev) | ||
1004 | { | ||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | static int hsw_pcm_runtime_suspend(struct device *dev) | ||
1009 | { | ||
1010 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1011 | struct sst_hsw *hsw = pdata->hsw; | ||
1012 | |||
1013 | if (pdata->pm_state == HSW_PM_STATE_D3) | ||
1014 | return 0; | ||
1015 | |||
1016 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1017 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1018 | pdata->pm_state = HSW_PM_STATE_D3; | ||
1019 | |||
1020 | return 0; | ||
1021 | } | ||
1022 | |||
1023 | static int hsw_pcm_runtime_resume(struct device *dev) | ||
1024 | { | ||
1025 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1026 | struct sst_hsw *hsw = pdata->hsw; | ||
1027 | int ret; | ||
1028 | |||
1029 | if (pdata->pm_state == HSW_PM_STATE_D0) | ||
1030 | return 0; | ||
1031 | |||
1032 | ret = sst_hsw_dsp_load(hsw); | ||
1033 | if (ret < 0) { | ||
1034 | dev_err(dev, "failed to reload %d\n", ret); | ||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | ret = hsw_pcm_create_modules(pdata); | ||
1039 | if (ret < 0) { | ||
1040 | dev_err(dev, "failed to create modules %d\n", ret); | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | ret = sst_hsw_dsp_runtime_resume(hsw); | ||
1045 | if (ret < 0) | ||
1046 | return ret; | ||
1047 | else if (ret == 1) /* no action required */ | ||
1048 | return 0; | ||
1049 | |||
1050 | pdata->pm_state = HSW_PM_STATE_D0; | ||
1051 | return ret; | ||
1052 | } | ||
1053 | |||
1054 | #else | ||
1055 | #define hsw_pcm_runtime_idle NULL | ||
1056 | #define hsw_pcm_runtime_suspend NULL | ||
1057 | #define hsw_pcm_runtime_resume NULL | ||
1058 | #endif | ||
1059 | |||
1060 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_RUNTIME) | ||
1061 | |||
1062 | static void hsw_pcm_complete(struct device *dev) | ||
1063 | { | ||
1064 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1065 | struct sst_hsw *hsw = pdata->hsw; | ||
1066 | struct hsw_pcm_data *pcm_data; | ||
1067 | int i, err; | ||
1068 | |||
1069 | if (pdata->pm_state == HSW_PM_STATE_D0) | ||
1070 | return; | ||
1071 | |||
1072 | err = sst_hsw_dsp_load(hsw); | ||
1073 | if (err < 0) { | ||
1074 | dev_err(dev, "failed to reload %d\n", err); | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | err = hsw_pcm_create_modules(pdata); | ||
1079 | if (err < 0) { | ||
1080 | dev_err(dev, "failed to create modules %d\n", err); | ||
1081 | return; | ||
1082 | } | ||
1083 | |||
1084 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1085 | pcm_data = &pdata->pcm[i]; | ||
1086 | |||
1087 | if (!pcm_data->substream) | ||
1088 | continue; | ||
1089 | |||
1090 | err = sst_module_runtime_restore(pcm_data->runtime, | ||
1091 | &pcm_data->context); | ||
1092 | if (err < 0) | ||
1093 | dev_err(dev, "failed to restore context for PCM %d\n", i); | ||
1094 | } | ||
1095 | |||
1096 | snd_soc_resume(pdata->soc_card->dev); | ||
1097 | |||
1098 | err = sst_hsw_dsp_runtime_resume(hsw); | ||
1099 | if (err < 0) | ||
1100 | return; | ||
1101 | else if (err == 1) /* no action required */ | ||
1102 | return; | ||
1103 | |||
1104 | pdata->pm_state = HSW_PM_STATE_D0; | ||
1105 | return; | ||
1106 | } | ||
1107 | |||
1108 | static int hsw_pcm_prepare(struct device *dev) | ||
1109 | { | ||
1110 | struct hsw_priv_data *pdata = dev_get_drvdata(dev); | ||
1111 | struct sst_hsw *hsw = pdata->hsw; | ||
1112 | struct hsw_pcm_data *pcm_data; | ||
1113 | int i, err; | ||
1114 | |||
1115 | if (pdata->pm_state == HSW_PM_STATE_D3) | ||
1116 | return 0; | ||
1117 | /* suspend all active streams */ | ||
1118 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1119 | pcm_data = &pdata->pcm[i]; | ||
1120 | |||
1121 | if (!pcm_data->substream) | ||
1122 | continue; | ||
1123 | dev_dbg(dev, "suspending pcm %d\n", i); | ||
1124 | snd_pcm_suspend_all(pcm_data->hsw_pcm); | ||
1125 | |||
1126 | /* We need to wait until the DSP FW stops the streams */ | ||
1127 | msleep(2); | ||
1128 | } | ||
1129 | |||
1130 | snd_soc_suspend(pdata->soc_card->dev); | ||
1131 | snd_soc_poweroff(pdata->soc_card->dev); | ||
1132 | |||
1133 | /* enter D3 state and stall */ | ||
1134 | sst_hsw_dsp_runtime_suspend(hsw); | ||
1135 | |||
1136 | /* preserve persistent memory */ | ||
1137 | for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) { | ||
1138 | pcm_data = &pdata->pcm[i]; | ||
1139 | |||
1140 | if (!pcm_data->substream) | ||
1141 | continue; | ||
1142 | |||
1143 | dev_dbg(dev, "saving context pcm %d\n", i); | ||
1144 | err = sst_module_runtime_save(pcm_data->runtime, | ||
1145 | &pcm_data->context); | ||
1146 | if (err < 0) | ||
1147 | dev_err(dev, "failed to save context for PCM %d\n", i); | ||
1148 | } | ||
1149 | |||
1150 | /* put the DSP to sleep */ | ||
1151 | sst_hsw_dsp_runtime_sleep(hsw); | ||
1152 | pdata->pm_state = HSW_PM_STATE_D3; | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | #else | ||
1158 | #define hsw_pcm_prepare NULL | ||
1159 | #define hsw_pcm_complete NULL | ||
1160 | #endif | ||
1161 | |||
1162 | static const struct dev_pm_ops hsw_pcm_pm = { | ||
1163 | .runtime_idle = hsw_pcm_runtime_idle, | ||
1164 | .runtime_suspend = hsw_pcm_runtime_suspend, | ||
1165 | .runtime_resume = hsw_pcm_runtime_resume, | ||
1166 | .prepare = hsw_pcm_prepare, | ||
1167 | .complete = hsw_pcm_complete, | ||
1168 | }; | ||
1169 | |||
899 | static struct platform_driver hsw_pcm_driver = { | 1170 | static struct platform_driver hsw_pcm_driver = { |
900 | .driver = { | 1171 | .driver = { |
901 | .name = "haswell-pcm-audio", | 1172 | .name = "haswell-pcm-audio", |
902 | .owner = THIS_MODULE, | 1173 | .owner = THIS_MODULE, |
1174 | .pm = &hsw_pcm_pm, | ||
1175 | |||
903 | }, | 1176 | }, |
904 | 1177 | ||
905 | .probe = hsw_pcm_dev_probe, | 1178 | .probe = hsw_pcm_dev_probe, |
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 59467775c9b8..395168986462 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c | |||
@@ -67,8 +67,11 @@ static int sst_platform_compr_open(struct snd_compr_stream *cstream) | |||
67 | goto out_ops; | 67 | goto out_ops; |
68 | } | 68 | } |
69 | stream->compr_ops = sst->compr_ops; | 69 | stream->compr_ops = sst->compr_ops; |
70 | |||
71 | stream->id = 0; | 70 | stream->id = 0; |
71 | |||
72 | /* Turn on LPE */ | ||
73 | sst->compr_ops->power(sst->dev, true); | ||
74 | |||
72 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 75 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
73 | runtime->private_data = stream; | 76 | runtime->private_data = stream; |
74 | return 0; | 77 | return 0; |
@@ -83,6 +86,9 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) | |||
83 | int ret_val = 0, str_id; | 86 | int ret_val = 0, str_id; |
84 | 87 | ||
85 | stream = cstream->runtime->private_data; | 88 | stream = cstream->runtime->private_data; |
89 | /* Turn off LPE */ | ||
90 | sst->compr_ops->power(sst->dev, false); | ||
91 | |||
86 | /*need to check*/ | 92 | /*need to check*/ |
87 | str_id = stream->id; | 93 | str_id = stream->id; |
88 | if (str_id) | 94 | if (str_id) |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index aa9b600dfc9b..6032f18693be 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -101,35 +101,11 @@ static struct sst_dev_stream_map dpcm_strm_map[] = { | |||
101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, | 101 | {MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0}, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | /* MFLD - MSIC */ | 104 | static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream) |
105 | static struct snd_soc_dai_driver sst_platform_dai[] = { | ||
106 | { | 105 | { |
107 | .name = "Headset-cpu-dai", | 106 | |
108 | .id = 0, | 107 | return sst_send_pipe_gains(dai, stream, mute); |
109 | .playback = { | 108 | } |
110 | .channels_min = SST_STEREO, | ||
111 | .channels_max = SST_STEREO, | ||
112 | .rates = SNDRV_PCM_RATE_48000, | ||
113 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
114 | }, | ||
115 | .capture = { | ||
116 | .channels_min = 1, | ||
117 | .channels_max = 5, | ||
118 | .rates = SNDRV_PCM_RATE_48000, | ||
119 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
120 | }, | ||
121 | }, | ||
122 | { | ||
123 | .name = "Compress-cpu-dai", | ||
124 | .compress_dai = 1, | ||
125 | .playback = { | ||
126 | .channels_min = SST_STEREO, | ||
127 | .channels_max = SST_STEREO, | ||
128 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
129 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
130 | }, | ||
131 | }, | ||
132 | }; | ||
133 | 109 | ||
134 | /* helper functions */ | 110 | /* helper functions */ |
135 | void sst_set_stream_status(struct sst_runtime_stream *stream, | 111 | void sst_set_stream_status(struct sst_runtime_stream *stream, |
@@ -451,12 +427,133 @@ static int sst_media_hw_free(struct snd_pcm_substream *substream, | |||
451 | return snd_pcm_lib_free_pages(substream); | 427 | return snd_pcm_lib_free_pages(substream); |
452 | } | 428 | } |
453 | 429 | ||
430 | static int sst_enable_ssp(struct snd_pcm_substream *substream, | ||
431 | struct snd_soc_dai *dai) | ||
432 | { | ||
433 | int ret = 0; | ||
434 | |||
435 | if (!dai->active) { | ||
436 | ret = sst_handle_vb_timer(dai, true); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | ret = send_ssp_cmd(dai, dai->name, 1); | ||
440 | } | ||
441 | return ret; | ||
442 | } | ||
443 | |||
444 | static void sst_disable_ssp(struct snd_pcm_substream *substream, | ||
445 | struct snd_soc_dai *dai) | ||
446 | { | ||
447 | if (!dai->active) { | ||
448 | send_ssp_cmd(dai, dai->name, 0); | ||
449 | sst_handle_vb_timer(dai, false); | ||
450 | } | ||
451 | } | ||
452 | |||
454 | static struct snd_soc_dai_ops sst_media_dai_ops = { | 453 | static struct snd_soc_dai_ops sst_media_dai_ops = { |
455 | .startup = sst_media_open, | 454 | .startup = sst_media_open, |
456 | .shutdown = sst_media_close, | 455 | .shutdown = sst_media_close, |
457 | .prepare = sst_media_prepare, | 456 | .prepare = sst_media_prepare, |
458 | .hw_params = sst_media_hw_params, | 457 | .hw_params = sst_media_hw_params, |
459 | .hw_free = sst_media_hw_free, | 458 | .hw_free = sst_media_hw_free, |
459 | .mute_stream = sst_media_digital_mute, | ||
460 | }; | ||
461 | |||
462 | static struct snd_soc_dai_ops sst_compr_dai_ops = { | ||
463 | .mute_stream = sst_media_digital_mute, | ||
464 | }; | ||
465 | |||
466 | static struct snd_soc_dai_ops sst_be_dai_ops = { | ||
467 | .startup = sst_enable_ssp, | ||
468 | .shutdown = sst_disable_ssp, | ||
469 | }; | ||
470 | |||
471 | static struct snd_soc_dai_driver sst_platform_dai[] = { | ||
472 | { | ||
473 | .name = "media-cpu-dai", | ||
474 | .ops = &sst_media_dai_ops, | ||
475 | .playback = { | ||
476 | .stream_name = "Headset Playback", | ||
477 | .channels_min = SST_STEREO, | ||
478 | .channels_max = SST_STEREO, | ||
479 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
480 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
481 | }, | ||
482 | .capture = { | ||
483 | .stream_name = "Headset Capture", | ||
484 | .channels_min = 1, | ||
485 | .channels_max = 2, | ||
486 | .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000, | ||
487 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
488 | }, | ||
489 | }, | ||
490 | { | ||
491 | .name = "compress-cpu-dai", | ||
492 | .compress_dai = 1, | ||
493 | .ops = &sst_compr_dai_ops, | ||
494 | .playback = { | ||
495 | .stream_name = "Compress Playback", | ||
496 | .channels_min = SST_STEREO, | ||
497 | .channels_max = SST_STEREO, | ||
498 | .rates = SNDRV_PCM_RATE_48000, | ||
499 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
500 | }, | ||
501 | }, | ||
502 | /* BE CPU Dais */ | ||
503 | { | ||
504 | .name = "ssp0-port", | ||
505 | .ops = &sst_be_dai_ops, | ||
506 | .playback = { | ||
507 | .stream_name = "ssp0 Tx", | ||
508 | .channels_min = SST_STEREO, | ||
509 | .channels_max = SST_STEREO, | ||
510 | .rates = SNDRV_PCM_RATE_48000, | ||
511 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
512 | }, | ||
513 | .capture = { | ||
514 | .stream_name = "ssp0 Rx", | ||
515 | .channels_min = SST_STEREO, | ||
516 | .channels_max = SST_STEREO, | ||
517 | .rates = SNDRV_PCM_RATE_48000, | ||
518 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
519 | }, | ||
520 | }, | ||
521 | { | ||
522 | .name = "ssp1-port", | ||
523 | .ops = &sst_be_dai_ops, | ||
524 | .playback = { | ||
525 | .stream_name = "ssp1 Tx", | ||
526 | .channels_min = SST_STEREO, | ||
527 | .channels_max = SST_STEREO, | ||
528 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, | ||
529 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
530 | }, | ||
531 | .capture = { | ||
532 | .stream_name = "ssp1 Rx", | ||
533 | .channels_min = SST_STEREO, | ||
534 | .channels_max = SST_STEREO, | ||
535 | .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, | ||
536 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
537 | }, | ||
538 | }, | ||
539 | { | ||
540 | .name = "ssp2-port", | ||
541 | .ops = &sst_be_dai_ops, | ||
542 | .playback = { | ||
543 | .stream_name = "ssp2 Tx", | ||
544 | .channels_min = SST_STEREO, | ||
545 | .channels_max = SST_STEREO, | ||
546 | .rates = SNDRV_PCM_RATE_48000, | ||
547 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
548 | }, | ||
549 | .capture = { | ||
550 | .stream_name = "ssp2 Rx", | ||
551 | .channels_min = SST_STEREO, | ||
552 | .channels_max = SST_STEREO, | ||
553 | .rates = SNDRV_PCM_RATE_48000, | ||
554 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
555 | }, | ||
556 | }, | ||
460 | }; | 557 | }; |
461 | 558 | ||
462 | static int sst_platform_open(struct snd_pcm_substream *substream) | 559 | static int sst_platform_open(struct snd_pcm_substream *substream) |
@@ -609,6 +706,7 @@ static int sst_platform_probe(struct platform_device *pdev) | |||
609 | pdata->pdev_strm_map = dpcm_strm_map; | 706 | pdata->pdev_strm_map = dpcm_strm_map; |
610 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); | 707 | pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map); |
611 | drv->pdata = pdata; | 708 | drv->pdata = pdata; |
709 | drv->pdev = pdev; | ||
612 | mutex_init(&drv->lock); | 710 | mutex_init(&drv->lock); |
613 | dev_set_drvdata(&pdev->dev, drv); | 711 | dev_set_drvdata(&pdev->dev, drv); |
614 | 712 | ||
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 19f83ec51613..79c8d1246a8f 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
@@ -117,6 +117,7 @@ struct compress_sst_ops { | |||
117 | int (*get_codec_caps)(struct snd_compr_codec_caps *codec); | 117 | int (*get_codec_caps)(struct snd_compr_codec_caps *codec); |
118 | int (*set_metadata)(struct device *dev, unsigned int str_id, | 118 | int (*set_metadata)(struct device *dev, unsigned int str_id, |
119 | struct snd_compr_metadata *mdata); | 119 | struct snd_compr_metadata *mdata); |
120 | int (*power)(struct device *dev, bool state); | ||
120 | }; | 121 | }; |
121 | 122 | ||
122 | struct sst_ops { | 123 | struct sst_ops { |
@@ -153,6 +154,10 @@ struct sst_device { | |||
153 | struct sst_data; | 154 | struct sst_data; |
154 | 155 | ||
155 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); | 156 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); |
157 | int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute); | ||
158 | int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable); | ||
159 | int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable); | ||
160 | |||
156 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); | 161 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); |
157 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, | 162 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, |
158 | struct snd_sst_params *str_params, bool is_compress); | 163 | struct snd_sst_params *str_params, bool is_compress); |
diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/sst/Makefile new file mode 100644 index 000000000000..fd21726361b5 --- /dev/null +++ b/sound/soc/intel/sst/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o | ||
2 | snd-intel-sst-pci-objs += sst_pci.o | ||
3 | snd-intel-sst-acpi-objs += sst_acpi.o | ||
4 | |||
5 | obj-$(CONFIG_SND_SST_IPC) += snd-intel-sst-core.o | ||
6 | obj-$(CONFIG_SND_SST_IPC_PCI) += snd-intel-sst-pci.o | ||
7 | obj-$(CONFIG_SND_SST_IPC_ACPI) += snd-intel-sst-acpi.o | ||
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c new file mode 100644 index 000000000000..8a8d56a146e7 --- /dev/null +++ b/sound/soc/intel/sst/sst.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * sst.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/pm_qos.h> | ||
28 | #include <linux/async.h> | ||
29 | #include <linux/acpi.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
38 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
39 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver"); | ||
40 | MODULE_LICENSE("GPL v2"); | ||
41 | |||
42 | static inline bool sst_is_process_reply(u32 msg_id) | ||
43 | { | ||
44 | return ((msg_id & PROCESS_MSG) ? true : false); | ||
45 | } | ||
46 | |||
47 | static inline bool sst_validate_mailbox_size(unsigned int size) | ||
48 | { | ||
49 | return ((size <= SST_MAILBOX_SIZE) ? true : false); | ||
50 | } | ||
51 | |||
52 | static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context) | ||
53 | { | ||
54 | union interrupt_reg_mrfld isr; | ||
55 | union ipc_header_mrfld header; | ||
56 | union sst_imr_reg_mrfld imr; | ||
57 | struct ipc_post *msg = NULL; | ||
58 | unsigned int size = 0; | ||
59 | struct intel_sst_drv *drv = (struct intel_sst_drv *) context; | ||
60 | irqreturn_t retval = IRQ_HANDLED; | ||
61 | |||
62 | /* Interrupt arrived, check src */ | ||
63 | isr.full = sst_shim_read64(drv->shim, SST_ISRX); | ||
64 | |||
65 | if (isr.part.done_interrupt) { | ||
66 | /* Clear done bit */ | ||
67 | spin_lock(&drv->ipc_spin_lock); | ||
68 | header.full = sst_shim_read64(drv->shim, | ||
69 | drv->ipc_reg.ipcx); | ||
70 | header.p.header_high.part.done = 0; | ||
71 | sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full); | ||
72 | |||
73 | /* write 1 to clear status register */; | ||
74 | isr.part.done_interrupt = 1; | ||
75 | sst_shim_write64(drv->shim, SST_ISRX, isr.full); | ||
76 | spin_unlock(&drv->ipc_spin_lock); | ||
77 | |||
78 | /* we can send more messages to DSP so trigger work */ | ||
79 | queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq); | ||
80 | retval = IRQ_HANDLED; | ||
81 | } | ||
82 | |||
83 | if (isr.part.busy_interrupt) { | ||
84 | /* message from dsp so copy that */ | ||
85 | spin_lock(&drv->ipc_spin_lock); | ||
86 | imr.full = sst_shim_read64(drv->shim, SST_IMRX); | ||
87 | imr.part.busy_interrupt = 1; | ||
88 | sst_shim_write64(drv->shim, SST_IMRX, imr.full); | ||
89 | spin_unlock(&drv->ipc_spin_lock); | ||
90 | header.full = sst_shim_read64(drv->shim, drv->ipc_reg.ipcd); | ||
91 | |||
92 | if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) { | ||
93 | drv->ops->clear_interrupt(drv); | ||
94 | return IRQ_HANDLED; | ||
95 | } | ||
96 | |||
97 | if (header.p.header_high.part.large) { | ||
98 | size = header.p.header_low_payload; | ||
99 | if (sst_validate_mailbox_size(size)) { | ||
100 | memcpy_fromio(msg->mailbox_data, | ||
101 | drv->mailbox + drv->mailbox_recv_offset, size); | ||
102 | } else { | ||
103 | dev_err(drv->dev, | ||
104 | "Mailbox not copied, payload size is: %u\n", size); | ||
105 | header.p.header_low_payload = 0; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | msg->mrfld_header = header; | ||
110 | msg->is_process_reply = | ||
111 | sst_is_process_reply(header.p.header_high.part.msg_id); | ||
112 | spin_lock(&drv->rx_msg_lock); | ||
113 | list_add_tail(&msg->node, &drv->rx_list); | ||
114 | spin_unlock(&drv->rx_msg_lock); | ||
115 | drv->ops->clear_interrupt(drv); | ||
116 | retval = IRQ_WAKE_THREAD; | ||
117 | } | ||
118 | return retval; | ||
119 | } | ||
120 | |||
121 | static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context) | ||
122 | { | ||
123 | struct intel_sst_drv *drv = (struct intel_sst_drv *) context; | ||
124 | struct ipc_post *__msg, *msg = NULL; | ||
125 | unsigned long irq_flags; | ||
126 | |||
127 | spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); | ||
128 | if (list_empty(&drv->rx_list)) { | ||
129 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
130 | return IRQ_HANDLED; | ||
131 | } | ||
132 | |||
133 | list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) { | ||
134 | list_del(&msg->node); | ||
135 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
136 | if (msg->is_process_reply) | ||
137 | drv->ops->process_message(msg); | ||
138 | else | ||
139 | drv->ops->process_reply(drv, msg); | ||
140 | |||
141 | if (msg->is_large) | ||
142 | kfree(msg->mailbox_data); | ||
143 | kfree(msg); | ||
144 | spin_lock_irqsave(&drv->rx_msg_lock, irq_flags); | ||
145 | } | ||
146 | spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags); | ||
147 | return IRQ_HANDLED; | ||
148 | } | ||
149 | |||
150 | static int sst_save_dsp_context_v2(struct intel_sst_drv *sst) | ||
151 | { | ||
152 | int ret = 0; | ||
153 | |||
154 | ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD, | ||
155 | IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL, | ||
156 | true, true, false, true); | ||
157 | |||
158 | if (ret < 0) { | ||
159 | dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret); | ||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | |||
167 | static struct intel_sst_ops mrfld_ops = { | ||
168 | .interrupt = intel_sst_interrupt_mrfld, | ||
169 | .irq_thread = intel_sst_irq_thread_mrfld, | ||
170 | .clear_interrupt = intel_sst_clear_intr_mrfld, | ||
171 | .start = sst_start_mrfld, | ||
172 | .reset = intel_sst_reset_dsp_mrfld, | ||
173 | .post_message = sst_post_message_mrfld, | ||
174 | .process_reply = sst_process_reply_mrfld, | ||
175 | .save_dsp_context = sst_save_dsp_context_v2, | ||
176 | .alloc_stream = sst_alloc_stream_mrfld, | ||
177 | .post_download = sst_post_download_mrfld, | ||
178 | }; | ||
179 | |||
180 | int sst_driver_ops(struct intel_sst_drv *sst) | ||
181 | { | ||
182 | |||
183 | switch (sst->dev_id) { | ||
184 | case SST_MRFLD_PCI_ID: | ||
185 | case SST_BYT_ACPI_ID: | ||
186 | case SST_CHV_ACPI_ID: | ||
187 | sst->tstamp = SST_TIME_STAMP_MRFLD; | ||
188 | sst->ops = &mrfld_ops; | ||
189 | return 0; | ||
190 | |||
191 | default: | ||
192 | dev_err(sst->dev, | ||
193 | "SST Driver capablities missing for dev_id: %x", sst->dev_id); | ||
194 | return -EINVAL; | ||
195 | }; | ||
196 | } | ||
197 | |||
198 | void sst_process_pending_msg(struct work_struct *work) | ||
199 | { | ||
200 | struct intel_sst_drv *ctx = container_of(work, | ||
201 | struct intel_sst_drv, ipc_post_msg_wq); | ||
202 | |||
203 | ctx->ops->post_message(ctx, NULL, false); | ||
204 | } | ||
205 | |||
206 | static int sst_workqueue_init(struct intel_sst_drv *ctx) | ||
207 | { | ||
208 | INIT_LIST_HEAD(&ctx->memcpy_list); | ||
209 | INIT_LIST_HEAD(&ctx->rx_list); | ||
210 | INIT_LIST_HEAD(&ctx->ipc_dispatch_list); | ||
211 | INIT_LIST_HEAD(&ctx->block_list); | ||
212 | INIT_WORK(&ctx->ipc_post_msg_wq, sst_process_pending_msg); | ||
213 | init_waitqueue_head(&ctx->wait_queue); | ||
214 | |||
215 | ctx->post_msg_wq = | ||
216 | create_singlethread_workqueue("sst_post_msg_wq"); | ||
217 | if (!ctx->post_msg_wq) | ||
218 | return -EBUSY; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static void sst_init_locks(struct intel_sst_drv *ctx) | ||
223 | { | ||
224 | mutex_init(&ctx->sst_lock); | ||
225 | spin_lock_init(&ctx->rx_msg_lock); | ||
226 | spin_lock_init(&ctx->ipc_spin_lock); | ||
227 | spin_lock_init(&ctx->block_lock); | ||
228 | } | ||
229 | |||
230 | int sst_alloc_drv_context(struct intel_sst_drv **ctx, | ||
231 | struct device *dev, unsigned int dev_id) | ||
232 | { | ||
233 | *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL); | ||
234 | if (!(*ctx)) | ||
235 | return -ENOMEM; | ||
236 | |||
237 | (*ctx)->dev = dev; | ||
238 | (*ctx)->dev_id = dev_id; | ||
239 | |||
240 | return 0; | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(sst_alloc_drv_context); | ||
243 | |||
244 | int sst_context_init(struct intel_sst_drv *ctx) | ||
245 | { | ||
246 | int ret = 0, i; | ||
247 | |||
248 | if (!ctx->pdata) | ||
249 | return -EINVAL; | ||
250 | |||
251 | if (!ctx->pdata->probe_data) | ||
252 | return -EINVAL; | ||
253 | |||
254 | memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info)); | ||
255 | |||
256 | ret = sst_driver_ops(ctx); | ||
257 | if (ret != 0) | ||
258 | return -EINVAL; | ||
259 | |||
260 | sst_init_locks(ctx); | ||
261 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
262 | |||
263 | /* pvt_id 0 reserved for async messages */ | ||
264 | ctx->pvt_id = 1; | ||
265 | ctx->stream_cnt = 0; | ||
266 | ctx->fw_in_mem = NULL; | ||
267 | /* we use memcpy, so set to 0 */ | ||
268 | ctx->use_dma = 0; | ||
269 | ctx->use_lli = 0; | ||
270 | |||
271 | if (sst_workqueue_init(ctx)) | ||
272 | return -EINVAL; | ||
273 | |||
274 | ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off; | ||
275 | ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset; | ||
276 | ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset; | ||
277 | |||
278 | dev_info(ctx->dev, "Got drv data max stream %d\n", | ||
279 | ctx->info.max_streams); | ||
280 | |||
281 | for (i = 1; i <= ctx->info.max_streams; i++) { | ||
282 | struct stream_info *stream = &ctx->streams[i]; | ||
283 | |||
284 | memset(stream, 0, sizeof(*stream)); | ||
285 | stream->pipe_id = PIPE_RSVD; | ||
286 | mutex_init(&stream->lock); | ||
287 | } | ||
288 | |||
289 | /* Register the ISR */ | ||
290 | ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt, | ||
291 | ctx->ops->irq_thread, 0, SST_DRV_NAME, | ||
292 | ctx); | ||
293 | if (ret) | ||
294 | goto do_free_mem; | ||
295 | |||
296 | dev_dbg(ctx->dev, "Registered IRQ %#x\n", ctx->irq_num); | ||
297 | |||
298 | /* default intr are unmasked so set this as masked */ | ||
299 | sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038); | ||
300 | |||
301 | ctx->qos = devm_kzalloc(ctx->dev, | ||
302 | sizeof(struct pm_qos_request), GFP_KERNEL); | ||
303 | if (!ctx->qos) { | ||
304 | ret = -ENOMEM; | ||
305 | goto do_free_mem; | ||
306 | } | ||
307 | pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY, | ||
308 | PM_QOS_DEFAULT_VALUE); | ||
309 | |||
310 | dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name); | ||
311 | ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name, | ||
312 | ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb); | ||
313 | if (ret) { | ||
314 | dev_err(ctx->dev, "Firmware download failed:%d\n", ret); | ||
315 | goto do_free_mem; | ||
316 | } | ||
317 | sst_register(ctx->dev); | ||
318 | return 0; | ||
319 | |||
320 | do_free_mem: | ||
321 | destroy_workqueue(ctx->post_msg_wq); | ||
322 | return ret; | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(sst_context_init); | ||
325 | |||
326 | void sst_context_cleanup(struct intel_sst_drv *ctx) | ||
327 | { | ||
328 | pm_runtime_get_noresume(ctx->dev); | ||
329 | pm_runtime_disable(ctx->dev); | ||
330 | sst_unregister(ctx->dev); | ||
331 | sst_set_fw_state_locked(ctx, SST_SHUTDOWN); | ||
332 | flush_scheduled_work(); | ||
333 | destroy_workqueue(ctx->post_msg_wq); | ||
334 | pm_qos_remove_request(ctx->qos); | ||
335 | kfree(ctx->fw_sg_list.src); | ||
336 | kfree(ctx->fw_sg_list.dst); | ||
337 | ctx->fw_sg_list.list_len = 0; | ||
338 | kfree(ctx->fw_in_mem); | ||
339 | ctx->fw_in_mem = NULL; | ||
340 | sst_memcpy_free_resources(ctx); | ||
341 | ctx = NULL; | ||
342 | } | ||
343 | EXPORT_SYMBOL_GPL(sst_context_cleanup); | ||
344 | |||
345 | static inline void sst_save_shim64(struct intel_sst_drv *ctx, | ||
346 | void __iomem *shim, | ||
347 | struct sst_shim_regs64 *shim_regs) | ||
348 | { | ||
349 | unsigned long irq_flags; | ||
350 | |||
351 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); | ||
352 | |||
353 | shim_regs->imrx = sst_shim_read64(shim, SST_IMRX), | ||
354 | |||
355 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); | ||
356 | } | ||
357 | |||
358 | static inline void sst_restore_shim64(struct intel_sst_drv *ctx, | ||
359 | void __iomem *shim, | ||
360 | struct sst_shim_regs64 *shim_regs) | ||
361 | { | ||
362 | unsigned long irq_flags; | ||
363 | |||
364 | /* | ||
365 | * we only need to restore IMRX for this case, rest will be | ||
366 | * initialize by FW or driver when firmware is loaded | ||
367 | */ | ||
368 | spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags); | ||
369 | sst_shim_write64(shim, SST_IMRX, shim_regs->imrx), | ||
370 | spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags); | ||
371 | } | ||
372 | |||
373 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx) | ||
374 | { | ||
375 | pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY); | ||
376 | pm_runtime_use_autosuspend(ctx->dev); | ||
377 | /* | ||
378 | * For acpi devices, the actual physical device state is | ||
379 | * initially active. So change the state to active before | ||
380 | * enabling the pm | ||
381 | */ | ||
382 | pm_runtime_enable(ctx->dev); | ||
383 | |||
384 | if (acpi_disabled) | ||
385 | pm_runtime_set_active(ctx->dev); | ||
386 | else | ||
387 | pm_runtime_put_noidle(ctx->dev); | ||
388 | |||
389 | sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); | ||
390 | } | ||
391 | EXPORT_SYMBOL_GPL(sst_configure_runtime_pm); | ||
392 | |||
393 | static int intel_sst_runtime_suspend(struct device *dev) | ||
394 | { | ||
395 | int ret = 0; | ||
396 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
397 | |||
398 | if (ctx->sst_state == SST_RESET) { | ||
399 | dev_dbg(dev, "LPE is already in RESET state, No action\n"); | ||
400 | return 0; | ||
401 | } | ||
402 | /* save fw context */ | ||
403 | if (ctx->ops->save_dsp_context(ctx)) | ||
404 | return -EBUSY; | ||
405 | |||
406 | /* Move the SST state to Reset */ | ||
407 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
408 | |||
409 | synchronize_irq(ctx->irq_num); | ||
410 | flush_workqueue(ctx->post_msg_wq); | ||
411 | |||
412 | /* save the shim registers because PMC doesn't save state */ | ||
413 | sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | static int intel_sst_runtime_resume(struct device *dev) | ||
419 | { | ||
420 | int ret = 0; | ||
421 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
422 | |||
423 | if (ctx->sst_state == SST_RESET) { | ||
424 | ret = sst_load_fw(ctx); | ||
425 | if (ret) { | ||
426 | dev_err(dev, "FW download fail %d\n", ret); | ||
427 | sst_set_fw_state_locked(ctx, SST_RESET); | ||
428 | } | ||
429 | } | ||
430 | return ret; | ||
431 | } | ||
432 | |||
433 | const struct dev_pm_ops intel_sst_pm = { | ||
434 | .runtime_suspend = intel_sst_runtime_suspend, | ||
435 | .runtime_resume = intel_sst_runtime_resume, | ||
436 | }; | ||
437 | EXPORT_SYMBOL_GPL(intel_sst_pm); | ||
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h new file mode 100644 index 000000000000..7f4bbfcbc6f5 --- /dev/null +++ b/sound/soc/intel/sst/sst.h | |||
@@ -0,0 +1,546 @@ | |||
1 | /* | ||
2 | * sst.h - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corporation | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | * | ||
22 | * Common private declarations for SST | ||
23 | */ | ||
24 | #ifndef __SST_H__ | ||
25 | #define __SST_H__ | ||
26 | |||
27 | #include <linux/firmware.h> | ||
28 | |||
29 | /* driver names */ | ||
30 | #define SST_DRV_NAME "intel_sst_driver" | ||
31 | #define SST_MRFLD_PCI_ID 0x119A | ||
32 | #define SST_BYT_ACPI_ID 0x80860F28 | ||
33 | #define SST_CHV_ACPI_ID 0x808622A8 | ||
34 | |||
35 | #define SST_SUSPEND_DELAY 2000 | ||
36 | #define FW_CONTEXT_MEM (64*1024) | ||
37 | #define SST_ICCM_BOUNDARY 4 | ||
38 | #define SST_CONFIG_SSP_SIGN 0x7ffe8001 | ||
39 | |||
40 | #define MRFLD_FW_VIRTUAL_BASE 0xC0000000 | ||
41 | #define MRFLD_FW_DDR_BASE_OFFSET 0x0 | ||
42 | #define MRFLD_FW_FEATURE_BASE_OFFSET 0x4 | ||
43 | #define MRFLD_FW_BSS_RESET_BIT 0 | ||
44 | |||
45 | extern const struct dev_pm_ops intel_sst_pm; | ||
46 | enum sst_states { | ||
47 | SST_FW_LOADING = 1, | ||
48 | SST_FW_RUNNING, | ||
49 | SST_RESET, | ||
50 | SST_SHUTDOWN, | ||
51 | }; | ||
52 | |||
53 | enum sst_algo_ops { | ||
54 | SST_SET_ALGO = 0, | ||
55 | SST_GET_ALGO = 1, | ||
56 | }; | ||
57 | |||
58 | #define SST_BLOCK_TIMEOUT 1000 | ||
59 | |||
60 | #define FW_SIGNATURE_SIZE 4 | ||
61 | |||
62 | /* stream states */ | ||
63 | enum sst_stream_states { | ||
64 | STREAM_UN_INIT = 0, /* Freed/Not used stream */ | ||
65 | STREAM_RUNNING = 1, /* Running */ | ||
66 | STREAM_PAUSED = 2, /* Paused stream */ | ||
67 | STREAM_DECODE = 3, /* stream is in decoding only state */ | ||
68 | STREAM_INIT = 4, /* stream init, waiting for data */ | ||
69 | STREAM_RESET = 5, /* force reset on recovery */ | ||
70 | }; | ||
71 | |||
72 | enum sst_ram_type { | ||
73 | SST_IRAM = 1, | ||
74 | SST_DRAM = 2, | ||
75 | SST_DDR = 5, | ||
76 | SST_CUSTOM_INFO = 7, /* consists of FW binary information */ | ||
77 | }; | ||
78 | |||
79 | /* SST shim registers to structure mapping */ | ||
80 | union interrupt_reg { | ||
81 | struct { | ||
82 | u64 done_interrupt:1; | ||
83 | u64 busy_interrupt:1; | ||
84 | u64 rsvd:62; | ||
85 | } part; | ||
86 | u64 full; | ||
87 | }; | ||
88 | |||
89 | union sst_pisr_reg { | ||
90 | struct { | ||
91 | u32 pssp0:1; | ||
92 | u32 pssp1:1; | ||
93 | u32 rsvd0:3; | ||
94 | u32 dmac:1; | ||
95 | u32 rsvd1:26; | ||
96 | } part; | ||
97 | u32 full; | ||
98 | }; | ||
99 | |||
100 | union sst_pimr_reg { | ||
101 | struct { | ||
102 | u32 ssp0:1; | ||
103 | u32 ssp1:1; | ||
104 | u32 rsvd0:3; | ||
105 | u32 dmac:1; | ||
106 | u32 rsvd1:10; | ||
107 | u32 ssp0_sc:1; | ||
108 | u32 ssp1_sc:1; | ||
109 | u32 rsvd2:3; | ||
110 | u32 dmac_sc:1; | ||
111 | u32 rsvd3:10; | ||
112 | } part; | ||
113 | u32 full; | ||
114 | }; | ||
115 | |||
116 | union config_status_reg_mrfld { | ||
117 | struct { | ||
118 | u64 lpe_reset:1; | ||
119 | u64 lpe_reset_vector:1; | ||
120 | u64 runstall:1; | ||
121 | u64 pwaitmode:1; | ||
122 | u64 clk_sel:3; | ||
123 | u64 rsvd2:1; | ||
124 | u64 sst_clk:3; | ||
125 | u64 xt_snoop:1; | ||
126 | u64 rsvd3:4; | ||
127 | u64 clk_sel1:6; | ||
128 | u64 clk_enable:3; | ||
129 | u64 rsvd4:6; | ||
130 | u64 slim0baseclk:1; | ||
131 | u64 rsvd:32; | ||
132 | } part; | ||
133 | u64 full; | ||
134 | }; | ||
135 | |||
136 | union interrupt_reg_mrfld { | ||
137 | struct { | ||
138 | u64 done_interrupt:1; | ||
139 | u64 busy_interrupt:1; | ||
140 | u64 rsvd:62; | ||
141 | } part; | ||
142 | u64 full; | ||
143 | }; | ||
144 | |||
145 | union sst_imr_reg_mrfld { | ||
146 | struct { | ||
147 | u64 done_interrupt:1; | ||
148 | u64 busy_interrupt:1; | ||
149 | u64 rsvd:62; | ||
150 | } part; | ||
151 | u64 full; | ||
152 | }; | ||
153 | |||
154 | /** | ||
155 | * struct sst_block - This structure is used to block a user/fw data call to another | ||
156 | * fw/user call | ||
157 | * | ||
158 | * @condition: condition for blocking check | ||
159 | * @ret_code: ret code when block is released | ||
160 | * @data: data ptr | ||
161 | * @size: size of data | ||
162 | * @on: block condition | ||
163 | * @msg_id: msg_id = msgid in mfld/ctp, mrfld = NULL | ||
164 | * @drv_id: str_id in mfld/ctp, = drv_id in mrfld | ||
165 | * @node: list head node | ||
166 | */ | ||
167 | struct sst_block { | ||
168 | bool condition; | ||
169 | int ret_code; | ||
170 | void *data; | ||
171 | u32 size; | ||
172 | bool on; | ||
173 | u32 msg_id; | ||
174 | u32 drv_id; | ||
175 | struct list_head node; | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * struct stream_info - structure that holds the stream information | ||
180 | * | ||
181 | * @status : stream current state | ||
182 | * @prev : stream prev state | ||
183 | * @ops : stream operation pb/cp/drm... | ||
184 | * @bufs: stream buffer list | ||
185 | * @lock : stream mutex for protecting state | ||
186 | * @pcm_substream : PCM substream | ||
187 | * @period_elapsed : PCM period elapsed callback | ||
188 | * @sfreq : stream sampling freq | ||
189 | * @str_type : stream type | ||
190 | * @cumm_bytes : cummulative bytes decoded | ||
191 | * @str_type : stream type | ||
192 | * @src : stream source | ||
193 | */ | ||
194 | struct stream_info { | ||
195 | unsigned int status; | ||
196 | unsigned int prev; | ||
197 | unsigned int ops; | ||
198 | struct mutex lock; | ||
199 | |||
200 | void *pcm_substream; | ||
201 | void (*period_elapsed)(void *pcm_substream); | ||
202 | |||
203 | unsigned int sfreq; | ||
204 | u32 cumm_bytes; | ||
205 | |||
206 | void *compr_cb_param; | ||
207 | void (*compr_cb)(void *compr_cb_param); | ||
208 | |||
209 | void *drain_cb_param; | ||
210 | void (*drain_notify)(void *drain_cb_param); | ||
211 | |||
212 | unsigned int num_ch; | ||
213 | unsigned int pipe_id; | ||
214 | unsigned int str_id; | ||
215 | unsigned int task_id; | ||
216 | }; | ||
217 | |||
218 | #define SST_FW_SIGN "$SST" | ||
219 | #define SST_FW_LIB_SIGN "$LIB" | ||
220 | |||
221 | /** | ||
222 | * struct sst_fw_header - FW file headers | ||
223 | * | ||
224 | * @signature : FW signature | ||
225 | * @file_size: size of fw image | ||
226 | * @modules : # of modules | ||
227 | * @file_format : version of header format | ||
228 | * @reserved : reserved fields | ||
229 | */ | ||
230 | struct sst_fw_header { | ||
231 | unsigned char signature[FW_SIGNATURE_SIZE]; | ||
232 | u32 file_size; | ||
233 | u32 modules; | ||
234 | u32 file_format; | ||
235 | u32 reserved[4]; | ||
236 | }; | ||
237 | |||
238 | /** | ||
239 | * struct fw_module_header - module header in FW | ||
240 | * | ||
241 | * @signature: module signature | ||
242 | * @mod_size: size of module | ||
243 | * @blocks: block count | ||
244 | * @type: block type | ||
245 | * @entry_point: module netry point | ||
246 | */ | ||
247 | struct fw_module_header { | ||
248 | unsigned char signature[FW_SIGNATURE_SIZE]; | ||
249 | u32 mod_size; | ||
250 | u32 blocks; | ||
251 | u32 type; | ||
252 | u32 entry_point; | ||
253 | }; | ||
254 | |||
255 | /** | ||
256 | * struct fw_block_info - block header for FW | ||
257 | * | ||
258 | * @type: block ram type I/D | ||
259 | * @size: size of block | ||
260 | * @ram_offset: offset in ram | ||
261 | */ | ||
262 | struct fw_block_info { | ||
263 | enum sst_ram_type type; | ||
264 | u32 size; | ||
265 | u32 ram_offset; | ||
266 | u32 rsvd; | ||
267 | }; | ||
268 | |||
269 | struct sst_runtime_param { | ||
270 | struct snd_sst_runtime_params param; | ||
271 | }; | ||
272 | |||
273 | struct sst_sg_list { | ||
274 | struct scatterlist *src; | ||
275 | struct scatterlist *dst; | ||
276 | int list_len; | ||
277 | unsigned int sg_idx; | ||
278 | }; | ||
279 | |||
280 | struct sst_memcpy_list { | ||
281 | struct list_head memcpylist; | ||
282 | void *dstn; | ||
283 | const void *src; | ||
284 | u32 size; | ||
285 | bool is_io; | ||
286 | }; | ||
287 | |||
288 | /*Firmware Module Information*/ | ||
289 | enum sst_lib_dwnld_status { | ||
290 | SST_LIB_NOT_FOUND = 0, | ||
291 | SST_LIB_FOUND, | ||
292 | SST_LIB_DOWNLOADED, | ||
293 | }; | ||
294 | |||
295 | struct sst_module_info { | ||
296 | const char *name; /*Library name*/ | ||
297 | u32 id; /*Module ID*/ | ||
298 | u32 entry_pt; /*Module entry point*/ | ||
299 | u8 status; /*module status*/ | ||
300 | u8 rsvd1; | ||
301 | u16 rsvd2; | ||
302 | }; | ||
303 | |||
304 | /* | ||
305 | * Structure for managing the Library Region(1.5MB) | ||
306 | * in DDR in Merrifield | ||
307 | */ | ||
308 | struct sst_mem_mgr { | ||
309 | phys_addr_t current_base; | ||
310 | int avail; | ||
311 | unsigned int count; | ||
312 | }; | ||
313 | |||
314 | struct sst_ipc_reg { | ||
315 | int ipcx; | ||
316 | int ipcd; | ||
317 | }; | ||
318 | |||
319 | struct sst_shim_regs64 { | ||
320 | u64 csr; | ||
321 | u64 pisr; | ||
322 | u64 pimr; | ||
323 | u64 isrx; | ||
324 | u64 isrd; | ||
325 | u64 imrx; | ||
326 | u64 imrd; | ||
327 | u64 ipcx; | ||
328 | u64 ipcd; | ||
329 | u64 isrsc; | ||
330 | u64 isrlpesc; | ||
331 | u64 imrsc; | ||
332 | u64 imrlpesc; | ||
333 | u64 ipcsc; | ||
334 | u64 ipclpesc; | ||
335 | u64 clkctl; | ||
336 | u64 csr2; | ||
337 | }; | ||
338 | |||
339 | /** | ||
340 | * struct intel_sst_drv - driver ops | ||
341 | * | ||
342 | * @sst_state : current sst device state | ||
343 | * @dev_id : device identifier, pci_id for pci devices and acpi_id for acpi | ||
344 | * devices | ||
345 | * @shim : SST shim pointer | ||
346 | * @mailbox : SST mailbox pointer | ||
347 | * @iram : SST IRAM pointer | ||
348 | * @dram : SST DRAM pointer | ||
349 | * @pdata : SST info passed as a part of pci platform data | ||
350 | * @shim_phy_add : SST shim phy addr | ||
351 | * @shim_regs64: Struct to save shim registers | ||
352 | * @ipc_dispatch_list : ipc messages dispatched | ||
353 | * @rx_list : to copy the process_reply/process_msg from DSP | ||
354 | * @ipc_post_msg_wq : wq to post IPC messages context | ||
355 | * @mad_ops : MAD driver operations registered | ||
356 | * @mad_wq : MAD driver wq | ||
357 | * @post_msg_wq : wq to post IPC messages | ||
358 | * @streams : sst stream contexts | ||
359 | * @list_lock : sst driver list lock (deprecated) | ||
360 | * @ipc_spin_lock : spin lock to handle audio shim access and ipc queue | ||
361 | * @block_lock : spin lock to add block to block_list and assign pvt_id | ||
362 | * @rx_msg_lock : spin lock to handle the rx messages from the DSP | ||
363 | * @scard_ops : sst card ops | ||
364 | * @pci : sst pci device struture | ||
365 | * @dev : pointer to current device struct | ||
366 | * @sst_lock : sst device lock | ||
367 | * @pvt_id : sst private id | ||
368 | * @stream_cnt : total sst active stream count | ||
369 | * @pb_streams : total active pb streams | ||
370 | * @cp_streams : total active cp streams | ||
371 | * @audio_start : audio status | ||
372 | * @qos : PM Qos struct | ||
373 | * firmware_name : Firmware / Library name | ||
374 | */ | ||
375 | struct intel_sst_drv { | ||
376 | int sst_state; | ||
377 | int irq_num; | ||
378 | unsigned int dev_id; | ||
379 | void __iomem *ddr; | ||
380 | void __iomem *shim; | ||
381 | void __iomem *mailbox; | ||
382 | void __iomem *iram; | ||
383 | void __iomem *dram; | ||
384 | unsigned int mailbox_add; | ||
385 | unsigned int iram_base; | ||
386 | unsigned int dram_base; | ||
387 | unsigned int shim_phy_add; | ||
388 | unsigned int iram_end; | ||
389 | unsigned int dram_end; | ||
390 | unsigned int ddr_end; | ||
391 | unsigned int ddr_base; | ||
392 | unsigned int mailbox_recv_offset; | ||
393 | struct sst_shim_regs64 *shim_regs64; | ||
394 | struct list_head block_list; | ||
395 | struct list_head ipc_dispatch_list; | ||
396 | struct sst_platform_info *pdata; | ||
397 | struct list_head rx_list; | ||
398 | struct work_struct ipc_post_msg_wq; | ||
399 | wait_queue_head_t wait_queue; | ||
400 | struct workqueue_struct *post_msg_wq; | ||
401 | unsigned int tstamp; | ||
402 | /* str_id 0 is not used */ | ||
403 | struct stream_info streams[MAX_NUM_STREAMS+1]; | ||
404 | spinlock_t ipc_spin_lock; | ||
405 | spinlock_t block_lock; | ||
406 | spinlock_t rx_msg_lock; | ||
407 | struct pci_dev *pci; | ||
408 | struct device *dev; | ||
409 | volatile long unsigned pvt_id; | ||
410 | struct mutex sst_lock; | ||
411 | unsigned int stream_cnt; | ||
412 | unsigned int csr_value; | ||
413 | void *fw_in_mem; | ||
414 | struct sst_sg_list fw_sg_list, library_list; | ||
415 | struct intel_sst_ops *ops; | ||
416 | struct sst_info info; | ||
417 | struct pm_qos_request *qos; | ||
418 | unsigned int use_dma; | ||
419 | unsigned int use_lli; | ||
420 | atomic_t fw_clear_context; | ||
421 | bool lib_dwnld_reqd; | ||
422 | struct list_head memcpy_list; | ||
423 | struct sst_ipc_reg ipc_reg; | ||
424 | struct sst_mem_mgr lib_mem_mgr; | ||
425 | /* | ||
426 | * Holder for firmware name. Due to async call it needs to be | ||
427 | * persistent till worker thread gets called | ||
428 | */ | ||
429 | char firmware_name[20]; | ||
430 | }; | ||
431 | |||
432 | /* misc definitions */ | ||
433 | #define FW_DWNL_ID 0x01 | ||
434 | |||
435 | struct intel_sst_ops { | ||
436 | irqreturn_t (*interrupt)(int, void *); | ||
437 | irqreturn_t (*irq_thread)(int, void *); | ||
438 | void (*clear_interrupt)(struct intel_sst_drv *ctx); | ||
439 | int (*start)(struct intel_sst_drv *ctx); | ||
440 | int (*reset)(struct intel_sst_drv *ctx); | ||
441 | void (*process_reply)(struct intel_sst_drv *ctx, struct ipc_post *msg); | ||
442 | int (*post_message)(struct intel_sst_drv *ctx, | ||
443 | struct ipc_post *msg, bool sync); | ||
444 | void (*process_message)(struct ipc_post *msg); | ||
445 | void (*set_bypass)(bool set); | ||
446 | int (*save_dsp_context)(struct intel_sst_drv *sst); | ||
447 | void (*restore_dsp_context)(void); | ||
448 | int (*alloc_stream)(struct intel_sst_drv *ctx, void *params); | ||
449 | void (*post_download)(struct intel_sst_drv *sst); | ||
450 | }; | ||
451 | |||
452 | int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
453 | int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
454 | int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
455 | int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id); | ||
456 | int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id); | ||
457 | int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx, | ||
458 | struct snd_sst_bytes_v2 *sbytes); | ||
459 | int sst_set_stream_param(int str_id, struct snd_sst_params *str_param); | ||
460 | int sst_set_metadata(int str_id, char *params); | ||
461 | int sst_get_stream(struct intel_sst_drv *sst_drv_ctx, | ||
462 | struct snd_sst_params *str_param); | ||
463 | int sst_get_stream_allocated(struct intel_sst_drv *ctx, | ||
464 | struct snd_sst_params *str_param, | ||
465 | struct snd_sst_lib_download **lib_dnld); | ||
466 | int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, | ||
467 | int str_id, bool partial_drain); | ||
468 | int sst_post_message_mrfld(struct intel_sst_drv *ctx, | ||
469 | struct ipc_post *msg, bool sync); | ||
470 | void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg); | ||
471 | int sst_start_mrfld(struct intel_sst_drv *ctx); | ||
472 | int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx); | ||
473 | void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx); | ||
474 | |||
475 | int sst_load_fw(struct intel_sst_drv *ctx); | ||
476 | int sst_load_library(struct snd_sst_lib_download *lib, u8 ops); | ||
477 | void sst_post_download_mrfld(struct intel_sst_drv *ctx); | ||
478 | int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx); | ||
479 | void sst_memcpy_free_resources(struct intel_sst_drv *ctx); | ||
480 | |||
481 | int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, | ||
482 | struct sst_block *block); | ||
483 | int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, | ||
484 | struct sst_block *block); | ||
485 | int sst_create_ipc_msg(struct ipc_post **arg, bool large); | ||
486 | int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id); | ||
487 | void sst_clean_stream(struct stream_info *stream); | ||
488 | int intel_sst_register_compress(struct intel_sst_drv *sst); | ||
489 | int intel_sst_remove_compress(struct intel_sst_drv *sst); | ||
490 | void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id); | ||
491 | int sst_send_sync_msg(int ipc, int str_id); | ||
492 | int sst_get_num_channel(struct snd_sst_params *str_param); | ||
493 | int sst_get_sfreq(struct snd_sst_params *str_param); | ||
494 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params); | ||
495 | void sst_restore_fw_context(void); | ||
496 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, | ||
497 | u32 msg_id, u32 drv_id); | ||
498 | int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, | ||
499 | struct intel_sst_drv *sst_drv_ctx, struct sst_block **block, | ||
500 | u32 msg_id, u32 drv_id); | ||
501 | int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed); | ||
502 | int sst_wake_up_block(struct intel_sst_drv *ctx, int result, | ||
503 | u32 drv_id, u32 ipc, void *data, u32 size); | ||
504 | int sst_request_firmware_async(struct intel_sst_drv *ctx); | ||
505 | int sst_driver_ops(struct intel_sst_drv *sst); | ||
506 | struct sst_platform_info *sst_get_acpi_driver_data(const char *hid); | ||
507 | void sst_firmware_load_cb(const struct firmware *fw, void *context); | ||
508 | int sst_prepare_and_post_msg(struct intel_sst_drv *sst, | ||
509 | int task_id, int ipc_msg, int cmd_id, int pipe_id, | ||
510 | size_t mbox_data_len, const void *mbox_data, void **data, | ||
511 | bool large, bool fill_dsp, bool sync, bool response); | ||
512 | |||
513 | void sst_process_pending_msg(struct work_struct *work); | ||
514 | int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx); | ||
515 | void sst_init_stream(struct stream_info *stream, | ||
516 | int codec, int sst_id, int ops, u8 slot); | ||
517 | int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id); | ||
518 | struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx, | ||
519 | int str_id); | ||
520 | int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
521 | u32 pipe_id); | ||
522 | u32 relocate_imr_addr_mrfld(u32 base_addr); | ||
523 | void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst, | ||
524 | struct ipc_post *msg); | ||
525 | int sst_pm_runtime_put(struct intel_sst_drv *sst_drv); | ||
526 | int sst_shim_write(void __iomem *addr, int offset, int value); | ||
527 | u32 sst_shim_read(void __iomem *addr, int offset); | ||
528 | u64 sst_reg_read64(void __iomem *addr, int offset); | ||
529 | int sst_shim_write64(void __iomem *addr, int offset, u64 value); | ||
530 | u64 sst_shim_read64(void __iomem *addr, int offset); | ||
531 | void sst_set_fw_state_locked( | ||
532 | struct intel_sst_drv *sst_drv_ctx, int sst_state); | ||
533 | void sst_fill_header_mrfld(union ipc_header_mrfld *header, | ||
534 | int msg, int task_id, int large, int drv_id); | ||
535 | void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg, | ||
536 | int pipe_id, int len); | ||
537 | |||
538 | int sst_register(struct device *); | ||
539 | int sst_unregister(struct device *); | ||
540 | |||
541 | int sst_alloc_drv_context(struct intel_sst_drv **ctx, | ||
542 | struct device *dev, unsigned int dev_id); | ||
543 | int sst_context_init(struct intel_sst_drv *ctx); | ||
544 | void sst_context_cleanup(struct intel_sst_drv *ctx); | ||
545 | void sst_configure_runtime_pm(struct intel_sst_drv *ctx); | ||
546 | #endif | ||
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c new file mode 100644 index 000000000000..31124aa4434e --- /dev/null +++ b/sound/soc/intel/sst/sst_acpi.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration. | ||
3 | * | ||
4 | * Copyright (c) 2013, Intel Corporation. | ||
5 | * | ||
6 | * Authors: Ramesh Babu K V <Ramesh.Babu@intel.com> | ||
7 | * Authors: Omair Mohammed Abdullah <omair.m.abdullah@intel.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms and conditions of the GNU General Public License, | ||
11 | * version 2, as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
16 | * more details. | ||
17 | * | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/fs.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/miscdevice.h> | ||
27 | #include <linux/platform_device.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | #include <linux/pm_qos.h> | ||
31 | #include <linux/acpi.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/soc.h> | ||
35 | #include <sound/compress_driver.h> | ||
36 | #include <acpi/acbuffer.h> | ||
37 | #include <acpi/platform/acenv.h> | ||
38 | #include <acpi/platform/aclinux.h> | ||
39 | #include <acpi/actypes.h> | ||
40 | #include <acpi/acpi_bus.h> | ||
41 | #include "../sst-mfld-platform.h" | ||
42 | #include "../sst-dsp.h" | ||
43 | #include "sst.h" | ||
44 | |||
45 | struct sst_machines { | ||
46 | char codec_id[32]; | ||
47 | char board[32]; | ||
48 | char machine[32]; | ||
49 | void (*machine_quirk)(void); | ||
50 | char firmware[32]; | ||
51 | struct sst_platform_info *pdata; | ||
52 | |||
53 | }; | ||
54 | |||
55 | /* LPE viewpoint addresses */ | ||
56 | #define SST_BYT_IRAM_PHY_START 0xff2c0000 | ||
57 | #define SST_BYT_IRAM_PHY_END 0xff2d4000 | ||
58 | #define SST_BYT_DRAM_PHY_START 0xff300000 | ||
59 | #define SST_BYT_DRAM_PHY_END 0xff320000 | ||
60 | #define SST_BYT_IMR_VIRT_START 0xc0000000 /* virtual addr in LPE */ | ||
61 | #define SST_BYT_IMR_VIRT_END 0xc01fffff | ||
62 | #define SST_BYT_SHIM_PHY_ADDR 0xff340000 | ||
63 | #define SST_BYT_MBOX_PHY_ADDR 0xff344000 | ||
64 | #define SST_BYT_DMA0_PHY_ADDR 0xff298000 | ||
65 | #define SST_BYT_DMA1_PHY_ADDR 0xff29c000 | ||
66 | #define SST_BYT_SSP0_PHY_ADDR 0xff2a0000 | ||
67 | #define SST_BYT_SSP2_PHY_ADDR 0xff2a2000 | ||
68 | |||
69 | #define BYT_FW_MOD_TABLE_OFFSET 0x80000 | ||
70 | #define BYT_FW_MOD_TABLE_SIZE 0x100 | ||
71 | #define BYT_FW_MOD_OFFSET (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE) | ||
72 | |||
73 | static const struct sst_info byt_fwparse_info = { | ||
74 | .use_elf = false, | ||
75 | .max_streams = 25, | ||
76 | .iram_start = SST_BYT_IRAM_PHY_START, | ||
77 | .iram_end = SST_BYT_IRAM_PHY_END, | ||
78 | .iram_use = true, | ||
79 | .dram_start = SST_BYT_DRAM_PHY_START, | ||
80 | .dram_end = SST_BYT_DRAM_PHY_END, | ||
81 | .dram_use = true, | ||
82 | .imr_start = SST_BYT_IMR_VIRT_START, | ||
83 | .imr_end = SST_BYT_IMR_VIRT_END, | ||
84 | .imr_use = true, | ||
85 | .mailbox_start = SST_BYT_MBOX_PHY_ADDR, | ||
86 | .num_probes = 0, | ||
87 | .lpe_viewpt_rqd = true, | ||
88 | }; | ||
89 | |||
90 | static const struct sst_ipc_info byt_ipc_info = { | ||
91 | .ipc_offset = 0, | ||
92 | .mbox_recv_off = 0x400, | ||
93 | }; | ||
94 | |||
95 | static const struct sst_lib_dnld_info byt_lib_dnld_info = { | ||
96 | .mod_base = SST_BYT_IMR_VIRT_START, | ||
97 | .mod_end = SST_BYT_IMR_VIRT_END, | ||
98 | .mod_table_offset = BYT_FW_MOD_TABLE_OFFSET, | ||
99 | .mod_table_size = BYT_FW_MOD_TABLE_SIZE, | ||
100 | .mod_ddr_dnld = false, | ||
101 | }; | ||
102 | |||
103 | static const struct sst_res_info byt_rvp_res_info = { | ||
104 | .shim_offset = 0x140000, | ||
105 | .shim_size = 0x000100, | ||
106 | .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR, | ||
107 | .ssp0_offset = 0xa0000, | ||
108 | .ssp0_size = 0x1000, | ||
109 | .dma0_offset = 0x98000, | ||
110 | .dma0_size = 0x4000, | ||
111 | .dma1_offset = 0x9c000, | ||
112 | .dma1_size = 0x4000, | ||
113 | .iram_offset = 0x0c0000, | ||
114 | .iram_size = 0x14000, | ||
115 | .dram_offset = 0x100000, | ||
116 | .dram_size = 0x28000, | ||
117 | .mbox_offset = 0x144000, | ||
118 | .mbox_size = 0x1000, | ||
119 | .acpi_lpe_res_index = 0, | ||
120 | .acpi_ddr_index = 2, | ||
121 | .acpi_ipc_irq_index = 5, | ||
122 | }; | ||
123 | |||
124 | static struct sst_platform_info byt_rvp_platform_data = { | ||
125 | .probe_data = &byt_fwparse_info, | ||
126 | .ipc_info = &byt_ipc_info, | ||
127 | .lib_info = &byt_lib_dnld_info, | ||
128 | .res_info = &byt_rvp_res_info, | ||
129 | .platform = "sst-mfld-platform", | ||
130 | }; | ||
131 | |||
132 | /* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail, | ||
133 | * so pdata is same as Baytrail. | ||
134 | */ | ||
135 | static struct sst_platform_info chv_platform_data = { | ||
136 | .probe_data = &byt_fwparse_info, | ||
137 | .ipc_info = &byt_ipc_info, | ||
138 | .lib_info = &byt_lib_dnld_info, | ||
139 | .res_info = &byt_rvp_res_info, | ||
140 | .platform = "sst-mfld-platform", | ||
141 | }; | ||
142 | |||
143 | static int sst_platform_get_resources(struct intel_sst_drv *ctx) | ||
144 | { | ||
145 | struct resource *rsrc; | ||
146 | struct platform_device *pdev = to_platform_device(ctx->dev); | ||
147 | |||
148 | /* All ACPI resource request here */ | ||
149 | /* Get Shim addr */ | ||
150 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | ||
151 | ctx->pdata->res_info->acpi_lpe_res_index); | ||
152 | if (!rsrc) { | ||
153 | dev_err(ctx->dev, "Invalid SHIM base from IFWI"); | ||
154 | return -EIO; | ||
155 | } | ||
156 | dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start, | ||
157 | (unsigned int)resource_size(rsrc)); | ||
158 | |||
159 | ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset; | ||
160 | ctx->iram_end = ctx->iram_base + ctx->pdata->res_info->iram_size - 1; | ||
161 | dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base); | ||
162 | ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base, | ||
163 | ctx->pdata->res_info->iram_size); | ||
164 | if (!ctx->iram) { | ||
165 | dev_err(ctx->dev, "unable to map IRAM"); | ||
166 | return -EIO; | ||
167 | } | ||
168 | |||
169 | ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset; | ||
170 | ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1; | ||
171 | dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base); | ||
172 | ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base, | ||
173 | ctx->pdata->res_info->dram_size); | ||
174 | if (!ctx->dram) { | ||
175 | dev_err(ctx->dev, "unable to map DRAM"); | ||
176 | return -EIO; | ||
177 | } | ||
178 | |||
179 | ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset; | ||
180 | dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add); | ||
181 | ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add, | ||
182 | ctx->pdata->res_info->shim_size); | ||
183 | if (!ctx->shim) { | ||
184 | dev_err(ctx->dev, "unable to map SHIM"); | ||
185 | return -EIO; | ||
186 | } | ||
187 | |||
188 | /* reassign physical address to LPE viewpoint address */ | ||
189 | ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr; | ||
190 | |||
191 | /* Get mailbox addr */ | ||
192 | ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset; | ||
193 | dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add); | ||
194 | ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add, | ||
195 | ctx->pdata->res_info->mbox_size); | ||
196 | if (!ctx->mailbox) { | ||
197 | dev_err(ctx->dev, "unable to map mailbox"); | ||
198 | return -EIO; | ||
199 | } | ||
200 | |||
201 | /* reassign physical address to LPE viewpoint address */ | ||
202 | ctx->mailbox_add = ctx->info.mailbox_start; | ||
203 | |||
204 | rsrc = platform_get_resource(pdev, IORESOURCE_MEM, | ||
205 | ctx->pdata->res_info->acpi_ddr_index); | ||
206 | if (!rsrc) { | ||
207 | dev_err(ctx->dev, "Invalid DDR base from IFWI"); | ||
208 | return -EIO; | ||
209 | } | ||
210 | ctx->ddr_base = rsrc->start; | ||
211 | ctx->ddr_end = rsrc->end; | ||
212 | dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base); | ||
213 | ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base, | ||
214 | resource_size(rsrc)); | ||
215 | if (!ctx->ddr) { | ||
216 | dev_err(ctx->dev, "unable to map DDR"); | ||
217 | return -EIO; | ||
218 | } | ||
219 | |||
220 | /* Find the IRQ */ | ||
221 | ctx->irq_num = platform_get_irq(pdev, | ||
222 | ctx->pdata->res_info->acpi_ipc_irq_index); | ||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, | ||
227 | void *context, void **ret) | ||
228 | { | ||
229 | *(bool *)context = true; | ||
230 | return AE_OK; | ||
231 | } | ||
232 | |||
233 | static struct sst_machines *sst_acpi_find_machine( | ||
234 | struct sst_machines *machines) | ||
235 | { | ||
236 | struct sst_machines *mach; | ||
237 | bool found = false; | ||
238 | |||
239 | for (mach = machines; mach->codec_id; mach++) | ||
240 | if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id, | ||
241 | sst_acpi_mach_match, | ||
242 | &found, NULL)) && found) | ||
243 | return mach; | ||
244 | |||
245 | return NULL; | ||
246 | } | ||
247 | |||
248 | int sst_acpi_probe(struct platform_device *pdev) | ||
249 | { | ||
250 | struct device *dev = &pdev->dev; | ||
251 | int ret = 0; | ||
252 | struct intel_sst_drv *ctx; | ||
253 | const struct acpi_device_id *id; | ||
254 | struct sst_machines *mach; | ||
255 | struct platform_device *mdev; | ||
256 | struct platform_device *plat_dev; | ||
257 | unsigned int dev_id; | ||
258 | |||
259 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
260 | if (!id) | ||
261 | return -ENODEV; | ||
262 | dev_dbg(dev, "for %s", id->id); | ||
263 | |||
264 | mach = (struct sst_machines *)id->driver_data; | ||
265 | mach = sst_acpi_find_machine(mach); | ||
266 | if (mach == NULL) { | ||
267 | dev_err(dev, "No matching machine driver found\n"); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | ret = kstrtouint(id->id, 16, &dev_id); | ||
272 | if (ret < 0) { | ||
273 | dev_err(dev, "Unique device id conversion error: %d\n", ret); | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | dev_dbg(dev, "ACPI device id: %x\n", dev_id); | ||
278 | |||
279 | plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0); | ||
280 | if (plat_dev == NULL) { | ||
281 | dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | |||
285 | /* Create platform device for sst machine driver */ | ||
286 | mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0); | ||
287 | if (mdev == NULL) { | ||
288 | dev_err(dev, "Failed to create machine device: %s\n", mach->machine); | ||
289 | return -ENODEV; | ||
290 | } | ||
291 | |||
292 | ret = sst_alloc_drv_context(&ctx, dev, dev_id); | ||
293 | if (ret < 0) | ||
294 | return ret; | ||
295 | |||
296 | /* Fill sst platform data */ | ||
297 | ctx->pdata = mach->pdata; | ||
298 | strcpy(ctx->firmware_name, mach->firmware); | ||
299 | |||
300 | ret = sst_platform_get_resources(ctx); | ||
301 | if (ret) | ||
302 | return ret; | ||
303 | |||
304 | ret = sst_context_init(ctx); | ||
305 | if (ret < 0) | ||
306 | return ret; | ||
307 | |||
308 | /* need to save shim registers in BYT */ | ||
309 | ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64), | ||
310 | GFP_KERNEL); | ||
311 | if (!ctx->shim_regs64) { | ||
312 | return -ENOMEM; | ||
313 | goto do_sst_cleanup; | ||
314 | } | ||
315 | |||
316 | sst_configure_runtime_pm(ctx); | ||
317 | platform_set_drvdata(pdev, ctx); | ||
318 | return ret; | ||
319 | |||
320 | do_sst_cleanup: | ||
321 | sst_context_cleanup(ctx); | ||
322 | platform_set_drvdata(pdev, NULL); | ||
323 | dev_err(ctx->dev, "failed with %d\n", ret); | ||
324 | return ret; | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * intel_sst_remove - remove function | ||
329 | * | ||
330 | * @pdev: platform device structure | ||
331 | * | ||
332 | * This function is called by OS when a device is unloaded | ||
333 | * This frees the interrupt etc | ||
334 | */ | ||
335 | int sst_acpi_remove(struct platform_device *pdev) | ||
336 | { | ||
337 | struct intel_sst_drv *ctx; | ||
338 | |||
339 | ctx = platform_get_drvdata(pdev); | ||
340 | sst_context_cleanup(ctx); | ||
341 | platform_set_drvdata(pdev, NULL); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static struct sst_machines sst_acpi_bytcr[] = { | ||
346 | {"10EC5640", "T100", "bytt100_rt5640", NULL, "fw_sst_0f28.bin", | ||
347 | &byt_rvp_platform_data }, | ||
348 | {}, | ||
349 | }; | ||
350 | |||
351 | /* Cherryview-based platforms: CherryTrail and Braswell */ | ||
352 | static struct sst_machines sst_acpi_chv[] = { | ||
353 | {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin", | ||
354 | &chv_platform_data }, | ||
355 | {}, | ||
356 | }; | ||
357 | |||
358 | static const struct acpi_device_id sst_acpi_ids[] = { | ||
359 | { "80860F28", (unsigned long)&sst_acpi_bytcr}, | ||
360 | { "808622A8", (unsigned long) &sst_acpi_chv}, | ||
361 | { }, | ||
362 | }; | ||
363 | |||
364 | MODULE_DEVICE_TABLE(acpi, sst_acpi_ids); | ||
365 | |||
366 | static struct platform_driver sst_acpi_driver = { | ||
367 | .driver = { | ||
368 | .name = "intel_sst_acpi", | ||
369 | .owner = THIS_MODULE, | ||
370 | .acpi_match_table = ACPI_PTR(sst_acpi_ids), | ||
371 | .pm = &intel_sst_pm, | ||
372 | }, | ||
373 | .probe = sst_acpi_probe, | ||
374 | .remove = sst_acpi_remove, | ||
375 | }; | ||
376 | |||
377 | module_platform_driver(sst_acpi_driver); | ||
378 | |||
379 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver"); | ||
380 | MODULE_AUTHOR("Ramesh Babu K V"); | ||
381 | MODULE_AUTHOR("Omair Mohammed Abdullah"); | ||
382 | MODULE_LICENSE("GPL v2"); | ||
383 | MODULE_ALIAS("sst"); | ||
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c new file mode 100644 index 000000000000..5f75ef3cdd22 --- /dev/null +++ b/sound/soc/intel/sst/sst_drv_interface.c | |||
@@ -0,0 +1,686 @@ | |||
1 | /* | ||
2 | * sst_drv_interface.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com) | ||
8 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; version 2 of the License. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/fs.h> | ||
24 | #include <linux/firmware.h> | ||
25 | #include <linux/pm_runtime.h> | ||
26 | #include <linux/pm_qos.h> | ||
27 | #include <linux/math64.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/compress_driver.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | |||
38 | |||
39 | #define NUM_CODEC 2 | ||
40 | #define MIN_FRAGMENT 2 | ||
41 | #define MAX_FRAGMENT 4 | ||
42 | #define MIN_FRAGMENT_SIZE (50 * 1024) | ||
43 | #define MAX_FRAGMENT_SIZE (1024 * 1024) | ||
44 | #define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz) (((pcm_wd_sz + 15) >> 4) << 1) | ||
45 | |||
46 | int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id) | ||
47 | { | ||
48 | struct stream_info *stream; | ||
49 | int ret = 0; | ||
50 | |||
51 | stream = get_stream_info(ctx, str_id); | ||
52 | if (stream) { | ||
53 | /* str_id is valid, so stream is alloacted */ | ||
54 | ret = sst_free_stream(ctx, str_id); | ||
55 | if (ret) | ||
56 | sst_clean_stream(&ctx->streams[str_id]); | ||
57 | return ret; | ||
58 | } else { | ||
59 | dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id); | ||
60 | } | ||
61 | return ret; | ||
62 | } | ||
63 | |||
64 | int sst_get_stream_allocated(struct intel_sst_drv *ctx, | ||
65 | struct snd_sst_params *str_param, | ||
66 | struct snd_sst_lib_download **lib_dnld) | ||
67 | { | ||
68 | int retval; | ||
69 | |||
70 | retval = ctx->ops->alloc_stream(ctx, str_param); | ||
71 | if (retval > 0) | ||
72 | dev_dbg(ctx->dev, "Stream allocated %d\n", retval); | ||
73 | return retval; | ||
74 | |||
75 | } | ||
76 | |||
77 | /* | ||
78 | * sst_get_sfreq - this function returns the frequency of the stream | ||
79 | * | ||
80 | * @str_param : stream params | ||
81 | */ | ||
82 | int sst_get_sfreq(struct snd_sst_params *str_param) | ||
83 | { | ||
84 | switch (str_param->codec) { | ||
85 | case SST_CODEC_TYPE_PCM: | ||
86 | return str_param->sparams.uc.pcm_params.sfreq; | ||
87 | case SST_CODEC_TYPE_AAC: | ||
88 | return str_param->sparams.uc.aac_params.externalsr; | ||
89 | case SST_CODEC_TYPE_MP3: | ||
90 | return 0; | ||
91 | default: | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | /* | ||
97 | * sst_get_num_channel - get number of channels for the stream | ||
98 | * | ||
99 | * @str_param : stream params | ||
100 | */ | ||
101 | int sst_get_num_channel(struct snd_sst_params *str_param) | ||
102 | { | ||
103 | switch (str_param->codec) { | ||
104 | case SST_CODEC_TYPE_PCM: | ||
105 | return str_param->sparams.uc.pcm_params.num_chan; | ||
106 | case SST_CODEC_TYPE_MP3: | ||
107 | return str_param->sparams.uc.mp3_params.num_chan; | ||
108 | case SST_CODEC_TYPE_AAC: | ||
109 | return str_param->sparams.uc.aac_params.num_chan; | ||
110 | default: | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * sst_get_stream - this function prepares for stream allocation | ||
117 | * | ||
118 | * @str_param : stream param | ||
119 | */ | ||
120 | int sst_get_stream(struct intel_sst_drv *ctx, | ||
121 | struct snd_sst_params *str_param) | ||
122 | { | ||
123 | int retval; | ||
124 | struct stream_info *str_info; | ||
125 | |||
126 | /* stream is not allocated, we are allocating */ | ||
127 | retval = ctx->ops->alloc_stream(ctx, str_param); | ||
128 | if (retval <= 0) { | ||
129 | return -EIO; | ||
130 | } | ||
131 | /* store sampling freq */ | ||
132 | str_info = &ctx->streams[retval]; | ||
133 | str_info->sfreq = sst_get_sfreq(str_param); | ||
134 | |||
135 | return retval; | ||
136 | } | ||
137 | |||
138 | static int sst_power_control(struct device *dev, bool state) | ||
139 | { | ||
140 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
141 | |||
142 | dev_dbg(ctx->dev, "state:%d", state); | ||
143 | if (state == true) | ||
144 | return pm_runtime_get_sync(dev); | ||
145 | else | ||
146 | return sst_pm_runtime_put(ctx); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * sst_open_pcm_stream - Open PCM interface | ||
151 | * | ||
152 | * @str_param: parameters of pcm stream | ||
153 | * | ||
154 | * This function is called by MID sound card driver to open | ||
155 | * a new pcm interface | ||
156 | */ | ||
157 | static int sst_open_pcm_stream(struct device *dev, | ||
158 | struct snd_sst_params *str_param) | ||
159 | { | ||
160 | int retval; | ||
161 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
162 | |||
163 | if (!str_param) | ||
164 | return -EINVAL; | ||
165 | |||
166 | retval = sst_get_stream(ctx, str_param); | ||
167 | if (retval > 0) | ||
168 | ctx->stream_cnt++; | ||
169 | else | ||
170 | dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval); | ||
171 | |||
172 | return retval; | ||
173 | } | ||
174 | |||
175 | static int sst_cdev_open(struct device *dev, | ||
176 | struct snd_sst_params *str_params, struct sst_compress_cb *cb) | ||
177 | { | ||
178 | int str_id, retval; | ||
179 | struct stream_info *stream; | ||
180 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
181 | |||
182 | retval = pm_runtime_get_sync(ctx->dev); | ||
183 | if (retval < 0) | ||
184 | return retval; | ||
185 | |||
186 | str_id = sst_get_stream(ctx, str_params); | ||
187 | if (str_id > 0) { | ||
188 | dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id); | ||
189 | stream = &ctx->streams[str_id]; | ||
190 | stream->compr_cb = cb->compr_cb; | ||
191 | stream->compr_cb_param = cb->param; | ||
192 | stream->drain_notify = cb->drain_notify; | ||
193 | stream->drain_cb_param = cb->drain_cb_param; | ||
194 | } else { | ||
195 | dev_err(dev, "stream encountered error during alloc %d\n", str_id); | ||
196 | str_id = -EINVAL; | ||
197 | sst_pm_runtime_put(ctx); | ||
198 | } | ||
199 | return str_id; | ||
200 | } | ||
201 | |||
202 | static int sst_cdev_close(struct device *dev, unsigned int str_id) | ||
203 | { | ||
204 | int retval; | ||
205 | struct stream_info *stream; | ||
206 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
207 | |||
208 | stream = get_stream_info(ctx, str_id); | ||
209 | if (!stream) { | ||
210 | dev_err(dev, "stream info is NULL for str %d!!!\n", str_id); | ||
211 | return -EINVAL; | ||
212 | } | ||
213 | |||
214 | if (stream->status == STREAM_RESET) { | ||
215 | dev_dbg(dev, "stream in reset state...\n"); | ||
216 | stream->status = STREAM_UN_INIT; | ||
217 | |||
218 | retval = 0; | ||
219 | goto put; | ||
220 | } | ||
221 | |||
222 | retval = sst_free_stream(ctx, str_id); | ||
223 | put: | ||
224 | stream->compr_cb_param = NULL; | ||
225 | stream->compr_cb = NULL; | ||
226 | |||
227 | if (retval) | ||
228 | dev_err(dev, "free stream returned err %d\n", retval); | ||
229 | |||
230 | dev_dbg(dev, "End\n"); | ||
231 | return retval; | ||
232 | |||
233 | } | ||
234 | |||
235 | static int sst_cdev_ack(struct device *dev, unsigned int str_id, | ||
236 | unsigned long bytes) | ||
237 | { | ||
238 | struct stream_info *stream; | ||
239 | struct snd_sst_tstamp fw_tstamp = {0,}; | ||
240 | int offset; | ||
241 | void __iomem *addr; | ||
242 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
243 | |||
244 | stream = get_stream_info(ctx, str_id); | ||
245 | if (!stream) | ||
246 | return -EINVAL; | ||
247 | |||
248 | /* update bytes sent */ | ||
249 | stream->cumm_bytes += bytes; | ||
250 | dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes); | ||
251 | |||
252 | memcpy_fromio(&fw_tstamp, | ||
253 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
254 | +(str_id * sizeof(fw_tstamp))), | ||
255 | sizeof(fw_tstamp)); | ||
256 | |||
257 | fw_tstamp.bytes_copied = stream->cumm_bytes; | ||
258 | dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n", | ||
259 | fw_tstamp.bytes_copied, bytes); | ||
260 | |||
261 | addr = ((void *)(ctx->mailbox + ctx->tstamp)) + | ||
262 | (str_id * sizeof(fw_tstamp)); | ||
263 | offset = offsetof(struct snd_sst_tstamp, bytes_copied); | ||
264 | sst_shim_write(addr, offset, fw_tstamp.bytes_copied); | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | static int sst_cdev_set_metadata(struct device *dev, | ||
269 | unsigned int str_id, struct snd_compr_metadata *metadata) | ||
270 | { | ||
271 | int retval = 0; | ||
272 | struct stream_info *str_info; | ||
273 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
274 | |||
275 | dev_dbg(dev, "set metadata for stream %d\n", str_id); | ||
276 | |||
277 | str_info = get_stream_info(ctx, str_id); | ||
278 | if (!str_info) | ||
279 | return -EINVAL; | ||
280 | |||
281 | dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id); | ||
282 | retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD, | ||
283 | IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id, | ||
284 | sizeof(*metadata), metadata, NULL, | ||
285 | true, true, true, false); | ||
286 | |||
287 | return retval; | ||
288 | } | ||
289 | |||
290 | static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id) | ||
291 | { | ||
292 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
293 | |||
294 | return sst_pause_stream(ctx, str_id); | ||
295 | } | ||
296 | |||
297 | static int sst_cdev_stream_pause_release(struct device *dev, | ||
298 | unsigned int str_id) | ||
299 | { | ||
300 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
301 | |||
302 | return sst_resume_stream(ctx, str_id); | ||
303 | } | ||
304 | |||
305 | static int sst_cdev_stream_start(struct device *dev, unsigned int str_id) | ||
306 | { | ||
307 | struct stream_info *str_info; | ||
308 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
309 | |||
310 | str_info = get_stream_info(ctx, str_id); | ||
311 | if (!str_info) | ||
312 | return -EINVAL; | ||
313 | str_info->prev = str_info->status; | ||
314 | str_info->status = STREAM_RUNNING; | ||
315 | return sst_start_stream(ctx, str_id); | ||
316 | } | ||
317 | |||
318 | static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id) | ||
319 | { | ||
320 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
321 | |||
322 | return sst_drop_stream(ctx, str_id); | ||
323 | } | ||
324 | |||
325 | static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id) | ||
326 | { | ||
327 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
328 | |||
329 | return sst_drain_stream(ctx, str_id, false); | ||
330 | } | ||
331 | |||
332 | static int sst_cdev_stream_partial_drain(struct device *dev, | ||
333 | unsigned int str_id) | ||
334 | { | ||
335 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
336 | |||
337 | return sst_drain_stream(ctx, str_id, true); | ||
338 | } | ||
339 | |||
340 | static int sst_cdev_tstamp(struct device *dev, unsigned int str_id, | ||
341 | struct snd_compr_tstamp *tstamp) | ||
342 | { | ||
343 | struct snd_sst_tstamp fw_tstamp = {0,}; | ||
344 | struct stream_info *stream; | ||
345 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
346 | |||
347 | memcpy_fromio(&fw_tstamp, | ||
348 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
349 | +(str_id * sizeof(fw_tstamp))), | ||
350 | sizeof(fw_tstamp)); | ||
351 | |||
352 | stream = get_stream_info(ctx, str_id); | ||
353 | if (!stream) | ||
354 | return -EINVAL; | ||
355 | dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter); | ||
356 | |||
357 | tstamp->copied_total = fw_tstamp.ring_buffer_counter; | ||
358 | tstamp->pcm_frames = fw_tstamp.frames_decoded; | ||
359 | tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter, | ||
360 | (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24))); | ||
361 | tstamp->sampling_rate = fw_tstamp.sampling_frequency; | ||
362 | |||
363 | dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames); | ||
364 | dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n", | ||
365 | str_id, tstamp->copied_total, tstamp->pcm_frames); | ||
366 | dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int sst_cdev_caps(struct snd_compr_caps *caps) | ||
372 | { | ||
373 | caps->num_codecs = NUM_CODEC; | ||
374 | caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */ | ||
375 | caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */ | ||
376 | caps->min_fragments = MIN_FRAGMENT; | ||
377 | caps->max_fragments = MAX_FRAGMENT; | ||
378 | caps->codecs[0] = SND_AUDIOCODEC_MP3; | ||
379 | caps->codecs[1] = SND_AUDIOCODEC_AAC; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | static struct snd_compr_codec_caps caps_mp3 = { | ||
384 | .num_descriptors = 1, | ||
385 | .descriptor[0].max_ch = 2, | ||
386 | .descriptor[0].sample_rates[0] = 48000, | ||
387 | .descriptor[0].sample_rates[1] = 44100, | ||
388 | .descriptor[0].sample_rates[2] = 32000, | ||
389 | .descriptor[0].sample_rates[3] = 16000, | ||
390 | .descriptor[0].sample_rates[4] = 8000, | ||
391 | .descriptor[0].num_sample_rates = 5, | ||
392 | .descriptor[0].bit_rate[0] = 320, | ||
393 | .descriptor[0].bit_rate[1] = 192, | ||
394 | .descriptor[0].num_bitrates = 2, | ||
395 | .descriptor[0].profiles = 0, | ||
396 | .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO, | ||
397 | .descriptor[0].formats = 0, | ||
398 | }; | ||
399 | |||
400 | static struct snd_compr_codec_caps caps_aac = { | ||
401 | .num_descriptors = 2, | ||
402 | .descriptor[1].max_ch = 2, | ||
403 | .descriptor[0].sample_rates[0] = 48000, | ||
404 | .descriptor[0].sample_rates[1] = 44100, | ||
405 | .descriptor[0].sample_rates[2] = 32000, | ||
406 | .descriptor[0].sample_rates[3] = 16000, | ||
407 | .descriptor[0].sample_rates[4] = 8000, | ||
408 | .descriptor[0].num_sample_rates = 5, | ||
409 | .descriptor[1].bit_rate[0] = 320, | ||
410 | .descriptor[1].bit_rate[1] = 192, | ||
411 | .descriptor[1].num_bitrates = 2, | ||
412 | .descriptor[1].profiles = 0, | ||
413 | .descriptor[1].modes = 0, | ||
414 | .descriptor[1].formats = | ||
415 | (SND_AUDIOSTREAMFORMAT_MP4ADTS | | ||
416 | SND_AUDIOSTREAMFORMAT_RAW), | ||
417 | }; | ||
418 | |||
419 | static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec) | ||
420 | { | ||
421 | if (codec->codec == SND_AUDIOCODEC_MP3) | ||
422 | *codec = caps_mp3; | ||
423 | else if (codec->codec == SND_AUDIOCODEC_AAC) | ||
424 | *codec = caps_aac; | ||
425 | else | ||
426 | return -EINVAL; | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id) | ||
432 | { | ||
433 | struct stream_info *stream; | ||
434 | |||
435 | dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n", | ||
436 | str_id); | ||
437 | stream = &ctx->streams[str_id]; | ||
438 | if (stream->compr_cb) | ||
439 | stream->compr_cb(stream->compr_cb_param); | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | * sst_close_pcm_stream - Close PCM interface | ||
444 | * | ||
445 | * @str_id: stream id to be closed | ||
446 | * | ||
447 | * This function is called by MID sound card driver to close | ||
448 | * an existing pcm interface | ||
449 | */ | ||
450 | static int sst_close_pcm_stream(struct device *dev, unsigned int str_id) | ||
451 | { | ||
452 | struct stream_info *stream; | ||
453 | int retval = 0; | ||
454 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
455 | |||
456 | stream = get_stream_info(ctx, str_id); | ||
457 | if (!stream) { | ||
458 | dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id); | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | if (stream->status == STREAM_RESET) { | ||
463 | /* silently fail here as we have cleaned the stream earlier */ | ||
464 | dev_dbg(ctx->dev, "stream in reset state...\n"); | ||
465 | |||
466 | retval = 0; | ||
467 | goto put; | ||
468 | } | ||
469 | |||
470 | retval = free_stream_context(ctx, str_id); | ||
471 | put: | ||
472 | stream->pcm_substream = NULL; | ||
473 | stream->status = STREAM_UN_INIT; | ||
474 | stream->period_elapsed = NULL; | ||
475 | ctx->stream_cnt--; | ||
476 | |||
477 | if (retval) | ||
478 | dev_err(ctx->dev, "free stream returned err %d\n", retval); | ||
479 | |||
480 | dev_dbg(ctx->dev, "Exit\n"); | ||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static inline int sst_calc_tstamp(struct intel_sst_drv *ctx, | ||
485 | struct pcm_stream_info *info, | ||
486 | struct snd_pcm_substream *substream, | ||
487 | struct snd_sst_tstamp *fw_tstamp) | ||
488 | { | ||
489 | size_t delay_bytes, delay_frames; | ||
490 | size_t buffer_sz; | ||
491 | u32 pointer_bytes, pointer_samples; | ||
492 | |||
493 | dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n", | ||
494 | fw_tstamp->ring_buffer_counter); | ||
495 | dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n", | ||
496 | fw_tstamp->hardware_counter); | ||
497 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
498 | delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter - | ||
499 | fw_tstamp->hardware_counter); | ||
500 | else | ||
501 | delay_bytes = (size_t) (fw_tstamp->hardware_counter - | ||
502 | fw_tstamp->ring_buffer_counter); | ||
503 | delay_frames = bytes_to_frames(substream->runtime, delay_bytes); | ||
504 | buffer_sz = snd_pcm_lib_buffer_bytes(substream); | ||
505 | div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes); | ||
506 | pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes); | ||
507 | |||
508 | dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes); | ||
509 | |||
510 | info->buffer_ptr = pointer_samples / substream->runtime->channels; | ||
511 | |||
512 | info->pcm_delay = delay_frames / substream->runtime->channels; | ||
513 | dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n", | ||
514 | info->buffer_ptr, info->pcm_delay); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info) | ||
519 | { | ||
520 | struct stream_info *stream; | ||
521 | struct snd_pcm_substream *substream; | ||
522 | struct snd_sst_tstamp fw_tstamp; | ||
523 | unsigned int str_id; | ||
524 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
525 | |||
526 | str_id = info->str_id; | ||
527 | stream = get_stream_info(ctx, str_id); | ||
528 | if (!stream) | ||
529 | return -EINVAL; | ||
530 | |||
531 | if (!stream->pcm_substream) | ||
532 | return -EINVAL; | ||
533 | substream = stream->pcm_substream; | ||
534 | |||
535 | memcpy_fromio(&fw_tstamp, | ||
536 | ((void *)(ctx->mailbox + ctx->tstamp) | ||
537 | + (str_id * sizeof(fw_tstamp))), | ||
538 | sizeof(fw_tstamp)); | ||
539 | return sst_calc_tstamp(ctx, info, substream, &fw_tstamp); | ||
540 | } | ||
541 | |||
542 | static int sst_stream_start(struct device *dev, int str_id) | ||
543 | { | ||
544 | struct stream_info *str_info; | ||
545 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
546 | |||
547 | if (ctx->sst_state != SST_FW_RUNNING) | ||
548 | return 0; | ||
549 | str_info = get_stream_info(ctx, str_id); | ||
550 | if (!str_info) | ||
551 | return -EINVAL; | ||
552 | str_info->prev = str_info->status; | ||
553 | str_info->status = STREAM_RUNNING; | ||
554 | sst_start_stream(ctx, str_id); | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static int sst_stream_drop(struct device *dev, int str_id) | ||
560 | { | ||
561 | struct stream_info *str_info; | ||
562 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
563 | |||
564 | if (ctx->sst_state != SST_FW_RUNNING) | ||
565 | return 0; | ||
566 | |||
567 | str_info = get_stream_info(ctx, str_id); | ||
568 | if (!str_info) | ||
569 | return -EINVAL; | ||
570 | str_info->prev = STREAM_UN_INIT; | ||
571 | str_info->status = STREAM_INIT; | ||
572 | return sst_drop_stream(ctx, str_id); | ||
573 | } | ||
574 | |||
575 | static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info) | ||
576 | { | ||
577 | int str_id = 0; | ||
578 | struct stream_info *stream; | ||
579 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
580 | |||
581 | str_id = str_info->str_id; | ||
582 | |||
583 | if (ctx->sst_state != SST_FW_RUNNING) | ||
584 | return 0; | ||
585 | |||
586 | stream = get_stream_info(ctx, str_id); | ||
587 | if (!stream) | ||
588 | return -EINVAL; | ||
589 | |||
590 | dev_dbg(ctx->dev, "setting the period ptrs\n"); | ||
591 | stream->pcm_substream = str_info->arg; | ||
592 | stream->period_elapsed = str_info->period_elapsed; | ||
593 | stream->sfreq = str_info->sfreq; | ||
594 | stream->prev = stream->status; | ||
595 | stream->status = STREAM_INIT; | ||
596 | dev_dbg(ctx->dev, | ||
597 | "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n", | ||
598 | stream->pcm_substream, stream->period_elapsed, | ||
599 | stream->sfreq, stream->status); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | /* | ||
605 | * sst_set_byte_stream - Set generic params | ||
606 | * | ||
607 | * @cmd: control cmd to be set | ||
608 | * @arg: command argument | ||
609 | * | ||
610 | * This function is called by MID sound card driver to configure | ||
611 | * SST runtime params. | ||
612 | */ | ||
613 | static int sst_send_byte_stream(struct device *dev, | ||
614 | struct snd_sst_bytes_v2 *bytes) | ||
615 | { | ||
616 | int ret_val = 0; | ||
617 | struct intel_sst_drv *ctx = dev_get_drvdata(dev); | ||
618 | |||
619 | if (NULL == bytes) | ||
620 | return -EINVAL; | ||
621 | ret_val = pm_runtime_get_sync(ctx->dev); | ||
622 | if (ret_val < 0) | ||
623 | return ret_val; | ||
624 | |||
625 | ret_val = sst_send_byte_stream_mrfld(ctx, bytes); | ||
626 | sst_pm_runtime_put(ctx); | ||
627 | |||
628 | return ret_val; | ||
629 | } | ||
630 | |||
631 | static struct sst_ops pcm_ops = { | ||
632 | .open = sst_open_pcm_stream, | ||
633 | .stream_init = sst_stream_init, | ||
634 | .stream_start = sst_stream_start, | ||
635 | .stream_drop = sst_stream_drop, | ||
636 | .stream_read_tstamp = sst_read_timestamp, | ||
637 | .send_byte_stream = sst_send_byte_stream, | ||
638 | .close = sst_close_pcm_stream, | ||
639 | .power = sst_power_control, | ||
640 | }; | ||
641 | |||
642 | static struct compress_sst_ops compr_ops = { | ||
643 | .open = sst_cdev_open, | ||
644 | .close = sst_cdev_close, | ||
645 | .stream_pause = sst_cdev_stream_pause, | ||
646 | .stream_pause_release = sst_cdev_stream_pause_release, | ||
647 | .stream_start = sst_cdev_stream_start, | ||
648 | .stream_drop = sst_cdev_stream_drop, | ||
649 | .stream_drain = sst_cdev_stream_drain, | ||
650 | .stream_partial_drain = sst_cdev_stream_partial_drain, | ||
651 | .tstamp = sst_cdev_tstamp, | ||
652 | .ack = sst_cdev_ack, | ||
653 | .get_caps = sst_cdev_caps, | ||
654 | .get_codec_caps = sst_cdev_codec_caps, | ||
655 | .set_metadata = sst_cdev_set_metadata, | ||
656 | .power = sst_power_control, | ||
657 | }; | ||
658 | |||
659 | static struct sst_device sst_dsp_device = { | ||
660 | .name = "Intel(R) SST LPE", | ||
661 | .dev = NULL, | ||
662 | .ops = &pcm_ops, | ||
663 | .compr_ops = &compr_ops, | ||
664 | }; | ||
665 | |||
666 | /* | ||
667 | * sst_register - function to register DSP | ||
668 | * | ||
669 | * This functions registers DSP with the platform driver | ||
670 | */ | ||
671 | int sst_register(struct device *dev) | ||
672 | { | ||
673 | int ret_val; | ||
674 | |||
675 | sst_dsp_device.dev = dev; | ||
676 | ret_val = sst_register_dsp(&sst_dsp_device); | ||
677 | if (ret_val) | ||
678 | dev_err(dev, "Unable to register DSP with platform driver\n"); | ||
679 | |||
680 | return ret_val; | ||
681 | } | ||
682 | |||
683 | int sst_unregister(struct device *dev) | ||
684 | { | ||
685 | return sst_unregister_dsp(&sst_dsp_device); | ||
686 | } | ||
diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/sst/sst_ipc.c new file mode 100644 index 000000000000..484e60978477 --- /dev/null +++ b/sound/soc/intel/sst/sst_ipc.c | |||
@@ -0,0 +1,373 @@ | |||
1 | /* | ||
2 | * sst_ipc.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corporation | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/compress_driver.h> | ||
31 | #include <asm/intel-mid.h> | ||
32 | #include <asm/platform_sst_audio.h> | ||
33 | #include "../sst-mfld-platform.h" | ||
34 | #include "sst.h" | ||
35 | #include "../sst-dsp.h" | ||
36 | |||
37 | struct sst_block *sst_create_block(struct intel_sst_drv *ctx, | ||
38 | u32 msg_id, u32 drv_id) | ||
39 | { | ||
40 | struct sst_block *msg = NULL; | ||
41 | |||
42 | dev_dbg(ctx->dev, "Enter\n"); | ||
43 | msg = kzalloc(sizeof(*msg), GFP_KERNEL); | ||
44 | if (!msg) | ||
45 | return NULL; | ||
46 | msg->condition = false; | ||
47 | msg->on = true; | ||
48 | msg->msg_id = msg_id; | ||
49 | msg->drv_id = drv_id; | ||
50 | spin_lock_bh(&ctx->block_lock); | ||
51 | list_add_tail(&msg->node, &ctx->block_list); | ||
52 | spin_unlock_bh(&ctx->block_lock); | ||
53 | |||
54 | return msg; | ||
55 | } | ||
56 | |||
57 | /* | ||
58 | * while handling the interrupts, we need to check for message status and | ||
59 | * then if we are blocking for a message | ||
60 | * | ||
61 | * here we are unblocking the blocked ones, this is based on id we have | ||
62 | * passed and search that for block threads. | ||
63 | * We will not find block in two cases | ||
64 | * a) when its small message and block in not there, so silently ignore | ||
65 | * them | ||
66 | * b) when we are actually not able to find the block (bug perhaps) | ||
67 | * | ||
68 | * Since we have bit of small messages we can spam kernel log with err | ||
69 | * print on above so need to keep as debug prints which should be enabled | ||
70 | * via dynamic debug while debugging IPC issues | ||
71 | */ | ||
72 | int sst_wake_up_block(struct intel_sst_drv *ctx, int result, | ||
73 | u32 drv_id, u32 ipc, void *data, u32 size) | ||
74 | { | ||
75 | struct sst_block *block = NULL; | ||
76 | |||
77 | dev_dbg(ctx->dev, "Enter\n"); | ||
78 | |||
79 | spin_lock_bh(&ctx->block_lock); | ||
80 | list_for_each_entry(block, &ctx->block_list, node) { | ||
81 | dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id, | ||
82 | block->drv_id); | ||
83 | if (block->msg_id == ipc && block->drv_id == drv_id) { | ||
84 | dev_dbg(ctx->dev, "free up the block\n"); | ||
85 | block->ret_code = result; | ||
86 | block->data = data; | ||
87 | block->size = size; | ||
88 | block->condition = true; | ||
89 | spin_unlock_bh(&ctx->block_lock); | ||
90 | wake_up(&ctx->wait_queue); | ||
91 | return 0; | ||
92 | } | ||
93 | } | ||
94 | spin_unlock_bh(&ctx->block_lock); | ||
95 | dev_dbg(ctx->dev, | ||
96 | "Block not found or a response received for a short msg for ipc %d, drv_id %d\n", | ||
97 | ipc, drv_id); | ||
98 | return -EINVAL; | ||
99 | } | ||
100 | |||
101 | int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed) | ||
102 | { | ||
103 | struct sst_block *block = NULL, *__block; | ||
104 | |||
105 | dev_dbg(ctx->dev, "Enter\n"); | ||
106 | spin_lock_bh(&ctx->block_lock); | ||
107 | list_for_each_entry_safe(block, __block, &ctx->block_list, node) { | ||
108 | if (block == freed) { | ||
109 | pr_debug("pvt_id freed --> %d\n", freed->drv_id); | ||
110 | /* toggle the index position of pvt_id */ | ||
111 | list_del(&freed->node); | ||
112 | spin_unlock_bh(&ctx->block_lock); | ||
113 | kfree(freed->data); | ||
114 | freed->data = NULL; | ||
115 | kfree(freed); | ||
116 | return 0; | ||
117 | } | ||
118 | } | ||
119 | spin_unlock_bh(&ctx->block_lock); | ||
120 | dev_err(ctx->dev, "block is already freed!!!\n"); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
125 | struct ipc_post *ipc_msg, bool sync) | ||
126 | { | ||
127 | struct ipc_post *msg = ipc_msg; | ||
128 | union ipc_header_mrfld header; | ||
129 | unsigned int loop_count = 0; | ||
130 | int retval = 0; | ||
131 | unsigned long irq_flags; | ||
132 | |||
133 | dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync); | ||
134 | spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
135 | header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); | ||
136 | if (sync) { | ||
137 | while (header.p.header_high.part.busy) { | ||
138 | if (loop_count > 25) { | ||
139 | dev_err(sst_drv_ctx->dev, | ||
140 | "sst: Busy wait failed, cant send this msg\n"); | ||
141 | retval = -EBUSY; | ||
142 | goto out; | ||
143 | } | ||
144 | cpu_relax(); | ||
145 | loop_count++; | ||
146 | header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX); | ||
147 | } | ||
148 | } else { | ||
149 | if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) { | ||
150 | /* queue is empty, nothing to send */ | ||
151 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
152 | dev_dbg(sst_drv_ctx->dev, | ||
153 | "Empty msg queue... NO Action\n"); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | if (header.p.header_high.part.busy) { | ||
158 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
159 | dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n"); | ||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /* copy msg from list */ | ||
164 | msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next, | ||
165 | struct ipc_post, node); | ||
166 | list_del(&msg->node); | ||
167 | } | ||
168 | dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n", | ||
169 | msg->mrfld_header.p.header_high.full); | ||
170 | dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n", | ||
171 | msg->mrfld_header.p.header_low_payload); | ||
172 | |||
173 | if (msg->mrfld_header.p.header_high.part.large) | ||
174 | memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND, | ||
175 | msg->mailbox_data, | ||
176 | msg->mrfld_header.p.header_low_payload); | ||
177 | |||
178 | sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full); | ||
179 | |||
180 | out: | ||
181 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
182 | kfree(msg->mailbox_data); | ||
183 | kfree(msg); | ||
184 | return retval; | ||
185 | } | ||
186 | |||
187 | void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
188 | { | ||
189 | union interrupt_reg_mrfld isr; | ||
190 | union interrupt_reg_mrfld imr; | ||
191 | union ipc_header_mrfld clear_ipc; | ||
192 | unsigned long irq_flags; | ||
193 | |||
194 | spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
195 | imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX); | ||
196 | isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX); | ||
197 | |||
198 | /* write 1 to clear*/ | ||
199 | isr.part.busy_interrupt = 1; | ||
200 | sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full); | ||
201 | |||
202 | /* Set IA done bit */ | ||
203 | clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD); | ||
204 | |||
205 | clear_ipc.p.header_high.part.busy = 0; | ||
206 | clear_ipc.p.header_high.part.done = 1; | ||
207 | clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS; | ||
208 | sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full); | ||
209 | /* un mask busy interrupt */ | ||
210 | imr.part.busy_interrupt = 0; | ||
211 | sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full); | ||
212 | spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags); | ||
213 | } | ||
214 | |||
215 | |||
216 | /* | ||
217 | * process_fw_init - process the FW init msg | ||
218 | * | ||
219 | * @msg: IPC message mailbox data from FW | ||
220 | * | ||
221 | * This function processes the FW init msg from FW | ||
222 | * marks FW state and prints debug info of loaded FW | ||
223 | */ | ||
224 | static void process_fw_init(struct intel_sst_drv *sst_drv_ctx, | ||
225 | void *msg) | ||
226 | { | ||
227 | struct ipc_header_fw_init *init = | ||
228 | (struct ipc_header_fw_init *)msg; | ||
229 | int retval = 0; | ||
230 | |||
231 | dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n"); | ||
232 | if (init->result) { | ||
233 | sst_set_fw_state_locked(sst_drv_ctx, SST_RESET); | ||
234 | dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n", | ||
235 | init->result); | ||
236 | retval = init->result; | ||
237 | goto ret; | ||
238 | } | ||
239 | |||
240 | ret: | ||
241 | sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0); | ||
242 | } | ||
243 | |||
244 | static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx, | ||
245 | struct ipc_post *msg) | ||
246 | { | ||
247 | u32 msg_id; | ||
248 | int str_id; | ||
249 | u32 data_size, i; | ||
250 | void *data_offset; | ||
251 | struct stream_info *stream; | ||
252 | union ipc_header_high msg_high; | ||
253 | u32 msg_low, pipe_id; | ||
254 | |||
255 | msg_high = msg->mrfld_header.p.header_high; | ||
256 | msg_low = msg->mrfld_header.p.header_low_payload; | ||
257 | msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id; | ||
258 | data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr)); | ||
259 | data_size = msg_low - (sizeof(struct ipc_dsp_hdr)); | ||
260 | |||
261 | switch (msg_id) { | ||
262 | case IPC_SST_PERIOD_ELAPSED_MRFLD: | ||
263 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
264 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
265 | if (str_id > 0) { | ||
266 | dev_dbg(sst_drv_ctx->dev, | ||
267 | "Period elapsed rcvd for pipe id 0x%x\n", | ||
268 | pipe_id); | ||
269 | stream = &sst_drv_ctx->streams[str_id]; | ||
270 | if (stream->period_elapsed) | ||
271 | stream->period_elapsed(stream->pcm_substream); | ||
272 | if (stream->compr_cb) | ||
273 | stream->compr_cb(stream->compr_cb_param); | ||
274 | } | ||
275 | break; | ||
276 | |||
277 | case IPC_IA_DRAIN_STREAM_MRFLD: | ||
278 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
279 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
280 | if (str_id > 0) { | ||
281 | stream = &sst_drv_ctx->streams[str_id]; | ||
282 | if (stream->drain_notify) | ||
283 | stream->drain_notify(stream->drain_cb_param); | ||
284 | } | ||
285 | break; | ||
286 | |||
287 | case IPC_IA_FW_ASYNC_ERR_MRFLD: | ||
288 | dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n"); | ||
289 | for (i = 0; i < (data_size/4); i++) | ||
290 | print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, | ||
291 | 16, 4, data_offset, data_size, false); | ||
292 | break; | ||
293 | |||
294 | case IPC_IA_FW_INIT_CMPLT_MRFLD: | ||
295 | process_fw_init(sst_drv_ctx, data_offset); | ||
296 | break; | ||
297 | |||
298 | case IPC_IA_BUF_UNDER_RUN_MRFLD: | ||
299 | pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id; | ||
300 | str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id); | ||
301 | if (str_id > 0) | ||
302 | dev_err(sst_drv_ctx->dev, | ||
303 | "Buffer under-run for pipe:%#x str_id:%d\n", | ||
304 | pipe_id, str_id); | ||
305 | break; | ||
306 | |||
307 | default: | ||
308 | dev_err(sst_drv_ctx->dev, | ||
309 | "Unrecognized async msg from FW msg_id %#x\n", msg_id); | ||
310 | } | ||
311 | } | ||
312 | |||
313 | void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
314 | struct ipc_post *msg) | ||
315 | { | ||
316 | unsigned int drv_id; | ||
317 | void *data; | ||
318 | union ipc_header_high msg_high; | ||
319 | u32 msg_low; | ||
320 | struct ipc_dsp_hdr *dsp_hdr; | ||
321 | unsigned int cmd_id; | ||
322 | |||
323 | msg_high = msg->mrfld_header.p.header_high; | ||
324 | msg_low = msg->mrfld_header.p.header_low_payload; | ||
325 | |||
326 | dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n", | ||
327 | msg->mrfld_header.p.header_high.full, | ||
328 | msg->mrfld_header.p.header_low_payload); | ||
329 | |||
330 | drv_id = msg_high.part.drv_id; | ||
331 | |||
332 | /* Check for async messages first */ | ||
333 | if (drv_id == SST_ASYNC_DRV_ID) { | ||
334 | /*FW sent async large message*/ | ||
335 | process_fw_async_msg(sst_drv_ctx, msg); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | /* FW sent short error response for an IPC */ | ||
340 | if (msg_high.part.result && drv_id && !msg_high.part.large) { | ||
341 | /* 32-bit FW error code in msg_low */ | ||
342 | dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low); | ||
343 | sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
344 | msg_high.part.drv_id, | ||
345 | msg_high.part.msg_id, NULL, 0); | ||
346 | return; | ||
347 | } | ||
348 | |||
349 | /* | ||
350 | * Process all valid responses | ||
351 | * if it is a large message, the payload contains the size to | ||
352 | * copy from mailbox | ||
353 | **/ | ||
354 | if (msg_high.part.large) { | ||
355 | data = kzalloc(msg_low, GFP_KERNEL); | ||
356 | if (!data) | ||
357 | return; | ||
358 | memcpy(data, (void *) msg->mailbox_data, msg_low); | ||
359 | /* Copy command id so that we can use to put sst to reset */ | ||
360 | dsp_hdr = (struct ipc_dsp_hdr *)data; | ||
361 | cmd_id = dsp_hdr->cmd_id; | ||
362 | dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id); | ||
363 | if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
364 | msg_high.part.drv_id, | ||
365 | msg_high.part.msg_id, data, msg_low)) | ||
366 | kfree(data); | ||
367 | } else { | ||
368 | sst_wake_up_block(sst_drv_ctx, msg_high.part.result, | ||
369 | msg_high.part.drv_id, | ||
370 | msg_high.part.msg_id, NULL, 0); | ||
371 | } | ||
372 | |||
373 | } | ||
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c new file mode 100644 index 000000000000..b580f96e25e5 --- /dev/null +++ b/sound/soc/intel/sst/sst_loader.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * sst_dsp.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | * | ||
22 | * This file contains all dsp controlling functions like firmware download, | ||
23 | * setting/resetting dsp cores, etc | ||
24 | */ | ||
25 | #include <linux/pci.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/sched.h> | ||
29 | #include <linux/firmware.h> | ||
30 | #include <linux/dmaengine.h> | ||
31 | #include <linux/pm_runtime.h> | ||
32 | #include <linux/pm_qos.h> | ||
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/compress_driver.h> | ||
37 | #include <asm/platform_sst_audio.h> | ||
38 | #include "../sst-mfld-platform.h" | ||
39 | #include "sst.h" | ||
40 | #include "../sst-dsp.h" | ||
41 | |||
42 | static inline void memcpy32_toio(void __iomem *dst, const void *src, int count) | ||
43 | { | ||
44 | /* __iowrite32_copy uses 32-bit count values so divide by 4 for | ||
45 | * right count in words | ||
46 | */ | ||
47 | __iowrite32_copy(dst, src, count/4); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * intel_sst_reset_dsp_mrfld - Resetting SST DSP | ||
52 | * | ||
53 | * This resets DSP in case of MRFLD platfroms | ||
54 | */ | ||
55 | int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
56 | { | ||
57 | union config_status_reg_mrfld csr; | ||
58 | |||
59 | dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n"); | ||
60 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
61 | |||
62 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
63 | |||
64 | csr.full |= 0x7; | ||
65 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
66 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
67 | |||
68 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
69 | |||
70 | csr.full &= ~(0x1); | ||
71 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
72 | |||
73 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
74 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * sst_start_merrifield - Start the SST DSP processor | ||
80 | * | ||
81 | * This starts the DSP in MERRIFIELD platfroms | ||
82 | */ | ||
83 | int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx) | ||
84 | { | ||
85 | union config_status_reg_mrfld csr; | ||
86 | |||
87 | dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n"); | ||
88 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
89 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
90 | |||
91 | csr.full |= 0x7; | ||
92 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
93 | |||
94 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
95 | dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full); | ||
96 | |||
97 | csr.part.xt_snoop = 1; | ||
98 | csr.full &= ~(0x5); | ||
99 | sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full); | ||
100 | |||
101 | csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR); | ||
102 | dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n", | ||
103 | csr.full); | ||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size, | ||
108 | struct fw_module_header **module, u32 *num_modules) | ||
109 | { | ||
110 | struct sst_fw_header *header; | ||
111 | const void *sst_fw_in_mem = ctx->fw_in_mem; | ||
112 | |||
113 | dev_dbg(ctx->dev, "Enter\n"); | ||
114 | |||
115 | /* Read the header information from the data pointer */ | ||
116 | header = (struct sst_fw_header *)sst_fw_in_mem; | ||
117 | dev_dbg(ctx->dev, | ||
118 | "header sign=%s size=%x modules=%x fmt=%x size=%zx\n", | ||
119 | header->signature, header->file_size, header->modules, | ||
120 | header->file_format, sizeof(*header)); | ||
121 | |||
122 | /* verify FW */ | ||
123 | if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) || | ||
124 | (size != header->file_size + sizeof(*header))) { | ||
125 | /* Invalid FW signature */ | ||
126 | dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n"); | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | *num_modules = header->modules; | ||
130 | *module = (void *)sst_fw_in_mem + sizeof(*header); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * sst_fill_memcpy_list - Fill the memcpy list | ||
137 | * | ||
138 | * @memcpy_list: List to be filled | ||
139 | * @destn: Destination addr to be filled in the list | ||
140 | * @src: Source addr to be filled in the list | ||
141 | * @size: Size to be filled in the list | ||
142 | * | ||
143 | * Adds the node to the list after required fields | ||
144 | * are populated in the node | ||
145 | */ | ||
146 | static int sst_fill_memcpy_list(struct list_head *memcpy_list, | ||
147 | void *destn, const void *src, u32 size, bool is_io) | ||
148 | { | ||
149 | struct sst_memcpy_list *listnode; | ||
150 | |||
151 | listnode = kzalloc(sizeof(*listnode), GFP_KERNEL); | ||
152 | if (listnode == NULL) | ||
153 | return -ENOMEM; | ||
154 | listnode->dstn = destn; | ||
155 | listnode->src = src; | ||
156 | listnode->size = size; | ||
157 | listnode->is_io = is_io; | ||
158 | list_add_tail(&listnode->memcpylist, memcpy_list); | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list | ||
165 | * | ||
166 | * @sst_drv_ctx : driver context | ||
167 | * @module : FW module header | ||
168 | * @memcpy_list : Pointer to the list to be populated | ||
169 | * Create the memcpy list as the number of block to be copied | ||
170 | * returns error or 0 if module sizes are proper | ||
171 | */ | ||
172 | static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx, | ||
173 | struct fw_module_header *module, struct list_head *memcpy_list) | ||
174 | { | ||
175 | struct fw_block_info *block; | ||
176 | u32 count; | ||
177 | int ret_val = 0; | ||
178 | void __iomem *ram_iomem; | ||
179 | |||
180 | dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n", | ||
181 | module->signature, module->mod_size, | ||
182 | module->blocks, module->type); | ||
183 | dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point); | ||
184 | |||
185 | block = (void *)module + sizeof(*module); | ||
186 | |||
187 | for (count = 0; count < module->blocks; count++) { | ||
188 | if (block->size <= 0) { | ||
189 | dev_err(sst_drv_ctx->dev, "block size invalid\n"); | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | switch (block->type) { | ||
193 | case SST_IRAM: | ||
194 | ram_iomem = sst_drv_ctx->iram; | ||
195 | break; | ||
196 | case SST_DRAM: | ||
197 | ram_iomem = sst_drv_ctx->dram; | ||
198 | break; | ||
199 | case SST_DDR: | ||
200 | ram_iomem = sst_drv_ctx->ddr; | ||
201 | break; | ||
202 | case SST_CUSTOM_INFO: | ||
203 | block = (void *)block + sizeof(*block) + block->size; | ||
204 | continue; | ||
205 | default: | ||
206 | dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n", | ||
207 | block->type, count); | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | ret_val = sst_fill_memcpy_list(memcpy_list, | ||
212 | ram_iomem + block->ram_offset, | ||
213 | (void *)block + sizeof(*block), block->size, 1); | ||
214 | if (ret_val) | ||
215 | return ret_val; | ||
216 | |||
217 | block = (void *)block + sizeof(*block) + block->size; | ||
218 | } | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy | ||
224 | * | ||
225 | * @ctx : pointer to drv context | ||
226 | * @size : size of the firmware | ||
227 | * @fw_list : pointer to list_head to be populated | ||
228 | * This function parses the FW image and saves the parsed image in the list | ||
229 | * for memcpy | ||
230 | */ | ||
231 | static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size, | ||
232 | struct list_head *fw_list) | ||
233 | { | ||
234 | struct fw_module_header *module; | ||
235 | u32 count, num_modules; | ||
236 | int ret_val; | ||
237 | |||
238 | ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules); | ||
239 | if (ret_val) | ||
240 | return ret_val; | ||
241 | |||
242 | for (count = 0; count < num_modules; count++) { | ||
243 | ret_val = sst_parse_module_memcpy(ctx, module, fw_list); | ||
244 | if (ret_val) | ||
245 | return ret_val; | ||
246 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * sst_do_memcpy - function initiates the memcpy | ||
254 | * | ||
255 | * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated | ||
256 | * | ||
257 | * Triggers the memcpy | ||
258 | */ | ||
259 | static void sst_do_memcpy(struct list_head *memcpy_list) | ||
260 | { | ||
261 | struct sst_memcpy_list *listnode; | ||
262 | |||
263 | list_for_each_entry(listnode, memcpy_list, memcpylist) { | ||
264 | if (listnode->is_io == true) | ||
265 | memcpy32_toio((void __iomem *)listnode->dstn, | ||
266 | listnode->src, listnode->size); | ||
267 | else | ||
268 | memcpy(listnode->dstn, listnode->src, listnode->size); | ||
269 | } | ||
270 | } | ||
271 | |||
272 | void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx) | ||
273 | { | ||
274 | struct sst_memcpy_list *listnode, *tmplistnode; | ||
275 | |||
276 | /* Free the list */ | ||
277 | if (!list_empty(&sst_drv_ctx->memcpy_list)) { | ||
278 | list_for_each_entry_safe(listnode, tmplistnode, | ||
279 | &sst_drv_ctx->memcpy_list, memcpylist) { | ||
280 | list_del(&listnode->memcpylist); | ||
281 | kfree(listnode); | ||
282 | } | ||
283 | } | ||
284 | } | ||
285 | |||
286 | static int sst_cache_and_parse_fw(struct intel_sst_drv *sst, | ||
287 | const struct firmware *fw) | ||
288 | { | ||
289 | int retval = 0; | ||
290 | |||
291 | sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL); | ||
292 | if (!sst->fw_in_mem) { | ||
293 | retval = -ENOMEM; | ||
294 | goto end_release; | ||
295 | } | ||
296 | dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem); | ||
297 | dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem)); | ||
298 | memcpy(sst->fw_in_mem, fw->data, fw->size); | ||
299 | retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list); | ||
300 | if (retval) { | ||
301 | dev_err(sst->dev, "Failed to parse fw\n"); | ||
302 | kfree(sst->fw_in_mem); | ||
303 | sst->fw_in_mem = NULL; | ||
304 | } | ||
305 | |||
306 | end_release: | ||
307 | release_firmware(fw); | ||
308 | return retval; | ||
309 | |||
310 | } | ||
311 | |||
312 | void sst_firmware_load_cb(const struct firmware *fw, void *context) | ||
313 | { | ||
314 | struct intel_sst_drv *ctx = context; | ||
315 | |||
316 | dev_dbg(ctx->dev, "Enter\n"); | ||
317 | |||
318 | if (fw == NULL) { | ||
319 | dev_err(ctx->dev, "request fw failed\n"); | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | mutex_lock(&ctx->sst_lock); | ||
324 | |||
325 | if (ctx->sst_state != SST_RESET || | ||
326 | ctx->fw_in_mem != NULL) { | ||
327 | if (fw != NULL) | ||
328 | release_firmware(fw); | ||
329 | mutex_unlock(&ctx->sst_lock); | ||
330 | return; | ||
331 | } | ||
332 | |||
333 | dev_dbg(ctx->dev, "Request Fw completed\n"); | ||
334 | sst_cache_and_parse_fw(ctx, fw); | ||
335 | mutex_unlock(&ctx->sst_lock); | ||
336 | } | ||
337 | |||
338 | /* | ||
339 | * sst_request_fw - requests audio fw from kernel and saves a copy | ||
340 | * | ||
341 | * This function requests the SST FW from the kernel, parses it and | ||
342 | * saves a copy in the driver context | ||
343 | */ | ||
344 | static int sst_request_fw(struct intel_sst_drv *sst) | ||
345 | { | ||
346 | int retval = 0; | ||
347 | const struct firmware *fw; | ||
348 | |||
349 | retval = request_firmware(&fw, sst->firmware_name, sst->dev); | ||
350 | if (fw == NULL) { | ||
351 | dev_err(sst->dev, "fw is returning as null\n"); | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | if (retval) { | ||
355 | dev_err(sst->dev, "request fw failed %d\n", retval); | ||
356 | return retval; | ||
357 | } | ||
358 | mutex_lock(&sst->sst_lock); | ||
359 | retval = sst_cache_and_parse_fw(sst, fw); | ||
360 | mutex_unlock(&sst->sst_lock); | ||
361 | |||
362 | return retval; | ||
363 | } | ||
364 | |||
365 | /* | ||
366 | * Writing the DDR physical base to DCCM offset | ||
367 | * so that FW can use it to setup TLB | ||
368 | */ | ||
369 | static void sst_dccm_config_write(void __iomem *dram_base, | ||
370 | unsigned int ddr_base) | ||
371 | { | ||
372 | void __iomem *addr; | ||
373 | u32 bss_reset = 0; | ||
374 | |||
375 | addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET); | ||
376 | memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32)); | ||
377 | bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT); | ||
378 | addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET); | ||
379 | memcpy32_toio(addr, &bss_reset, sizeof(u32)); | ||
380 | |||
381 | } | ||
382 | |||
383 | void sst_post_download_mrfld(struct intel_sst_drv *ctx) | ||
384 | { | ||
385 | sst_dccm_config_write(ctx->dram, ctx->ddr_base); | ||
386 | dev_dbg(ctx->dev, "config written to DCCM\n"); | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * sst_load_fw - function to load FW into DSP | ||
391 | * Transfers the FW to DSP using dma/memcpy | ||
392 | */ | ||
393 | int sst_load_fw(struct intel_sst_drv *sst_drv_ctx) | ||
394 | { | ||
395 | int ret_val = 0; | ||
396 | struct sst_block *block; | ||
397 | |||
398 | dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n"); | ||
399 | |||
400 | if (sst_drv_ctx->sst_state != SST_RESET || | ||
401 | sst_drv_ctx->sst_state == SST_SHUTDOWN) | ||
402 | return -EAGAIN; | ||
403 | |||
404 | if (!sst_drv_ctx->fw_in_mem) { | ||
405 | dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n"); | ||
406 | ret_val = sst_request_fw(sst_drv_ctx); | ||
407 | if (ret_val) | ||
408 | return ret_val; | ||
409 | } | ||
410 | |||
411 | BUG_ON(!sst_drv_ctx->fw_in_mem); | ||
412 | block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID); | ||
413 | if (block == NULL) | ||
414 | return -ENOMEM; | ||
415 | |||
416 | /* Prevent C-states beyond C6 */ | ||
417 | pm_qos_update_request(sst_drv_ctx->qos, 0); | ||
418 | |||
419 | sst_drv_ctx->sst_state = SST_FW_LOADING; | ||
420 | |||
421 | ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx); | ||
422 | if (ret_val) | ||
423 | goto restore; | ||
424 | |||
425 | sst_do_memcpy(&sst_drv_ctx->memcpy_list); | ||
426 | |||
427 | /* Write the DRAM/DCCM config before enabling FW */ | ||
428 | if (sst_drv_ctx->ops->post_download) | ||
429 | sst_drv_ctx->ops->post_download(sst_drv_ctx); | ||
430 | |||
431 | /* bring sst out of reset */ | ||
432 | ret_val = sst_drv_ctx->ops->start(sst_drv_ctx); | ||
433 | if (ret_val) | ||
434 | goto restore; | ||
435 | |||
436 | ret_val = sst_wait_timeout(sst_drv_ctx, block); | ||
437 | if (ret_val) { | ||
438 | dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val); | ||
439 | /* FW download failed due to timeout */ | ||
440 | ret_val = -EBUSY; | ||
441 | |||
442 | } | ||
443 | |||
444 | |||
445 | restore: | ||
446 | /* Re-enable Deeper C-states beyond C6 */ | ||
447 | pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE); | ||
448 | sst_free_block(sst_drv_ctx, block); | ||
449 | dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n"); | ||
450 | |||
451 | if (sst_drv_ctx->ops->restore_dsp_context) | ||
452 | sst_drv_ctx->ops->restore_dsp_context(); | ||
453 | sst_drv_ctx->sst_state = SST_FW_RUNNING; | ||
454 | return ret_val; | ||
455 | } | ||
456 | |||
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/sst/sst_pci.c new file mode 100644 index 000000000000..3a0b3bf0af97 --- /dev/null +++ b/sound/soc/intel/sst/sst_pci.c | |||
@@ -0,0 +1,209 @@ | |||
1 | /* | ||
2 | * sst_pci.c - SST (LPE) driver init file for pci enumeration. | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <asm/platform_sst_audio.h> | ||
30 | #include "../sst-mfld-platform.h" | ||
31 | #include "sst.h" | ||
32 | |||
33 | static int sst_platform_get_resources(struct intel_sst_drv *ctx) | ||
34 | { | ||
35 | int ddr_base, ret = 0; | ||
36 | struct pci_dev *pci = ctx->pci; | ||
37 | |||
38 | ret = pci_request_regions(pci, SST_DRV_NAME); | ||
39 | if (ret) | ||
40 | return ret; | ||
41 | |||
42 | /* map registers */ | ||
43 | /* DDR base */ | ||
44 | if (ctx->dev_id == SST_MRFLD_PCI_ID) { | ||
45 | ctx->ddr_base = pci_resource_start(pci, 0); | ||
46 | /* check that the relocated IMR base matches with FW Binary */ | ||
47 | ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base); | ||
48 | if (!ctx->pdata->lib_info) { | ||
49 | dev_err(ctx->dev, "lib_info pointer NULL\n"); | ||
50 | ret = -EINVAL; | ||
51 | goto do_release_regions; | ||
52 | } | ||
53 | if (ddr_base != ctx->pdata->lib_info->mod_base) { | ||
54 | dev_err(ctx->dev, | ||
55 | "FW LSP DDR BASE does not match with IFWI\n"); | ||
56 | ret = -EINVAL; | ||
57 | goto do_release_regions; | ||
58 | } | ||
59 | ctx->ddr_end = pci_resource_end(pci, 0); | ||
60 | |||
61 | ctx->ddr = pcim_iomap(pci, 0, | ||
62 | pci_resource_len(pci, 0)); | ||
63 | if (!ctx->ddr) { | ||
64 | ret = -EINVAL; | ||
65 | goto do_release_regions; | ||
66 | } | ||
67 | dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr); | ||
68 | } else { | ||
69 | ctx->ddr = NULL; | ||
70 | } | ||
71 | /* SHIM */ | ||
72 | ctx->shim_phy_add = pci_resource_start(pci, 1); | ||
73 | ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1)); | ||
74 | if (!ctx->shim) { | ||
75 | ret = -EINVAL; | ||
76 | goto do_release_regions; | ||
77 | } | ||
78 | dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim); | ||
79 | |||
80 | /* Shared SRAM */ | ||
81 | ctx->mailbox_add = pci_resource_start(pci, 2); | ||
82 | ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2)); | ||
83 | if (!ctx->mailbox) { | ||
84 | ret = -EINVAL; | ||
85 | goto do_release_regions; | ||
86 | } | ||
87 | dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox); | ||
88 | |||
89 | /* IRAM */ | ||
90 | ctx->iram_end = pci_resource_end(pci, 3); | ||
91 | ctx->iram_base = pci_resource_start(pci, 3); | ||
92 | ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3)); | ||
93 | if (!ctx->iram) { | ||
94 | ret = -EINVAL; | ||
95 | goto do_release_regions; | ||
96 | } | ||
97 | dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram); | ||
98 | |||
99 | /* DRAM */ | ||
100 | ctx->dram_end = pci_resource_end(pci, 4); | ||
101 | ctx->dram_base = pci_resource_start(pci, 4); | ||
102 | ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4)); | ||
103 | if (!ctx->dram) { | ||
104 | ret = -EINVAL; | ||
105 | goto do_release_regions; | ||
106 | } | ||
107 | dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram); | ||
108 | do_release_regions: | ||
109 | pci_release_regions(pci); | ||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * intel_sst_probe - PCI probe function | ||
115 | * | ||
116 | * @pci: PCI device structure | ||
117 | * @pci_id: PCI device ID structure | ||
118 | * | ||
119 | */ | ||
120 | static int intel_sst_probe(struct pci_dev *pci, | ||
121 | const struct pci_device_id *pci_id) | ||
122 | { | ||
123 | int ret = 0; | ||
124 | struct intel_sst_drv *sst_drv_ctx; | ||
125 | struct sst_platform_info *sst_pdata = pci->dev.platform_data; | ||
126 | |||
127 | dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device); | ||
128 | ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | sst_drv_ctx->pdata = sst_pdata; | ||
133 | sst_drv_ctx->irq_num = pci->irq; | ||
134 | snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name), | ||
135 | "%s%04x%s", "fw_sst_", | ||
136 | sst_drv_ctx->dev_id, ".bin"); | ||
137 | |||
138 | ret = sst_context_init(sst_drv_ctx); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | /* Init the device */ | ||
143 | ret = pcim_enable_device(pci); | ||
144 | if (ret) { | ||
145 | dev_err(sst_drv_ctx->dev, | ||
146 | "device can't be enabled. Returned err: %d\n", ret); | ||
147 | goto do_free_drv_ctx; | ||
148 | } | ||
149 | sst_drv_ctx->pci = pci_dev_get(pci); | ||
150 | ret = sst_platform_get_resources(sst_drv_ctx); | ||
151 | if (ret < 0) | ||
152 | goto do_free_drv_ctx; | ||
153 | |||
154 | pci_set_drvdata(pci, sst_drv_ctx); | ||
155 | sst_configure_runtime_pm(sst_drv_ctx); | ||
156 | |||
157 | return ret; | ||
158 | |||
159 | do_free_drv_ctx: | ||
160 | sst_context_cleanup(sst_drv_ctx); | ||
161 | dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret); | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | /** | ||
166 | * intel_sst_remove - PCI remove function | ||
167 | * | ||
168 | * @pci: PCI device structure | ||
169 | * | ||
170 | * This function is called by OS when a device is unloaded | ||
171 | * This frees the interrupt etc | ||
172 | */ | ||
173 | static void intel_sst_remove(struct pci_dev *pci) | ||
174 | { | ||
175 | struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci); | ||
176 | |||
177 | sst_context_cleanup(sst_drv_ctx); | ||
178 | pci_dev_put(sst_drv_ctx->pci); | ||
179 | pci_release_regions(pci); | ||
180 | pci_set_drvdata(pci, NULL); | ||
181 | } | ||
182 | |||
183 | /* PCI Routines */ | ||
184 | static struct pci_device_id intel_sst_ids[] = { | ||
185 | { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0}, | ||
186 | { 0, } | ||
187 | }; | ||
188 | |||
189 | static struct pci_driver sst_driver = { | ||
190 | .name = SST_DRV_NAME, | ||
191 | .id_table = intel_sst_ids, | ||
192 | .probe = intel_sst_probe, | ||
193 | .remove = intel_sst_remove, | ||
194 | #ifdef CONFIG_PM | ||
195 | .driver = { | ||
196 | .pm = &intel_sst_pm, | ||
197 | }, | ||
198 | #endif | ||
199 | }; | ||
200 | |||
201 | module_pci_driver(sst_driver); | ||
202 | |||
203 | MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver"); | ||
204 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
205 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
206 | MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>"); | ||
207 | MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>"); | ||
208 | MODULE_LICENSE("GPL v2"); | ||
209 | MODULE_ALIAS("sst"); | ||
diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/sst/sst_pvt.c new file mode 100644 index 000000000000..4b7720864492 --- /dev/null +++ b/sound/soc/intel/sst/sst_pvt.c | |||
@@ -0,0 +1,449 @@ | |||
1 | /* | ||
2 | * sst_pvt.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/kobject.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/firmware.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <sound/asound.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/soc.h> | ||
33 | #include <sound/compress_driver.h> | ||
34 | #include <asm/platform_sst_audio.h> | ||
35 | #include "../sst-mfld-platform.h" | ||
36 | #include "sst.h" | ||
37 | #include "../sst-dsp.h" | ||
38 | |||
39 | int sst_shim_write(void __iomem *addr, int offset, int value) | ||
40 | { | ||
41 | writel(value, addr + offset); | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | u32 sst_shim_read(void __iomem *addr, int offset) | ||
46 | { | ||
47 | return readl(addr + offset); | ||
48 | } | ||
49 | |||
50 | u64 sst_reg_read64(void __iomem *addr, int offset) | ||
51 | { | ||
52 | u64 val = 0; | ||
53 | |||
54 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
55 | |||
56 | return val; | ||
57 | } | ||
58 | |||
59 | int sst_shim_write64(void __iomem *addr, int offset, u64 value) | ||
60 | { | ||
61 | memcpy_toio(addr + offset, &value, sizeof(value)); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | u64 sst_shim_read64(void __iomem *addr, int offset) | ||
66 | { | ||
67 | u64 val = 0; | ||
68 | |||
69 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
70 | return val; | ||
71 | } | ||
72 | |||
73 | void sst_set_fw_state_locked( | ||
74 | struct intel_sst_drv *sst_drv_ctx, int sst_state) | ||
75 | { | ||
76 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
77 | sst_drv_ctx->sst_state = sst_state; | ||
78 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * sst_wait_interruptible - wait on event | ||
83 | * | ||
84 | * @sst_drv_ctx: Driver context | ||
85 | * @block: Driver block to wait on | ||
86 | * | ||
87 | * This function waits without a timeout (and is interruptable) for a | ||
88 | * given block event | ||
89 | */ | ||
90 | int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx, | ||
91 | struct sst_block *block) | ||
92 | { | ||
93 | int retval = 0; | ||
94 | |||
95 | if (!wait_event_interruptible(sst_drv_ctx->wait_queue, | ||
96 | block->condition)) { | ||
97 | /* event wake */ | ||
98 | if (block->ret_code < 0) { | ||
99 | dev_err(sst_drv_ctx->dev, | ||
100 | "stream failed %d\n", block->ret_code); | ||
101 | retval = -EBUSY; | ||
102 | } else { | ||
103 | dev_dbg(sst_drv_ctx->dev, "event up\n"); | ||
104 | retval = 0; | ||
105 | } | ||
106 | } else { | ||
107 | dev_err(sst_drv_ctx->dev, "signal interrupted\n"); | ||
108 | retval = -EINTR; | ||
109 | } | ||
110 | return retval; | ||
111 | |||
112 | } | ||
113 | |||
114 | unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr) | ||
115 | { | ||
116 | unsigned long long val = 0; | ||
117 | |||
118 | switch (sst->dev_id) { | ||
119 | case SST_MRFLD_PCI_ID: | ||
120 | case SST_BYT_ACPI_ID: | ||
121 | val = sst_shim_read64(sst->shim, addr); | ||
122 | break; | ||
123 | } | ||
124 | return val; | ||
125 | } | ||
126 | |||
127 | void write_shim_data(struct intel_sst_drv *sst, int addr, | ||
128 | unsigned long long data) | ||
129 | { | ||
130 | switch (sst->dev_id) { | ||
131 | case SST_MRFLD_PCI_ID: | ||
132 | case SST_BYT_ACPI_ID: | ||
133 | sst_shim_write64(sst->shim, addr, (u64) data); | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * sst_wait_timeout - wait on event for timeout | ||
140 | * | ||
141 | * @sst_drv_ctx: Driver context | ||
142 | * @block: Driver block to wait on | ||
143 | * | ||
144 | * This function waits with a timeout value (and is not interruptible) on a | ||
145 | * given block event | ||
146 | */ | ||
147 | int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block) | ||
148 | { | ||
149 | int retval = 0; | ||
150 | |||
151 | /* | ||
152 | * NOTE: | ||
153 | * Observed that FW processes the alloc msg and replies even | ||
154 | * before the alloc thread has finished execution | ||
155 | */ | ||
156 | dev_dbg(sst_drv_ctx->dev, | ||
157 | "waiting for condition %x ipc %d drv_id %d\n", | ||
158 | block->condition, block->msg_id, block->drv_id); | ||
159 | if (wait_event_timeout(sst_drv_ctx->wait_queue, | ||
160 | block->condition, | ||
161 | msecs_to_jiffies(SST_BLOCK_TIMEOUT))) { | ||
162 | /* event wake */ | ||
163 | dev_dbg(sst_drv_ctx->dev, "Event wake %x\n", | ||
164 | block->condition); | ||
165 | dev_dbg(sst_drv_ctx->dev, "message ret: %d\n", | ||
166 | block->ret_code); | ||
167 | retval = -block->ret_code; | ||
168 | } else { | ||
169 | block->on = false; | ||
170 | dev_err(sst_drv_ctx->dev, | ||
171 | "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n", | ||
172 | block->condition, block->msg_id, sst_drv_ctx->sst_state); | ||
173 | sst_drv_ctx->sst_state = SST_RESET; | ||
174 | |||
175 | retval = -EBUSY; | ||
176 | } | ||
177 | return retval; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * sst_create_ipc_msg - create a IPC message | ||
182 | * | ||
183 | * @arg: ipc message | ||
184 | * @large: large or short message | ||
185 | * | ||
186 | * this function allocates structures to send a large or short | ||
187 | * message to the firmware | ||
188 | */ | ||
189 | int sst_create_ipc_msg(struct ipc_post **arg, bool large) | ||
190 | { | ||
191 | struct ipc_post *msg; | ||
192 | |||
193 | msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC); | ||
194 | if (!msg) | ||
195 | return -ENOMEM; | ||
196 | if (large) { | ||
197 | msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC); | ||
198 | if (!msg->mailbox_data) { | ||
199 | kfree(msg); | ||
200 | return -ENOMEM; | ||
201 | } | ||
202 | } else { | ||
203 | msg->mailbox_data = NULL; | ||
204 | } | ||
205 | msg->is_large = large; | ||
206 | *arg = msg; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | /* | ||
211 | * sst_create_block_and_ipc_msg - Creates IPC message and sst block | ||
212 | * @arg: passed to sst_create_ipc_message API | ||
213 | * @large: large or short message | ||
214 | * @sst_drv_ctx: sst driver context | ||
215 | * @block: return block allocated | ||
216 | * @msg_id: IPC | ||
217 | * @drv_id: stream id or private id | ||
218 | */ | ||
219 | int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large, | ||
220 | struct intel_sst_drv *sst_drv_ctx, struct sst_block **block, | ||
221 | u32 msg_id, u32 drv_id) | ||
222 | { | ||
223 | int retval = 0; | ||
224 | |||
225 | retval = sst_create_ipc_msg(arg, large); | ||
226 | if (retval) | ||
227 | return retval; | ||
228 | *block = sst_create_block(sst_drv_ctx, msg_id, drv_id); | ||
229 | if (*block == NULL) { | ||
230 | kfree(*arg); | ||
231 | return -ENOMEM; | ||
232 | } | ||
233 | return retval; | ||
234 | } | ||
235 | |||
236 | /* | ||
237 | * sst_clean_stream - clean the stream context | ||
238 | * | ||
239 | * @stream: stream structure | ||
240 | * | ||
241 | * this function resets the stream contexts | ||
242 | * should be called in free | ||
243 | */ | ||
244 | void sst_clean_stream(struct stream_info *stream) | ||
245 | { | ||
246 | stream->status = STREAM_UN_INIT; | ||
247 | stream->prev = STREAM_UN_INIT; | ||
248 | mutex_lock(&stream->lock); | ||
249 | stream->cumm_bytes = 0; | ||
250 | mutex_unlock(&stream->lock); | ||
251 | } | ||
252 | |||
253 | int sst_prepare_and_post_msg(struct intel_sst_drv *sst, | ||
254 | int task_id, int ipc_msg, int cmd_id, int pipe_id, | ||
255 | size_t mbox_data_len, const void *mbox_data, void **data, | ||
256 | bool large, bool fill_dsp, bool sync, bool response) | ||
257 | { | ||
258 | struct ipc_post *msg = NULL; | ||
259 | struct ipc_dsp_hdr dsp_hdr; | ||
260 | struct sst_block *block; | ||
261 | int ret = 0, pvt_id; | ||
262 | |||
263 | pvt_id = sst_assign_pvt_id(sst); | ||
264 | if (pvt_id < 0) | ||
265 | return pvt_id; | ||
266 | |||
267 | if (response) | ||
268 | ret = sst_create_block_and_ipc_msg( | ||
269 | &msg, large, sst, &block, ipc_msg, pvt_id); | ||
270 | else | ||
271 | ret = sst_create_ipc_msg(&msg, large); | ||
272 | |||
273 | if (ret < 0) { | ||
274 | test_and_clear_bit(pvt_id, &sst->pvt_id); | ||
275 | return -ENOMEM; | ||
276 | } | ||
277 | |||
278 | dev_dbg(sst->dev, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n", | ||
279 | pvt_id, pipe_id, task_id, ipc_msg); | ||
280 | sst_fill_header_mrfld(&msg->mrfld_header, ipc_msg, | ||
281 | task_id, large, pvt_id); | ||
282 | msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr) + mbox_data_len; | ||
283 | msg->mrfld_header.p.header_high.part.res_rqd = !sync; | ||
284 | dev_dbg(sst->dev, "header:%x\n", | ||
285 | msg->mrfld_header.p.header_high.full); | ||
286 | dev_dbg(sst->dev, "response rqd: %x", | ||
287 | msg->mrfld_header.p.header_high.part.res_rqd); | ||
288 | dev_dbg(sst->dev, "msg->mrfld_header.p.header_low_payload:%d", | ||
289 | msg->mrfld_header.p.header_low_payload); | ||
290 | if (fill_dsp) { | ||
291 | sst_fill_header_dsp(&dsp_hdr, cmd_id, pipe_id, mbox_data_len); | ||
292 | memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr)); | ||
293 | if (mbox_data_len) { | ||
294 | memcpy(msg->mailbox_data + sizeof(dsp_hdr), | ||
295 | mbox_data, mbox_data_len); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | if (sync) | ||
300 | sst->ops->post_message(sst, msg, true); | ||
301 | else | ||
302 | sst_add_to_dispatch_list_and_post(sst, msg); | ||
303 | |||
304 | if (response) { | ||
305 | ret = sst_wait_timeout(sst, block); | ||
306 | if (ret < 0) { | ||
307 | goto out; | ||
308 | } else if(block->data) { | ||
309 | if (!data) | ||
310 | goto out; | ||
311 | *data = kzalloc(block->size, GFP_KERNEL); | ||
312 | if (!(*data)) { | ||
313 | ret = -ENOMEM; | ||
314 | goto out; | ||
315 | } else | ||
316 | memcpy(data, (void *) block->data, block->size); | ||
317 | } | ||
318 | } | ||
319 | out: | ||
320 | if (response) | ||
321 | sst_free_block(sst, block); | ||
322 | test_and_clear_bit(pvt_id, &sst->pvt_id); | ||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | int sst_pm_runtime_put(struct intel_sst_drv *sst_drv) | ||
327 | { | ||
328 | int ret; | ||
329 | |||
330 | pm_runtime_mark_last_busy(sst_drv->dev); | ||
331 | ret = pm_runtime_put_autosuspend(sst_drv->dev); | ||
332 | if (ret < 0) | ||
333 | return ret; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | void sst_fill_header_mrfld(union ipc_header_mrfld *header, | ||
338 | int msg, int task_id, int large, int drv_id) | ||
339 | { | ||
340 | header->full = 0; | ||
341 | header->p.header_high.part.msg_id = msg; | ||
342 | header->p.header_high.part.task_id = task_id; | ||
343 | header->p.header_high.part.large = large; | ||
344 | header->p.header_high.part.drv_id = drv_id; | ||
345 | header->p.header_high.part.done = 0; | ||
346 | header->p.header_high.part.busy = 1; | ||
347 | header->p.header_high.part.res_rqd = 1; | ||
348 | } | ||
349 | |||
350 | void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg, | ||
351 | int pipe_id, int len) | ||
352 | { | ||
353 | dsp->cmd_id = msg; | ||
354 | dsp->mod_index_id = 0xff; | ||
355 | dsp->pipe_id = pipe_id; | ||
356 | dsp->length = len; | ||
357 | dsp->mod_id = 0; | ||
358 | } | ||
359 | |||
360 | #define SST_MAX_BLOCKS 15 | ||
361 | /* | ||
362 | * sst_assign_pvt_id - assign a pvt id for stream | ||
363 | * | ||
364 | * @sst_drv_ctx : driver context | ||
365 | * | ||
366 | * this function assigns a private id for calls that dont have stream | ||
367 | * context yet, should be called with lock held | ||
368 | * uses bits for the id, and finds first free bits and assigns that | ||
369 | */ | ||
370 | int sst_assign_pvt_id(struct intel_sst_drv *drv) | ||
371 | { | ||
372 | int local; | ||
373 | |||
374 | spin_lock(&drv->block_lock); | ||
375 | /* find first zero index from lsb */ | ||
376 | local = ffz(drv->pvt_id); | ||
377 | dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local); | ||
378 | if (local >= SST_MAX_BLOCKS){ | ||
379 | spin_unlock(&drv->block_lock); | ||
380 | dev_err(drv->dev, "PVT _ID error: no free id blocks "); | ||
381 | return -EINVAL; | ||
382 | } | ||
383 | /* toggle the index */ | ||
384 | change_bit(local, &drv->pvt_id); | ||
385 | spin_unlock(&drv->block_lock); | ||
386 | return local; | ||
387 | } | ||
388 | |||
389 | void sst_init_stream(struct stream_info *stream, | ||
390 | int codec, int sst_id, int ops, u8 slot) | ||
391 | { | ||
392 | stream->status = STREAM_INIT; | ||
393 | stream->prev = STREAM_UN_INIT; | ||
394 | stream->ops = ops; | ||
395 | } | ||
396 | |||
397 | int sst_validate_strid( | ||
398 | struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
399 | { | ||
400 | if (str_id <= 0 || str_id > sst_drv_ctx->info.max_streams) { | ||
401 | dev_err(sst_drv_ctx->dev, | ||
402 | "SST ERR: invalid stream id : %d, max %d\n", | ||
403 | str_id, sst_drv_ctx->info.max_streams); | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | struct stream_info *get_stream_info( | ||
411 | struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
412 | { | ||
413 | if (sst_validate_strid(sst_drv_ctx, str_id)) | ||
414 | return NULL; | ||
415 | return &sst_drv_ctx->streams[str_id]; | ||
416 | } | ||
417 | |||
418 | int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
419 | u32 pipe_id) | ||
420 | { | ||
421 | int i; | ||
422 | |||
423 | for (i = 1; i <= sst_drv_ctx->info.max_streams; i++) | ||
424 | if (pipe_id == sst_drv_ctx->streams[i].pipe_id) | ||
425 | return i; | ||
426 | |||
427 | dev_dbg(sst_drv_ctx->dev, "no such pipe_id(%u)", pipe_id); | ||
428 | return -1; | ||
429 | } | ||
430 | |||
431 | u32 relocate_imr_addr_mrfld(u32 base_addr) | ||
432 | { | ||
433 | /* Get the difference from 512MB aligned base addr */ | ||
434 | /* relocate the base */ | ||
435 | base_addr = MRFLD_FW_VIRTUAL_BASE + (base_addr % (512 * 1024 * 1024)); | ||
436 | return base_addr; | ||
437 | } | ||
438 | EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld); | ||
439 | |||
440 | void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst, | ||
441 | struct ipc_post *msg) | ||
442 | { | ||
443 | unsigned long irq_flags; | ||
444 | |||
445 | spin_lock_irqsave(&sst->ipc_spin_lock, irq_flags); | ||
446 | list_add_tail(&msg->node, &sst->ipc_dispatch_list); | ||
447 | spin_unlock_irqrestore(&sst->ipc_spin_lock, irq_flags); | ||
448 | sst->ops->post_message(sst, NULL, false); | ||
449 | } | ||
diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/sst/sst_stream.c new file mode 100644 index 000000000000..dae2a41997aa --- /dev/null +++ b/sound/soc/intel/sst/sst_stream.c | |||
@@ -0,0 +1,437 @@ | |||
1 | /* | ||
2 | * sst_stream.c - Intel SST Driver for audio engine | ||
3 | * | ||
4 | * Copyright (C) 2008-14 Intel Corp | ||
5 | * Authors: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Harsha Priya <priya.harsha@intel.com> | ||
7 | * Dharageswari R <dharageswari.r@intel.com> | ||
8 | * KP Jeeja <jeeja.kp@intel.com> | ||
9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License as published by | ||
13 | * the Free Software Foundation; version 2 of the License. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, but | ||
16 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
18 | * General Public License for more details. | ||
19 | * | ||
20 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
21 | */ | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/firmware.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/soc.h> | ||
30 | #include <sound/compress_driver.h> | ||
31 | #include <asm/platform_sst_audio.h> | ||
32 | #include "../sst-mfld-platform.h" | ||
33 | #include "sst.h" | ||
34 | #include "../sst-dsp.h" | ||
35 | |||
36 | int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params) | ||
37 | { | ||
38 | struct snd_sst_alloc_mrfld alloc_param; | ||
39 | struct snd_sst_params *str_params; | ||
40 | struct snd_sst_tstamp fw_tstamp; | ||
41 | struct stream_info *str_info; | ||
42 | struct snd_sst_alloc_response *response; | ||
43 | unsigned int str_id, pipe_id, task_id; | ||
44 | int i, num_ch, ret = 0; | ||
45 | void *data = NULL; | ||
46 | |||
47 | dev_dbg(sst_drv_ctx->dev, "Enter\n"); | ||
48 | BUG_ON(!params); | ||
49 | |||
50 | str_params = (struct snd_sst_params *)params; | ||
51 | memset(&alloc_param, 0, sizeof(alloc_param)); | ||
52 | alloc_param.operation = str_params->ops; | ||
53 | alloc_param.codec_type = str_params->codec; | ||
54 | alloc_param.sg_count = str_params->aparams.sg_count; | ||
55 | alloc_param.ring_buf_info[0].addr = | ||
56 | str_params->aparams.ring_buf_info[0].addr; | ||
57 | alloc_param.ring_buf_info[0].size = | ||
58 | str_params->aparams.ring_buf_info[0].size; | ||
59 | alloc_param.frag_size = str_params->aparams.frag_size; | ||
60 | |||
61 | memcpy(&alloc_param.codec_params, &str_params->sparams, | ||
62 | sizeof(struct snd_sst_stream_params)); | ||
63 | |||
64 | /* | ||
65 | * fill channel map params for multichannel support. | ||
66 | * Ideally channel map should be received from upper layers | ||
67 | * for multichannel support. | ||
68 | * Currently hardcoding as per FW reqm. | ||
69 | */ | ||
70 | num_ch = sst_get_num_channel(str_params); | ||
71 | for (i = 0; i < 8; i++) { | ||
72 | if (i < num_ch) | ||
73 | alloc_param.codec_params.uc.pcm_params.channel_map[i] = i; | ||
74 | else | ||
75 | alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF; | ||
76 | } | ||
77 | |||
78 | str_id = str_params->stream_id; | ||
79 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
80 | if (str_info == NULL) { | ||
81 | dev_err(sst_drv_ctx->dev, "get stream info returned null\n"); | ||
82 | return -EINVAL; | ||
83 | } | ||
84 | |||
85 | pipe_id = str_params->device_type; | ||
86 | task_id = str_params->task; | ||
87 | sst_drv_ctx->streams[str_id].pipe_id = pipe_id; | ||
88 | sst_drv_ctx->streams[str_id].task_id = task_id; | ||
89 | sst_drv_ctx->streams[str_id].num_ch = num_ch; | ||
90 | |||
91 | if (sst_drv_ctx->info.lpe_viewpt_rqd) | ||
92 | alloc_param.ts = sst_drv_ctx->info.mailbox_start + | ||
93 | sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); | ||
94 | else | ||
95 | alloc_param.ts = sst_drv_ctx->mailbox_add + | ||
96 | sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp)); | ||
97 | |||
98 | dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n", | ||
99 | alloc_param.ts); | ||
100 | dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n", | ||
101 | pipe_id, task_id); | ||
102 | |||
103 | /* allocate device type context */ | ||
104 | sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type, | ||
105 | str_id, alloc_param.operation, 0); | ||
106 | |||
107 | dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n", | ||
108 | str_id, pipe_id); | ||
109 | ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD, | ||
110 | IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param), | ||
111 | &alloc_param, data, true, true, false, true); | ||
112 | |||
113 | if (ret < 0) { | ||
114 | dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); | ||
115 | /* alloc failed, so reset the state to uninit */ | ||
116 | str_info->status = STREAM_UN_INIT; | ||
117 | str_id = ret; | ||
118 | } else if (data) { | ||
119 | response = (struct snd_sst_alloc_response *)data; | ||
120 | ret = response->str_type.result; | ||
121 | if (!ret) | ||
122 | goto out; | ||
123 | dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret); | ||
124 | if (ret == SST_ERR_STREAM_IN_USE) { | ||
125 | dev_err(sst_drv_ctx->dev, | ||
126 | "FW not in clean state, send free for:%d\n", str_id); | ||
127 | sst_free_stream(sst_drv_ctx, str_id); | ||
128 | } | ||
129 | str_id = -ret; | ||
130 | } | ||
131 | out: | ||
132 | kfree(data); | ||
133 | return str_id; | ||
134 | } | ||
135 | |||
136 | /** | ||
137 | * sst_start_stream - Send msg for a starting stream | ||
138 | * @str_id: stream ID | ||
139 | * | ||
140 | * This function is called by any function which wants to start | ||
141 | * a stream. | ||
142 | */ | ||
143 | int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
144 | { | ||
145 | int retval = 0; | ||
146 | struct stream_info *str_info; | ||
147 | u16 data = 0; | ||
148 | |||
149 | dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id); | ||
150 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
151 | if (!str_info) | ||
152 | return -EINVAL; | ||
153 | if (str_info->status != STREAM_RUNNING) | ||
154 | return -EBADRQC; | ||
155 | |||
156 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
157 | IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id, | ||
158 | sizeof(u16), &data, NULL, true, true, true, false); | ||
159 | |||
160 | return retval; | ||
161 | } | ||
162 | |||
163 | int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, | ||
164 | struct snd_sst_bytes_v2 *bytes) | ||
165 | { struct ipc_post *msg = NULL; | ||
166 | u32 length; | ||
167 | int pvt_id, ret = 0; | ||
168 | struct sst_block *block = NULL; | ||
169 | |||
170 | dev_dbg(sst_drv_ctx->dev, | ||
171 | "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n", | ||
172 | bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id, | ||
173 | bytes->pipe_id, bytes->len); | ||
174 | |||
175 | if (sst_create_ipc_msg(&msg, true)) | ||
176 | return -ENOMEM; | ||
177 | |||
178 | pvt_id = sst_assign_pvt_id(sst_drv_ctx); | ||
179 | sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg, | ||
180 | bytes->task_id, 1, pvt_id); | ||
181 | msg->mrfld_header.p.header_high.part.res_rqd = bytes->block; | ||
182 | length = bytes->len; | ||
183 | msg->mrfld_header.p.header_low_payload = length; | ||
184 | dev_dbg(sst_drv_ctx->dev, "length is %d\n", length); | ||
185 | memcpy(msg->mailbox_data, &bytes->bytes, bytes->len); | ||
186 | if (bytes->block) { | ||
187 | block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id); | ||
188 | if (block == NULL) { | ||
189 | kfree(msg); | ||
190 | ret = -ENOMEM; | ||
191 | goto out; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg); | ||
196 | dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d", | ||
197 | msg->mrfld_header.p.header_low_payload); | ||
198 | |||
199 | if (bytes->block) { | ||
200 | ret = sst_wait_timeout(sst_drv_ctx, block); | ||
201 | if (ret) { | ||
202 | dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret); | ||
203 | sst_free_block(sst_drv_ctx, block); | ||
204 | goto out; | ||
205 | } | ||
206 | } | ||
207 | if (bytes->type == SND_SST_BYTES_GET) { | ||
208 | /* | ||
209 | * copy the reply and send back | ||
210 | * we need to update only sz and payload | ||
211 | */ | ||
212 | if (bytes->block) { | ||
213 | unsigned char *r = block->data; | ||
214 | |||
215 | dev_dbg(sst_drv_ctx->dev, "read back %d bytes", | ||
216 | bytes->len); | ||
217 | memcpy(bytes->bytes, r, bytes->len); | ||
218 | } | ||
219 | } | ||
220 | if (bytes->block) | ||
221 | sst_free_block(sst_drv_ctx, block); | ||
222 | out: | ||
223 | test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id); | ||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * sst_pause_stream - Send msg for a pausing stream | ||
229 | * @str_id: stream ID | ||
230 | * | ||
231 | * This function is called by any function which wants to pause | ||
232 | * an already running stream. | ||
233 | */ | ||
234 | int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
235 | { | ||
236 | int retval = 0; | ||
237 | struct stream_info *str_info; | ||
238 | |||
239 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id); | ||
240 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
241 | if (!str_info) | ||
242 | return -EINVAL; | ||
243 | if (str_info->status == STREAM_PAUSED) | ||
244 | return 0; | ||
245 | if (str_info->status == STREAM_RUNNING || | ||
246 | str_info->status == STREAM_INIT) { | ||
247 | if (str_info->prev == STREAM_UN_INIT) | ||
248 | return -EBADRQC; | ||
249 | |||
250 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
251 | IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id, | ||
252 | 0, NULL, NULL, true, true, false, true); | ||
253 | |||
254 | if (retval == 0) { | ||
255 | str_info->prev = str_info->status; | ||
256 | str_info->status = STREAM_PAUSED; | ||
257 | } else if (retval == SST_ERR_INVALID_STREAM_ID) { | ||
258 | retval = -EINVAL; | ||
259 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
260 | sst_clean_stream(str_info); | ||
261 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
262 | } | ||
263 | } else { | ||
264 | retval = -EBADRQC; | ||
265 | dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n "); | ||
266 | } | ||
267 | |||
268 | return retval; | ||
269 | } | ||
270 | |||
271 | /** | ||
272 | * sst_resume_stream - Send msg for resuming stream | ||
273 | * @str_id: stream ID | ||
274 | * | ||
275 | * This function is called by any function which wants to resume | ||
276 | * an already paused stream. | ||
277 | */ | ||
278 | int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
279 | { | ||
280 | int retval = 0; | ||
281 | struct stream_info *str_info; | ||
282 | |||
283 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id); | ||
284 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
285 | if (!str_info) | ||
286 | return -EINVAL; | ||
287 | if (str_info->status == STREAM_RUNNING) | ||
288 | return 0; | ||
289 | if (str_info->status == STREAM_PAUSED) { | ||
290 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
291 | IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD, | ||
292 | str_info->pipe_id, 0, NULL, NULL, | ||
293 | true, true, false, true); | ||
294 | |||
295 | if (!retval) { | ||
296 | if (str_info->prev == STREAM_RUNNING) | ||
297 | str_info->status = STREAM_RUNNING; | ||
298 | else | ||
299 | str_info->status = STREAM_INIT; | ||
300 | str_info->prev = STREAM_PAUSED; | ||
301 | } else if (retval == -SST_ERR_INVALID_STREAM_ID) { | ||
302 | retval = -EINVAL; | ||
303 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
304 | sst_clean_stream(str_info); | ||
305 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
306 | } | ||
307 | } else { | ||
308 | retval = -EBADRQC; | ||
309 | dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n"); | ||
310 | } | ||
311 | |||
312 | return retval; | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * sst_drop_stream - Send msg for stopping stream | ||
318 | * @str_id: stream ID | ||
319 | * | ||
320 | * This function is called by any function which wants to stop | ||
321 | * a stream. | ||
322 | */ | ||
323 | int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
324 | { | ||
325 | int retval = 0; | ||
326 | struct stream_info *str_info; | ||
327 | |||
328 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id); | ||
329 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
330 | if (!str_info) | ||
331 | return -EINVAL; | ||
332 | |||
333 | if (str_info->status != STREAM_UN_INIT) { | ||
334 | str_info->prev = STREAM_UN_INIT; | ||
335 | str_info->status = STREAM_INIT; | ||
336 | str_info->cumm_bytes = 0; | ||
337 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, | ||
338 | IPC_CMD, IPC_IA_DROP_STREAM_MRFLD, | ||
339 | str_info->pipe_id, 0, NULL, NULL, | ||
340 | true, true, true, false); | ||
341 | } else { | ||
342 | retval = -EBADRQC; | ||
343 | dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n", | ||
344 | str_info->status); | ||
345 | } | ||
346 | return retval; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * sst_drain_stream - Send msg for draining stream | ||
351 | * @str_id: stream ID | ||
352 | * | ||
353 | * This function is called by any function which wants to drain | ||
354 | * a stream. | ||
355 | */ | ||
356 | int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx, | ||
357 | int str_id, bool partial_drain) | ||
358 | { | ||
359 | int retval = 0; | ||
360 | struct stream_info *str_info; | ||
361 | |||
362 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id); | ||
363 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
364 | if (!str_info) | ||
365 | return -EINVAL; | ||
366 | if (str_info->status != STREAM_RUNNING && | ||
367 | str_info->status != STREAM_INIT && | ||
368 | str_info->status != STREAM_PAUSED) { | ||
369 | dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n", | ||
370 | str_info->status); | ||
371 | return -EBADRQC; | ||
372 | } | ||
373 | |||
374 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
375 | IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id, | ||
376 | sizeof(u8), &partial_drain, NULL, true, true, false, false); | ||
377 | /* | ||
378 | * with new non blocked drain implementation in core we dont need to | ||
379 | * wait for respsonse, and need to only invoke callback for drain | ||
380 | * complete | ||
381 | */ | ||
382 | |||
383 | return retval; | ||
384 | } | ||
385 | |||
386 | /** | ||
387 | * sst_free_stream - Frees a stream | ||
388 | * @str_id: stream ID | ||
389 | * | ||
390 | * This function is called by any function which wants to free | ||
391 | * a stream. | ||
392 | */ | ||
393 | int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id) | ||
394 | { | ||
395 | int retval = 0; | ||
396 | struct stream_info *str_info; | ||
397 | struct intel_sst_ops *ops; | ||
398 | |||
399 | dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id); | ||
400 | |||
401 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
402 | if (sst_drv_ctx->sst_state == SST_RESET) { | ||
403 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
404 | return -ENODEV; | ||
405 | } | ||
406 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
407 | str_info = get_stream_info(sst_drv_ctx, str_id); | ||
408 | if (!str_info) | ||
409 | return -EINVAL; | ||
410 | ops = sst_drv_ctx->ops; | ||
411 | |||
412 | mutex_lock(&str_info->lock); | ||
413 | if (str_info->status != STREAM_UN_INIT) { | ||
414 | str_info->prev = str_info->status; | ||
415 | str_info->status = STREAM_UN_INIT; | ||
416 | mutex_unlock(&str_info->lock); | ||
417 | |||
418 | dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n", | ||
419 | str_id, str_info->pipe_id); | ||
420 | retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD, | ||
421 | IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0, | ||
422 | NULL, NULL, true, true, false, true); | ||
423 | |||
424 | dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n", | ||
425 | retval); | ||
426 | mutex_lock(&sst_drv_ctx->sst_lock); | ||
427 | sst_clean_stream(str_info); | ||
428 | mutex_unlock(&sst_drv_ctx->sst_lock); | ||
429 | dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n"); | ||
430 | } else { | ||
431 | mutex_unlock(&str_info->lock); | ||
432 | retval = -EBADRQC; | ||
433 | dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n"); | ||
434 | } | ||
435 | |||
436 | return retval; | ||
437 | } | ||
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c index 5cb91f9e8626..0fb7d2a91c3a 100644 --- a/sound/soc/jz4740/qi_lb60.c +++ b/sound/soc/jz4740/qi_lb60.c | |||
@@ -77,25 +77,18 @@ static int qi_lb60_probe(struct platform_device *pdev) | |||
77 | { | 77 | { |
78 | struct qi_lb60 *qi_lb60; | 78 | struct qi_lb60 *qi_lb60; |
79 | struct snd_soc_card *card = &qi_lb60_card; | 79 | struct snd_soc_card *card = &qi_lb60_card; |
80 | int ret; | ||
81 | 80 | ||
82 | qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL); | 81 | qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL); |
83 | if (!qi_lb60) | 82 | if (!qi_lb60) |
84 | return -ENOMEM; | 83 | return -ENOMEM; |
85 | 84 | ||
86 | qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd"); | 85 | qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd", GPIOD_OUT_LOW); |
87 | if (IS_ERR(qi_lb60->snd_gpio)) | 86 | if (IS_ERR(qi_lb60->snd_gpio)) |
88 | return PTR_ERR(qi_lb60->snd_gpio); | 87 | return PTR_ERR(qi_lb60->snd_gpio); |
89 | ret = gpiod_direction_output(qi_lb60->snd_gpio, 0); | ||
90 | if (ret) | ||
91 | return ret; | ||
92 | 88 | ||
93 | qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp"); | 89 | qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp", GPIOD_OUT_LOW); |
94 | if (IS_ERR(qi_lb60->amp_gpio)) | 90 | if (IS_ERR(qi_lb60->amp_gpio)) |
95 | return PTR_ERR(qi_lb60->amp_gpio); | 91 | return PTR_ERR(qi_lb60->amp_gpio); |
96 | ret = gpiod_direction_output(qi_lb60->amp_gpio, 0); | ||
97 | if (ret) | ||
98 | return ret; | ||
99 | 92 | ||
100 | card->dev = &pdev->dev; | 93 | card->dev = &pdev->dev; |
101 | 94 | ||
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c index 231d7e7b0711..83b2fea09219 100644 --- a/sound/soc/mxs/mxs-saif.c +++ b/sound/soc/mxs/mxs-saif.c | |||
@@ -773,7 +773,7 @@ static int mxs_saif_probe(struct platform_device *pdev) | |||
773 | 773 | ||
774 | saif->dev = &pdev->dev; | 774 | saif->dev = &pdev->dev; |
775 | ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, | 775 | ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0, |
776 | "mxs-saif", saif); | 776 | dev_name(&pdev->dev), saif); |
777 | if (ret) { | 777 | if (ret) { |
778 | dev_err(&pdev->dev, "failed to request irq\n"); | 778 | dev_err(&pdev->dev, "failed to request irq\n"); |
779 | return ret; | 779 | return ret; |
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 61822cc53bd3..3bba6cfe4f29 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c | |||
@@ -49,13 +49,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream, | |||
49 | break; | 49 | break; |
50 | } | 50 | } |
51 | 51 | ||
52 | /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */ | ||
53 | if (mclk < 8000000 || mclk > 27000000) { | ||
54 | dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n", | ||
55 | mclk / 1000000, mclk / 1000 % 1000); | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ | 52 | /* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */ |
60 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); | 53 | ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0); |
61 | if (ret) { | 54 | if (ret) { |
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c index f2f67942b229..dff443e4b657 100644 --- a/sound/soc/nuc900/nuc900-ac97.c +++ b/sound/soc/nuc900/nuc900-ac97.c | |||
@@ -298,7 +298,7 @@ static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = { | |||
298 | static struct snd_soc_dai_driver nuc900_ac97_dai = { | 298 | static struct snd_soc_dai_driver nuc900_ac97_dai = { |
299 | .probe = nuc900_ac97_probe, | 299 | .probe = nuc900_ac97_probe, |
300 | .remove = nuc900_ac97_remove, | 300 | .remove = nuc900_ac97_remove, |
301 | .ac97_control = 1, | 301 | .bus_control = true, |
302 | .playback = { | 302 | .playback = { |
303 | .rates = SNDRV_PCM_RATE_8000_48000, | 303 | .rates = SNDRV_PCM_RATE_8000_48000, |
304 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 304 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index d44463a7b0fa..2738b1984410 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -25,15 +25,15 @@ config SND_OMAP_SOC_N810 | |||
25 | Say Y if you want to add support for SoC audio on Nokia N810. | 25 | Say Y if you want to add support for SoC audio on Nokia N810. |
26 | 26 | ||
27 | config SND_OMAP_SOC_RX51 | 27 | config SND_OMAP_SOC_RX51 |
28 | tristate "SoC Audio support for Nokia RX-51" | 28 | tristate "SoC Audio support for Nokia N900 (RX-51)" |
29 | depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C | 29 | depends on SND_OMAP_SOC && ARM && I2C |
30 | select SND_OMAP_SOC_MCBSP | 30 | select SND_OMAP_SOC_MCBSP |
31 | select SND_SOC_TLV320AIC3X | 31 | select SND_SOC_TLV320AIC3X |
32 | select SND_SOC_TPA6130A2 | 32 | select SND_SOC_TPA6130A2 |
33 | depends on GPIOLIB | 33 | depends on GPIOLIB |
34 | help | 34 | help |
35 | Say Y if you want to add support for SoC audio on Nokia RX-51 | 35 | Say Y if you want to add support for SoC audio on Nokia N900 |
36 | hardware. This is also known as Nokia N900 product. | 36 | cellphone. |
37 | 37 | ||
38 | config SND_OMAP_SOC_AMS_DELTA | 38 | config SND_OMAP_SOC_AMS_DELTA |
39 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" | 39 | tristate "SoC Audio support for Amstrad E3 (Delta) videophone" |
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 86c75384c3c8..68a125205375 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -621,8 +621,7 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp) | |||
621 | mcbsp->reg_cache = NULL; | 621 | mcbsp->reg_cache = NULL; |
622 | spin_unlock(&mcbsp->lock); | 622 | spin_unlock(&mcbsp->lock); |
623 | 623 | ||
624 | if (reg_cache) | 624 | kfree(reg_cache); |
625 | kfree(reg_cache); | ||
626 | } | 625 | } |
627 | 626 | ||
628 | /* | 627 | /* |
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 595eee341e90..a6b2be20cc0b 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -127,15 +127,12 @@ 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 | unsigned short reg; | ||
131 | 130 | ||
132 | /* Prepare GPIO8 for rear speaker amplifier */ | 131 | /* Prepare GPIO8 for rear speaker amplifier */ |
133 | reg = codec->driver->read(codec, AC97_GPIO_CFG); | 132 | snd_soc_update_bits(codec, AC97_GPIO_CFG, 0x100, 0x100); |
134 | codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100); | ||
135 | 133 | ||
136 | /* Prepare MIC input */ | 134 | /* Prepare MIC input */ |
137 | reg = codec->driver->read(codec, AC97_3D_CONTROL); | 135 | snd_soc_update_bits(codec, AC97_3D_CONTROL, 0xc000, 0xc000); |
138 | codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000); | ||
139 | 136 | ||
140 | return 0; | 137 | return 0; |
141 | } | 138 | } |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index a8e097433074..cbba063a7210 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -97,7 +97,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, | |||
97 | int ret = 0; | 97 | int ret = 0; |
98 | 98 | ||
99 | if (!cpu_dai->active) { | 99 | if (!cpu_dai->active) { |
100 | clk_enable(ssp->clk); | 100 | clk_prepare_enable(ssp->clk); |
101 | pxa_ssp_disable(ssp); | 101 | pxa_ssp_disable(ssp); |
102 | } | 102 | } |
103 | 103 | ||
@@ -121,7 +121,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, | |||
121 | 121 | ||
122 | if (!cpu_dai->active) { | 122 | if (!cpu_dai->active) { |
123 | pxa_ssp_disable(ssp); | 123 | pxa_ssp_disable(ssp); |
124 | clk_disable(ssp->clk); | 124 | clk_disable_unprepare(ssp->clk); |
125 | } | 125 | } |
126 | 126 | ||
127 | kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); | 127 | kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); |
@@ -136,7 +136,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) | |||
136 | struct ssp_device *ssp = priv->ssp; | 136 | struct ssp_device *ssp = priv->ssp; |
137 | 137 | ||
138 | if (!cpu_dai->active) | 138 | if (!cpu_dai->active) |
139 | clk_enable(ssp->clk); | 139 | clk_prepare_enable(ssp->clk); |
140 | 140 | ||
141 | priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0); | 141 | priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0); |
142 | priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1); | 142 | priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1); |
@@ -144,7 +144,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) | |||
144 | priv->psp = __raw_readl(ssp->mmio_base + SSPSP); | 144 | priv->psp = __raw_readl(ssp->mmio_base + SSPSP); |
145 | 145 | ||
146 | pxa_ssp_disable(ssp); | 146 | pxa_ssp_disable(ssp); |
147 | clk_disable(ssp->clk); | 147 | clk_disable_unprepare(ssp->clk); |
148 | return 0; | 148 | return 0; |
149 | } | 149 | } |
150 | 150 | ||
@@ -154,7 +154,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) | |||
154 | struct ssp_device *ssp = priv->ssp; | 154 | struct ssp_device *ssp = priv->ssp; |
155 | uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; | 155 | uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; |
156 | 156 | ||
157 | clk_enable(ssp->clk); | 157 | clk_prepare_enable(ssp->clk); |
158 | 158 | ||
159 | __raw_writel(sssr, ssp->mmio_base + SSSR); | 159 | __raw_writel(sssr, ssp->mmio_base + SSSR); |
160 | __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); | 160 | __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); |
@@ -165,7 +165,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) | |||
165 | if (cpu_dai->active) | 165 | if (cpu_dai->active) |
166 | pxa_ssp_enable(ssp); | 166 | pxa_ssp_enable(ssp); |
167 | else | 167 | else |
168 | clk_disable(ssp->clk); | 168 | clk_disable_unprepare(ssp->clk); |
169 | 169 | ||
170 | return 0; | 170 | return 0; |
171 | } | 171 | } |
@@ -256,11 +256,11 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
256 | /* The SSP clock must be disabled when changing SSP clock mode | 256 | /* The SSP clock must be disabled when changing SSP clock mode |
257 | * on PXA2xx. On PXA3xx it must be enabled when doing so. */ | 257 | * on PXA2xx. On PXA3xx it must be enabled when doing so. */ |
258 | if (ssp->type != PXA3xx_SSP) | 258 | if (ssp->type != PXA3xx_SSP) |
259 | clk_disable(ssp->clk); | 259 | clk_disable_unprepare(ssp->clk); |
260 | val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0; | 260 | val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0; |
261 | pxa_ssp_write_reg(ssp, SSCR0, val); | 261 | pxa_ssp_write_reg(ssp, SSCR0, val); |
262 | if (ssp->type != PXA3xx_SSP) | 262 | if (ssp->type != PXA3xx_SSP) |
263 | clk_enable(ssp->clk); | 263 | clk_prepare_enable(ssp->clk); |
264 | 264 | ||
265 | return 0; | 265 | return 0; |
266 | } | 266 | } |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index ae956e3f4b9d..73ca2820c08c 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -157,7 +157,7 @@ static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = { | |||
157 | static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | 157 | static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { |
158 | { | 158 | { |
159 | .name = "pxa2xx-ac97", | 159 | .name = "pxa2xx-ac97", |
160 | .ac97_control = 1, | 160 | .bus_control = true, |
161 | .playback = { | 161 | .playback = { |
162 | .stream_name = "AC97 Playback", | 162 | .stream_name = "AC97 Playback", |
163 | .channels_min = 2, | 163 | .channels_min = 2, |
@@ -174,7 +174,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | |||
174 | }, | 174 | }, |
175 | { | 175 | { |
176 | .name = "pxa2xx-ac97-aux", | 176 | .name = "pxa2xx-ac97-aux", |
177 | .ac97_control = 1, | 177 | .bus_control = true, |
178 | .playback = { | 178 | .playback = { |
179 | .stream_name = "AC97 Aux Playback", | 179 | .stream_name = "AC97 Aux Playback", |
180 | .channels_min = 1, | 180 | .channels_min = 1, |
@@ -191,7 +191,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { | |||
191 | }, | 191 | }, |
192 | { | 192 | { |
193 | .name = "pxa2xx-ac97-mic", | 193 | .name = "pxa2xx-ac97-mic", |
194 | .ac97_control = 1, | 194 | .bus_control = true, |
195 | .capture = { | 195 | .capture = { |
196 | .stream_name = "AC97 Mic Capture", | 196 | .stream_name = "AC97 Mic Capture", |
197 | .channels_min = 1, | 197 | .channels_min = 1, |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 1373b017a951..d7d5fb20ea6f 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -305,19 +305,15 @@ static struct snd_soc_card snd_soc_spitz = { | |||
305 | .num_dapm_routes = ARRAY_SIZE(spitz_audio_map), | 305 | .num_dapm_routes = ARRAY_SIZE(spitz_audio_map), |
306 | }; | 306 | }; |
307 | 307 | ||
308 | static struct platform_device *spitz_snd_device; | 308 | static int spitz_probe(struct platform_device *pdev) |
309 | |||
310 | static int __init spitz_init(void) | ||
311 | { | 309 | { |
310 | struct snd_soc_card *card = &snd_soc_spitz; | ||
312 | int ret; | 311 | int ret; |
313 | 312 | ||
314 | if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita())) | 313 | if (machine_is_akita()) |
315 | return -ENODEV; | ||
316 | |||
317 | if (machine_is_borzoi() || machine_is_spitz()) | ||
318 | spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; | ||
319 | else | ||
320 | spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; | 314 | spitz_mic_gpio = AKITA_GPIO_MIC_BIAS; |
315 | else | ||
316 | spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS; | ||
321 | 317 | ||
322 | ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); | 318 | ret = gpio_request(spitz_mic_gpio, "MIC GPIO"); |
323 | if (ret) | 319 | if (ret) |
@@ -327,37 +323,45 @@ static int __init spitz_init(void) | |||
327 | if (ret) | 323 | if (ret) |
328 | goto err2; | 324 | goto err2; |
329 | 325 | ||
330 | spitz_snd_device = platform_device_alloc("soc-audio", -1); | 326 | card->dev = &pdev->dev; |
331 | if (!spitz_snd_device) { | 327 | |
332 | ret = -ENOMEM; | 328 | ret = snd_soc_register_card(card); |
329 | if (ret) { | ||
330 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
331 | ret); | ||
333 | goto err2; | 332 | goto err2; |
334 | } | 333 | } |
335 | 334 | ||
336 | platform_set_drvdata(spitz_snd_device, &snd_soc_spitz); | ||
337 | |||
338 | ret = platform_device_add(spitz_snd_device); | ||
339 | if (ret) | ||
340 | goto err3; | ||
341 | |||
342 | return 0; | 335 | return 0; |
343 | 336 | ||
344 | err3: | ||
345 | platform_device_put(spitz_snd_device); | ||
346 | err2: | 337 | err2: |
347 | gpio_free(spitz_mic_gpio); | 338 | gpio_free(spitz_mic_gpio); |
348 | err1: | 339 | err1: |
349 | return ret; | 340 | return ret; |
350 | } | 341 | } |
351 | 342 | ||
352 | static void __exit spitz_exit(void) | 343 | static int spitz_remove(struct platform_device *pdev) |
353 | { | 344 | { |
354 | platform_device_unregister(spitz_snd_device); | 345 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
346 | |||
347 | snd_soc_unregister_card(card); | ||
355 | gpio_free(spitz_mic_gpio); | 348 | gpio_free(spitz_mic_gpio); |
349 | return 0; | ||
356 | } | 350 | } |
357 | 351 | ||
358 | module_init(spitz_init); | 352 | static struct platform_driver spitz_driver = { |
359 | module_exit(spitz_exit); | 353 | .driver = { |
354 | .name = "spitz-audio", | ||
355 | .owner = THIS_MODULE, | ||
356 | .pm = &snd_soc_pm_ops, | ||
357 | }, | ||
358 | .probe = spitz_probe, | ||
359 | .remove = spitz_remove, | ||
360 | }; | ||
361 | |||
362 | module_platform_driver(spitz_driver); | ||
360 | 363 | ||
361 | MODULE_AUTHOR("Richard Purdie"); | 364 | MODULE_AUTHOR("Richard Purdie"); |
362 | MODULE_DESCRIPTION("ALSA SoC Spitz"); | 365 | MODULE_DESCRIPTION("ALSA SoC Spitz"); |
363 | MODULE_LICENSE("GPL"); | 366 | MODULE_LICENSE("GPL"); |
367 | MODULE_ALIAS("platform:spitz-audio"); | ||
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index 78fc159559b0..e18182699d83 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig | |||
@@ -1,11 +1,16 @@ | |||
1 | config SND_SOC_ROCKCHIP | 1 | config SND_SOC_ROCKCHIP |
2 | tristate "ASoC support for Rockchip" | 2 | tristate "ASoC support for Rockchip" |
3 | depends on COMPILE_TEST || ARCH_ROCKCHIP | 3 | depends on COMPILE_TEST || ARCH_ROCKCHIP |
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
5 | help | 4 | help |
6 | Say Y or M if you want to add support for codecs attached to | 5 | Say Y or M if you want to add support for codecs attached to |
7 | the Rockchip SoCs' Audio interfaces. You will also need to | 6 | the Rockchip SoCs' Audio interfaces. You will also need to |
8 | select the audio interfaces to support below. | 7 | select the audio interfaces to support below. |
9 | 8 | ||
10 | config SND_SOC_ROCKCHIP_I2S | 9 | config SND_SOC_ROCKCHIP_I2S |
11 | tristate | 10 | tristate "Rockchip I2S Device Driver" |
11 | depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP | ||
12 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
13 | help | ||
14 | Say Y or M if you want to add support for I2S driver for | ||
15 | Rockchip I2S device. The device supports upto maximum of | ||
16 | 8 channels each for play and record. | ||
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 55a38697443d..fc67f97f19f6 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_SOC_SAMSUNG | 1 | config SND_SOC_SAMSUNG |
2 | tristate "ASoC support for Samsung" | 2 | tristate "ASoC support for Samsung" |
3 | depends on PLAT_SAMSUNG | 3 | depends on (PLAT_SAMSUNG || ARCH_EXYNOS) |
4 | depends on S3C64XX_PL080 || !ARCH_S3C64XX | 4 | depends on S3C64XX_PL080 || !ARCH_S3C64XX |
5 | depends on S3C24XX_DMAC || !ARCH_S3C24XX | 5 | depends on S3C24XX_DMAC || !ARCH_S3C24XX |
6 | select SND_SOC_GENERIC_DMAENGINE_PCM | 6 | select SND_SOC_GENERIC_DMAENGINE_PCM |
@@ -239,3 +239,9 @@ config SND_SOC_ODROIDX2 | |||
239 | select SND_SAMSUNG_I2S | 239 | select SND_SAMSUNG_I2S |
240 | help | 240 | help |
241 | Say Y here to enable audio support for the Odroid-X2/U3. | 241 | Say Y here to enable audio support for the Odroid-X2/U3. |
242 | |||
243 | config SND_SOC_ARNDALE_RT5631_ALC5631 | ||
244 | tristate "Audio support for RT5631(ALC5631) on Arndale Board" | ||
245 | depends on SND_SOC_SAMSUNG | ||
246 | select SND_SAMSUNG_I2S | ||
247 | select SND_SOC_RT5631 | ||
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 91505ddaaf95..31e3dba7e3b5 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile | |||
@@ -45,6 +45,7 @@ snd-soc-lowland-objs := lowland.o | |||
45 | snd-soc-littlemill-objs := littlemill.o | 45 | snd-soc-littlemill-objs := littlemill.o |
46 | snd-soc-bells-objs := bells.o | 46 | snd-soc-bells-objs := bells.o |
47 | snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o | 47 | snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o |
48 | snd-soc-arndale-rt5631-objs := arndale_rt5631.o | ||
48 | 49 | ||
49 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o | 50 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o |
50 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 51 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o | |||
71 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o | 72 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o |
72 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o | 73 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o |
73 | obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o | 74 | obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o |
75 | obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o | ||
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index e1615113fd84..7952a625669d 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -288,7 +288,7 @@ static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai) | |||
288 | static struct snd_soc_dai_driver s3c_ac97_dai[] = { | 288 | static struct snd_soc_dai_driver s3c_ac97_dai[] = { |
289 | [S3C_AC97_DAI_PCM] = { | 289 | [S3C_AC97_DAI_PCM] = { |
290 | .name = "samsung-ac97", | 290 | .name = "samsung-ac97", |
291 | .ac97_control = 1, | 291 | .bus_control = true, |
292 | .playback = { | 292 | .playback = { |
293 | .stream_name = "AC97 Playback", | 293 | .stream_name = "AC97 Playback", |
294 | .channels_min = 2, | 294 | .channels_min = 2, |
@@ -306,7 +306,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = { | |||
306 | }, | 306 | }, |
307 | [S3C_AC97_DAI_MIC] = { | 307 | [S3C_AC97_DAI_MIC] = { |
308 | .name = "samsung-ac97-mic", | 308 | .name = "samsung-ac97-mic", |
309 | .ac97_control = 1, | 309 | .bus_control = true, |
310 | .capture = { | 310 | .capture = { |
311 | .stream_name = "AC97 Mic Capture", | 311 | .stream_name = "AC97 Mic Capture", |
312 | .channels_min = 1, | 312 | .channels_min = 1, |
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c new file mode 100644 index 000000000000..1e2b61ca8db2 --- /dev/null +++ b/sound/soc/samsung/arndale_rt5631.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * arndale_rt5631.c | ||
3 | * | ||
4 | * Copyright (c) 2014, Insignal Co., Ltd. | ||
5 | * | ||
6 | * Author: Claude <claude@insginal.co.kr> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/platform_device.h> | ||
16 | #include <linux/clk.h> | ||
17 | |||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | |||
23 | #include "i2s.h" | ||
24 | |||
25 | static int arndale_hw_params(struct snd_pcm_substream *substream, | ||
26 | struct snd_pcm_hw_params *params) | ||
27 | { | ||
28 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
29 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
30 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
31 | int rfs, ret; | ||
32 | unsigned long rclk; | ||
33 | |||
34 | rfs = 256; | ||
35 | |||
36 | rclk = params_rate(params) * rfs; | ||
37 | |||
38 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, | ||
39 | 0, SND_SOC_CLOCK_OUT); | ||
40 | if (ret < 0) | ||
41 | return ret; | ||
42 | |||
43 | ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0, | ||
44 | 0, SND_SOC_CLOCK_OUT); | ||
45 | |||
46 | if (ret < 0) | ||
47 | return ret; | ||
48 | |||
49 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT); | ||
50 | if (ret < 0) | ||
51 | return ret; | ||
52 | |||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | static struct snd_soc_ops arndale_ops = { | ||
57 | .hw_params = arndale_hw_params, | ||
58 | }; | ||
59 | |||
60 | static struct snd_soc_dai_link arndale_rt5631_dai[] = { | ||
61 | { | ||
62 | .name = "RT5631 HiFi", | ||
63 | .stream_name = "Primary", | ||
64 | .codec_dai_name = "rt5631-hifi", | ||
65 | .dai_fmt = SND_SOC_DAIFMT_I2S | ||
66 | | SND_SOC_DAIFMT_NB_NF | ||
67 | | SND_SOC_DAIFMT_CBS_CFS, | ||
68 | .ops = &arndale_ops, | ||
69 | }, | ||
70 | }; | ||
71 | |||
72 | static struct snd_soc_card arndale_rt5631 = { | ||
73 | .name = "Arndale RT5631", | ||
74 | .dai_link = arndale_rt5631_dai, | ||
75 | .num_links = ARRAY_SIZE(arndale_rt5631_dai), | ||
76 | }; | ||
77 | |||
78 | static int arndale_audio_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | int n, ret; | ||
81 | struct device_node *np = pdev->dev.of_node; | ||
82 | struct snd_soc_card *card = &arndale_rt5631; | ||
83 | |||
84 | card->dev = &pdev->dev; | ||
85 | |||
86 | for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) { | ||
87 | if (!arndale_rt5631_dai[n].cpu_dai_name) { | ||
88 | arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np, | ||
89 | "samsung,audio-cpu", n); | ||
90 | |||
91 | if (!arndale_rt5631_dai[n].cpu_of_node) { | ||
92 | dev_err(&pdev->dev, | ||
93 | "Property 'samsung,audio-cpu' missing or invalid\n"); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | } | ||
97 | if (!arndale_rt5631_dai[n].platform_name) | ||
98 | arndale_rt5631_dai[n].platform_of_node = | ||
99 | arndale_rt5631_dai[n].cpu_of_node; | ||
100 | |||
101 | arndale_rt5631_dai[n].codec_name = NULL; | ||
102 | arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np, | ||
103 | "samsung,audio-codec", n); | ||
104 | if (!arndale_rt5631_dai[0].codec_of_node) { | ||
105 | dev_err(&pdev->dev, | ||
106 | "Property 'samsung,audio-codec' missing or invalid\n"); | ||
107 | return -EINVAL; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | ret = devm_snd_soc_register_card(card->dev, card); | ||
112 | |||
113 | if (ret) | ||
114 | dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int arndale_audio_remove(struct platform_device *pdev) | ||
120 | { | ||
121 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
122 | |||
123 | snd_soc_unregister_card(card); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = { | ||
129 | { .compatible = "samsung,arndale-rt5631", }, | ||
130 | { .compatible = "samsung,arndale-alc5631", }, | ||
131 | {}, | ||
132 | }; | ||
133 | MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match); | ||
134 | |||
135 | static struct platform_driver arndale_audio_driver = { | ||
136 | .driver = { | ||
137 | .name = "arndale-audio", | ||
138 | .owner = THIS_MODULE, | ||
139 | .pm = &snd_soc_pm_ops, | ||
140 | .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match), | ||
141 | }, | ||
142 | .probe = arndale_audio_probe, | ||
143 | .remove = arndale_audio_remove, | ||
144 | }; | ||
145 | |||
146 | module_platform_driver(arndale_audio_driver); | ||
147 | |||
148 | MODULE_AUTHOR("Claude <claude@insignal.co.kr>"); | ||
149 | MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board"); | ||
150 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h index 821a50231002..9170c311d66e 100644 --- a/sound/soc/samsung/i2s-regs.h +++ b/sound/soc/samsung/i2s-regs.h | |||
@@ -33,8 +33,9 @@ | |||
33 | #define I2SLVL3ADDR 0x3c | 33 | #define I2SLVL3ADDR 0x3c |
34 | #define I2SSTR1 0x40 | 34 | #define I2SSTR1 0x40 |
35 | #define I2SVER 0x44 | 35 | #define I2SVER 0x44 |
36 | #define I2SFIC2 0x48 | 36 | #define I2SFIC1 0x48 |
37 | #define I2STDM 0x4c | 37 | #define I2STDM 0x4c |
38 | #define I2SFSTA 0x50 | ||
38 | 39 | ||
39 | #define CON_RSTCLR (1 << 31) | 40 | #define CON_RSTCLR (1 << 31) |
40 | #define CON_FRXOFSTATUS (1 << 26) | 41 | #define CON_FRXOFSTATUS (1 << 26) |
@@ -93,8 +94,6 @@ | |||
93 | #define MOD_BLC_24BIT (2 << 13) | 94 | #define MOD_BLC_24BIT (2 << 13) |
94 | #define MOD_BLC_MASK (3 << 13) | 95 | #define MOD_BLC_MASK (3 << 13) |
95 | 96 | ||
96 | #define MOD_IMS_SYSMUX (1 << 10) | ||
97 | #define MOD_SLAVE (1 << 11) | ||
98 | #define MOD_TXONLY (0 << 8) | 97 | #define MOD_TXONLY (0 << 8) |
99 | #define MOD_RXONLY (1 << 8) | 98 | #define MOD_RXONLY (1 << 8) |
100 | #define MOD_TXRX (2 << 8) | 99 | #define MOD_TXRX (2 << 8) |
@@ -132,7 +131,10 @@ | |||
132 | #define EXYNOS5420_MOD_BCLK_256FS 8 | 131 | #define EXYNOS5420_MOD_BCLK_256FS 8 |
133 | #define EXYNOS5420_MOD_BCLK_MASK 0xf | 132 | #define EXYNOS5420_MOD_BCLK_MASK 0xf |
134 | 133 | ||
135 | #define MOD_CDCLKCON (1 << 12) | 134 | #define EXYNOS7_MOD_RCLK_64FS 4 |
135 | #define EXYNOS7_MOD_RCLK_128FS 5 | ||
136 | #define EXYNOS7_MOD_RCLK_96FS 6 | ||
137 | #define EXYNOS7_MOD_RCLK_192FS 7 | ||
136 | 138 | ||
137 | #define PSR_PSREN (1 << 15) | 139 | #define PSR_PSREN (1 << 15) |
138 | 140 | ||
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 9d513473b300..c7aafcd95de3 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -36,9 +36,24 @@ enum samsung_dai_type { | |||
36 | TYPE_SEC, | 36 | TYPE_SEC, |
37 | }; | 37 | }; |
38 | 38 | ||
39 | struct samsung_i2s_variant_regs { | ||
40 | unsigned int bfs_off; | ||
41 | unsigned int rfs_off; | ||
42 | unsigned int sdf_off; | ||
43 | unsigned int txr_off; | ||
44 | unsigned int rclksrc_off; | ||
45 | unsigned int mss_off; | ||
46 | unsigned int cdclkcon_off; | ||
47 | unsigned int lrp_off; | ||
48 | unsigned int bfs_mask; | ||
49 | unsigned int rfs_mask; | ||
50 | unsigned int ftx0cnt_off; | ||
51 | }; | ||
52 | |||
39 | struct samsung_i2s_dai_data { | 53 | struct samsung_i2s_dai_data { |
40 | int dai_type; | 54 | int dai_type; |
41 | u32 quirks; | 55 | u32 quirks; |
56 | const struct samsung_i2s_variant_regs *i2s_variant_regs; | ||
42 | }; | 57 | }; |
43 | 58 | ||
44 | struct i2s_dai { | 59 | struct i2s_dai { |
@@ -81,6 +96,7 @@ struct i2s_dai { | |||
81 | u32 suspend_i2scon; | 96 | u32 suspend_i2scon; |
82 | u32 suspend_i2spsr; | 97 | u32 suspend_i2spsr; |
83 | unsigned long gpios[7]; /* i2s gpio line numbers */ | 98 | unsigned long gpios[7]; /* i2s gpio line numbers */ |
99 | const struct samsung_i2s_variant_regs *variant_regs; | ||
84 | }; | 100 | }; |
85 | 101 | ||
86 | /* Lock for cross i/f checks */ | 102 | /* Lock for cross i/f checks */ |
@@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s) | |||
95 | /* If operating in SoC-Slave mode */ | 111 | /* If operating in SoC-Slave mode */ |
96 | static inline bool is_slave(struct i2s_dai *i2s) | 112 | static inline bool is_slave(struct i2s_dai *i2s) |
97 | { | 113 | { |
98 | return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false; | 114 | u32 mod = readl(i2s->addr + I2SMOD); |
115 | return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false; | ||
99 | } | 116 | } |
100 | 117 | ||
101 | /* If this interface of the controller is transmitting data */ | 118 | /* If this interface of the controller is transmitting data */ |
@@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s) | |||
200 | static inline unsigned get_rfs(struct i2s_dai *i2s) | 217 | static inline unsigned get_rfs(struct i2s_dai *i2s) |
201 | { | 218 | { |
202 | u32 rfs; | 219 | u32 rfs; |
203 | 220 | rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off; | |
204 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) | 221 | rfs &= i2s->variant_regs->rfs_mask; |
205 | rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT; | ||
206 | else | ||
207 | rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT); | ||
208 | rfs &= MOD_RCLK_MASK; | ||
209 | 222 | ||
210 | switch (rfs) { | 223 | switch (rfs) { |
224 | case 7: return 192; | ||
225 | case 6: return 96; | ||
226 | case 5: return 128; | ||
227 | case 4: return 64; | ||
211 | case 3: return 768; | 228 | case 3: return 768; |
212 | case 2: return 384; | 229 | case 2: return 384; |
213 | case 1: return 512; | 230 | case 1: return 512; |
@@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s) | |||
219 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | 236 | static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) |
220 | { | 237 | { |
221 | u32 mod = readl(i2s->addr + I2SMOD); | 238 | u32 mod = readl(i2s->addr + I2SMOD); |
222 | int rfs_shift; | 239 | int rfs_shift = i2s->variant_regs->rfs_off; |
223 | 240 | ||
224 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) | 241 | mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift); |
225 | rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT; | ||
226 | else | ||
227 | rfs_shift = MOD_RCLK_SHIFT; | ||
228 | mod &= ~(MOD_RCLK_MASK << rfs_shift); | ||
229 | 242 | ||
230 | switch (rfs) { | 243 | switch (rfs) { |
244 | case 192: | ||
245 | mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift); | ||
246 | break; | ||
247 | case 96: | ||
248 | mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift); | ||
249 | break; | ||
250 | case 128: | ||
251 | mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift); | ||
252 | break; | ||
253 | case 64: | ||
254 | mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift); | ||
255 | break; | ||
231 | case 768: | 256 | case 768: |
232 | mod |= (MOD_RCLK_768FS << rfs_shift); | 257 | mod |= (MOD_RCLK_768FS << rfs_shift); |
233 | break; | 258 | break; |
@@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs) | |||
249 | static inline unsigned get_bfs(struct i2s_dai *i2s) | 274 | static inline unsigned get_bfs(struct i2s_dai *i2s) |
250 | { | 275 | { |
251 | u32 bfs; | 276 | u32 bfs; |
252 | 277 | bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off; | |
253 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | 278 | bfs &= i2s->variant_regs->bfs_mask; |
254 | bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT; | ||
255 | bfs &= EXYNOS5420_MOD_BCLK_MASK; | ||
256 | } else { | ||
257 | bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT; | ||
258 | bfs &= MOD_BCLK_MASK; | ||
259 | } | ||
260 | 279 | ||
261 | switch (bfs) { | 280 | switch (bfs) { |
262 | case 8: return 256; | 281 | case 8: return 256; |
@@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s) | |||
275 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | 294 | static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) |
276 | { | 295 | { |
277 | u32 mod = readl(i2s->addr + I2SMOD); | 296 | u32 mod = readl(i2s->addr + I2SMOD); |
278 | int bfs_shift; | ||
279 | int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; | 297 | int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM; |
280 | 298 | int bfs_shift = i2s->variant_regs->bfs_off; | |
281 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | ||
282 | bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT; | ||
283 | mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift); | ||
284 | } else { | ||
285 | bfs_shift = MOD_BCLK_SHIFT; | ||
286 | mod &= ~(MOD_BCLK_MASK << bfs_shift); | ||
287 | } | ||
288 | 299 | ||
289 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ | 300 | /* Non-TDM I2S controllers do not support BCLK > 48 * FS */ |
290 | if (!tdm && bfs > 48) { | 301 | if (!tdm && bfs > 48) { |
@@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs) | |||
292 | return; | 303 | return; |
293 | } | 304 | } |
294 | 305 | ||
306 | mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift); | ||
307 | |||
295 | switch (bfs) { | 308 | switch (bfs) { |
296 | case 48: | 309 | case 48: |
297 | mod |= (MOD_BCLK_48FS << bfs_shift); | 310 | mod |= (MOD_BCLK_48FS << bfs_shift); |
@@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s) | |||
346 | static void i2s_txctrl(struct i2s_dai *i2s, int on) | 359 | static void i2s_txctrl(struct i2s_dai *i2s, int on) |
347 | { | 360 | { |
348 | void __iomem *addr = i2s->addr; | 361 | void __iomem *addr = i2s->addr; |
362 | int txr_off = i2s->variant_regs->txr_off; | ||
349 | u32 con = readl(addr + I2SCON); | 363 | u32 con = readl(addr + I2SCON); |
350 | u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; | 364 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
351 | 365 | ||
352 | if (on) { | 366 | if (on) { |
353 | con |= CON_ACTIVE; | 367 | con |= CON_ACTIVE; |
@@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
362 | } | 376 | } |
363 | 377 | ||
364 | if (any_rx_active(i2s)) | 378 | if (any_rx_active(i2s)) |
365 | mod |= MOD_TXRX; | 379 | mod |= 2 << txr_off; |
366 | else | 380 | else |
367 | mod |= MOD_TXONLY; | 381 | mod |= 0 << txr_off; |
368 | } else { | 382 | } else { |
369 | if (is_secondary(i2s)) { | 383 | if (is_secondary(i2s)) { |
370 | con |= CON_TXSDMA_PAUSE; | 384 | con |= CON_TXSDMA_PAUSE; |
@@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
382 | con |= CON_TXCH_PAUSE; | 396 | con |= CON_TXCH_PAUSE; |
383 | 397 | ||
384 | if (any_rx_active(i2s)) | 398 | if (any_rx_active(i2s)) |
385 | mod |= MOD_RXONLY; | 399 | mod |= 1 << txr_off; |
386 | else | 400 | else |
387 | con &= ~CON_ACTIVE; | 401 | con &= ~CON_ACTIVE; |
388 | } | 402 | } |
@@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on) | |||
395 | static void i2s_rxctrl(struct i2s_dai *i2s, int on) | 409 | static void i2s_rxctrl(struct i2s_dai *i2s, int on) |
396 | { | 410 | { |
397 | void __iomem *addr = i2s->addr; | 411 | void __iomem *addr = i2s->addr; |
412 | int txr_off = i2s->variant_regs->txr_off; | ||
398 | u32 con = readl(addr + I2SCON); | 413 | u32 con = readl(addr + I2SCON); |
399 | u32 mod = readl(addr + I2SMOD) & ~MOD_MASK; | 414 | u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off); |
400 | 415 | ||
401 | if (on) { | 416 | if (on) { |
402 | con |= CON_RXDMA_ACTIVE | CON_ACTIVE; | 417 | con |= CON_RXDMA_ACTIVE | CON_ACTIVE; |
403 | con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); | 418 | con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE); |
404 | 419 | ||
405 | if (any_tx_active(i2s)) | 420 | if (any_tx_active(i2s)) |
406 | mod |= MOD_TXRX; | 421 | mod |= 2 << txr_off; |
407 | else | 422 | else |
408 | mod |= MOD_RXONLY; | 423 | mod |= 1 << txr_off; |
409 | } else { | 424 | } else { |
410 | con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; | 425 | con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE; |
411 | con &= ~CON_RXDMA_ACTIVE; | 426 | con &= ~CON_RXDMA_ACTIVE; |
412 | 427 | ||
413 | if (any_tx_active(i2s)) | 428 | if (any_tx_active(i2s)) |
414 | mod |= MOD_TXONLY; | 429 | mod |= 0 << txr_off; |
415 | else | 430 | else |
416 | con &= ~CON_ACTIVE; | 431 | con &= ~CON_ACTIVE; |
417 | } | 432 | } |
@@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
451 | struct i2s_dai *i2s = to_info(dai); | 466 | struct i2s_dai *i2s = to_info(dai); |
452 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 467 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
453 | u32 mod = readl(i2s->addr + I2SMOD); | 468 | u32 mod = readl(i2s->addr + I2SMOD); |
469 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
470 | unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off; | ||
471 | unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off; | ||
454 | 472 | ||
455 | switch (clk_id) { | 473 | switch (clk_id) { |
456 | case SAMSUNG_I2S_OPCLK: | 474 | case SAMSUNG_I2S_OPCLK: |
@@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
465 | if ((rfs && other && other->rfs && (other->rfs != rfs)) || | 483 | if ((rfs && other && other->rfs && (other->rfs != rfs)) || |
466 | (any_active(i2s) && | 484 | (any_active(i2s) && |
467 | (((dir == SND_SOC_CLOCK_IN) | 485 | (((dir == SND_SOC_CLOCK_IN) |
468 | && !(mod & MOD_CDCLKCON)) || | 486 | && !(mod & cdcon_mask)) || |
469 | ((dir == SND_SOC_CLOCK_OUT) | 487 | ((dir == SND_SOC_CLOCK_OUT) |
470 | && (mod & MOD_CDCLKCON))))) { | 488 | && (mod & cdcon_mask))))) { |
471 | dev_err(&i2s->pdev->dev, | 489 | dev_err(&i2s->pdev->dev, |
472 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 490 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
473 | return -EAGAIN; | 491 | return -EAGAIN; |
474 | } | 492 | } |
475 | 493 | ||
476 | if (dir == SND_SOC_CLOCK_IN) | 494 | if (dir == SND_SOC_CLOCK_IN) |
477 | mod |= MOD_CDCLKCON; | 495 | mod |= 1 << i2s_regs->cdclkcon_off; |
478 | else | 496 | else |
479 | mod &= ~MOD_CDCLKCON; | 497 | mod &= ~(1 << i2s_regs->cdclkcon_off); |
480 | 498 | ||
481 | i2s->rfs = rfs; | 499 | i2s->rfs = rfs; |
482 | break; | 500 | break; |
@@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
491 | 509 | ||
492 | if (!any_active(i2s)) { | 510 | if (!any_active(i2s)) { |
493 | if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { | 511 | if (i2s->op_clk && !IS_ERR(i2s->op_clk)) { |
494 | if ((clk_id && !(mod & MOD_IMS_SYSMUX)) || | 512 | if ((clk_id && !(mod & rsrc_mask)) || |
495 | (!clk_id && (mod & MOD_IMS_SYSMUX))) { | 513 | (!clk_id && (mod & rsrc_mask))) { |
496 | clk_disable_unprepare(i2s->op_clk); | 514 | clk_disable_unprepare(i2s->op_clk); |
497 | clk_put(i2s->op_clk); | 515 | clk_put(i2s->op_clk); |
498 | } else { | 516 | } else { |
@@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
520 | other->op_clk = i2s->op_clk; | 538 | other->op_clk = i2s->op_clk; |
521 | other->rclk_srcrate = i2s->rclk_srcrate; | 539 | other->rclk_srcrate = i2s->rclk_srcrate; |
522 | } | 540 | } |
523 | } else if ((!clk_id && (mod & MOD_IMS_SYSMUX)) | 541 | } else if ((!clk_id && (mod & rsrc_mask)) |
524 | || (clk_id && !(mod & MOD_IMS_SYSMUX))) { | 542 | || (clk_id && !(mod & rsrc_mask))) { |
525 | dev_err(&i2s->pdev->dev, | 543 | dev_err(&i2s->pdev->dev, |
526 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 544 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
527 | return -EAGAIN; | 545 | return -EAGAIN; |
@@ -533,11 +551,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
533 | } | 551 | } |
534 | 552 | ||
535 | if (clk_id == 0) | 553 | if (clk_id == 0) |
536 | mod &= ~MOD_IMS_SYSMUX; | 554 | mod &= ~(1 << i2s_regs->rclksrc_off); |
537 | else | 555 | else |
538 | mod |= MOD_IMS_SYSMUX; | 556 | mod |= 1 << i2s_regs->rclksrc_off; |
539 | break; | ||
540 | 557 | ||
558 | break; | ||
541 | default: | 559 | default: |
542 | dev_err(&i2s->pdev->dev, "We don't serve that!\n"); | 560 | dev_err(&i2s->pdev->dev, "We don't serve that!\n"); |
543 | return -EINVAL; | 561 | return -EINVAL; |
@@ -553,16 +571,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
553 | { | 571 | { |
554 | struct i2s_dai *i2s = to_info(dai); | 572 | struct i2s_dai *i2s = to_info(dai); |
555 | u32 mod = readl(i2s->addr + I2SMOD); | 573 | u32 mod = readl(i2s->addr + I2SMOD); |
556 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow; | 574 | int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave; |
557 | u32 tmp = 0; | 575 | u32 tmp = 0; |
558 | 576 | ||
559 | if (i2s->quirks & QUIRK_SUPPORTS_TDM) { | 577 | lrp_shift = i2s->variant_regs->lrp_off; |
560 | lrp_shift = EXYNOS5420_MOD_LRP_SHIFT; | 578 | sdf_shift = i2s->variant_regs->sdf_off; |
561 | sdf_shift = EXYNOS5420_MOD_SDF_SHIFT; | 579 | mod_slave = 1 << i2s->variant_regs->mss_off; |
562 | } else { | ||
563 | lrp_shift = MOD_LRP_SHIFT; | ||
564 | sdf_shift = MOD_SDF_SHIFT; | ||
565 | } | ||
566 | 580 | ||
567 | sdf_mask = MOD_SDF_MASK << sdf_shift; | 581 | sdf_mask = MOD_SDF_MASK << sdf_shift; |
568 | lrp_rlow = MOD_LR_RLOW << lrp_shift; | 582 | lrp_rlow = MOD_LR_RLOW << lrp_shift; |
@@ -605,7 +619,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
605 | 619 | ||
606 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 620 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
607 | case SND_SOC_DAIFMT_CBM_CFM: | 621 | case SND_SOC_DAIFMT_CBM_CFM: |
608 | tmp |= MOD_SLAVE; | 622 | tmp |= mod_slave; |
609 | break; | 623 | break; |
610 | case SND_SOC_DAIFMT_CBS_CFS: | 624 | case SND_SOC_DAIFMT_CBS_CFS: |
611 | /* Set default source clock in Master mode */ | 625 | /* Set default source clock in Master mode */ |
@@ -623,13 +637,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, | |||
623 | * channel. | 637 | * channel. |
624 | */ | 638 | */ |
625 | if (any_active(i2s) && | 639 | if (any_active(i2s) && |
626 | ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) { | 640 | ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { |
627 | dev_err(&i2s->pdev->dev, | 641 | dev_err(&i2s->pdev->dev, |
628 | "%s:%d Other DAI busy\n", __func__, __LINE__); | 642 | "%s:%d Other DAI busy\n", __func__, __LINE__); |
629 | return -EAGAIN; | 643 | return -EAGAIN; |
630 | } | 644 | } |
631 | 645 | ||
632 | mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE); | 646 | mod &= ~(sdf_mask | lrp_rlow | mod_slave); |
633 | mod |= tmp; | 647 | mod |= tmp; |
634 | writel(mod, i2s->addr + I2SMOD); | 648 | writel(mod, i2s->addr + I2SMOD); |
635 | 649 | ||
@@ -751,6 +765,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
751 | struct i2s_dai *i2s = to_info(dai); | 765 | struct i2s_dai *i2s = to_info(dai); |
752 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 766 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
753 | unsigned long flags; | 767 | unsigned long flags; |
768 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
754 | 769 | ||
755 | spin_lock_irqsave(&lock, flags); | 770 | spin_lock_irqsave(&lock, flags); |
756 | 771 | ||
@@ -761,7 +776,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
761 | other->mode |= DAI_MANAGER; | 776 | other->mode |= DAI_MANAGER; |
762 | } else { | 777 | } else { |
763 | u32 mod = readl(i2s->addr + I2SMOD); | 778 | u32 mod = readl(i2s->addr + I2SMOD); |
764 | i2s->cdclk_out = !(mod & MOD_CDCLKCON); | 779 | i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off)); |
765 | if (other) | 780 | if (other) |
766 | other->cdclk_out = i2s->cdclk_out; | 781 | other->cdclk_out = i2s->cdclk_out; |
767 | } | 782 | } |
@@ -914,13 +929,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) | |||
914 | struct i2s_dai *i2s = to_info(dai); | 929 | struct i2s_dai *i2s = to_info(dai); |
915 | u32 reg = readl(i2s->addr + I2SFIC); | 930 | u32 reg = readl(i2s->addr + I2SFIC); |
916 | snd_pcm_sframes_t delay; | 931 | snd_pcm_sframes_t delay; |
932 | const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs; | ||
917 | 933 | ||
918 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | 934 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
919 | delay = FIC_RXCOUNT(reg); | 935 | delay = FIC_RXCOUNT(reg); |
920 | else if (is_secondary(i2s)) | 936 | else if (is_secondary(i2s)) |
921 | delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); | 937 | delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS)); |
922 | else | 938 | else |
923 | delay = FIC_TXCOUNT(reg); | 939 | delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f; |
924 | 940 | ||
925 | return delay; | 941 | return delay; |
926 | } | 942 | } |
@@ -956,6 +972,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
956 | { | 972 | { |
957 | struct i2s_dai *i2s = to_info(dai); | 973 | struct i2s_dai *i2s = to_info(dai); |
958 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; | 974 | struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai; |
975 | int ret; | ||
959 | 976 | ||
960 | if (other && other->clk) { /* If this is probe on secondary */ | 977 | if (other && other->clk) { /* If this is probe on secondary */ |
961 | samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, | 978 | samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback, |
@@ -973,9 +990,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
973 | if (IS_ERR(i2s->clk)) { | 990 | if (IS_ERR(i2s->clk)) { |
974 | dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); | 991 | dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n"); |
975 | iounmap(i2s->addr); | 992 | iounmap(i2s->addr); |
976 | return -ENOENT; | 993 | return PTR_ERR(i2s->clk); |
994 | } | ||
995 | |||
996 | ret = clk_prepare_enable(i2s->clk); | ||
997 | if (ret != 0) { | ||
998 | dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret); | ||
999 | return ret; | ||
977 | } | 1000 | } |
978 | clk_prepare_enable(i2s->clk); | ||
979 | 1001 | ||
980 | samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); | 1002 | samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture); |
981 | 1003 | ||
@@ -987,7 +1009,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) | |||
987 | if (i2s->quirks & QUIRK_NEED_RSTCLR) | 1009 | if (i2s->quirks & QUIRK_NEED_RSTCLR) |
988 | writel(CON_RSTCLR, i2s->addr + I2SCON); | 1010 | writel(CON_RSTCLR, i2s->addr + I2SCON); |
989 | 1011 | ||
990 | if (i2s->quirks & QUIRK_SEC_DAI) | 1012 | if (i2s->quirks & QUIRK_SUPPORTS_IDMA) |
991 | idma_reg_addr_init(i2s->addr, | 1013 | idma_reg_addr_init(i2s->addr, |
992 | i2s->sec_dai->idma_playback.dma_addr); | 1014 | i2s->sec_dai->idma_playback.dma_addr); |
993 | 1015 | ||
@@ -1199,10 +1221,9 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1199 | quirks = i2s_dai_data->quirks; | 1221 | quirks = i2s_dai_data->quirks; |
1200 | if (of_property_read_u32(np, "samsung,idma-addr", | 1222 | if (of_property_read_u32(np, "samsung,idma-addr", |
1201 | &idma_addr)) { | 1223 | &idma_addr)) { |
1202 | if (quirks & QUIRK_SEC_DAI) { | 1224 | if (quirks & QUIRK_SUPPORTS_IDMA) { |
1203 | dev_err(&pdev->dev, "idma address is not"\ | 1225 | dev_info(&pdev->dev, "idma address is not"\ |
1204 | "specified"); | 1226 | "specified"); |
1205 | return -EINVAL; | ||
1206 | } | 1227 | } |
1207 | } | 1228 | } |
1208 | } | 1229 | } |
@@ -1228,6 +1249,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1228 | pri_dai->dma_capture.dma_size = 4; | 1249 | pri_dai->dma_capture.dma_size = 4; |
1229 | pri_dai->base = regs_base; | 1250 | pri_dai->base = regs_base; |
1230 | pri_dai->quirks = quirks; | 1251 | pri_dai->quirks = quirks; |
1252 | pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs; | ||
1231 | 1253 | ||
1232 | if (quirks & QUIRK_PRI_6CHAN) | 1254 | if (quirks & QUIRK_PRI_6CHAN) |
1233 | pri_dai->i2s_dai_drv.playback.channels_max = 6; | 1255 | pri_dai->i2s_dai_drv.playback.channels_max = 6; |
@@ -1302,20 +1324,93 @@ static int samsung_i2s_remove(struct platform_device *pdev) | |||
1302 | return 0; | 1324 | return 0; |
1303 | } | 1325 | } |
1304 | 1326 | ||
1327 | static const struct samsung_i2s_variant_regs i2sv3_regs = { | ||
1328 | .bfs_off = 1, | ||
1329 | .rfs_off = 3, | ||
1330 | .sdf_off = 5, | ||
1331 | .txr_off = 8, | ||
1332 | .rclksrc_off = 10, | ||
1333 | .mss_off = 11, | ||
1334 | .cdclkcon_off = 12, | ||
1335 | .lrp_off = 7, | ||
1336 | .bfs_mask = 0x3, | ||
1337 | .rfs_mask = 0x3, | ||
1338 | .ftx0cnt_off = 8, | ||
1339 | }; | ||
1340 | |||
1341 | static const struct samsung_i2s_variant_regs i2sv6_regs = { | ||
1342 | .bfs_off = 0, | ||
1343 | .rfs_off = 4, | ||
1344 | .sdf_off = 6, | ||
1345 | .txr_off = 8, | ||
1346 | .rclksrc_off = 10, | ||
1347 | .mss_off = 11, | ||
1348 | .cdclkcon_off = 12, | ||
1349 | .lrp_off = 15, | ||
1350 | .bfs_mask = 0xf, | ||
1351 | .rfs_mask = 0x3, | ||
1352 | .ftx0cnt_off = 8, | ||
1353 | }; | ||
1354 | |||
1355 | static const struct samsung_i2s_variant_regs i2sv7_regs = { | ||
1356 | .bfs_off = 0, | ||
1357 | .rfs_off = 4, | ||
1358 | .sdf_off = 7, | ||
1359 | .txr_off = 9, | ||
1360 | .rclksrc_off = 11, | ||
1361 | .mss_off = 12, | ||
1362 | .cdclkcon_off = 22, | ||
1363 | .lrp_off = 15, | ||
1364 | .bfs_mask = 0xf, | ||
1365 | .rfs_mask = 0x7, | ||
1366 | .ftx0cnt_off = 0, | ||
1367 | }; | ||
1368 | |||
1369 | static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = { | ||
1370 | .bfs_off = 0, | ||
1371 | .rfs_off = 3, | ||
1372 | .sdf_off = 6, | ||
1373 | .txr_off = 8, | ||
1374 | .rclksrc_off = 10, | ||
1375 | .mss_off = 11, | ||
1376 | .cdclkcon_off = 12, | ||
1377 | .lrp_off = 15, | ||
1378 | .bfs_mask = 0x7, | ||
1379 | .rfs_mask = 0x7, | ||
1380 | .ftx0cnt_off = 8, | ||
1381 | }; | ||
1382 | |||
1305 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { | 1383 | static const struct samsung_i2s_dai_data i2sv3_dai_type = { |
1306 | .dai_type = TYPE_PRI, | 1384 | .dai_type = TYPE_PRI, |
1307 | .quirks = QUIRK_NO_MUXPSR, | 1385 | .quirks = QUIRK_NO_MUXPSR, |
1386 | .i2s_variant_regs = &i2sv3_regs, | ||
1308 | }; | 1387 | }; |
1309 | 1388 | ||
1310 | static const struct samsung_i2s_dai_data i2sv5_dai_type = { | 1389 | static const struct samsung_i2s_dai_data i2sv5_dai_type = { |
1311 | .dai_type = TYPE_PRI, | 1390 | .dai_type = TYPE_PRI, |
1312 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR, | 1391 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | |
1392 | QUIRK_SUPPORTS_IDMA, | ||
1393 | .i2s_variant_regs = &i2sv3_regs, | ||
1313 | }; | 1394 | }; |
1314 | 1395 | ||
1315 | static const struct samsung_i2s_dai_data i2sv6_dai_type = { | 1396 | static const struct samsung_i2s_dai_data i2sv6_dai_type = { |
1316 | .dai_type = TYPE_PRI, | 1397 | .dai_type = TYPE_PRI, |
1317 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | | 1398 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | |
1399 | QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA, | ||
1400 | .i2s_variant_regs = &i2sv6_regs, | ||
1401 | }; | ||
1402 | |||
1403 | static const struct samsung_i2s_dai_data i2sv7_dai_type = { | ||
1404 | .dai_type = TYPE_PRI, | ||
1405 | .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR | | ||
1318 | QUIRK_SUPPORTS_TDM, | 1406 | QUIRK_SUPPORTS_TDM, |
1407 | .i2s_variant_regs = &i2sv7_regs, | ||
1408 | }; | ||
1409 | |||
1410 | static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = { | ||
1411 | .dai_type = TYPE_PRI, | ||
1412 | .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR, | ||
1413 | .i2s_variant_regs = &i2sv5_i2s1_regs, | ||
1319 | }; | 1414 | }; |
1320 | 1415 | ||
1321 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { | 1416 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { |
@@ -1329,10 +1424,13 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | |||
1329 | static struct platform_device_id samsung_i2s_driver_ids[] = { | 1424 | static struct platform_device_id samsung_i2s_driver_ids[] = { |
1330 | { | 1425 | { |
1331 | .name = "samsung-i2s", | 1426 | .name = "samsung-i2s", |
1332 | .driver_data = (kernel_ulong_t)&samsung_dai_type_pri, | 1427 | .driver_data = (kernel_ulong_t)&i2sv3_dai_type, |
1333 | }, { | 1428 | }, { |
1334 | .name = "samsung-i2s-sec", | 1429 | .name = "samsung-i2s-sec", |
1335 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, | 1430 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, |
1431 | }, { | ||
1432 | .name = "samsung-i2sv4", | ||
1433 | .driver_data = (kernel_ulong_t)&i2sv5_dai_type, | ||
1336 | }, | 1434 | }, |
1337 | {}, | 1435 | {}, |
1338 | }; | 1436 | }; |
@@ -1349,6 +1447,12 @@ static const struct of_device_id exynos_i2s_match[] = { | |||
1349 | }, { | 1447 | }, { |
1350 | .compatible = "samsung,exynos5420-i2s", | 1448 | .compatible = "samsung,exynos5420-i2s", |
1351 | .data = &i2sv6_dai_type, | 1449 | .data = &i2sv6_dai_type, |
1450 | }, { | ||
1451 | .compatible = "samsung,exynos7-i2s", | ||
1452 | .data = &i2sv7_dai_type, | ||
1453 | }, { | ||
1454 | .compatible = "samsung,exynos7-i2s1", | ||
1455 | .data = &i2sv5_dai_type_i2s1, | ||
1352 | }, | 1456 | }, |
1353 | {}, | 1457 | {}, |
1354 | }; | 1458 | }; |
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 3c8f60423e82..d7640e72cb1d 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c | |||
@@ -153,8 +153,8 @@ static int odroidx2_audio_remove(struct platform_device *pdev) | |||
153 | 153 | ||
154 | snd_soc_unregister_card(card); | 154 | snd_soc_unregister_card(card); |
155 | 155 | ||
156 | of_node_put((struct device_node *)odroidx2_dai[0].cpu_of_node); | 156 | of_node_put(odroidx2_dai[0].cpu_of_node); |
157 | of_node_put((struct device_node *)odroidx2_dai[0].codec_of_node); | 157 | of_node_put(odroidx2_dai[0].codec_of_node); |
158 | 158 | ||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 88e5df474ccf..8869971d7884 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -842,12 +842,9 @@ static int fsi_clk_disable(struct device *dev, | |||
842 | return -EINVAL; | 842 | return -EINVAL; |
843 | 843 | ||
844 | if (1 == clock->count--) { | 844 | if (1 == clock->count--) { |
845 | if (clock->xck) | 845 | clk_disable(clock->xck); |
846 | clk_disable(clock->xck); | 846 | clk_disable(clock->ick); |
847 | if (clock->ick) | 847 | clk_disable(clock->div); |
848 | clk_disable(clock->ick); | ||
849 | if (clock->div) | ||
850 | clk_disable(clock->div); | ||
851 | } | 848 | } |
852 | 849 | ||
853 | return 0; | 850 | return 0; |
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c index 0af2e4dfd139..d5f567e085ff 100644 --- a/sound/soc/sh/hac.c +++ b/sound/soc/sh/hac.c | |||
@@ -272,7 +272,7 @@ static const struct snd_soc_dai_ops hac_dai_ops = { | |||
272 | static struct snd_soc_dai_driver sh4_hac_dai[] = { | 272 | static struct snd_soc_dai_driver sh4_hac_dai[] = { |
273 | { | 273 | { |
274 | .name = "hac-dai.0", | 274 | .name = "hac-dai.0", |
275 | .ac97_control = 1, | 275 | .bus_control = true, |
276 | .playback = { | 276 | .playback = { |
277 | .rates = AC97_RATES, | 277 | .rates = AC97_RATES, |
278 | .formats = AC97_FMTS, | 278 | .formats = AC97_FMTS, |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index fc41a0e8b09f..14d1a7193469 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
430 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); | 430 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); |
431 | 431 | ||
432 | for_each_rsnd_clk(clk, adg, i) | 432 | for_each_rsnd_clk(clk, adg, i) |
433 | dev_dbg(dev, "clk %d : %p\n", i, clk); | 433 | dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); |
434 | 434 | ||
435 | rsnd_adg_ssi_clk_init(priv, adg); | 435 | rsnd_adg_ssi_clk_init(priv, adg); |
436 | 436 | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 70042197f9e2..75308bbc2ce8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
349 | dma_name); | 349 | dma_name); |
350 | if (!dma->chan) { | 350 | if (!dma->chan) { |
351 | dev_err(dev, "can't get dma channel\n"); | 351 | dev_err(dev, "can't get dma channel\n"); |
352 | return -EIO; | 352 | goto rsnd_dma_channel_err; |
353 | } | 353 | } |
354 | 354 | ||
355 | ret = dmaengine_slave_config(dma->chan, &cfg); | 355 | ret = dmaengine_slave_config(dma->chan, &cfg); |
@@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
363 | 363 | ||
364 | rsnd_dma_init_err: | 364 | rsnd_dma_init_err: |
365 | rsnd_dma_quit(priv, dma); | 365 | rsnd_dma_quit(priv, dma); |
366 | rsnd_dma_channel_err: | ||
366 | 367 | ||
367 | return ret; | 368 | /* |
369 | * DMA failed. try to PIO mode | ||
370 | * see | ||
371 | * rsnd_ssi_fallback() | ||
372 | * rsnd_rdai_continuance_probe() | ||
373 | */ | ||
374 | return -EAGAIN; | ||
368 | } | 375 | } |
369 | 376 | ||
370 | void rsnd_dma_quit(struct rsnd_priv *priv, | 377 | void rsnd_dma_quit(struct rsnd_priv *priv, |
@@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod) | |||
409 | ({ \ | 416 | ({ \ |
410 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 417 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
411 | struct device *dev = rsnd_priv_to_dev(priv); \ | 418 | struct device *dev = rsnd_priv_to_dev(priv); \ |
412 | dev_dbg(dev, "%s [%d] %s\n", \ | 419 | u32 mask = 1 << __rsnd_mod_shift_##func; \ |
413 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ | 420 | u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \ |
414 | (mod)->ops->func(mod, rdai); \ | 421 | int ret = 0; \ |
422 | if ((mod->status & mask) == call) { \ | ||
423 | dev_dbg(dev, "%s[%d] %s\n", \ | ||
424 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ | ||
425 | ret = (mod)->ops->func(mod, rdai); \ | ||
426 | mod->status = (mod->status & ~mask) | (~call & mask); \ | ||
427 | } \ | ||
428 | ret; \ | ||
415 | }) | 429 | }) |
416 | 430 | ||
417 | #define rsnd_mod_call(mod, func, rdai...) \ | 431 | #define rsnd_mod_call(mod, func, rdai...) \ |
@@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
456 | return 0; | 470 | return 0; |
457 | } | 471 | } |
458 | 472 | ||
473 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, | ||
474 | struct rsnd_dai_stream *io) | ||
475 | { | ||
476 | mod->io = NULL; | ||
477 | io->mod[mod->type] = NULL; | ||
478 | } | ||
479 | |||
459 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | 480 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) |
460 | { | 481 | { |
461 | int id = rdai - priv->rdai; | 482 | int id = rdai - priv->rdai; |
@@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | |||
686 | ret; \ | 707 | ret; \ |
687 | }) | 708 | }) |
688 | 709 | ||
710 | #define rsnd_path_break(priv, io, type) \ | ||
711 | { \ | ||
712 | struct rsnd_mod *mod; \ | ||
713 | int id = -1; \ | ||
714 | \ | ||
715 | if (rsnd_is_enable_path(io, type)) { \ | ||
716 | id = rsnd_info_id(priv, io, type); \ | ||
717 | if (id >= 0) { \ | ||
718 | mod = rsnd_##type##_mod_get(priv, id); \ | ||
719 | rsnd_dai_disconnect(mod, io); \ | ||
720 | } \ | ||
721 | } \ | ||
722 | } | ||
723 | |||
689 | static int rsnd_path_init(struct rsnd_priv *priv, | 724 | static int rsnd_path_init(struct rsnd_priv *priv, |
690 | struct rsnd_dai *rdai, | 725 | struct rsnd_dai *rdai, |
691 | struct rsnd_dai_stream *io) | 726 | struct rsnd_dai_stream *io) |
@@ -934,6 +969,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = { | |||
934 | }; | 969 | }; |
935 | 970 | ||
936 | /* | 971 | /* |
972 | * snd_kcontrol | ||
973 | */ | ||
974 | #define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value) | ||
975 | static int rsnd_kctrl_info(struct snd_kcontrol *kctrl, | ||
976 | struct snd_ctl_elem_info *uinfo) | ||
977 | { | ||
978 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
979 | |||
980 | if (cfg->texts) { | ||
981 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
982 | uinfo->count = cfg->size; | ||
983 | uinfo->value.enumerated.items = cfg->max; | ||
984 | if (uinfo->value.enumerated.item >= cfg->max) | ||
985 | uinfo->value.enumerated.item = cfg->max - 1; | ||
986 | strlcpy(uinfo->value.enumerated.name, | ||
987 | cfg->texts[uinfo->value.enumerated.item], | ||
988 | sizeof(uinfo->value.enumerated.name)); | ||
989 | } else { | ||
990 | uinfo->count = cfg->size; | ||
991 | uinfo->value.integer.min = 0; | ||
992 | uinfo->value.integer.max = cfg->max; | ||
993 | uinfo->type = (cfg->max == 1) ? | ||
994 | SNDRV_CTL_ELEM_TYPE_BOOLEAN : | ||
995 | SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
996 | } | ||
997 | |||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | static int rsnd_kctrl_get(struct snd_kcontrol *kctrl, | ||
1002 | struct snd_ctl_elem_value *uc) | ||
1003 | { | ||
1004 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
1005 | int i; | ||
1006 | |||
1007 | for (i = 0; i < cfg->size; i++) | ||
1008 | if (cfg->texts) | ||
1009 | uc->value.enumerated.item[i] = cfg->val[i]; | ||
1010 | else | ||
1011 | uc->value.integer.value[i] = cfg->val[i]; | ||
1012 | |||
1013 | return 0; | ||
1014 | } | ||
1015 | |||
1016 | static int rsnd_kctrl_put(struct snd_kcontrol *kctrl, | ||
1017 | struct snd_ctl_elem_value *uc) | ||
1018 | { | ||
1019 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
1020 | struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl); | ||
1021 | int i, change = 0; | ||
1022 | |||
1023 | for (i = 0; i < cfg->size; i++) { | ||
1024 | if (cfg->texts) { | ||
1025 | change |= (uc->value.enumerated.item[i] != cfg->val[i]); | ||
1026 | cfg->val[i] = uc->value.enumerated.item[i]; | ||
1027 | } else { | ||
1028 | change |= (uc->value.integer.value[i] != cfg->val[i]); | ||
1029 | cfg->val[i] = uc->value.integer.value[i]; | ||
1030 | } | ||
1031 | } | ||
1032 | |||
1033 | if (change) | ||
1034 | cfg->update(mod); | ||
1035 | |||
1036 | return change; | ||
1037 | } | ||
1038 | |||
1039 | static int __rsnd_kctrl_new(struct rsnd_mod *mod, | ||
1040 | struct rsnd_dai *rdai, | ||
1041 | struct snd_soc_pcm_runtime *rtd, | ||
1042 | const unsigned char *name, | ||
1043 | struct rsnd_kctrl_cfg *cfg, | ||
1044 | void (*update)(struct rsnd_mod *mod)) | ||
1045 | { | ||
1046 | struct snd_card *card = rtd->card->snd_card; | ||
1047 | struct snd_kcontrol *kctrl; | ||
1048 | struct snd_kcontrol_new knew = { | ||
1049 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
1050 | .name = name, | ||
1051 | .info = rsnd_kctrl_info, | ||
1052 | .get = rsnd_kctrl_get, | ||
1053 | .put = rsnd_kctrl_put, | ||
1054 | .private_value = (unsigned long)cfg, | ||
1055 | }; | ||
1056 | int ret; | ||
1057 | |||
1058 | kctrl = snd_ctl_new1(&knew, mod); | ||
1059 | if (!kctrl) | ||
1060 | return -ENOMEM; | ||
1061 | |||
1062 | ret = snd_ctl_add(card, kctrl); | ||
1063 | if (ret < 0) | ||
1064 | return ret; | ||
1065 | |||
1066 | cfg->update = update; | ||
1067 | |||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | ||
1072 | struct rsnd_dai *rdai, | ||
1073 | struct snd_soc_pcm_runtime *rtd, | ||
1074 | const unsigned char *name, | ||
1075 | void (*update)(struct rsnd_mod *mod), | ||
1076 | struct rsnd_kctrl_cfg_m *_cfg, | ||
1077 | u32 max) | ||
1078 | { | ||
1079 | _cfg->cfg.max = max; | ||
1080 | _cfg->cfg.size = RSND_DVC_CHANNELS; | ||
1081 | _cfg->cfg.val = _cfg->val; | ||
1082 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1083 | } | ||
1084 | |||
1085 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | ||
1086 | struct rsnd_dai *rdai, | ||
1087 | struct snd_soc_pcm_runtime *rtd, | ||
1088 | const unsigned char *name, | ||
1089 | void (*update)(struct rsnd_mod *mod), | ||
1090 | struct rsnd_kctrl_cfg_s *_cfg, | ||
1091 | u32 max) | ||
1092 | { | ||
1093 | _cfg->cfg.max = max; | ||
1094 | _cfg->cfg.size = 1; | ||
1095 | _cfg->cfg.val = &_cfg->val; | ||
1096 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1097 | } | ||
1098 | |||
1099 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | ||
1100 | struct rsnd_dai *rdai, | ||
1101 | struct snd_soc_pcm_runtime *rtd, | ||
1102 | const unsigned char *name, | ||
1103 | struct rsnd_kctrl_cfg_s *_cfg, | ||
1104 | void (*update)(struct rsnd_mod *mod), | ||
1105 | const char * const *texts, | ||
1106 | u32 max) | ||
1107 | { | ||
1108 | _cfg->cfg.max = max; | ||
1109 | _cfg->cfg.size = 1; | ||
1110 | _cfg->cfg.val = &_cfg->val; | ||
1111 | _cfg->cfg.texts = texts; | ||
1112 | return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update); | ||
1113 | } | ||
1114 | |||
1115 | /* | ||
937 | * snd_soc_platform | 1116 | * snd_soc_platform |
938 | */ | 1117 | */ |
939 | 1118 | ||
@@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = { | |||
976 | .name = "rsnd", | 1155 | .name = "rsnd", |
977 | }; | 1156 | }; |
978 | 1157 | ||
1158 | static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, | ||
1159 | struct rsnd_dai *rdai, | ||
1160 | int is_play) | ||
1161 | { | ||
1162 | struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; | ||
1163 | int ret; | ||
1164 | |||
1165 | ret = rsnd_dai_call(probe, io, rdai); | ||
1166 | if (ret == -EAGAIN) { | ||
1167 | /* | ||
1168 | * Fallback to PIO mode | ||
1169 | */ | ||
1170 | |||
1171 | /* | ||
1172 | * call "remove" for SSI/SRC/DVC | ||
1173 | * SSI will be switch to PIO mode if it was DMA mode | ||
1174 | * see | ||
1175 | * rsnd_dma_init() | ||
1176 | * rsnd_ssi_fallback() | ||
1177 | */ | ||
1178 | rsnd_dai_call(remove, io, rdai); | ||
1179 | |||
1180 | /* | ||
1181 | * remove SRC/DVC from DAI, | ||
1182 | */ | ||
1183 | rsnd_path_break(priv, io, src); | ||
1184 | rsnd_path_break(priv, io, dvc); | ||
1185 | |||
1186 | /* | ||
1187 | * fallback | ||
1188 | */ | ||
1189 | rsnd_dai_call(fallback, io, rdai); | ||
1190 | |||
1191 | /* | ||
1192 | * retry to "probe". | ||
1193 | * DAI has SSI which is PIO mode only now. | ||
1194 | */ | ||
1195 | ret = rsnd_dai_call(probe, io, rdai); | ||
1196 | } | ||
1197 | |||
1198 | return ret; | ||
1199 | } | ||
1200 | |||
979 | /* | 1201 | /* |
980 | * rsnd probe | 1202 | * rsnd probe |
981 | */ | 1203 | */ |
@@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev) | |||
1037 | } | 1259 | } |
1038 | 1260 | ||
1039 | for_each_rsnd_dai(rdai, priv, i) { | 1261 | for_each_rsnd_dai(rdai, priv, i) { |
1040 | ret = rsnd_dai_call(probe, &rdai->playback, rdai); | 1262 | ret = rsnd_rdai_continuance_probe(priv, rdai, 1); |
1041 | if (ret) | 1263 | if (ret) |
1042 | goto exit_snd_probe; | 1264 | goto exit_snd_probe; |
1043 | 1265 | ||
1044 | ret = rsnd_dai_call(probe, &rdai->capture, rdai); | 1266 | ret = rsnd_rdai_continuance_probe(priv, rdai, 0); |
1045 | if (ret) | 1267 | if (ret) |
1046 | goto exit_snd_probe; | 1268 | goto exit_snd_probe; |
1047 | } | 1269 | } |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 3f443930c2b1..5380a4827ba7 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
@@ -11,8 +11,6 @@ | |||
11 | #include "rsnd.h" | 11 | #include "rsnd.h" |
12 | 12 | ||
13 | #define RSND_DVC_NAME_SIZE 16 | 13 | #define RSND_DVC_NAME_SIZE 16 |
14 | #define RSND_DVC_VOLUME_MAX 100 | ||
15 | #define RSND_DVC_VOLUME_NUM 2 | ||
16 | 14 | ||
17 | #define DVC_NAME "dvc" | 15 | #define DVC_NAME "dvc" |
18 | 16 | ||
@@ -20,8 +18,11 @@ struct rsnd_dvc { | |||
20 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ | 18 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ |
21 | struct rsnd_mod mod; | 19 | struct rsnd_mod mod; |
22 | struct clk *clk; | 20 | struct clk *clk; |
23 | u8 volume[RSND_DVC_VOLUME_NUM]; | 21 | struct rsnd_kctrl_cfg_m volume; |
24 | u8 mute[RSND_DVC_VOLUME_NUM]; | 22 | struct rsnd_kctrl_cfg_m mute; |
23 | struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */ | ||
24 | struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */ | ||
25 | struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | #define rsnd_mod_to_dvc(_mod) \ | 28 | #define rsnd_mod_to_dvc(_mod) \ |
@@ -33,23 +34,87 @@ struct rsnd_dvc { | |||
33 | ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ | 34 | ((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \ |
34 | i++) | 35 | i++) |
35 | 36 | ||
37 | static const char const *dvc_ramp_rate[] = { | ||
38 | "128 dB/1 step", /* 00000 */ | ||
39 | "64 dB/1 step", /* 00001 */ | ||
40 | "32 dB/1 step", /* 00010 */ | ||
41 | "16 dB/1 step", /* 00011 */ | ||
42 | "8 dB/1 step", /* 00100 */ | ||
43 | "4 dB/1 step", /* 00101 */ | ||
44 | "2 dB/1 step", /* 00110 */ | ||
45 | "1 dB/1 step", /* 00111 */ | ||
46 | "0.5 dB/1 step", /* 01000 */ | ||
47 | "0.25 dB/1 step", /* 01001 */ | ||
48 | "0.125 dB/1 step", /* 01010 */ | ||
49 | "0.125 dB/2 steps", /* 01011 */ | ||
50 | "0.125 dB/4 steps", /* 01100 */ | ||
51 | "0.125 dB/8 steps", /* 01101 */ | ||
52 | "0.125 dB/16 steps", /* 01110 */ | ||
53 | "0.125 dB/32 steps", /* 01111 */ | ||
54 | "0.125 dB/64 steps", /* 10000 */ | ||
55 | "0.125 dB/128 steps", /* 10001 */ | ||
56 | "0.125 dB/256 steps", /* 10010 */ | ||
57 | "0.125 dB/512 steps", /* 10011 */ | ||
58 | "0.125 dB/1024 steps", /* 10100 */ | ||
59 | "0.125 dB/2048 steps", /* 10101 */ | ||
60 | "0.125 dB/4096 steps", /* 10110 */ | ||
61 | "0.125 dB/8192 steps", /* 10111 */ | ||
62 | }; | ||
63 | |||
36 | static void rsnd_dvc_volume_update(struct rsnd_mod *mod) | 64 | static void rsnd_dvc_volume_update(struct rsnd_mod *mod) |
37 | { | 65 | { |
38 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 66 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
39 | u32 max = (0x00800000 - 1); | 67 | u32 val[RSND_DVC_CHANNELS]; |
40 | u32 vol[RSND_DVC_VOLUME_NUM]; | 68 | u32 dvucr = 0; |
41 | u32 mute = 0; | 69 | u32 mute = 0; |
42 | int i; | 70 | int i; |
43 | 71 | ||
44 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { | 72 | for (i = 0; i < dvc->mute.cfg.size; i++) |
45 | vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i]; | 73 | mute |= (!!dvc->mute.cfg.val[i]) << i; |
46 | mute |= (!!dvc->mute[i]) << i; | 74 | |
75 | /* Disable DVC Register access */ | ||
76 | rsnd_mod_write(mod, DVC_DVUER, 0); | ||
77 | |||
78 | /* Enable Ramp */ | ||
79 | if (dvc->ren.val) { | ||
80 | dvucr |= 0x10; | ||
81 | |||
82 | /* Digital Volume Max */ | ||
83 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
84 | val[i] = dvc->volume.cfg.max; | ||
85 | |||
86 | rsnd_mod_write(mod, DVC_VRCTR, 0xff); | ||
87 | rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 | | ||
88 | dvc->rdown.val); | ||
89 | /* | ||
90 | * FIXME !! | ||
91 | * use scale-downed Digital Volume | ||
92 | * as Volume Ramp | ||
93 | * 7F FFFF -> 3FF | ||
94 | */ | ||
95 | rsnd_mod_write(mod, DVC_VRDBR, | ||
96 | 0x3ff - (dvc->volume.val[0] >> 13)); | ||
97 | |||
98 | } else { | ||
99 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
100 | val[i] = dvc->volume.val[i]; | ||
101 | } | ||
102 | |||
103 | /* Enable Digital Volume */ | ||
104 | dvucr |= 0x100; | ||
105 | rsnd_mod_write(mod, DVC_VOL0R, val[0]); | ||
106 | rsnd_mod_write(mod, DVC_VOL1R, val[1]); | ||
107 | |||
108 | /* Enable Mute */ | ||
109 | if (mute) { | ||
110 | dvucr |= 0x1; | ||
111 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | ||
47 | } | 112 | } |
48 | 113 | ||
49 | rsnd_mod_write(mod, DVC_VOL0R, vol[0]); | 114 | rsnd_mod_write(mod, DVC_DVUCR, dvucr); |
50 | rsnd_mod_write(mod, DVC_VOL1R, vol[1]); | ||
51 | 115 | ||
52 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | 116 | /* Enable DVC Register access */ |
117 | rsnd_mod_write(mod, DVC_DVUER, 1); | ||
53 | } | 118 | } |
54 | 119 | ||
55 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, | 120 | static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, |
@@ -58,7 +123,8 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod, | |||
58 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 123 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
59 | struct device *dev = rsnd_priv_to_dev(priv); | 124 | struct device *dev = rsnd_priv_to_dev(priv); |
60 | 125 | ||
61 | dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); | 126 | dev_dbg(dev, "%s[%d] (Gen2) is probed\n", |
127 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
62 | 128 | ||
63 | return 0; | 129 | return 0; |
64 | } | 130 | } |
@@ -102,16 +168,11 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, | |||
102 | 168 | ||
103 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); | 169 | rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod)); |
104 | 170 | ||
105 | /* enable Volume / Mute */ | ||
106 | rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101); | ||
107 | |||
108 | /* ch0/ch1 Volume */ | 171 | /* ch0/ch1 Volume */ |
109 | rsnd_dvc_volume_update(dvc_mod); | 172 | rsnd_dvc_volume_update(dvc_mod); |
110 | 173 | ||
111 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); | 174 | rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); |
112 | 175 | ||
113 | rsnd_mod_write(dvc_mod, DVC_DVUER, 1); | ||
114 | |||
115 | rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); | 176 | rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io); |
116 | 177 | ||
117 | return 0; | 178 | return 0; |
@@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod, | |||
143 | return 0; | 204 | return 0; |
144 | } | 205 | } |
145 | 206 | ||
146 | static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl, | ||
147 | struct snd_ctl_elem_info *uinfo) | ||
148 | { | ||
149 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
150 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
151 | u8 *val = (u8 *)kctrl->private_value; | ||
152 | |||
153 | uinfo->count = RSND_DVC_VOLUME_NUM; | ||
154 | uinfo->value.integer.min = 0; | ||
155 | |||
156 | if (val == dvc->volume) { | ||
157 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
158 | uinfo->value.integer.max = RSND_DVC_VOLUME_MAX; | ||
159 | } else { | ||
160 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
161 | uinfo->value.integer.max = 1; | ||
162 | } | ||
163 | |||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl, | ||
168 | struct snd_ctl_elem_value *ucontrol) | ||
169 | { | ||
170 | u8 *val = (u8 *)kctrl->private_value; | ||
171 | int i; | ||
172 | |||
173 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) | ||
174 | ucontrol->value.integer.value[i] = val[i]; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl, | ||
180 | struct snd_ctl_elem_value *ucontrol) | ||
181 | { | ||
182 | struct rsnd_mod *mod = snd_kcontrol_chip(kctrl); | ||
183 | u8 *val = (u8 *)kctrl->private_value; | ||
184 | int i, change = 0; | ||
185 | |||
186 | for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) { | ||
187 | change |= (ucontrol->value.integer.value[i] != val[i]); | ||
188 | val[i] = ucontrol->value.integer.value[i]; | ||
189 | } | ||
190 | |||
191 | if (change) | ||
192 | rsnd_dvc_volume_update(mod); | ||
193 | |||
194 | return change; | ||
195 | } | ||
196 | |||
197 | static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod, | ||
198 | struct rsnd_dai *rdai, | ||
199 | struct snd_soc_pcm_runtime *rtd, | ||
200 | const unsigned char *name, | ||
201 | u8 *private) | ||
202 | { | ||
203 | struct snd_card *card = rtd->card->snd_card; | ||
204 | struct snd_kcontrol *kctrl; | ||
205 | struct snd_kcontrol_new knew = { | ||
206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
207 | .name = name, | ||
208 | .info = rsnd_dvc_volume_info, | ||
209 | .get = rsnd_dvc_volume_get, | ||
210 | .put = rsnd_dvc_volume_put, | ||
211 | .private_value = (unsigned long)private, | ||
212 | }; | ||
213 | int ret; | ||
214 | |||
215 | kctrl = snd_ctl_new1(&knew, mod); | ||
216 | if (!kctrl) | ||
217 | return -ENOMEM; | ||
218 | |||
219 | ret = snd_ctl_add(card, kctrl); | ||
220 | if (ret < 0) | ||
221 | return ret; | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | 207 | static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, |
227 | struct rsnd_dai *rdai, | 208 | struct rsnd_dai *rdai, |
228 | struct snd_soc_pcm_runtime *rtd) | 209 | struct snd_soc_pcm_runtime *rtd) |
@@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
232 | int ret; | 213 | int ret; |
233 | 214 | ||
234 | /* Volume */ | 215 | /* Volume */ |
235 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | 216 | ret = rsnd_kctrl_new_m(mod, rdai, rtd, |
236 | rsnd_dai_is_play(rdai, io) ? | 217 | rsnd_dai_is_play(rdai, io) ? |
237 | "DVC Out Playback Volume" : "DVC In Capture Volume", | 218 | "DVC Out Playback Volume" : "DVC In Capture Volume", |
238 | dvc->volume); | 219 | rsnd_dvc_volume_update, |
220 | &dvc->volume, 0x00800000 - 1); | ||
239 | if (ret < 0) | 221 | if (ret < 0) |
240 | return ret; | 222 | return ret; |
241 | 223 | ||
242 | /* Mute */ | 224 | /* Mute */ |
243 | ret = __rsnd_dvc_pcm_new(mod, rdai, rtd, | 225 | ret = rsnd_kctrl_new_m(mod, rdai, rtd, |
244 | rsnd_dai_is_play(rdai, io) ? | 226 | rsnd_dai_is_play(rdai, io) ? |
245 | "DVC Out Mute Switch" : "DVC In Mute Switch", | 227 | "DVC Out Mute Switch" : "DVC In Mute Switch", |
246 | dvc->mute); | 228 | rsnd_dvc_volume_update, |
229 | &dvc->mute, 1); | ||
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
233 | /* Ramp */ | ||
234 | ret = rsnd_kctrl_new_s(mod, rdai, rtd, | ||
235 | rsnd_dai_is_play(rdai, io) ? | ||
236 | "DVC Out Ramp Switch" : "DVC In Ramp Switch", | ||
237 | rsnd_dvc_volume_update, | ||
238 | &dvc->ren, 1); | ||
239 | if (ret < 0) | ||
240 | return ret; | ||
241 | |||
242 | ret = rsnd_kctrl_new_e(mod, rdai, rtd, | ||
243 | rsnd_dai_is_play(rdai, io) ? | ||
244 | "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate", | ||
245 | &dvc->rup, | ||
246 | rsnd_dvc_volume_update, | ||
247 | dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); | ||
248 | if (ret < 0) | ||
249 | return ret; | ||
250 | |||
251 | ret = rsnd_kctrl_new_e(mod, rdai, rtd, | ||
252 | rsnd_dai_is_play(rdai, io) ? | ||
253 | "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate", | ||
254 | &dvc->rdown, | ||
255 | rsnd_dvc_volume_update, | ||
256 | dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate)); | ||
257 | |||
247 | if (ret < 0) | 258 | if (ret < 0) |
248 | return ret; | 259 | return ret; |
249 | 260 | ||
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index f95e7ab135e8..87a6f2d62775 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -8,6 +8,17 @@ | |||
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 9 | * published by the Free Software Foundation. |
10 | */ | 10 | */ |
11 | |||
12 | /* | ||
13 | * #define DEBUG | ||
14 | * | ||
15 | * you can also add below in | ||
16 | * ${LINUX}/drivers/base/regmap/regmap.c | ||
17 | * for regmap debug | ||
18 | * | ||
19 | * #define LOG_DEVICE "xxxx.rcar_sound" | ||
20 | */ | ||
21 | |||
11 | #include "rsnd.h" | 22 | #include "rsnd.h" |
12 | 23 | ||
13 | struct rsnd_gen { | 24 | struct rsnd_gen { |
@@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv, | |||
67 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 78 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
68 | return 0; | 79 | return 0; |
69 | 80 | ||
70 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 81 | dev_dbg(dev, "r %s[%d] - %4d : %08x\n", |
82 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val); | ||
71 | 83 | ||
72 | dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val); | 84 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
73 | 85 | ||
74 | return val; | 86 | return val; |
75 | } | 87 | } |
@@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv, | |||
84 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 96 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
85 | return; | 97 | return; |
86 | 98 | ||
87 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); | 99 | dev_dbg(dev, "w %s[%d] - %4d : %08x\n", |
100 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); | ||
88 | 101 | ||
89 | dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data); | 102 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
90 | } | 103 | } |
91 | 104 | ||
92 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | 105 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, |
@@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
98 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 111 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
99 | return; | 112 | return; |
100 | 113 | ||
114 | dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n", | ||
115 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); | ||
116 | |||
101 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), | 117 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
102 | mask, data); | 118 | mask, data); |
103 | |||
104 | dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n", | ||
105 | rsnd_mod_name(mod), reg, data, mask); | ||
106 | } | 119 | } |
107 | 120 | ||
108 | #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ | 121 | #define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \ |
@@ -311,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
311 | RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), | 324 | RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), |
312 | RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), | 325 | RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100), |
313 | RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), | 326 | RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100), |
327 | RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100), | ||
328 | RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100), | ||
329 | RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), | ||
314 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), | 330 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), |
315 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), | 331 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), |
316 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), | 332 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index d119adf97c9c..5826c8abf794 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -91,6 +91,9 @@ enum rsnd_reg { | |||
91 | RSND_REG_SHARE20, | 91 | RSND_REG_SHARE20, |
92 | RSND_REG_SHARE21, | 92 | RSND_REG_SHARE21, |
93 | RSND_REG_SHARE22, | 93 | RSND_REG_SHARE22, |
94 | RSND_REG_SHARE23, | ||
95 | RSND_REG_SHARE24, | ||
96 | RSND_REG_SHARE25, | ||
94 | 97 | ||
95 | RSND_REG_MAX, | 98 | RSND_REG_MAX, |
96 | }; | 99 | }; |
@@ -129,6 +132,9 @@ enum rsnd_reg { | |||
129 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 | 132 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 |
130 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 | 133 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 |
131 | #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 | 134 | #define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 |
135 | #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 | ||
136 | #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 | ||
137 | #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 | ||
132 | 138 | ||
133 | struct rsnd_of_data; | 139 | struct rsnd_of_data; |
134 | struct rsnd_priv; | 140 | struct rsnd_priv; |
@@ -200,6 +206,8 @@ struct rsnd_mod_ops { | |||
200 | int (*pcm_new)(struct rsnd_mod *mod, | 206 | int (*pcm_new)(struct rsnd_mod *mod, |
201 | struct rsnd_dai *rdai, | 207 | struct rsnd_dai *rdai, |
202 | struct snd_soc_pcm_runtime *rtd); | 208 | struct snd_soc_pcm_runtime *rtd); |
209 | int (*fallback)(struct rsnd_mod *mod, | ||
210 | struct rsnd_dai *rdai); | ||
203 | }; | 211 | }; |
204 | 212 | ||
205 | struct rsnd_dai_stream; | 213 | struct rsnd_dai_stream; |
@@ -210,7 +218,35 @@ struct rsnd_mod { | |||
210 | struct rsnd_mod_ops *ops; | 218 | struct rsnd_mod_ops *ops; |
211 | struct rsnd_dma dma; | 219 | struct rsnd_dma dma; |
212 | struct rsnd_dai_stream *io; | 220 | struct rsnd_dai_stream *io; |
221 | u32 status; | ||
213 | }; | 222 | }; |
223 | /* | ||
224 | * status | ||
225 | * | ||
226 | * bit | ||
227 | * 0 0: probe 1: remove | ||
228 | * 1 0: init 1: quit | ||
229 | * 2 0: start 1: stop | ||
230 | * 3 0: pcm_new | ||
231 | * 4 0: fallback | ||
232 | */ | ||
233 | #define __rsnd_mod_shift_probe 0 | ||
234 | #define __rsnd_mod_shift_remove 0 | ||
235 | #define __rsnd_mod_shift_init 1 | ||
236 | #define __rsnd_mod_shift_quit 1 | ||
237 | #define __rsnd_mod_shift_start 2 | ||
238 | #define __rsnd_mod_shift_stop 2 | ||
239 | #define __rsnd_mod_shift_pcm_new 3 | ||
240 | #define __rsnd_mod_shift_fallback 4 | ||
241 | |||
242 | #define __rsnd_mod_call_probe 0 | ||
243 | #define __rsnd_mod_call_remove 1 | ||
244 | #define __rsnd_mod_call_init 0 | ||
245 | #define __rsnd_mod_call_quit 1 | ||
246 | #define __rsnd_mod_call_start 0 | ||
247 | #define __rsnd_mod_call_stop 1 | ||
248 | #define __rsnd_mod_call_pcm_new 0 | ||
249 | #define __rsnd_mod_call_fallback 0 | ||
214 | 250 | ||
215 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 251 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
216 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 252 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
@@ -267,7 +303,8 @@ struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | |||
267 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | 303 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
268 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | 304 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); |
269 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | 305 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
270 | #define rsnd_io_to_runtime(io) ((io)->substream->runtime) | 306 | #define rsnd_io_to_runtime(io) ((io)->substream ? \ |
307 | (io)->substream->runtime : NULL) | ||
271 | 308 | ||
272 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 309 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
273 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 310 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
@@ -382,6 +419,51 @@ struct rsnd_priv { | |||
382 | }) | 419 | }) |
383 | 420 | ||
384 | /* | 421 | /* |
422 | * rsnd_kctrl | ||
423 | */ | ||
424 | struct rsnd_kctrl_cfg { | ||
425 | unsigned int max; | ||
426 | unsigned int size; | ||
427 | u32 *val; | ||
428 | const char * const *texts; | ||
429 | void (*update)(struct rsnd_mod *mod); | ||
430 | }; | ||
431 | |||
432 | #define RSND_DVC_CHANNELS 2 | ||
433 | struct rsnd_kctrl_cfg_m { | ||
434 | struct rsnd_kctrl_cfg cfg; | ||
435 | u32 val[RSND_DVC_CHANNELS]; | ||
436 | }; | ||
437 | |||
438 | struct rsnd_kctrl_cfg_s { | ||
439 | struct rsnd_kctrl_cfg cfg; | ||
440 | u32 val; | ||
441 | }; | ||
442 | |||
443 | int rsnd_kctrl_new_m(struct rsnd_mod *mod, | ||
444 | struct rsnd_dai *rdai, | ||
445 | struct snd_soc_pcm_runtime *rtd, | ||
446 | const unsigned char *name, | ||
447 | void (*update)(struct rsnd_mod *mod), | ||
448 | struct rsnd_kctrl_cfg_m *_cfg, | ||
449 | u32 max); | ||
450 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | ||
451 | struct rsnd_dai *rdai, | ||
452 | struct snd_soc_pcm_runtime *rtd, | ||
453 | const unsigned char *name, | ||
454 | void (*update)(struct rsnd_mod *mod), | ||
455 | struct rsnd_kctrl_cfg_s *_cfg, | ||
456 | u32 max); | ||
457 | int rsnd_kctrl_new_e(struct rsnd_mod *mod, | ||
458 | struct rsnd_dai *rdai, | ||
459 | struct snd_soc_pcm_runtime *rtd, | ||
460 | const unsigned char *name, | ||
461 | struct rsnd_kctrl_cfg_s *_cfg, | ||
462 | void (*update)(struct rsnd_mod *mod), | ||
463 | const char * const *texts, | ||
464 | u32 max); | ||
465 | |||
466 | /* | ||
385 | * R-Car SRC | 467 | * R-Car SRC |
386 | */ | 468 | */ |
387 | int rsnd_src_probe(struct platform_device *pdev, | 469 | int rsnd_src_probe(struct platform_device *pdev, |
@@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
395 | struct rsnd_dai *rdai, | 477 | struct rsnd_dai *rdai, |
396 | int use_busif); | 478 | int use_busif); |
397 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | 479 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
398 | struct rsnd_dai *rdai, | 480 | struct rsnd_dai *rdai); |
399 | int use_busif); | 481 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod, |
400 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
401 | struct rsnd_dai *rdai); | 482 | struct rsnd_dai *rdai); |
483 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod, | ||
484 | struct rsnd_dai *rdai); | ||
402 | 485 | ||
403 | #define rsnd_src_nr(priv) ((priv)->src_nr) | 486 | #define rsnd_src_nr(priv) ((priv)->src_nr) |
404 | 487 | ||
@@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
410 | struct rsnd_priv *priv); | 493 | struct rsnd_priv *priv); |
411 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 494 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
412 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 495 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
496 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | ||
413 | 497 | ||
414 | /* | 498 | /* |
415 | * R-Car DVC | 499 | * R-Car DVC |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 9183e0145503..eede3ac6eed2 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | |||
175 | } | 175 | } |
176 | 176 | ||
177 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | 177 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, |
178 | struct rsnd_dai *rdai, | 178 | struct rsnd_dai *rdai) |
179 | int use_busif) | ||
180 | { | 179 | { |
181 | /* | 180 | /* |
182 | * DMA settings for SSIU | 181 | * DMA settings for SSIU |
183 | */ | 182 | */ |
184 | if (use_busif) | 183 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); |
185 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); | ||
186 | 184 | ||
187 | return 0; | 185 | return 0; |
188 | } | 186 | } |
189 | 187 | ||
190 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | 188 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod, |
191 | struct rsnd_dai *rdai) | 189 | struct rsnd_dai *rdai) |
192 | { | 190 | { |
193 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | 191 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); |
194 | 192 | ||
195 | /* enable PIO interrupt if Gen2 */ | 193 | if (rsnd_is_gen1(priv)) |
196 | if (rsnd_is_gen2(priv)) | 194 | return 0; |
195 | |||
196 | /* enable SSI interrupt if Gen2 */ | ||
197 | if (rsnd_ssi_is_dma_mode(ssi_mod)) | ||
198 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000); | ||
199 | else | ||
197 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); | 200 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); |
198 | 201 | ||
199 | return 0; | 202 | return 0; |
200 | } | 203 | } |
201 | 204 | ||
205 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod, | ||
206 | struct rsnd_dai *rdai) | ||
207 | { | ||
208 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
209 | |||
210 | if (rsnd_is_gen1(priv)) | ||
211 | return 0; | ||
212 | |||
213 | /* disable SSI interrupt if Gen2 */ | ||
214 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
202 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 219 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
203 | struct rsnd_dai_stream *io, | 220 | struct rsnd_dai_stream *io, |
204 | struct snd_pcm_runtime *runtime) | 221 | struct snd_pcm_runtime *runtime) |
@@ -239,12 +256,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, | |||
239 | rsnd_mod_write(mod, SRC_SWRSR, 0); | 256 | rsnd_mod_write(mod, SRC_SWRSR, 0); |
240 | rsnd_mod_write(mod, SRC_SWRSR, 1); | 257 | rsnd_mod_write(mod, SRC_SWRSR, 1); |
241 | 258 | ||
242 | /* | ||
243 | * Initialize the operation of the SRC internal circuits | ||
244 | * see rsnd_src_start() | ||
245 | */ | ||
246 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
247 | |||
248 | /* Set channel number and output bit length */ | 259 | /* Set channel number and output bit length */ |
249 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); | 260 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod)); |
250 | 261 | ||
@@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod, | |||
269 | 280 | ||
270 | clk_prepare_enable(src->clk); | 281 | clk_prepare_enable(src->clk); |
271 | 282 | ||
283 | /* | ||
284 | * Initialize the operation of the SRC internal circuits | ||
285 | * see rsnd_src_start() | ||
286 | */ | ||
287 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
288 | |||
272 | return 0; | 289 | return 0; |
273 | } | 290 | } |
274 | 291 | ||
@@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod, | |||
282 | return 0; | 299 | return 0; |
283 | } | 300 | } |
284 | 301 | ||
285 | static int rsnd_src_start(struct rsnd_mod *mod, | 302 | static int rsnd_src_start(struct rsnd_mod *mod) |
286 | struct rsnd_dai *rdai) | ||
287 | { | 303 | { |
288 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
289 | |||
290 | /* | 304 | /* |
291 | * Cancel the initialization and operate the SRC function | 305 | * Cancel the initialization and operate the SRC function |
292 | * see rsnd_src_set_convert_rate() | 306 | * see rsnd_src_init() |
293 | */ | 307 | */ |
294 | rsnd_mod_write(mod, SRC_SRCIR, 0); | 308 | rsnd_mod_write(mod, SRC_SRCIR, 0); |
295 | 309 | ||
296 | if (rsnd_src_convert_rate(src)) | ||
297 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
298 | |||
299 | return 0; | 310 | return 0; |
300 | } | 311 | } |
301 | 312 | ||
302 | 313 | static int rsnd_src_stop(struct rsnd_mod *mod) | |
303 | static int rsnd_src_stop(struct rsnd_mod *mod, | ||
304 | struct rsnd_dai *rdai) | ||
305 | { | 314 | { |
306 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 315 | /* nothing to do */ |
307 | |||
308 | if (rsnd_src_convert_rate(src)) | ||
309 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
310 | |||
311 | return 0; | 316 | return 0; |
312 | } | 317 | } |
313 | 318 | ||
@@ -414,6 +419,7 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, | |||
414 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | 419 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, |
415 | struct rsnd_dai *rdai) | 420 | struct rsnd_dai *rdai) |
416 | { | 421 | { |
422 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
417 | int ret; | 423 | int ret; |
418 | 424 | ||
419 | ret = rsnd_src_set_convert_rate(mod, rdai); | 425 | ret = rsnd_src_set_convert_rate(mod, rdai); |
@@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | |||
427 | rsnd_mod_write(mod, SRC_MNFSR, | 433 | rsnd_mod_write(mod, SRC_MNFSR, |
428 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | 434 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); |
429 | 435 | ||
436 | /* Gen1/Gen2 are not compatible */ | ||
437 | if (rsnd_src_convert_rate(src)) | ||
438 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
439 | |||
430 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | 440 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ |
431 | 441 | ||
432 | return 0; | 442 | return 0; |
@@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod, | |||
438 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 448 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
439 | struct device *dev = rsnd_priv_to_dev(priv); | 449 | struct device *dev = rsnd_priv_to_dev(priv); |
440 | 450 | ||
441 | dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod)); | 451 | dev_dbg(dev, "%s[%d] (Gen1) is probed\n", |
452 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
442 | 453 | ||
443 | return 0; | 454 | return 0; |
444 | } | 455 | } |
@@ -474,7 +485,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod, | |||
474 | 485 | ||
475 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); | 486 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); |
476 | 487 | ||
477 | return rsnd_src_start(mod, rdai); | 488 | return rsnd_src_start(mod); |
478 | } | 489 | } |
479 | 490 | ||
480 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | 491 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, |
@@ -484,7 +495,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | |||
484 | 495 | ||
485 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); | 496 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); |
486 | 497 | ||
487 | return rsnd_src_stop(mod, rdai); | 498 | return rsnd_src_stop(mod); |
488 | } | 499 | } |
489 | 500 | ||
490 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { | 501 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { |
@@ -507,16 +518,17 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | |||
507 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 518 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
508 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 519 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
509 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 520 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
521 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
510 | uint ratio; | 522 | uint ratio; |
511 | int ret; | 523 | int ret; |
512 | 524 | ||
513 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ | 525 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ |
514 | if (!rsnd_src_convert_rate(src)) | 526 | if (!convert_rate) |
515 | ratio = 0; | 527 | ratio = 0; |
516 | else if (rsnd_src_convert_rate(src) > runtime->rate) | 528 | else if (convert_rate > runtime->rate) |
517 | ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate; | 529 | ratio = 100 * convert_rate / runtime->rate; |
518 | else | 530 | else |
519 | ratio = 100 * runtime->rate / rsnd_src_convert_rate(src); | 531 | ratio = 100 * runtime->rate / convert_rate; |
520 | 532 | ||
521 | if (ratio > 600) { | 533 | if (ratio > 600) { |
522 | dev_err(dev, "FSO/FSI ratio error\n"); | 534 | dev_err(dev, "FSO/FSI ratio error\n"); |
@@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | |||
529 | 541 | ||
530 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | 542 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); |
531 | 543 | ||
544 | if (convert_rate) { | ||
545 | /* Gen1/Gen2 are not compatible */ | ||
546 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
547 | } | ||
548 | |||
532 | switch (rsnd_mod_id(mod)) { | 549 | switch (rsnd_mod_id(mod)) { |
533 | case 5: | 550 | case 5: |
534 | case 6: | 551 | case 6: |
@@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | |||
578 | rsnd_info_is_playback(priv, src), | 595 | rsnd_info_is_playback(priv, src), |
579 | src->info->dma_id); | 596 | src->info->dma_id); |
580 | if (ret < 0) | 597 | if (ret < 0) |
581 | dev_err(dev, "SRC DMA failed\n"); | 598 | dev_err(dev, "%s[%d] (Gen2) failed\n", |
582 | 599 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
583 | dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod)); | 600 | else |
601 | dev_dbg(dev, "%s[%d] (Gen2) is probed\n", | ||
602 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
584 | 603 | ||
585 | return ret; | 604 | return ret; |
586 | } | 605 | } |
@@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod, | |||
624 | 643 | ||
625 | rsnd_mod_write(mod, SRC_CTRL, val); | 644 | rsnd_mod_write(mod, SRC_CTRL, val); |
626 | 645 | ||
627 | return rsnd_src_start(mod, rdai); | 646 | return rsnd_src_start(mod); |
628 | } | 647 | } |
629 | 648 | ||
630 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | 649 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, |
@@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | |||
636 | 655 | ||
637 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); | 656 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); |
638 | 657 | ||
639 | return rsnd_src_stop(mod, rdai); | 658 | return rsnd_src_stop(mod); |
640 | } | 659 | } |
641 | 660 | ||
642 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | 661 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 34e84009162b..3844fbef4664 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -68,7 +68,6 @@ struct rsnd_ssi { | |||
68 | struct rsnd_dai *rdai; | 68 | struct rsnd_dai *rdai; |
69 | u32 cr_own; | 69 | u32 cr_own; |
70 | u32 cr_clk; | 70 | u32 cr_clk; |
71 | u32 cr_etc; | ||
72 | int err; | 71 | int err; |
73 | unsigned int usrcnt; | 72 | unsigned int usrcnt; |
74 | unsigned int rate; | 73 | unsigned int rate; |
@@ -83,7 +82,7 @@ struct rsnd_ssi { | |||
83 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) | 82 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
84 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 83 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
85 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 84 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
86 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 85 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) |
87 | #define rsnd_ssi_dma_available(ssi) \ | 86 | #define rsnd_ssi_dma_available(ssi) \ |
88 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 87 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
89 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 88 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
@@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod) | |||
96 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 95 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
97 | int use_busif = 0; | 96 | int use_busif = 0; |
98 | 97 | ||
98 | if (!rsnd_ssi_is_dma_mode(mod)) | ||
99 | return 0; | ||
100 | |||
99 | if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) | 101 | if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF)) |
100 | use_busif = 1; | 102 | use_busif = 1; |
101 | if (rsnd_io_to_mod_src(io)) | 103 | if (rsnd_io_to_mod_src(io)) |
@@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
159 | ssi->cr_clk = FORCE | SWL_32 | | 161 | ssi->cr_clk = FORCE | SWL_32 | |
160 | SCKD | SWSD | CKDV(j); | 162 | SCKD | SWSD | CKDV(j); |
161 | 163 | ||
162 | dev_dbg(dev, "ssi%d outputs %u Hz\n", | 164 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", |
165 | rsnd_mod_name(&ssi->mod), | ||
163 | rsnd_mod_id(&ssi->mod), rate); | 166 | rsnd_mod_id(&ssi->mod), rate); |
164 | 167 | ||
165 | return 0; | 168 | return 0; |
@@ -184,6 +187,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
184 | { | 187 | { |
185 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); | 188 | struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod); |
186 | struct device *dev = rsnd_priv_to_dev(priv); | 189 | struct device *dev = rsnd_priv_to_dev(priv); |
190 | u32 cr_mode; | ||
187 | u32 cr; | 191 | u32 cr; |
188 | 192 | ||
189 | if (0 == ssi->usrcnt) { | 193 | if (0 == ssi->usrcnt) { |
@@ -197,16 +201,29 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
197 | } | 201 | } |
198 | } | 202 | } |
199 | 203 | ||
204 | cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ? | ||
205 | DMEN : /* DMA : enable DMA */ | ||
206 | DIEN; /* PIO : enable Data interrupt */ | ||
207 | |||
208 | |||
200 | cr = ssi->cr_own | | 209 | cr = ssi->cr_own | |
201 | ssi->cr_clk | | 210 | ssi->cr_clk | |
202 | ssi->cr_etc | | 211 | cr_mode | |
203 | EN; | 212 | UIEN | OIEN | EN; |
204 | 213 | ||
205 | rsnd_mod_write(&ssi->mod, SSICR, cr); | 214 | rsnd_mod_write(&ssi->mod, SSICR, cr); |
206 | 215 | ||
216 | /* enable WS continue */ | ||
217 | if (rsnd_dai_is_clk_master(rdai)) | ||
218 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | ||
219 | |||
220 | /* clear error status */ | ||
221 | rsnd_mod_write(&ssi->mod, SSISR, 0); | ||
222 | |||
207 | ssi->usrcnt++; | 223 | ssi->usrcnt++; |
208 | 224 | ||
209 | dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod)); | 225 | dev_dbg(dev, "%s[%d] hw started\n", |
226 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); | ||
210 | } | 227 | } |
211 | 228 | ||
212 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | 229 | static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, |
@@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | |||
249 | clk_disable_unprepare(ssi->clk); | 266 | clk_disable_unprepare(ssi->clk); |
250 | } | 267 | } |
251 | 268 | ||
252 | dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod)); | 269 | dev_dbg(dev, "%s[%d] hw stopped\n", |
270 | rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod)); | ||
253 | } | 271 | } |
254 | 272 | ||
255 | /* | 273 | /* |
@@ -334,25 +352,54 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
334 | } | 352 | } |
335 | } | 353 | } |
336 | 354 | ||
337 | /* | 355 | static int rsnd_ssi_start(struct rsnd_mod *mod, |
338 | * SSI PIO | 356 | struct rsnd_dai *rdai) |
339 | */ | 357 | { |
340 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 358 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
359 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
360 | |||
361 | rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); | ||
362 | |||
363 | rsnd_ssi_hw_start(ssi, rdai, io); | ||
364 | |||
365 | rsnd_src_ssi_irq_enable(mod, rdai); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static int rsnd_ssi_stop(struct rsnd_mod *mod, | ||
371 | struct rsnd_dai *rdai) | ||
372 | { | ||
373 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
374 | |||
375 | rsnd_src_ssi_irq_disable(mod, rdai); | ||
376 | |||
377 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
378 | |||
379 | rsnd_ssi_hw_stop(ssi, rdai); | ||
380 | |||
381 | rsnd_src_ssiu_stop(mod, rdai); | ||
382 | |||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | ||
341 | { | 387 | { |
342 | struct rsnd_ssi *ssi = data; | 388 | struct rsnd_ssi *ssi = data; |
389 | struct rsnd_dai *rdai = ssi->rdai; | ||
343 | struct rsnd_mod *mod = &ssi->mod; | 390 | struct rsnd_mod *mod = &ssi->mod; |
344 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | 391 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
345 | u32 status = rsnd_mod_read(mod, SSISR); | 392 | u32 status = rsnd_mod_read(mod, SSISR); |
346 | irqreturn_t ret = IRQ_NONE; | ||
347 | 393 | ||
348 | if (io && (status & DIRQ)) { | 394 | if (!io) |
349 | struct rsnd_dai *rdai = ssi->rdai; | 395 | return IRQ_NONE; |
396 | |||
397 | /* PIO only */ | ||
398 | if (status & DIRQ) { | ||
350 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 399 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
351 | u32 *buf = (u32 *)(runtime->dma_area + | 400 | u32 *buf = (u32 *)(runtime->dma_area + |
352 | rsnd_dai_pointer_offset(io, 0)); | 401 | rsnd_dai_pointer_offset(io, 0)); |
353 | 402 | ||
354 | rsnd_ssi_record_error(ssi, status); | ||
355 | |||
356 | /* | 403 | /* |
357 | * 8/16/32 data can be assesse to TDR/RDR register | 404 | * 8/16/32 data can be assesse to TDR/RDR register |
358 | * directly as 32bit data | 405 | * directly as 32bit data |
@@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
364 | *buf = rsnd_mod_read(mod, SSIRDR); | 411 | *buf = rsnd_mod_read(mod, SSIRDR); |
365 | 412 | ||
366 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 413 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
414 | } | ||
415 | |||
416 | /* PIO / DMA */ | ||
417 | if (status & (UIRQ | OIRQ)) { | ||
418 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
419 | struct device *dev = rsnd_priv_to_dev(priv); | ||
420 | |||
421 | /* | ||
422 | * restart SSI | ||
423 | */ | ||
424 | rsnd_ssi_stop(mod, rdai); | ||
425 | rsnd_ssi_start(mod, rdai); | ||
367 | 426 | ||
368 | ret = IRQ_HANDLED; | 427 | dev_dbg(dev, "%s[%d] restart\n", |
428 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
369 | } | 429 | } |
370 | 430 | ||
371 | return ret; | 431 | rsnd_ssi_record_error(ssi, status); |
432 | |||
433 | return IRQ_HANDLED; | ||
372 | } | 434 | } |
373 | 435 | ||
436 | /* | ||
437 | * SSI PIO | ||
438 | */ | ||
374 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | 439 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
375 | struct rsnd_dai *rdai) | 440 | struct rsnd_dai *rdai) |
376 | { | 441 | { |
377 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 442 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
378 | struct device *dev = rsnd_priv_to_dev(priv); | 443 | struct device *dev = rsnd_priv_to_dev(priv); |
379 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 444 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
380 | int irq = ssi->info->pio_irq; | ||
381 | int ret; | 445 | int ret; |
382 | 446 | ||
383 | ret = devm_request_irq(dev, irq, | 447 | ret = devm_request_irq(dev, ssi->info->irq, |
384 | rsnd_ssi_pio_interrupt, | 448 | rsnd_ssi_interrupt, |
385 | IRQF_SHARED, | 449 | IRQF_SHARED, |
386 | dev_name(dev), ssi); | 450 | dev_name(dev), ssi); |
387 | if (ret) | 451 | if (ret) |
388 | dev_err(dev, "SSI request interrupt failed\n"); | 452 | dev_err(dev, "%s[%d] (PIO) request interrupt failed\n", |
389 | 453 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | |
390 | dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod)); | 454 | else |
455 | dev_dbg(dev, "%s[%d] (PIO) is probed\n", | ||
456 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
391 | 457 | ||
392 | return ret; | 458 | return ret; |
393 | } | 459 | } |
394 | 460 | ||
395 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
396 | struct rsnd_dai *rdai) | ||
397 | { | ||
398 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
399 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
400 | |||
401 | /* enable PIO IRQ */ | ||
402 | ssi->cr_etc = UIEN | OIEN | DIEN; | ||
403 | |||
404 | rsnd_src_ssiu_start(mod, rdai, 0); | ||
405 | |||
406 | rsnd_src_enable_ssi_irq(mod, rdai); | ||
407 | |||
408 | rsnd_ssi_hw_start(ssi, rdai, io); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | ||
414 | struct rsnd_dai *rdai) | ||
415 | { | ||
416 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
417 | |||
418 | ssi->cr_etc = 0; | ||
419 | |||
420 | rsnd_ssi_hw_stop(ssi, rdai); | ||
421 | |||
422 | rsnd_src_ssiu_stop(mod, rdai, 0); | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 461 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
428 | .name = SSI_NAME, | 462 | .name = SSI_NAME, |
429 | .probe = rsnd_ssi_pio_probe, | 463 | .probe = rsnd_ssi_pio_probe, |
430 | .init = rsnd_ssi_init, | 464 | .init = rsnd_ssi_init, |
431 | .quit = rsnd_ssi_quit, | 465 | .quit = rsnd_ssi_quit, |
432 | .start = rsnd_ssi_pio_start, | 466 | .start = rsnd_ssi_start, |
433 | .stop = rsnd_ssi_pio_stop, | 467 | .stop = rsnd_ssi_stop, |
434 | }; | 468 | }; |
435 | 469 | ||
436 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | 470 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
@@ -442,15 +476,28 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
442 | int dma_id = ssi->info->dma_id; | 476 | int dma_id = ssi->info->dma_id; |
443 | int ret; | 477 | int ret; |
444 | 478 | ||
479 | ret = devm_request_irq(dev, ssi->info->irq, | ||
480 | rsnd_ssi_interrupt, | ||
481 | IRQF_SHARED, | ||
482 | dev_name(dev), ssi); | ||
483 | if (ret) | ||
484 | goto rsnd_ssi_dma_probe_fail; | ||
485 | |||
445 | ret = rsnd_dma_init( | 486 | ret = rsnd_dma_init( |
446 | priv, rsnd_mod_to_dma(mod), | 487 | priv, rsnd_mod_to_dma(mod), |
447 | rsnd_info_is_playback(priv, ssi), | 488 | rsnd_info_is_playback(priv, ssi), |
448 | dma_id); | 489 | dma_id); |
490 | if (ret) | ||
491 | goto rsnd_ssi_dma_probe_fail; | ||
449 | 492 | ||
450 | if (ret < 0) | 493 | dev_dbg(dev, "%s[%d] (DMA) is probed\n", |
451 | dev_err(dev, "SSI DMA failed\n"); | 494 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
495 | |||
496 | return ret; | ||
452 | 497 | ||
453 | dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod)); | 498 | rsnd_ssi_dma_probe_fail: |
499 | dev_err(dev, "%s[%d] (DMA) is failed\n", | ||
500 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
454 | 501 | ||
455 | return ret; | 502 | return ret; |
456 | } | 503 | } |
@@ -458,30 +505,48 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
458 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, | 505 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
459 | struct rsnd_dai *rdai) | 506 | struct rsnd_dai *rdai) |
460 | { | 507 | { |
508 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
509 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
510 | struct device *dev = rsnd_priv_to_dev(priv); | ||
511 | int irq = ssi->info->irq; | ||
512 | |||
461 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | 513 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); |
462 | 514 | ||
515 | /* PIO will request IRQ again */ | ||
516 | devm_free_irq(dev, irq, ssi); | ||
517 | |||
463 | return 0; | 518 | return 0; |
464 | } | 519 | } |
465 | 520 | ||
466 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | 521 | static int rsnd_ssi_fallback(struct rsnd_mod *mod, |
467 | struct rsnd_dai *rdai) | 522 | struct rsnd_dai *rdai) |
468 | { | 523 | { |
469 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 524 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
470 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | 525 | struct device *dev = rsnd_priv_to_dev(priv); |
471 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
472 | 526 | ||
473 | /* enable DMA transfer */ | 527 | /* |
474 | ssi->cr_etc = DMEN; | 528 | * fallback to PIO |
529 | * | ||
530 | * SSI .probe might be called again. | ||
531 | * see | ||
532 | * rsnd_rdai_continuance_probe() | ||
533 | */ | ||
534 | mod->ops = &rsnd_ssi_pio_ops; | ||
475 | 535 | ||
476 | rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod)); | 536 | dev_info(dev, "%s[%d] fallback to PIO mode\n", |
537 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
477 | 538 | ||
478 | rsnd_dma_start(dma); | 539 | return 0; |
540 | } | ||
479 | 541 | ||
480 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 542 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, |
543 | struct rsnd_dai *rdai) | ||
544 | { | ||
545 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
481 | 546 | ||
482 | /* enable WS continue */ | 547 | rsnd_ssi_start(mod, rdai); |
483 | if (rsnd_dai_is_clk_master(rdai)) | 548 | |
484 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 549 | rsnd_dma_start(dma); |
485 | 550 | ||
486 | return 0; | 551 | return 0; |
487 | } | 552 | } |
@@ -489,18 +554,11 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
489 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | 554 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, |
490 | struct rsnd_dai *rdai) | 555 | struct rsnd_dai *rdai) |
491 | { | 556 | { |
492 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 557 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); |
493 | struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod); | ||
494 | |||
495 | ssi->cr_etc = 0; | ||
496 | |||
497 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
498 | |||
499 | rsnd_ssi_hw_stop(ssi, rdai); | ||
500 | 558 | ||
501 | rsnd_dma_stop(dma); | 559 | rsnd_dma_stop(dma); |
502 | 560 | ||
503 | rsnd_src_ssiu_stop(mod, rdai, 1); | 561 | rsnd_ssi_stop(mod, rdai); |
504 | 562 | ||
505 | return 0; | 563 | return 0; |
506 | } | 564 | } |
@@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
519 | .quit = rsnd_ssi_quit, | 577 | .quit = rsnd_ssi_quit, |
520 | .start = rsnd_ssi_dma_start, | 578 | .start = rsnd_ssi_dma_start, |
521 | .stop = rsnd_ssi_dma_stop, | 579 | .stop = rsnd_ssi_dma_stop, |
580 | .fallback = rsnd_ssi_fallback, | ||
522 | }; | 581 | }; |
523 | 582 | ||
583 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod) | ||
584 | { | ||
585 | return mod->ops == &rsnd_ssi_dma_ops; | ||
586 | } | ||
587 | |||
588 | |||
524 | /* | 589 | /* |
525 | * Non SSI | 590 | * Non SSI |
526 | */ | 591 | */ |
@@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev, | |||
614 | /* | 679 | /* |
615 | * irq | 680 | * irq |
616 | */ | 681 | */ |
617 | ssi_info->pio_irq = irq_of_parse_and_map(np, 0); | 682 | ssi_info->irq = irq_of_parse_and_map(np, 0); |
618 | 683 | ||
619 | /* | 684 | /* |
620 | * DMA | 685 | * DMA |
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c new file mode 100644 index 000000000000..2e10e9a38376 --- /dev/null +++ b/sound/soc/soc-ac97.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * soc-ac97.c -- ALSA SoC Audio Layer AC97 support | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | ||
10 | * with code, comments and ideas from :- | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/ctype.h> | ||
20 | #include <linux/delay.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/of_gpio.h> | ||
25 | #include <linux/of.h> | ||
26 | #include <linux/pinctrl/consumer.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <sound/ac97_codec.h> | ||
29 | #include <sound/soc.h> | ||
30 | |||
31 | struct snd_ac97_reset_cfg { | ||
32 | struct pinctrl *pctl; | ||
33 | struct pinctrl_state *pstate_reset; | ||
34 | struct pinctrl_state *pstate_warm_reset; | ||
35 | struct pinctrl_state *pstate_run; | ||
36 | int gpio_sdata; | ||
37 | int gpio_sync; | ||
38 | int gpio_reset; | ||
39 | }; | ||
40 | |||
41 | static struct snd_ac97_bus soc_ac97_bus = { | ||
42 | .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */ | ||
43 | }; | ||
44 | |||
45 | static void soc_ac97_device_release(struct device *dev) | ||
46 | { | ||
47 | kfree(to_ac97_t(dev)); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
52 | * @codec: audio codec | ||
53 | * | ||
54 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
55 | */ | ||
56 | struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) | ||
57 | { | ||
58 | struct snd_ac97 *ac97; | ||
59 | int ret; | ||
60 | |||
61 | ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
62 | if (ac97 == NULL) | ||
63 | return ERR_PTR(-ENOMEM); | ||
64 | |||
65 | ac97->bus = &soc_ac97_bus; | ||
66 | ac97->num = 0; | ||
67 | |||
68 | ac97->dev.bus = &ac97_bus_type; | ||
69 | ac97->dev.parent = codec->component.card->dev; | ||
70 | ac97->dev.release = soc_ac97_device_release; | ||
71 | |||
72 | dev_set_name(&ac97->dev, "%d-%d:%s", | ||
73 | codec->component.card->snd_card->number, 0, | ||
74 | codec->component.name); | ||
75 | |||
76 | ret = device_register(&ac97->dev); | ||
77 | if (ret) { | ||
78 | put_device(&ac97->dev); | ||
79 | return ERR_PTR(ret); | ||
80 | } | ||
81 | |||
82 | return ac97; | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
85 | |||
86 | /** | ||
87 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
88 | * @codec: audio codec | ||
89 | * | ||
90 | * Frees AC97 codec device resources. | ||
91 | */ | ||
92 | void snd_soc_free_ac97_codec(struct snd_ac97 *ac97) | ||
93 | { | ||
94 | device_del(&ac97->dev); | ||
95 | ac97->bus = NULL; | ||
96 | put_device(&ac97->dev); | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
99 | |||
100 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
101 | |||
102 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
103 | { | ||
104 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
105 | |||
106 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
107 | |||
108 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
109 | |||
110 | udelay(10); | ||
111 | |||
112 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
113 | |||
114 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
115 | msleep(2); | ||
116 | } | ||
117 | |||
118 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
119 | { | ||
120 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
121 | |||
122 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
123 | |||
124 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
125 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
126 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
127 | |||
128 | udelay(10); | ||
129 | |||
130 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
131 | |||
132 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
133 | msleep(2); | ||
134 | } | ||
135 | |||
136 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
137 | struct snd_ac97_reset_cfg *cfg) | ||
138 | { | ||
139 | struct pinctrl *p; | ||
140 | struct pinctrl_state *state; | ||
141 | int gpio; | ||
142 | int ret; | ||
143 | |||
144 | p = devm_pinctrl_get(dev); | ||
145 | if (IS_ERR(p)) { | ||
146 | dev_err(dev, "Failed to get pinctrl\n"); | ||
147 | return PTR_ERR(p); | ||
148 | } | ||
149 | cfg->pctl = p; | ||
150 | |||
151 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
152 | if (IS_ERR(state)) { | ||
153 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
154 | return PTR_ERR(state); | ||
155 | } | ||
156 | cfg->pstate_reset = state; | ||
157 | |||
158 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
159 | if (IS_ERR(state)) { | ||
160 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
161 | return PTR_ERR(state); | ||
162 | } | ||
163 | cfg->pstate_warm_reset = state; | ||
164 | |||
165 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
166 | if (IS_ERR(state)) { | ||
167 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
168 | return PTR_ERR(state); | ||
169 | } | ||
170 | cfg->pstate_run = state; | ||
171 | |||
172 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
173 | if (gpio < 0) { | ||
174 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
175 | return gpio; | ||
176 | } | ||
177 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
178 | if (ret) { | ||
179 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
180 | return ret; | ||
181 | } | ||
182 | cfg->gpio_sync = gpio; | ||
183 | |||
184 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
185 | if (gpio < 0) { | ||
186 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
187 | return gpio; | ||
188 | } | ||
189 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
190 | if (ret) { | ||
191 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
192 | return ret; | ||
193 | } | ||
194 | cfg->gpio_sdata = gpio; | ||
195 | |||
196 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
197 | if (gpio < 0) { | ||
198 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
199 | return gpio; | ||
200 | } | ||
201 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
202 | if (ret) { | ||
203 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
204 | return ret; | ||
205 | } | ||
206 | cfg->gpio_reset = gpio; | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | struct snd_ac97_bus_ops *soc_ac97_ops; | ||
212 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
213 | |||
214 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | ||
215 | { | ||
216 | if (ops == soc_ac97_ops) | ||
217 | return 0; | ||
218 | |||
219 | if (soc_ac97_ops && ops) | ||
220 | return -EBUSY; | ||
221 | |||
222 | soc_ac97_ops = ops; | ||
223 | soc_ac97_bus.ops = ops; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | ||
228 | |||
229 | /** | ||
230 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
231 | * | ||
232 | * This function sets the reset and warm_reset properties of ops and parses | ||
233 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
234 | */ | ||
235 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
236 | struct platform_device *pdev) | ||
237 | { | ||
238 | struct device *dev = &pdev->dev; | ||
239 | struct snd_ac97_reset_cfg cfg; | ||
240 | int ret; | ||
241 | |||
242 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
243 | if (ret) | ||
244 | return ret; | ||
245 | |||
246 | ret = snd_soc_set_ac97_ops(ops); | ||
247 | if (ret) | ||
248 | return ret; | ||
249 | |||
250 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
251 | ops->reset = snd_soc_ac97_reset; | ||
252 | |||
253 | snd_ac97_rst_cfg = cfg; | ||
254 | return 0; | ||
255 | } | ||
256 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index a9f82b5aba9d..07f43356f963 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -15,56 +15,6 @@ | |||
15 | #include <linux/export.h> | 15 | #include <linux/export.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | 17 | ||
18 | #include <trace/events/asoc.h> | ||
19 | |||
20 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
21 | unsigned int val, unsigned int word_size) | ||
22 | { | ||
23 | switch (word_size) { | ||
24 | case 1: { | ||
25 | u8 *cache = base; | ||
26 | if (cache[idx] == val) | ||
27 | return true; | ||
28 | cache[idx] = val; | ||
29 | break; | ||
30 | } | ||
31 | case 2: { | ||
32 | u16 *cache = base; | ||
33 | if (cache[idx] == val) | ||
34 | return true; | ||
35 | cache[idx] = val; | ||
36 | break; | ||
37 | } | ||
38 | default: | ||
39 | WARN(1, "Invalid word_size %d\n", word_size); | ||
40 | break; | ||
41 | } | ||
42 | return false; | ||
43 | } | ||
44 | |||
45 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
46 | unsigned int word_size) | ||
47 | { | ||
48 | if (!base) | ||
49 | return -1; | ||
50 | |||
51 | switch (word_size) { | ||
52 | case 1: { | ||
53 | const u8 *cache = base; | ||
54 | return cache[idx]; | ||
55 | } | ||
56 | case 2: { | ||
57 | const u16 *cache = base; | ||
58 | return cache[idx]; | ||
59 | } | ||
60 | default: | ||
61 | WARN(1, "Invalid word_size %d\n", word_size); | ||
62 | break; | ||
63 | } | ||
64 | /* unreachable */ | ||
65 | return -1; | ||
66 | } | ||
67 | |||
68 | int snd_soc_cache_init(struct snd_soc_codec *codec) | 18 | int snd_soc_cache_init(struct snd_soc_codec *codec) |
69 | { | 19 | { |
70 | const struct snd_soc_codec_driver *codec_drv = codec->driver; | 20 | const struct snd_soc_codec_driver *codec_drv = codec->driver; |
@@ -75,8 +25,6 @@ int snd_soc_cache_init(struct snd_soc_codec *codec) | |||
75 | if (!reg_size) | 25 | if (!reg_size) |
76 | return 0; | 26 | return 0; |
77 | 27 | ||
78 | mutex_init(&codec->cache_rw_mutex); | ||
79 | |||
80 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", | 28 | dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n", |
81 | codec->component.name); | 29 | codec->component.name); |
82 | 30 | ||
@@ -103,100 +51,3 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
103 | codec->reg_cache = NULL; | 51 | codec->reg_cache = NULL; |
104 | return 0; | 52 | return 0; |
105 | } | 53 | } |
106 | |||
107 | /** | ||
108 | * snd_soc_cache_read: Fetch the value of a given register from the cache. | ||
109 | * | ||
110 | * @codec: CODEC to configure. | ||
111 | * @reg: The register index. | ||
112 | * @value: The value to be returned. | ||
113 | */ | ||
114 | int snd_soc_cache_read(struct snd_soc_codec *codec, | ||
115 | unsigned int reg, unsigned int *value) | ||
116 | { | ||
117 | if (!value) | ||
118 | return -EINVAL; | ||
119 | |||
120 | mutex_lock(&codec->cache_rw_mutex); | ||
121 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
122 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | ||
123 | codec->driver->reg_word_size); | ||
124 | mutex_unlock(&codec->cache_rw_mutex); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | EXPORT_SYMBOL_GPL(snd_soc_cache_read); | ||
129 | |||
130 | /** | ||
131 | * snd_soc_cache_write: Set the value of a given register in the cache. | ||
132 | * | ||
133 | * @codec: CODEC to configure. | ||
134 | * @reg: The register index. | ||
135 | * @value: The new register value. | ||
136 | */ | ||
137 | int snd_soc_cache_write(struct snd_soc_codec *codec, | ||
138 | unsigned int reg, unsigned int value) | ||
139 | { | ||
140 | mutex_lock(&codec->cache_rw_mutex); | ||
141 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) | ||
142 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | ||
143 | codec->driver->reg_word_size); | ||
144 | mutex_unlock(&codec->cache_rw_mutex); | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | EXPORT_SYMBOL_GPL(snd_soc_cache_write); | ||
149 | |||
150 | static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | ||
151 | { | ||
152 | int i; | ||
153 | int ret; | ||
154 | const struct snd_soc_codec_driver *codec_drv; | ||
155 | unsigned int val; | ||
156 | |||
157 | codec_drv = codec->driver; | ||
158 | for (i = 0; i < codec_drv->reg_cache_size; ++i) { | ||
159 | ret = snd_soc_cache_read(codec, i, &val); | ||
160 | if (ret) | ||
161 | return ret; | ||
162 | if (codec_drv->reg_cache_default) | ||
163 | if (snd_soc_get_cache_val(codec_drv->reg_cache_default, | ||
164 | i, codec_drv->reg_word_size) == val) | ||
165 | continue; | ||
166 | |||
167 | ret = snd_soc_write(codec, i, val); | ||
168 | if (ret) | ||
169 | return ret; | ||
170 | dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n", | ||
171 | i, val); | ||
172 | } | ||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_cache_sync: Sync the register cache with the hardware. | ||
178 | * | ||
179 | * @codec: CODEC to configure. | ||
180 | * | ||
181 | * Any registers that should not be synced should be marked as | ||
182 | * volatile. In general drivers can choose not to use the provided | ||
183 | * syncing functionality if they so require. | ||
184 | */ | ||
185 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | ||
186 | { | ||
187 | const char *name = "flat"; | ||
188 | int ret; | ||
189 | |||
190 | if (!codec->cache_sync) | ||
191 | return 0; | ||
192 | |||
193 | dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n", | ||
194 | codec->component.name); | ||
195 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
196 | ret = snd_soc_flat_cache_sync(codec); | ||
197 | if (!ret) | ||
198 | codec->cache_sync = 0; | ||
199 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
200 | return ret; | ||
201 | } | ||
202 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | ||
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index cecfab3cc948..590a82f01d0b 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -258,10 +258,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) | |||
258 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) | 258 | list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be) |
259 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; | 259 | dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE; |
260 | 260 | ||
261 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 261 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); |
262 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | ||
263 | else | ||
264 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP); | ||
265 | 262 | ||
266 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; | 263 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; |
267 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 264 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
@@ -456,11 +453,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream, | |||
456 | if (ret < 0) | 453 | if (ret < 0) |
457 | goto out; | 454 | goto out; |
458 | 455 | ||
459 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 456 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); |
460 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | ||
461 | else | ||
462 | dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START); | ||
463 | |||
464 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; | 457 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE; |
465 | 458 | ||
466 | out: | 459 | out: |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b60ff56ebc0f..935721062c21 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -34,9 +34,6 @@ | |||
34 | #include <linux/ctype.h> | 34 | #include <linux/ctype.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | #include <linux/of.h> | 36 | #include <linux/of.h> |
37 | #include <linux/gpio.h> | ||
38 | #include <linux/of_gpio.h> | ||
39 | #include <sound/ac97_codec.h> | ||
40 | #include <sound/core.h> | 37 | #include <sound/core.h> |
41 | #include <sound/jack.h> | 38 | #include <sound/jack.h> |
42 | #include <sound/pcm.h> | 39 | #include <sound/pcm.h> |
@@ -69,16 +66,6 @@ static int pmdown_time = 5000; | |||
69 | module_param(pmdown_time, int, 0); | 66 | module_param(pmdown_time, int, 0); |
70 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 67 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
71 | 68 | ||
72 | struct snd_ac97_reset_cfg { | ||
73 | struct pinctrl *pctl; | ||
74 | struct pinctrl_state *pstate_reset; | ||
75 | struct pinctrl_state *pstate_warm_reset; | ||
76 | struct pinctrl_state *pstate_run; | ||
77 | int gpio_sdata; | ||
78 | int gpio_sync; | ||
79 | int gpio_reset; | ||
80 | }; | ||
81 | |||
82 | /* returns the minimum number of bytes needed to represent | 69 | /* returns the minimum number of bytes needed to represent |
83 | * a particular given value */ | 70 | * a particular given value */ |
84 | static int min_bytes_needed(unsigned long val) | 71 | static int min_bytes_needed(unsigned long val) |
@@ -309,9 +296,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component) | |||
309 | { | 296 | { |
310 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | 297 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); |
311 | 298 | ||
312 | debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, | ||
313 | &codec->cache_sync); | ||
314 | |||
315 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 299 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
316 | codec->component.debugfs_root, | 300 | codec->component.debugfs_root, |
317 | codec, &codec_reg_fops); | 301 | codec, &codec_reg_fops); |
@@ -499,40 +483,6 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | |||
499 | } | 483 | } |
500 | EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); | 484 | EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); |
501 | 485 | ||
502 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
503 | /* unregister ac97 codec */ | ||
504 | static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) | ||
505 | { | ||
506 | if (codec->ac97->dev.bus) | ||
507 | device_unregister(&codec->ac97->dev); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | /* stop no dev release warning */ | ||
512 | static void soc_ac97_device_release(struct device *dev){} | ||
513 | |||
514 | /* register ac97 codec to bus */ | ||
515 | static int soc_ac97_dev_register(struct snd_soc_codec *codec) | ||
516 | { | ||
517 | int err; | ||
518 | |||
519 | codec->ac97->dev.bus = &ac97_bus_type; | ||
520 | codec->ac97->dev.parent = codec->component.card->dev; | ||
521 | codec->ac97->dev.release = soc_ac97_device_release; | ||
522 | |||
523 | dev_set_name(&codec->ac97->dev, "%d-%d:%s", | ||
524 | codec->component.card->snd_card->number, 0, | ||
525 | codec->component.name); | ||
526 | err = device_register(&codec->ac97->dev); | ||
527 | if (err < 0) { | ||
528 | dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); | ||
529 | codec->ac97->dev.bus = NULL; | ||
530 | return err; | ||
531 | } | ||
532 | return 0; | ||
533 | } | ||
534 | #endif | ||
535 | |||
536 | static void codec2codec_close_delayed_work(struct work_struct *work) | 486 | static void codec2codec_close_delayed_work(struct work_struct *work) |
537 | { | 487 | { |
538 | /* Currently nothing to do for c2c links | 488 | /* Currently nothing to do for c2c links |
@@ -592,17 +542,12 @@ int snd_soc_suspend(struct device *dev) | |||
592 | 542 | ||
593 | for (i = 0; i < card->num_rtd; i++) { | 543 | for (i = 0; i < card->num_rtd; i++) { |
594 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 544 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
595 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
596 | 545 | ||
597 | if (card->rtd[i].dai_link->ignore_suspend) | 546 | if (card->rtd[i].dai_link->ignore_suspend) |
598 | continue; | 547 | continue; |
599 | 548 | ||
600 | if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) | 549 | if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) |
601 | cpu_dai->driver->suspend(cpu_dai); | 550 | cpu_dai->driver->suspend(cpu_dai); |
602 | if (platform->driver->suspend && !platform->suspended) { | ||
603 | platform->driver->suspend(cpu_dai); | ||
604 | platform->suspended = 1; | ||
605 | } | ||
606 | } | 551 | } |
607 | 552 | ||
608 | /* close any waiting streams and save state */ | 553 | /* close any waiting streams and save state */ |
@@ -629,8 +574,8 @@ int snd_soc_suspend(struct device *dev) | |||
629 | SND_SOC_DAPM_STREAM_SUSPEND); | 574 | SND_SOC_DAPM_STREAM_SUSPEND); |
630 | } | 575 | } |
631 | 576 | ||
632 | /* Recheck all analogue paths too */ | 577 | /* Recheck all endpoints too, their state is affected by suspend */ |
633 | dapm_mark_io_dirty(&card->dapm); | 578 | dapm_mark_endpoints_dirty(card); |
634 | snd_soc_dapm_sync(&card->dapm); | 579 | snd_soc_dapm_sync(&card->dapm); |
635 | 580 | ||
636 | /* suspend all CODECs */ | 581 | /* suspend all CODECs */ |
@@ -656,7 +601,6 @@ int snd_soc_suspend(struct device *dev) | |||
656 | if (codec->driver->suspend) | 601 | if (codec->driver->suspend) |
657 | codec->driver->suspend(codec); | 602 | codec->driver->suspend(codec); |
658 | codec->suspended = 1; | 603 | codec->suspended = 1; |
659 | codec->cache_sync = 1; | ||
660 | if (codec->component.regmap) | 604 | if (codec->component.regmap) |
661 | regcache_mark_dirty(codec->component.regmap); | 605 | regcache_mark_dirty(codec->component.regmap); |
662 | /* deactivate pins to sleep state */ | 606 | /* deactivate pins to sleep state */ |
@@ -676,7 +620,7 @@ int snd_soc_suspend(struct device *dev) | |||
676 | if (card->rtd[i].dai_link->ignore_suspend) | 620 | if (card->rtd[i].dai_link->ignore_suspend) |
677 | continue; | 621 | continue; |
678 | 622 | ||
679 | if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) | 623 | if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) |
680 | cpu_dai->driver->suspend(cpu_dai); | 624 | cpu_dai->driver->suspend(cpu_dai); |
681 | 625 | ||
682 | /* deactivate pins to sleep state */ | 626 | /* deactivate pins to sleep state */ |
@@ -712,14 +656,14 @@ static void soc_resume_deferred(struct work_struct *work) | |||
712 | if (card->resume_pre) | 656 | if (card->resume_pre) |
713 | card->resume_pre(card); | 657 | card->resume_pre(card); |
714 | 658 | ||
715 | /* resume AC97 DAIs */ | 659 | /* resume control bus DAIs */ |
716 | for (i = 0; i < card->num_rtd; i++) { | 660 | for (i = 0; i < card->num_rtd; i++) { |
717 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 661 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
718 | 662 | ||
719 | if (card->rtd[i].dai_link->ignore_suspend) | 663 | if (card->rtd[i].dai_link->ignore_suspend) |
720 | continue; | 664 | continue; |
721 | 665 | ||
722 | if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) | 666 | if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) |
723 | cpu_dai->driver->resume(cpu_dai); | 667 | cpu_dai->driver->resume(cpu_dai); |
724 | } | 668 | } |
725 | 669 | ||
@@ -775,17 +719,12 @@ static void soc_resume_deferred(struct work_struct *work) | |||
775 | 719 | ||
776 | for (i = 0; i < card->num_rtd; i++) { | 720 | for (i = 0; i < card->num_rtd; i++) { |
777 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 721 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
778 | struct snd_soc_platform *platform = card->rtd[i].platform; | ||
779 | 722 | ||
780 | if (card->rtd[i].dai_link->ignore_suspend) | 723 | if (card->rtd[i].dai_link->ignore_suspend) |
781 | continue; | 724 | continue; |
782 | 725 | ||
783 | if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) | 726 | if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) |
784 | cpu_dai->driver->resume(cpu_dai); | 727 | cpu_dai->driver->resume(cpu_dai); |
785 | if (platform->driver->resume && platform->suspended) { | ||
786 | platform->driver->resume(cpu_dai); | ||
787 | platform->suspended = 0; | ||
788 | } | ||
789 | } | 728 | } |
790 | 729 | ||
791 | if (card->resume_post) | 730 | if (card->resume_post) |
@@ -796,8 +735,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
796 | /* userspace can access us now we are back as we were before */ | 735 | /* userspace can access us now we are back as we were before */ |
797 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); | 736 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0); |
798 | 737 | ||
799 | /* Recheck all analogue paths too */ | 738 | /* Recheck all endpoints too, their state is affected by suspend */ |
800 | dapm_mark_io_dirty(&card->dapm); | 739 | dapm_mark_endpoints_dirty(card); |
801 | snd_soc_dapm_sync(&card->dapm); | 740 | snd_soc_dapm_sync(&card->dapm); |
802 | } | 741 | } |
803 | 742 | ||
@@ -805,7 +744,8 @@ static void soc_resume_deferred(struct work_struct *work) | |||
805 | int snd_soc_resume(struct device *dev) | 744 | int snd_soc_resume(struct device *dev) |
806 | { | 745 | { |
807 | struct snd_soc_card *card = dev_get_drvdata(dev); | 746 | struct snd_soc_card *card = dev_get_drvdata(dev); |
808 | int i, ac97_control = 0; | 747 | bool bus_control = false; |
748 | int i; | ||
809 | 749 | ||
810 | /* If the card is not initialized yet there is nothing to do */ | 750 | /* If the card is not initialized yet there is nothing to do */ |
811 | if (!card->instantiated) | 751 | if (!card->instantiated) |
@@ -828,17 +768,18 @@ int snd_soc_resume(struct device *dev) | |||
828 | } | 768 | } |
829 | } | 769 | } |
830 | 770 | ||
831 | /* AC97 devices might have other drivers hanging off them so | 771 | /* |
832 | * need to resume immediately. Other drivers don't have that | 772 | * DAIs that also act as the control bus master might have other drivers |
833 | * problem and may take a substantial amount of time to resume | 773 | * hanging off them so need to resume immediately. Other drivers don't |
774 | * have that problem and may take a substantial amount of time to resume | ||
834 | * due to I/O costs and anti-pop so handle them out of line. | 775 | * due to I/O costs and anti-pop so handle them out of line. |
835 | */ | 776 | */ |
836 | for (i = 0; i < card->num_rtd; i++) { | 777 | for (i = 0; i < card->num_rtd; i++) { |
837 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 778 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
838 | ac97_control |= cpu_dai->driver->ac97_control; | 779 | bus_control |= cpu_dai->driver->bus_control; |
839 | } | 780 | } |
840 | if (ac97_control) { | 781 | if (bus_control) { |
841 | dev_dbg(dev, "ASoC: Resuming AC97 immediately\n"); | 782 | dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); |
842 | soc_resume_deferred(&card->deferred_resume_work); | 783 | soc_resume_deferred(&card->deferred_resume_work); |
843 | } else { | 784 | } else { |
844 | dev_dbg(dev, "ASoC: Scheduling resume work\n"); | 785 | dev_dbg(dev, "ASoC: Scheduling resume work\n"); |
@@ -1251,25 +1192,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1251 | return 0; | 1192 | return 0; |
1252 | } | 1193 | } |
1253 | 1194 | ||
1254 | static int soc_probe_codec_dai(struct snd_soc_card *card, | 1195 | static int soc_probe_dai(struct snd_soc_dai *dai, int order) |
1255 | struct snd_soc_dai *codec_dai, | ||
1256 | int order) | ||
1257 | { | 1196 | { |
1258 | int ret; | 1197 | int ret; |
1259 | 1198 | ||
1260 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { | 1199 | if (!dai->probed && dai->driver->probe_order == order) { |
1261 | if (codec_dai->driver->probe) { | 1200 | if (dai->driver->probe) { |
1262 | ret = codec_dai->driver->probe(codec_dai); | 1201 | ret = dai->driver->probe(dai); |
1263 | if (ret < 0) { | 1202 | if (ret < 0) { |
1264 | dev_err(codec_dai->dev, | 1203 | dev_err(dai->dev, |
1265 | "ASoC: failed to probe CODEC DAI %s: %d\n", | 1204 | "ASoC: failed to probe DAI %s: %d\n", |
1266 | codec_dai->name, ret); | 1205 | dai->name, ret); |
1267 | return ret; | 1206 | return ret; |
1268 | } | 1207 | } |
1269 | } | 1208 | } |
1270 | 1209 | ||
1271 | /* mark codec_dai as probed and add to card dai list */ | 1210 | dai->probed = 1; |
1272 | codec_dai->probed = 1; | ||
1273 | } | 1211 | } |
1274 | 1212 | ||
1275 | return 0; | 1213 | return 0; |
@@ -1319,40 +1257,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1319 | { | 1257 | { |
1320 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1258 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1321 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1259 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1322 | struct snd_soc_platform *platform = rtd->platform; | ||
1323 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1260 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1324 | int i, ret; | 1261 | int i, ret; |
1325 | 1262 | ||
1326 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", | 1263 | dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n", |
1327 | card->name, num, order); | 1264 | card->name, num, order); |
1328 | 1265 | ||
1329 | /* config components */ | ||
1330 | cpu_dai->platform = platform; | ||
1331 | cpu_dai->card = card; | ||
1332 | for (i = 0; i < rtd->num_codecs; i++) | ||
1333 | rtd->codec_dais[i]->card = card; | ||
1334 | |||
1335 | /* set default power off timeout */ | 1266 | /* set default power off timeout */ |
1336 | rtd->pmdown_time = pmdown_time; | 1267 | rtd->pmdown_time = pmdown_time; |
1337 | 1268 | ||
1338 | /* probe the cpu_dai */ | 1269 | ret = soc_probe_dai(cpu_dai, order); |
1339 | if (!cpu_dai->probed && | 1270 | if (ret) |
1340 | cpu_dai->driver->probe_order == order) { | 1271 | return ret; |
1341 | if (cpu_dai->driver->probe) { | ||
1342 | ret = cpu_dai->driver->probe(cpu_dai); | ||
1343 | if (ret < 0) { | ||
1344 | dev_err(cpu_dai->dev, | ||
1345 | "ASoC: failed to probe CPU DAI %s: %d\n", | ||
1346 | cpu_dai->name, ret); | ||
1347 | return ret; | ||
1348 | } | ||
1349 | } | ||
1350 | cpu_dai->probed = 1; | ||
1351 | } | ||
1352 | 1272 | ||
1353 | /* probe the CODEC DAI */ | 1273 | /* probe the CODEC DAI */ |
1354 | for (i = 0; i < rtd->num_codecs; i++) { | 1274 | for (i = 0; i < rtd->num_codecs; i++) { |
1355 | ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order); | 1275 | ret = soc_probe_dai(rtd->codec_dais[i], order); |
1356 | if (ret) | 1276 | if (ret) |
1357 | return ret; | 1277 | return ret; |
1358 | } | 1278 | } |
@@ -1422,84 +1342,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1422 | } | 1342 | } |
1423 | } | 1343 | } |
1424 | 1344 | ||
1425 | /* add platform data for AC97 devices */ | ||
1426 | for (i = 0; i < rtd->num_codecs; i++) { | ||
1427 | if (rtd->codec_dais[i]->driver->ac97_control) | ||
1428 | snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97, | ||
1429 | rtd->cpu_dai->ac97_pdata); | ||
1430 | } | ||
1431 | |||
1432 | return 0; | 1345 | return 0; |
1433 | } | 1346 | } |
1434 | 1347 | ||
1435 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1436 | static int soc_register_ac97_codec(struct snd_soc_codec *codec, | ||
1437 | struct snd_soc_dai *codec_dai) | ||
1438 | { | ||
1439 | int ret; | ||
1440 | |||
1441 | /* Only instantiate AC97 if not already done by the adaptor | ||
1442 | * for the generic AC97 subsystem. | ||
1443 | */ | ||
1444 | if (codec_dai->driver->ac97_control && !codec->ac97_registered) { | ||
1445 | /* | ||
1446 | * It is possible that the AC97 device is already registered to | ||
1447 | * the device subsystem. This happens when the device is created | ||
1448 | * via snd_ac97_mixer(). Currently only SoC codec that does so | ||
1449 | * is the generic AC97 glue but others migh emerge. | ||
1450 | * | ||
1451 | * In those cases we don't try to register the device again. | ||
1452 | */ | ||
1453 | if (!codec->ac97_created) | ||
1454 | return 0; | ||
1455 | |||
1456 | ret = soc_ac97_dev_register(codec); | ||
1457 | if (ret < 0) { | ||
1458 | dev_err(codec->dev, | ||
1459 | "ASoC: AC97 device register failed: %d\n", ret); | ||
1460 | return ret; | ||
1461 | } | ||
1462 | |||
1463 | codec->ac97_registered = 1; | ||
1464 | } | ||
1465 | return 0; | ||
1466 | } | ||
1467 | |||
1468 | static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) | ||
1469 | { | ||
1470 | if (codec->ac97_registered) { | ||
1471 | soc_ac97_dev_unregister(codec); | ||
1472 | codec->ac97_registered = 0; | ||
1473 | } | ||
1474 | } | ||
1475 | |||
1476 | static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | ||
1477 | { | ||
1478 | int i, ret; | ||
1479 | |||
1480 | for (i = 0; i < rtd->num_codecs; i++) { | ||
1481 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | ||
1482 | |||
1483 | ret = soc_register_ac97_codec(codec_dai->codec, codec_dai); | ||
1484 | if (ret) { | ||
1485 | while (--i >= 0) | ||
1486 | soc_unregister_ac97_codec(codec_dai->codec); | ||
1487 | return ret; | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | return 0; | ||
1492 | } | ||
1493 | |||
1494 | static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) | ||
1495 | { | ||
1496 | int i; | ||
1497 | |||
1498 | for (i = 0; i < rtd->num_codecs; i++) | ||
1499 | soc_unregister_ac97_codec(rtd->codec_dais[i]->codec); | ||
1500 | } | ||
1501 | #endif | ||
1502 | |||
1503 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) | 1348 | static int soc_bind_aux_dev(struct snd_soc_card *card, int num) |
1504 | { | 1349 | { |
1505 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | 1350 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; |
@@ -1793,20 +1638,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1793 | goto probe_aux_dev_err; | 1638 | goto probe_aux_dev_err; |
1794 | } | 1639 | } |
1795 | 1640 | ||
1796 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
1797 | /* register any AC97 codecs */ | ||
1798 | for (i = 0; i < card->num_rtd; i++) { | ||
1799 | ret = soc_register_ac97_dai_link(&card->rtd[i]); | ||
1800 | if (ret < 0) { | ||
1801 | dev_err(card->dev, | ||
1802 | "ASoC: failed to register AC97: %d\n", ret); | ||
1803 | while (--i >= 0) | ||
1804 | soc_unregister_ac97_dai_link(&card->rtd[i]); | ||
1805 | goto probe_aux_dev_err; | ||
1806 | } | ||
1807 | } | ||
1808 | #endif | ||
1809 | |||
1810 | card->instantiated = 1; | 1641 | card->instantiated = 1; |
1811 | snd_soc_dapm_sync(&card->dapm); | 1642 | snd_soc_dapm_sync(&card->dapm); |
1812 | mutex_unlock(&card->mutex); | 1643 | mutex_unlock(&card->mutex); |
@@ -1949,216 +1780,6 @@ static struct platform_driver soc_driver = { | |||
1949 | }; | 1780 | }; |
1950 | 1781 | ||
1951 | /** | 1782 | /** |
1952 | * snd_soc_new_ac97_codec - initailise AC97 device | ||
1953 | * @codec: audio codec | ||
1954 | * @ops: AC97 bus operations | ||
1955 | * @num: AC97 codec number | ||
1956 | * | ||
1957 | * Initialises AC97 codec resources for use by ad-hoc devices only. | ||
1958 | */ | ||
1959 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | ||
1960 | struct snd_ac97_bus_ops *ops, int num) | ||
1961 | { | ||
1962 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | ||
1963 | if (codec->ac97 == NULL) | ||
1964 | return -ENOMEM; | ||
1965 | |||
1966 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | ||
1967 | if (codec->ac97->bus == NULL) { | ||
1968 | kfree(codec->ac97); | ||
1969 | codec->ac97 = NULL; | ||
1970 | return -ENOMEM; | ||
1971 | } | ||
1972 | |||
1973 | codec->ac97->bus->ops = ops; | ||
1974 | codec->ac97->num = num; | ||
1975 | |||
1976 | /* | ||
1977 | * Mark the AC97 device to be created by us. This way we ensure that the | ||
1978 | * device will be registered with the device subsystem later on. | ||
1979 | */ | ||
1980 | codec->ac97_created = 1; | ||
1981 | |||
1982 | return 0; | ||
1983 | } | ||
1984 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | ||
1985 | |||
1986 | static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; | ||
1987 | |||
1988 | static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) | ||
1989 | { | ||
1990 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
1991 | |||
1992 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); | ||
1993 | |||
1994 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); | ||
1995 | |||
1996 | udelay(10); | ||
1997 | |||
1998 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
1999 | |||
2000 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2001 | msleep(2); | ||
2002 | } | ||
2003 | |||
2004 | static void snd_soc_ac97_reset(struct snd_ac97 *ac97) | ||
2005 | { | ||
2006 | struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; | ||
2007 | |||
2008 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); | ||
2009 | |||
2010 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); | ||
2011 | gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); | ||
2012 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); | ||
2013 | |||
2014 | udelay(10); | ||
2015 | |||
2016 | gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); | ||
2017 | |||
2018 | pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); | ||
2019 | msleep(2); | ||
2020 | } | ||
2021 | |||
2022 | static int snd_soc_ac97_parse_pinctl(struct device *dev, | ||
2023 | struct snd_ac97_reset_cfg *cfg) | ||
2024 | { | ||
2025 | struct pinctrl *p; | ||
2026 | struct pinctrl_state *state; | ||
2027 | int gpio; | ||
2028 | int ret; | ||
2029 | |||
2030 | p = devm_pinctrl_get(dev); | ||
2031 | if (IS_ERR(p)) { | ||
2032 | dev_err(dev, "Failed to get pinctrl\n"); | ||
2033 | return PTR_ERR(p); | ||
2034 | } | ||
2035 | cfg->pctl = p; | ||
2036 | |||
2037 | state = pinctrl_lookup_state(p, "ac97-reset"); | ||
2038 | if (IS_ERR(state)) { | ||
2039 | dev_err(dev, "Can't find pinctrl state ac97-reset\n"); | ||
2040 | return PTR_ERR(state); | ||
2041 | } | ||
2042 | cfg->pstate_reset = state; | ||
2043 | |||
2044 | state = pinctrl_lookup_state(p, "ac97-warm-reset"); | ||
2045 | if (IS_ERR(state)) { | ||
2046 | dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); | ||
2047 | return PTR_ERR(state); | ||
2048 | } | ||
2049 | cfg->pstate_warm_reset = state; | ||
2050 | |||
2051 | state = pinctrl_lookup_state(p, "ac97-running"); | ||
2052 | if (IS_ERR(state)) { | ||
2053 | dev_err(dev, "Can't find pinctrl state ac97-running\n"); | ||
2054 | return PTR_ERR(state); | ||
2055 | } | ||
2056 | cfg->pstate_run = state; | ||
2057 | |||
2058 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); | ||
2059 | if (gpio < 0) { | ||
2060 | dev_err(dev, "Can't find ac97-sync gpio\n"); | ||
2061 | return gpio; | ||
2062 | } | ||
2063 | ret = devm_gpio_request(dev, gpio, "AC97 link sync"); | ||
2064 | if (ret) { | ||
2065 | dev_err(dev, "Failed requesting ac97-sync gpio\n"); | ||
2066 | return ret; | ||
2067 | } | ||
2068 | cfg->gpio_sync = gpio; | ||
2069 | |||
2070 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); | ||
2071 | if (gpio < 0) { | ||
2072 | dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); | ||
2073 | return gpio; | ||
2074 | } | ||
2075 | ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); | ||
2076 | if (ret) { | ||
2077 | dev_err(dev, "Failed requesting ac97-sdata gpio\n"); | ||
2078 | return ret; | ||
2079 | } | ||
2080 | cfg->gpio_sdata = gpio; | ||
2081 | |||
2082 | gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); | ||
2083 | if (gpio < 0) { | ||
2084 | dev_err(dev, "Can't find ac97-reset gpio\n"); | ||
2085 | return gpio; | ||
2086 | } | ||
2087 | ret = devm_gpio_request(dev, gpio, "AC97 link reset"); | ||
2088 | if (ret) { | ||
2089 | dev_err(dev, "Failed requesting ac97-reset gpio\n"); | ||
2090 | return ret; | ||
2091 | } | ||
2092 | cfg->gpio_reset = gpio; | ||
2093 | |||
2094 | return 0; | ||
2095 | } | ||
2096 | |||
2097 | struct snd_ac97_bus_ops *soc_ac97_ops; | ||
2098 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | ||
2099 | |||
2100 | int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) | ||
2101 | { | ||
2102 | if (ops == soc_ac97_ops) | ||
2103 | return 0; | ||
2104 | |||
2105 | if (soc_ac97_ops && ops) | ||
2106 | return -EBUSY; | ||
2107 | |||
2108 | soc_ac97_ops = ops; | ||
2109 | |||
2110 | return 0; | ||
2111 | } | ||
2112 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); | ||
2113 | |||
2114 | /** | ||
2115 | * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions | ||
2116 | * | ||
2117 | * This function sets the reset and warm_reset properties of ops and parses | ||
2118 | * the device node of pdev to get pinctrl states and gpio numbers to use. | ||
2119 | */ | ||
2120 | int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, | ||
2121 | struct platform_device *pdev) | ||
2122 | { | ||
2123 | struct device *dev = &pdev->dev; | ||
2124 | struct snd_ac97_reset_cfg cfg; | ||
2125 | int ret; | ||
2126 | |||
2127 | ret = snd_soc_ac97_parse_pinctl(dev, &cfg); | ||
2128 | if (ret) | ||
2129 | return ret; | ||
2130 | |||
2131 | ret = snd_soc_set_ac97_ops(ops); | ||
2132 | if (ret) | ||
2133 | return ret; | ||
2134 | |||
2135 | ops->warm_reset = snd_soc_ac97_warm_reset; | ||
2136 | ops->reset = snd_soc_ac97_reset; | ||
2137 | |||
2138 | snd_ac97_rst_cfg = cfg; | ||
2139 | return 0; | ||
2140 | } | ||
2141 | EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | ||
2142 | |||
2143 | /** | ||
2144 | * snd_soc_free_ac97_codec - free AC97 codec device | ||
2145 | * @codec: audio codec | ||
2146 | * | ||
2147 | * Frees AC97 codec device resources. | ||
2148 | */ | ||
2149 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | ||
2150 | { | ||
2151 | #ifdef CONFIG_SND_SOC_AC97_BUS | ||
2152 | soc_unregister_ac97_codec(codec); | ||
2153 | #endif | ||
2154 | kfree(codec->ac97->bus); | ||
2155 | kfree(codec->ac97); | ||
2156 | codec->ac97 = NULL; | ||
2157 | codec->ac97_created = 0; | ||
2158 | } | ||
2159 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | ||
2160 | |||
2161 | /** | ||
2162 | * snd_soc_cnew - create new control | 1783 | * snd_soc_cnew - create new control |
2163 | * @_template: control template | 1784 | * @_template: control template |
2164 | * @data: control private data | 1785 | * @data: control private data |
@@ -2326,7 +1947,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls); | |||
2326 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | 1947 | int snd_soc_add_dai_controls(struct snd_soc_dai *dai, |
2327 | const struct snd_kcontrol_new *controls, int num_controls) | 1948 | const struct snd_kcontrol_new *controls, int num_controls) |
2328 | { | 1949 | { |
2329 | struct snd_card *card = dai->card->snd_card; | 1950 | struct snd_card *card = dai->component->card->snd_card; |
2330 | 1951 | ||
2331 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, | 1952 | return snd_soc_add_controls(card, dai->dev, controls, num_controls, |
2332 | NULL, dai); | 1953 | NULL, dai); |
@@ -2334,1020 +1955,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai, | |||
2334 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); | 1955 | EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls); |
2335 | 1956 | ||
2336 | /** | 1957 | /** |
2337 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
2338 | * @kcontrol: mixer control | ||
2339 | * @uinfo: control element information | ||
2340 | * | ||
2341 | * Callback to provide information about a double enumerated | ||
2342 | * mixer control. | ||
2343 | * | ||
2344 | * Returns 0 for success. | ||
2345 | */ | ||
2346 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
2347 | struct snd_ctl_elem_info *uinfo) | ||
2348 | { | ||
2349 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2350 | |||
2351 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2352 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | ||
2353 | uinfo->value.enumerated.items = e->items; | ||
2354 | |||
2355 | if (uinfo->value.enumerated.item >= e->items) | ||
2356 | uinfo->value.enumerated.item = e->items - 1; | ||
2357 | strlcpy(uinfo->value.enumerated.name, | ||
2358 | e->texts[uinfo->value.enumerated.item], | ||
2359 | sizeof(uinfo->value.enumerated.name)); | ||
2360 | return 0; | ||
2361 | } | ||
2362 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
2363 | |||
2364 | /** | ||
2365 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
2366 | * @kcontrol: mixer control | ||
2367 | * @ucontrol: control element information | ||
2368 | * | ||
2369 | * Callback to get the value of a double enumerated mixer. | ||
2370 | * | ||
2371 | * Returns 0 for success. | ||
2372 | */ | ||
2373 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
2374 | struct snd_ctl_elem_value *ucontrol) | ||
2375 | { | ||
2376 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2377 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2378 | unsigned int val, item; | ||
2379 | unsigned int reg_val; | ||
2380 | int ret; | ||
2381 | |||
2382 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
2383 | if (ret) | ||
2384 | return ret; | ||
2385 | val = (reg_val >> e->shift_l) & e->mask; | ||
2386 | item = snd_soc_enum_val_to_item(e, val); | ||
2387 | ucontrol->value.enumerated.item[0] = item; | ||
2388 | if (e->shift_l != e->shift_r) { | ||
2389 | val = (reg_val >> e->shift_l) & e->mask; | ||
2390 | item = snd_soc_enum_val_to_item(e, val); | ||
2391 | ucontrol->value.enumerated.item[1] = item; | ||
2392 | } | ||
2393 | |||
2394 | return 0; | ||
2395 | } | ||
2396 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
2397 | |||
2398 | /** | ||
2399 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
2400 | * @kcontrol: mixer control | ||
2401 | * @ucontrol: control element information | ||
2402 | * | ||
2403 | * Callback to set the value of a double enumerated mixer. | ||
2404 | * | ||
2405 | * Returns 0 for success. | ||
2406 | */ | ||
2407 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
2408 | struct snd_ctl_elem_value *ucontrol) | ||
2409 | { | ||
2410 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2411 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2412 | unsigned int *item = ucontrol->value.enumerated.item; | ||
2413 | unsigned int val; | ||
2414 | unsigned int mask; | ||
2415 | |||
2416 | if (item[0] >= e->items) | ||
2417 | return -EINVAL; | ||
2418 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
2419 | mask = e->mask << e->shift_l; | ||
2420 | if (e->shift_l != e->shift_r) { | ||
2421 | if (item[1] >= e->items) | ||
2422 | return -EINVAL; | ||
2423 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
2424 | mask |= e->mask << e->shift_r; | ||
2425 | } | ||
2426 | |||
2427 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
2428 | } | ||
2429 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
2430 | |||
2431 | /** | ||
2432 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
2433 | * @component: component | ||
2434 | * @reg: Register to read | ||
2435 | * @mask: Mask to use after shifting the register value | ||
2436 | * @shift: Right shift of register value | ||
2437 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2438 | * @signed_val: Pointer to where the read value should be stored | ||
2439 | * | ||
2440 | * This functions reads a codec register. The register value is shifted right | ||
2441 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
2442 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2443 | * | ||
2444 | * Returns 0 on sucess, otherwise an error value | ||
2445 | */ | ||
2446 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
2447 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
2448 | unsigned int sign_bit, int *signed_val) | ||
2449 | { | ||
2450 | int ret; | ||
2451 | unsigned int val; | ||
2452 | |||
2453 | ret = snd_soc_component_read(component, reg, &val); | ||
2454 | if (ret < 0) | ||
2455 | return ret; | ||
2456 | |||
2457 | val = (val >> shift) & mask; | ||
2458 | |||
2459 | if (!sign_bit) { | ||
2460 | *signed_val = val; | ||
2461 | return 0; | ||
2462 | } | ||
2463 | |||
2464 | /* non-negative number */ | ||
2465 | if (!(val & BIT(sign_bit))) { | ||
2466 | *signed_val = val; | ||
2467 | return 0; | ||
2468 | } | ||
2469 | |||
2470 | ret = val; | ||
2471 | |||
2472 | /* | ||
2473 | * The register most probably does not contain a full-sized int. | ||
2474 | * Instead we have an arbitrary number of bits in a signed | ||
2475 | * representation which has to be translated into a full-sized int. | ||
2476 | * This is done by filling up all bits above the sign-bit. | ||
2477 | */ | ||
2478 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2479 | |||
2480 | *signed_val = ret; | ||
2481 | |||
2482 | return 0; | ||
2483 | } | ||
2484 | |||
2485 | /** | ||
2486 | * snd_soc_info_volsw - single mixer info callback | ||
2487 | * @kcontrol: mixer control | ||
2488 | * @uinfo: control element information | ||
2489 | * | ||
2490 | * Callback to provide information about a single mixer control, or a double | ||
2491 | * mixer control that spans 2 registers. | ||
2492 | * | ||
2493 | * Returns 0 for success. | ||
2494 | */ | ||
2495 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
2496 | struct snd_ctl_elem_info *uinfo) | ||
2497 | { | ||
2498 | struct soc_mixer_control *mc = | ||
2499 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2500 | int platform_max; | ||
2501 | |||
2502 | if (!mc->platform_max) | ||
2503 | mc->platform_max = mc->max; | ||
2504 | platform_max = mc->platform_max; | ||
2505 | |||
2506 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
2507 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
2508 | else | ||
2509 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2510 | |||
2511 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2512 | uinfo->value.integer.min = 0; | ||
2513 | uinfo->value.integer.max = platform_max - mc->min; | ||
2514 | return 0; | ||
2515 | } | ||
2516 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
2517 | |||
2518 | /** | ||
2519 | * snd_soc_get_volsw - single mixer get callback | ||
2520 | * @kcontrol: mixer control | ||
2521 | * @ucontrol: control element information | ||
2522 | * | ||
2523 | * Callback to get the value of a single mixer control, or a double mixer | ||
2524 | * control that spans 2 registers. | ||
2525 | * | ||
2526 | * Returns 0 for success. | ||
2527 | */ | ||
2528 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
2529 | struct snd_ctl_elem_value *ucontrol) | ||
2530 | { | ||
2531 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2532 | struct soc_mixer_control *mc = | ||
2533 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2534 | unsigned int reg = mc->reg; | ||
2535 | unsigned int reg2 = mc->rreg; | ||
2536 | unsigned int shift = mc->shift; | ||
2537 | unsigned int rshift = mc->rshift; | ||
2538 | int max = mc->max; | ||
2539 | int min = mc->min; | ||
2540 | int sign_bit = mc->sign_bit; | ||
2541 | unsigned int mask = (1 << fls(max)) - 1; | ||
2542 | unsigned int invert = mc->invert; | ||
2543 | int val; | ||
2544 | int ret; | ||
2545 | |||
2546 | if (sign_bit) | ||
2547 | mask = BIT(sign_bit + 1) - 1; | ||
2548 | |||
2549 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
2550 | if (ret) | ||
2551 | return ret; | ||
2552 | |||
2553 | ucontrol->value.integer.value[0] = val - min; | ||
2554 | if (invert) | ||
2555 | ucontrol->value.integer.value[0] = | ||
2556 | max - ucontrol->value.integer.value[0]; | ||
2557 | |||
2558 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2559 | if (reg == reg2) | ||
2560 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
2561 | sign_bit, &val); | ||
2562 | else | ||
2563 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
2564 | sign_bit, &val); | ||
2565 | if (ret) | ||
2566 | return ret; | ||
2567 | |||
2568 | ucontrol->value.integer.value[1] = val - min; | ||
2569 | if (invert) | ||
2570 | ucontrol->value.integer.value[1] = | ||
2571 | max - ucontrol->value.integer.value[1]; | ||
2572 | } | ||
2573 | |||
2574 | return 0; | ||
2575 | } | ||
2576 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
2577 | |||
2578 | /** | ||
2579 | * snd_soc_put_volsw - single mixer put callback | ||
2580 | * @kcontrol: mixer control | ||
2581 | * @ucontrol: control element information | ||
2582 | * | ||
2583 | * Callback to set the value of a single mixer control, or a double mixer | ||
2584 | * control that spans 2 registers. | ||
2585 | * | ||
2586 | * Returns 0 for success. | ||
2587 | */ | ||
2588 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
2589 | struct snd_ctl_elem_value *ucontrol) | ||
2590 | { | ||
2591 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2592 | struct soc_mixer_control *mc = | ||
2593 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2594 | unsigned int reg = mc->reg; | ||
2595 | unsigned int reg2 = mc->rreg; | ||
2596 | unsigned int shift = mc->shift; | ||
2597 | unsigned int rshift = mc->rshift; | ||
2598 | int max = mc->max; | ||
2599 | int min = mc->min; | ||
2600 | unsigned int sign_bit = mc->sign_bit; | ||
2601 | unsigned int mask = (1 << fls(max)) - 1; | ||
2602 | unsigned int invert = mc->invert; | ||
2603 | int err; | ||
2604 | bool type_2r = false; | ||
2605 | unsigned int val2 = 0; | ||
2606 | unsigned int val, val_mask; | ||
2607 | |||
2608 | if (sign_bit) | ||
2609 | mask = BIT(sign_bit + 1) - 1; | ||
2610 | |||
2611 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2612 | if (invert) | ||
2613 | val = max - val; | ||
2614 | val_mask = mask << shift; | ||
2615 | val = val << shift; | ||
2616 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2617 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2618 | if (invert) | ||
2619 | val2 = max - val2; | ||
2620 | if (reg == reg2) { | ||
2621 | val_mask |= mask << rshift; | ||
2622 | val |= val2 << rshift; | ||
2623 | } else { | ||
2624 | val2 = val2 << shift; | ||
2625 | type_2r = true; | ||
2626 | } | ||
2627 | } | ||
2628 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2629 | if (err < 0) | ||
2630 | return err; | ||
2631 | |||
2632 | if (type_2r) | ||
2633 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2634 | val2); | ||
2635 | |||
2636 | return err; | ||
2637 | } | ||
2638 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
2639 | |||
2640 | /** | ||
2641 | * snd_soc_get_volsw_sx - single mixer get callback | ||
2642 | * @kcontrol: mixer control | ||
2643 | * @ucontrol: control element information | ||
2644 | * | ||
2645 | * Callback to get the value of a single mixer control, or a double mixer | ||
2646 | * control that spans 2 registers. | ||
2647 | * | ||
2648 | * Returns 0 for success. | ||
2649 | */ | ||
2650 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2651 | struct snd_ctl_elem_value *ucontrol) | ||
2652 | { | ||
2653 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2654 | struct soc_mixer_control *mc = | ||
2655 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2656 | unsigned int reg = mc->reg; | ||
2657 | unsigned int reg2 = mc->rreg; | ||
2658 | unsigned int shift = mc->shift; | ||
2659 | unsigned int rshift = mc->rshift; | ||
2660 | int max = mc->max; | ||
2661 | int min = mc->min; | ||
2662 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2663 | unsigned int val; | ||
2664 | int ret; | ||
2665 | |||
2666 | ret = snd_soc_component_read(component, reg, &val); | ||
2667 | if (ret < 0) | ||
2668 | return ret; | ||
2669 | |||
2670 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
2671 | |||
2672 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2673 | ret = snd_soc_component_read(component, reg2, &val); | ||
2674 | if (ret < 0) | ||
2675 | return ret; | ||
2676 | |||
2677 | val = ((val >> rshift) - min) & mask; | ||
2678 | ucontrol->value.integer.value[1] = val; | ||
2679 | } | ||
2680 | |||
2681 | return 0; | ||
2682 | } | ||
2683 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
2684 | |||
2685 | /** | ||
2686 | * snd_soc_put_volsw_sx - double mixer set callback | ||
2687 | * @kcontrol: mixer control | ||
2688 | * @uinfo: control element information | ||
2689 | * | ||
2690 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
2691 | * | ||
2692 | * Returns 0 for success. | ||
2693 | */ | ||
2694 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
2695 | struct snd_ctl_elem_value *ucontrol) | ||
2696 | { | ||
2697 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2698 | struct soc_mixer_control *mc = | ||
2699 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2700 | |||
2701 | unsigned int reg = mc->reg; | ||
2702 | unsigned int reg2 = mc->rreg; | ||
2703 | unsigned int shift = mc->shift; | ||
2704 | unsigned int rshift = mc->rshift; | ||
2705 | int max = mc->max; | ||
2706 | int min = mc->min; | ||
2707 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
2708 | int err = 0; | ||
2709 | unsigned int val, val_mask, val2 = 0; | ||
2710 | |||
2711 | val_mask = mask << shift; | ||
2712 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
2713 | val = val << shift; | ||
2714 | |||
2715 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2716 | if (err < 0) | ||
2717 | return err; | ||
2718 | |||
2719 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2720 | val_mask = mask << rshift; | ||
2721 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
2722 | val2 = val2 << rshift; | ||
2723 | |||
2724 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
2725 | val2); | ||
2726 | } | ||
2727 | return err; | ||
2728 | } | ||
2729 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
2730 | |||
2731 | /** | ||
2732 | * snd_soc_info_volsw_s8 - signed mixer info callback | ||
2733 | * @kcontrol: mixer control | ||
2734 | * @uinfo: control element information | ||
2735 | * | ||
2736 | * Callback to provide information about a signed mixer control. | ||
2737 | * | ||
2738 | * Returns 0 for success. | ||
2739 | */ | ||
2740 | int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2741 | struct snd_ctl_elem_info *uinfo) | ||
2742 | { | ||
2743 | struct soc_mixer_control *mc = | ||
2744 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2745 | int platform_max; | ||
2746 | int min = mc->min; | ||
2747 | |||
2748 | if (!mc->platform_max) | ||
2749 | mc->platform_max = mc->max; | ||
2750 | platform_max = mc->platform_max; | ||
2751 | |||
2752 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2753 | uinfo->count = 2; | ||
2754 | uinfo->value.integer.min = 0; | ||
2755 | uinfo->value.integer.max = platform_max - min; | ||
2756 | return 0; | ||
2757 | } | ||
2758 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8); | ||
2759 | |||
2760 | /** | ||
2761 | * snd_soc_get_volsw_s8 - signed mixer get callback | ||
2762 | * @kcontrol: mixer control | ||
2763 | * @ucontrol: control element information | ||
2764 | * | ||
2765 | * Callback to get the value of a signed mixer control. | ||
2766 | * | ||
2767 | * Returns 0 for success. | ||
2768 | */ | ||
2769 | int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2770 | struct snd_ctl_elem_value *ucontrol) | ||
2771 | { | ||
2772 | struct soc_mixer_control *mc = | ||
2773 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2774 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2775 | unsigned int reg = mc->reg; | ||
2776 | unsigned int val; | ||
2777 | int min = mc->min; | ||
2778 | int ret; | ||
2779 | |||
2780 | ret = snd_soc_component_read(component, reg, &val); | ||
2781 | if (ret) | ||
2782 | return ret; | ||
2783 | |||
2784 | ucontrol->value.integer.value[0] = | ||
2785 | ((signed char)(val & 0xff))-min; | ||
2786 | ucontrol->value.integer.value[1] = | ||
2787 | ((signed char)((val >> 8) & 0xff))-min; | ||
2788 | return 0; | ||
2789 | } | ||
2790 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8); | ||
2791 | |||
2792 | /** | ||
2793 | * snd_soc_put_volsw_sgn - signed mixer put callback | ||
2794 | * @kcontrol: mixer control | ||
2795 | * @ucontrol: control element information | ||
2796 | * | ||
2797 | * Callback to set the value of a signed mixer control. | ||
2798 | * | ||
2799 | * Returns 0 for success. | ||
2800 | */ | ||
2801 | int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | ||
2802 | struct snd_ctl_elem_value *ucontrol) | ||
2803 | { | ||
2804 | struct soc_mixer_control *mc = | ||
2805 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2806 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2807 | unsigned int reg = mc->reg; | ||
2808 | int min = mc->min; | ||
2809 | unsigned int val; | ||
2810 | |||
2811 | val = (ucontrol->value.integer.value[0]+min) & 0xff; | ||
2812 | val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8; | ||
2813 | |||
2814 | return snd_soc_component_update_bits(component, reg, 0xffff, val); | ||
2815 | } | ||
2816 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | ||
2817 | |||
2818 | /** | ||
2819 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
2820 | * @kcontrol: mixer control | ||
2821 | * @uinfo: control element information | ||
2822 | * | ||
2823 | * Callback to provide information, within a range, about a single | ||
2824 | * mixer control. | ||
2825 | * | ||
2826 | * returns 0 for success. | ||
2827 | */ | ||
2828 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
2829 | struct snd_ctl_elem_info *uinfo) | ||
2830 | { | ||
2831 | struct soc_mixer_control *mc = | ||
2832 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2833 | int platform_max; | ||
2834 | int min = mc->min; | ||
2835 | |||
2836 | if (!mc->platform_max) | ||
2837 | mc->platform_max = mc->max; | ||
2838 | platform_max = mc->platform_max; | ||
2839 | |||
2840 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2841 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
2842 | uinfo->value.integer.min = 0; | ||
2843 | uinfo->value.integer.max = platform_max - min; | ||
2844 | |||
2845 | return 0; | ||
2846 | } | ||
2847 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
2848 | |||
2849 | /** | ||
2850 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
2851 | * @kcontrol: mixer control | ||
2852 | * @ucontrol: control element information | ||
2853 | * | ||
2854 | * Callback to set the value, within a range, for a single mixer control. | ||
2855 | * | ||
2856 | * Returns 0 for success. | ||
2857 | */ | ||
2858 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
2859 | struct snd_ctl_elem_value *ucontrol) | ||
2860 | { | ||
2861 | struct soc_mixer_control *mc = | ||
2862 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2863 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2864 | unsigned int reg = mc->reg; | ||
2865 | unsigned int rreg = mc->rreg; | ||
2866 | unsigned int shift = mc->shift; | ||
2867 | int min = mc->min; | ||
2868 | int max = mc->max; | ||
2869 | unsigned int mask = (1 << fls(max)) - 1; | ||
2870 | unsigned int invert = mc->invert; | ||
2871 | unsigned int val, val_mask; | ||
2872 | int ret; | ||
2873 | |||
2874 | if (invert) | ||
2875 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
2876 | else | ||
2877 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2878 | val_mask = mask << shift; | ||
2879 | val = val << shift; | ||
2880 | |||
2881 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
2882 | if (ret < 0) | ||
2883 | return ret; | ||
2884 | |||
2885 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2886 | if (invert) | ||
2887 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
2888 | else | ||
2889 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
2890 | val_mask = mask << shift; | ||
2891 | val = val << shift; | ||
2892 | |||
2893 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
2894 | val); | ||
2895 | } | ||
2896 | |||
2897 | return ret; | ||
2898 | } | ||
2899 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
2900 | |||
2901 | /** | ||
2902 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
2903 | * @kcontrol: mixer control | ||
2904 | * @ucontrol: control element information | ||
2905 | * | ||
2906 | * Callback to get the value, within a range, of a single mixer control. | ||
2907 | * | ||
2908 | * Returns 0 for success. | ||
2909 | */ | ||
2910 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
2911 | struct snd_ctl_elem_value *ucontrol) | ||
2912 | { | ||
2913 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2914 | struct soc_mixer_control *mc = | ||
2915 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2916 | unsigned int reg = mc->reg; | ||
2917 | unsigned int rreg = mc->rreg; | ||
2918 | unsigned int shift = mc->shift; | ||
2919 | int min = mc->min; | ||
2920 | int max = mc->max; | ||
2921 | unsigned int mask = (1 << fls(max)) - 1; | ||
2922 | unsigned int invert = mc->invert; | ||
2923 | unsigned int val; | ||
2924 | int ret; | ||
2925 | |||
2926 | ret = snd_soc_component_read(component, reg, &val); | ||
2927 | if (ret) | ||
2928 | return ret; | ||
2929 | |||
2930 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
2931 | if (invert) | ||
2932 | ucontrol->value.integer.value[0] = | ||
2933 | max - ucontrol->value.integer.value[0]; | ||
2934 | else | ||
2935 | ucontrol->value.integer.value[0] = | ||
2936 | ucontrol->value.integer.value[0] - min; | ||
2937 | |||
2938 | if (snd_soc_volsw_is_stereo(mc)) { | ||
2939 | ret = snd_soc_component_read(component, rreg, &val); | ||
2940 | if (ret) | ||
2941 | return ret; | ||
2942 | |||
2943 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
2944 | if (invert) | ||
2945 | ucontrol->value.integer.value[1] = | ||
2946 | max - ucontrol->value.integer.value[1]; | ||
2947 | else | ||
2948 | ucontrol->value.integer.value[1] = | ||
2949 | ucontrol->value.integer.value[1] - min; | ||
2950 | } | ||
2951 | |||
2952 | return 0; | ||
2953 | } | ||
2954 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
2955 | |||
2956 | /** | ||
2957 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
2958 | * | ||
2959 | * @codec: where to look for the control | ||
2960 | * @name: Name of the control | ||
2961 | * @max: new maximum limit | ||
2962 | * | ||
2963 | * Return 0 for success, else error. | ||
2964 | */ | ||
2965 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
2966 | const char *name, int max) | ||
2967 | { | ||
2968 | struct snd_card *card = codec->component.card->snd_card; | ||
2969 | struct snd_kcontrol *kctl; | ||
2970 | struct soc_mixer_control *mc; | ||
2971 | int found = 0; | ||
2972 | int ret = -EINVAL; | ||
2973 | |||
2974 | /* Sanity check for name and max */ | ||
2975 | if (unlikely(!name || max <= 0)) | ||
2976 | return -EINVAL; | ||
2977 | |||
2978 | list_for_each_entry(kctl, &card->controls, list) { | ||
2979 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
2980 | found = 1; | ||
2981 | break; | ||
2982 | } | ||
2983 | } | ||
2984 | if (found) { | ||
2985 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
2986 | if (max <= mc->max) { | ||
2987 | mc->platform_max = max; | ||
2988 | ret = 0; | ||
2989 | } | ||
2990 | } | ||
2991 | return ret; | ||
2992 | } | ||
2993 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
2994 | |||
2995 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
2996 | struct snd_ctl_elem_info *uinfo) | ||
2997 | { | ||
2998 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
2999 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3000 | |||
3001 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
3002 | uinfo->count = params->num_regs * component->val_bytes; | ||
3003 | |||
3004 | return 0; | ||
3005 | } | ||
3006 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
3007 | |||
3008 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
3009 | struct snd_ctl_elem_value *ucontrol) | ||
3010 | { | ||
3011 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3012 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3013 | int ret; | ||
3014 | |||
3015 | if (component->regmap) | ||
3016 | ret = regmap_raw_read(component->regmap, params->base, | ||
3017 | ucontrol->value.bytes.data, | ||
3018 | params->num_regs * component->val_bytes); | ||
3019 | else | ||
3020 | ret = -EINVAL; | ||
3021 | |||
3022 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
3023 | if (ret == 0 && params->mask) { | ||
3024 | switch (component->val_bytes) { | ||
3025 | case 1: | ||
3026 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
3027 | break; | ||
3028 | case 2: | ||
3029 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
3030 | &= cpu_to_be16(~params->mask); | ||
3031 | break; | ||
3032 | case 4: | ||
3033 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
3034 | &= cpu_to_be32(~params->mask); | ||
3035 | break; | ||
3036 | default: | ||
3037 | return -EINVAL; | ||
3038 | } | ||
3039 | } | ||
3040 | |||
3041 | return ret; | ||
3042 | } | ||
3043 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
3044 | |||
3045 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
3046 | struct snd_ctl_elem_value *ucontrol) | ||
3047 | { | ||
3048 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3049 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
3050 | int ret, len; | ||
3051 | unsigned int val, mask; | ||
3052 | void *data; | ||
3053 | |||
3054 | if (!component->regmap || !params->num_regs) | ||
3055 | return -EINVAL; | ||
3056 | |||
3057 | len = params->num_regs * component->val_bytes; | ||
3058 | |||
3059 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
3060 | if (!data) | ||
3061 | return -ENOMEM; | ||
3062 | |||
3063 | /* | ||
3064 | * If we've got a mask then we need to preserve the register | ||
3065 | * bits. We shouldn't modify the incoming data so take a | ||
3066 | * copy. | ||
3067 | */ | ||
3068 | if (params->mask) { | ||
3069 | ret = regmap_read(component->regmap, params->base, &val); | ||
3070 | if (ret != 0) | ||
3071 | goto out; | ||
3072 | |||
3073 | val &= params->mask; | ||
3074 | |||
3075 | switch (component->val_bytes) { | ||
3076 | case 1: | ||
3077 | ((u8 *)data)[0] &= ~params->mask; | ||
3078 | ((u8 *)data)[0] |= val; | ||
3079 | break; | ||
3080 | case 2: | ||
3081 | mask = ~params->mask; | ||
3082 | ret = regmap_parse_val(component->regmap, | ||
3083 | &mask, &mask); | ||
3084 | if (ret != 0) | ||
3085 | goto out; | ||
3086 | |||
3087 | ((u16 *)data)[0] &= mask; | ||
3088 | |||
3089 | ret = regmap_parse_val(component->regmap, | ||
3090 | &val, &val); | ||
3091 | if (ret != 0) | ||
3092 | goto out; | ||
3093 | |||
3094 | ((u16 *)data)[0] |= val; | ||
3095 | break; | ||
3096 | case 4: | ||
3097 | mask = ~params->mask; | ||
3098 | ret = regmap_parse_val(component->regmap, | ||
3099 | &mask, &mask); | ||
3100 | if (ret != 0) | ||
3101 | goto out; | ||
3102 | |||
3103 | ((u32 *)data)[0] &= mask; | ||
3104 | |||
3105 | ret = regmap_parse_val(component->regmap, | ||
3106 | &val, &val); | ||
3107 | if (ret != 0) | ||
3108 | goto out; | ||
3109 | |||
3110 | ((u32 *)data)[0] |= val; | ||
3111 | break; | ||
3112 | default: | ||
3113 | ret = -EINVAL; | ||
3114 | goto out; | ||
3115 | } | ||
3116 | } | ||
3117 | |||
3118 | ret = regmap_raw_write(component->regmap, params->base, | ||
3119 | data, len); | ||
3120 | |||
3121 | out: | ||
3122 | kfree(data); | ||
3123 | |||
3124 | return ret; | ||
3125 | } | ||
3126 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
3127 | |||
3128 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
3129 | struct snd_ctl_elem_info *ucontrol) | ||
3130 | { | ||
3131 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
3132 | |||
3133 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
3134 | ucontrol->count = params->max; | ||
3135 | |||
3136 | return 0; | ||
3137 | } | ||
3138 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
3139 | |||
3140 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
3141 | unsigned int size, unsigned int __user *tlv) | ||
3142 | { | ||
3143 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
3144 | unsigned int count = size < params->max ? size : params->max; | ||
3145 | int ret = -ENXIO; | ||
3146 | |||
3147 | switch (op_flag) { | ||
3148 | case SNDRV_CTL_TLV_OP_READ: | ||
3149 | if (params->get) | ||
3150 | ret = params->get(tlv, count); | ||
3151 | break; | ||
3152 | case SNDRV_CTL_TLV_OP_WRITE: | ||
3153 | if (params->put) | ||
3154 | ret = params->put(tlv, count); | ||
3155 | break; | ||
3156 | } | ||
3157 | return ret; | ||
3158 | } | ||
3159 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
3160 | |||
3161 | /** | ||
3162 | * snd_soc_info_xr_sx - signed multi register info callback | ||
3163 | * @kcontrol: mreg control | ||
3164 | * @uinfo: control element information | ||
3165 | * | ||
3166 | * Callback to provide information of a control that can | ||
3167 | * span multiple codec registers which together | ||
3168 | * forms a single signed value in a MSB/LSB manner. | ||
3169 | * | ||
3170 | * Returns 0 for success. | ||
3171 | */ | ||
3172 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
3173 | struct snd_ctl_elem_info *uinfo) | ||
3174 | { | ||
3175 | struct soc_mreg_control *mc = | ||
3176 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3177 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
3178 | uinfo->count = 1; | ||
3179 | uinfo->value.integer.min = mc->min; | ||
3180 | uinfo->value.integer.max = mc->max; | ||
3181 | |||
3182 | return 0; | ||
3183 | } | ||
3184 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
3185 | |||
3186 | /** | ||
3187 | * snd_soc_get_xr_sx - signed multi register get callback | ||
3188 | * @kcontrol: mreg control | ||
3189 | * @ucontrol: control element information | ||
3190 | * | ||
3191 | * Callback to get the value of a control that can span | ||
3192 | * multiple codec registers which together forms a single | ||
3193 | * signed value in a MSB/LSB manner. The control supports | ||
3194 | * specifying total no of bits used to allow for bitfields | ||
3195 | * across the multiple codec registers. | ||
3196 | * | ||
3197 | * Returns 0 for success. | ||
3198 | */ | ||
3199 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
3200 | struct snd_ctl_elem_value *ucontrol) | ||
3201 | { | ||
3202 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3203 | struct soc_mreg_control *mc = | ||
3204 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3205 | unsigned int regbase = mc->regbase; | ||
3206 | unsigned int regcount = mc->regcount; | ||
3207 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
3208 | unsigned int regwmask = (1<<regwshift)-1; | ||
3209 | unsigned int invert = mc->invert; | ||
3210 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
3211 | long min = mc->min; | ||
3212 | long max = mc->max; | ||
3213 | long val = 0; | ||
3214 | unsigned int regval; | ||
3215 | unsigned int i; | ||
3216 | int ret; | ||
3217 | |||
3218 | for (i = 0; i < regcount; i++) { | ||
3219 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
3220 | if (ret) | ||
3221 | return ret; | ||
3222 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
3223 | } | ||
3224 | val &= mask; | ||
3225 | if (min < 0 && val > max) | ||
3226 | val |= ~mask; | ||
3227 | if (invert) | ||
3228 | val = max - val; | ||
3229 | ucontrol->value.integer.value[0] = val; | ||
3230 | |||
3231 | return 0; | ||
3232 | } | ||
3233 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
3234 | |||
3235 | /** | ||
3236 | * snd_soc_put_xr_sx - signed multi register get callback | ||
3237 | * @kcontrol: mreg control | ||
3238 | * @ucontrol: control element information | ||
3239 | * | ||
3240 | * Callback to set the value of a control that can span | ||
3241 | * multiple codec registers which together forms a single | ||
3242 | * signed value in a MSB/LSB manner. The control supports | ||
3243 | * specifying total no of bits used to allow for bitfields | ||
3244 | * across the multiple codec registers. | ||
3245 | * | ||
3246 | * Returns 0 for success. | ||
3247 | */ | ||
3248 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
3249 | struct snd_ctl_elem_value *ucontrol) | ||
3250 | { | ||
3251 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3252 | struct soc_mreg_control *mc = | ||
3253 | (struct soc_mreg_control *)kcontrol->private_value; | ||
3254 | unsigned int regbase = mc->regbase; | ||
3255 | unsigned int regcount = mc->regcount; | ||
3256 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
3257 | unsigned int regwmask = (1<<regwshift)-1; | ||
3258 | unsigned int invert = mc->invert; | ||
3259 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
3260 | long max = mc->max; | ||
3261 | long val = ucontrol->value.integer.value[0]; | ||
3262 | unsigned int i, regval, regmask; | ||
3263 | int err; | ||
3264 | |||
3265 | if (invert) | ||
3266 | val = max - val; | ||
3267 | val &= mask; | ||
3268 | for (i = 0; i < regcount; i++) { | ||
3269 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
3270 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
3271 | err = snd_soc_component_update_bits(component, regbase+i, | ||
3272 | regmask, regval); | ||
3273 | if (err < 0) | ||
3274 | return err; | ||
3275 | } | ||
3276 | |||
3277 | return 0; | ||
3278 | } | ||
3279 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
3280 | |||
3281 | /** | ||
3282 | * snd_soc_get_strobe - strobe get callback | ||
3283 | * @kcontrol: mixer control | ||
3284 | * @ucontrol: control element information | ||
3285 | * | ||
3286 | * Callback get the value of a strobe mixer control. | ||
3287 | * | ||
3288 | * Returns 0 for success. | ||
3289 | */ | ||
3290 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
3291 | struct snd_ctl_elem_value *ucontrol) | ||
3292 | { | ||
3293 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3294 | struct soc_mixer_control *mc = | ||
3295 | (struct soc_mixer_control *)kcontrol->private_value; | ||
3296 | unsigned int reg = mc->reg; | ||
3297 | unsigned int shift = mc->shift; | ||
3298 | unsigned int mask = 1 << shift; | ||
3299 | unsigned int invert = mc->invert != 0; | ||
3300 | unsigned int val; | ||
3301 | int ret; | ||
3302 | |||
3303 | ret = snd_soc_component_read(component, reg, &val); | ||
3304 | if (ret) | ||
3305 | return ret; | ||
3306 | |||
3307 | val &= mask; | ||
3308 | |||
3309 | if (shift != 0 && val != 0) | ||
3310 | val = val >> shift; | ||
3311 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
3312 | |||
3313 | return 0; | ||
3314 | } | ||
3315 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
3316 | |||
3317 | /** | ||
3318 | * snd_soc_put_strobe - strobe put callback | ||
3319 | * @kcontrol: mixer control | ||
3320 | * @ucontrol: control element information | ||
3321 | * | ||
3322 | * Callback strobe a register bit to high then low (or the inverse) | ||
3323 | * in one pass of a single mixer enum control. | ||
3324 | * | ||
3325 | * Returns 1 for success. | ||
3326 | */ | ||
3327 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
3328 | struct snd_ctl_elem_value *ucontrol) | ||
3329 | { | ||
3330 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
3331 | struct soc_mixer_control *mc = | ||
3332 | (struct soc_mixer_control *)kcontrol->private_value; | ||
3333 | unsigned int reg = mc->reg; | ||
3334 | unsigned int shift = mc->shift; | ||
3335 | unsigned int mask = 1 << shift; | ||
3336 | unsigned int invert = mc->invert != 0; | ||
3337 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
3338 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
3339 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
3340 | int err; | ||
3341 | |||
3342 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
3343 | if (err < 0) | ||
3344 | return err; | ||
3345 | |||
3346 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
3347 | } | ||
3348 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
3349 | |||
3350 | /** | ||
3351 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. | 1958 | * snd_soc_dai_set_sysclk - configure DAI system or master clock. |
3352 | * @dai: DAI | 1959 | * @dai: DAI |
3353 | * @clk_id: DAI specific clock ID | 1960 | * @clk_id: DAI specific clock ID |
@@ -3996,22 +2603,62 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, | |||
3996 | return 0; | 2603 | return 0; |
3997 | } | 2604 | } |
3998 | 2605 | ||
3999 | static void snd_soc_component_init_regmap(struct snd_soc_component *component) | 2606 | static void snd_soc_component_setup_regmap(struct snd_soc_component *component) |
4000 | { | 2607 | { |
4001 | if (!component->regmap) | 2608 | int val_bytes = regmap_get_val_bytes(component->regmap); |
4002 | component->regmap = dev_get_regmap(component->dev, NULL); | 2609 | |
4003 | if (component->regmap) { | 2610 | /* Errors are legitimate for non-integer byte multiples */ |
4004 | int val_bytes = regmap_get_val_bytes(component->regmap); | 2611 | if (val_bytes > 0) |
4005 | /* Errors are legitimate for non-integer byte multiples */ | 2612 | component->val_bytes = val_bytes; |
4006 | if (val_bytes > 0) | 2613 | } |
4007 | component->val_bytes = val_bytes; | 2614 | |
4008 | } | 2615 | #ifdef CONFIG_REGMAP |
2616 | |||
2617 | /** | ||
2618 | * snd_soc_component_init_regmap() - Initialize regmap instance for the component | ||
2619 | * @component: The component for which to initialize the regmap instance | ||
2620 | * @regmap: The regmap instance that should be used by the component | ||
2621 | * | ||
2622 | * This function allows deferred assignment of the regmap instance that is | ||
2623 | * associated with the component. Only use this if the regmap instance is not | ||
2624 | * yet ready when the component is registered. The function must also be called | ||
2625 | * before the first IO attempt of the component. | ||
2626 | */ | ||
2627 | void snd_soc_component_init_regmap(struct snd_soc_component *component, | ||
2628 | struct regmap *regmap) | ||
2629 | { | ||
2630 | component->regmap = regmap; | ||
2631 | snd_soc_component_setup_regmap(component); | ||
2632 | } | ||
2633 | EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); | ||
2634 | |||
2635 | /** | ||
2636 | * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component | ||
2637 | * @component: The component for which to de-initialize the regmap instance | ||
2638 | * | ||
2639 | * Calls regmap_exit() on the regmap instance associated to the component and | ||
2640 | * removes the regmap instance from the component. | ||
2641 | * | ||
2642 | * This function should only be used if snd_soc_component_init_regmap() was used | ||
2643 | * to initialize the regmap instance. | ||
2644 | */ | ||
2645 | void snd_soc_component_exit_regmap(struct snd_soc_component *component) | ||
2646 | { | ||
2647 | regmap_exit(component->regmap); | ||
2648 | component->regmap = NULL; | ||
4009 | } | 2649 | } |
2650 | EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); | ||
2651 | |||
2652 | #endif | ||
4010 | 2653 | ||
4011 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) | 2654 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) |
4012 | { | 2655 | { |
4013 | if (!component->write && !component->read) | 2656 | if (!component->write && !component->read) { |
4014 | snd_soc_component_init_regmap(component); | 2657 | if (!component->regmap) |
2658 | component->regmap = dev_get_regmap(component->dev, NULL); | ||
2659 | if (component->regmap) | ||
2660 | snd_soc_component_setup_regmap(component); | ||
2661 | } | ||
4015 | 2662 | ||
4016 | list_add(&component->list, &component_list); | 2663 | list_add(&component->list, &component_list); |
4017 | } | 2664 | } |
@@ -4362,7 +3009,6 @@ int snd_soc_register_codec(struct device *dev, | |||
4362 | codec->dev = dev; | 3009 | codec->dev = dev; |
4363 | codec->driver = codec_drv; | 3010 | codec->driver = codec_drv; |
4364 | codec->component.val_bytes = codec_drv->reg_word_size; | 3011 | codec->component.val_bytes = codec_drv->reg_word_size; |
4365 | mutex_init(&codec->mutex); | ||
4366 | 3012 | ||
4367 | #ifdef CONFIG_DEBUG_FS | 3013 | #ifdef CONFIG_DEBUG_FS |
4368 | codec->component.init_debugfs = soc_init_codec_debugfs; | 3014 | codec->component.init_debugfs = soc_init_codec_debugfs; |
@@ -4585,7 +3231,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4585 | const char *propname) | 3231 | const char *propname) |
4586 | { | 3232 | { |
4587 | struct device_node *np = card->dev->of_node; | 3233 | struct device_node *np = card->dev->of_node; |
4588 | int num_routes; | 3234 | int num_routes, old_routes; |
4589 | struct snd_soc_dapm_route *routes; | 3235 | struct snd_soc_dapm_route *routes; |
4590 | int i, ret; | 3236 | int i, ret; |
4591 | 3237 | ||
@@ -4603,7 +3249,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4603 | return -EINVAL; | 3249 | return -EINVAL; |
4604 | } | 3250 | } |
4605 | 3251 | ||
4606 | routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes), | 3252 | old_routes = card->num_dapm_routes; |
3253 | routes = devm_kzalloc(card->dev, | ||
3254 | (old_routes + num_routes) * sizeof(*routes), | ||
4607 | GFP_KERNEL); | 3255 | GFP_KERNEL); |
4608 | if (!routes) { | 3256 | if (!routes) { |
4609 | dev_err(card->dev, | 3257 | dev_err(card->dev, |
@@ -4611,9 +3259,11 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4611 | return -EINVAL; | 3259 | return -EINVAL; |
4612 | } | 3260 | } |
4613 | 3261 | ||
3262 | memcpy(routes, card->dapm_routes, old_routes * sizeof(*routes)); | ||
3263 | |||
4614 | for (i = 0; i < num_routes; i++) { | 3264 | for (i = 0; i < num_routes; i++) { |
4615 | ret = of_property_read_string_index(np, propname, | 3265 | ret = of_property_read_string_index(np, propname, |
4616 | 2 * i, &routes[i].sink); | 3266 | 2 * i, &routes[old_routes + i].sink); |
4617 | if (ret) { | 3267 | if (ret) { |
4618 | dev_err(card->dev, | 3268 | dev_err(card->dev, |
4619 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3269 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4621,7 +3271,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4621 | return -EINVAL; | 3271 | return -EINVAL; |
4622 | } | 3272 | } |
4623 | ret = of_property_read_string_index(np, propname, | 3273 | ret = of_property_read_string_index(np, propname, |
4624 | (2 * i) + 1, &routes[i].source); | 3274 | (2 * i) + 1, &routes[old_routes + i].source); |
4625 | if (ret) { | 3275 | if (ret) { |
4626 | dev_err(card->dev, | 3276 | dev_err(card->dev, |
4627 | "ASoC: Property '%s' index %d could not be read: %d\n", | 3277 | "ASoC: Property '%s' index %d could not be read: %d\n", |
@@ -4630,7 +3280,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
4630 | } | 3280 | } |
4631 | } | 3281 | } |
4632 | 3282 | ||
4633 | card->num_dapm_routes = num_routes; | 3283 | card->num_dapm_routes += num_routes; |
4634 | card->dapm_routes = routes; | 3284 | card->dapm_routes = routes; |
4635 | 3285 | ||
4636 | return 0; | 3286 | return 0; |
@@ -4750,36 +3400,30 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
4750 | } | 3400 | } |
4751 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | 3401 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); |
4752 | 3402 | ||
4753 | int snd_soc_of_get_dai_name(struct device_node *of_node, | 3403 | static int snd_soc_get_dai_name(struct of_phandle_args *args, |
4754 | const char **dai_name) | 3404 | const char **dai_name) |
4755 | { | 3405 | { |
4756 | struct snd_soc_component *pos; | 3406 | struct snd_soc_component *pos; |
4757 | struct of_phandle_args args; | 3407 | int ret = -EPROBE_DEFER; |
4758 | int ret; | ||
4759 | |||
4760 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | ||
4761 | "#sound-dai-cells", 0, &args); | ||
4762 | if (ret) | ||
4763 | return ret; | ||
4764 | |||
4765 | ret = -EPROBE_DEFER; | ||
4766 | 3408 | ||
4767 | mutex_lock(&client_mutex); | 3409 | mutex_lock(&client_mutex); |
4768 | list_for_each_entry(pos, &component_list, list) { | 3410 | list_for_each_entry(pos, &component_list, list) { |
4769 | if (pos->dev->of_node != args.np) | 3411 | if (pos->dev->of_node != args->np) |
4770 | continue; | 3412 | continue; |
4771 | 3413 | ||
4772 | if (pos->driver->of_xlate_dai_name) { | 3414 | if (pos->driver->of_xlate_dai_name) { |
4773 | ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); | 3415 | ret = pos->driver->of_xlate_dai_name(pos, |
3416 | args, | ||
3417 | dai_name); | ||
4774 | } else { | 3418 | } else { |
4775 | int id = -1; | 3419 | int id = -1; |
4776 | 3420 | ||
4777 | switch (args.args_count) { | 3421 | switch (args->args_count) { |
4778 | case 0: | 3422 | case 0: |
4779 | id = 0; /* same as dai_drv[0] */ | 3423 | id = 0; /* same as dai_drv[0] */ |
4780 | break; | 3424 | break; |
4781 | case 1: | 3425 | case 1: |
4782 | id = args.args[0]; | 3426 | id = args->args[0]; |
4783 | break; | 3427 | break; |
4784 | default: | 3428 | default: |
4785 | /* not supported */ | 3429 | /* not supported */ |
@@ -4801,6 +3445,21 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, | |||
4801 | break; | 3445 | break; |
4802 | } | 3446 | } |
4803 | mutex_unlock(&client_mutex); | 3447 | mutex_unlock(&client_mutex); |
3448 | return ret; | ||
3449 | } | ||
3450 | |||
3451 | int snd_soc_of_get_dai_name(struct device_node *of_node, | ||
3452 | const char **dai_name) | ||
3453 | { | ||
3454 | struct of_phandle_args args; | ||
3455 | int ret; | ||
3456 | |||
3457 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | ||
3458 | "#sound-dai-cells", 0, &args); | ||
3459 | if (ret) | ||
3460 | return ret; | ||
3461 | |||
3462 | ret = snd_soc_get_dai_name(&args, dai_name); | ||
4804 | 3463 | ||
4805 | of_node_put(args.np); | 3464 | of_node_put(args.np); |
4806 | 3465 | ||
@@ -4808,6 +3467,77 @@ int snd_soc_of_get_dai_name(struct device_node *of_node, | |||
4808 | } | 3467 | } |
4809 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); | 3468 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); |
4810 | 3469 | ||
3470 | /* | ||
3471 | * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree | ||
3472 | * @dev: Card device | ||
3473 | * @of_node: Device node | ||
3474 | * @dai_link: DAI link | ||
3475 | * | ||
3476 | * Builds an array of CODEC DAI components from the DAI link property | ||
3477 | * 'sound-dai'. | ||
3478 | * The array is set in the DAI link and the number of DAIs is set accordingly. | ||
3479 | * The device nodes in the array (of_node) must be dereferenced by the caller. | ||
3480 | * | ||
3481 | * Returns 0 for success | ||
3482 | */ | ||
3483 | int snd_soc_of_get_dai_link_codecs(struct device *dev, | ||
3484 | struct device_node *of_node, | ||
3485 | struct snd_soc_dai_link *dai_link) | ||
3486 | { | ||
3487 | struct of_phandle_args args; | ||
3488 | struct snd_soc_dai_link_component *component; | ||
3489 | char *name; | ||
3490 | int index, num_codecs, ret; | ||
3491 | |||
3492 | /* Count the number of CODECs */ | ||
3493 | name = "sound-dai"; | ||
3494 | num_codecs = of_count_phandle_with_args(of_node, name, | ||
3495 | "#sound-dai-cells"); | ||
3496 | if (num_codecs <= 0) { | ||
3497 | if (num_codecs == -ENOENT) | ||
3498 | dev_err(dev, "No 'sound-dai' property\n"); | ||
3499 | else | ||
3500 | dev_err(dev, "Bad phandle in 'sound-dai'\n"); | ||
3501 | return num_codecs; | ||
3502 | } | ||
3503 | component = devm_kzalloc(dev, | ||
3504 | sizeof *component * num_codecs, | ||
3505 | GFP_KERNEL); | ||
3506 | if (!component) | ||
3507 | return -ENOMEM; | ||
3508 | dai_link->codecs = component; | ||
3509 | dai_link->num_codecs = num_codecs; | ||
3510 | |||
3511 | /* Parse the list */ | ||
3512 | for (index = 0, component = dai_link->codecs; | ||
3513 | index < dai_link->num_codecs; | ||
3514 | index++, component++) { | ||
3515 | ret = of_parse_phandle_with_args(of_node, name, | ||
3516 | "#sound-dai-cells", | ||
3517 | index, &args); | ||
3518 | if (ret) | ||
3519 | goto err; | ||
3520 | component->of_node = args.np; | ||
3521 | ret = snd_soc_get_dai_name(&args, &component->dai_name); | ||
3522 | if (ret < 0) | ||
3523 | goto err; | ||
3524 | } | ||
3525 | return 0; | ||
3526 | err: | ||
3527 | for (index = 0, component = dai_link->codecs; | ||
3528 | index < dai_link->num_codecs; | ||
3529 | index++, component++) { | ||
3530 | if (!component->of_node) | ||
3531 | break; | ||
3532 | of_node_put(component->of_node); | ||
3533 | component->of_node = NULL; | ||
3534 | } | ||
3535 | dai_link->codecs = NULL; | ||
3536 | dai_link->num_codecs = 0; | ||
3537 | return ret; | ||
3538 | } | ||
3539 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs); | ||
3540 | |||
4811 | static int __init snd_soc_init(void) | 3541 | static int __init snd_soc_init(void) |
4812 | { | 3542 | { |
4813 | #ifdef CONFIG_DEBUG_FS | 3543 | #ifdef CONFIG_DEBUG_FS |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c61cb9cedbcd..c5136bb1f982 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | |||
159 | } | 159 | } |
160 | } | 160 | } |
161 | 161 | ||
162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | /* |
163 | * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input | ||
164 | * paths | ||
165 | * @w: The widget for which to invalidate the cached number of input paths | ||
166 | * | ||
167 | * The function resets the cached number of inputs for the specified widget and | ||
168 | * all widgets that can be reached via outgoing paths from the widget. | ||
169 | * | ||
170 | * This function must be called if the number of input paths for a widget might | ||
171 | * have changed. E.g. if the source state of a widget changes or a path is added | ||
172 | * or activated with the widget as the sink. | ||
173 | */ | ||
174 | static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w) | ||
175 | { | ||
176 | struct snd_soc_dapm_widget *sink; | ||
177 | struct snd_soc_dapm_path *p; | ||
178 | LIST_HEAD(list); | ||
179 | |||
180 | dapm_assert_locked(w->dapm); | ||
181 | |||
182 | if (w->inputs == -1) | ||
183 | return; | ||
184 | |||
185 | w->inputs = -1; | ||
186 | list_add_tail(&w->work_list, &list); | ||
187 | |||
188 | list_for_each_entry(w, &list, work_list) { | ||
189 | list_for_each_entry(p, &w->sinks, list_source) { | ||
190 | if (p->is_supply || p->weak || !p->connect) | ||
191 | continue; | ||
192 | sink = p->sink; | ||
193 | if (sink->inputs != -1) { | ||
194 | sink->inputs = -1; | ||
195 | list_add_tail(&sink->work_list, &list); | ||
196 | } | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * dapm_widget_invalidate_output_paths() - Invalidate the cached number of | ||
203 | * output paths | ||
204 | * @w: The widget for which to invalidate the cached number of output paths | ||
205 | * | ||
206 | * Resets the cached number of outputs for the specified widget and all widgets | ||
207 | * that can be reached via incoming paths from the widget. | ||
208 | * | ||
209 | * This function must be called if the number of output paths for a widget might | ||
210 | * have changed. E.g. if the sink state of a widget changes or a path is added | ||
211 | * or activated with the widget as the source. | ||
212 | */ | ||
213 | static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w) | ||
214 | { | ||
215 | struct snd_soc_dapm_widget *source; | ||
216 | struct snd_soc_dapm_path *p; | ||
217 | LIST_HEAD(list); | ||
218 | |||
219 | dapm_assert_locked(w->dapm); | ||
220 | |||
221 | if (w->outputs == -1) | ||
222 | return; | ||
223 | |||
224 | w->outputs = -1; | ||
225 | list_add_tail(&w->work_list, &list); | ||
226 | |||
227 | list_for_each_entry(w, &list, work_list) { | ||
228 | list_for_each_entry(p, &w->sources, list_sink) { | ||
229 | if (p->is_supply || p->weak || !p->connect) | ||
230 | continue; | ||
231 | source = p->source; | ||
232 | if (source->outputs != -1) { | ||
233 | source->outputs = -1; | ||
234 | list_add_tail(&source->work_list, &list); | ||
235 | } | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs | ||
242 | * for the widgets connected to a path | ||
243 | * @p: The path to invalidate | ||
244 | * | ||
245 | * Resets the cached number of inputs for the sink of the path and the cached | ||
246 | * number of outputs for the source of the path. | ||
247 | * | ||
248 | * This function must be called when a path is added, removed or the connected | ||
249 | * state changes. | ||
250 | */ | ||
251 | static void dapm_path_invalidate(struct snd_soc_dapm_path *p) | ||
252 | { | ||
253 | /* | ||
254 | * Weak paths or supply paths do not influence the number of input or | ||
255 | * output paths of their neighbors. | ||
256 | */ | ||
257 | if (p->weak || p->is_supply) | ||
258 | return; | ||
259 | |||
260 | /* | ||
261 | * The number of connected endpoints is the sum of the number of | ||
262 | * connected endpoints of all neighbors. If a node with 0 connected | ||
263 | * endpoints is either connected or disconnected that sum won't change, | ||
264 | * so there is no need to re-check the path. | ||
265 | */ | ||
266 | if (p->source->inputs != 0) | ||
267 | dapm_widget_invalidate_input_paths(p->sink); | ||
268 | if (p->sink->outputs != 0) | ||
269 | dapm_widget_invalidate_output_paths(p->source); | ||
270 | } | ||
271 | |||
272 | void dapm_mark_endpoints_dirty(struct snd_soc_card *card) | ||
163 | { | 273 | { |
164 | struct snd_soc_card *card = dapm->card; | ||
165 | struct snd_soc_dapm_widget *w; | 274 | struct snd_soc_dapm_widget *w; |
166 | 275 | ||
167 | mutex_lock(&card->dapm_mutex); | 276 | mutex_lock(&card->dapm_mutex); |
168 | 277 | ||
169 | list_for_each_entry(w, &card->widgets, list) { | 278 | list_for_each_entry(w, &card->widgets, list) { |
170 | switch (w->id) { | 279 | if (w->is_sink || w->is_source) { |
171 | case snd_soc_dapm_input: | 280 | dapm_mark_dirty(w, "Rechecking endpoints"); |
172 | case snd_soc_dapm_output: | 281 | if (w->is_sink) |
173 | dapm_mark_dirty(w, "Rechecking inputs and outputs"); | 282 | dapm_widget_invalidate_output_paths(w); |
174 | break; | 283 | if (w->is_source) |
175 | default: | 284 | dapm_widget_invalidate_input_paths(w); |
176 | break; | ||
177 | } | 285 | } |
178 | } | 286 | } |
179 | 287 | ||
180 | mutex_unlock(&card->dapm_mutex); | 288 | mutex_unlock(&card->dapm_mutex); |
181 | } | 289 | } |
182 | EXPORT_SYMBOL_GPL(dapm_mark_io_dirty); | 290 | EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); |
183 | 291 | ||
184 | /* create a new dapm widget */ | 292 | /* create a new dapm widget */ |
185 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | 293 | static inline struct snd_soc_dapm_widget *dapm_cnew_widget( |
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card) | |||
386 | list_for_each_entry(w, &card->widgets, list) { | 494 | list_for_each_entry(w, &card->widgets, list) { |
387 | w->new_power = w->power; | 495 | w->new_power = w->power; |
388 | w->power_checked = false; | 496 | w->power_checked = false; |
389 | w->inputs = -1; | ||
390 | w->outputs = -1; | ||
391 | } | 497 | } |
392 | } | 498 | } |
393 | 499 | ||
@@ -469,10 +575,9 @@ out: | |||
469 | 575 | ||
470 | /* connect mux widget to its interconnecting audio paths */ | 576 | /* connect mux widget to its interconnecting audio paths */ |
471 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | 577 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
472 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 578 | struct snd_soc_dapm_path *path, const char *control_name) |
473 | struct snd_soc_dapm_path *path, const char *control_name, | ||
474 | const struct snd_kcontrol_new *kcontrol) | ||
475 | { | 579 | { |
580 | const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0]; | ||
476 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 581 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
477 | unsigned int val, item; | 582 | unsigned int val, item; |
478 | int i; | 583 | int i; |
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
493 | 598 | ||
494 | for (i = 0; i < e->items; i++) { | 599 | for (i = 0; i < e->items; i++) { |
495 | if (!(strcmp(control_name, e->texts[i]))) { | 600 | if (!(strcmp(control_name, e->texts[i]))) { |
496 | list_add(&path->list, &dapm->card->paths); | 601 | path->name = e->texts[i]; |
497 | list_add(&path->list_sink, &dest->sources); | ||
498 | list_add(&path->list_source, &src->sinks); | ||
499 | path->name = (char*)e->texts[i]; | ||
500 | if (i == item) | 602 | if (i == item) |
501 | path->connect = 1; | 603 | path->connect = 1; |
502 | else | 604 | else |
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
509 | } | 611 | } |
510 | 612 | ||
511 | /* set up initial codec paths */ | 613 | /* set up initial codec paths */ |
512 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | 614 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i) |
513 | struct snd_soc_dapm_path *p, int i) | ||
514 | { | 615 | { |
515 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | 616 | struct soc_mixer_control *mc = (struct soc_mixer_control *) |
516 | w->kcontrol_news[i].private_value; | 617 | p->sink->kcontrol_news[i].private_value; |
517 | unsigned int reg = mc->reg; | 618 | unsigned int reg = mc->reg; |
518 | unsigned int shift = mc->shift; | 619 | unsigned int shift = mc->shift; |
519 | unsigned int max = mc->max; | 620 | unsigned int max = mc->max; |
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
522 | unsigned int val; | 623 | unsigned int val; |
523 | 624 | ||
524 | if (reg != SND_SOC_NOPM) { | 625 | if (reg != SND_SOC_NOPM) { |
525 | soc_dapm_read(w->dapm, reg, &val); | 626 | soc_dapm_read(p->sink->dapm, reg, &val); |
526 | val = (val >> shift) & mask; | 627 | val = (val >> shift) & mask; |
527 | if (invert) | 628 | if (invert) |
528 | val = max - val; | 629 | val = max - val; |
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | |||
534 | 635 | ||
535 | /* connect mixer widget to its interconnecting audio paths */ | 636 | /* connect mixer widget to its interconnecting audio paths */ |
536 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 637 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
537 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
538 | struct snd_soc_dapm_path *path, const char *control_name) | 638 | struct snd_soc_dapm_path *path, const char *control_name) |
539 | { | 639 | { |
540 | int i; | 640 | int i; |
541 | 641 | ||
542 | /* search for mixer kcontrol */ | 642 | /* search for mixer kcontrol */ |
543 | for (i = 0; i < dest->num_kcontrols; i++) { | 643 | for (i = 0; i < path->sink->num_kcontrols; i++) { |
544 | if (!strcmp(control_name, dest->kcontrol_news[i].name)) { | 644 | if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) { |
545 | list_add(&path->list, &dapm->card->paths); | 645 | path->name = path->sink->kcontrol_news[i].name; |
546 | list_add(&path->list_sink, &dest->sources); | 646 | dapm_set_mixer_path_status(path, i); |
547 | list_add(&path->list_source, &src->sinks); | ||
548 | path->name = dest->kcontrol_news[i].name; | ||
549 | dapm_set_mixer_path_status(dest, path, i); | ||
550 | return 0; | 647 | return 0; |
551 | } | 648 | } |
552 | } | 649 | } |
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w) | |||
738 | if (ret < 0) | 835 | if (ret < 0) |
739 | return ret; | 836 | return ret; |
740 | 837 | ||
741 | list_for_each_entry(path, &w->sources, list_sink) | 838 | list_for_each_entry(path, &w->sources, list_sink) { |
742 | dapm_kcontrol_add_path(w->kcontrols[0], path); | 839 | if (path->name) |
840 | dapm_kcontrol_add_path(w->kcontrols[0], path); | ||
841 | } | ||
743 | 842 | ||
744 | return 0; | 843 | return 0; |
745 | } | 844 | } |
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w) | |||
754 | return 0; | 853 | return 0; |
755 | } | 854 | } |
756 | 855 | ||
757 | /* reset 'walked' bit for each dapm path */ | ||
758 | static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm, | ||
759 | struct list_head *sink) | ||
760 | { | ||
761 | struct snd_soc_dapm_path *p; | ||
762 | |||
763 | list_for_each_entry(p, sink, list_source) { | ||
764 | if (p->walked) { | ||
765 | p->walked = 0; | ||
766 | dapm_clear_walk_output(dapm, &p->sink->sinks); | ||
767 | } | ||
768 | } | ||
769 | } | ||
770 | |||
771 | static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm, | ||
772 | struct list_head *source) | ||
773 | { | ||
774 | struct snd_soc_dapm_path *p; | ||
775 | |||
776 | list_for_each_entry(p, source, list_sink) { | ||
777 | if (p->walked) { | ||
778 | p->walked = 0; | ||
779 | dapm_clear_walk_input(dapm, &p->source->sources); | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | |||
784 | |||
785 | /* We implement power down on suspend by checking the power state of | 856 | /* We implement power down on suspend by checking the power state of |
786 | * the ALSA card - when we are suspending the ALSA state for the card | 857 | * the ALSA card - when we are suspending the ALSA state for the card |
787 | * is set to D3. | 858 | * is set to D3. |
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
856 | 927 | ||
857 | DAPM_UPDATE_STAT(widget, path_checks); | 928 | DAPM_UPDATE_STAT(widget, path_checks); |
858 | 929 | ||
859 | switch (widget->id) { | 930 | if (widget->is_sink && widget->connected) { |
860 | case snd_soc_dapm_supply: | 931 | widget->outputs = snd_soc_dapm_suspend_check(widget); |
861 | case snd_soc_dapm_regulator_supply: | 932 | return widget->outputs; |
862 | case snd_soc_dapm_clock_supply: | ||
863 | case snd_soc_dapm_kcontrol: | ||
864 | return 0; | ||
865 | default: | ||
866 | break; | ||
867 | } | ||
868 | |||
869 | switch (widget->id) { | ||
870 | case snd_soc_dapm_adc: | ||
871 | case snd_soc_dapm_aif_out: | ||
872 | case snd_soc_dapm_dai_out: | ||
873 | if (widget->active) { | ||
874 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
875 | return widget->outputs; | ||
876 | } | ||
877 | default: | ||
878 | break; | ||
879 | } | ||
880 | |||
881 | if (widget->connected) { | ||
882 | /* connected pin ? */ | ||
883 | if (widget->id == snd_soc_dapm_output && !widget->ext) { | ||
884 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
885 | return widget->outputs; | ||
886 | } | ||
887 | |||
888 | /* connected jack or spk ? */ | ||
889 | if (widget->id == snd_soc_dapm_hp || | ||
890 | widget->id == snd_soc_dapm_spk || | ||
891 | (widget->id == snd_soc_dapm_line && | ||
892 | !list_empty(&widget->sources))) { | ||
893 | widget->outputs = snd_soc_dapm_suspend_check(widget); | ||
894 | return widget->outputs; | ||
895 | } | ||
896 | } | 933 | } |
897 | 934 | ||
898 | list_for_each_entry(path, &widget->sinks, list_source) { | 935 | list_for_each_entry(path, &widget->sinks, list_source) { |
899 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 936 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
900 | 937 | ||
901 | if (path->weak) | 938 | if (path->weak || path->is_supply) |
902 | continue; | 939 | continue; |
903 | 940 | ||
904 | if (path->walking) | 941 | if (path->walking) |
905 | return 1; | 942 | return 1; |
906 | 943 | ||
907 | if (path->walked) | ||
908 | continue; | ||
909 | |||
910 | trace_snd_soc_dapm_output_path(widget, path); | 944 | trace_snd_soc_dapm_output_path(widget, path); |
911 | 945 | ||
912 | if (path->sink && path->connect) { | 946 | if (path->connect) { |
913 | path->walked = 1; | ||
914 | path->walking = 1; | 947 | path->walking = 1; |
915 | 948 | ||
916 | /* do we need to add this widget to the list ? */ | 949 | /* do we need to add this widget to the list ? */ |
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
952 | 985 | ||
953 | DAPM_UPDATE_STAT(widget, path_checks); | 986 | DAPM_UPDATE_STAT(widget, path_checks); |
954 | 987 | ||
955 | switch (widget->id) { | 988 | if (widget->is_source && widget->connected) { |
956 | case snd_soc_dapm_supply: | 989 | widget->inputs = snd_soc_dapm_suspend_check(widget); |
957 | case snd_soc_dapm_regulator_supply: | 990 | return widget->inputs; |
958 | case snd_soc_dapm_clock_supply: | ||
959 | case snd_soc_dapm_kcontrol: | ||
960 | return 0; | ||
961 | default: | ||
962 | break; | ||
963 | } | ||
964 | |||
965 | /* active stream ? */ | ||
966 | switch (widget->id) { | ||
967 | case snd_soc_dapm_dac: | ||
968 | case snd_soc_dapm_aif_in: | ||
969 | case snd_soc_dapm_dai_in: | ||
970 | if (widget->active) { | ||
971 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
972 | return widget->inputs; | ||
973 | } | ||
974 | default: | ||
975 | break; | ||
976 | } | ||
977 | |||
978 | if (widget->connected) { | ||
979 | /* connected pin ? */ | ||
980 | if (widget->id == snd_soc_dapm_input && !widget->ext) { | ||
981 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
982 | return widget->inputs; | ||
983 | } | ||
984 | |||
985 | /* connected VMID/Bias for lower pops */ | ||
986 | if (widget->id == snd_soc_dapm_vmid) { | ||
987 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
988 | return widget->inputs; | ||
989 | } | ||
990 | |||
991 | /* connected jack ? */ | ||
992 | if (widget->id == snd_soc_dapm_mic || | ||
993 | (widget->id == snd_soc_dapm_line && | ||
994 | !list_empty(&widget->sinks))) { | ||
995 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
996 | return widget->inputs; | ||
997 | } | ||
998 | |||
999 | /* signal generator */ | ||
1000 | if (widget->id == snd_soc_dapm_siggen) { | ||
1001 | widget->inputs = snd_soc_dapm_suspend_check(widget); | ||
1002 | return widget->inputs; | ||
1003 | } | ||
1004 | } | 991 | } |
1005 | 992 | ||
1006 | list_for_each_entry(path, &widget->sources, list_sink) { | 993 | list_for_each_entry(path, &widget->sources, list_sink) { |
1007 | DAPM_UPDATE_STAT(widget, neighbour_checks); | 994 | DAPM_UPDATE_STAT(widget, neighbour_checks); |
1008 | 995 | ||
1009 | if (path->weak) | 996 | if (path->weak || path->is_supply) |
1010 | continue; | 997 | continue; |
1011 | 998 | ||
1012 | if (path->walking) | 999 | if (path->walking) |
1013 | return 1; | 1000 | return 1; |
1014 | 1001 | ||
1015 | if (path->walked) | ||
1016 | continue; | ||
1017 | |||
1018 | trace_snd_soc_dapm_input_path(widget, path); | 1002 | trace_snd_soc_dapm_input_path(widget, path); |
1019 | 1003 | ||
1020 | if (path->source && path->connect) { | 1004 | if (path->connect) { |
1021 | path->walked = 1; | ||
1022 | path->walking = 1; | 1005 | path->walking = 1; |
1023 | 1006 | ||
1024 | /* do we need to add this widget to the list ? */ | 1007 | /* do we need to add this widget to the list ? */ |
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
1060 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 1043 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
1061 | struct snd_soc_dapm_widget_list **list) | 1044 | struct snd_soc_dapm_widget_list **list) |
1062 | { | 1045 | { |
1063 | struct snd_soc_card *card = dai->card; | 1046 | struct snd_soc_card *card = dai->component->card; |
1047 | struct snd_soc_dapm_widget *w; | ||
1064 | int paths; | 1048 | int paths; |
1065 | 1049 | ||
1066 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 1050 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
1067 | dapm_reset(card); | ||
1068 | 1051 | ||
1069 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 1052 | /* |
1053 | * For is_connected_{output,input}_ep fully discover the graph we need | ||
1054 | * to reset the cached number of inputs and outputs. | ||
1055 | */ | ||
1056 | list_for_each_entry(w, &card->widgets, list) { | ||
1057 | w->inputs = -1; | ||
1058 | w->outputs = -1; | ||
1059 | } | ||
1060 | |||
1061 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1070 | paths = is_connected_output_ep(dai->playback_widget, list); | 1062 | paths = is_connected_output_ep(dai->playback_widget, list); |
1071 | dapm_clear_walk_output(&card->dapm, | 1063 | else |
1072 | &dai->playback_widget->sinks); | ||
1073 | } else { | ||
1074 | paths = is_connected_input_ep(dai->capture_widget, list); | 1064 | paths = is_connected_input_ep(dai->capture_widget, list); |
1075 | dapm_clear_walk_input(&card->dapm, | ||
1076 | &dai->capture_widget->sources); | ||
1077 | } | ||
1078 | 1065 | ||
1079 | trace_snd_soc_dapm_connected(paths, stream); | 1066 | trace_snd_soc_dapm_connected(paths, stream); |
1080 | mutex_unlock(&card->dapm_mutex); | 1067 | mutex_unlock(&card->dapm_mutex); |
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
1163 | DAPM_UPDATE_STAT(w, power_checks); | 1150 | DAPM_UPDATE_STAT(w, power_checks); |
1164 | 1151 | ||
1165 | in = is_connected_input_ep(w, NULL); | 1152 | in = is_connected_input_ep(w, NULL); |
1166 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1167 | out = is_connected_output_ep(w, NULL); | 1153 | out = is_connected_output_ep(w, NULL); |
1168 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1169 | return out != 0 && in != 0; | 1154 | return out != 0 && in != 0; |
1170 | } | 1155 | } |
1171 | 1156 | ||
1172 | /* Check to see if an ADC has power */ | ||
1173 | static int dapm_adc_check_power(struct snd_soc_dapm_widget *w) | ||
1174 | { | ||
1175 | int in; | ||
1176 | |||
1177 | DAPM_UPDATE_STAT(w, power_checks); | ||
1178 | |||
1179 | if (w->active) { | ||
1180 | in = is_connected_input_ep(w, NULL); | ||
1181 | dapm_clear_walk_input(w->dapm, &w->sources); | ||
1182 | return in != 0; | ||
1183 | } else { | ||
1184 | return dapm_generic_check_power(w); | ||
1185 | } | ||
1186 | } | ||
1187 | |||
1188 | /* Check to see if a DAC has power */ | ||
1189 | static int dapm_dac_check_power(struct snd_soc_dapm_widget *w) | ||
1190 | { | ||
1191 | int out; | ||
1192 | |||
1193 | DAPM_UPDATE_STAT(w, power_checks); | ||
1194 | |||
1195 | if (w->active) { | ||
1196 | out = is_connected_output_ep(w, NULL); | ||
1197 | dapm_clear_walk_output(w->dapm, &w->sinks); | ||
1198 | return out != 0; | ||
1199 | } else { | ||
1200 | return dapm_generic_check_power(w); | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | /* Check to see if a power supply is needed */ | 1157 | /* Check to see if a power supply is needed */ |
1205 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | 1158 | static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) |
1206 | { | 1159 | { |
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
1219 | !path->connected(path->source, path->sink)) | 1172 | !path->connected(path->source, path->sink)) |
1220 | continue; | 1173 | continue; |
1221 | 1174 | ||
1222 | if (!path->sink) | ||
1223 | continue; | ||
1224 | |||
1225 | if (dapm_widget_power_check(path->sink)) | 1175 | if (dapm_widget_power_check(path->sink)) |
1226 | return 1; | 1176 | return 1; |
1227 | } | 1177 | } |
@@ -1636,27 +1586,14 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1636 | /* If we changed our power state perhaps our neigbours changed | 1586 | /* If we changed our power state perhaps our neigbours changed |
1637 | * also. | 1587 | * also. |
1638 | */ | 1588 | */ |
1639 | list_for_each_entry(path, &w->sources, list_sink) { | 1589 | list_for_each_entry(path, &w->sources, list_sink) |
1640 | if (path->source) { | 1590 | dapm_widget_set_peer_power(path->source, power, path->connect); |
1641 | dapm_widget_set_peer_power(path->source, power, | 1591 | |
1592 | /* Supplies can't affect their outputs, only their inputs */ | ||
1593 | if (!w->is_supply) { | ||
1594 | list_for_each_entry(path, &w->sinks, list_source) | ||
1595 | dapm_widget_set_peer_power(path->sink, power, | ||
1642 | path->connect); | 1596 | path->connect); |
1643 | } | ||
1644 | } | ||
1645 | switch (w->id) { | ||
1646 | case snd_soc_dapm_supply: | ||
1647 | case snd_soc_dapm_regulator_supply: | ||
1648 | case snd_soc_dapm_clock_supply: | ||
1649 | case snd_soc_dapm_kcontrol: | ||
1650 | /* Supplies can't affect their outputs, only their inputs */ | ||
1651 | break; | ||
1652 | default: | ||
1653 | list_for_each_entry(path, &w->sinks, list_source) { | ||
1654 | if (path->sink) { | ||
1655 | dapm_widget_set_peer_power(path->sink, power, | ||
1656 | path->connect); | ||
1657 | } | ||
1658 | } | ||
1659 | break; | ||
1660 | } | 1597 | } |
1661 | 1598 | ||
1662 | if (power) | 1599 | if (power) |
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1863 | if (!buf) | 1800 | if (!buf) |
1864 | return -ENOMEM; | 1801 | return -ENOMEM; |
1865 | 1802 | ||
1866 | in = is_connected_input_ep(w, NULL); | 1803 | /* Supply widgets are not handled by is_connected_{input,output}_ep() */ |
1867 | dapm_clear_walk_input(w->dapm, &w->sources); | 1804 | if (w->is_supply) { |
1868 | out = is_connected_output_ep(w, NULL); | 1805 | in = 0; |
1869 | dapm_clear_walk_output(w->dapm, &w->sinks); | 1806 | out = 0; |
1807 | } else { | ||
1808 | in = is_connected_input_ep(w, NULL); | ||
1809 | out = is_connected_output_ep(w, NULL); | ||
1810 | } | ||
1870 | 1811 | ||
1871 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", | 1812 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
1872 | w->name, w->power ? "On" : "Off", | 1813 | w->name, w->power ? "On" : "Off", |
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm) | |||
2011 | 1952 | ||
2012 | #endif | 1953 | #endif |
2013 | 1954 | ||
1955 | /* | ||
1956 | * soc_dapm_connect_path() - Connects or disconnects a path | ||
1957 | * @path: The path to update | ||
1958 | * @connect: The new connect state of the path. True if the path is connected, | ||
1959 | * false if it is disconneted. | ||
1960 | * @reason: The reason why the path changed (for debugging only) | ||
1961 | */ | ||
1962 | static void soc_dapm_connect_path(struct snd_soc_dapm_path *path, | ||
1963 | bool connect, const char *reason) | ||
1964 | { | ||
1965 | if (path->connect == connect) | ||
1966 | return; | ||
1967 | |||
1968 | path->connect = connect; | ||
1969 | dapm_mark_dirty(path->source, reason); | ||
1970 | dapm_mark_dirty(path->sink, reason); | ||
1971 | dapm_path_invalidate(path); | ||
1972 | } | ||
1973 | |||
2014 | /* test and update the power status of a mux widget */ | 1974 | /* test and update the power status of a mux widget */ |
2015 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, | 1975 | static int soc_dapm_mux_update_power(struct snd_soc_card *card, |
2016 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) | 1976 | struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) |
2017 | { | 1977 | { |
2018 | struct snd_soc_dapm_path *path; | 1978 | struct snd_soc_dapm_path *path; |
2019 | int found = 0; | 1979 | int found = 0; |
1980 | bool connect; | ||
2020 | 1981 | ||
2021 | lockdep_assert_held(&card->dapm_mutex); | 1982 | lockdep_assert_held(&card->dapm_mutex); |
2022 | 1983 | ||
2023 | /* find dapm widget path assoc with kcontrol */ | 1984 | /* find dapm widget path assoc with kcontrol */ |
2024 | dapm_kcontrol_for_each_path(path, kcontrol) { | 1985 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2025 | if (!path->name || !e->texts[mux]) | ||
2026 | continue; | ||
2027 | |||
2028 | found = 1; | 1986 | found = 1; |
2029 | /* we now need to match the string in the enum to the path */ | 1987 | /* we now need to match the string in the enum to the path */ |
2030 | if (!(strcmp(path->name, e->texts[mux]))) { | 1988 | if (!(strcmp(path->name, e->texts[mux]))) |
2031 | path->connect = 1; /* new connection */ | 1989 | connect = true; |
2032 | dapm_mark_dirty(path->source, "mux connection"); | 1990 | else |
2033 | } else { | 1991 | connect = false; |
2034 | if (path->connect) | 1992 | |
2035 | dapm_mark_dirty(path->source, | 1993 | soc_dapm_connect_path(path, connect, "mux update"); |
2036 | "mux disconnection"); | ||
2037 | path->connect = 0; /* old connection must be powered down */ | ||
2038 | } | ||
2039 | dapm_mark_dirty(path->sink, "mux change"); | ||
2040 | } | 1994 | } |
2041 | 1995 | ||
2042 | if (found) | 1996 | if (found) |
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
2075 | /* find dapm widget path assoc with kcontrol */ | 2029 | /* find dapm widget path assoc with kcontrol */ |
2076 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2030 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2077 | found = 1; | 2031 | found = 1; |
2078 | path->connect = connect; | 2032 | soc_dapm_connect_path(path, connect, "mixer update"); |
2079 | dapm_mark_dirty(path->source, "mixer connection"); | ||
2080 | dapm_mark_dirty(path->sink, "mixer update"); | ||
2081 | } | 2033 | } |
2082 | 2034 | ||
2083 | if (found) | 2035 | if (found) |
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2255 | return -EINVAL; | 2207 | return -EINVAL; |
2256 | } | 2208 | } |
2257 | 2209 | ||
2258 | if (w->connected != status) | 2210 | if (w->connected != status) { |
2259 | dapm_mark_dirty(w, "pin configuration"); | 2211 | dapm_mark_dirty(w, "pin configuration"); |
2212 | dapm_widget_invalidate_input_paths(w); | ||
2213 | dapm_widget_invalidate_output_paths(w); | ||
2214 | } | ||
2260 | 2215 | ||
2261 | w->connected = status; | 2216 | w->connected = status; |
2262 | if (status == 0) | 2217 | if (status == 0) |
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2309 | } | 2264 | } |
2310 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 2265 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
2311 | 2266 | ||
2267 | /* | ||
2268 | * dapm_update_widget_flags() - Re-compute widget sink and source flags | ||
2269 | * @w: The widget for which to update the flags | ||
2270 | * | ||
2271 | * Some widgets have a dynamic category which depends on which neighbors they | ||
2272 | * are connected to. This function update the category for these widgets. | ||
2273 | * | ||
2274 | * This function must be called whenever a path is added or removed to a widget. | ||
2275 | */ | ||
2276 | static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w) | ||
2277 | { | ||
2278 | struct snd_soc_dapm_path *p; | ||
2279 | |||
2280 | switch (w->id) { | ||
2281 | case snd_soc_dapm_input: | ||
2282 | w->is_source = 1; | ||
2283 | list_for_each_entry(p, &w->sources, list_sink) { | ||
2284 | if (p->source->id == snd_soc_dapm_micbias || | ||
2285 | p->source->id == snd_soc_dapm_mic || | ||
2286 | p->source->id == snd_soc_dapm_line || | ||
2287 | p->source->id == snd_soc_dapm_output) { | ||
2288 | w->is_source = 0; | ||
2289 | break; | ||
2290 | } | ||
2291 | } | ||
2292 | break; | ||
2293 | case snd_soc_dapm_output: | ||
2294 | w->is_sink = 1; | ||
2295 | list_for_each_entry(p, &w->sinks, list_source) { | ||
2296 | if (p->sink->id == snd_soc_dapm_spk || | ||
2297 | p->sink->id == snd_soc_dapm_hp || | ||
2298 | p->sink->id == snd_soc_dapm_line || | ||
2299 | p->sink->id == snd_soc_dapm_input) { | ||
2300 | w->is_sink = 0; | ||
2301 | break; | ||
2302 | } | ||
2303 | } | ||
2304 | break; | ||
2305 | case snd_soc_dapm_line: | ||
2306 | w->is_sink = !list_empty(&w->sources); | ||
2307 | w->is_source = !list_empty(&w->sinks); | ||
2308 | break; | ||
2309 | default: | ||
2310 | break; | ||
2311 | } | ||
2312 | } | ||
2313 | |||
2312 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | 2314 | static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, |
2313 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, | 2315 | struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink, |
2314 | const char *control, | 2316 | const char *control, |
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2318 | struct snd_soc_dapm_path *path; | 2320 | struct snd_soc_dapm_path *path; |
2319 | int ret; | 2321 | int ret; |
2320 | 2322 | ||
2323 | if (wsink->is_supply && !wsource->is_supply) { | ||
2324 | dev_err(dapm->dev, | ||
2325 | "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n", | ||
2326 | wsource->name, wsink->name); | ||
2327 | return -EINVAL; | ||
2328 | } | ||
2329 | |||
2330 | if (connected && !wsource->is_supply) { | ||
2331 | dev_err(dapm->dev, | ||
2332 | "connected() callback only supported for supply widgets (%s -> %s)\n", | ||
2333 | wsource->name, wsink->name); | ||
2334 | return -EINVAL; | ||
2335 | } | ||
2336 | |||
2337 | if (wsource->is_supply && control) { | ||
2338 | dev_err(dapm->dev, | ||
2339 | "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n", | ||
2340 | wsource->name, control, wsink->name); | ||
2341 | return -EINVAL; | ||
2342 | } | ||
2343 | |||
2321 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); | 2344 | path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL); |
2322 | if (!path) | 2345 | if (!path) |
2323 | return -ENOMEM; | 2346 | return -ENOMEM; |
@@ -2330,85 +2353,49 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2330 | INIT_LIST_HEAD(&path->list_source); | 2353 | INIT_LIST_HEAD(&path->list_source); |
2331 | INIT_LIST_HEAD(&path->list_sink); | 2354 | INIT_LIST_HEAD(&path->list_sink); |
2332 | 2355 | ||
2333 | /* check for external widgets */ | 2356 | if (wsource->is_supply || wsink->is_supply) |
2334 | if (wsink->id == snd_soc_dapm_input) { | 2357 | path->is_supply = 1; |
2335 | if (wsource->id == snd_soc_dapm_micbias || | ||
2336 | wsource->id == snd_soc_dapm_mic || | ||
2337 | wsource->id == snd_soc_dapm_line || | ||
2338 | wsource->id == snd_soc_dapm_output) | ||
2339 | wsink->ext = 1; | ||
2340 | } | ||
2341 | if (wsource->id == snd_soc_dapm_output) { | ||
2342 | if (wsink->id == snd_soc_dapm_spk || | ||
2343 | wsink->id == snd_soc_dapm_hp || | ||
2344 | wsink->id == snd_soc_dapm_line || | ||
2345 | wsink->id == snd_soc_dapm_input) | ||
2346 | wsource->ext = 1; | ||
2347 | } | ||
2348 | |||
2349 | dapm_mark_dirty(wsource, "Route added"); | ||
2350 | dapm_mark_dirty(wsink, "Route added"); | ||
2351 | 2358 | ||
2352 | /* connect static paths */ | 2359 | /* connect static paths */ |
2353 | if (control == NULL) { | 2360 | if (control == NULL) { |
2354 | list_add(&path->list, &dapm->card->paths); | ||
2355 | list_add(&path->list_sink, &wsink->sources); | ||
2356 | list_add(&path->list_source, &wsource->sinks); | ||
2357 | path->connect = 1; | 2361 | path->connect = 1; |
2358 | return 0; | 2362 | } else { |
2359 | } | 2363 | /* connect dynamic paths */ |
2360 | 2364 | switch (wsink->id) { | |
2361 | /* connect dynamic paths */ | 2365 | case snd_soc_dapm_mux: |
2362 | switch (wsink->id) { | 2366 | ret = dapm_connect_mux(dapm, path, control); |
2363 | case snd_soc_dapm_adc: | 2367 | if (ret != 0) |
2364 | case snd_soc_dapm_dac: | 2368 | goto err; |
2365 | case snd_soc_dapm_pga: | 2369 | break; |
2366 | case snd_soc_dapm_out_drv: | 2370 | case snd_soc_dapm_switch: |
2367 | case snd_soc_dapm_input: | 2371 | case snd_soc_dapm_mixer: |
2368 | case snd_soc_dapm_output: | 2372 | case snd_soc_dapm_mixer_named_ctl: |
2369 | case snd_soc_dapm_siggen: | 2373 | ret = dapm_connect_mixer(dapm, path, control); |
2370 | case snd_soc_dapm_micbias: | 2374 | if (ret != 0) |
2371 | case snd_soc_dapm_vmid: | 2375 | goto err; |
2372 | case snd_soc_dapm_pre: | 2376 | break; |
2373 | case snd_soc_dapm_post: | 2377 | default: |
2374 | case snd_soc_dapm_supply: | 2378 | dev_err(dapm->dev, |
2375 | case snd_soc_dapm_regulator_supply: | 2379 | "Control not supported for path %s -> [%s] -> %s\n", |
2376 | case snd_soc_dapm_clock_supply: | 2380 | wsource->name, control, wsink->name); |
2377 | case snd_soc_dapm_aif_in: | 2381 | ret = -EINVAL; |
2378 | case snd_soc_dapm_aif_out: | ||
2379 | case snd_soc_dapm_dai_in: | ||
2380 | case snd_soc_dapm_dai_out: | ||
2381 | case snd_soc_dapm_dai_link: | ||
2382 | case snd_soc_dapm_kcontrol: | ||
2383 | list_add(&path->list, &dapm->card->paths); | ||
2384 | list_add(&path->list_sink, &wsink->sources); | ||
2385 | list_add(&path->list_source, &wsource->sinks); | ||
2386 | path->connect = 1; | ||
2387 | return 0; | ||
2388 | case snd_soc_dapm_mux: | ||
2389 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | ||
2390 | &wsink->kcontrol_news[0]); | ||
2391 | if (ret != 0) | ||
2392 | goto err; | ||
2393 | break; | ||
2394 | case snd_soc_dapm_switch: | ||
2395 | case snd_soc_dapm_mixer: | ||
2396 | case snd_soc_dapm_mixer_named_ctl: | ||
2397 | ret = dapm_connect_mixer(dapm, wsource, wsink, path, control); | ||
2398 | if (ret != 0) | ||
2399 | goto err; | 2382 | goto err; |
2400 | break; | 2383 | } |
2401 | case snd_soc_dapm_hp: | ||
2402 | case snd_soc_dapm_mic: | ||
2403 | case snd_soc_dapm_line: | ||
2404 | case snd_soc_dapm_spk: | ||
2405 | list_add(&path->list, &dapm->card->paths); | ||
2406 | list_add(&path->list_sink, &wsink->sources); | ||
2407 | list_add(&path->list_source, &wsource->sinks); | ||
2408 | path->connect = 0; | ||
2409 | return 0; | ||
2410 | } | 2384 | } |
2411 | 2385 | ||
2386 | list_add(&path->list, &dapm->card->paths); | ||
2387 | list_add(&path->list_sink, &wsink->sources); | ||
2388 | list_add(&path->list_source, &wsource->sinks); | ||
2389 | |||
2390 | dapm_update_widget_flags(wsource); | ||
2391 | dapm_update_widget_flags(wsink); | ||
2392 | |||
2393 | dapm_mark_dirty(wsource, "Route added"); | ||
2394 | dapm_mark_dirty(wsink, "Route added"); | ||
2395 | |||
2396 | if (dapm->card->instantiated && path->connect) | ||
2397 | dapm_path_invalidate(path); | ||
2398 | |||
2412 | return 0; | 2399 | return 0; |
2413 | err: | 2400 | err: |
2414 | kfree(path); | 2401 | kfree(path); |
@@ -2489,6 +2476,7 @@ err: | |||
2489 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | 2476 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, |
2490 | const struct snd_soc_dapm_route *route) | 2477 | const struct snd_soc_dapm_route *route) |
2491 | { | 2478 | { |
2479 | struct snd_soc_dapm_widget *wsource, *wsink; | ||
2492 | struct snd_soc_dapm_path *path, *p; | 2480 | struct snd_soc_dapm_path *path, *p; |
2493 | const char *sink; | 2481 | const char *sink; |
2494 | const char *source; | 2482 | const char *source; |
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | |||
2526 | } | 2514 | } |
2527 | 2515 | ||
2528 | if (path) { | 2516 | if (path) { |
2529 | dapm_mark_dirty(path->source, "Route removed"); | 2517 | wsource = path->source; |
2530 | dapm_mark_dirty(path->sink, "Route removed"); | 2518 | wsink = path->sink; |
2519 | |||
2520 | dapm_mark_dirty(wsource, "Route removed"); | ||
2521 | dapm_mark_dirty(wsink, "Route removed"); | ||
2522 | if (path->connect) | ||
2523 | dapm_path_invalidate(path); | ||
2531 | 2524 | ||
2532 | dapm_free_path(path); | 2525 | dapm_free_path(path); |
2526 | |||
2527 | /* Update any path related flags */ | ||
2528 | dapm_update_widget_flags(wsource); | ||
2529 | dapm_update_widget_flags(wsink); | ||
2533 | } else { | 2530 | } else { |
2534 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", | 2531 | dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n", |
2535 | source, sink); | 2532 | source, sink); |
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3087 | } | 3084 | } |
3088 | 3085 | ||
3089 | switch (w->id) { | 3086 | switch (w->id) { |
3090 | case snd_soc_dapm_switch: | 3087 | case snd_soc_dapm_mic: |
3091 | case snd_soc_dapm_mixer: | 3088 | case snd_soc_dapm_input: |
3092 | case snd_soc_dapm_mixer_named_ctl: | 3089 | w->is_source = 1; |
3093 | w->power_check = dapm_generic_check_power; | 3090 | w->power_check = dapm_generic_check_power; |
3094 | break; | 3091 | break; |
3095 | case snd_soc_dapm_mux: | 3092 | case snd_soc_dapm_spk: |
3093 | case snd_soc_dapm_hp: | ||
3094 | case snd_soc_dapm_output: | ||
3095 | w->is_sink = 1; | ||
3096 | w->power_check = dapm_generic_check_power; | 3096 | w->power_check = dapm_generic_check_power; |
3097 | break; | 3097 | break; |
3098 | case snd_soc_dapm_dai_out: | 3098 | case snd_soc_dapm_vmid: |
3099 | w->power_check = dapm_adc_check_power; | 3099 | case snd_soc_dapm_siggen: |
3100 | break; | 3100 | w->is_source = 1; |
3101 | case snd_soc_dapm_dai_in: | 3101 | w->power_check = dapm_always_on_check_power; |
3102 | w->power_check = dapm_dac_check_power; | ||
3103 | break; | 3102 | break; |
3103 | case snd_soc_dapm_mux: | ||
3104 | case snd_soc_dapm_switch: | ||
3105 | case snd_soc_dapm_mixer: | ||
3106 | case snd_soc_dapm_mixer_named_ctl: | ||
3104 | case snd_soc_dapm_adc: | 3107 | case snd_soc_dapm_adc: |
3105 | case snd_soc_dapm_aif_out: | 3108 | case snd_soc_dapm_aif_out: |
3106 | case snd_soc_dapm_dac: | 3109 | case snd_soc_dapm_dac: |
3107 | case snd_soc_dapm_aif_in: | 3110 | case snd_soc_dapm_aif_in: |
3108 | case snd_soc_dapm_pga: | 3111 | case snd_soc_dapm_pga: |
3109 | case snd_soc_dapm_out_drv: | 3112 | case snd_soc_dapm_out_drv: |
3110 | case snd_soc_dapm_input: | ||
3111 | case snd_soc_dapm_output: | ||
3112 | case snd_soc_dapm_micbias: | 3113 | case snd_soc_dapm_micbias: |
3113 | case snd_soc_dapm_spk: | ||
3114 | case snd_soc_dapm_hp: | ||
3115 | case snd_soc_dapm_mic: | ||
3116 | case snd_soc_dapm_line: | 3114 | case snd_soc_dapm_line: |
3117 | case snd_soc_dapm_dai_link: | 3115 | case snd_soc_dapm_dai_link: |
3116 | case snd_soc_dapm_dai_out: | ||
3117 | case snd_soc_dapm_dai_in: | ||
3118 | w->power_check = dapm_generic_check_power; | 3118 | w->power_check = dapm_generic_check_power; |
3119 | break; | 3119 | break; |
3120 | case snd_soc_dapm_supply: | 3120 | case snd_soc_dapm_supply: |
3121 | case snd_soc_dapm_regulator_supply: | 3121 | case snd_soc_dapm_regulator_supply: |
3122 | case snd_soc_dapm_clock_supply: | 3122 | case snd_soc_dapm_clock_supply: |
3123 | case snd_soc_dapm_kcontrol: | 3123 | case snd_soc_dapm_kcontrol: |
3124 | w->is_supply = 1; | ||
3124 | w->power_check = dapm_supply_check_power; | 3125 | w->power_check = dapm_supply_check_power; |
3125 | break; | 3126 | break; |
3126 | default: | 3127 | default: |
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3137 | INIT_LIST_HEAD(&w->dirty); | 3138 | INIT_LIST_HEAD(&w->dirty); |
3138 | list_add(&w->list, &dapm->card->widgets); | 3139 | list_add(&w->list, &dapm->card->widgets); |
3139 | 3140 | ||
3141 | w->inputs = -1; | ||
3142 | w->outputs = -1; | ||
3143 | |||
3140 | /* machine layer set ups unconnected pins and insertions */ | 3144 | /* machine layer set ups unconnected pins and insertions */ |
3141 | w->connected = 1; | 3145 | w->connected = 1; |
3142 | return w; | 3146 | return w; |
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream, | |||
3484 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: | 3488 | case SND_SOC_DAPM_STREAM_PAUSE_RELEASE: |
3485 | break; | 3489 | break; |
3486 | } | 3490 | } |
3491 | |||
3492 | if (w->id == snd_soc_dapm_dai_in) { | ||
3493 | w->is_source = w->active; | ||
3494 | dapm_widget_invalidate_input_paths(w); | ||
3495 | } else { | ||
3496 | w->is_sink = w->active; | ||
3497 | dapm_widget_invalidate_output_paths(w); | ||
3498 | } | ||
3487 | } | 3499 | } |
3488 | } | 3500 | } |
3489 | 3501 | ||
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | |||
3610 | } | 3622 | } |
3611 | 3623 | ||
3612 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); | 3624 | dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin); |
3613 | w->connected = 1; | 3625 | if (!w->connected) { |
3626 | /* | ||
3627 | * w->force does not affect the number of input or output paths, | ||
3628 | * so we only have to recheck if w->connected is changed | ||
3629 | */ | ||
3630 | dapm_widget_invalidate_input_paths(w); | ||
3631 | dapm_widget_invalidate_output_paths(w); | ||
3632 | w->connected = 1; | ||
3633 | } | ||
3614 | w->force = 1; | 3634 | w->force = 1; |
3615 | dapm_mark_dirty(w, "force enable"); | 3635 | dapm_mark_dirty(w, "force enable"); |
3616 | 3636 | ||
@@ -3788,35 +3808,54 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, | |||
3788 | } | 3808 | } |
3789 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); | 3809 | EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend); |
3790 | 3810 | ||
3811 | /** | ||
3812 | * dapm_is_external_path() - Checks if a path is a external path | ||
3813 | * @card: The card the path belongs to | ||
3814 | * @path: The path to check | ||
3815 | * | ||
3816 | * Returns true if the path is either between two different DAPM contexts or | ||
3817 | * between two external pins of the same DAPM context. Otherwise returns | ||
3818 | * false. | ||
3819 | */ | ||
3820 | static bool dapm_is_external_path(struct snd_soc_card *card, | ||
3821 | struct snd_soc_dapm_path *path) | ||
3822 | { | ||
3823 | dev_dbg(card->dev, | ||
3824 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | ||
3825 | path->source->name, path->source->id, path->source->dapm, | ||
3826 | path->sink->name, path->sink->id, path->sink->dapm); | ||
3827 | |||
3828 | /* Connection between two different DAPM contexts */ | ||
3829 | if (path->source->dapm != path->sink->dapm) | ||
3830 | return true; | ||
3831 | |||
3832 | /* Loopback connection from external pin to external pin */ | ||
3833 | if (path->sink->id == snd_soc_dapm_input) { | ||
3834 | switch (path->source->id) { | ||
3835 | case snd_soc_dapm_output: | ||
3836 | case snd_soc_dapm_micbias: | ||
3837 | return true; | ||
3838 | default: | ||
3839 | break; | ||
3840 | } | ||
3841 | } | ||
3842 | |||
3843 | return false; | ||
3844 | } | ||
3845 | |||
3791 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, | 3846 | static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card, |
3792 | struct snd_soc_dapm_widget *w) | 3847 | struct snd_soc_dapm_widget *w) |
3793 | { | 3848 | { |
3794 | struct snd_soc_dapm_path *p; | 3849 | struct snd_soc_dapm_path *p; |
3795 | 3850 | ||
3796 | list_for_each_entry(p, &card->paths, list) { | 3851 | list_for_each_entry(p, &w->sources, list_sink) { |
3797 | if ((p->source == w) || (p->sink == w)) { | 3852 | if (dapm_is_external_path(card, p)) |
3798 | dev_dbg(card->dev, | 3853 | return true; |
3799 | "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n", | 3854 | } |
3800 | p->source->name, p->source->id, p->source->dapm, | ||
3801 | p->sink->name, p->sink->id, p->sink->dapm); | ||
3802 | 3855 | ||
3803 | /* Connected to something other than the codec */ | 3856 | list_for_each_entry(p, &w->sinks, list_source) { |
3804 | if (p->source->dapm != p->sink->dapm) | 3857 | if (dapm_is_external_path(card, p)) |
3805 | return true; | 3858 | return true; |
3806 | /* | ||
3807 | * Loopback connection from codec external pin to | ||
3808 | * codec external pin | ||
3809 | */ | ||
3810 | if (p->sink->id == snd_soc_dapm_input) { | ||
3811 | switch (p->source->id) { | ||
3812 | case snd_soc_dapm_output: | ||
3813 | case snd_soc_dapm_micbias: | ||
3814 | return true; | ||
3815 | default: | ||
3816 | break; | ||
3817 | } | ||
3818 | } | ||
3819 | } | ||
3820 | } | 3859 | } |
3821 | 3860 | ||
3822 | return false; | 3861 | return false; |
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index ab47fea997a3..4380dcc064a5 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_report); | |||
116 | * | 116 | * |
117 | * @jack: ASoC jack | 117 | * @jack: ASoC jack |
118 | * @count: Number of zones | 118 | * @count: Number of zones |
119 | * @zone: Array of zones | 119 | * @zones: Array of zones |
120 | * | 120 | * |
121 | * After this function has been called the zones specified in the | 121 | * After this function has been called the zones specified in the |
122 | * array will be associated with the jack. | 122 | * array will be associated with the jack. |
@@ -309,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
309 | /* GPIO descriptor */ | 309 | /* GPIO descriptor */ |
310 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, | 310 | gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev, |
311 | gpios[i].name, | 311 | gpios[i].name, |
312 | gpios[i].idx); | 312 | gpios[i].idx, GPIOD_IN); |
313 | if (IS_ERR(gpios[i].desc)) { | 313 | if (IS_ERR(gpios[i].desc)) { |
314 | ret = PTR_ERR(gpios[i].desc); | 314 | ret = PTR_ERR(gpios[i].desc); |
315 | dev_err(gpios[i].gpiod_dev, | 315 | dev_err(gpios[i].gpiod_dev, |
@@ -327,17 +327,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
327 | goto undo; | 327 | goto undo; |
328 | } | 328 | } |
329 | 329 | ||
330 | ret = gpio_request(gpios[i].gpio, gpios[i].name); | 330 | ret = gpio_request_one(gpios[i].gpio, GPIOF_IN, |
331 | gpios[i].name); | ||
331 | if (ret) | 332 | if (ret) |
332 | goto undo; | 333 | goto undo; |
333 | 334 | ||
334 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); | 335 | gpios[i].desc = gpio_to_desc(gpios[i].gpio); |
335 | } | 336 | } |
336 | 337 | ||
337 | ret = gpiod_direction_input(gpios[i].desc); | ||
338 | if (ret) | ||
339 | goto err; | ||
340 | |||
341 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); | 338 | INIT_DELAYED_WORK(&gpios[i].work, gpio_work); |
342 | gpios[i].jack = jack; | 339 | gpios[i].jack = jack; |
343 | 340 | ||
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c new file mode 100644 index 000000000000..100d92b5b77e --- /dev/null +++ b/sound/soc/soc-ops.c | |||
@@ -0,0 +1,952 @@ | |||
1 | /* | ||
2 | * soc-ops.c -- Generic ASoC operations | ||
3 | * | ||
4 | * Copyright 2005 Wolfson Microelectronics PLC. | ||
5 | * Copyright 2005 Openedhand Ltd. | ||
6 | * Copyright (C) 2010 Slimlogic Ltd. | ||
7 | * Copyright (C) 2010 Texas Instruments Inc. | ||
8 | * | ||
9 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | ||
10 | * with code, comments and ideas from :- | ||
11 | * Richard Purdie <richard@openedhand.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/moduleparam.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/pm.h> | ||
24 | #include <linux/bitops.h> | ||
25 | #include <linux/ctype.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/jack.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dpcm.h> | ||
33 | #include <sound/initval.h> | ||
34 | |||
35 | /** | ||
36 | * snd_soc_info_enum_double - enumerated double mixer info callback | ||
37 | * @kcontrol: mixer control | ||
38 | * @uinfo: control element information | ||
39 | * | ||
40 | * Callback to provide information about a double enumerated | ||
41 | * mixer control. | ||
42 | * | ||
43 | * Returns 0 for success. | ||
44 | */ | ||
45 | int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | ||
46 | struct snd_ctl_elem_info *uinfo) | ||
47 | { | ||
48 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
49 | |||
50 | return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2, | ||
51 | e->items, e->texts); | ||
52 | } | ||
53 | EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); | ||
54 | |||
55 | /** | ||
56 | * snd_soc_get_enum_double - enumerated double mixer get callback | ||
57 | * @kcontrol: mixer control | ||
58 | * @ucontrol: control element information | ||
59 | * | ||
60 | * Callback to get the value of a double enumerated mixer. | ||
61 | * | ||
62 | * Returns 0 for success. | ||
63 | */ | ||
64 | int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | ||
65 | struct snd_ctl_elem_value *ucontrol) | ||
66 | { | ||
67 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
68 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
69 | unsigned int val, item; | ||
70 | unsigned int reg_val; | ||
71 | int ret; | ||
72 | |||
73 | ret = snd_soc_component_read(component, e->reg, ®_val); | ||
74 | if (ret) | ||
75 | return ret; | ||
76 | val = (reg_val >> e->shift_l) & e->mask; | ||
77 | item = snd_soc_enum_val_to_item(e, val); | ||
78 | ucontrol->value.enumerated.item[0] = item; | ||
79 | if (e->shift_l != e->shift_r) { | ||
80 | val = (reg_val >> e->shift_l) & e->mask; | ||
81 | item = snd_soc_enum_val_to_item(e, val); | ||
82 | ucontrol->value.enumerated.item[1] = item; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); | ||
88 | |||
89 | /** | ||
90 | * snd_soc_put_enum_double - enumerated double mixer put callback | ||
91 | * @kcontrol: mixer control | ||
92 | * @ucontrol: control element information | ||
93 | * | ||
94 | * Callback to set the value of a double enumerated mixer. | ||
95 | * | ||
96 | * Returns 0 for success. | ||
97 | */ | ||
98 | int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | ||
99 | struct snd_ctl_elem_value *ucontrol) | ||
100 | { | ||
101 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
102 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
103 | unsigned int *item = ucontrol->value.enumerated.item; | ||
104 | unsigned int val; | ||
105 | unsigned int mask; | ||
106 | |||
107 | if (item[0] >= e->items) | ||
108 | return -EINVAL; | ||
109 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; | ||
110 | mask = e->mask << e->shift_l; | ||
111 | if (e->shift_l != e->shift_r) { | ||
112 | if (item[1] >= e->items) | ||
113 | return -EINVAL; | ||
114 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; | ||
115 | mask |= e->mask << e->shift_r; | ||
116 | } | ||
117 | |||
118 | return snd_soc_component_update_bits(component, e->reg, mask, val); | ||
119 | } | ||
120 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | ||
121 | |||
122 | /** | ||
123 | * snd_soc_read_signed - Read a codec register and interprete as signed value | ||
124 | * @component: component | ||
125 | * @reg: Register to read | ||
126 | * @mask: Mask to use after shifting the register value | ||
127 | * @shift: Right shift of register value | ||
128 | * @sign_bit: Bit that describes if a number is negative or not. | ||
129 | * @signed_val: Pointer to where the read value should be stored | ||
130 | * | ||
131 | * This functions reads a codec register. The register value is shifted right | ||
132 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates | ||
133 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
134 | * | ||
135 | * Returns 0 on sucess, otherwise an error value | ||
136 | */ | ||
137 | static int snd_soc_read_signed(struct snd_soc_component *component, | ||
138 | unsigned int reg, unsigned int mask, unsigned int shift, | ||
139 | unsigned int sign_bit, int *signed_val) | ||
140 | { | ||
141 | int ret; | ||
142 | unsigned int val; | ||
143 | |||
144 | ret = snd_soc_component_read(component, reg, &val); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | |||
148 | val = (val >> shift) & mask; | ||
149 | |||
150 | if (!sign_bit) { | ||
151 | *signed_val = val; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /* non-negative number */ | ||
156 | if (!(val & BIT(sign_bit))) { | ||
157 | *signed_val = val; | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | ret = val; | ||
162 | |||
163 | /* | ||
164 | * The register most probably does not contain a full-sized int. | ||
165 | * Instead we have an arbitrary number of bits in a signed | ||
166 | * representation which has to be translated into a full-sized int. | ||
167 | * This is done by filling up all bits above the sign-bit. | ||
168 | */ | ||
169 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
170 | |||
171 | *signed_val = ret; | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | /** | ||
177 | * snd_soc_info_volsw - single mixer info callback | ||
178 | * @kcontrol: mixer control | ||
179 | * @uinfo: control element information | ||
180 | * | ||
181 | * Callback to provide information about a single mixer control, or a double | ||
182 | * mixer control that spans 2 registers. | ||
183 | * | ||
184 | * Returns 0 for success. | ||
185 | */ | ||
186 | int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | ||
187 | struct snd_ctl_elem_info *uinfo) | ||
188 | { | ||
189 | struct soc_mixer_control *mc = | ||
190 | (struct soc_mixer_control *)kcontrol->private_value; | ||
191 | int platform_max; | ||
192 | |||
193 | if (!mc->platform_max) | ||
194 | mc->platform_max = mc->max; | ||
195 | platform_max = mc->platform_max; | ||
196 | |||
197 | if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume")) | ||
198 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
199 | else | ||
200 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
201 | |||
202 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
203 | uinfo->value.integer.min = 0; | ||
204 | uinfo->value.integer.max = platform_max - mc->min; | ||
205 | return 0; | ||
206 | } | ||
207 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | ||
208 | |||
209 | /** | ||
210 | * snd_soc_get_volsw - single mixer get callback | ||
211 | * @kcontrol: mixer control | ||
212 | * @ucontrol: control element information | ||
213 | * | ||
214 | * Callback to get the value of a single mixer control, or a double mixer | ||
215 | * control that spans 2 registers. | ||
216 | * | ||
217 | * Returns 0 for success. | ||
218 | */ | ||
219 | int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | ||
220 | struct snd_ctl_elem_value *ucontrol) | ||
221 | { | ||
222 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
223 | struct soc_mixer_control *mc = | ||
224 | (struct soc_mixer_control *)kcontrol->private_value; | ||
225 | unsigned int reg = mc->reg; | ||
226 | unsigned int reg2 = mc->rreg; | ||
227 | unsigned int shift = mc->shift; | ||
228 | unsigned int rshift = mc->rshift; | ||
229 | int max = mc->max; | ||
230 | int min = mc->min; | ||
231 | int sign_bit = mc->sign_bit; | ||
232 | unsigned int mask = (1 << fls(max)) - 1; | ||
233 | unsigned int invert = mc->invert; | ||
234 | int val; | ||
235 | int ret; | ||
236 | |||
237 | if (sign_bit) | ||
238 | mask = BIT(sign_bit + 1) - 1; | ||
239 | |||
240 | ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); | ||
241 | if (ret) | ||
242 | return ret; | ||
243 | |||
244 | ucontrol->value.integer.value[0] = val - min; | ||
245 | if (invert) | ||
246 | ucontrol->value.integer.value[0] = | ||
247 | max - ucontrol->value.integer.value[0]; | ||
248 | |||
249 | if (snd_soc_volsw_is_stereo(mc)) { | ||
250 | if (reg == reg2) | ||
251 | ret = snd_soc_read_signed(component, reg, mask, rshift, | ||
252 | sign_bit, &val); | ||
253 | else | ||
254 | ret = snd_soc_read_signed(component, reg2, mask, shift, | ||
255 | sign_bit, &val); | ||
256 | if (ret) | ||
257 | return ret; | ||
258 | |||
259 | ucontrol->value.integer.value[1] = val - min; | ||
260 | if (invert) | ||
261 | ucontrol->value.integer.value[1] = | ||
262 | max - ucontrol->value.integer.value[1]; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw); | ||
268 | |||
269 | /** | ||
270 | * snd_soc_put_volsw - single mixer put callback | ||
271 | * @kcontrol: mixer control | ||
272 | * @ucontrol: control element information | ||
273 | * | ||
274 | * Callback to set the value of a single mixer control, or a double mixer | ||
275 | * control that spans 2 registers. | ||
276 | * | ||
277 | * Returns 0 for success. | ||
278 | */ | ||
279 | int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | ||
280 | struct snd_ctl_elem_value *ucontrol) | ||
281 | { | ||
282 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
283 | struct soc_mixer_control *mc = | ||
284 | (struct soc_mixer_control *)kcontrol->private_value; | ||
285 | unsigned int reg = mc->reg; | ||
286 | unsigned int reg2 = mc->rreg; | ||
287 | unsigned int shift = mc->shift; | ||
288 | unsigned int rshift = mc->rshift; | ||
289 | int max = mc->max; | ||
290 | int min = mc->min; | ||
291 | unsigned int sign_bit = mc->sign_bit; | ||
292 | unsigned int mask = (1 << fls(max)) - 1; | ||
293 | unsigned int invert = mc->invert; | ||
294 | int err; | ||
295 | bool type_2r = false; | ||
296 | unsigned int val2 = 0; | ||
297 | unsigned int val, val_mask; | ||
298 | |||
299 | if (sign_bit) | ||
300 | mask = BIT(sign_bit + 1) - 1; | ||
301 | |||
302 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
303 | if (invert) | ||
304 | val = max - val; | ||
305 | val_mask = mask << shift; | ||
306 | val = val << shift; | ||
307 | if (snd_soc_volsw_is_stereo(mc)) { | ||
308 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); | ||
309 | if (invert) | ||
310 | val2 = max - val2; | ||
311 | if (reg == reg2) { | ||
312 | val_mask |= mask << rshift; | ||
313 | val |= val2 << rshift; | ||
314 | } else { | ||
315 | val2 = val2 << shift; | ||
316 | type_2r = true; | ||
317 | } | ||
318 | } | ||
319 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
320 | if (err < 0) | ||
321 | return err; | ||
322 | |||
323 | if (type_2r) | ||
324 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
325 | val2); | ||
326 | |||
327 | return err; | ||
328 | } | ||
329 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw); | ||
330 | |||
331 | /** | ||
332 | * snd_soc_get_volsw_sx - single mixer get callback | ||
333 | * @kcontrol: mixer control | ||
334 | * @ucontrol: control element information | ||
335 | * | ||
336 | * Callback to get the value of a single mixer control, or a double mixer | ||
337 | * control that spans 2 registers. | ||
338 | * | ||
339 | * Returns 0 for success. | ||
340 | */ | ||
341 | int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, | ||
342 | struct snd_ctl_elem_value *ucontrol) | ||
343 | { | ||
344 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
345 | struct soc_mixer_control *mc = | ||
346 | (struct soc_mixer_control *)kcontrol->private_value; | ||
347 | unsigned int reg = mc->reg; | ||
348 | unsigned int reg2 = mc->rreg; | ||
349 | unsigned int shift = mc->shift; | ||
350 | unsigned int rshift = mc->rshift; | ||
351 | int max = mc->max; | ||
352 | int min = mc->min; | ||
353 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
354 | unsigned int val; | ||
355 | int ret; | ||
356 | |||
357 | ret = snd_soc_component_read(component, reg, &val); | ||
358 | if (ret < 0) | ||
359 | return ret; | ||
360 | |||
361 | ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; | ||
362 | |||
363 | if (snd_soc_volsw_is_stereo(mc)) { | ||
364 | ret = snd_soc_component_read(component, reg2, &val); | ||
365 | if (ret < 0) | ||
366 | return ret; | ||
367 | |||
368 | val = ((val >> rshift) - min) & mask; | ||
369 | ucontrol->value.integer.value[1] = val; | ||
370 | } | ||
371 | |||
372 | return 0; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); | ||
375 | |||
376 | /** | ||
377 | * snd_soc_put_volsw_sx - double mixer set callback | ||
378 | * @kcontrol: mixer control | ||
379 | * @uinfo: control element information | ||
380 | * | ||
381 | * Callback to set the value of a double mixer control that spans 2 registers. | ||
382 | * | ||
383 | * Returns 0 for success. | ||
384 | */ | ||
385 | int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, | ||
386 | struct snd_ctl_elem_value *ucontrol) | ||
387 | { | ||
388 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
389 | struct soc_mixer_control *mc = | ||
390 | (struct soc_mixer_control *)kcontrol->private_value; | ||
391 | |||
392 | unsigned int reg = mc->reg; | ||
393 | unsigned int reg2 = mc->rreg; | ||
394 | unsigned int shift = mc->shift; | ||
395 | unsigned int rshift = mc->rshift; | ||
396 | int max = mc->max; | ||
397 | int min = mc->min; | ||
398 | int mask = (1 << (fls(min + max) - 1)) - 1; | ||
399 | int err = 0; | ||
400 | unsigned int val, val_mask, val2 = 0; | ||
401 | |||
402 | val_mask = mask << shift; | ||
403 | val = (ucontrol->value.integer.value[0] + min) & mask; | ||
404 | val = val << shift; | ||
405 | |||
406 | err = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
407 | if (err < 0) | ||
408 | return err; | ||
409 | |||
410 | if (snd_soc_volsw_is_stereo(mc)) { | ||
411 | val_mask = mask << rshift; | ||
412 | val2 = (ucontrol->value.integer.value[1] + min) & mask; | ||
413 | val2 = val2 << rshift; | ||
414 | |||
415 | err = snd_soc_component_update_bits(component, reg2, val_mask, | ||
416 | val2); | ||
417 | } | ||
418 | return err; | ||
419 | } | ||
420 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); | ||
421 | |||
422 | /** | ||
423 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
424 | * @kcontrol: mixer control | ||
425 | * @uinfo: control element information | ||
426 | * | ||
427 | * Callback to provide information, within a range, about a single | ||
428 | * mixer control. | ||
429 | * | ||
430 | * returns 0 for success. | ||
431 | */ | ||
432 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
433 | struct snd_ctl_elem_info *uinfo) | ||
434 | { | ||
435 | struct soc_mixer_control *mc = | ||
436 | (struct soc_mixer_control *)kcontrol->private_value; | ||
437 | int platform_max; | ||
438 | int min = mc->min; | ||
439 | |||
440 | if (!mc->platform_max) | ||
441 | mc->platform_max = mc->max; | ||
442 | platform_max = mc->platform_max; | ||
443 | |||
444 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
445 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | ||
446 | uinfo->value.integer.min = 0; | ||
447 | uinfo->value.integer.max = platform_max - min; | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
452 | |||
453 | /** | ||
454 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
455 | * @kcontrol: mixer control | ||
456 | * @ucontrol: control element information | ||
457 | * | ||
458 | * Callback to set the value, within a range, for a single mixer control. | ||
459 | * | ||
460 | * Returns 0 for success. | ||
461 | */ | ||
462 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
463 | struct snd_ctl_elem_value *ucontrol) | ||
464 | { | ||
465 | struct soc_mixer_control *mc = | ||
466 | (struct soc_mixer_control *)kcontrol->private_value; | ||
467 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
468 | unsigned int reg = mc->reg; | ||
469 | unsigned int rreg = mc->rreg; | ||
470 | unsigned int shift = mc->shift; | ||
471 | int min = mc->min; | ||
472 | int max = mc->max; | ||
473 | unsigned int mask = (1 << fls(max)) - 1; | ||
474 | unsigned int invert = mc->invert; | ||
475 | unsigned int val, val_mask; | ||
476 | int ret; | ||
477 | |||
478 | if (invert) | ||
479 | val = (max - ucontrol->value.integer.value[0]) & mask; | ||
480 | else | ||
481 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
482 | val_mask = mask << shift; | ||
483 | val = val << shift; | ||
484 | |||
485 | ret = snd_soc_component_update_bits(component, reg, val_mask, val); | ||
486 | if (ret < 0) | ||
487 | return ret; | ||
488 | |||
489 | if (snd_soc_volsw_is_stereo(mc)) { | ||
490 | if (invert) | ||
491 | val = (max - ucontrol->value.integer.value[1]) & mask; | ||
492 | else | ||
493 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
494 | val_mask = mask << shift; | ||
495 | val = val << shift; | ||
496 | |||
497 | ret = snd_soc_component_update_bits(component, rreg, val_mask, | ||
498 | val); | ||
499 | } | ||
500 | |||
501 | return ret; | ||
502 | } | ||
503 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
504 | |||
505 | /** | ||
506 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
507 | * @kcontrol: mixer control | ||
508 | * @ucontrol: control element information | ||
509 | * | ||
510 | * Callback to get the value, within a range, of a single mixer control. | ||
511 | * | ||
512 | * Returns 0 for success. | ||
513 | */ | ||
514 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
515 | struct snd_ctl_elem_value *ucontrol) | ||
516 | { | ||
517 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
518 | struct soc_mixer_control *mc = | ||
519 | (struct soc_mixer_control *)kcontrol->private_value; | ||
520 | unsigned int reg = mc->reg; | ||
521 | unsigned int rreg = mc->rreg; | ||
522 | unsigned int shift = mc->shift; | ||
523 | int min = mc->min; | ||
524 | int max = mc->max; | ||
525 | unsigned int mask = (1 << fls(max)) - 1; | ||
526 | unsigned int invert = mc->invert; | ||
527 | unsigned int val; | ||
528 | int ret; | ||
529 | |||
530 | ret = snd_soc_component_read(component, reg, &val); | ||
531 | if (ret) | ||
532 | return ret; | ||
533 | |||
534 | ucontrol->value.integer.value[0] = (val >> shift) & mask; | ||
535 | if (invert) | ||
536 | ucontrol->value.integer.value[0] = | ||
537 | max - ucontrol->value.integer.value[0]; | ||
538 | else | ||
539 | ucontrol->value.integer.value[0] = | ||
540 | ucontrol->value.integer.value[0] - min; | ||
541 | |||
542 | if (snd_soc_volsw_is_stereo(mc)) { | ||
543 | ret = snd_soc_component_read(component, rreg, &val); | ||
544 | if (ret) | ||
545 | return ret; | ||
546 | |||
547 | ucontrol->value.integer.value[1] = (val >> shift) & mask; | ||
548 | if (invert) | ||
549 | ucontrol->value.integer.value[1] = | ||
550 | max - ucontrol->value.integer.value[1]; | ||
551 | else | ||
552 | ucontrol->value.integer.value[1] = | ||
553 | ucontrol->value.integer.value[1] - min; | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
559 | |||
560 | /** | ||
561 | * snd_soc_limit_volume - Set new limit to an existing volume control. | ||
562 | * | ||
563 | * @codec: where to look for the control | ||
564 | * @name: Name of the control | ||
565 | * @max: new maximum limit | ||
566 | * | ||
567 | * Return 0 for success, else error. | ||
568 | */ | ||
569 | int snd_soc_limit_volume(struct snd_soc_codec *codec, | ||
570 | const char *name, int max) | ||
571 | { | ||
572 | struct snd_card *card = codec->component.card->snd_card; | ||
573 | struct snd_kcontrol *kctl; | ||
574 | struct soc_mixer_control *mc; | ||
575 | int found = 0; | ||
576 | int ret = -EINVAL; | ||
577 | |||
578 | /* Sanity check for name and max */ | ||
579 | if (unlikely(!name || max <= 0)) | ||
580 | return -EINVAL; | ||
581 | |||
582 | list_for_each_entry(kctl, &card->controls, list) { | ||
583 | if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) { | ||
584 | found = 1; | ||
585 | break; | ||
586 | } | ||
587 | } | ||
588 | if (found) { | ||
589 | mc = (struct soc_mixer_control *)kctl->private_value; | ||
590 | if (max <= mc->max) { | ||
591 | mc->platform_max = max; | ||
592 | ret = 0; | ||
593 | } | ||
594 | } | ||
595 | return ret; | ||
596 | } | ||
597 | EXPORT_SYMBOL_GPL(snd_soc_limit_volume); | ||
598 | |||
599 | int snd_soc_bytes_info(struct snd_kcontrol *kcontrol, | ||
600 | struct snd_ctl_elem_info *uinfo) | ||
601 | { | ||
602 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
603 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
604 | |||
605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
606 | uinfo->count = params->num_regs * component->val_bytes; | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info); | ||
611 | |||
612 | int snd_soc_bytes_get(struct snd_kcontrol *kcontrol, | ||
613 | struct snd_ctl_elem_value *ucontrol) | ||
614 | { | ||
615 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
616 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
617 | int ret; | ||
618 | |||
619 | if (component->regmap) | ||
620 | ret = regmap_raw_read(component->regmap, params->base, | ||
621 | ucontrol->value.bytes.data, | ||
622 | params->num_regs * component->val_bytes); | ||
623 | else | ||
624 | ret = -EINVAL; | ||
625 | |||
626 | /* Hide any masked bytes to ensure consistent data reporting */ | ||
627 | if (ret == 0 && params->mask) { | ||
628 | switch (component->val_bytes) { | ||
629 | case 1: | ||
630 | ucontrol->value.bytes.data[0] &= ~params->mask; | ||
631 | break; | ||
632 | case 2: | ||
633 | ((u16 *)(&ucontrol->value.bytes.data))[0] | ||
634 | &= cpu_to_be16(~params->mask); | ||
635 | break; | ||
636 | case 4: | ||
637 | ((u32 *)(&ucontrol->value.bytes.data))[0] | ||
638 | &= cpu_to_be32(~params->mask); | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | } | ||
644 | |||
645 | return ret; | ||
646 | } | ||
647 | EXPORT_SYMBOL_GPL(snd_soc_bytes_get); | ||
648 | |||
649 | int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | ||
650 | struct snd_ctl_elem_value *ucontrol) | ||
651 | { | ||
652 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
653 | struct soc_bytes *params = (void *)kcontrol->private_value; | ||
654 | int ret, len; | ||
655 | unsigned int val, mask; | ||
656 | void *data; | ||
657 | |||
658 | if (!component->regmap || !params->num_regs) | ||
659 | return -EINVAL; | ||
660 | |||
661 | len = params->num_regs * component->val_bytes; | ||
662 | |||
663 | data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); | ||
664 | if (!data) | ||
665 | return -ENOMEM; | ||
666 | |||
667 | /* | ||
668 | * If we've got a mask then we need to preserve the register | ||
669 | * bits. We shouldn't modify the incoming data so take a | ||
670 | * copy. | ||
671 | */ | ||
672 | if (params->mask) { | ||
673 | ret = regmap_read(component->regmap, params->base, &val); | ||
674 | if (ret != 0) | ||
675 | goto out; | ||
676 | |||
677 | val &= params->mask; | ||
678 | |||
679 | switch (component->val_bytes) { | ||
680 | case 1: | ||
681 | ((u8 *)data)[0] &= ~params->mask; | ||
682 | ((u8 *)data)[0] |= val; | ||
683 | break; | ||
684 | case 2: | ||
685 | mask = ~params->mask; | ||
686 | ret = regmap_parse_val(component->regmap, | ||
687 | &mask, &mask); | ||
688 | if (ret != 0) | ||
689 | goto out; | ||
690 | |||
691 | ((u16 *)data)[0] &= mask; | ||
692 | |||
693 | ret = regmap_parse_val(component->regmap, | ||
694 | &val, &val); | ||
695 | if (ret != 0) | ||
696 | goto out; | ||
697 | |||
698 | ((u16 *)data)[0] |= val; | ||
699 | break; | ||
700 | case 4: | ||
701 | mask = ~params->mask; | ||
702 | ret = regmap_parse_val(component->regmap, | ||
703 | &mask, &mask); | ||
704 | if (ret != 0) | ||
705 | goto out; | ||
706 | |||
707 | ((u32 *)data)[0] &= mask; | ||
708 | |||
709 | ret = regmap_parse_val(component->regmap, | ||
710 | &val, &val); | ||
711 | if (ret != 0) | ||
712 | goto out; | ||
713 | |||
714 | ((u32 *)data)[0] |= val; | ||
715 | break; | ||
716 | default: | ||
717 | ret = -EINVAL; | ||
718 | goto out; | ||
719 | } | ||
720 | } | ||
721 | |||
722 | ret = regmap_raw_write(component->regmap, params->base, | ||
723 | data, len); | ||
724 | |||
725 | out: | ||
726 | kfree(data); | ||
727 | |||
728 | return ret; | ||
729 | } | ||
730 | EXPORT_SYMBOL_GPL(snd_soc_bytes_put); | ||
731 | |||
732 | int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, | ||
733 | struct snd_ctl_elem_info *ucontrol) | ||
734 | { | ||
735 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
736 | |||
737 | ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
738 | ucontrol->count = params->max; | ||
739 | |||
740 | return 0; | ||
741 | } | ||
742 | EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); | ||
743 | |||
744 | int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, | ||
745 | unsigned int size, unsigned int __user *tlv) | ||
746 | { | ||
747 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
748 | unsigned int count = size < params->max ? size : params->max; | ||
749 | int ret = -ENXIO; | ||
750 | |||
751 | switch (op_flag) { | ||
752 | case SNDRV_CTL_TLV_OP_READ: | ||
753 | if (params->get) | ||
754 | ret = params->get(tlv, count); | ||
755 | break; | ||
756 | case SNDRV_CTL_TLV_OP_WRITE: | ||
757 | if (params->put) | ||
758 | ret = params->put(tlv, count); | ||
759 | break; | ||
760 | } | ||
761 | return ret; | ||
762 | } | ||
763 | EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); | ||
764 | |||
765 | /** | ||
766 | * snd_soc_info_xr_sx - signed multi register info callback | ||
767 | * @kcontrol: mreg control | ||
768 | * @uinfo: control element information | ||
769 | * | ||
770 | * Callback to provide information of a control that can | ||
771 | * span multiple codec registers which together | ||
772 | * forms a single signed value in a MSB/LSB manner. | ||
773 | * | ||
774 | * Returns 0 for success. | ||
775 | */ | ||
776 | int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, | ||
777 | struct snd_ctl_elem_info *uinfo) | ||
778 | { | ||
779 | struct soc_mreg_control *mc = | ||
780 | (struct soc_mreg_control *)kcontrol->private_value; | ||
781 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
782 | uinfo->count = 1; | ||
783 | uinfo->value.integer.min = mc->min; | ||
784 | uinfo->value.integer.max = mc->max; | ||
785 | |||
786 | return 0; | ||
787 | } | ||
788 | EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); | ||
789 | |||
790 | /** | ||
791 | * snd_soc_get_xr_sx - signed multi register get callback | ||
792 | * @kcontrol: mreg control | ||
793 | * @ucontrol: control element information | ||
794 | * | ||
795 | * Callback to get the value of a control that can span | ||
796 | * multiple codec registers which together forms a single | ||
797 | * signed value in a MSB/LSB manner. The control supports | ||
798 | * specifying total no of bits used to allow for bitfields | ||
799 | * across the multiple codec registers. | ||
800 | * | ||
801 | * Returns 0 for success. | ||
802 | */ | ||
803 | int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, | ||
804 | struct snd_ctl_elem_value *ucontrol) | ||
805 | { | ||
806 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
807 | struct soc_mreg_control *mc = | ||
808 | (struct soc_mreg_control *)kcontrol->private_value; | ||
809 | unsigned int regbase = mc->regbase; | ||
810 | unsigned int regcount = mc->regcount; | ||
811 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
812 | unsigned int regwmask = (1<<regwshift)-1; | ||
813 | unsigned int invert = mc->invert; | ||
814 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
815 | long min = mc->min; | ||
816 | long max = mc->max; | ||
817 | long val = 0; | ||
818 | unsigned int regval; | ||
819 | unsigned int i; | ||
820 | int ret; | ||
821 | |||
822 | for (i = 0; i < regcount; i++) { | ||
823 | ret = snd_soc_component_read(component, regbase+i, ®val); | ||
824 | if (ret) | ||
825 | return ret; | ||
826 | val |= (regval & regwmask) << (regwshift*(regcount-i-1)); | ||
827 | } | ||
828 | val &= mask; | ||
829 | if (min < 0 && val > max) | ||
830 | val |= ~mask; | ||
831 | if (invert) | ||
832 | val = max - val; | ||
833 | ucontrol->value.integer.value[0] = val; | ||
834 | |||
835 | return 0; | ||
836 | } | ||
837 | EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); | ||
838 | |||
839 | /** | ||
840 | * snd_soc_put_xr_sx - signed multi register get callback | ||
841 | * @kcontrol: mreg control | ||
842 | * @ucontrol: control element information | ||
843 | * | ||
844 | * Callback to set the value of a control that can span | ||
845 | * multiple codec registers which together forms a single | ||
846 | * signed value in a MSB/LSB manner. The control supports | ||
847 | * specifying total no of bits used to allow for bitfields | ||
848 | * across the multiple codec registers. | ||
849 | * | ||
850 | * Returns 0 for success. | ||
851 | */ | ||
852 | int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, | ||
853 | struct snd_ctl_elem_value *ucontrol) | ||
854 | { | ||
855 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
856 | struct soc_mreg_control *mc = | ||
857 | (struct soc_mreg_control *)kcontrol->private_value; | ||
858 | unsigned int regbase = mc->regbase; | ||
859 | unsigned int regcount = mc->regcount; | ||
860 | unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; | ||
861 | unsigned int regwmask = (1<<regwshift)-1; | ||
862 | unsigned int invert = mc->invert; | ||
863 | unsigned long mask = (1UL<<mc->nbits)-1; | ||
864 | long max = mc->max; | ||
865 | long val = ucontrol->value.integer.value[0]; | ||
866 | unsigned int i, regval, regmask; | ||
867 | int err; | ||
868 | |||
869 | if (invert) | ||
870 | val = max - val; | ||
871 | val &= mask; | ||
872 | for (i = 0; i < regcount; i++) { | ||
873 | regval = (val >> (regwshift*(regcount-i-1))) & regwmask; | ||
874 | regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; | ||
875 | err = snd_soc_component_update_bits(component, regbase+i, | ||
876 | regmask, regval); | ||
877 | if (err < 0) | ||
878 | return err; | ||
879 | } | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); | ||
884 | |||
885 | /** | ||
886 | * snd_soc_get_strobe - strobe get callback | ||
887 | * @kcontrol: mixer control | ||
888 | * @ucontrol: control element information | ||
889 | * | ||
890 | * Callback get the value of a strobe mixer control. | ||
891 | * | ||
892 | * Returns 0 for success. | ||
893 | */ | ||
894 | int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, | ||
895 | struct snd_ctl_elem_value *ucontrol) | ||
896 | { | ||
897 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
898 | struct soc_mixer_control *mc = | ||
899 | (struct soc_mixer_control *)kcontrol->private_value; | ||
900 | unsigned int reg = mc->reg; | ||
901 | unsigned int shift = mc->shift; | ||
902 | unsigned int mask = 1 << shift; | ||
903 | unsigned int invert = mc->invert != 0; | ||
904 | unsigned int val; | ||
905 | int ret; | ||
906 | |||
907 | ret = snd_soc_component_read(component, reg, &val); | ||
908 | if (ret) | ||
909 | return ret; | ||
910 | |||
911 | val &= mask; | ||
912 | |||
913 | if (shift != 0 && val != 0) | ||
914 | val = val >> shift; | ||
915 | ucontrol->value.enumerated.item[0] = val ^ invert; | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | EXPORT_SYMBOL_GPL(snd_soc_get_strobe); | ||
920 | |||
921 | /** | ||
922 | * snd_soc_put_strobe - strobe put callback | ||
923 | * @kcontrol: mixer control | ||
924 | * @ucontrol: control element information | ||
925 | * | ||
926 | * Callback strobe a register bit to high then low (or the inverse) | ||
927 | * in one pass of a single mixer enum control. | ||
928 | * | ||
929 | * Returns 1 for success. | ||
930 | */ | ||
931 | int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, | ||
932 | struct snd_ctl_elem_value *ucontrol) | ||
933 | { | ||
934 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
935 | struct soc_mixer_control *mc = | ||
936 | (struct soc_mixer_control *)kcontrol->private_value; | ||
937 | unsigned int reg = mc->reg; | ||
938 | unsigned int shift = mc->shift; | ||
939 | unsigned int mask = 1 << shift; | ||
940 | unsigned int invert = mc->invert != 0; | ||
941 | unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; | ||
942 | unsigned int val1 = (strobe ^ invert) ? mask : 0; | ||
943 | unsigned int val2 = (strobe ^ invert) ? 0 : mask; | ||
944 | int err; | ||
945 | |||
946 | err = snd_soc_component_update_bits(component, reg, mask, val1); | ||
947 | if (err < 0) | ||
948 | return err; | ||
949 | |||
950 | return snd_soc_component_update_bits(component, reg, mask, val2); | ||
951 | } | ||
952 | EXPORT_SYMBOL_GPL(snd_soc_put_strobe); | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 57277dd79e11..eb87d96e2cf0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
654 | codec_dai->rate = 0; | 654 | codec_dai->rate = 0; |
655 | } | 655 | } |
656 | 656 | ||
657 | snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream); | ||
658 | |||
657 | if (cpu_dai->driver->ops->shutdown) | 659 | if (cpu_dai->driver->ops->shutdown) |
658 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); | 660 | cpu_dai->driver->ops->shutdown(substream, cpu_dai); |
659 | 661 | ||
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) | |||
772 | for (i = 0; i < rtd->num_codecs; i++) | 774 | for (i = 0; i < rtd->num_codecs; i++) |
773 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, | 775 | snd_soc_dai_digital_mute(rtd->codec_dais[i], 0, |
774 | substream->stream); | 776 | substream->stream); |
777 | snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream); | ||
775 | 778 | ||
776 | out: | 779 | out: |
777 | mutex_unlock(&rtd->pcm_mutex); | 780 | mutex_unlock(&rtd->pcm_mutex); |
@@ -1664,6 +1667,10 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) | |||
1664 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) | 1667 | if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream)) |
1665 | continue; | 1668 | continue; |
1666 | 1669 | ||
1670 | /* do not free hw if this BE is used by other FE */ | ||
1671 | if (be->dpcm[stream].users > 1) | ||
1672 | continue; | ||
1673 | |||
1667 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && | 1674 | if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) && |
1668 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && | 1675 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) && |
1669 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && | 1676 | (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) && |
@@ -2288,7 +2295,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2288 | fe->dai_link->name); | 2295 | fe->dai_link->name); |
2289 | 2296 | ||
2290 | /* skip if FE doesn't have playback capability */ | 2297 | /* skip if FE doesn't have playback capability */ |
2291 | if (!fe->cpu_dai->driver->playback.channels_min) | 2298 | if (!fe->cpu_dai->driver->playback.channels_min |
2299 | || !fe->codec_dai->driver->playback.channels_min) | ||
2300 | goto capture; | ||
2301 | |||
2302 | /* skip if FE isn't currently playing */ | ||
2303 | if (!fe->cpu_dai->playback_active | ||
2304 | || !fe->codec_dai->playback_active) | ||
2292 | goto capture; | 2305 | goto capture; |
2293 | 2306 | ||
2294 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); | 2307 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); |
@@ -2318,7 +2331,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
2318 | dpcm_path_put(&list); | 2331 | dpcm_path_put(&list); |
2319 | capture: | 2332 | capture: |
2320 | /* skip if FE doesn't have capture capability */ | 2333 | /* skip if FE doesn't have capture capability */ |
2321 | if (!fe->cpu_dai->driver->capture.channels_min) | 2334 | if (!fe->cpu_dai->driver->capture.channels_min |
2335 | || !fe->codec_dai->driver->capture.channels_min) | ||
2336 | continue; | ||
2337 | |||
2338 | /* skip if FE isn't currently capturing */ | ||
2339 | if (!fe->cpu_dai->capture_active | ||
2340 | || !fe->codec_dai->capture_active) | ||
2322 | continue; | 2341 | continue; |
2323 | 2342 | ||
2324 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); | 2343 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); |
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c index 3b0fa12dbff7..29a9957d335a 100644 --- a/sound/soc/tegra/tegra20_ac97.c +++ b/sound/soc/tegra/tegra20_ac97.c | |||
@@ -228,7 +228,7 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai) | |||
228 | 228 | ||
229 | static struct snd_soc_dai_driver tegra20_ac97_dai = { | 229 | static struct snd_soc_dai_driver tegra20_ac97_dai = { |
230 | .name = "tegra-ac97-pcm", | 230 | .name = "tegra-ac97-pcm", |
231 | .ac97_control = 1, | 231 | .bus_control = true, |
232 | .probe = tegra20_ac97_probe, | 232 | .probe = tegra20_ac97_probe, |
233 | .playback = { | 233 | .playback = { |
234 | .stream_name = "PCM Playback", | 234 | .stream_name = "PCM Playback", |
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c index a6898831fb9f..4ebe3871e610 100644 --- a/sound/soc/tegra/tegra_rt5640.c +++ b/sound/soc/tegra/tegra_rt5640.c | |||
@@ -44,6 +44,7 @@ | |||
44 | struct tegra_rt5640 { | 44 | struct tegra_rt5640 { |
45 | struct tegra_asoc_utils_data util_data; | 45 | struct tegra_asoc_utils_data util_data; |
46 | int gpio_hp_det; | 46 | int gpio_hp_det; |
47 | enum of_gpio_flags gpio_hp_det_flags; | ||
47 | }; | 48 | }; |
48 | 49 | ||
49 | static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, | 50 | static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream, |
@@ -119,6 +120,8 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
119 | 120 | ||
120 | if (gpio_is_valid(machine->gpio_hp_det)) { | 121 | if (gpio_is_valid(machine->gpio_hp_det)) { |
121 | tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; | 122 | tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det; |
123 | tegra_rt5640_hp_jack_gpio.invert = | ||
124 | !!(machine->gpio_hp_det_flags & OF_GPIO_ACTIVE_LOW); | ||
122 | snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, | 125 | snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack, |
123 | 1, | 126 | 1, |
124 | &tegra_rt5640_hp_jack_gpio); | 127 | &tegra_rt5640_hp_jack_gpio); |
@@ -180,7 +183,8 @@ static int tegra_rt5640_probe(struct platform_device *pdev) | |||
180 | platform_set_drvdata(pdev, card); | 183 | platform_set_drvdata(pdev, card); |
181 | snd_soc_card_set_drvdata(card, machine); | 184 | snd_soc_card_set_drvdata(card, machine); |
182 | 185 | ||
183 | machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); | 186 | machine->gpio_hp_det = of_get_named_gpio_flags( |
187 | np, "nvidia,hp-det-gpios", 0, &machine->gpio_hp_det_flags); | ||
184 | if (machine->gpio_hp_det == -EPROBE_DEFER) | 188 | if (machine->gpio_hp_det == -EPROBE_DEFER) |
185 | return -EPROBE_DEFER; | 189 | return -EPROBE_DEFER; |
186 | 190 | ||
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index 9edd68db9f48..f7135cdaa2ca 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c | |||
@@ -152,7 +152,7 @@ static int txx9aclc_ac97_remove(struct snd_soc_dai *dai) | |||
152 | } | 152 | } |
153 | 153 | ||
154 | static struct snd_soc_dai_driver txx9aclc_ac97_dai = { | 154 | static struct snd_soc_dai_driver txx9aclc_ac97_dai = { |
155 | .ac97_control = 1, | 155 | .bus_control = true, |
156 | .probe = txx9aclc_ac97_probe, | 156 | .probe = txx9aclc_ac97_probe, |
157 | .remove = txx9aclc_ac97_remove, | 157 | .remove = txx9aclc_ac97_remove, |
158 | .playback = { | 158 | .playback = { |
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index cd71fd889d8b..00b7e2d02690 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c | |||
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
292 | struct snd_card *card = rtd->card->snd_card; | 292 | struct snd_card *card = rtd->card->snd_card; |
293 | struct snd_soc_dai *dai = rtd->cpu_dai; | 293 | struct snd_soc_dai *dai = rtd->cpu_dai; |
294 | struct snd_pcm *pcm = rtd->pcm; | 294 | struct snd_pcm *pcm = rtd->pcm; |
295 | struct platform_device *pdev = to_platform_device(dai->platform->dev); | 295 | struct platform_device *pdev = to_platform_device(rtd->platform->dev); |
296 | struct txx9aclc_soc_device *dev; | 296 | struct txx9aclc_soc_device *dev; |
297 | struct resource *r; | 297 | struct resource *r; |
298 | int i; | 298 | int i; |
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c index b3b66aa98dce..9f2d045ee118 100644 --- a/sound/soc/ux500/mop500.c +++ b/sound/soc/ux500/mop500.c | |||
@@ -63,12 +63,8 @@ static void mop500_of_node_put(void) | |||
63 | int i; | 63 | int i; |
64 | 64 | ||
65 | for (i = 0; i < 2; i++) { | 65 | for (i = 0; i < 2; i++) { |
66 | if (mop500_dai_links[i].cpu_of_node) | 66 | of_node_put(mop500_dai_links[i].cpu_of_node); |
67 | of_node_put((struct device_node *) | 67 | of_node_put(mop500_dai_links[i].codec_of_node); |
68 | mop500_dai_links[i].cpu_of_node); | ||
69 | if (mop500_dai_links[i].codec_of_node) | ||
70 | of_node_put((struct device_node *) | ||
71 | mop500_dai_links[i].codec_of_node); | ||
72 | } | 68 | } |
73 | } | 69 | } |
74 | 70 | ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 7c83bab69dee..8c9bf4b7aaf0 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -593,10 +593,10 @@ static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol, | |||
593 | if (mixer->chip->shutdown) | 593 | if (mixer->chip->shutdown) |
594 | ret = -ENODEV; | 594 | ret = -ENODEV; |
595 | else | 595 | else |
596 | ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, | 596 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest, |
597 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, | 597 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
598 | 0, wIndex, | 598 | 0, wIndex, |
599 | &tmp, sizeof(tmp), 1000); | 599 | &tmp, sizeof(tmp)); |
600 | up_read(&mixer->chip->shutdown_rwsem); | 600 | up_read(&mixer->chip->shutdown_rwsem); |
601 | 601 | ||
602 | if (ret < 0) { | 602 | if (ret < 0) { |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index a5941f80fc5b..60dfe0d28771 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -1193,12 +1193,12 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1193 | /* iFi Audio micro/nano iDSD */ | 1193 | /* iFi Audio micro/nano iDSD */ |
1194 | case USB_ID(0x20b1, 0x3008): | 1194 | case USB_ID(0x20b1, 0x3008): |
1195 | if (fp->altsetting == 2) | 1195 | if (fp->altsetting == 2) |
1196 | return SNDRV_PCM_FMTBIT_DSD_U32_LE; | 1196 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1197 | break; | 1197 | break; |
1198 | /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ | 1198 | /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ |
1199 | case USB_ID(0x20b1, 0x2009): | 1199 | case USB_ID(0x20b1, 0x2009): |
1200 | if (fp->altsetting == 3) | 1200 | if (fp->altsetting == 3) |
1201 | return SNDRV_PCM_FMTBIT_DSD_U32_LE; | 1201 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1202 | break; | 1202 | break; |
1203 | default: | 1203 | default: |
1204 | break; | 1204 | break; |
diff --git a/virt/kvm/arm/vgic.c b/virt/kvm/arm/vgic.c index 3aaca49de325..aacdb59f30de 100644 --- a/virt/kvm/arm/vgic.c +++ b/virt/kvm/arm/vgic.c | |||
@@ -1933,7 +1933,7 @@ out: | |||
1933 | 1933 | ||
1934 | int kvm_vgic_create(struct kvm *kvm) | 1934 | int kvm_vgic_create(struct kvm *kvm) |
1935 | { | 1935 | { |
1936 | int i, vcpu_lock_idx = -1, ret = 0; | 1936 | int i, vcpu_lock_idx = -1, ret; |
1937 | struct kvm_vcpu *vcpu; | 1937 | struct kvm_vcpu *vcpu; |
1938 | 1938 | ||
1939 | mutex_lock(&kvm->lock); | 1939 | mutex_lock(&kvm->lock); |
@@ -1948,6 +1948,7 @@ int kvm_vgic_create(struct kvm *kvm) | |||
1948 | * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure | 1948 | * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure |
1949 | * that no other VCPUs are run while we create the vgic. | 1949 | * that no other VCPUs are run while we create the vgic. |
1950 | */ | 1950 | */ |
1951 | ret = -EBUSY; | ||
1951 | kvm_for_each_vcpu(i, vcpu, kvm) { | 1952 | kvm_for_each_vcpu(i, vcpu, kvm) { |
1952 | if (!mutex_trylock(&vcpu->mutex)) | 1953 | if (!mutex_trylock(&vcpu->mutex)) |
1953 | goto out_unlock; | 1954 | goto out_unlock; |
@@ -1955,11 +1956,10 @@ int kvm_vgic_create(struct kvm *kvm) | |||
1955 | } | 1956 | } |
1956 | 1957 | ||
1957 | kvm_for_each_vcpu(i, vcpu, kvm) { | 1958 | kvm_for_each_vcpu(i, vcpu, kvm) { |
1958 | if (vcpu->arch.has_run_once) { | 1959 | if (vcpu->arch.has_run_once) |
1959 | ret = -EBUSY; | ||
1960 | goto out_unlock; | 1960 | goto out_unlock; |
1961 | } | ||
1962 | } | 1961 | } |
1962 | ret = 0; | ||
1963 | 1963 | ||
1964 | spin_lock_init(&kvm->arch.vgic.lock); | 1964 | spin_lock_init(&kvm->arch.vgic.lock); |
1965 | kvm->arch.vgic.in_kernel = true; | 1965 | kvm->arch.vgic.in_kernel = true; |
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 25ffac9e947d..3cee7b167052 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -107,10 +107,10 @@ EXPORT_SYMBOL_GPL(kvm_rebooting); | |||
107 | 107 | ||
108 | static bool largepages_enabled = true; | 108 | static bool largepages_enabled = true; |
109 | 109 | ||
110 | bool kvm_is_mmio_pfn(pfn_t pfn) | 110 | bool kvm_is_reserved_pfn(pfn_t pfn) |
111 | { | 111 | { |
112 | if (pfn_valid(pfn)) | 112 | if (pfn_valid(pfn)) |
113 | return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn)); | 113 | return PageReserved(pfn_to_page(pfn)); |
114 | 114 | ||
115 | return true; | 115 | return true; |
116 | } | 116 | } |
@@ -1321,7 +1321,7 @@ static pfn_t hva_to_pfn(unsigned long addr, bool atomic, bool *async, | |||
1321 | else if ((vma->vm_flags & VM_PFNMAP)) { | 1321 | else if ((vma->vm_flags & VM_PFNMAP)) { |
1322 | pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + | 1322 | pfn = ((addr - vma->vm_start) >> PAGE_SHIFT) + |
1323 | vma->vm_pgoff; | 1323 | vma->vm_pgoff; |
1324 | BUG_ON(!kvm_is_mmio_pfn(pfn)); | 1324 | BUG_ON(!kvm_is_reserved_pfn(pfn)); |
1325 | } else { | 1325 | } else { |
1326 | if (async && vma_is_valid(vma, write_fault)) | 1326 | if (async && vma_is_valid(vma, write_fault)) |
1327 | *async = true; | 1327 | *async = true; |
@@ -1427,7 +1427,7 @@ static struct page *kvm_pfn_to_page(pfn_t pfn) | |||
1427 | if (is_error_noslot_pfn(pfn)) | 1427 | if (is_error_noslot_pfn(pfn)) |
1428 | return KVM_ERR_PTR_BAD_PAGE; | 1428 | return KVM_ERR_PTR_BAD_PAGE; |
1429 | 1429 | ||
1430 | if (kvm_is_mmio_pfn(pfn)) { | 1430 | if (kvm_is_reserved_pfn(pfn)) { |
1431 | WARN_ON(1); | 1431 | WARN_ON(1); |
1432 | return KVM_ERR_PTR_BAD_PAGE; | 1432 | return KVM_ERR_PTR_BAD_PAGE; |
1433 | } | 1433 | } |
@@ -1456,7 +1456,7 @@ EXPORT_SYMBOL_GPL(kvm_release_page_clean); | |||
1456 | 1456 | ||
1457 | void kvm_release_pfn_clean(pfn_t pfn) | 1457 | void kvm_release_pfn_clean(pfn_t pfn) |
1458 | { | 1458 | { |
1459 | if (!is_error_noslot_pfn(pfn) && !kvm_is_mmio_pfn(pfn)) | 1459 | if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn)) |
1460 | put_page(pfn_to_page(pfn)); | 1460 | put_page(pfn_to_page(pfn)); |
1461 | } | 1461 | } |
1462 | EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); | 1462 | EXPORT_SYMBOL_GPL(kvm_release_pfn_clean); |
@@ -1477,7 +1477,7 @@ static void kvm_release_pfn_dirty(pfn_t pfn) | |||
1477 | 1477 | ||
1478 | void kvm_set_pfn_dirty(pfn_t pfn) | 1478 | void kvm_set_pfn_dirty(pfn_t pfn) |
1479 | { | 1479 | { |
1480 | if (!kvm_is_mmio_pfn(pfn)) { | 1480 | if (!kvm_is_reserved_pfn(pfn)) { |
1481 | struct page *page = pfn_to_page(pfn); | 1481 | struct page *page = pfn_to_page(pfn); |
1482 | if (!PageReserved(page)) | 1482 | if (!PageReserved(page)) |
1483 | SetPageDirty(page); | 1483 | SetPageDirty(page); |
@@ -1487,14 +1487,14 @@ EXPORT_SYMBOL_GPL(kvm_set_pfn_dirty); | |||
1487 | 1487 | ||
1488 | void kvm_set_pfn_accessed(pfn_t pfn) | 1488 | void kvm_set_pfn_accessed(pfn_t pfn) |
1489 | { | 1489 | { |
1490 | if (!kvm_is_mmio_pfn(pfn)) | 1490 | if (!kvm_is_reserved_pfn(pfn)) |
1491 | mark_page_accessed(pfn_to_page(pfn)); | 1491 | mark_page_accessed(pfn_to_page(pfn)); |
1492 | } | 1492 | } |
1493 | EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); | 1493 | EXPORT_SYMBOL_GPL(kvm_set_pfn_accessed); |
1494 | 1494 | ||
1495 | void kvm_get_pfn(pfn_t pfn) | 1495 | void kvm_get_pfn(pfn_t pfn) |
1496 | { | 1496 | { |
1497 | if (!kvm_is_mmio_pfn(pfn)) | 1497 | if (!kvm_is_reserved_pfn(pfn)) |
1498 | get_page(pfn_to_page(pfn)); | 1498 | get_page(pfn_to_page(pfn)); |
1499 | } | 1499 | } |
1500 | EXPORT_SYMBOL_GPL(kvm_get_pfn); | 1500 | EXPORT_SYMBOL_GPL(kvm_get_pfn); |