diff options
241 files changed, 19420 insertions, 3301 deletions
diff --git a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt index 8dbce0e18dda..1447dec28125 100644 --- a/Documentation/devicetree/bindings/sound/adi,adau17x1.txt +++ b/Documentation/devicetree/bindings/sound/adi,adau17x1.txt | |||
@@ -13,6 +13,11 @@ Required properties: | |||
13 | - reg: The i2c address. Value depends on the state of ADDR0 | 13 | - reg: The i2c address. Value depends on the state of ADDR0 |
14 | and ADDR1, as wired in hardware. | 14 | and ADDR1, as wired in hardware. |
15 | 15 | ||
16 | Optional properties: | ||
17 | - clock-names: If provided must be "mclk". | ||
18 | - clocks: phandle + clock-specifiers for the clock that provides | ||
19 | the audio master clock for the device. | ||
20 | |||
16 | Examples: | 21 | Examples: |
17 | #include <dt-bindings/sound/adau17x1.h> | 22 | #include <dt-bindings/sound/adau17x1.h> |
18 | 23 | ||
@@ -20,5 +25,8 @@ Examples: | |||
20 | adau1361@38 { | 25 | adau1361@38 { |
21 | compatible = "adi,adau1761"; | 26 | compatible = "adi,adau1761"; |
22 | reg = <0x38>; | 27 | reg = <0x38>; |
28 | |||
29 | clock-names = "mclk"; | ||
30 | clocks = <&audio_clock>; | ||
23 | }; | 31 | }; |
24 | }; | 32 | }; |
diff --git a/Documentation/devicetree/bindings/sound/adi,adau7002.txt b/Documentation/devicetree/bindings/sound/adi,adau7002.txt new file mode 100644 index 000000000000..f144ee1abf85 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/adi,adau7002.txt | |||
@@ -0,0 +1,19 @@ | |||
1 | Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible: Must be "adi,adau7002" | ||
6 | |||
7 | Optional properties: | ||
8 | |||
9 | - IOVDD-supply: Phandle and specifier for the power supply providing the IOVDD | ||
10 | supply as covered in Documentation/devicetree/bindings/regulator/regulator.txt | ||
11 | |||
12 | If this property is not present it is assumed that the supply pin is | ||
13 | hardwired to always on. | ||
14 | |||
15 | Example: | ||
16 | adau7002: pdm-to-i2s { | ||
17 | compatible = "adi,adau7002"; | ||
18 | IOVDD-supply = <&supply>; | ||
19 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt new file mode 100644 index 000000000000..b139e66d2a11 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/brcm,cygnus-audio.txt | |||
@@ -0,0 +1,67 @@ | |||
1 | BROADCOM Cygnus Audio I2S/TDM/SPDIF controller | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "brcm,cygnus-audio" | ||
5 | - #address-cells: 32bit valued, 1 cell. | ||
6 | - #size-cells: 32bit valued, 0 cell. | ||
7 | - reg : Should contain audio registers location and length | ||
8 | - reg-names: names of the registers listed in "reg" property | ||
9 | Valid names are "aud" and "i2s_in". "aud" contains a | ||
10 | set of DMA, I2S_OUT and SPDIF registers. "i2s_in" contains | ||
11 | a set of I2S_IN registers. | ||
12 | - clocks: PLL and leaf clocks used by audio ports | ||
13 | - assigned-clocks: PLL and leaf clocks | ||
14 | - assigned-clock-parents: parent clocks of the assigned clocks | ||
15 | (usually the PLL) | ||
16 | - assigned-clock-rates: List of clock frequencies of the | ||
17 | assigned clocks | ||
18 | - clock-names: names of 3 leaf clocks used by audio ports | ||
19 | Valid names are "ch0_audio", "ch1_audio", "ch2_audio" | ||
20 | - interrupts: audio DMA interrupt number | ||
21 | |||
22 | SSP Subnode properties: | ||
23 | - reg: The index of ssp port interface to use | ||
24 | Valid value are 0, 1, 2, or 3 (for spdif) | ||
25 | |||
26 | Example: | ||
27 | cygnus_audio: audio@180ae000 { | ||
28 | compatible = "brcm,cygnus-audio"; | ||
29 | #address-cells = <1>; | ||
30 | #size-cells = <0>; | ||
31 | reg = <0x180ae000 0xafd>, <0x180aec00 0x1f8>; | ||
32 | reg-names = "aud", "i2s_in"; | ||
33 | clocks = <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>, | ||
34 | <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>, | ||
35 | <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>; | ||
36 | assigned-clocks = <&audiopll BCM_CYGNUS_AUDIOPLL>, | ||
37 | <&audiopll BCM_CYGNUS_AUDIOPLL_CH0>, | ||
38 | <&audiopll BCM_CYGNUS_AUDIOPLL_CH1>, | ||
39 | <&audiopll BCM_CYGNUS_AUDIOPLL_CH2>; | ||
40 | assigned-clock-parents = <&audiopll BCM_CYGNUS_AUDIOPLL>; | ||
41 | assigned-clock-rates = <1769470191>, | ||
42 | <0>, | ||
43 | <0>, | ||
44 | <0>; | ||
45 | clock-names = "ch0_audio", "ch1_audio", "ch2_audio"; | ||
46 | interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>; | ||
47 | |||
48 | ssp0: ssp_port@0 { | ||
49 | reg = <0>; | ||
50 | status = "okay"; | ||
51 | }; | ||
52 | |||
53 | ssp1: ssp_port@1 { | ||
54 | reg = <1>; | ||
55 | status = "disabled"; | ||
56 | }; | ||
57 | |||
58 | ssp2: ssp_port@2 { | ||
59 | reg = <2>; | ||
60 | status = "disabled"; | ||
61 | }; | ||
62 | |||
63 | spdif: spdif_port@3 { | ||
64 | reg = <3>; | ||
65 | status = "disabled"; | ||
66 | }; | ||
67 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/bt-sco.txt b/Documentation/devicetree/bindings/sound/bt-sco.txt index 29b8e5d40203..641edf75e184 100644 --- a/Documentation/devicetree/bindings/sound/bt-sco.txt +++ b/Documentation/devicetree/bindings/sound/bt-sco.txt | |||
@@ -4,7 +4,7 @@ This device support generic Bluetooth SCO link. | |||
4 | 4 | ||
5 | Required properties: | 5 | Required properties: |
6 | 6 | ||
7 | - compatible : "delta,dfbmcs320" | 7 | - compatible : "delta,dfbmcs320" or "linux,bt-sco" |
8 | 8 | ||
9 | Example: | 9 | Example: |
10 | 10 | ||
diff --git a/Documentation/devicetree/bindings/sound/cs35l33.txt b/Documentation/devicetree/bindings/sound/cs35l33.txt new file mode 100644 index 000000000000..acfb47525b49 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs35l33.txt | |||
@@ -0,0 +1,126 @@ | |||
1 | CS35L33 Speaker Amplifier | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible : "cirrus,cs35l33" | ||
6 | |||
7 | - reg : the I2C address of the device for I2C | ||
8 | |||
9 | - VA-supply, VP-supply : power supplies for the device, | ||
10 | as covered in | ||
11 | Documentation/devicetree/bindings/regulator/regulator.txt. | ||
12 | |||
13 | Optional properties: | ||
14 | |||
15 | - reset-gpios : gpio used to reset the amplifier | ||
16 | |||
17 | - interrupt-parent : Specifies the phandle of the interrupt controller to | ||
18 | which the IRQs from CS35L33 are delivered to. | ||
19 | - interrupts : IRQ line info CS35L33. | ||
20 | (See Documentation/devicetree/bindings/interrupt-controller/interrupts.txt | ||
21 | for further information relating to interrupt properties) | ||
22 | |||
23 | - cirrus,boost-ctl : Booster voltage use to supply the amp. If the value is | ||
24 | 0, then VBST = VP. If greater than 0, the boost voltage will be 3300mV with | ||
25 | a value of 1 and will increase at a step size of 100mV until a maximum of | ||
26 | 8000mV. | ||
27 | |||
28 | - cirrus,ramp-rate : On power up, it affects the time from when the power | ||
29 | up sequence begins to the time the audio reaches a full-scale output. | ||
30 | On power down, it affects the time from when the power-down sequence | ||
31 | begins to when the amplifier disables the PWM outputs. If this property | ||
32 | is not set then soft ramping will be disabled and ramp time would be | ||
33 | 20ms. If this property is set to 0,1,2,3 then ramp times would be 40ms, | ||
34 | 60ms,100ms,175ms respectively for 48KHz sample rate. | ||
35 | |||
36 | - cirrus,boost-ipk : The maximum current allowed for the boost converter. | ||
37 | The range starts at 1850000uA and goes to a maximum of 3600000uA | ||
38 | with a step size of 15625uA. The default is 2500000uA. | ||
39 | |||
40 | - cirrus,imon-adc-scale : Configures the scaling of data bits from the IMON | ||
41 | ADC data word. This property can be set as a value of 0 for bits 15 down | ||
42 | to 0, 6 for 21 down to 6, 7, for 22 down to 7, 8 for 23 down to 8. | ||
43 | |||
44 | |||
45 | Optional H/G Algorithm sub-node: | ||
46 | |||
47 | The cs35l33 node can have a single "cirrus,hg-algo" sub-node that will enable | ||
48 | the internal H/G Algorithm. | ||
49 | |||
50 | - cirrus,hg-algo : Sub-node for internal Class H/G algorithm that | ||
51 | controls the amplifier supplies. | ||
52 | |||
53 | Optional properties for the "cirrus,hg-algo" sub-node: | ||
54 | |||
55 | - cirrus,mem-depth : Memory depth for the Class H/G algorithm measured in | ||
56 | LRCLK cycles. If this property is set to 0, 1, 2, or 3 then the memory | ||
57 | depths will be 1, 4, 8, 16 LRCLK cycles. The default is 16 LRCLK cycles. | ||
58 | |||
59 | cirrus,release-rate : The number of consecutive LRCLK periods before | ||
60 | allowing release condition tracking updates. The number of LRCLK periods | ||
61 | start at 3 to a maximum of 255. | ||
62 | |||
63 | - cirrus,ldo-thld : Configures the signal threshold at which the PWM output | ||
64 | stage enters LDO operation. Starts as a default value of 50mV for a value | ||
65 | of 1 and increases with a step size of 50mV to a maximum of 750mV (value of | ||
66 | 0xF). | ||
67 | |||
68 | - cirrus,ldo-path-disable : This is a boolean property. If present, the H/G | ||
69 | algorithm uses the max detection path. If not present, the LDO | ||
70 | detection path is used. | ||
71 | |||
72 | - cirrus,ldo-entry-delay : The LDO entry delay in milliseconds before the H/G | ||
73 | algorithm switches to the LDO voltage. This property can be set to values | ||
74 | from 0 to 7 for delays of 5ms, 10ms, 50ms, 100ms, 200ms, 500ms, 1000ms. | ||
75 | The default is 100ms. | ||
76 | |||
77 | - cirrus,vp-hg-auto : This is a boolean property. When set, class H/G VPhg | ||
78 | automatic updating is enabled. | ||
79 | |||
80 | - cirrus,vp-hg : Class H/G algorithm VPhg. Controls the H/G algorithm's | ||
81 | reference to the VP voltage for when to start generating a boosted VBST. | ||
82 | The reference voltage starts at 3000mV with a value of 0x3 and is increased | ||
83 | by 100mV per step to a maximum of 5500mV. | ||
84 | |||
85 | - cirrus,vp-hg-rate : The rate (number of LRCLK periods) at which the VPhg is | ||
86 | allowed to increase to a higher voltage when using VPhg automatic | ||
87 | tracking. This property can be set to values from 0 to 3 with rates of 128 | ||
88 | periods, 2048 periods, 32768 periods, and 524288 periods. | ||
89 | The default is 32768 periods. | ||
90 | |||
91 | - cirrus,vp-hg-va : VA calculation reference for automatic VPhg tracking | ||
92 | using VPMON. This property can be set to values from 0 to 6 starting at | ||
93 | 1800mV with a step size of 50mV up to a maximum value of 1750mV. | ||
94 | Default is 1800mV. | ||
95 | |||
96 | Example: | ||
97 | |||
98 | cs35l33: cs35l33@40 { | ||
99 | compatible = "cirrus,cs35l33"; | ||
100 | reg = <0x40>; | ||
101 | |||
102 | VA-supply = <&ldo5_reg>; | ||
103 | VP-supply = <&ldo5_reg>; | ||
104 | |||
105 | interrupt-parent = <&gpio8>; | ||
106 | interrupts = <3 IRQ_TYPE_LEVEL_LOW>; | ||
107 | |||
108 | reset-gpios = <&cs47l91 34 0>; | ||
109 | |||
110 | cirrus,ramp-rate = <0x0>; | ||
111 | cirrus,boost-ctl = <0x30>; /* VBST = 8000mV */ | ||
112 | cirrus,boost-ipk = <0xE0>; /* 3600mA */ | ||
113 | cirrus,imon-adc-scale = <0> /* Bits 15 down to 0 */ | ||
114 | |||
115 | cirrus,hg-algo { | ||
116 | cirrus,mem-depth = <0x3>; | ||
117 | cirrus,release-rate = <0x3>; | ||
118 | cirrus,ldo-thld = <0x1>; | ||
119 | cirrus,ldo-path-disable = <0x0>; | ||
120 | cirrus,ldo-entry-delay=<0x4>; | ||
121 | cirrus,vp-hg-auto; | ||
122 | cirrus,vp-hg=<0xF>; | ||
123 | cirrus,vp-hg-rate=<0x2>; | ||
124 | cirrus,vp-hg-va=<0x0>; | ||
125 | }; | ||
126 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/cs53l30.txt b/Documentation/devicetree/bindings/sound/cs53l30.txt new file mode 100644 index 000000000000..4dbfb8274cd9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs53l30.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | CS53L30 audio CODEC | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible : "cirrus,cs53l30" | ||
6 | |||
7 | - reg : the I2C address of the device | ||
8 | |||
9 | - VA-supply, VP-supply : power supplies for the device, | ||
10 | as covered in Documentation/devicetree/bindings/regulator/regulator.txt. | ||
11 | |||
12 | Optional properties: | ||
13 | |||
14 | - reset-gpios : a GPIO spec for the reset pin. | ||
15 | |||
16 | - mute-gpios : a GPIO spec for the MUTE pin. The active state can be either | ||
17 | GPIO_ACTIVE_HIGH or GPIO_ACTIVE_LOW, which would be handled | ||
18 | by the driver automatically. | ||
19 | |||
20 | - cirrus,micbias-lvl : Set the output voltage level on the MICBIAS Pin. | ||
21 | 0 = Hi-Z | ||
22 | 1 = 1.80 V | ||
23 | 2 = 2.75 V | ||
24 | |||
25 | - cirrus,use-sdout2 : This is a boolean property. If present, it indicates | ||
26 | the hardware design connects both SDOUT1 and SDOUT2 | ||
27 | pins to output data. Otherwise, it indicates that | ||
28 | only SDOUT1 is connected for data output. | ||
29 | * CS53l30 supports 4-channel data output in the same | ||
30 | * frame using two different ways: | ||
31 | * 1) Normal I2S mode on two data pins -- each SDOUT | ||
32 | * carries 2-channel data in the same time. | ||
33 | * 2) TDM mode on one signle data pin -- SDOUT1 carries | ||
34 | * 4-channel data per frame. | ||
35 | |||
36 | Example: | ||
37 | |||
38 | codec: cs53l30@48 { | ||
39 | compatible = "cirrus,cs53l30"; | ||
40 | reg = <0x48>; | ||
41 | reset-gpios = <&gpio 54 0>; | ||
42 | VA-supply = <&cs53l30_va>; | ||
43 | VP-supply = <&cs53l30_vp>; | ||
44 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/designware-i2s.txt b/Documentation/devicetree/bindings/sound/designware-i2s.txt index 7bb54247f8e8..6a536d570e29 100644 --- a/Documentation/devicetree/bindings/sound/designware-i2s.txt +++ b/Documentation/devicetree/bindings/sound/designware-i2s.txt | |||
@@ -12,6 +12,10 @@ Required properties: | |||
12 | one for receive. | 12 | one for receive. |
13 | - dma-names : "tx" for the transmit channel, "rx" for the receive channel. | 13 | - dma-names : "tx" for the transmit channel, "rx" for the receive channel. |
14 | 14 | ||
15 | Optional properties: | ||
16 | - interrupts: The interrupt line number for the I2S controller. Add this | ||
17 | parameter if the I2S controller that you are using does not support DMA. | ||
18 | |||
15 | For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' | 19 | For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' |
16 | properties please check: | 20 | properties please check: |
17 | * resource-names.txt | 21 | * resource-names.txt |
diff --git a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt index ceaef5126989..f749e2744824 100644 --- a/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/fsl-asoc-card.txt | |||
@@ -58,7 +58,7 @@ Required properties: | |||
58 | * DMIC (stands for Digital Microphone Jack) | 58 | * DMIC (stands for Digital Microphone Jack) |
59 | 59 | ||
60 | Note: The "Mic Jack" and "AMIC" are redundant while | 60 | Note: The "Mic Jack" and "AMIC" are redundant while |
61 | coexsiting in order to support the old bindings | 61 | coexisting in order to support the old bindings |
62 | of wm8962 and sgtl5000. | 62 | of wm8962 and sgtl5000. |
63 | 63 | ||
64 | Optional properties: | 64 | Optional properties: |
diff --git a/Documentation/devicetree/bindings/sound/max98504.txt b/Documentation/devicetree/bindings/sound/max98504.txt new file mode 100644 index 000000000000..583ed5fdfb28 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98504.txt | |||
@@ -0,0 +1,44 @@ | |||
1 | Maxim MAX98504 class D mono speaker amplifier | ||
2 | |||
3 | This device supports I2C control interface and an IRQ output signal. It features | ||
4 | a PCM and PDM digital audio interface (DAI) and a differential analog input. | ||
5 | |||
6 | Required properties: | ||
7 | |||
8 | - compatible : "maxim,max98504" | ||
9 | - reg : should contain the I2C slave device address | ||
10 | - DVDD-supply, DIOVDD-supply, PVDD-supply: power supplies for the device, | ||
11 | as covered in ../regulator/regulator.txt | ||
12 | - interrupts : should specify the interrupt line the device is connected to, | ||
13 | as described in ../interrupt-controller/interrupts.txt | ||
14 | |||
15 | Optional properties: | ||
16 | |||
17 | - maxim,brownout-threshold - the PVDD brownout threshold, the value must be | ||
18 | from 0, 1...21 range, corresponding to 2.6V, 2.65V...3.65V voltage range | ||
19 | - maxim,brownout-attenuation - the brownout attenuation to the speaker gain | ||
20 | applied during the "attack hold" and "timed hold" phase, the value must be | ||
21 | from 0...6 (dB) range | ||
22 | - maxim,brownout-attack-hold-ms - the brownout attack hold phase time in ms, | ||
23 | 0...255 (VBATBROWN_ATTK_HOLD, register 0x0018) | ||
24 | - maxim,brownout-timed-hold-ms - the brownout timed hold phase time in ms, | ||
25 | 0...255 (VBATBROWN_TIME_HOLD, register 0x0019) | ||
26 | - maxim,brownout-release-rate-ms - the brownout release phase step time in ms, | ||
27 | 0...255 (VBATBROWN_RELEASE, register 0x001A) | ||
28 | |||
29 | The default value when the above properties are not specified is 0, | ||
30 | the maxim,brownout-threshold property must be specified to actually enable | ||
31 | the PVDD brownout protection. | ||
32 | |||
33 | Example: | ||
34 | |||
35 | max98504@31 { | ||
36 | compatible = "maxim,max98504"; | ||
37 | reg = <0x31>; | ||
38 | interrupt-parent = <&gpio_bank_0>; | ||
39 | interrupts = <2 0>; | ||
40 | |||
41 | DVDD-supply = <®ulator>; | ||
42 | DIOVDD-supply = <®ulator>; | ||
43 | PVDD-supply = <®ulator>; | ||
44 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/max9860.txt b/Documentation/devicetree/bindings/sound/max9860.txt new file mode 100644 index 000000000000..e0d4e95e31b3 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max9860.txt | |||
@@ -0,0 +1,28 @@ | |||
1 | MAX9860 Mono Audio Voice Codec | ||
2 | |||
3 | Required properties: | ||
4 | |||
5 | - compatible : "maxim,max9860" | ||
6 | |||
7 | - reg : the I2C address of the device | ||
8 | |||
9 | - AVDD-supply, DVDD-supply and DVDDIO-supply : power supplies for | ||
10 | the device, as covered in bindings/regulator/regulator.txt | ||
11 | |||
12 | - clock-names : Required element: "mclk". | ||
13 | |||
14 | - clocks : A clock specifier for the clock connected as MCLK. | ||
15 | |||
16 | Examples: | ||
17 | |||
18 | max9860: max9860@10 { | ||
19 | compatible = "maxim,max9860"; | ||
20 | reg = <0x10>; | ||
21 | |||
22 | AVDD-supply = <®_1v8>; | ||
23 | DVDD-supply = <®_1v8>; | ||
24 | DVDDIO-supply = <®_3v0>; | ||
25 | |||
26 | clock-names = "mclk"; | ||
27 | clocks = <&pck2>; | ||
28 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt new file mode 100644 index 000000000000..3e623a724e55 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt2701-afe-pcm.txt | |||
@@ -0,0 +1,150 @@ | |||
1 | Mediatek AFE PCM controller for mt2701 | ||
2 | |||
3 | Required properties: | ||
4 | - compatible = "mediatek,mt2701-audio"; | ||
5 | - reg: register location and size | ||
6 | - interrupts: Should contain AFE interrupt | ||
7 | - clock-names: should have these clock names: | ||
8 | "infra_sys_audio_clk", | ||
9 | "top_audio_mux1_sel", | ||
10 | "top_audio_mux2_sel", | ||
11 | "top_audio_mux1_div", | ||
12 | "top_audio_mux2_div", | ||
13 | "top_audio_48k_timing", | ||
14 | "top_audio_44k_timing", | ||
15 | "top_audpll_mux_sel", | ||
16 | "top_apll_sel", | ||
17 | "top_aud1_pll_98M", | ||
18 | "top_aud2_pll_90M", | ||
19 | "top_hadds2_pll_98M", | ||
20 | "top_hadds2_pll_294M", | ||
21 | "top_audpll", | ||
22 | "top_audpll_d4", | ||
23 | "top_audpll_d8", | ||
24 | "top_audpll_d16", | ||
25 | "top_audpll_d24", | ||
26 | "top_audintbus_sel", | ||
27 | "clk_26m", | ||
28 | "top_syspll1_d4", | ||
29 | "top_aud_k1_src_sel", | ||
30 | "top_aud_k2_src_sel", | ||
31 | "top_aud_k3_src_sel", | ||
32 | "top_aud_k4_src_sel", | ||
33 | "top_aud_k5_src_sel", | ||
34 | "top_aud_k6_src_sel", | ||
35 | "top_aud_k1_src_div", | ||
36 | "top_aud_k2_src_div", | ||
37 | "top_aud_k3_src_div", | ||
38 | "top_aud_k4_src_div", | ||
39 | "top_aud_k5_src_div", | ||
40 | "top_aud_k6_src_div", | ||
41 | "top_aud_i2s1_mclk", | ||
42 | "top_aud_i2s2_mclk", | ||
43 | "top_aud_i2s3_mclk", | ||
44 | "top_aud_i2s4_mclk", | ||
45 | "top_aud_i2s5_mclk", | ||
46 | "top_aud_i2s6_mclk", | ||
47 | "top_asm_m_sel", | ||
48 | "top_asm_h_sel", | ||
49 | "top_univpll2_d4", | ||
50 | "top_univpll2_d2", | ||
51 | "top_syspll_d5"; | ||
52 | |||
53 | Example: | ||
54 | |||
55 | afe: mt2701-afe-pcm@11220000 { | ||
56 | compatible = "mediatek,mt2701-audio"; | ||
57 | reg = <0 0x11220000 0 0x2000>, | ||
58 | <0 0x112A0000 0 0x20000>; | ||
59 | interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>, | ||
60 | <GIC_SPI 132 IRQ_TYPE_LEVEL_LOW>; | ||
61 | clocks = <&infracfg CLK_INFRA_AUDIO>, | ||
62 | <&topckgen CLK_TOP_AUD_MUX1_SEL>, | ||
63 | <&topckgen CLK_TOP_AUD_MUX2_SEL>, | ||
64 | <&topckgen CLK_TOP_AUD_MUX1_DIV>, | ||
65 | <&topckgen CLK_TOP_AUD_MUX2_DIV>, | ||
66 | <&topckgen CLK_TOP_AUD_48K_TIMING>, | ||
67 | <&topckgen CLK_TOP_AUD_44K_TIMING>, | ||
68 | <&topckgen CLK_TOP_AUDPLL_MUX_SEL>, | ||
69 | <&topckgen CLK_TOP_APLL_SEL>, | ||
70 | <&topckgen CLK_TOP_AUD1PLL_98M>, | ||
71 | <&topckgen CLK_TOP_AUD2PLL_90M>, | ||
72 | <&topckgen CLK_TOP_HADDS2PLL_98M>, | ||
73 | <&topckgen CLK_TOP_HADDS2PLL_294M>, | ||
74 | <&topckgen CLK_TOP_AUDPLL>, | ||
75 | <&topckgen CLK_TOP_AUDPLL_D4>, | ||
76 | <&topckgen CLK_TOP_AUDPLL_D8>, | ||
77 | <&topckgen CLK_TOP_AUDPLL_D16>, | ||
78 | <&topckgen CLK_TOP_AUDPLL_D24>, | ||
79 | <&topckgen CLK_TOP_AUDINTBUS_SEL>, | ||
80 | <&clk26m>, | ||
81 | <&topckgen CLK_TOP_SYSPLL1_D4>, | ||
82 | <&topckgen CLK_TOP_AUD_K1_SRC_SEL>, | ||
83 | <&topckgen CLK_TOP_AUD_K2_SRC_SEL>, | ||
84 | <&topckgen CLK_TOP_AUD_K3_SRC_SEL>, | ||
85 | <&topckgen CLK_TOP_AUD_K4_SRC_SEL>, | ||
86 | <&topckgen CLK_TOP_AUD_K5_SRC_SEL>, | ||
87 | <&topckgen CLK_TOP_AUD_K6_SRC_SEL>, | ||
88 | <&topckgen CLK_TOP_AUD_K1_SRC_DIV>, | ||
89 | <&topckgen CLK_TOP_AUD_K2_SRC_DIV>, | ||
90 | <&topckgen CLK_TOP_AUD_K3_SRC_DIV>, | ||
91 | <&topckgen CLK_TOP_AUD_K4_SRC_DIV>, | ||
92 | <&topckgen CLK_TOP_AUD_K5_SRC_DIV>, | ||
93 | <&topckgen CLK_TOP_AUD_K6_SRC_DIV>, | ||
94 | <&topckgen CLK_TOP_AUD_I2S1_MCLK>, | ||
95 | <&topckgen CLK_TOP_AUD_I2S2_MCLK>, | ||
96 | <&topckgen CLK_TOP_AUD_I2S3_MCLK>, | ||
97 | <&topckgen CLK_TOP_AUD_I2S4_MCLK>, | ||
98 | <&topckgen CLK_TOP_AUD_I2S5_MCLK>, | ||
99 | <&topckgen CLK_TOP_AUD_I2S6_MCLK>, | ||
100 | <&topckgen CLK_TOP_ASM_M_SEL>, | ||
101 | <&topckgen CLK_TOP_ASM_H_SEL>, | ||
102 | <&topckgen CLK_TOP_UNIVPLL2_D4>, | ||
103 | <&topckgen CLK_TOP_UNIVPLL2_D2>, | ||
104 | <&topckgen CLK_TOP_SYSPLL_D5>; | ||
105 | |||
106 | clock-names = "infra_sys_audio_clk", | ||
107 | "top_audio_mux1_sel", | ||
108 | "top_audio_mux2_sel", | ||
109 | "top_audio_mux1_div", | ||
110 | "top_audio_mux2_div", | ||
111 | "top_audio_48k_timing", | ||
112 | "top_audio_44k_timing", | ||
113 | "top_audpll_mux_sel", | ||
114 | "top_apll_sel", | ||
115 | "top_aud1_pll_98M", | ||
116 | "top_aud2_pll_90M", | ||
117 | "top_hadds2_pll_98M", | ||
118 | "top_hadds2_pll_294M", | ||
119 | "top_audpll", | ||
120 | "top_audpll_d4", | ||
121 | "top_audpll_d8", | ||
122 | "top_audpll_d16", | ||
123 | "top_audpll_d24", | ||
124 | "top_audintbus_sel", | ||
125 | "clk_26m", | ||
126 | "top_syspll1_d4", | ||
127 | "top_aud_k1_src_sel", | ||
128 | "top_aud_k2_src_sel", | ||
129 | "top_aud_k3_src_sel", | ||
130 | "top_aud_k4_src_sel", | ||
131 | "top_aud_k5_src_sel", | ||
132 | "top_aud_k6_src_sel", | ||
133 | "top_aud_k1_src_div", | ||
134 | "top_aud_k2_src_div", | ||
135 | "top_aud_k3_src_div", | ||
136 | "top_aud_k4_src_div", | ||
137 | "top_aud_k5_src_div", | ||
138 | "top_aud_k6_src_div", | ||
139 | "top_aud_i2s1_mclk", | ||
140 | "top_aud_i2s2_mclk", | ||
141 | "top_aud_i2s3_mclk", | ||
142 | "top_aud_i2s4_mclk", | ||
143 | "top_aud_i2s5_mclk", | ||
144 | "top_aud_i2s6_mclk", | ||
145 | "top_asm_m_sel", | ||
146 | "top_asm_h_sel", | ||
147 | "top_univpll2_d4", | ||
148 | "top_univpll2_d2", | ||
149 | "top_syspll_d5"; | ||
150 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt b/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt new file mode 100644 index 000000000000..05574446ceb6 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/mt2701-cs42448.txt | |||
@@ -0,0 +1,43 @@ | |||
1 | MT2701 with CS42448 CODEC | ||
2 | |||
3 | Required properties: | ||
4 | - compatible: "mediatek,mt2701-cs42448-machine" | ||
5 | - mediatek,platform: the phandle of MT2701 ASoC platform | ||
6 | - audio-routing: a list of the connections between audio | ||
7 | - mediatek,audio-codec: the phandles of cs42448 codec | ||
8 | - mediatek,audio-codec-bt-mrg the phandles of bt-sco dummy codec | ||
9 | - pinctrl-names: Should contain only one value - "default" | ||
10 | - pinctrl-0: Should specify pin control groups used for this controller. | ||
11 | - i2s1-in-sel-gpio1, i2s1-in-sel-gpio2: Should specify two gpio pins to | ||
12 | control I2S1-in mux. | ||
13 | |||
14 | Example: | ||
15 | |||
16 | sound:sound { | ||
17 | compatible = "mediatek,mt2701-cs42448-machine"; | ||
18 | mediatek,platform = <&afe>; | ||
19 | /* CS42448 Machine name */ | ||
20 | audio-routing = | ||
21 | "Line Out Jack", "AOUT1L", | ||
22 | "Line Out Jack", "AOUT1R", | ||
23 | "Line Out Jack", "AOUT2L", | ||
24 | "Line Out Jack", "AOUT2R", | ||
25 | "Line Out Jack", "AOUT3L", | ||
26 | "Line Out Jack", "AOUT3R", | ||
27 | "Line Out Jack", "AOUT4L", | ||
28 | "Line Out Jack", "AOUT4R", | ||
29 | "AIN1L", "AMIC", | ||
30 | "AIN1R", "AMIC", | ||
31 | "AIN2L", "Tuner In", | ||
32 | "AIN2R", "Tuner In", | ||
33 | "AIN3L", "Satellite Tuner In", | ||
34 | "AIN3R", "Satellite Tuner In", | ||
35 | "AIN3L", "AUX In", | ||
36 | "AIN3R", "AUX In"; | ||
37 | mediatek,audio-codec = <&cs42448>; | ||
38 | mediatek,audio-codec-bt-mrg = <&bt_sco_codec>; | ||
39 | pinctrl-names = "default"; | ||
40 | pinctrl-0 = <&aud_pins_default>; | ||
41 | i2s1-in-sel-gpio1 = <&pio 53 0>; | ||
42 | i2s1-in-sel-gpio2 = <&pio 54 0>; | ||
43 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt index 5bfa6b60530b..29dce2ac8773 100644 --- a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt | |||
@@ -1,8 +1,9 @@ | |||
1 | MT8173 with RT5650 CODECS | 1 | MT8173 with RT5650 CODECS and HDMI via I2S |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "mediatek,mt8173-rt5650" | 4 | - compatible : "mediatek,mt8173-rt5650" |
5 | - mediatek,audio-codec: the phandles of rt5650 codecs | 5 | - mediatek,audio-codec: the phandles of rt5650 codecs |
6 | and of the hdmi encoder node | ||
6 | - mediatek,platform: the phandle of MT8173 ASoC platform | 7 | - mediatek,platform: the phandle of MT8173 ASoC platform |
7 | 8 | ||
8 | Optional subnodes: | 9 | Optional subnodes: |
@@ -12,12 +13,17 @@ Required codec-capture subnode properties: | |||
12 | <&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1) | 13 | <&rt5650 0> : Default setting. Connect rt5650 I2S1 for capture. (dai_name = rt5645-aif1) |
13 | <&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2) | 14 | <&rt5650 1> : Connect rt5650 I2S2 for capture. (dai_name = rt5645-aif2) |
14 | 15 | ||
16 | - mediatek,mclk: the MCLK source | ||
17 | 0 : external oscillator, MCLK = 12.288M | ||
18 | 1 : internal source from mt8173, MCLK = sampling rate*256 | ||
19 | |||
15 | Example: | 20 | Example: |
16 | 21 | ||
17 | sound { | 22 | sound { |
18 | compatible = "mediatek,mt8173-rt5650"; | 23 | compatible = "mediatek,mt8173-rt5650"; |
19 | mediatek,audio-codec = <&rt5650>; | 24 | mediatek,audio-codec = <&rt5650 &hdmi0>; |
20 | mediatek,platform = <&afe>; | 25 | mediatek,platform = <&afe>; |
26 | mediatek,mclk = <0>; | ||
21 | codec-capture { | 27 | codec-capture { |
22 | sound-dai = <&rt5650 1>; | 28 | sound-dai = <&rt5650 1>; |
23 | }; | 29 | }; |
diff --git a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt index 0741dff048dd..6f6c2f8e908d 100644 --- a/Documentation/devicetree/bindings/sound/omap-mcpdm.txt +++ b/Documentation/devicetree/bindings/sound/omap-mcpdm.txt | |||
@@ -8,6 +8,8 @@ Required properties: | |||
8 | - interrupts: Interrupt number for McPDM | 8 | - interrupts: Interrupt number for McPDM |
9 | - interrupt-parent: The parent interrupt controller | 9 | - interrupt-parent: The parent interrupt controller |
10 | - ti,hwmods: Name of the hwmod associated to the McPDM | 10 | - ti,hwmods: Name of the hwmod associated to the McPDM |
11 | - clocks: phandle for the pdmclk provider, likely <&twl6040> | ||
12 | - clock-names: Must be "pdmclk" | ||
11 | 13 | ||
12 | Example: | 14 | Example: |
13 | 15 | ||
@@ -19,3 +21,11 @@ mcpdm: mcpdm@40132000 { | |||
19 | interrupt-parent = <&gic>; | 21 | interrupt-parent = <&gic>; |
20 | ti,hwmods = "mcpdm"; | 22 | ti,hwmods = "mcpdm"; |
21 | }; | 23 | }; |
24 | |||
25 | In board DTS file the pdmclk needs to be added: | ||
26 | |||
27 | &mcpdm { | ||
28 | clocks = <&twl6040>; | ||
29 | clock-names = "pdmclk"; | ||
30 | status = "okay"; | ||
31 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index c7b29df4a963..15a7316e4c91 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt | |||
@@ -373,6 +373,8 @@ Optional properties: | |||
373 | - #clock-cells : it must be 0 if your system has audio_clkout | 373 | - #clock-cells : it must be 0 if your system has audio_clkout |
374 | it must be 1 if your system has audio_clkout0/1/2/3 | 374 | it must be 1 if your system has audio_clkout0/1/2/3 |
375 | - clock-frequency : for all audio_clkout0/1/2/3 | 375 | - clock-frequency : for all audio_clkout0/1/2/3 |
376 | - clkout-lr-asynchronous : boolean property. it indicates that audio_clkoutn | ||
377 | is asynchronizes with lr-clock. | ||
376 | 378 | ||
377 | SSI subnode properties: | 379 | SSI subnode properties: |
378 | - interrupts : Should contain SSI interrupt for PIO transfer | 380 | - interrupts : Should contain SSI interrupt for PIO transfer |
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt index 6e86d8aa29b4..4ea29aa9af59 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt | |||
@@ -23,6 +23,11 @@ Required properties: | |||
23 | - rockchip,playback-channels: max playback channels, if not set, 8 channels default. | 23 | - rockchip,playback-channels: max playback channels, if not set, 8 channels default. |
24 | - rockchip,capture-channels: max capture channels, if not set, 2 channels default. | 24 | - rockchip,capture-channels: max capture channels, if not set, 2 channels default. |
25 | 25 | ||
26 | Required properties for controller which support multi channels | ||
27 | playback/capture: | ||
28 | |||
29 | - rockchip,grf: the phandle of the syscon node for GRF register. | ||
30 | |||
26 | Example for rk3288 I2S controller: | 31 | Example for rk3288 I2S controller: |
27 | 32 | ||
28 | i2s@ff890000 { | 33 | i2s@ff890000 { |
diff --git a/Documentation/devicetree/bindings/sound/rt5514.txt b/Documentation/devicetree/bindings/sound/rt5514.txt index e24436fc5ea9..9cabfc18cb57 100644 --- a/Documentation/devicetree/bindings/sound/rt5514.txt +++ b/Documentation/devicetree/bindings/sound/rt5514.txt | |||
@@ -8,6 +8,11 @@ Required properties: | |||
8 | 8 | ||
9 | - reg : The I2C address of the device. | 9 | - reg : The I2C address of the device. |
10 | 10 | ||
11 | Optional properties: | ||
12 | |||
13 | - clocks: The phandle of the master clock to the CODEC | ||
14 | - clock-names: Should be "mclk" | ||
15 | |||
11 | Pins on the device (for linking into audio routes) for RT5514: | 16 | Pins on the device (for linking into audio routes) for RT5514: |
12 | 17 | ||
13 | * DMIC1L | 18 | * DMIC1L |
diff --git a/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt b/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt deleted file mode 100644 index 9148f72319e1..000000000000 --- a/Documentation/devicetree/bindings/sound/samsung,odroidx2-max98090.txt +++ /dev/null | |||
@@ -1,35 +0,0 @@ | |||
1 | Samsung Exynos Odroid X2/U3 audio complex with MAX98090 codec | ||
2 | |||
3 | Required properties: | ||
4 | - compatible : "samsung,odroidx2-audio" - for Odroid X2 board, | ||
5 | "samsung,odroidu3-audio" - for Odroid U3 board | ||
6 | - samsung,model : the user-visible name of this sound complex | ||
7 | - samsung,i2s-controller : the phandle of the I2S controller | ||
8 | - samsung,audio-codec : the phandle of the MAX98090 audio codec | ||
9 | - samsung,audio-routing : a list of the connections between audio | ||
10 | components; each entry is a pair of strings, the first being the | ||
11 | connection's sink, the second being the connection's source; | ||
12 | valid names for sources and sinks are the MAX98090's pins (as | ||
13 | documented in its binding), and the jacks on the board | ||
14 | For Odroid X2: | ||
15 | * Headphone Jack | ||
16 | * Mic Jack | ||
17 | * DMIC | ||
18 | |||
19 | For Odroid U3: | ||
20 | * Headphone Jack | ||
21 | * Speakers | ||
22 | |||
23 | Example: | ||
24 | |||
25 | sound { | ||
26 | compatible = "samsung,odroidu3-audio"; | ||
27 | samsung,i2s-controller = <&i2s0>; | ||
28 | samsung,audio-codec = <&max98090>; | ||
29 | samsung,model = "Odroid-X2"; | ||
30 | samsung,audio-routing = | ||
31 | "Headphone Jack", "HPL", | ||
32 | "Headphone Jack", "HPR", | ||
33 | "IN1", "Mic Jack", | ||
34 | "Mic Jack", "MICBIAS"; | ||
35 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt index 0e5e4eb3ef1b..5666da7b8605 100644 --- a/Documentation/devicetree/bindings/sound/sgtl5000.txt +++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt | |||
@@ -7,6 +7,14 @@ Required properties: | |||
7 | 7 | ||
8 | - clocks : the clock provider of SYS_MCLK | 8 | - clocks : the clock provider of SYS_MCLK |
9 | 9 | ||
10 | - VDDA-supply : the regulator provider of VDDA | ||
11 | |||
12 | - VDDIO-supply: the regulator provider of VDDIO | ||
13 | |||
14 | Optional properties: | ||
15 | |||
16 | - VDDD-supply : the regulator provider of VDDD | ||
17 | |||
10 | - micbias-resistor-k-ohms : the bias resistor to be used in kOmhs | 18 | - micbias-resistor-k-ohms : the bias resistor to be used in kOmhs |
11 | The resistor can take values of 2k, 4k or 8k. | 19 | The resistor can take values of 2k, 4k or 8k. |
12 | If set to 0 it will be off. | 20 | If set to 0 it will be off. |
@@ -15,17 +23,9 @@ Required properties: | |||
15 | 23 | ||
16 | - micbias-voltage-m-volts : the bias voltage to be used in mVolts | 24 | - 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 | 25 | 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 | 26 | If this node is not mentioned or the value is unknown, then |
19 | the value is set to 1.25V. | 27 | the value is set to 1.25V. |
20 | 28 | ||
21 | - VDDA-supply : the regulator provider of VDDA | ||
22 | |||
23 | - VDDIO-supply: the regulator provider of VDDIO | ||
24 | |||
25 | Optional properties: | ||
26 | |||
27 | - VDDD-supply : the regulator provider of VDDD | ||
28 | |||
29 | Example: | 29 | Example: |
30 | 30 | ||
31 | codec: sgtl5000@0a { | 31 | codec: sgtl5000@0a { |
diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt index 4d9a83d9a017..16bcdfb6760e 100644 --- a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt | |||
@@ -33,11 +33,11 @@ Required properties: | |||
33 | "tx" for "st,sti-uni-player" compatibility | 33 | "tx" for "st,sti-uni-player" compatibility |
34 | "rx" for "st,sti-uni-reader" compatibility | 34 | "rx" for "st,sti-uni-reader" compatibility |
35 | 35 | ||
36 | - version: IP version integrated in SOC. | 36 | - st,version: IP version integrated in SOC. |
37 | 37 | ||
38 | - dai-name: DAI name that describes the IP. | 38 | - dai-name: DAI name that describes the IP. |
39 | 39 | ||
40 | - IP mode: IP working mode depending on associated codec. | 40 | - st,mode: IP working mode depending on associated codec. |
41 | "HDMI" connected to HDMI codec and support IEC HDMI formats (player only). | 41 | "HDMI" connected to HDMI codec and support IEC HDMI formats (player only). |
42 | "SPDIF" connected to SPDIF codec and support SPDIF formats (player only). | 42 | "SPDIF" connected to SPDIF codec and support SPDIF formats (player only). |
43 | "PCM" PCM standard mode for I2S or TDM bus. | 43 | "PCM" PCM standard mode for I2S or TDM bus. |
@@ -47,7 +47,7 @@ Required properties ("st,sti-uni-player" compatibility only): | |||
47 | - clocks: CPU_DAI IP clock source, listed in the same order than the | 47 | - clocks: CPU_DAI IP clock source, listed in the same order than the |
48 | CPU_DAI properties. | 48 | CPU_DAI properties. |
49 | 49 | ||
50 | - uniperiph-id: internal SOC IP instance ID. | 50 | - st,uniperiph-id: internal SOC IP instance ID. |
51 | 51 | ||
52 | Optional properties: | 52 | Optional properties: |
53 | - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for | 53 | - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for |
@@ -84,9 +84,9 @@ Example: | |||
84 | dmas = <&fdma0 4 0 1>; | 84 | dmas = <&fdma0 4 0 1>; |
85 | dai-name = "Uni Player #2 (DAC)"; | 85 | dai-name = "Uni Player #2 (DAC)"; |
86 | dma-names = "tx"; | 86 | dma-names = "tx"; |
87 | uniperiph-id = <2>; | 87 | st,uniperiph-id = <2>; |
88 | version = <5>; | 88 | st,version = <5>; |
89 | mode = "PCM"; | 89 | st,mode = "PCM"; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | sti_uni_player3: sti-uni-player@3 { | 92 | sti_uni_player3: sti-uni-player@3 { |
@@ -100,9 +100,9 @@ Example: | |||
100 | dmas = <&fdma0 7 0 1>; | 100 | dmas = <&fdma0 7 0 1>; |
101 | dma-names = "tx"; | 101 | dma-names = "tx"; |
102 | dai-name = "Uni Player #3 (SPDIF)"; | 102 | dai-name = "Uni Player #3 (SPDIF)"; |
103 | uniperiph-id = <3>; | 103 | st,uniperiph-id = <3>; |
104 | version = <5>; | 104 | st,version = <5>; |
105 | mode = "SPDIF"; | 105 | st,mode = "SPDIF"; |
106 | }; | 106 | }; |
107 | 107 | ||
108 | sti_uni_reader1: sti-uni-reader@1 { | 108 | sti_uni_reader1: sti-uni-reader@1 { |
@@ -115,7 +115,7 @@ Example: | |||
115 | dmas = <&fdma0 6 0 1>; | 115 | dmas = <&fdma0 6 0 1>; |
116 | dma-names = "rx"; | 116 | dma-names = "rx"; |
117 | dai-name = "Uni Reader #1 (HDMI RX)"; | 117 | dai-name = "Uni Reader #1 (HDMI RX)"; |
118 | version = <3>; | 118 | st,version = <3>; |
119 | st,mode = "PCM"; | 119 | st,mode = "PCM"; |
120 | }; | 120 | }; |
121 | 121 | ||
diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt new file mode 100644 index 000000000000..7b526ec64991 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt | |||
@@ -0,0 +1,34 @@ | |||
1 | * Allwinner A10 I2S controller | ||
2 | |||
3 | The I2S bus (Inter-IC sound bus) is a serial link for digital | ||
4 | audio data transfer between devices in the system. | ||
5 | |||
6 | Required properties: | ||
7 | |||
8 | - compatible: should be one of the followings | ||
9 | - "allwinner,sun4i-a10-i2s" | ||
10 | - reg: physical base address of the controller and length of memory mapped | ||
11 | region. | ||
12 | - interrupts: should contain the I2S interrupt. | ||
13 | - dmas: DMA specifiers for tx and rx dma. See the DMA client binding, | ||
14 | Documentation/devicetree/bindings/dma/dma.txt | ||
15 | - dma-names: should include "tx" and "rx". | ||
16 | - clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. | ||
17 | - clock-names: should contain followings: | ||
18 | - "apb" : clock for the I2S bus interface | ||
19 | - "mod" : module clock for the I2S controller | ||
20 | - #sound-dai-cells : Must be equal to 0 | ||
21 | |||
22 | Example: | ||
23 | |||
24 | i2s0: i2s@01c22400 { | ||
25 | #sound-dai-cells = <0>; | ||
26 | compatible = "allwinner,sun4i-a10-i2s"; | ||
27 | reg = <0x01c22400 0x400>; | ||
28 | interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; | ||
29 | clocks = <&apb0_gates 3>, <&i2s0_clk>; | ||
30 | clock-names = "apb", "mod"; | ||
31 | dmas = <&dma SUN4I_DMA_NORMAL 3>, | ||
32 | <&dma SUN4I_DMA_NORMAL 3>; | ||
33 | dma-names = "rx", "tx"; | ||
34 | }; | ||
diff --git a/Documentation/sound/alsa/soc/machine.txt b/Documentation/sound/alsa/soc/machine.txt index 74056dba52be..6bf2d2063b52 100644 --- a/Documentation/sound/alsa/soc/machine.txt +++ b/Documentation/sound/alsa/soc/machine.txt | |||
@@ -3,7 +3,7 @@ ASoC Machine Driver | |||
3 | 3 | ||
4 | The ASoC machine (or board) driver is the code that glues together all the | 4 | The ASoC machine (or board) driver is the code that glues together all the |
5 | component drivers (e.g. codecs, platforms and DAIs). It also describes the | 5 | component drivers (e.g. codecs, platforms and DAIs). It also describes the |
6 | relationships between each componnent which include audio paths, GPIOs, | 6 | relationships between each component which include audio paths, GPIOs, |
7 | interrupts, clocking, jacks and voltage regulators. | 7 | interrupts, clocking, jacks and voltage regulators. |
8 | 8 | ||
9 | The machine driver can contain codec and platform specific code. It registers | 9 | The machine driver can contain codec and platform specific code. It registers |
diff --git a/Documentation/sound/alsa/timestamping.txt b/Documentation/sound/alsa/timestamping.txt index 1b6473f393a8..9d579aefbffd 100644 --- a/Documentation/sound/alsa/timestamping.txt +++ b/Documentation/sound/alsa/timestamping.txt | |||
@@ -14,7 +14,7 @@ provides a refined estimate with a delay. | |||
14 | event or application query. | 14 | event or application query. |
15 | The difference (tstamp - trigger_tstamp) defines the elapsed time. | 15 | The difference (tstamp - trigger_tstamp) defines the elapsed time. |
16 | 16 | ||
17 | The ALSA API provides reports two basic pieces of information, avail | 17 | The ALSA API provides two basic pieces of information, avail |
18 | and delay, which combined with the trigger and current system | 18 | and delay, which combined with the trigger and current system |
19 | timestamps allow for applications to keep track of the 'fullness' of | 19 | timestamps allow for applications to keep track of the 'fullness' of |
20 | the ring buffer and the amount of queued samples. | 20 | the ring buffer and the amount of queued samples. |
@@ -53,21 +53,21 @@ case): | |||
53 | The analog time is taken at the last stage of the playback, as close | 53 | The analog time is taken at the last stage of the playback, as close |
54 | as possible to the actual transducer | 54 | as possible to the actual transducer |
55 | 55 | ||
56 | The link time is taken at the output of the SOC/chipset as the samples | 56 | The link time is taken at the output of the SoC/chipset as the samples |
57 | are pushed on a link. The link time can be directly measured if | 57 | are pushed on a link. The link time can be directly measured if |
58 | supported in hardware by sample counters or wallclocks (e.g. with | 58 | supported in hardware by sample counters or wallclocks (e.g. with |
59 | HDAudio 24MHz or PTP clock for networked solutions) or indirectly | 59 | HDAudio 24MHz or PTP clock for networked solutions) or indirectly |
60 | estimated (e.g. with the frame counter in USB). | 60 | estimated (e.g. with the frame counter in USB). |
61 | 61 | ||
62 | The DMA time is measured using counters - typically the least reliable | 62 | The DMA time is measured using counters - typically the least reliable |
63 | of all measurements due to the bursty natured of DMA transfers. | 63 | of all measurements due to the bursty nature of DMA transfers. |
64 | 64 | ||
65 | The app time corresponds to the time tracked by an application after | 65 | The app time corresponds to the time tracked by an application after |
66 | writing in the ring buffer. | 66 | writing in the ring buffer. |
67 | 67 | ||
68 | The application can query what the hardware supports, define which | 68 | The application can query the hardware capabilities, define which |
69 | audio time it wants reported by selecting the relevant settings in | 69 | audio time it wants reported by selecting the relevant settings in |
70 | audio_tstamp_config fields, get an estimate of the timestamp | 70 | audio_tstamp_config fields, thus get an estimate of the timestamp |
71 | accuracy. It can also request the delay-to-analog be included in the | 71 | accuracy. It can also request the delay-to-analog be included in the |
72 | measurement. Direct access to the link time is very interesting on | 72 | measurement. Direct access to the link time is very interesting on |
73 | platforms that provide an embedded DSP; measuring directly the link | 73 | platforms that provide an embedded DSP; measuring directly the link |
@@ -169,7 +169,7 @@ playback: systime: 938107562 nsec, audio time 938112708 nsec, systime delta -51 | |||
169 | Example 1 shows that the timestamp at the DMA level is close to 1ms | 169 | Example 1 shows that the timestamp at the DMA level is close to 1ms |
170 | ahead of the actual playback time (as a side time this sort of | 170 | ahead of the actual playback time (as a side time this sort of |
171 | measurement can help define rewind safeguards). Compensating for the | 171 | measurement can help define rewind safeguards). Compensating for the |
172 | DMA-link delay in example 2 helps remove the hardware buffering abut | 172 | DMA-link delay in example 2 helps remove the hardware buffering but |
173 | the information is still very jittery, with up to one sample of | 173 | the information is still very jittery, with up to one sample of |
174 | error. In example 3 where the timestamps are measured with the link | 174 | error. In example 3 where the timestamps are measured with the link |
175 | wallclock, the timestamps show a monotonic behavior and a lower | 175 | wallclock, the timestamps show a monotonic behavior and a lower |
diff --git a/MAINTAINERS b/MAINTAINERS index 8af18097e92c..8ca0b205759f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -1611,7 +1611,6 @@ F: drivers/*/*/*s3c2410* | |||
1611 | F: drivers/memory/samsung/* | 1611 | F: drivers/memory/samsung/* |
1612 | F: drivers/soc/samsung/* | 1612 | F: drivers/soc/samsung/* |
1613 | F: drivers/spi/spi-s3c* | 1613 | F: drivers/spi/spi-s3c* |
1614 | F: sound/soc/samsung/* | ||
1615 | F: Documentation/arm/Samsung/ | 1614 | F: Documentation/arm/Samsung/ |
1616 | F: Documentation/devicetree/bindings/arm/samsung/ | 1615 | F: Documentation/devicetree/bindings/arm/samsung/ |
1617 | F: Documentation/devicetree/bindings/sram/samsung-sram.txt | 1616 | F: Documentation/devicetree/bindings/sram/samsung-sram.txt |
@@ -7355,6 +7354,13 @@ F: Documentation/devicetree/bindings/i2c/max6697.txt | |||
7355 | F: drivers/hwmon/max6697.c | 7354 | F: drivers/hwmon/max6697.c |
7356 | F: include/linux/platform_data/max6697.h | 7355 | F: include/linux/platform_data/max6697.h |
7357 | 7356 | ||
7357 | MAX9860 MONO AUDIO VOICE CODEC DRIVER | ||
7358 | M: Peter Rosin <peda@axentia.se> | ||
7359 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
7360 | S: Maintained | ||
7361 | F: Documentation/devicetree/bindings/sound/max9860.txt | ||
7362 | F: sound/soc/codecs/max9860.* | ||
7363 | |||
7358 | MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS | 7364 | MAXIM MUIC CHARGER DRIVERS FOR EXYNOS BASED BOARDS |
7359 | M: Krzysztof Kozlowski <k.kozlowski@samsung.com> | 7365 | M: Krzysztof Kozlowski <k.kozlowski@samsung.com> |
7360 | L: linux-pm@vger.kernel.org | 7366 | L: linux-pm@vger.kernel.org |
@@ -10027,7 +10033,9 @@ S: Maintained | |||
10027 | F: drivers/platform/x86/samsung-laptop.c | 10033 | F: drivers/platform/x86/samsung-laptop.c |
10028 | 10034 | ||
10029 | SAMSUNG AUDIO (ASoC) DRIVERS | 10035 | SAMSUNG AUDIO (ASoC) DRIVERS |
10036 | M: Krzysztof Kozlowski <k.kozlowski@samsung.com> | ||
10030 | M: Sangbeom Kim <sbkim73@samsung.com> | 10037 | M: Sangbeom Kim <sbkim73@samsung.com> |
10038 | M: Sylwester Nawrocki <s.nawrocki@samsung.com> | ||
10031 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 10039 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
10032 | S: Supported | 10040 | S: Supported |
10033 | F: sound/soc/samsung/ | 10041 | F: sound/soc/samsung/ |
@@ -10856,6 +10864,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git | |||
10856 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 10864 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
10857 | W: http://alsa-project.org/main/index.php/ASoC | 10865 | W: http://alsa-project.org/main/index.php/ASoC |
10858 | S: Supported | 10866 | S: Supported |
10867 | F: Documentation/devicetree/bindings/sound/ | ||
10859 | F: Documentation/sound/alsa/soc/ | 10868 | F: Documentation/sound/alsa/soc/ |
10860 | F: sound/soc/ | 10869 | F: sound/soc/ |
10861 | F: include/sound/soc* | 10870 | F: include/sound/soc* |
diff --git a/drivers/base/property.c b/drivers/base/property.c index f38c21de29b7..43a36d68c3fd 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c | |||
@@ -888,6 +888,34 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, | |||
888 | EXPORT_SYMBOL_GPL(device_get_next_child_node); | 888 | EXPORT_SYMBOL_GPL(device_get_next_child_node); |
889 | 889 | ||
890 | /** | 890 | /** |
891 | * device_get_named_child_node - Return first matching named child node handle | ||
892 | * @dev: Device to find the named child node for. | ||
893 | * @childname: String to match child node name against. | ||
894 | */ | ||
895 | struct fwnode_handle *device_get_named_child_node(struct device *dev, | ||
896 | const char *childname) | ||
897 | { | ||
898 | struct fwnode_handle *child; | ||
899 | |||
900 | /* | ||
901 | * Find first matching named child node of this device. | ||
902 | * For ACPI this will be a data only sub-node. | ||
903 | */ | ||
904 | device_for_each_child_node(dev, child) { | ||
905 | if (is_of_node(child)) { | ||
906 | if (!of_node_cmp(to_of_node(child)->name, childname)) | ||
907 | return child; | ||
908 | } else if (is_acpi_data_node(child)) { | ||
909 | if (acpi_data_node_match(child, childname)) | ||
910 | return child; | ||
911 | } | ||
912 | } | ||
913 | |||
914 | return NULL; | ||
915 | } | ||
916 | EXPORT_SYMBOL_GPL(device_get_named_child_node); | ||
917 | |||
918 | /** | ||
891 | * fwnode_handle_put - Drop reference to a device node | 919 | * fwnode_handle_put - Drop reference to a device node |
892 | * @fwnode: Pointer to the device node to drop the reference to. | 920 | * @fwnode: Pointer to the device node to drop the reference to. |
893 | * | 921 | * |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 788c6c35291a..c1a524de67c5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -420,6 +420,13 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn | |||
420 | container_of(fwnode, struct acpi_data_node, fwnode) : NULL; | 420 | container_of(fwnode, struct acpi_data_node, fwnode) : NULL; |
421 | } | 421 | } |
422 | 422 | ||
423 | static inline bool acpi_data_node_match(struct fwnode_handle *fwnode, | ||
424 | const char *name) | ||
425 | { | ||
426 | return is_acpi_data_node(fwnode) ? | ||
427 | (!strcmp(to_acpi_data_node(fwnode)->name, name)) : false; | ||
428 | } | ||
429 | |||
423 | static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) | 430 | static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) |
424 | { | 431 | { |
425 | return &adev->fwnode; | 432 | return &adev->fwnode; |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index db7c8bd39a3c..4d8452c2384b 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
@@ -608,6 +608,12 @@ static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwn | |||
608 | return NULL; | 608 | return NULL; |
609 | } | 609 | } |
610 | 610 | ||
611 | static inline bool acpi_data_node_match(struct fwnode_handle *fwnode, | ||
612 | const char *name) | ||
613 | { | ||
614 | return false; | ||
615 | } | ||
616 | |||
611 | static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) | 617 | static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) |
612 | { | 618 | { |
613 | return NULL; | 619 | return NULL; |
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h index d55a42297d49..58ab4c0fe761 100644 --- a/include/linux/mfd/arizona/core.h +++ b/include/linux/mfd/arizona/core.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define _WM_ARIZONA_CORE_H | 14 | #define _WM_ARIZONA_CORE_H |
15 | 15 | ||
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/notifier.h> | ||
17 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
18 | #include <linux/regulator/consumer.h> | 19 | #include <linux/regulator/consumer.h> |
19 | #include <linux/mfd/arizona/pdata.h> | 20 | #include <linux/mfd/arizona/pdata.h> |
@@ -148,8 +149,17 @@ struct arizona { | |||
148 | uint16_t dac_comp_coeff; | 149 | uint16_t dac_comp_coeff; |
149 | uint8_t dac_comp_enabled; | 150 | uint8_t dac_comp_enabled; |
150 | struct mutex dac_comp_lock; | 151 | struct mutex dac_comp_lock; |
152 | |||
153 | struct blocking_notifier_head notifier; | ||
151 | }; | 154 | }; |
152 | 155 | ||
156 | static inline int arizona_call_notifiers(struct arizona *arizona, | ||
157 | unsigned long event, | ||
158 | void *data) | ||
159 | { | ||
160 | return blocking_notifier_call_chain(&arizona->notifier, event, data); | ||
161 | } | ||
162 | |||
153 | int arizona_clk32k_enable(struct arizona *arizona); | 163 | int arizona_clk32k_enable(struct arizona *arizona); |
154 | int arizona_clk32k_disable(struct arizona *arizona); | 164 | int arizona_clk32k_disable(struct arizona *arizona); |
155 | 165 | ||
diff --git a/include/linux/of.h b/include/linux/of.h index eb8d4b4c5dfc..3d9ff8e9d803 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -238,13 +238,6 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) | |||
238 | #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 | 238 | #define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 |
239 | #endif | 239 | #endif |
240 | 240 | ||
241 | /* Default string compare functions, Allow arch asm/prom.h to override */ | ||
242 | #if !defined(of_compat_cmp) | ||
243 | #define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) | ||
244 | #define of_prop_cmp(s1, s2) strcmp((s1), (s2)) | ||
245 | #define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) | ||
246 | #endif | ||
247 | |||
248 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) | 241 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) |
249 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) | 242 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) |
250 | 243 | ||
@@ -728,6 +721,13 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag | |||
728 | #define of_match_node(_matches, _node) NULL | 721 | #define of_match_node(_matches, _node) NULL |
729 | #endif /* CONFIG_OF */ | 722 | #endif /* CONFIG_OF */ |
730 | 723 | ||
724 | /* Default string compare functions, Allow arch asm/prom.h to override */ | ||
725 | #if !defined(of_compat_cmp) | ||
726 | #define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) | ||
727 | #define of_prop_cmp(s1, s2) strcmp((s1), (s2)) | ||
728 | #define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) | ||
729 | #endif | ||
730 | |||
731 | #if defined(CONFIG_OF) && defined(CONFIG_NUMA) | 731 | #if defined(CONFIG_OF) && defined(CONFIG_NUMA) |
732 | extern int of_node_to_nid(struct device_node *np); | 732 | extern int of_node_to_nid(struct device_node *np); |
733 | #else | 733 | #else |
diff --git a/include/linux/property.h b/include/linux/property.h index ecab11e40794..3a2f9ae25c86 100644 --- a/include/linux/property.h +++ b/include/linux/property.h | |||
@@ -77,6 +77,9 @@ struct fwnode_handle *device_get_next_child_node(struct device *dev, | |||
77 | for (child = device_get_next_child_node(dev, NULL); child; \ | 77 | for (child = device_get_next_child_node(dev, NULL); child; \ |
78 | child = device_get_next_child_node(dev, child)) | 78 | child = device_get_next_child_node(dev, child)) |
79 | 79 | ||
80 | struct fwnode_handle *device_get_named_child_node(struct device *dev, | ||
81 | const char *childname); | ||
82 | |||
80 | void fwnode_handle_put(struct fwnode_handle *fwnode); | 83 | void fwnode_handle_put(struct fwnode_handle *fwnode); |
81 | 84 | ||
82 | unsigned int device_get_child_node_count(struct device *dev); | 85 | unsigned int device_get_child_node_count(struct device *dev); |
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index c0abcdc11470..cee8c00f3d3e 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h | |||
@@ -68,6 +68,7 @@ struct snd_compr_runtime { | |||
68 | * @ops: pointer to DSP callbacks | 68 | * @ops: pointer to DSP callbacks |
69 | * @runtime: pointer to runtime structure | 69 | * @runtime: pointer to runtime structure |
70 | * @device: device pointer | 70 | * @device: device pointer |
71 | * @error_work: delayed work used when closing the stream due to an error | ||
71 | * @direction: stream direction, playback/recording | 72 | * @direction: stream direction, playback/recording |
72 | * @metadata_set: metadata set flag, true when set | 73 | * @metadata_set: metadata set flag, true when set |
73 | * @next_track: has userspace signal next track transition, true when set | 74 | * @next_track: has userspace signal next track transition, true when set |
@@ -78,6 +79,7 @@ struct snd_compr_stream { | |||
78 | struct snd_compr_ops *ops; | 79 | struct snd_compr_ops *ops; |
79 | struct snd_compr_runtime *runtime; | 80 | struct snd_compr_runtime *runtime; |
80 | struct snd_compr *device; | 81 | struct snd_compr *device; |
82 | struct delayed_work error_work; | ||
81 | enum snd_compr_direction direction; | 83 | enum snd_compr_direction direction; |
82 | bool metadata_set; | 84 | bool metadata_set; |
83 | bool next_track; | 85 | bool next_track; |
@@ -187,4 +189,7 @@ static inline void snd_compr_drain_notify(struct snd_compr_stream *stream) | |||
187 | wake_up(&stream->runtime->sleep); | 189 | wake_up(&stream->runtime->sleep); |
188 | } | 190 | } |
189 | 191 | ||
192 | int snd_compr_stop_error(struct snd_compr_stream *stream, | ||
193 | snd_pcm_state_t state); | ||
194 | |||
190 | #endif | 195 | #endif |
diff --git a/include/sound/cs35l33.h b/include/sound/cs35l33.h new file mode 100644 index 000000000000..b6eadce76fc8 --- /dev/null +++ b/include/sound/cs35l33.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * linux/sound/cs35l33.h -- Platform data for CS35l33 | ||
3 | * | ||
4 | * Copyright (c) 2016 Cirrus Logic 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 __CS35L33_H | ||
12 | #define __CS35L33_H | ||
13 | |||
14 | struct cs35l33_hg { | ||
15 | bool enable_hg_algo; | ||
16 | unsigned int mem_depth; | ||
17 | unsigned int release_rate; | ||
18 | unsigned int hd_rm; | ||
19 | unsigned int ldo_thld; | ||
20 | unsigned int ldo_path_disable; | ||
21 | unsigned int ldo_entry_delay; | ||
22 | bool vp_hg_auto; | ||
23 | unsigned int vp_hg; | ||
24 | unsigned int vp_hg_rate; | ||
25 | unsigned int vp_hg_va; | ||
26 | }; | ||
27 | |||
28 | struct cs35l33_pdata { | ||
29 | /* Boost Controller Voltage Setting */ | ||
30 | unsigned int boost_ctl; | ||
31 | |||
32 | /* Boost Controller Peak Current */ | ||
33 | unsigned int boost_ipk; | ||
34 | |||
35 | /* Amplifier Drive Select */ | ||
36 | unsigned int amp_drv_sel; | ||
37 | |||
38 | /* soft volume ramp */ | ||
39 | unsigned int ramp_rate; | ||
40 | |||
41 | /* IMON adc scale */ | ||
42 | unsigned int imon_adc_scale; | ||
43 | |||
44 | /* H/G algo configuration */ | ||
45 | struct cs35l33_hg hg_config; | ||
46 | }; | ||
47 | |||
48 | #endif /* __CS35L33_H */ | ||
diff --git a/include/sound/hdmi-codec.h b/include/sound/hdmi-codec.h index fc3a481ad91e..530c57bdefa0 100644 --- a/include/sound/hdmi-codec.h +++ b/include/sound/hdmi-codec.h | |||
@@ -53,18 +53,19 @@ struct hdmi_codec_params { | |||
53 | int channels; | 53 | int channels; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct hdmi_codec_pdata; | ||
56 | struct hdmi_codec_ops { | 57 | struct hdmi_codec_ops { |
57 | /* | 58 | /* |
58 | * Called when ASoC starts an audio stream setup. | 59 | * Called when ASoC starts an audio stream setup. |
59 | * Optional | 60 | * Optional |
60 | */ | 61 | */ |
61 | int (*audio_startup)(struct device *dev); | 62 | int (*audio_startup)(struct device *dev, void *data); |
62 | 63 | ||
63 | /* | 64 | /* |
64 | * Configures HDMI-encoder for audio stream. | 65 | * Configures HDMI-encoder for audio stream. |
65 | * Mandatory | 66 | * Mandatory |
66 | */ | 67 | */ |
67 | int (*hw_params)(struct device *dev, | 68 | int (*hw_params)(struct device *dev, void *data, |
68 | struct hdmi_codec_daifmt *fmt, | 69 | struct hdmi_codec_daifmt *fmt, |
69 | struct hdmi_codec_params *hparms); | 70 | struct hdmi_codec_params *hparms); |
70 | 71 | ||
@@ -72,19 +73,20 @@ struct hdmi_codec_ops { | |||
72 | * Shuts down the audio stream. | 73 | * Shuts down the audio stream. |
73 | * Mandatory | 74 | * Mandatory |
74 | */ | 75 | */ |
75 | void (*audio_shutdown)(struct device *dev); | 76 | void (*audio_shutdown)(struct device *dev, void *data); |
76 | 77 | ||
77 | /* | 78 | /* |
78 | * Mute/unmute HDMI audio stream. | 79 | * Mute/unmute HDMI audio stream. |
79 | * Optional | 80 | * Optional |
80 | */ | 81 | */ |
81 | int (*digital_mute)(struct device *dev, bool enable); | 82 | int (*digital_mute)(struct device *dev, void *data, bool enable); |
82 | 83 | ||
83 | /* | 84 | /* |
84 | * Provides EDID-Like-Data from connected HDMI device. | 85 | * Provides EDID-Like-Data from connected HDMI device. |
85 | * Optional | 86 | * Optional |
86 | */ | 87 | */ |
87 | int (*get_eld)(struct device *dev, uint8_t *buf, size_t len); | 88 | int (*get_eld)(struct device *dev, void *data, |
89 | uint8_t *buf, size_t len); | ||
88 | }; | 90 | }; |
89 | 91 | ||
90 | /* HDMI codec initalization data */ | 92 | /* HDMI codec initalization data */ |
@@ -93,6 +95,7 @@ struct hdmi_codec_pdata { | |||
93 | uint i2s:1; | 95 | uint i2s:1; |
94 | uint spdif:1; | 96 | uint spdif:1; |
95 | int max_i2s_channels; | 97 | int max_i2s_channels; |
98 | void *data; | ||
96 | }; | 99 | }; |
97 | 100 | ||
98 | #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" | 101 | #define HDMI_CODEC_DRV_NAME "hdmi-audio-codec" |
diff --git a/include/sound/simple_card.h b/include/sound/simple_card.h index 0399352f3a62..a6a2e1547092 100644 --- a/include/sound/simple_card.h +++ b/include/sound/simple_card.h | |||
@@ -13,16 +13,7 @@ | |||
13 | #define __SIMPLE_CARD_H | 13 | #define __SIMPLE_CARD_H |
14 | 14 | ||
15 | #include <sound/soc.h> | 15 | #include <sound/soc.h> |
16 | 16 | #include <sound/simple_card_utils.h> | |
17 | struct asoc_simple_dai { | ||
18 | const char *name; | ||
19 | unsigned int sysclk; | ||
20 | int slots; | ||
21 | int slot_width; | ||
22 | unsigned int tx_slot_mask; | ||
23 | unsigned int rx_slot_mask; | ||
24 | struct clk *clk; | ||
25 | }; | ||
26 | 17 | ||
27 | struct asoc_simple_card_info { | 18 | struct asoc_simple_card_info { |
28 | const char *name; | 19 | const char *name; |
diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h new file mode 100644 index 000000000000..86088aed9002 --- /dev/null +++ b/include/sound/simple_card_utils.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * simple_card_core.h | ||
3 | * | ||
4 | * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
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 | #ifndef __SIMPLE_CARD_CORE_H | ||
11 | #define __SIMPLE_CARD_CORE_H | ||
12 | |||
13 | #include <sound/soc.h> | ||
14 | |||
15 | struct asoc_simple_dai { | ||
16 | const char *name; | ||
17 | unsigned int sysclk; | ||
18 | int slots; | ||
19 | int slot_width; | ||
20 | unsigned int tx_slot_mask; | ||
21 | unsigned int rx_slot_mask; | ||
22 | struct clk *clk; | ||
23 | }; | ||
24 | |||
25 | int asoc_simple_card_parse_daifmt(struct device *dev, | ||
26 | struct device_node *node, | ||
27 | struct device_node *codec, | ||
28 | char *prefix, | ||
29 | unsigned int *retfmt); | ||
30 | int asoc_simple_card_set_dailink_name(struct device *dev, | ||
31 | struct snd_soc_dai_link *dai_link, | ||
32 | const char *fmt, ...); | ||
33 | int asoc_simple_card_parse_card_name(struct snd_soc_card *card, | ||
34 | char *prefix); | ||
35 | |||
36 | #endif /* __SIMPLE_CARD_CORE_H */ | ||
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 3101d53468aa..f60d755f7ac6 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h | |||
@@ -358,6 +358,7 @@ struct snd_soc_dapm_context; | |||
358 | struct regulator; | 358 | struct regulator; |
359 | struct snd_soc_dapm_widget_list; | 359 | struct snd_soc_dapm_widget_list; |
360 | struct snd_soc_dapm_update; | 360 | struct snd_soc_dapm_update; |
361 | enum snd_soc_dapm_direction; | ||
361 | 362 | ||
362 | int dapm_regulator_event(struct snd_soc_dapm_widget *w, | 363 | int dapm_regulator_event(struct snd_soc_dapm_widget *w, |
363 | struct snd_kcontrol *kcontrol, int event); | 364 | struct snd_kcontrol *kcontrol, int event); |
@@ -382,6 +383,9 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
382 | int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, | 383 | int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm, |
383 | const struct snd_soc_dapm_widget *widget, | 384 | const struct snd_soc_dapm_widget *widget, |
384 | int num); | 385 | int num); |
386 | struct snd_soc_dapm_widget *snd_soc_dapm_new_control( | ||
387 | struct snd_soc_dapm_context *dapm, | ||
388 | const struct snd_soc_dapm_widget *widget); | ||
385 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, | 389 | int snd_soc_dapm_new_dai_widgets(struct snd_soc_dapm_context *dapm, |
386 | struct snd_soc_dai *dai); | 390 | struct snd_soc_dai *dai); |
387 | int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); | 391 | int snd_soc_dapm_link_dai_widgets(struct snd_soc_card *card); |
@@ -451,7 +455,9 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card); | |||
451 | 455 | ||
452 | /* dapm path query */ | 456 | /* dapm path query */ |
453 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 457 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
454 | struct snd_soc_dapm_widget_list **list); | 458 | struct snd_soc_dapm_widget_list **list, |
459 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, | ||
460 | enum snd_soc_dapm_direction)); | ||
455 | 461 | ||
456 | struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( | 462 | struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm( |
457 | struct snd_kcontrol *kcontrol); | 463 | struct snd_kcontrol *kcontrol); |
diff --git a/include/sound/soc.h b/include/sound/soc.h index fd7b58a58d6f..6144882cc96a 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
@@ -179,6 +179,17 @@ | |||
179 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ | 179 | .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \ |
180 | .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \ | 180 | .private_value = SOC_DOUBLE_R_S_VALUE(reg_left, reg_right, xshift, \ |
181 | xmin, xmax, xsign_bit, xinvert) } | 181 | xmin, xmax, xsign_bit, xinvert) } |
182 | #define SOC_SINGLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | ||
183 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
184 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
185 | SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
186 | .tlv.p = (tlv_array), \ | ||
187 | .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ | ||
188 | .put = snd_soc_put_volsw, \ | ||
189 | .private_value = (unsigned long)&(struct soc_mixer_control) \ | ||
190 | {.reg = xreg, .rreg = xreg, \ | ||
191 | .min = xmin, .max = xmax, .platform_max = xmax, \ | ||
192 | .sign_bit = 7,} } | ||
182 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ | 193 | #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ |
183 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | 194 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ |
184 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 195 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
diff --git a/sound/Makefile b/sound/Makefile index 77320709fd26..c41bdf5fdf24 100644 --- a/sound/Makefile +++ b/sound/Makefile | |||
@@ -2,7 +2,6 @@ | |||
2 | # | 2 | # |
3 | 3 | ||
4 | obj-$(CONFIG_SOUND) += soundcore.o | 4 | obj-$(CONFIG_SOUND) += soundcore.o |
5 | obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o | ||
6 | obj-$(CONFIG_SOUND_PRIME) += oss/ | 5 | obj-$(CONFIG_SOUND_PRIME) += oss/ |
7 | obj-$(CONFIG_DMASOUND) += oss/ | 6 | obj-$(CONFIG_DMASOUND) += oss/ |
8 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ | 7 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ |
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 9b3334be9df2..2c498488af6c 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -67,6 +67,8 @@ struct snd_compr_file { | |||
67 | struct snd_compr_stream stream; | 67 | struct snd_compr_stream stream; |
68 | }; | 68 | }; |
69 | 69 | ||
70 | static void error_delayed_work(struct work_struct *work); | ||
71 | |||
70 | /* | 72 | /* |
71 | * a note on stream states used: | 73 | * a note on stream states used: |
72 | * we use following states in the compressed core | 74 | * we use following states in the compressed core |
@@ -123,6 +125,9 @@ static int snd_compr_open(struct inode *inode, struct file *f) | |||
123 | snd_card_unref(compr->card); | 125 | snd_card_unref(compr->card); |
124 | return -ENOMEM; | 126 | return -ENOMEM; |
125 | } | 127 | } |
128 | |||
129 | INIT_DELAYED_WORK(&data->stream.error_work, error_delayed_work); | ||
130 | |||
126 | data->stream.ops = compr->ops; | 131 | data->stream.ops = compr->ops; |
127 | data->stream.direction = dirn; | 132 | data->stream.direction = dirn; |
128 | data->stream.private_data = compr->private_data; | 133 | data->stream.private_data = compr->private_data; |
@@ -153,6 +158,8 @@ static int snd_compr_free(struct inode *inode, struct file *f) | |||
153 | struct snd_compr_file *data = f->private_data; | 158 | struct snd_compr_file *data = f->private_data; |
154 | struct snd_compr_runtime *runtime = data->stream.runtime; | 159 | struct snd_compr_runtime *runtime = data->stream.runtime; |
155 | 160 | ||
161 | cancel_delayed_work_sync(&data->stream.error_work); | ||
162 | |||
156 | switch (runtime->state) { | 163 | switch (runtime->state) { |
157 | case SNDRV_PCM_STATE_RUNNING: | 164 | case SNDRV_PCM_STATE_RUNNING: |
158 | case SNDRV_PCM_STATE_DRAINING: | 165 | case SNDRV_PCM_STATE_DRAINING: |
@@ -237,6 +244,15 @@ snd_compr_ioctl_avail(struct snd_compr_stream *stream, unsigned long arg) | |||
237 | avail = snd_compr_calc_avail(stream, &ioctl_avail); | 244 | avail = snd_compr_calc_avail(stream, &ioctl_avail); |
238 | ioctl_avail.avail = avail; | 245 | ioctl_avail.avail = avail; |
239 | 246 | ||
247 | switch (stream->runtime->state) { | ||
248 | case SNDRV_PCM_STATE_OPEN: | ||
249 | return -EBADFD; | ||
250 | case SNDRV_PCM_STATE_XRUN: | ||
251 | return -EPIPE; | ||
252 | default: | ||
253 | break; | ||
254 | } | ||
255 | |||
240 | if (copy_to_user((__u64 __user *)arg, | 256 | if (copy_to_user((__u64 __user *)arg, |
241 | &ioctl_avail, sizeof(ioctl_avail))) | 257 | &ioctl_avail, sizeof(ioctl_avail))) |
242 | return -EFAULT; | 258 | return -EFAULT; |
@@ -346,11 +362,13 @@ static ssize_t snd_compr_read(struct file *f, char __user *buf, | |||
346 | switch (stream->runtime->state) { | 362 | switch (stream->runtime->state) { |
347 | case SNDRV_PCM_STATE_OPEN: | 363 | case SNDRV_PCM_STATE_OPEN: |
348 | case SNDRV_PCM_STATE_PREPARED: | 364 | case SNDRV_PCM_STATE_PREPARED: |
349 | case SNDRV_PCM_STATE_XRUN: | ||
350 | case SNDRV_PCM_STATE_SUSPENDED: | 365 | case SNDRV_PCM_STATE_SUSPENDED: |
351 | case SNDRV_PCM_STATE_DISCONNECTED: | 366 | case SNDRV_PCM_STATE_DISCONNECTED: |
352 | retval = -EBADFD; | 367 | retval = -EBADFD; |
353 | goto out; | 368 | goto out; |
369 | case SNDRV_PCM_STATE_XRUN: | ||
370 | retval = -EPIPE; | ||
371 | goto out; | ||
354 | } | 372 | } |
355 | 373 | ||
356 | avail = snd_compr_get_avail(stream); | 374 | avail = snd_compr_get_avail(stream); |
@@ -399,10 +417,16 @@ static unsigned int snd_compr_poll(struct file *f, poll_table *wait) | |||
399 | stream = &data->stream; | 417 | stream = &data->stream; |
400 | 418 | ||
401 | mutex_lock(&stream->device->lock); | 419 | mutex_lock(&stream->device->lock); |
402 | if (stream->runtime->state == SNDRV_PCM_STATE_OPEN) { | 420 | |
421 | switch (stream->runtime->state) { | ||
422 | case SNDRV_PCM_STATE_OPEN: | ||
423 | case SNDRV_PCM_STATE_XRUN: | ||
403 | retval = snd_compr_get_poll(stream) | POLLERR; | 424 | retval = snd_compr_get_poll(stream) | POLLERR; |
404 | goto out; | 425 | goto out; |
426 | default: | ||
427 | break; | ||
405 | } | 428 | } |
429 | |||
406 | poll_wait(f, &stream->runtime->sleep, wait); | 430 | poll_wait(f, &stream->runtime->sleep, wait); |
407 | 431 | ||
408 | avail = snd_compr_get_avail(stream); | 432 | avail = snd_compr_get_avail(stream); |
@@ -697,6 +721,45 @@ static int snd_compr_stop(struct snd_compr_stream *stream) | |||
697 | return retval; | 721 | return retval; |
698 | } | 722 | } |
699 | 723 | ||
724 | static void error_delayed_work(struct work_struct *work) | ||
725 | { | ||
726 | struct snd_compr_stream *stream; | ||
727 | |||
728 | stream = container_of(work, struct snd_compr_stream, error_work.work); | ||
729 | |||
730 | mutex_lock(&stream->device->lock); | ||
731 | |||
732 | stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); | ||
733 | wake_up(&stream->runtime->sleep); | ||
734 | |||
735 | mutex_unlock(&stream->device->lock); | ||
736 | } | ||
737 | |||
738 | /* | ||
739 | * snd_compr_stop_error: Report a fatal error on a stream | ||
740 | * @stream: pointer to stream | ||
741 | * @state: state to transition the stream to | ||
742 | * | ||
743 | * Stop the stream and set its state. | ||
744 | * | ||
745 | * Should be called with compressed device lock held. | ||
746 | */ | ||
747 | int snd_compr_stop_error(struct snd_compr_stream *stream, | ||
748 | snd_pcm_state_t state) | ||
749 | { | ||
750 | if (stream->runtime->state == state) | ||
751 | return 0; | ||
752 | |||
753 | stream->runtime->state = state; | ||
754 | |||
755 | pr_debug("Changing state to: %d\n", state); | ||
756 | |||
757 | queue_delayed_work(system_power_efficient_wq, &stream->error_work, 0); | ||
758 | |||
759 | return 0; | ||
760 | } | ||
761 | EXPORT_SYMBOL_GPL(snd_compr_stop_error); | ||
762 | |||
700 | static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) | 763 | static int snd_compress_wait_for_drain(struct snd_compr_stream *stream) |
701 | { | 764 | { |
702 | int ret; | 765 | int ret; |
diff --git a/sound/core/control.c b/sound/core/control.c index b4fe9b002512..fb096cb20a80 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -807,6 +807,36 @@ static int snd_ctl_elem_list(struct snd_card *card, | |||
807 | return 0; | 807 | return 0; |
808 | } | 808 | } |
809 | 809 | ||
810 | static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) | ||
811 | { | ||
812 | unsigned int members; | ||
813 | unsigned int i; | ||
814 | |||
815 | if (info->dimen.d[0] == 0) | ||
816 | return true; | ||
817 | |||
818 | members = 1; | ||
819 | for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) { | ||
820 | if (info->dimen.d[i] == 0) | ||
821 | break; | ||
822 | members *= info->dimen.d[i]; | ||
823 | |||
824 | /* | ||
825 | * info->count should be validated in advance, to guarantee | ||
826 | * calculation soundness. | ||
827 | */ | ||
828 | if (members > info->count) | ||
829 | return false; | ||
830 | } | ||
831 | |||
832 | for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) { | ||
833 | if (info->dimen.d[i] > 0) | ||
834 | return false; | ||
835 | } | ||
836 | |||
837 | return members == info->count; | ||
838 | } | ||
839 | |||
810 | static int snd_ctl_elem_info(struct snd_ctl_file *ctl, | 840 | static int snd_ctl_elem_info(struct snd_ctl_file *ctl, |
811 | struct snd_ctl_elem_info *info) | 841 | struct snd_ctl_elem_info *info) |
812 | { | 842 | { |
@@ -1274,6 +1304,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, | |||
1274 | if (info->count < 1 || | 1304 | if (info->count < 1 || |
1275 | info->count > max_value_counts[info->type]) | 1305 | info->count > max_value_counts[info->type]) |
1276 | return -EINVAL; | 1306 | return -EINVAL; |
1307 | if (!validate_element_member_dimension(info)) | ||
1308 | return -EINVAL; | ||
1277 | private_size = value_sizes[info->type] * info->count; | 1309 | private_size = value_sizes[info->type] * info->count; |
1278 | 1310 | ||
1279 | /* | 1311 | /* |
diff --git a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c index b16dbef04174..cd0e0ebbfdb1 100644 --- a/sound/core/seq/oss/seq_oss_synth.c +++ b/sound/core/seq/oss/seq_oss_synth.c | |||
@@ -70,11 +70,11 @@ struct seq_oss_synth { | |||
70 | static int max_synth_devs; | 70 | static int max_synth_devs; |
71 | static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS]; | 71 | static struct seq_oss_synth *synth_devs[SNDRV_SEQ_OSS_MAX_SYNTH_DEVS]; |
72 | static struct seq_oss_synth midi_synth_dev = { | 72 | static struct seq_oss_synth midi_synth_dev = { |
73 | -1, /* seq_device */ | 73 | .seq_device = -1, |
74 | SYNTH_TYPE_MIDI, /* synth_type */ | 74 | .synth_type = SYNTH_TYPE_MIDI, |
75 | 0, /* synth_subtype */ | 75 | .synth_subtype = 0, |
76 | 16, /* nr_voices */ | 76 | .nr_voices = 16, |
77 | "MIDI", /* name */ | 77 | .name = "MIDI", |
78 | }; | 78 | }; |
79 | 79 | ||
80 | static DEFINE_SPINLOCK(register_lock); | 80 | static DEFINE_SPINLOCK(register_lock); |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 293104926098..dcc102813aef 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -165,7 +165,7 @@ static void snd_seq_timer_interrupt(struct snd_timer_instance *timeri, | |||
165 | snd_seq_timer_update_tick(&tmr->tick, resolution); | 165 | snd_seq_timer_update_tick(&tmr->tick, resolution); |
166 | 166 | ||
167 | /* register actual time of this timer update */ | 167 | /* register actual time of this timer update */ |
168 | do_gettimeofday(&tmr->last_update); | 168 | ktime_get_ts64(&tmr->last_update); |
169 | 169 | ||
170 | spin_unlock_irqrestore(&tmr->lock, flags); | 170 | spin_unlock_irqrestore(&tmr->lock, flags); |
171 | 171 | ||
@@ -392,7 +392,7 @@ static int seq_timer_start(struct snd_seq_timer *tmr) | |||
392 | return -EINVAL; | 392 | return -EINVAL; |
393 | snd_timer_start(tmr->timeri, tmr->ticks); | 393 | snd_timer_start(tmr->timeri, tmr->ticks); |
394 | tmr->running = 1; | 394 | tmr->running = 1; |
395 | do_gettimeofday(&tmr->last_update); | 395 | ktime_get_ts64(&tmr->last_update); |
396 | return 0; | 396 | return 0; |
397 | } | 397 | } |
398 | 398 | ||
@@ -420,7 +420,7 @@ static int seq_timer_continue(struct snd_seq_timer *tmr) | |||
420 | } | 420 | } |
421 | snd_timer_start(tmr->timeri, tmr->ticks); | 421 | snd_timer_start(tmr->timeri, tmr->ticks); |
422 | tmr->running = 1; | 422 | tmr->running = 1; |
423 | do_gettimeofday(&tmr->last_update); | 423 | ktime_get_ts64(&tmr->last_update); |
424 | return 0; | 424 | return 0; |
425 | } | 425 | } |
426 | 426 | ||
@@ -444,17 +444,12 @@ snd_seq_real_time_t snd_seq_timer_get_cur_time(struct snd_seq_timer *tmr) | |||
444 | spin_lock_irqsave(&tmr->lock, flags); | 444 | spin_lock_irqsave(&tmr->lock, flags); |
445 | cur_time = tmr->cur_time; | 445 | cur_time = tmr->cur_time; |
446 | if (tmr->running) { | 446 | if (tmr->running) { |
447 | struct timeval tm; | 447 | struct timespec64 tm; |
448 | int usec; | 448 | |
449 | do_gettimeofday(&tm); | 449 | ktime_get_ts64(&tm); |
450 | usec = (int)(tm.tv_usec - tmr->last_update.tv_usec); | 450 | tm = timespec64_sub(tm, tmr->last_update); |
451 | if (usec < 0) { | 451 | cur_time.tv_nsec = tm.tv_nsec; |
452 | cur_time.tv_nsec += (1000000 + usec) * 1000; | 452 | cur_time.tv_sec = tm.tv_sec; |
453 | cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec - 1; | ||
454 | } else { | ||
455 | cur_time.tv_nsec += usec * 1000; | ||
456 | cur_time.tv_sec += tm.tv_sec - tmr->last_update.tv_sec; | ||
457 | } | ||
458 | snd_seq_sanity_real_time(&cur_time); | 453 | snd_seq_sanity_real_time(&cur_time); |
459 | } | 454 | } |
460 | spin_unlock_irqrestore(&tmr->lock, flags); | 455 | spin_unlock_irqrestore(&tmr->lock, flags); |
diff --git a/sound/core/seq/seq_timer.h b/sound/core/seq/seq_timer.h index 88dfb71805ae..9506b661fe5b 100644 --- a/sound/core/seq/seq_timer.h +++ b/sound/core/seq/seq_timer.h | |||
@@ -52,7 +52,7 @@ struct snd_seq_timer { | |||
52 | unsigned int skew; | 52 | unsigned int skew; |
53 | unsigned int skew_base; | 53 | unsigned int skew_base; |
54 | 54 | ||
55 | struct timeval last_update; /* time of last clock update, used for interpolation */ | 55 | struct timespec64 last_update; /* time of last clock update, used for interpolation */ |
56 | 56 | ||
57 | spinlock_t lock; | 57 | spinlock_t lock; |
58 | }; | 58 | }; |
diff --git a/sound/hda/hdmi_chmap.c b/sound/hda/hdmi_chmap.c index c6c75e7e0981..81acc20c2535 100644 --- a/sound/hda/hdmi_chmap.c +++ b/sound/hda/hdmi_chmap.c | |||
@@ -353,7 +353,8 @@ static void hdmi_std_setup_channel_mapping(struct hdac_chmap *chmap, | |||
353 | int hdmi_slot = 0; | 353 | int hdmi_slot = 0; |
354 | /* fill actual channel mappings in ALSA channel (i) order */ | 354 | /* fill actual channel mappings in ALSA channel (i) order */ |
355 | for (i = 0; i < ch_alloc->channels; i++) { | 355 | for (i = 0; i < ch_alloc->channels; i++) { |
356 | while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8)) | 356 | while (!WARN_ON(hdmi_slot >= 8) && |
357 | !ch_alloc->speakers[7 - hdmi_slot]) | ||
357 | hdmi_slot++; /* skip zero slots */ | 358 | hdmi_slot++; /* skip zero slots */ |
358 | 359 | ||
359 | hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; | 360 | hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; |
@@ -430,6 +431,12 @@ static int to_cea_slot(int ordered_ca, unsigned char pos) | |||
430 | int mask = snd_hdac_chmap_to_spk_mask(pos); | 431 | int mask = snd_hdac_chmap_to_spk_mask(pos); |
431 | int i; | 432 | int i; |
432 | 433 | ||
434 | /* Add sanity check to pass klockwork check. | ||
435 | * This should never happen. | ||
436 | */ | ||
437 | if (ordered_ca >= ARRAY_SIZE(channel_allocations)) | ||
438 | return -1; | ||
439 | |||
433 | if (mask) { | 440 | if (mask) { |
434 | for (i = 0; i < 8; i++) { | 441 | for (i = 0; i < 8; i++) { |
435 | if (channel_allocations[ordered_ca].speakers[7 - i] == mask) | 442 | if (channel_allocations[ordered_ca].speakers[7 - i] == mask) |
@@ -456,7 +463,15 @@ EXPORT_SYMBOL_GPL(snd_hdac_spk_to_chmap); | |||
456 | /* from CEA slot to ALSA API channel position */ | 463 | /* from CEA slot to ALSA API channel position */ |
457 | static int from_cea_slot(int ordered_ca, unsigned char slot) | 464 | static int from_cea_slot(int ordered_ca, unsigned char slot) |
458 | { | 465 | { |
459 | int mask = channel_allocations[ordered_ca].speakers[7 - slot]; | 466 | int mask; |
467 | |||
468 | /* Add sanity check to pass klockwork check. | ||
469 | * This should never happen. | ||
470 | */ | ||
471 | if (slot >= 8) | ||
472 | return 0; | ||
473 | |||
474 | mask = channel_allocations[ordered_ca].speakers[7 - slot]; | ||
460 | 475 | ||
461 | return snd_hdac_spk_to_chmap(mask); | 476 | return snd_hdac_spk_to_chmap(mask); |
462 | } | 477 | } |
@@ -523,7 +538,8 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca) | |||
523 | int ordered_ca = get_channel_allocation_order(ca); | 538 | int ordered_ca = get_channel_allocation_order(ca); |
524 | 539 | ||
525 | for (i = 0; i < 8; i++) { | 540 | for (i = 0; i < 8; i++) { |
526 | if (i < channel_allocations[ordered_ca].channels) | 541 | if (ordered_ca < ARRAY_SIZE(channel_allocations) && |
542 | i < channel_allocations[ordered_ca].channels) | ||
527 | map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f); | 543 | map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f); |
528 | else | 544 | else |
529 | map[i] = 0; | 545 | map[i] = 0; |
@@ -551,6 +567,12 @@ int snd_hdac_get_active_channels(int ca) | |||
551 | { | 567 | { |
552 | int ordered_ca = get_channel_allocation_order(ca); | 568 | int ordered_ca = get_channel_allocation_order(ca); |
553 | 569 | ||
570 | /* Add sanity check to pass klockwork check. | ||
571 | * This should never happen. | ||
572 | */ | ||
573 | if (ordered_ca >= ARRAY_SIZE(channel_allocations)) | ||
574 | ordered_ca = 0; | ||
575 | |||
554 | return channel_allocations[ordered_ca].channels; | 576 | return channel_allocations[ordered_ca].channels; |
555 | } | 577 | } |
556 | EXPORT_SYMBOL_GPL(snd_hdac_get_active_channels); | 578 | EXPORT_SYMBOL_GPL(snd_hdac_get_active_channels); |
diff --git a/sound/i2c/other/ak4114.c b/sound/i2c/other/ak4114.c index 5a4cf3fab4ae..d53c9bb36281 100644 --- a/sound/i2c/other/ak4114.c +++ b/sound/i2c/other/ak4114.c | |||
@@ -121,7 +121,7 @@ int snd_ak4114_create(struct snd_card *card, | |||
121 | 121 | ||
122 | __fail: | 122 | __fail: |
123 | snd_ak4114_free(chip); | 123 | snd_ak4114_free(chip); |
124 | return err < 0 ? err : -EIO; | 124 | return err; |
125 | } | 125 | } |
126 | EXPORT_SYMBOL(snd_ak4114_create); | 126 | EXPORT_SYMBOL(snd_ak4114_create); |
127 | 127 | ||
diff --git a/sound/i2c/other/ak4117.c b/sound/i2c/other/ak4117.c index 48848909a5a9..0702f0552d19 100644 --- a/sound/i2c/other/ak4117.c +++ b/sound/i2c/other/ak4117.c | |||
@@ -110,7 +110,7 @@ int snd_ak4117_create(struct snd_card *card, ak4117_read_t *read, ak4117_write_t | |||
110 | 110 | ||
111 | __fail: | 111 | __fail: |
112 | snd_ak4117_free(chip); | 112 | snd_ak4117_free(chip); |
113 | return err < 0 ? err : -EIO; | 113 | return err; |
114 | } | 114 | } |
115 | 115 | ||
116 | void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val) | 116 | void snd_ak4117_reg_write(struct ak4117 *chip, unsigned char reg, unsigned char mask, unsigned char val) |
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c index f159da4ec890..a302d1f8d14f 100644 --- a/sound/isa/ad1848/ad1848.c +++ b/sound/isa/ad1848/ad1848.c | |||
@@ -170,15 +170,4 @@ static struct isa_driver snd_ad1848_driver = { | |||
170 | } | 170 | } |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static int __init alsa_card_ad1848_init(void) | 173 | module_isa_driver(snd_ad1848_driver, SNDRV_CARDS); |
174 | { | ||
175 | return isa_register_driver(&snd_ad1848_driver, SNDRV_CARDS); | ||
176 | } | ||
177 | |||
178 | static void __exit alsa_card_ad1848_exit(void) | ||
179 | { | ||
180 | isa_unregister_driver(&snd_ad1848_driver); | ||
181 | } | ||
182 | |||
183 | module_init(alsa_card_ad1848_init); | ||
184 | module_exit(alsa_card_ad1848_exit); | ||
diff --git a/sound/isa/adlib.c b/sound/isa/adlib.c index 120c524bb2a0..8d3060fd7ad7 100644 --- a/sound/isa/adlib.c +++ b/sound/isa/adlib.c | |||
@@ -112,15 +112,4 @@ static struct isa_driver snd_adlib_driver = { | |||
112 | } | 112 | } |
113 | }; | 113 | }; |
114 | 114 | ||
115 | static int __init alsa_card_adlib_init(void) | 115 | module_isa_driver(snd_adlib_driver, SNDRV_CARDS); |
116 | { | ||
117 | return isa_register_driver(&snd_adlib_driver, SNDRV_CARDS); | ||
118 | } | ||
119 | |||
120 | static void __exit alsa_card_adlib_exit(void) | ||
121 | { | ||
122 | isa_unregister_driver(&snd_adlib_driver); | ||
123 | } | ||
124 | |||
125 | module_init(alsa_card_adlib_init); | ||
126 | module_exit(alsa_card_adlib_exit); | ||
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index 2c89d95da674..787475084f46 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c | |||
@@ -469,15 +469,4 @@ static struct isa_driver snd_cmi8328_driver = { | |||
469 | }, | 469 | }, |
470 | }; | 470 | }; |
471 | 471 | ||
472 | static int __init alsa_card_cmi8328_init(void) | 472 | module_isa_driver(snd_cmi8328_driver, CMI8328_MAX); |
473 | { | ||
474 | return isa_register_driver(&snd_cmi8328_driver, CMI8328_MAX); | ||
475 | } | ||
476 | |||
477 | static void __exit alsa_card_cmi8328_exit(void) | ||
478 | { | ||
479 | isa_unregister_driver(&snd_cmi8328_driver); | ||
480 | } | ||
481 | |||
482 | module_init(alsa_card_cmi8328_init) | ||
483 | module_exit(alsa_card_cmi8328_exit) | ||
diff --git a/sound/isa/cs423x/cs4231.c b/sound/isa/cs423x/cs4231.c index 282cd75d2235..ef7448e9f813 100644 --- a/sound/isa/cs423x/cs4231.c +++ b/sound/isa/cs423x/cs4231.c | |||
@@ -186,15 +186,4 @@ static struct isa_driver snd_cs4231_driver = { | |||
186 | } | 186 | } |
187 | }; | 187 | }; |
188 | 188 | ||
189 | static int __init alsa_card_cs4231_init(void) | 189 | module_isa_driver(snd_cs4231_driver, SNDRV_CARDS); |
190 | { | ||
191 | return isa_register_driver(&snd_cs4231_driver, SNDRV_CARDS); | ||
192 | } | ||
193 | |||
194 | static void __exit alsa_card_cs4231_exit(void) | ||
195 | { | ||
196 | isa_unregister_driver(&snd_cs4231_driver); | ||
197 | } | ||
198 | |||
199 | module_init(alsa_card_cs4231_init); | ||
200 | module_exit(alsa_card_cs4231_exit); | ||
diff --git a/sound/isa/galaxy/galaxy.c b/sound/isa/galaxy/galaxy.c index 32278847884f..379abe2cbeb2 100644 --- a/sound/isa/galaxy/galaxy.c +++ b/sound/isa/galaxy/galaxy.c | |||
@@ -634,15 +634,4 @@ static struct isa_driver snd_galaxy_driver = { | |||
634 | } | 634 | } |
635 | }; | 635 | }; |
636 | 636 | ||
637 | static int __init alsa_card_galaxy_init(void) | 637 | module_isa_driver(snd_galaxy_driver, SNDRV_CARDS); |
638 | { | ||
639 | return isa_register_driver(&snd_galaxy_driver, SNDRV_CARDS); | ||
640 | } | ||
641 | |||
642 | static void __exit alsa_card_galaxy_exit(void) | ||
643 | { | ||
644 | isa_unregister_driver(&snd_galaxy_driver); | ||
645 | } | ||
646 | |||
647 | module_init(alsa_card_galaxy_init); | ||
648 | module_exit(alsa_card_galaxy_exit); | ||
diff --git a/sound/isa/gus/gusclassic.c b/sound/isa/gus/gusclassic.c index f0019715d82e..c169be49ed71 100644 --- a/sound/isa/gus/gusclassic.c +++ b/sound/isa/gus/gusclassic.c | |||
@@ -229,15 +229,4 @@ static struct isa_driver snd_gusclassic_driver = { | |||
229 | } | 229 | } |
230 | }; | 230 | }; |
231 | 231 | ||
232 | static int __init alsa_card_gusclassic_init(void) | 232 | module_isa_driver(snd_gusclassic_driver, SNDRV_CARDS); |
233 | { | ||
234 | return isa_register_driver(&snd_gusclassic_driver, SNDRV_CARDS); | ||
235 | } | ||
236 | |||
237 | static void __exit alsa_card_gusclassic_exit(void) | ||
238 | { | ||
239 | isa_unregister_driver(&snd_gusclassic_driver); | ||
240 | } | ||
241 | |||
242 | module_init(alsa_card_gusclassic_init); | ||
243 | module_exit(alsa_card_gusclassic_exit); | ||
diff --git a/sound/isa/gus/gusextreme.c b/sound/isa/gus/gusextreme.c index 693d95f46804..77ac2fd723b4 100644 --- a/sound/isa/gus/gusextreme.c +++ b/sound/isa/gus/gusextreme.c | |||
@@ -358,15 +358,4 @@ static struct isa_driver snd_gusextreme_driver = { | |||
358 | } | 358 | } |
359 | }; | 359 | }; |
360 | 360 | ||
361 | static int __init alsa_card_gusextreme_init(void) | 361 | module_isa_driver(snd_gusextreme_driver, SNDRV_CARDS); |
362 | { | ||
363 | return isa_register_driver(&snd_gusextreme_driver, SNDRV_CARDS); | ||
364 | } | ||
365 | |||
366 | static void __exit alsa_card_gusextreme_exit(void) | ||
367 | { | ||
368 | isa_unregister_driver(&snd_gusextreme_driver); | ||
369 | } | ||
370 | |||
371 | module_init(alsa_card_gusextreme_init); | ||
372 | module_exit(alsa_card_gusextreme_exit); | ||
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c index 8216e8d8f017..dd88c9d33492 100644 --- a/sound/isa/gus/gusmax.c +++ b/sound/isa/gus/gusmax.c | |||
@@ -370,15 +370,4 @@ static struct isa_driver snd_gusmax_driver = { | |||
370 | }, | 370 | }, |
371 | }; | 371 | }; |
372 | 372 | ||
373 | static int __init alsa_card_gusmax_init(void) | 373 | module_isa_driver(snd_gusmax_driver, SNDRV_CARDS); |
374 | { | ||
375 | return isa_register_driver(&snd_gusmax_driver, SNDRV_CARDS); | ||
376 | } | ||
377 | |||
378 | static void __exit alsa_card_gusmax_exit(void) | ||
379 | { | ||
380 | isa_unregister_driver(&snd_gusmax_driver); | ||
381 | } | ||
382 | |||
383 | module_init(alsa_card_gusmax_init) | ||
384 | module_exit(alsa_card_gusmax_exit) | ||
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 6b4884d052a5..4d909971eedb 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c | |||
@@ -387,15 +387,4 @@ static struct isa_driver snd_jazz16_driver = { | |||
387 | }, | 387 | }, |
388 | }; | 388 | }; |
389 | 389 | ||
390 | static int __init alsa_card_jazz16_init(void) | 390 | module_isa_driver(snd_jazz16_driver, SNDRV_CARDS); |
391 | { | ||
392 | return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS); | ||
393 | } | ||
394 | |||
395 | static void __exit alsa_card_jazz16_exit(void) | ||
396 | { | ||
397 | isa_unregister_driver(&snd_jazz16_driver); | ||
398 | } | ||
399 | |||
400 | module_init(alsa_card_jazz16_init) | ||
401 | module_exit(alsa_card_jazz16_exit) | ||
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c index b8e2391c33ff..ad42d2364199 100644 --- a/sound/isa/sb/sb8.c +++ b/sound/isa/sb/sb8.c | |||
@@ -251,15 +251,4 @@ static struct isa_driver snd_sb8_driver = { | |||
251 | }, | 251 | }, |
252 | }; | 252 | }; |
253 | 253 | ||
254 | static int __init alsa_card_sb8_init(void) | 254 | module_isa_driver(snd_sb8_driver, SNDRV_CARDS); |
255 | { | ||
256 | return isa_register_driver(&snd_sb8_driver, SNDRV_CARDS); | ||
257 | } | ||
258 | |||
259 | static void __exit alsa_card_sb8_exit(void) | ||
260 | { | ||
261 | isa_unregister_driver(&snd_sb8_driver); | ||
262 | } | ||
263 | |||
264 | module_init(alsa_card_sb8_init) | ||
265 | module_exit(alsa_card_sb8_exit) | ||
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index 51cfa7615f72..b61a6633d8f2 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c | |||
@@ -711,15 +711,4 @@ static struct isa_driver snd_sc6000_driver = { | |||
711 | }; | 711 | }; |
712 | 712 | ||
713 | 713 | ||
714 | static int __init alsa_card_sc6000_init(void) | 714 | module_isa_driver(snd_sc6000_driver, SNDRV_CARDS); |
715 | { | ||
716 | return isa_register_driver(&snd_sc6000_driver, SNDRV_CARDS); | ||
717 | } | ||
718 | |||
719 | static void __exit alsa_card_sc6000_exit(void) | ||
720 | { | ||
721 | isa_unregister_driver(&snd_sc6000_driver); | ||
722 | } | ||
723 | |||
724 | module_init(alsa_card_sc6000_init) | ||
725 | module_exit(alsa_card_sc6000_exit) | ||
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c index 10c8de1f8d29..6368e5c7d0ba 100644 --- a/sound/oss/ad1848.c +++ b/sound/oss/ad1848.c | |||
@@ -254,7 +254,7 @@ static void ad_write(ad1848_info * devc, int reg, int data) | |||
254 | 254 | ||
255 | static void wait_for_calibration(ad1848_info * devc) | 255 | static void wait_for_calibration(ad1848_info * devc) |
256 | { | 256 | { |
257 | int timeout = 0; | 257 | int timeout; |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * Wait until the auto calibration process has finished. | 260 | * Wait until the auto calibration process has finished. |
diff --git a/sound/oss/aedsp16.c b/sound/oss/aedsp16.c index 35b5912cf3f8..bb477d5c8528 100644 --- a/sound/oss/aedsp16.c +++ b/sound/oss/aedsp16.c | |||
@@ -482,13 +482,13 @@ static struct orVals orDMA[] __initdata = { | |||
482 | }; | 482 | }; |
483 | 483 | ||
484 | static struct aedsp16_info ae_config = { | 484 | static struct aedsp16_info ae_config = { |
485 | DEF_AEDSP16_IOB, | 485 | .base_io = DEF_AEDSP16_IOB, |
486 | DEF_AEDSP16_IRQ, | 486 | .irq = DEF_AEDSP16_IRQ, |
487 | DEF_AEDSP16_MRQ, | 487 | .mpu_irq = DEF_AEDSP16_MRQ, |
488 | DEF_AEDSP16_DMA, | 488 | .dma = DEF_AEDSP16_DMA, |
489 | -1, | 489 | .mss_base = -1, |
490 | -1, | 490 | .mpu_base = -1, |
491 | INIT_NONE | 491 | .init = INIT_NONE |
492 | }; | 492 | }; |
493 | 493 | ||
494 | /* | 494 | /* |
diff --git a/sound/oss/sound_firmware.h b/sound/oss/sound_firmware.h index 0a0cbfdfb855..da4c67e005ed 100644 --- a/sound/oss/sound_firmware.h +++ b/sound/oss/sound_firmware.h | |||
@@ -1,2 +1,29 @@ | |||
1 | extern int mod_firmware_load(const char *fn, char **fp); | 1 | #include <linux/fs.h> |
2 | 2 | ||
3 | /** | ||
4 | * mod_firmware_load - load sound driver firmware | ||
5 | * @fn: filename | ||
6 | * @fp: return for the buffer. | ||
7 | * | ||
8 | * Load the firmware for a sound module (up to 128K) into a buffer. | ||
9 | * The buffer is returned in *fp. It is allocated with vmalloc so is | ||
10 | * virtually linear and not DMAable. The caller should free it with | ||
11 | * vfree when finished. | ||
12 | * | ||
13 | * The length of the buffer is returned on a successful load, the | ||
14 | * value zero on a failure. | ||
15 | * | ||
16 | * Caution: This API is not recommended. Firmware should be loaded via | ||
17 | * request_firmware. | ||
18 | */ | ||
19 | static inline int mod_firmware_load(const char *fn, char **fp) | ||
20 | { | ||
21 | loff_t size; | ||
22 | int err; | ||
23 | |||
24 | err = kernel_read_file_from_path((char *)fn, (void **)fp, &size, | ||
25 | 131072, READING_FIRMWARE); | ||
26 | if (err < 0) | ||
27 | return 0; | ||
28 | return size; | ||
29 | } | ||
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c index 8021c85f076d..3a444a6f10eb 100644 --- a/sound/oss/sound_timer.c +++ b/sound/oss/sound_timer.c | |||
@@ -17,7 +17,7 @@ | |||
17 | #include "sound_config.h" | 17 | #include "sound_config.h" |
18 | 18 | ||
19 | static volatile int initialized, opened, tmr_running; | 19 | static volatile int initialized, opened, tmr_running; |
20 | static volatile time_t tmr_offs, tmr_ctr; | 20 | static volatile unsigned int tmr_offs, tmr_ctr; |
21 | static volatile unsigned long ticks_offs; | 21 | static volatile unsigned long ticks_offs; |
22 | static volatile int curr_tempo, curr_timebase; | 22 | static volatile int curr_tempo, curr_timebase; |
23 | static volatile unsigned long curr_ticks; | 23 | static volatile unsigned long curr_ticks; |
diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c index 2226dda0eff0..d17019d25b99 100644 --- a/sound/oss/sys_timer.c +++ b/sound/oss/sys_timer.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include "sound_config.h" | 19 | #include "sound_config.h" |
20 | 20 | ||
21 | static volatile int opened, tmr_running; | 21 | static volatile int opened, tmr_running; |
22 | static volatile time_t tmr_offs, tmr_ctr; | 22 | static volatile unsigned int tmr_offs, tmr_ctr; |
23 | static volatile unsigned long ticks_offs; | 23 | static volatile unsigned long ticks_offs; |
24 | static volatile int curr_tempo, curr_timebase; | 24 | static volatile int curr_tempo, curr_timebase; |
25 | static volatile unsigned long curr_ticks; | 25 | static volatile unsigned long curr_ticks; |
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index 9dc2950e1ab7..6414ecf93efa 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c | |||
@@ -1615,23 +1615,23 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | |||
1615 | int i; | 1615 | int i; |
1616 | struct regs_cs4382 cs_read = {0}; | 1616 | struct regs_cs4382 cs_read = {0}; |
1617 | struct regs_cs4382 cs_def = { | 1617 | struct regs_cs4382 cs_def = { |
1618 | 0x00000001, /* Mode Control 1 */ | 1618 | .mode_control_1 = 0x00000001, /* Mode Control 1 */ |
1619 | 0x00000000, /* Mode Control 2 */ | 1619 | .mode_control_2 = 0x00000000, /* Mode Control 2 */ |
1620 | 0x00000084, /* Mode Control 3 */ | 1620 | .mode_control_3 = 0x00000084, /* Mode Control 3 */ |
1621 | 0x00000000, /* Filter Control */ | 1621 | .filter_control = 0x00000000, /* Filter Control */ |
1622 | 0x00000000, /* Invert Control */ | 1622 | .invert_control = 0x00000000, /* Invert Control */ |
1623 | 0x00000024, /* Mixing Control Pair 1 */ | 1623 | .mix_control_P1 = 0x00000024, /* Mixing Control Pair 1 */ |
1624 | 0x00000000, /* Vol Control A1 */ | 1624 | .vol_control_A1 = 0x00000000, /* Vol Control A1 */ |
1625 | 0x00000000, /* Vol Control B1 */ | 1625 | .vol_control_B1 = 0x00000000, /* Vol Control B1 */ |
1626 | 0x00000024, /* Mixing Control Pair 2 */ | 1626 | .mix_control_P2 = 0x00000024, /* Mixing Control Pair 2 */ |
1627 | 0x00000000, /* Vol Control A2 */ | 1627 | .vol_control_A2 = 0x00000000, /* Vol Control A2 */ |
1628 | 0x00000000, /* Vol Control B2 */ | 1628 | .vol_control_B2 = 0x00000000, /* Vol Control B2 */ |
1629 | 0x00000024, /* Mixing Control Pair 3 */ | 1629 | .mix_control_P3 = 0x00000024, /* Mixing Control Pair 3 */ |
1630 | 0x00000000, /* Vol Control A3 */ | 1630 | .vol_control_A3 = 0x00000000, /* Vol Control A3 */ |
1631 | 0x00000000, /* Vol Control B3 */ | 1631 | .vol_control_B3 = 0x00000000, /* Vol Control B3 */ |
1632 | 0x00000024, /* Mixing Control Pair 4 */ | 1632 | .mix_control_P4 = 0x00000024, /* Mixing Control Pair 4 */ |
1633 | 0x00000000, /* Vol Control A4 */ | 1633 | .vol_control_A4 = 0x00000000, /* Vol Control A4 */ |
1634 | 0x00000000 /* Vol Control B4 */ | 1634 | .vol_control_B4 = 0x00000000 /* Vol Control B4 */ |
1635 | }; | 1635 | }; |
1636 | 1636 | ||
1637 | if (hw->model == CTSB1270) { | 1637 | if (hw->model == CTSB1270) { |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 286f5e3686a3..937071760bc4 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -1272,11 +1272,11 @@ static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol, | |||
1272 | 1272 | ||
1273 | chip = snd_kcontrol_chip(kcontrol); | 1273 | chip = snd_kcontrol_chip(kcontrol); |
1274 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1274 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1275 | uinfo->count = 1; | ||
1276 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 1275 | uinfo->value.integer.min = ECHOGAIN_MINOUT; |
1277 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; | 1276 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; |
1278 | uinfo->dimen.d[0] = num_busses_out(chip); | 1277 | uinfo->dimen.d[0] = num_busses_out(chip); |
1279 | uinfo->dimen.d[1] = num_busses_in(chip); | 1278 | uinfo->dimen.d[1] = num_busses_in(chip); |
1279 | uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1]; | ||
1280 | return 0; | 1280 | return 0; |
1281 | } | 1281 | } |
1282 | 1282 | ||
@@ -1344,11 +1344,11 @@ static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol, | |||
1344 | 1344 | ||
1345 | chip = snd_kcontrol_chip(kcontrol); | 1345 | chip = snd_kcontrol_chip(kcontrol); |
1346 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1346 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1347 | uinfo->count = 1; | ||
1348 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 1347 | uinfo->value.integer.min = ECHOGAIN_MINOUT; |
1349 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; | 1348 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; |
1350 | uinfo->dimen.d[0] = num_busses_out(chip); | 1349 | uinfo->dimen.d[0] = num_busses_out(chip); |
1351 | uinfo->dimen.d[1] = num_pipes_out(chip); | 1350 | uinfo->dimen.d[1] = num_pipes_out(chip); |
1351 | uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1]; | ||
1352 | return 0; | 1352 | return 0; |
1353 | } | 1353 | } |
1354 | 1354 | ||
@@ -1728,7 +1728,6 @@ static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, | |||
1728 | struct snd_ctl_elem_info *uinfo) | 1728 | struct snd_ctl_elem_info *uinfo) |
1729 | { | 1729 | { |
1730 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 1730 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
1731 | uinfo->count = 96; | ||
1732 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 1731 | uinfo->value.integer.min = ECHOGAIN_MINOUT; |
1733 | uinfo->value.integer.max = 0; | 1732 | uinfo->value.integer.max = 0; |
1734 | #ifdef ECHOCARD_HAS_VMIXER | 1733 | #ifdef ECHOCARD_HAS_VMIXER |
@@ -1738,6 +1737,7 @@ static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, | |||
1738 | #endif | 1737 | #endif |
1739 | uinfo->dimen.d[1] = 16; /* 16 channels */ | 1738 | uinfo->dimen.d[1] = 16; /* 16 channels */ |
1740 | uinfo->dimen.d[2] = 2; /* 0=level, 1=peak */ | 1739 | uinfo->dimen.d[2] = 2; /* 0=level, 1=peak */ |
1740 | uinfo->count = uinfo->dimen.d[0] * uinfo->dimen.d[1] * uinfo->dimen.d[2]; | ||
1741 | return 0; | 1741 | return 0; |
1742 | } | 1742 | } |
1743 | 1743 | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 83741887faa1..9913be8532ab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -3584,6 +3584,12 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, | |||
3584 | bool reset; | 3584 | bool reset; |
3585 | 3585 | ||
3586 | spdif = snd_hda_spdif_out_of_nid(codec, nid); | 3586 | spdif = snd_hda_spdif_out_of_nid(codec, nid); |
3587 | /* Add sanity check to pass klockwork check. | ||
3588 | * This should never happen. | ||
3589 | */ | ||
3590 | if (WARN_ON(spdif == NULL)) | ||
3591 | return; | ||
3592 | |||
3587 | curr_fmt = snd_hda_codec_read(codec, nid, 0, | 3593 | curr_fmt = snd_hda_codec_read(codec, nid, 0, |
3588 | AC_VERB_GET_STREAM_FORMAT, 0); | 3594 | AC_VERB_GET_STREAM_FORMAT, 0); |
3589 | reset = codec->spdif_status_reset && | 3595 | reset = codec->spdif_status_reset && |
@@ -3768,7 +3774,7 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, | |||
3768 | spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); | 3774 | spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); |
3769 | if (mout->dig_out_nid && mout->share_spdif && | 3775 | if (mout->dig_out_nid && mout->share_spdif && |
3770 | mout->dig_out_used != HDA_DIG_EXCLUSIVE) { | 3776 | mout->dig_out_used != HDA_DIG_EXCLUSIVE) { |
3771 | if (chs == 2 && | 3777 | if (chs == 2 && spdif != NULL && |
3772 | snd_hda_is_supported_format(codec, mout->dig_out_nid, | 3778 | snd_hda_is_supported_format(codec, mout->dig_out_nid, |
3773 | format) && | 3779 | format) && |
3774 | !(spdif->status & IEC958_AES0_NONAUDIO)) { | 3780 | !(spdif->status & IEC958_AES0_NONAUDIO)) { |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 79c7b340acc2..e7c8f4f076d5 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -2492,10 +2492,6 @@ static int create_loopback_mixing_ctl(struct hda_codec *codec) | |||
2492 | if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) | 2492 | if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) |
2493 | return -ENOMEM; | 2493 | return -ENOMEM; |
2494 | spec->have_aamix_ctl = 1; | 2494 | spec->have_aamix_ctl = 1; |
2495 | /* if no explicit aamix path is present (e.g. for Realtek codecs), | ||
2496 | * enable aamix as default -- just for compatibility | ||
2497 | */ | ||
2498 | spec->aamix_mode = !has_aamix_out_paths(spec); | ||
2499 | return 0; | 2495 | return 0; |
2500 | } | 2496 | } |
2501 | 2497 | ||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index d0d5ad8beac5..56e5204ac9c1 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -1680,6 +1680,11 @@ static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) | |||
1680 | 1680 | ||
1681 | mutex_lock(&codec->spdif_mutex); | 1681 | mutex_lock(&codec->spdif_mutex); |
1682 | spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid); | 1682 | spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid); |
1683 | /* Add sanity check to pass klockwork check. | ||
1684 | * This should never happen. | ||
1685 | */ | ||
1686 | if (WARN_ON(spdif == NULL)) | ||
1687 | return true; | ||
1683 | non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); | 1688 | non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO); |
1684 | mutex_unlock(&codec->spdif_mutex); | 1689 | mutex_unlock(&codec->spdif_mutex); |
1685 | return non_pcm; | 1690 | return non_pcm; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index abcb5a6a1cd9..ddd29b9819ba 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -3718,6 +3718,9 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) | |||
3718 | case 0x10ec0295: | 3718 | case 0x10ec0295: |
3719 | alc_process_coef_fw(codec, coef0225); | 3719 | alc_process_coef_fw(codec, coef0225); |
3720 | break; | 3720 | break; |
3721 | case 0x10ec0867: | ||
3722 | alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); | ||
3723 | break; | ||
3721 | } | 3724 | } |
3722 | codec_dbg(codec, "Headset jack set to unplugged mode.\n"); | 3725 | codec_dbg(codec, "Headset jack set to unplugged mode.\n"); |
3723 | } | 3726 | } |
@@ -3805,6 +3808,9 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, | |||
3805 | alc_process_coef_fw(codec, coef0293); | 3808 | alc_process_coef_fw(codec, coef0293); |
3806 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | 3809 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); |
3807 | break; | 3810 | break; |
3811 | case 0x10ec0867: | ||
3812 | alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14); | ||
3813 | /* fallthru */ | ||
3808 | case 0x10ec0662: | 3814 | case 0x10ec0662: |
3809 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); | 3815 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); |
3810 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | 3816 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); |
@@ -3899,6 +3905,9 @@ static void alc_headset_mode_default(struct hda_codec *codec) | |||
3899 | case 0x10ec0668: | 3905 | case 0x10ec0668: |
3900 | alc_process_coef_fw(codec, coef0688); | 3906 | alc_process_coef_fw(codec, coef0688); |
3901 | break; | 3907 | break; |
3908 | case 0x10ec0867: | ||
3909 | alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); | ||
3910 | break; | ||
3902 | } | 3911 | } |
3903 | codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); | 3912 | codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); |
3904 | } | 3913 | } |
@@ -3989,6 +3998,9 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) | |||
3989 | case 0x10ec0295: | 3998 | case 0x10ec0295: |
3990 | alc_process_coef_fw(codec, coef0225); | 3999 | alc_process_coef_fw(codec, coef0225); |
3991 | break; | 4000 | break; |
4001 | case 0x10ec0867: | ||
4002 | alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0); | ||
4003 | break; | ||
3992 | } | 4004 | } |
3993 | codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); | 4005 | codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); |
3994 | } | 4006 | } |
@@ -4166,6 +4178,9 @@ static void alc_determine_headset_type(struct hda_codec *codec) | |||
4166 | val = alc_read_coef_idx(codec, 0x46); | 4178 | val = alc_read_coef_idx(codec, 0x46); |
4167 | is_ctia = (val & 0x00f0) == 0x00f0; | 4179 | is_ctia = (val & 0x00f0) == 0x00f0; |
4168 | break; | 4180 | break; |
4181 | case 0x10ec0867: | ||
4182 | is_ctia = true; | ||
4183 | break; | ||
4169 | } | 4184 | } |
4170 | 4185 | ||
4171 | codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", | 4186 | codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", |
@@ -6532,6 +6547,8 @@ enum { | |||
6532 | ALC668_FIXUP_DELL_XPS13, | 6547 | ALC668_FIXUP_DELL_XPS13, |
6533 | ALC662_FIXUP_ASUS_Nx50, | 6548 | ALC662_FIXUP_ASUS_Nx50, |
6534 | ALC668_FIXUP_ASUS_Nx51, | 6549 | ALC668_FIXUP_ASUS_Nx51, |
6550 | ALC891_FIXUP_HEADSET_MODE, | ||
6551 | ALC891_FIXUP_DELL_MIC_NO_PRESENCE, | ||
6535 | }; | 6552 | }; |
6536 | 6553 | ||
6537 | static const struct hda_fixup alc662_fixups[] = { | 6554 | static const struct hda_fixup alc662_fixups[] = { |
@@ -6787,6 +6804,20 @@ static const struct hda_fixup alc662_fixups[] = { | |||
6787 | .chained = true, | 6804 | .chained = true, |
6788 | .chain_id = ALC662_FIXUP_BASS_CHMAP, | 6805 | .chain_id = ALC662_FIXUP_BASS_CHMAP, |
6789 | }, | 6806 | }, |
6807 | [ALC891_FIXUP_HEADSET_MODE] = { | ||
6808 | .type = HDA_FIXUP_FUNC, | ||
6809 | .v.func = alc_fixup_headset_mode, | ||
6810 | }, | ||
6811 | [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = { | ||
6812 | .type = HDA_FIXUP_PINS, | ||
6813 | .v.pins = (const struct hda_pintbl[]) { | ||
6814 | { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ | ||
6815 | { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ | ||
6816 | { } | ||
6817 | }, | ||
6818 | .chained = true, | ||
6819 | .chain_id = ALC891_FIXUP_HEADSET_MODE | ||
6820 | }, | ||
6790 | }; | 6821 | }; |
6791 | 6822 | ||
6792 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { | 6823 | static const struct snd_pci_quirk alc662_fixup_tbl[] = { |
@@ -6903,6 +6934,11 @@ static const struct hda_model_fixup alc662_fixup_models[] = { | |||
6903 | }; | 6934 | }; |
6904 | 6935 | ||
6905 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { | 6936 | static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { |
6937 | SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE, | ||
6938 | {0x17, 0x02211010}, | ||
6939 | {0x18, 0x01a19030}, | ||
6940 | {0x1a, 0x01813040}, | ||
6941 | {0x21, 0x01014020}), | ||
6906 | SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, | 6942 | SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE, |
6907 | {0x14, 0x01014010}, | 6943 | {0x14, 0x01014010}, |
6908 | {0x18, 0x01a19020}, | 6944 | {0x18, 0x01a19020}, |
@@ -7091,7 +7127,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { | |||
7091 | HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269), | 7127 | HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269), |
7092 | HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269), | 7128 | HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269), |
7093 | HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269), | 7129 | HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269), |
7094 | HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc882), | 7130 | HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662), |
7095 | HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), | 7131 | HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880), |
7096 | HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), | 7132 | HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882), |
7097 | HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), | 7133 | HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882), |
diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 58fd79ebac20..51e53497f0ad 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c | |||
@@ -965,7 +965,7 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel) | |||
965 | int err; | 965 | int err; |
966 | struct mixart_msg request; | 966 | struct mixart_msg request; |
967 | struct mixart_set_out_audio_level audio_level; | 967 | struct mixart_set_out_audio_level audio_level; |
968 | u32 resp; | 968 | u32 resp = 0; |
969 | 969 | ||
970 | if(chip->pipe_out_ana.status == PIPE_UNDEFINED) | 970 | if(chip->pipe_out_ana.status == PIPE_UNDEFINED) |
971 | return -EINVAL; /* no pipe defined */ | 971 | return -EINVAL; /* no pipe defined */ |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 94639d6b5fb5..067a91207d8e 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -1496,7 +1496,7 @@ static int snd_riptide_prepare(struct snd_pcm_substream *substream) | |||
1496 | f = PAGE_SIZE; | 1496 | f = PAGE_SIZE; |
1497 | while ((size + (f >> 1) - 1) <= (f << 7) && (f << 1) > period) | 1497 | while ((size + (f >> 1) - 1) <= (f << 7) && (f << 1) > period) |
1498 | f = f >> 1; | 1498 | f = f >> 1; |
1499 | pages = (size + f - 1) / f; | 1499 | pages = DIV_ROUND_UP(size, f); |
1500 | data->size = size; | 1500 | data->size = size; |
1501 | data->pages = pages; | 1501 | data->pages = pages; |
1502 | snd_printdd | 1502 | snd_printdd |
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 09da7b52bc2e..1468e4b7bf93 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c | |||
@@ -991,6 +991,7 @@ snd_pmac_awacs_init(struct snd_pmac *chip) | |||
991 | if (err < 0) | 991 | if (err < 0) |
992 | return err; | 992 | return err; |
993 | } | 993 | } |
994 | master_vol = NULL; | ||
994 | if (pm7500) | 995 | if (pm7500) |
995 | err = build_mixers(chip, | 996 | err = build_mixers(chip, |
996 | ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500), | 997 | ARRAY_SIZE(snd_pmac_awacs_mixers_pmac7500), |
diff --git a/sound/sh/aica.c b/sound/sh/aica.c index ad3d9ae38034..fbbc25279559 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c | |||
@@ -63,9 +63,6 @@ MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | |||
63 | module_param(enable, bool, 0644); | 63 | module_param(enable, bool, 0644); |
64 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | 64 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); |
65 | 65 | ||
66 | /* Use workqueue */ | ||
67 | static struct workqueue_struct *aica_queue; | ||
68 | |||
69 | /* Simple platform device */ | 66 | /* Simple platform device */ |
70 | static struct platform_device *pd; | 67 | static struct platform_device *pd; |
71 | static struct resource aica_memory_space[2] = { | 68 | static struct resource aica_memory_space[2] = { |
@@ -327,7 +324,7 @@ static void aica_period_elapsed(unsigned long timer_var) | |||
327 | dreamcastcard->current_period = play_period; | 324 | dreamcastcard->current_period = play_period; |
328 | if (unlikely(dreamcastcard->dma_check == 0)) | 325 | if (unlikely(dreamcastcard->dma_check == 0)) |
329 | dreamcastcard->dma_check = 1; | 326 | dreamcastcard->dma_check = 1; |
330 | queue_work(aica_queue, &(dreamcastcard->spu_dma_work)); | 327 | schedule_work(&(dreamcastcard->spu_dma_work)); |
331 | } | 328 | } |
332 | 329 | ||
333 | static void spu_begin_dma(struct snd_pcm_substream *substream) | 330 | static void spu_begin_dma(struct snd_pcm_substream *substream) |
@@ -337,7 +334,7 @@ static void spu_begin_dma(struct snd_pcm_substream *substream) | |||
337 | runtime = substream->runtime; | 334 | runtime = substream->runtime; |
338 | dreamcastcard = substream->pcm->private_data; | 335 | dreamcastcard = substream->pcm->private_data; |
339 | /*get the queue to do the work */ | 336 | /*get the queue to do the work */ |
340 | queue_work(aica_queue, &(dreamcastcard->spu_dma_work)); | 337 | schedule_work(&(dreamcastcard->spu_dma_work)); |
341 | /* Timer may already be running */ | 338 | /* Timer may already be running */ |
342 | if (unlikely(dreamcastcard->timer.data)) { | 339 | if (unlikely(dreamcastcard->timer.data)) { |
343 | mod_timer(&dreamcastcard->timer, jiffies + 4); | 340 | mod_timer(&dreamcastcard->timer, jiffies + 4); |
@@ -381,7 +378,7 @@ static int snd_aicapcm_pcm_close(struct snd_pcm_substream | |||
381 | *substream) | 378 | *substream) |
382 | { | 379 | { |
383 | struct snd_card_aica *dreamcastcard = substream->pcm->private_data; | 380 | struct snd_card_aica *dreamcastcard = substream->pcm->private_data; |
384 | flush_workqueue(aica_queue); | 381 | flush_work(&(dreamcastcard->spu_dma_work)); |
385 | if (dreamcastcard->timer.data) | 382 | if (dreamcastcard->timer.data) |
386 | del_timer(&dreamcastcard->timer); | 383 | del_timer(&dreamcastcard->timer); |
387 | kfree(dreamcastcard->channel); | 384 | kfree(dreamcastcard->channel); |
@@ -633,9 +630,6 @@ static int snd_aica_probe(struct platform_device *devptr) | |||
633 | if (unlikely(err < 0)) | 630 | if (unlikely(err < 0)) |
634 | goto freedreamcast; | 631 | goto freedreamcast; |
635 | platform_set_drvdata(devptr, dreamcastcard); | 632 | platform_set_drvdata(devptr, dreamcastcard); |
636 | aica_queue = create_workqueue(CARD_NAME); | ||
637 | if (unlikely(!aica_queue)) | ||
638 | goto freedreamcast; | ||
639 | snd_printk | 633 | snd_printk |
640 | ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n"); | 634 | ("ALSA Driver for Yamaha AICA Super Intelligent Sound Processor\n"); |
641 | return 0; | 635 | return 0; |
@@ -671,10 +665,6 @@ static int __init aica_init(void) | |||
671 | 665 | ||
672 | static void __exit aica_exit(void) | 666 | static void __exit aica_exit(void) |
673 | { | 667 | { |
674 | /* Destroy the aica kernel thread * | ||
675 | * being extra cautious to check if it exists*/ | ||
676 | if (likely(aica_queue)) | ||
677 | destroy_workqueue(aica_queue); | ||
678 | platform_device_unregister(pd); | 668 | platform_device_unregister(pd); |
679 | platform_driver_unregister(&snd_aica_driver); | 669 | platform_driver_unregister(&snd_aica_driver); |
680 | /* Kill any sound still playing and reset ARM7 to safe state */ | 670 | /* Kill any sound still playing and reset ARM7 to safe state */ |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index 06e099e802df..22aec9a1e9a4 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -10,6 +10,7 @@ if SND_ATMEL_SOC | |||
10 | 10 | ||
11 | config SND_ATMEL_SOC_PDC | 11 | config SND_ATMEL_SOC_PDC |
12 | tristate | 12 | tristate |
13 | depends on HAS_DMA | ||
13 | default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m | 14 | default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m |
14 | default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) | 15 | default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) |
15 | 16 | ||
diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index 6107de9c538b..6d9b8b44e2da 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c | |||
@@ -593,11 +593,6 @@ static int atmel_classd_probe(struct platform_device *pdev) | |||
593 | } | 593 | } |
594 | 594 | ||
595 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 595 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
596 | if (!res) { | ||
597 | dev_err(dev, "no memory resource\n"); | ||
598 | return -ENXIO; | ||
599 | } | ||
600 | |||
601 | io_base = devm_ioremap_resource(dev, res); | 596 | io_base = devm_ioremap_resource(dev, res); |
602 | if (IS_ERR(io_base)) { | 597 | if (IS_ERR(io_base)) { |
603 | ret = PTR_ERR(io_base); | 598 | ret = PTR_ERR(io_base); |
diff --git a/sound/soc/atmel/atmel-pdmic.c b/sound/soc/atmel/atmel-pdmic.c index aee4787a0b89..5f56da60c92f 100644 --- a/sound/soc/atmel/atmel-pdmic.c +++ b/sound/soc/atmel/atmel-pdmic.c | |||
@@ -624,11 +624,6 @@ static int atmel_pdmic_probe(struct platform_device *pdev) | |||
624 | } | 624 | } |
625 | 625 | ||
626 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 626 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
627 | if (!res) { | ||
628 | dev_err(dev, "no memory resource\n"); | ||
629 | return -ENXIO; | ||
630 | } | ||
631 | |||
632 | io_base = devm_ioremap_resource(dev, res); | 627 | io_base = devm_ioremap_resource(dev, res); |
633 | if (IS_ERR(io_base)) { | 628 | if (IS_ERR(io_base)) { |
634 | ret = PTR_ERR(io_base); | 629 | ret = PTR_ERR(io_base); |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1267e1af0fae..54c09acd3fed 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -321,7 +321,7 @@ static int atmel_ssc_startup(struct snd_pcm_substream *substream, | |||
321 | return ret; | 321 | return ret; |
322 | } | 322 | } |
323 | 323 | ||
324 | dma_params = &ssc_dma_params[dai->id][dir]; | 324 | dma_params = &ssc_dma_params[pdev->id][dir]; |
325 | dma_params->ssc = ssc_p->ssc; | 325 | dma_params->ssc = ssc_p->ssc; |
326 | dma_params->substream = substream; | 326 | dma_params->substream = substream; |
327 | 327 | ||
diff --git a/sound/soc/bcm/Kconfig b/sound/soc/bcm/Kconfig index 6a834e109f1d..d528aaceaad9 100644 --- a/sound/soc/bcm/Kconfig +++ b/sound/soc/bcm/Kconfig | |||
@@ -7,3 +7,12 @@ config SND_BCM2835_SOC_I2S | |||
7 | Say Y or M if you want to add support for codecs attached to | 7 | Say Y or M if you want to add support for codecs attached to |
8 | the BCM2835 I2S interface. You will also need | 8 | the BCM2835 I2S interface. You will also need |
9 | to select the audio interfaces to support below. | 9 | to select the audio interfaces to support below. |
10 | |||
11 | config SND_SOC_CYGNUS | ||
12 | tristate "SoC platform audio for Broadcom Cygnus chips" | ||
13 | depends on ARCH_BCM_CYGNUS || COMPILE_TEST | ||
14 | help | ||
15 | Say Y if you want to add support for ASoC audio on Broadcom | ||
16 | Cygnus chips (bcm958300, bcm958305, bcm911360) | ||
17 | |||
18 | If you don't know what to do here, say N. \ No newline at end of file | ||
diff --git a/sound/soc/bcm/Makefile b/sound/soc/bcm/Makefile index bc816b71e5a4..fc739d007884 100644 --- a/sound/soc/bcm/Makefile +++ b/sound/soc/bcm/Makefile | |||
@@ -3,3 +3,8 @@ snd-soc-bcm2835-i2s-objs := bcm2835-i2s.o | |||
3 | 3 | ||
4 | obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o | 4 | obj-$(CONFIG_SND_BCM2835_SOC_I2S) += snd-soc-bcm2835-i2s.o |
5 | 5 | ||
6 | # CYGNUS Platform Support | ||
7 | snd-soc-cygnus-objs := cygnus-pcm.o cygnus-ssp.o | ||
8 | |||
9 | obj-$(CONFIG_SND_SOC_CYGNUS) += snd-soc-cygnus.o | ||
10 | |||
diff --git a/sound/soc/bcm/cygnus-pcm.c b/sound/soc/bcm/cygnus-pcm.c new file mode 100644 index 000000000000..d616e096462e --- /dev/null +++ b/sound/soc/bcm/cygnus-pcm.c | |||
@@ -0,0 +1,861 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Broadcom Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #include <linux/debugfs.h> | ||
14 | #include <linux/dma-mapping.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/timer.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dai.h> | ||
25 | |||
26 | #include "cygnus-ssp.h" | ||
27 | |||
28 | /* Register offset needed for ASoC PCM module */ | ||
29 | |||
30 | #define INTH_R5F_STATUS_OFFSET 0x040 | ||
31 | #define INTH_R5F_CLEAR_OFFSET 0x048 | ||
32 | #define INTH_R5F_MASK_SET_OFFSET 0x050 | ||
33 | #define INTH_R5F_MASK_CLEAR_OFFSET 0x054 | ||
34 | |||
35 | #define BF_REARM_FREE_MARK_OFFSET 0x344 | ||
36 | #define BF_REARM_FULL_MARK_OFFSET 0x348 | ||
37 | |||
38 | /* Ring Buffer Ctrl Regs --- Start */ | ||
39 | /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_RDADDR_REG_BASE */ | ||
40 | #define SRC_RBUF_0_RDADDR_OFFSET 0x500 | ||
41 | #define SRC_RBUF_1_RDADDR_OFFSET 0x518 | ||
42 | #define SRC_RBUF_2_RDADDR_OFFSET 0x530 | ||
43 | #define SRC_RBUF_3_RDADDR_OFFSET 0x548 | ||
44 | #define SRC_RBUF_4_RDADDR_OFFSET 0x560 | ||
45 | #define SRC_RBUF_5_RDADDR_OFFSET 0x578 | ||
46 | #define SRC_RBUF_6_RDADDR_OFFSET 0x590 | ||
47 | |||
48 | /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_WRADDR_REG_BASE */ | ||
49 | #define SRC_RBUF_0_WRADDR_OFFSET 0x504 | ||
50 | #define SRC_RBUF_1_WRADDR_OFFSET 0x51c | ||
51 | #define SRC_RBUF_2_WRADDR_OFFSET 0x534 | ||
52 | #define SRC_RBUF_3_WRADDR_OFFSET 0x54c | ||
53 | #define SRC_RBUF_4_WRADDR_OFFSET 0x564 | ||
54 | #define SRC_RBUF_5_WRADDR_OFFSET 0x57c | ||
55 | #define SRC_RBUF_6_WRADDR_OFFSET 0x594 | ||
56 | |||
57 | /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_BASEADDR_REG_BASE */ | ||
58 | #define SRC_RBUF_0_BASEADDR_OFFSET 0x508 | ||
59 | #define SRC_RBUF_1_BASEADDR_OFFSET 0x520 | ||
60 | #define SRC_RBUF_2_BASEADDR_OFFSET 0x538 | ||
61 | #define SRC_RBUF_3_BASEADDR_OFFSET 0x550 | ||
62 | #define SRC_RBUF_4_BASEADDR_OFFSET 0x568 | ||
63 | #define SRC_RBUF_5_BASEADDR_OFFSET 0x580 | ||
64 | #define SRC_RBUF_6_BASEADDR_OFFSET 0x598 | ||
65 | |||
66 | /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_ENDADDR_REG_BASE */ | ||
67 | #define SRC_RBUF_0_ENDADDR_OFFSET 0x50c | ||
68 | #define SRC_RBUF_1_ENDADDR_OFFSET 0x524 | ||
69 | #define SRC_RBUF_2_ENDADDR_OFFSET 0x53c | ||
70 | #define SRC_RBUF_3_ENDADDR_OFFSET 0x554 | ||
71 | #define SRC_RBUF_4_ENDADDR_OFFSET 0x56c | ||
72 | #define SRC_RBUF_5_ENDADDR_OFFSET 0x584 | ||
73 | #define SRC_RBUF_6_ENDADDR_OFFSET 0x59c | ||
74 | |||
75 | /* AUD_FMM_BF_CTRL_SOURCECH_RINGBUF_X_FREE_MARK_REG_BASE */ | ||
76 | #define SRC_RBUF_0_FREE_MARK_OFFSET 0x510 | ||
77 | #define SRC_RBUF_1_FREE_MARK_OFFSET 0x528 | ||
78 | #define SRC_RBUF_2_FREE_MARK_OFFSET 0x540 | ||
79 | #define SRC_RBUF_3_FREE_MARK_OFFSET 0x558 | ||
80 | #define SRC_RBUF_4_FREE_MARK_OFFSET 0x570 | ||
81 | #define SRC_RBUF_5_FREE_MARK_OFFSET 0x588 | ||
82 | #define SRC_RBUF_6_FREE_MARK_OFFSET 0x5a0 | ||
83 | |||
84 | /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_RDADDR_REG_BASE */ | ||
85 | #define DST_RBUF_0_RDADDR_OFFSET 0x5c0 | ||
86 | #define DST_RBUF_1_RDADDR_OFFSET 0x5d8 | ||
87 | #define DST_RBUF_2_RDADDR_OFFSET 0x5f0 | ||
88 | #define DST_RBUF_3_RDADDR_OFFSET 0x608 | ||
89 | #define DST_RBUF_4_RDADDR_OFFSET 0x620 | ||
90 | #define DST_RBUF_5_RDADDR_OFFSET 0x638 | ||
91 | |||
92 | /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_WRADDR_REG_BASE */ | ||
93 | #define DST_RBUF_0_WRADDR_OFFSET 0x5c4 | ||
94 | #define DST_RBUF_1_WRADDR_OFFSET 0x5dc | ||
95 | #define DST_RBUF_2_WRADDR_OFFSET 0x5f4 | ||
96 | #define DST_RBUF_3_WRADDR_OFFSET 0x60c | ||
97 | #define DST_RBUF_4_WRADDR_OFFSET 0x624 | ||
98 | #define DST_RBUF_5_WRADDR_OFFSET 0x63c | ||
99 | |||
100 | /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_BASEADDR_REG_BASE */ | ||
101 | #define DST_RBUF_0_BASEADDR_OFFSET 0x5c8 | ||
102 | #define DST_RBUF_1_BASEADDR_OFFSET 0x5e0 | ||
103 | #define DST_RBUF_2_BASEADDR_OFFSET 0x5f8 | ||
104 | #define DST_RBUF_3_BASEADDR_OFFSET 0x610 | ||
105 | #define DST_RBUF_4_BASEADDR_OFFSET 0x628 | ||
106 | #define DST_RBUF_5_BASEADDR_OFFSET 0x640 | ||
107 | |||
108 | /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_ENDADDR_REG_BASE */ | ||
109 | #define DST_RBUF_0_ENDADDR_OFFSET 0x5cc | ||
110 | #define DST_RBUF_1_ENDADDR_OFFSET 0x5e4 | ||
111 | #define DST_RBUF_2_ENDADDR_OFFSET 0x5fc | ||
112 | #define DST_RBUF_3_ENDADDR_OFFSET 0x614 | ||
113 | #define DST_RBUF_4_ENDADDR_OFFSET 0x62c | ||
114 | #define DST_RBUF_5_ENDADDR_OFFSET 0x644 | ||
115 | |||
116 | /* AUD_FMM_BF_CTRL_DESTCH_RINGBUF_X_FULL_MARK_REG_BASE */ | ||
117 | #define DST_RBUF_0_FULL_MARK_OFFSET 0x5d0 | ||
118 | #define DST_RBUF_1_FULL_MARK_OFFSET 0x5e8 | ||
119 | #define DST_RBUF_2_FULL_MARK_OFFSET 0x600 | ||
120 | #define DST_RBUF_3_FULL_MARK_OFFSET 0x618 | ||
121 | #define DST_RBUF_4_FULL_MARK_OFFSET 0x630 | ||
122 | #define DST_RBUF_5_FULL_MARK_OFFSET 0x648 | ||
123 | /* Ring Buffer Ctrl Regs --- End */ | ||
124 | |||
125 | /* Error Status Regs --- Start */ | ||
126 | /* AUD_FMM_BF_ESR_ESRX_STATUS_REG_BASE */ | ||
127 | #define ESR0_STATUS_OFFSET 0x900 | ||
128 | #define ESR1_STATUS_OFFSET 0x918 | ||
129 | #define ESR2_STATUS_OFFSET 0x930 | ||
130 | #define ESR3_STATUS_OFFSET 0x948 | ||
131 | #define ESR4_STATUS_OFFSET 0x960 | ||
132 | |||
133 | /* AUD_FMM_BF_ESR_ESRX_STATUS_CLEAR_REG_BASE */ | ||
134 | #define ESR0_STATUS_CLR_OFFSET 0x908 | ||
135 | #define ESR1_STATUS_CLR_OFFSET 0x920 | ||
136 | #define ESR2_STATUS_CLR_OFFSET 0x938 | ||
137 | #define ESR3_STATUS_CLR_OFFSET 0x950 | ||
138 | #define ESR4_STATUS_CLR_OFFSET 0x968 | ||
139 | |||
140 | /* AUD_FMM_BF_ESR_ESRX_MASK_REG_BASE */ | ||
141 | #define ESR0_MASK_STATUS_OFFSET 0x90c | ||
142 | #define ESR1_MASK_STATUS_OFFSET 0x924 | ||
143 | #define ESR2_MASK_STATUS_OFFSET 0x93c | ||
144 | #define ESR3_MASK_STATUS_OFFSET 0x954 | ||
145 | #define ESR4_MASK_STATUS_OFFSET 0x96c | ||
146 | |||
147 | /* AUD_FMM_BF_ESR_ESRX_MASK_SET_REG_BASE */ | ||
148 | #define ESR0_MASK_SET_OFFSET 0x910 | ||
149 | #define ESR1_MASK_SET_OFFSET 0x928 | ||
150 | #define ESR2_MASK_SET_OFFSET 0x940 | ||
151 | #define ESR3_MASK_SET_OFFSET 0x958 | ||
152 | #define ESR4_MASK_SET_OFFSET 0x970 | ||
153 | |||
154 | /* AUD_FMM_BF_ESR_ESRX_MASK_CLEAR_REG_BASE */ | ||
155 | #define ESR0_MASK_CLR_OFFSET 0x914 | ||
156 | #define ESR1_MASK_CLR_OFFSET 0x92c | ||
157 | #define ESR2_MASK_CLR_OFFSET 0x944 | ||
158 | #define ESR3_MASK_CLR_OFFSET 0x95c | ||
159 | #define ESR4_MASK_CLR_OFFSET 0x974 | ||
160 | /* Error Status Regs --- End */ | ||
161 | |||
162 | #define R5F_ESR0_SHIFT 0 /* esr0 = fifo underflow */ | ||
163 | #define R5F_ESR1_SHIFT 1 /* esr1 = ringbuf underflow */ | ||
164 | #define R5F_ESR2_SHIFT 2 /* esr2 = ringbuf overflow */ | ||
165 | #define R5F_ESR3_SHIFT 3 /* esr3 = freemark */ | ||
166 | #define R5F_ESR4_SHIFT 4 /* esr4 = fullmark */ | ||
167 | |||
168 | |||
169 | /* Mask for R5F register. Set all relevant interrupt for playback handler */ | ||
170 | #define ANY_PLAYBACK_IRQ (BIT(R5F_ESR0_SHIFT) | \ | ||
171 | BIT(R5F_ESR1_SHIFT) | \ | ||
172 | BIT(R5F_ESR3_SHIFT)) | ||
173 | |||
174 | /* Mask for R5F register. Set all relevant interrupt for capture handler */ | ||
175 | #define ANY_CAPTURE_IRQ (BIT(R5F_ESR2_SHIFT) | BIT(R5F_ESR4_SHIFT)) | ||
176 | |||
177 | /* | ||
178 | * PERIOD_BYTES_MIN is the number of bytes to at which the interrupt will tick. | ||
179 | * This number should be a multiple of 256. Minimum value is 256 | ||
180 | */ | ||
181 | #define PERIOD_BYTES_MIN 0x100 | ||
182 | |||
183 | static const struct snd_pcm_hardware cygnus_pcm_hw = { | ||
184 | .info = SNDRV_PCM_INFO_MMAP | | ||
185 | SNDRV_PCM_INFO_MMAP_VALID | | ||
186 | SNDRV_PCM_INFO_INTERLEAVED, | ||
187 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
188 | SNDRV_PCM_FMTBIT_S32_LE, | ||
189 | |||
190 | /* A period is basically an interrupt */ | ||
191 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
192 | .period_bytes_max = 0x10000, | ||
193 | |||
194 | /* period_min/max gives range of approx interrupts per buffer */ | ||
195 | .periods_min = 2, | ||
196 | .periods_max = 8, | ||
197 | |||
198 | /* | ||
199 | * maximum buffer size in bytes = period_bytes_max * periods_max | ||
200 | * We allocate this amount of data for each enabled channel | ||
201 | */ | ||
202 | .buffer_bytes_max = 4 * 0x8000, | ||
203 | }; | ||
204 | |||
205 | static u64 cygnus_dma_dmamask = DMA_BIT_MASK(32); | ||
206 | |||
207 | static struct cygnus_aio_port *cygnus_dai_get_dma_data( | ||
208 | struct snd_pcm_substream *substream) | ||
209 | { | ||
210 | struct snd_soc_pcm_runtime *soc_runtime = substream->private_data; | ||
211 | |||
212 | return snd_soc_dai_get_dma_data(soc_runtime->cpu_dai, substream); | ||
213 | } | ||
214 | |||
215 | static void ringbuf_set_initial(void __iomem *audio_io, | ||
216 | struct ringbuf_regs *p_rbuf, | ||
217 | bool is_playback, | ||
218 | u32 start, | ||
219 | u32 periodsize, | ||
220 | u32 bufsize) | ||
221 | { | ||
222 | u32 initial_rd; | ||
223 | u32 initial_wr; | ||
224 | u32 end; | ||
225 | u32 fmark_val; /* free or full mark */ | ||
226 | |||
227 | p_rbuf->period_bytes = periodsize; | ||
228 | p_rbuf->buf_size = bufsize; | ||
229 | |||
230 | if (is_playback) { | ||
231 | /* Set the pointers to indicate full (flip uppermost bit) */ | ||
232 | initial_rd = start; | ||
233 | initial_wr = initial_rd ^ BIT(31); | ||
234 | } else { | ||
235 | /* Set the pointers to indicate empty */ | ||
236 | initial_wr = start; | ||
237 | initial_rd = initial_wr; | ||
238 | } | ||
239 | |||
240 | end = start + bufsize - 1; | ||
241 | |||
242 | /* | ||
243 | * The interrupt will fire when free/full mark is *exceeded* | ||
244 | * The fmark value must be multiple of PERIOD_BYTES_MIN so set fmark | ||
245 | * to be PERIOD_BYTES_MIN less than the period size. | ||
246 | */ | ||
247 | fmark_val = periodsize - PERIOD_BYTES_MIN; | ||
248 | |||
249 | writel(start, audio_io + p_rbuf->baseaddr); | ||
250 | writel(end, audio_io + p_rbuf->endaddr); | ||
251 | writel(fmark_val, audio_io + p_rbuf->fmark); | ||
252 | writel(initial_rd, audio_io + p_rbuf->rdaddr); | ||
253 | writel(initial_wr, audio_io + p_rbuf->wraddr); | ||
254 | } | ||
255 | |||
256 | static int configure_ringbuf_regs(struct snd_pcm_substream *substream) | ||
257 | { | ||
258 | struct cygnus_aio_port *aio; | ||
259 | struct ringbuf_regs *p_rbuf; | ||
260 | int status = 0; | ||
261 | |||
262 | aio = cygnus_dai_get_dma_data(substream); | ||
263 | |||
264 | /* Map the ssp portnum to a set of ring buffers. */ | ||
265 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
266 | p_rbuf = &aio->play_rb_regs; | ||
267 | |||
268 | switch (aio->portnum) { | ||
269 | case 0: | ||
270 | *p_rbuf = RINGBUF_REG_PLAYBACK(0); | ||
271 | break; | ||
272 | case 1: | ||
273 | *p_rbuf = RINGBUF_REG_PLAYBACK(2); | ||
274 | break; | ||
275 | case 2: | ||
276 | *p_rbuf = RINGBUF_REG_PLAYBACK(4); | ||
277 | break; | ||
278 | case 3: /* SPDIF */ | ||
279 | *p_rbuf = RINGBUF_REG_PLAYBACK(6); | ||
280 | break; | ||
281 | default: | ||
282 | status = -EINVAL; | ||
283 | } | ||
284 | } else { | ||
285 | p_rbuf = &aio->capture_rb_regs; | ||
286 | |||
287 | switch (aio->portnum) { | ||
288 | case 0: | ||
289 | *p_rbuf = RINGBUF_REG_CAPTURE(0); | ||
290 | break; | ||
291 | case 1: | ||
292 | *p_rbuf = RINGBUF_REG_CAPTURE(2); | ||
293 | break; | ||
294 | case 2: | ||
295 | *p_rbuf = RINGBUF_REG_CAPTURE(4); | ||
296 | break; | ||
297 | default: | ||
298 | status = -EINVAL; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | return status; | ||
303 | } | ||
304 | |||
305 | static struct ringbuf_regs *get_ringbuf(struct snd_pcm_substream *substream) | ||
306 | { | ||
307 | struct cygnus_aio_port *aio; | ||
308 | struct ringbuf_regs *p_rbuf = NULL; | ||
309 | |||
310 | aio = cygnus_dai_get_dma_data(substream); | ||
311 | |||
312 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
313 | p_rbuf = &aio->play_rb_regs; | ||
314 | else | ||
315 | p_rbuf = &aio->capture_rb_regs; | ||
316 | |||
317 | return p_rbuf; | ||
318 | } | ||
319 | |||
320 | static void enable_intr(struct snd_pcm_substream *substream) | ||
321 | { | ||
322 | struct cygnus_aio_port *aio; | ||
323 | u32 clear_mask; | ||
324 | |||
325 | aio = cygnus_dai_get_dma_data(substream); | ||
326 | |||
327 | /* The port number maps to the bit position to be cleared */ | ||
328 | clear_mask = BIT(aio->portnum); | ||
329 | |||
330 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
331 | /* Clear interrupt status before enabling them */ | ||
332 | writel(clear_mask, aio->cygaud->audio + ESR0_STATUS_CLR_OFFSET); | ||
333 | writel(clear_mask, aio->cygaud->audio + ESR1_STATUS_CLR_OFFSET); | ||
334 | writel(clear_mask, aio->cygaud->audio + ESR3_STATUS_CLR_OFFSET); | ||
335 | /* Unmask the interrupts of the given port*/ | ||
336 | writel(clear_mask, aio->cygaud->audio + ESR0_MASK_CLR_OFFSET); | ||
337 | writel(clear_mask, aio->cygaud->audio + ESR1_MASK_CLR_OFFSET); | ||
338 | writel(clear_mask, aio->cygaud->audio + ESR3_MASK_CLR_OFFSET); | ||
339 | |||
340 | writel(ANY_PLAYBACK_IRQ, | ||
341 | aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET); | ||
342 | } else { | ||
343 | writel(clear_mask, aio->cygaud->audio + ESR2_STATUS_CLR_OFFSET); | ||
344 | writel(clear_mask, aio->cygaud->audio + ESR4_STATUS_CLR_OFFSET); | ||
345 | writel(clear_mask, aio->cygaud->audio + ESR2_MASK_CLR_OFFSET); | ||
346 | writel(clear_mask, aio->cygaud->audio + ESR4_MASK_CLR_OFFSET); | ||
347 | |||
348 | writel(ANY_CAPTURE_IRQ, | ||
349 | aio->cygaud->audio + INTH_R5F_MASK_CLEAR_OFFSET); | ||
350 | } | ||
351 | |||
352 | } | ||
353 | |||
354 | static void disable_intr(struct snd_pcm_substream *substream) | ||
355 | { | ||
356 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
357 | struct cygnus_aio_port *aio; | ||
358 | u32 set_mask; | ||
359 | |||
360 | aio = cygnus_dai_get_dma_data(substream); | ||
361 | |||
362 | dev_dbg(rtd->cpu_dai->dev, "%s on port %d\n", __func__, aio->portnum); | ||
363 | |||
364 | /* The port number maps to the bit position to be set */ | ||
365 | set_mask = BIT(aio->portnum); | ||
366 | |||
367 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
368 | /* Mask the interrupts of the given port*/ | ||
369 | writel(set_mask, aio->cygaud->audio + ESR0_MASK_SET_OFFSET); | ||
370 | writel(set_mask, aio->cygaud->audio + ESR1_MASK_SET_OFFSET); | ||
371 | writel(set_mask, aio->cygaud->audio + ESR3_MASK_SET_OFFSET); | ||
372 | } else { | ||
373 | writel(set_mask, aio->cygaud->audio + ESR2_MASK_SET_OFFSET); | ||
374 | writel(set_mask, aio->cygaud->audio + ESR4_MASK_SET_OFFSET); | ||
375 | } | ||
376 | |||
377 | } | ||
378 | |||
379 | static int cygnus_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
380 | { | ||
381 | int ret = 0; | ||
382 | |||
383 | switch (cmd) { | ||
384 | case SNDRV_PCM_TRIGGER_START: | ||
385 | case SNDRV_PCM_TRIGGER_RESUME: | ||
386 | enable_intr(substream); | ||
387 | break; | ||
388 | |||
389 | case SNDRV_PCM_TRIGGER_STOP: | ||
390 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
391 | disable_intr(substream); | ||
392 | break; | ||
393 | default: | ||
394 | ret = -EINVAL; | ||
395 | } | ||
396 | |||
397 | return ret; | ||
398 | } | ||
399 | |||
400 | static void cygnus_pcm_period_elapsed(struct snd_pcm_substream *substream) | ||
401 | { | ||
402 | struct cygnus_aio_port *aio; | ||
403 | struct ringbuf_regs *p_rbuf = NULL; | ||
404 | u32 regval; | ||
405 | |||
406 | aio = cygnus_dai_get_dma_data(substream); | ||
407 | |||
408 | p_rbuf = get_ringbuf(substream); | ||
409 | |||
410 | /* | ||
411 | * If free/full mark interrupt occurs, provide timestamp | ||
412 | * to ALSA and update appropriate idx by period_bytes | ||
413 | */ | ||
414 | snd_pcm_period_elapsed(substream); | ||
415 | |||
416 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
417 | /* Set the ring buffer to full */ | ||
418 | regval = readl(aio->cygaud->audio + p_rbuf->rdaddr); | ||
419 | regval = regval ^ BIT(31); | ||
420 | writel(regval, aio->cygaud->audio + p_rbuf->wraddr); | ||
421 | } else { | ||
422 | /* Set the ring buffer to empty */ | ||
423 | regval = readl(aio->cygaud->audio + p_rbuf->wraddr); | ||
424 | writel(regval, aio->cygaud->audio + p_rbuf->rdaddr); | ||
425 | } | ||
426 | } | ||
427 | |||
428 | /* | ||
429 | * ESR0/1/3 status Description | ||
430 | * 0x1 I2S0_out port caused interrupt | ||
431 | * 0x2 I2S1_out port caused interrupt | ||
432 | * 0x4 I2S2_out port caused interrupt | ||
433 | * 0x8 SPDIF_out port caused interrupt | ||
434 | */ | ||
435 | static void handle_playback_irq(struct cygnus_audio *cygaud) | ||
436 | { | ||
437 | void __iomem *audio_io; | ||
438 | u32 port; | ||
439 | u32 esr_status0, esr_status1, esr_status3; | ||
440 | |||
441 | audio_io = cygaud->audio; | ||
442 | |||
443 | /* | ||
444 | * ESR status gets updates with/without interrupts enabled. | ||
445 | * So, check the ESR mask, which provides interrupt enable/ | ||
446 | * disable status and use it to determine which ESR status | ||
447 | * should be serviced. | ||
448 | */ | ||
449 | esr_status0 = readl(audio_io + ESR0_STATUS_OFFSET); | ||
450 | esr_status0 &= ~readl(audio_io + ESR0_MASK_STATUS_OFFSET); | ||
451 | esr_status1 = readl(audio_io + ESR1_STATUS_OFFSET); | ||
452 | esr_status1 &= ~readl(audio_io + ESR1_MASK_STATUS_OFFSET); | ||
453 | esr_status3 = readl(audio_io + ESR3_STATUS_OFFSET); | ||
454 | esr_status3 &= ~readl(audio_io + ESR3_MASK_STATUS_OFFSET); | ||
455 | |||
456 | for (port = 0; port < CYGNUS_MAX_PLAYBACK_PORTS; port++) { | ||
457 | u32 esrmask = BIT(port); | ||
458 | |||
459 | /* | ||
460 | * Ringbuffer or FIFO underflow | ||
461 | * If we get this interrupt then, it is also true that we have | ||
462 | * not yet responded to the freemark interrupt. | ||
463 | * Log a debug message. The freemark handler below will | ||
464 | * handle getting everything going again. | ||
465 | */ | ||
466 | if ((esrmask & esr_status1) || (esrmask & esr_status0)) { | ||
467 | dev_dbg(cygaud->dev, | ||
468 | "Underrun: esr0=0x%x, esr1=0x%x esr3=0x%x\n", | ||
469 | esr_status0, esr_status1, esr_status3); | ||
470 | } | ||
471 | |||
472 | /* | ||
473 | * Freemark is hit. This is the normal interrupt. | ||
474 | * In typical operation the read and write regs will be equal | ||
475 | */ | ||
476 | if (esrmask & esr_status3) { | ||
477 | struct snd_pcm_substream *playstr; | ||
478 | |||
479 | playstr = cygaud->portinfo[port].play_stream; | ||
480 | cygnus_pcm_period_elapsed(playstr); | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* Clear ESR interrupt */ | ||
485 | writel(esr_status0, audio_io + ESR0_STATUS_CLR_OFFSET); | ||
486 | writel(esr_status1, audio_io + ESR1_STATUS_CLR_OFFSET); | ||
487 | writel(esr_status3, audio_io + ESR3_STATUS_CLR_OFFSET); | ||
488 | /* Rearm freemark logic by writing 1 to the correct bit */ | ||
489 | writel(esr_status3, audio_io + BF_REARM_FREE_MARK_OFFSET); | ||
490 | } | ||
491 | |||
492 | /* | ||
493 | * ESR2/4 status Description | ||
494 | * 0x1 I2S0_in port caused interrupt | ||
495 | * 0x2 I2S1_in port caused interrupt | ||
496 | * 0x4 I2S2_in port caused interrupt | ||
497 | */ | ||
498 | static void handle_capture_irq(struct cygnus_audio *cygaud) | ||
499 | { | ||
500 | void __iomem *audio_io; | ||
501 | u32 port; | ||
502 | u32 esr_status2, esr_status4; | ||
503 | |||
504 | audio_io = cygaud->audio; | ||
505 | |||
506 | /* | ||
507 | * ESR status gets updates with/without interrupts enabled. | ||
508 | * So, check the ESR mask, which provides interrupt enable/ | ||
509 | * disable status and use it to determine which ESR status | ||
510 | * should be serviced. | ||
511 | */ | ||
512 | esr_status2 = readl(audio_io + ESR2_STATUS_OFFSET); | ||
513 | esr_status2 &= ~readl(audio_io + ESR2_MASK_STATUS_OFFSET); | ||
514 | esr_status4 = readl(audio_io + ESR4_STATUS_OFFSET); | ||
515 | esr_status4 &= ~readl(audio_io + ESR4_MASK_STATUS_OFFSET); | ||
516 | |||
517 | for (port = 0; port < CYGNUS_MAX_CAPTURE_PORTS; port++) { | ||
518 | u32 esrmask = BIT(port); | ||
519 | |||
520 | /* | ||
521 | * Ringbuffer or FIFO overflow | ||
522 | * If we get this interrupt then, it is also true that we have | ||
523 | * not yet responded to the fullmark interrupt. | ||
524 | * Log a debug message. The fullmark handler below will | ||
525 | * handle getting everything going again. | ||
526 | */ | ||
527 | if (esrmask & esr_status2) | ||
528 | dev_dbg(cygaud->dev, | ||
529 | "Overflow: esr2=0x%x\n", esr_status2); | ||
530 | |||
531 | if (esrmask & esr_status4) { | ||
532 | struct snd_pcm_substream *capstr; | ||
533 | |||
534 | capstr = cygaud->portinfo[port].capture_stream; | ||
535 | cygnus_pcm_period_elapsed(capstr); | ||
536 | } | ||
537 | } | ||
538 | |||
539 | writel(esr_status2, audio_io + ESR2_STATUS_CLR_OFFSET); | ||
540 | writel(esr_status4, audio_io + ESR4_STATUS_CLR_OFFSET); | ||
541 | /* Rearm fullmark logic by writing 1 to the correct bit */ | ||
542 | writel(esr_status4, audio_io + BF_REARM_FULL_MARK_OFFSET); | ||
543 | } | ||
544 | |||
545 | static irqreturn_t cygnus_dma_irq(int irq, void *data) | ||
546 | { | ||
547 | u32 r5_status; | ||
548 | struct cygnus_audio *cygaud = data; | ||
549 | |||
550 | /* | ||
551 | * R5 status bits Description | ||
552 | * 0 ESR0 (playback FIFO interrupt) | ||
553 | * 1 ESR1 (playback rbuf interrupt) | ||
554 | * 2 ESR2 (capture rbuf interrupt) | ||
555 | * 3 ESR3 (Freemark play. interrupt) | ||
556 | * 4 ESR4 (Fullmark capt. interrupt) | ||
557 | */ | ||
558 | r5_status = readl(cygaud->audio + INTH_R5F_STATUS_OFFSET); | ||
559 | |||
560 | if (!(r5_status & (ANY_PLAYBACK_IRQ | ANY_CAPTURE_IRQ))) | ||
561 | return IRQ_NONE; | ||
562 | |||
563 | /* If playback interrupt happened */ | ||
564 | if (ANY_PLAYBACK_IRQ & r5_status) { | ||
565 | handle_playback_irq(cygaud); | ||
566 | writel(ANY_PLAYBACK_IRQ & r5_status, | ||
567 | cygaud->audio + INTH_R5F_CLEAR_OFFSET); | ||
568 | } | ||
569 | |||
570 | /* If capture interrupt happened */ | ||
571 | if (ANY_CAPTURE_IRQ & r5_status) { | ||
572 | handle_capture_irq(cygaud); | ||
573 | writel(ANY_CAPTURE_IRQ & r5_status, | ||
574 | cygaud->audio + INTH_R5F_CLEAR_OFFSET); | ||
575 | } | ||
576 | |||
577 | return IRQ_HANDLED; | ||
578 | } | ||
579 | |||
580 | static int cygnus_pcm_open(struct snd_pcm_substream *substream) | ||
581 | { | ||
582 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
583 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
584 | struct cygnus_aio_port *aio; | ||
585 | int ret; | ||
586 | |||
587 | aio = cygnus_dai_get_dma_data(substream); | ||
588 | if (!aio) | ||
589 | return -ENODEV; | ||
590 | |||
591 | dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); | ||
592 | |||
593 | snd_soc_set_runtime_hwparams(substream, &cygnus_pcm_hw); | ||
594 | |||
595 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
596 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, PERIOD_BYTES_MIN); | ||
597 | if (ret < 0) | ||
598 | return ret; | ||
599 | |||
600 | ret = snd_pcm_hw_constraint_step(runtime, 0, | ||
601 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, PERIOD_BYTES_MIN); | ||
602 | if (ret < 0) | ||
603 | return ret; | ||
604 | /* | ||
605 | * Keep track of which substream belongs to which port. | ||
606 | * This info is needed by snd_pcm_period_elapsed() in irq_handler | ||
607 | */ | ||
608 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
609 | aio->play_stream = substream; | ||
610 | else | ||
611 | aio->capture_stream = substream; | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int cygnus_pcm_close(struct snd_pcm_substream *substream) | ||
617 | { | ||
618 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
619 | struct cygnus_aio_port *aio; | ||
620 | |||
621 | aio = cygnus_dai_get_dma_data(substream); | ||
622 | |||
623 | dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); | ||
624 | |||
625 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
626 | aio->play_stream = NULL; | ||
627 | else | ||
628 | aio->capture_stream = NULL; | ||
629 | |||
630 | if (!aio->play_stream && !aio->capture_stream) | ||
631 | dev_dbg(rtd->cpu_dai->dev, "freed port %d\n", aio->portnum); | ||
632 | |||
633 | return 0; | ||
634 | } | ||
635 | |||
636 | static int cygnus_pcm_hw_params(struct snd_pcm_substream *substream, | ||
637 | struct snd_pcm_hw_params *params) | ||
638 | { | ||
639 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
640 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
641 | struct cygnus_aio_port *aio; | ||
642 | int ret = 0; | ||
643 | |||
644 | aio = cygnus_dai_get_dma_data(substream); | ||
645 | dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); | ||
646 | |||
647 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
648 | runtime->dma_bytes = params_buffer_bytes(params); | ||
649 | |||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static int cygnus_pcm_hw_free(struct snd_pcm_substream *substream) | ||
654 | { | ||
655 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
656 | struct cygnus_aio_port *aio; | ||
657 | |||
658 | aio = cygnus_dai_get_dma_data(substream); | ||
659 | dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); | ||
660 | |||
661 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static int cygnus_pcm_prepare(struct snd_pcm_substream *substream) | ||
666 | { | ||
667 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
668 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
669 | struct cygnus_aio_port *aio; | ||
670 | unsigned long bufsize, periodsize; | ||
671 | int ret = 0; | ||
672 | bool is_play; | ||
673 | u32 start; | ||
674 | struct ringbuf_regs *p_rbuf = NULL; | ||
675 | |||
676 | aio = cygnus_dai_get_dma_data(substream); | ||
677 | dev_dbg(rtd->cpu_dai->dev, "%s port %d\n", __func__, aio->portnum); | ||
678 | |||
679 | bufsize = snd_pcm_lib_buffer_bytes(substream); | ||
680 | periodsize = snd_pcm_lib_period_bytes(substream); | ||
681 | |||
682 | dev_dbg(rtd->cpu_dai->dev, "%s (buf_size %lu) (period_size %lu)\n", | ||
683 | __func__, bufsize, periodsize); | ||
684 | |||
685 | configure_ringbuf_regs(substream); | ||
686 | |||
687 | p_rbuf = get_ringbuf(substream); | ||
688 | |||
689 | start = runtime->dma_addr; | ||
690 | |||
691 | is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0; | ||
692 | |||
693 | ringbuf_set_initial(aio->cygaud->audio, p_rbuf, is_play, start, | ||
694 | periodsize, bufsize); | ||
695 | |||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | static snd_pcm_uframes_t cygnus_pcm_pointer(struct snd_pcm_substream *substream) | ||
700 | { | ||
701 | struct cygnus_aio_port *aio; | ||
702 | unsigned int res = 0, cur = 0, base = 0; | ||
703 | struct ringbuf_regs *p_rbuf = NULL; | ||
704 | |||
705 | aio = cygnus_dai_get_dma_data(substream); | ||
706 | |||
707 | /* | ||
708 | * Get the offset of the current read (for playack) or write | ||
709 | * index (for capture). Report this value back to the asoc framework. | ||
710 | */ | ||
711 | p_rbuf = get_ringbuf(substream); | ||
712 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
713 | cur = readl(aio->cygaud->audio + p_rbuf->rdaddr); | ||
714 | else | ||
715 | cur = readl(aio->cygaud->audio + p_rbuf->wraddr); | ||
716 | |||
717 | base = readl(aio->cygaud->audio + p_rbuf->baseaddr); | ||
718 | |||
719 | /* | ||
720 | * Mask off the MSB of the rdaddr,wraddr and baseaddr | ||
721 | * since MSB is not part of the address | ||
722 | */ | ||
723 | res = (cur & 0x7fffffff) - (base & 0x7fffffff); | ||
724 | |||
725 | return bytes_to_frames(substream->runtime, res); | ||
726 | } | ||
727 | |||
728 | static int cygnus_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
729 | { | ||
730 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
731 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
732 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
733 | size_t size; | ||
734 | |||
735 | size = cygnus_pcm_hw.buffer_bytes_max; | ||
736 | |||
737 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
738 | buf->dev.dev = pcm->card->dev; | ||
739 | buf->private_data = NULL; | ||
740 | buf->area = dma_alloc_coherent(pcm->card->dev, size, | ||
741 | &buf->addr, GFP_KERNEL); | ||
742 | |||
743 | dev_dbg(rtd->cpu_dai->dev, "%s: size 0x%zx @ %pK\n", | ||
744 | __func__, size, buf->area); | ||
745 | |||
746 | if (!buf->area) { | ||
747 | dev_err(rtd->cpu_dai->dev, "%s: dma_alloc failed\n", __func__); | ||
748 | return -ENOMEM; | ||
749 | } | ||
750 | buf->bytes = size; | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | |||
756 | static const struct snd_pcm_ops cygnus_pcm_ops = { | ||
757 | .open = cygnus_pcm_open, | ||
758 | .close = cygnus_pcm_close, | ||
759 | .ioctl = snd_pcm_lib_ioctl, | ||
760 | .hw_params = cygnus_pcm_hw_params, | ||
761 | .hw_free = cygnus_pcm_hw_free, | ||
762 | .prepare = cygnus_pcm_prepare, | ||
763 | .trigger = cygnus_pcm_trigger, | ||
764 | .pointer = cygnus_pcm_pointer, | ||
765 | }; | ||
766 | |||
767 | static void cygnus_dma_free_dma_buffers(struct snd_pcm *pcm) | ||
768 | { | ||
769 | struct snd_pcm_substream *substream; | ||
770 | struct snd_dma_buffer *buf; | ||
771 | |||
772 | substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | ||
773 | if (substream) { | ||
774 | buf = &substream->dma_buffer; | ||
775 | if (buf->area) { | ||
776 | dma_free_coherent(pcm->card->dev, buf->bytes, | ||
777 | buf->area, buf->addr); | ||
778 | buf->area = NULL; | ||
779 | } | ||
780 | } | ||
781 | |||
782 | substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; | ||
783 | if (substream) { | ||
784 | buf = &substream->dma_buffer; | ||
785 | if (buf->area) { | ||
786 | dma_free_coherent(pcm->card->dev, buf->bytes, | ||
787 | buf->area, buf->addr); | ||
788 | buf->area = NULL; | ||
789 | } | ||
790 | } | ||
791 | } | ||
792 | |||
793 | static int cygnus_dma_new(struct snd_soc_pcm_runtime *rtd) | ||
794 | { | ||
795 | struct snd_card *card = rtd->card->snd_card; | ||
796 | struct snd_pcm *pcm = rtd->pcm; | ||
797 | int ret; | ||
798 | |||
799 | if (!card->dev->dma_mask) | ||
800 | card->dev->dma_mask = &cygnus_dma_dmamask; | ||
801 | if (!card->dev->coherent_dma_mask) | ||
802 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
803 | |||
804 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) { | ||
805 | ret = cygnus_pcm_preallocate_dma_buffer(pcm, | ||
806 | SNDRV_PCM_STREAM_PLAYBACK); | ||
807 | if (ret) | ||
808 | return ret; | ||
809 | } | ||
810 | |||
811 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
812 | ret = cygnus_pcm_preallocate_dma_buffer(pcm, | ||
813 | SNDRV_PCM_STREAM_CAPTURE); | ||
814 | if (ret) { | ||
815 | cygnus_dma_free_dma_buffers(pcm); | ||
816 | return ret; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | return 0; | ||
821 | } | ||
822 | |||
823 | static struct snd_soc_platform_driver cygnus_soc_platform = { | ||
824 | .ops = &cygnus_pcm_ops, | ||
825 | .pcm_new = cygnus_dma_new, | ||
826 | .pcm_free = cygnus_dma_free_dma_buffers, | ||
827 | }; | ||
828 | |||
829 | int cygnus_soc_platform_register(struct device *dev, | ||
830 | struct cygnus_audio *cygaud) | ||
831 | { | ||
832 | int rc = 0; | ||
833 | |||
834 | dev_dbg(dev, "%s Enter\n", __func__); | ||
835 | |||
836 | rc = devm_request_irq(dev, cygaud->irq_num, cygnus_dma_irq, | ||
837 | IRQF_SHARED, "cygnus-audio", cygaud); | ||
838 | if (rc) { | ||
839 | dev_err(dev, "%s request_irq error %d\n", __func__, rc); | ||
840 | return rc; | ||
841 | } | ||
842 | |||
843 | rc = snd_soc_register_platform(dev, &cygnus_soc_platform); | ||
844 | if (rc) { | ||
845 | dev_err(dev, "%s failed\n", __func__); | ||
846 | return rc; | ||
847 | } | ||
848 | |||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | int cygnus_soc_platform_unregister(struct device *dev) | ||
853 | { | ||
854 | snd_soc_unregister_platform(dev); | ||
855 | |||
856 | return 0; | ||
857 | } | ||
858 | |||
859 | MODULE_LICENSE("GPL v2"); | ||
860 | MODULE_AUTHOR("Broadcom"); | ||
861 | MODULE_DESCRIPTION("Cygnus ASoC PCM module"); | ||
diff --git a/sound/soc/bcm/cygnus-ssp.c b/sound/soc/bcm/cygnus-ssp.c new file mode 100644 index 000000000000..e710bb0c5637 --- /dev/null +++ b/sound/soc/bcm/cygnus-ssp.c | |||
@@ -0,0 +1,1529 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Broadcom Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/of_device.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dai.h> | ||
25 | |||
26 | #include "cygnus-ssp.h" | ||
27 | |||
28 | #define DEFAULT_VCO 1354750204 | ||
29 | |||
30 | #define CYGNUS_TDM_RATE \ | ||
31 | (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | \ | ||
32 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050 | \ | ||
33 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
34 | SNDRV_PCM_RATE_48000) | ||
35 | |||
36 | #define CAPTURE_FCI_ID_BASE 0x180 | ||
37 | #define CYGNUS_SSP_TRISTATE_MASK 0x001fff | ||
38 | #define CYGNUS_PLLCLKSEL_MASK 0xf | ||
39 | |||
40 | /* Used with stream_on field to indicate which streams are active */ | ||
41 | #define PLAYBACK_STREAM_MASK BIT(0) | ||
42 | #define CAPTURE_STREAM_MASK BIT(1) | ||
43 | |||
44 | #define I2S_STREAM_CFG_MASK 0xff003ff | ||
45 | #define I2S_CAP_STREAM_CFG_MASK 0xf0 | ||
46 | #define SPDIF_STREAM_CFG_MASK 0x3ff | ||
47 | #define CH_GRP_STEREO 0x1 | ||
48 | |||
49 | /* Begin register offset defines */ | ||
50 | #define AUD_MISC_SEROUT_OE_REG_BASE 0x01c | ||
51 | #define AUD_MISC_SEROUT_SPDIF_OE 12 | ||
52 | #define AUD_MISC_SEROUT_MCLK_OE 3 | ||
53 | #define AUD_MISC_SEROUT_LRCK_OE 2 | ||
54 | #define AUD_MISC_SEROUT_SCLK_OE 1 | ||
55 | #define AUD_MISC_SEROUT_SDAT_OE 0 | ||
56 | |||
57 | /* AUD_FMM_BF_CTRL_xxx regs */ | ||
58 | #define BF_DST_CFG0_OFFSET 0x100 | ||
59 | #define BF_DST_CFG1_OFFSET 0x104 | ||
60 | #define BF_DST_CFG2_OFFSET 0x108 | ||
61 | |||
62 | #define BF_DST_CTRL0_OFFSET 0x130 | ||
63 | #define BF_DST_CTRL1_OFFSET 0x134 | ||
64 | #define BF_DST_CTRL2_OFFSET 0x138 | ||
65 | |||
66 | #define BF_SRC_CFG0_OFFSET 0x148 | ||
67 | #define BF_SRC_CFG1_OFFSET 0x14c | ||
68 | #define BF_SRC_CFG2_OFFSET 0x150 | ||
69 | #define BF_SRC_CFG3_OFFSET 0x154 | ||
70 | |||
71 | #define BF_SRC_CTRL0_OFFSET 0x1c0 | ||
72 | #define BF_SRC_CTRL1_OFFSET 0x1c4 | ||
73 | #define BF_SRC_CTRL2_OFFSET 0x1c8 | ||
74 | #define BF_SRC_CTRL3_OFFSET 0x1cc | ||
75 | |||
76 | #define BF_SRC_GRP0_OFFSET 0x1fc | ||
77 | #define BF_SRC_GRP1_OFFSET 0x200 | ||
78 | #define BF_SRC_GRP2_OFFSET 0x204 | ||
79 | #define BF_SRC_GRP3_OFFSET 0x208 | ||
80 | |||
81 | #define BF_SRC_GRP_EN_OFFSET 0x320 | ||
82 | #define BF_SRC_GRP_FLOWON_OFFSET 0x324 | ||
83 | #define BF_SRC_GRP_SYNC_DIS_OFFSET 0x328 | ||
84 | |||
85 | /* AUD_FMM_IOP_OUT_I2S_xxx regs */ | ||
86 | #define OUT_I2S_0_STREAM_CFG_OFFSET 0xa00 | ||
87 | #define OUT_I2S_0_CFG_OFFSET 0xa04 | ||
88 | #define OUT_I2S_0_MCLK_CFG_OFFSET 0xa0c | ||
89 | |||
90 | #define OUT_I2S_1_STREAM_CFG_OFFSET 0xa40 | ||
91 | #define OUT_I2S_1_CFG_OFFSET 0xa44 | ||
92 | #define OUT_I2S_1_MCLK_CFG_OFFSET 0xa4c | ||
93 | |||
94 | #define OUT_I2S_2_STREAM_CFG_OFFSET 0xa80 | ||
95 | #define OUT_I2S_2_CFG_OFFSET 0xa84 | ||
96 | #define OUT_I2S_2_MCLK_CFG_OFFSET 0xa8c | ||
97 | |||
98 | /* AUD_FMM_IOP_OUT_SPDIF_xxx regs */ | ||
99 | #define SPDIF_STREAM_CFG_OFFSET 0xac0 | ||
100 | #define SPDIF_CTRL_OFFSET 0xac4 | ||
101 | #define SPDIF_FORMAT_CFG_OFFSET 0xad8 | ||
102 | #define SPDIF_MCLK_CFG_OFFSET 0xadc | ||
103 | |||
104 | /* AUD_FMM_IOP_PLL_0_xxx regs */ | ||
105 | #define IOP_PLL_0_MACRO_OFFSET 0xb00 | ||
106 | #define IOP_PLL_0_MDIV_Ch0_OFFSET 0xb14 | ||
107 | #define IOP_PLL_0_MDIV_Ch1_OFFSET 0xb18 | ||
108 | #define IOP_PLL_0_MDIV_Ch2_OFFSET 0xb1c | ||
109 | |||
110 | #define IOP_PLL_0_ACTIVE_MDIV_Ch0_OFFSET 0xb30 | ||
111 | #define IOP_PLL_0_ACTIVE_MDIV_Ch1_OFFSET 0xb34 | ||
112 | #define IOP_PLL_0_ACTIVE_MDIV_Ch2_OFFSET 0xb38 | ||
113 | |||
114 | /* AUD_FMM_IOP_xxx regs */ | ||
115 | #define IOP_PLL_0_CONTROL_OFFSET 0xb04 | ||
116 | #define IOP_PLL_0_USER_NDIV_OFFSET 0xb08 | ||
117 | #define IOP_PLL_0_ACTIVE_NDIV_OFFSET 0xb20 | ||
118 | #define IOP_PLL_0_RESET_OFFSET 0xb5c | ||
119 | |||
120 | /* AUD_FMM_IOP_IN_I2S_xxx regs */ | ||
121 | #define IN_I2S_0_STREAM_CFG_OFFSET 0x00 | ||
122 | #define IN_I2S_0_CFG_OFFSET 0x04 | ||
123 | #define IN_I2S_1_STREAM_CFG_OFFSET 0x40 | ||
124 | #define IN_I2S_1_CFG_OFFSET 0x44 | ||
125 | #define IN_I2S_2_STREAM_CFG_OFFSET 0x80 | ||
126 | #define IN_I2S_2_CFG_OFFSET 0x84 | ||
127 | |||
128 | /* AUD_FMM_IOP_MISC_xxx regs */ | ||
129 | #define IOP_SW_INIT_LOGIC 0x1c0 | ||
130 | |||
131 | /* End register offset defines */ | ||
132 | |||
133 | |||
134 | /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_0_REG */ | ||
135 | #define I2S_OUT_MCLKRATE_SHIFT 16 | ||
136 | |||
137 | /* AUD_FMM_IOP_OUT_I2S_x_MCLK_CFG_REG */ | ||
138 | #define I2S_OUT_PLLCLKSEL_SHIFT 0 | ||
139 | |||
140 | /* AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG */ | ||
141 | #define I2S_OUT_STREAM_ENA 31 | ||
142 | #define I2S_OUT_STREAM_CFG_GROUP_ID 20 | ||
143 | #define I2S_OUT_STREAM_CFG_CHANNEL_GROUPING 24 | ||
144 | |||
145 | /* AUD_FMM_IOP_IN_I2S_x_CAP */ | ||
146 | #define I2S_IN_STREAM_CFG_CAP_ENA 31 | ||
147 | #define I2S_IN_STREAM_CFG_0_GROUP_ID 4 | ||
148 | |||
149 | /* AUD_FMM_IOP_OUT_I2S_x_I2S_CFG_REG */ | ||
150 | #define I2S_OUT_CFGX_CLK_ENA 0 | ||
151 | #define I2S_OUT_CFGX_DATA_ENABLE 1 | ||
152 | #define I2S_OUT_CFGX_DATA_ALIGNMENT 6 | ||
153 | #define I2S_OUT_CFGX_BITS_PER_SLOT 13 | ||
154 | #define I2S_OUT_CFGX_VALID_SLOT 14 | ||
155 | #define I2S_OUT_CFGX_FSYNC_WIDTH 18 | ||
156 | #define I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32 26 | ||
157 | #define I2S_OUT_CFGX_SLAVE_MODE 30 | ||
158 | #define I2S_OUT_CFGX_TDM_MODE 31 | ||
159 | |||
160 | /* AUD_FMM_BF_CTRL_SOURCECH_CFGx_REG */ | ||
161 | #define BF_SRC_CFGX_SFIFO_ENA 0 | ||
162 | #define BF_SRC_CFGX_BUFFER_PAIR_ENABLE 1 | ||
163 | #define BF_SRC_CFGX_SAMPLE_CH_MODE 2 | ||
164 | #define BF_SRC_CFGX_SFIFO_SZ_DOUBLE 5 | ||
165 | #define BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY 10 | ||
166 | #define BF_SRC_CFGX_BIT_RES 20 | ||
167 | #define BF_SRC_CFGX_PROCESS_SEQ_ID_VALID 31 | ||
168 | |||
169 | /* AUD_FMM_BF_CTRL_DESTCH_CFGx_REG */ | ||
170 | #define BF_DST_CFGX_CAP_ENA 0 | ||
171 | #define BF_DST_CFGX_BUFFER_PAIR_ENABLE 1 | ||
172 | #define BF_DST_CFGX_DFIFO_SZ_DOUBLE 2 | ||
173 | #define BF_DST_CFGX_NOT_PAUSE_WHEN_FULL 11 | ||
174 | #define BF_DST_CFGX_FCI_ID 12 | ||
175 | #define BF_DST_CFGX_CAP_MODE 24 | ||
176 | #define BF_DST_CFGX_PROC_SEQ_ID_VALID 31 | ||
177 | |||
178 | /* AUD_FMM_IOP_OUT_SPDIF_xxx */ | ||
179 | #define SPDIF_0_OUT_DITHER_ENA 3 | ||
180 | #define SPDIF_0_OUT_STREAM_ENA 31 | ||
181 | |||
182 | /* AUD_FMM_IOP_PLL_0_USER */ | ||
183 | #define IOP_PLL_0_USER_NDIV_FRAC 10 | ||
184 | |||
185 | /* AUD_FMM_IOP_PLL_0_ACTIVE */ | ||
186 | #define IOP_PLL_0_ACTIVE_NDIV_FRAC 10 | ||
187 | |||
188 | |||
189 | #define INIT_SSP_REGS(num) (struct cygnus_ssp_regs){ \ | ||
190 | .i2s_stream_cfg = OUT_I2S_ ##num## _STREAM_CFG_OFFSET, \ | ||
191 | .i2s_cap_stream_cfg = IN_I2S_ ##num## _STREAM_CFG_OFFSET, \ | ||
192 | .i2s_cfg = OUT_I2S_ ##num## _CFG_OFFSET, \ | ||
193 | .i2s_cap_cfg = IN_I2S_ ##num## _CFG_OFFSET, \ | ||
194 | .i2s_mclk_cfg = OUT_I2S_ ##num## _MCLK_CFG_OFFSET, \ | ||
195 | .bf_destch_ctrl = BF_DST_CTRL ##num## _OFFSET, \ | ||
196 | .bf_destch_cfg = BF_DST_CFG ##num## _OFFSET, \ | ||
197 | .bf_sourcech_ctrl = BF_SRC_CTRL ##num## _OFFSET, \ | ||
198 | .bf_sourcech_cfg = BF_SRC_CFG ##num## _OFFSET, \ | ||
199 | .bf_sourcech_grp = BF_SRC_GRP ##num## _OFFSET \ | ||
200 | } | ||
201 | |||
202 | struct pll_macro_entry { | ||
203 | u32 mclk; | ||
204 | u32 pll_ch_num; | ||
205 | }; | ||
206 | |||
207 | /* | ||
208 | * PLL has 3 output channels (1x, 2x, and 4x). Below are | ||
209 | * the common MCLK frequencies used by audio driver | ||
210 | */ | ||
211 | static const struct pll_macro_entry pll_predef_mclk[] = { | ||
212 | { 4096000, 0}, | ||
213 | { 8192000, 1}, | ||
214 | {16384000, 2}, | ||
215 | |||
216 | { 5644800, 0}, | ||
217 | {11289600, 1}, | ||
218 | {22579200, 2}, | ||
219 | |||
220 | { 6144000, 0}, | ||
221 | {12288000, 1}, | ||
222 | {24576000, 2}, | ||
223 | |||
224 | {12288000, 0}, | ||
225 | {24576000, 1}, | ||
226 | {49152000, 2}, | ||
227 | |||
228 | {22579200, 0}, | ||
229 | {45158400, 1}, | ||
230 | {90316800, 2}, | ||
231 | |||
232 | {24576000, 0}, | ||
233 | {49152000, 1}, | ||
234 | {98304000, 2}, | ||
235 | }; | ||
236 | |||
237 | /* List of valid frame sizes for tdm mode */ | ||
238 | static const int ssp_valid_tdm_framesize[] = {32, 64, 128, 256, 512}; | ||
239 | |||
240 | /* | ||
241 | * Use this relationship to derive the sampling rate (lrclk) | ||
242 | * lrclk = (mclk) / ((2*mclk_to_sclk_ratio) * (32 * SCLK))). | ||
243 | * | ||
244 | * Use mclk and pll_ch from the table above | ||
245 | * | ||
246 | * Valid SCLK = 0/1/2/4/8/12 | ||
247 | * | ||
248 | * mclk_to_sclk_ratio = number of MCLK per SCLK. Division is twice the | ||
249 | * value programmed in this field. | ||
250 | * Valid mclk_to_sclk_ratio = 1 through to 15 | ||
251 | * | ||
252 | * eg: To set lrclk = 48khz, set mclk = 12288000, mclk_to_sclk_ratio = 2, | ||
253 | * SCLK = 64 | ||
254 | */ | ||
255 | struct _ssp_clk_coeff { | ||
256 | u32 mclk; | ||
257 | u32 sclk_rate; | ||
258 | u32 rate; | ||
259 | u32 mclk_rate; | ||
260 | }; | ||
261 | |||
262 | static const struct _ssp_clk_coeff ssp_clk_coeff[] = { | ||
263 | { 4096000, 32, 16000, 4}, | ||
264 | { 4096000, 32, 32000, 2}, | ||
265 | { 4096000, 64, 8000, 4}, | ||
266 | { 4096000, 64, 16000, 2}, | ||
267 | { 4096000, 64, 32000, 1}, | ||
268 | { 4096000, 128, 8000, 2}, | ||
269 | { 4096000, 128, 16000, 1}, | ||
270 | { 4096000, 256, 8000, 1}, | ||
271 | |||
272 | { 6144000, 32, 16000, 6}, | ||
273 | { 6144000, 32, 32000, 3}, | ||
274 | { 6144000, 32, 48000, 2}, | ||
275 | { 6144000, 32, 96000, 1}, | ||
276 | { 6144000, 64, 8000, 6}, | ||
277 | { 6144000, 64, 16000, 3}, | ||
278 | { 6144000, 64, 48000, 1}, | ||
279 | { 6144000, 128, 8000, 3}, | ||
280 | |||
281 | { 8192000, 32, 32000, 4}, | ||
282 | { 8192000, 64, 16000, 4}, | ||
283 | { 8192000, 64, 32000, 2}, | ||
284 | { 8192000, 128, 8000, 4}, | ||
285 | { 8192000, 128, 16000, 2}, | ||
286 | { 8192000, 128, 32000, 1}, | ||
287 | { 8192000, 256, 8000, 2}, | ||
288 | { 8192000, 256, 16000, 1}, | ||
289 | { 8192000, 512, 8000, 1}, | ||
290 | |||
291 | {12288000, 32, 32000, 6}, | ||
292 | {12288000, 32, 48000, 4}, | ||
293 | {12288000, 32, 96000, 2}, | ||
294 | {12288000, 32, 192000, 1}, | ||
295 | {12288000, 64, 16000, 6}, | ||
296 | {12288000, 64, 32000, 3}, | ||
297 | {12288000, 64, 48000, 2}, | ||
298 | {12288000, 64, 96000, 1}, | ||
299 | {12288000, 128, 8000, 6}, | ||
300 | {12288000, 128, 16000, 3}, | ||
301 | {12288000, 128, 48000, 1}, | ||
302 | {12288000, 256, 8000, 3}, | ||
303 | |||
304 | {16384000, 64, 32000, 4}, | ||
305 | {16384000, 128, 16000, 4}, | ||
306 | {16384000, 128, 32000, 2}, | ||
307 | {16384000, 256, 8000, 4}, | ||
308 | {16384000, 256, 16000, 2}, | ||
309 | {16384000, 256, 32000, 1}, | ||
310 | {16384000, 512, 8000, 2}, | ||
311 | {16384000, 512, 16000, 1}, | ||
312 | |||
313 | {24576000, 32, 96000, 4}, | ||
314 | {24576000, 32, 192000, 2}, | ||
315 | {24576000, 64, 32000, 6}, | ||
316 | {24576000, 64, 48000, 4}, | ||
317 | {24576000, 64, 96000, 2}, | ||
318 | {24576000, 64, 192000, 1}, | ||
319 | {24576000, 128, 16000, 6}, | ||
320 | {24576000, 128, 32000, 3}, | ||
321 | {24576000, 128, 48000, 2}, | ||
322 | {24576000, 256, 8000, 6}, | ||
323 | {24576000, 256, 16000, 3}, | ||
324 | {24576000, 256, 48000, 1}, | ||
325 | {24576000, 512, 8000, 3}, | ||
326 | |||
327 | {49152000, 32, 192000, 4}, | ||
328 | {49152000, 64, 96000, 4}, | ||
329 | {49152000, 64, 192000, 2}, | ||
330 | {49152000, 128, 32000, 6}, | ||
331 | {49152000, 128, 48000, 4}, | ||
332 | {49152000, 128, 96000, 2}, | ||
333 | {49152000, 128, 192000, 1}, | ||
334 | {49152000, 256, 16000, 6}, | ||
335 | {49152000, 256, 32000, 3}, | ||
336 | {49152000, 256, 48000, 2}, | ||
337 | {49152000, 256, 96000, 1}, | ||
338 | {49152000, 512, 8000, 6}, | ||
339 | {49152000, 512, 16000, 3}, | ||
340 | {49152000, 512, 48000, 1}, | ||
341 | |||
342 | { 5644800, 32, 22050, 4}, | ||
343 | { 5644800, 32, 44100, 2}, | ||
344 | { 5644800, 32, 88200, 1}, | ||
345 | { 5644800, 64, 11025, 4}, | ||
346 | { 5644800, 64, 22050, 2}, | ||
347 | { 5644800, 64, 44100, 1}, | ||
348 | |||
349 | {11289600, 32, 44100, 4}, | ||
350 | {11289600, 32, 88200, 2}, | ||
351 | {11289600, 32, 176400, 1}, | ||
352 | {11289600, 64, 22050, 4}, | ||
353 | {11289600, 64, 44100, 2}, | ||
354 | {11289600, 64, 88200, 1}, | ||
355 | {11289600, 128, 11025, 4}, | ||
356 | {11289600, 128, 22050, 2}, | ||
357 | {11289600, 128, 44100, 1}, | ||
358 | |||
359 | {22579200, 32, 88200, 4}, | ||
360 | {22579200, 32, 176400, 2}, | ||
361 | {22579200, 64, 44100, 4}, | ||
362 | {22579200, 64, 88200, 2}, | ||
363 | {22579200, 64, 176400, 1}, | ||
364 | {22579200, 128, 22050, 4}, | ||
365 | {22579200, 128, 44100, 2}, | ||
366 | {22579200, 128, 88200, 1}, | ||
367 | {22579200, 256, 11025, 4}, | ||
368 | {22579200, 256, 22050, 2}, | ||
369 | {22579200, 256, 44100, 1}, | ||
370 | |||
371 | {45158400, 32, 176400, 4}, | ||
372 | {45158400, 64, 88200, 4}, | ||
373 | {45158400, 64, 176400, 2}, | ||
374 | {45158400, 128, 44100, 4}, | ||
375 | {45158400, 128, 88200, 2}, | ||
376 | {45158400, 128, 176400, 1}, | ||
377 | {45158400, 256, 22050, 4}, | ||
378 | {45158400, 256, 44100, 2}, | ||
379 | {45158400, 256, 88200, 1}, | ||
380 | {45158400, 512, 11025, 4}, | ||
381 | {45158400, 512, 22050, 2}, | ||
382 | {45158400, 512, 44100, 1}, | ||
383 | }; | ||
384 | |||
385 | static struct cygnus_aio_port *cygnus_dai_get_portinfo(struct snd_soc_dai *dai) | ||
386 | { | ||
387 | struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); | ||
388 | |||
389 | return &cygaud->portinfo[dai->id]; | ||
390 | } | ||
391 | |||
392 | static int audio_ssp_init_portregs(struct cygnus_aio_port *aio) | ||
393 | { | ||
394 | u32 value, fci_id; | ||
395 | int status = 0; | ||
396 | |||
397 | switch (aio->port_type) { | ||
398 | case PORT_TDM: | ||
399 | value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
400 | value &= ~I2S_STREAM_CFG_MASK; | ||
401 | |||
402 | /* Set Group ID */ | ||
403 | writel(aio->portnum, | ||
404 | aio->cygaud->audio + aio->regs.bf_sourcech_grp); | ||
405 | |||
406 | /* Configure the AUD_FMM_IOP_OUT_I2S_x_STREAM_CFG reg */ | ||
407 | value |= aio->portnum << I2S_OUT_STREAM_CFG_GROUP_ID; | ||
408 | value |= aio->portnum; /* FCI ID is the port num */ | ||
409 | value |= CH_GRP_STEREO << I2S_OUT_STREAM_CFG_CHANNEL_GROUPING; | ||
410 | writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
411 | |||
412 | /* Configure the AUD_FMM_BF_CTRL_SOURCECH_CFGX reg */ | ||
413 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
414 | value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY); | ||
415 | value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE); | ||
416 | value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID); | ||
417 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
418 | |||
419 | /* Configure the AUD_FMM_IOP_IN_I2S_x_CAP_STREAM_CFG_0 reg */ | ||
420 | value = readl(aio->cygaud->i2s_in + | ||
421 | aio->regs.i2s_cap_stream_cfg); | ||
422 | value &= ~I2S_CAP_STREAM_CFG_MASK; | ||
423 | value |= aio->portnum << I2S_IN_STREAM_CFG_0_GROUP_ID; | ||
424 | writel(value, aio->cygaud->i2s_in + | ||
425 | aio->regs.i2s_cap_stream_cfg); | ||
426 | |||
427 | /* Configure the AUD_FMM_BF_CTRL_DESTCH_CFGX_REG_BASE reg */ | ||
428 | fci_id = CAPTURE_FCI_ID_BASE + aio->portnum; | ||
429 | |||
430 | value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
431 | value |= BIT(BF_DST_CFGX_DFIFO_SZ_DOUBLE); | ||
432 | value &= ~BIT(BF_DST_CFGX_NOT_PAUSE_WHEN_FULL); | ||
433 | value |= (fci_id << BF_DST_CFGX_FCI_ID); | ||
434 | value |= BIT(BF_DST_CFGX_PROC_SEQ_ID_VALID); | ||
435 | writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
436 | |||
437 | /* Enable the transmit pin for this port */ | ||
438 | value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
439 | value &= ~BIT((aio->portnum * 4) + AUD_MISC_SEROUT_SDAT_OE); | ||
440 | writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
441 | break; | ||
442 | case PORT_SPDIF: | ||
443 | writel(aio->portnum, aio->cygaud->audio + BF_SRC_GRP3_OFFSET); | ||
444 | |||
445 | value = readl(aio->cygaud->audio + SPDIF_CTRL_OFFSET); | ||
446 | value |= BIT(SPDIF_0_OUT_DITHER_ENA); | ||
447 | writel(value, aio->cygaud->audio + SPDIF_CTRL_OFFSET); | ||
448 | |||
449 | /* Enable and set the FCI ID for the SPDIF channel */ | ||
450 | value = readl(aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET); | ||
451 | value &= ~SPDIF_STREAM_CFG_MASK; | ||
452 | value |= aio->portnum; /* FCI ID is the port num */ | ||
453 | value |= BIT(SPDIF_0_OUT_STREAM_ENA); | ||
454 | writel(value, aio->cygaud->audio + SPDIF_STREAM_CFG_OFFSET); | ||
455 | |||
456 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
457 | value &= ~BIT(BF_SRC_CFGX_NOT_PAUSE_WHEN_EMPTY); | ||
458 | value |= BIT(BF_SRC_CFGX_SFIFO_SZ_DOUBLE); | ||
459 | value |= BIT(BF_SRC_CFGX_PROCESS_SEQ_ID_VALID); | ||
460 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
461 | |||
462 | /* Enable the spdif output pin */ | ||
463 | value = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
464 | value &= ~BIT(AUD_MISC_SEROUT_SPDIF_OE); | ||
465 | writel(value, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
466 | break; | ||
467 | default: | ||
468 | dev_err(aio->cygaud->dev, "Port not supported\n"); | ||
469 | status = -EINVAL; | ||
470 | } | ||
471 | |||
472 | return status; | ||
473 | } | ||
474 | |||
475 | static void audio_ssp_in_enable(struct cygnus_aio_port *aio) | ||
476 | { | ||
477 | u32 value; | ||
478 | |||
479 | value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
480 | value |= BIT(BF_DST_CFGX_CAP_ENA); | ||
481 | writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
482 | |||
483 | writel(0x1, aio->cygaud->audio + aio->regs.bf_destch_ctrl); | ||
484 | |||
485 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
486 | value |= BIT(I2S_OUT_CFGX_CLK_ENA); | ||
487 | value |= BIT(I2S_OUT_CFGX_DATA_ENABLE); | ||
488 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
489 | |||
490 | value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg); | ||
491 | value |= BIT(I2S_IN_STREAM_CFG_CAP_ENA); | ||
492 | writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg); | ||
493 | |||
494 | aio->streams_on |= CAPTURE_STREAM_MASK; | ||
495 | } | ||
496 | |||
497 | static void audio_ssp_in_disable(struct cygnus_aio_port *aio) | ||
498 | { | ||
499 | u32 value; | ||
500 | |||
501 | value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg); | ||
502 | value &= ~BIT(I2S_IN_STREAM_CFG_CAP_ENA); | ||
503 | writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_stream_cfg); | ||
504 | |||
505 | aio->streams_on &= ~CAPTURE_STREAM_MASK; | ||
506 | |||
507 | /* If both playback and capture are off */ | ||
508 | if (!aio->streams_on) { | ||
509 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
510 | value &= ~BIT(I2S_OUT_CFGX_CLK_ENA); | ||
511 | value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE); | ||
512 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
513 | } | ||
514 | |||
515 | writel(0x0, aio->cygaud->audio + aio->regs.bf_destch_ctrl); | ||
516 | |||
517 | value = readl(aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
518 | value &= ~BIT(BF_DST_CFGX_CAP_ENA); | ||
519 | writel(value, aio->cygaud->audio + aio->regs.bf_destch_cfg); | ||
520 | } | ||
521 | |||
522 | static int audio_ssp_out_enable(struct cygnus_aio_port *aio) | ||
523 | { | ||
524 | u32 value; | ||
525 | int status = 0; | ||
526 | |||
527 | switch (aio->port_type) { | ||
528 | case PORT_TDM: | ||
529 | value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
530 | value |= BIT(I2S_OUT_STREAM_ENA); | ||
531 | writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
532 | |||
533 | writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl); | ||
534 | |||
535 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
536 | value |= BIT(I2S_OUT_CFGX_CLK_ENA); | ||
537 | value |= BIT(I2S_OUT_CFGX_DATA_ENABLE); | ||
538 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
539 | |||
540 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
541 | value |= BIT(BF_SRC_CFGX_SFIFO_ENA); | ||
542 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
543 | |||
544 | aio->streams_on |= PLAYBACK_STREAM_MASK; | ||
545 | break; | ||
546 | case PORT_SPDIF: | ||
547 | value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET); | ||
548 | value |= 0x3; | ||
549 | writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET); | ||
550 | |||
551 | writel(1, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl); | ||
552 | |||
553 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
554 | value |= BIT(BF_SRC_CFGX_SFIFO_ENA); | ||
555 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
556 | break; | ||
557 | default: | ||
558 | dev_err(aio->cygaud->dev, | ||
559 | "Port not supported %d\n", aio->portnum); | ||
560 | status = -EINVAL; | ||
561 | } | ||
562 | |||
563 | return status; | ||
564 | } | ||
565 | |||
566 | static int audio_ssp_out_disable(struct cygnus_aio_port *aio) | ||
567 | { | ||
568 | u32 value; | ||
569 | int status = 0; | ||
570 | |||
571 | switch (aio->port_type) { | ||
572 | case PORT_TDM: | ||
573 | aio->streams_on &= ~PLAYBACK_STREAM_MASK; | ||
574 | |||
575 | /* If both playback and capture are off */ | ||
576 | if (!aio->streams_on) { | ||
577 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
578 | value &= ~BIT(I2S_OUT_CFGX_CLK_ENA); | ||
579 | value &= ~BIT(I2S_OUT_CFGX_DATA_ENABLE); | ||
580 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
581 | } | ||
582 | |||
583 | /* set group_sync_dis = 1 */ | ||
584 | value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET); | ||
585 | value |= BIT(aio->portnum); | ||
586 | writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET); | ||
587 | |||
588 | writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl); | ||
589 | |||
590 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
591 | value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA); | ||
592 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
593 | |||
594 | /* set group_sync_dis = 0 */ | ||
595 | value = readl(aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET); | ||
596 | value &= ~BIT(aio->portnum); | ||
597 | writel(value, aio->cygaud->audio + BF_SRC_GRP_SYNC_DIS_OFFSET); | ||
598 | |||
599 | value = readl(aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
600 | value &= ~BIT(I2S_OUT_STREAM_ENA); | ||
601 | writel(value, aio->cygaud->audio + aio->regs.i2s_stream_cfg); | ||
602 | |||
603 | /* IOP SW INIT on OUT_I2S_x */ | ||
604 | value = readl(aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC); | ||
605 | value |= BIT(aio->portnum); | ||
606 | writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC); | ||
607 | value &= ~BIT(aio->portnum); | ||
608 | writel(value, aio->cygaud->i2s_in + IOP_SW_INIT_LOGIC); | ||
609 | break; | ||
610 | case PORT_SPDIF: | ||
611 | value = readl(aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET); | ||
612 | value &= ~0x3; | ||
613 | writel(value, aio->cygaud->audio + SPDIF_FORMAT_CFG_OFFSET); | ||
614 | writel(0, aio->cygaud->audio + aio->regs.bf_sourcech_ctrl); | ||
615 | |||
616 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
617 | value &= ~BIT(BF_SRC_CFGX_SFIFO_ENA); | ||
618 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
619 | break; | ||
620 | default: | ||
621 | dev_err(aio->cygaud->dev, | ||
622 | "Port not supported %d\n", aio->portnum); | ||
623 | status = -EINVAL; | ||
624 | } | ||
625 | |||
626 | return status; | ||
627 | } | ||
628 | |||
629 | static int pll_configure_mclk(struct cygnus_audio *cygaud, u32 mclk, | ||
630 | struct cygnus_aio_port *aio) | ||
631 | { | ||
632 | int i = 0, error; | ||
633 | bool found = false; | ||
634 | const struct pll_macro_entry *p_entry; | ||
635 | struct clk *ch_clk; | ||
636 | |||
637 | for (i = 0; i < ARRAY_SIZE(pll_predef_mclk); i++) { | ||
638 | p_entry = &pll_predef_mclk[i]; | ||
639 | if (p_entry->mclk == mclk) { | ||
640 | found = true; | ||
641 | break; | ||
642 | } | ||
643 | } | ||
644 | if (!found) { | ||
645 | dev_err(cygaud->dev, | ||
646 | "%s No valid mclk freq (%u) found!\n", __func__, mclk); | ||
647 | return -EINVAL; | ||
648 | } | ||
649 | |||
650 | ch_clk = cygaud->audio_clk[p_entry->pll_ch_num]; | ||
651 | |||
652 | if ((aio->clk_trace.cap_en) && (!aio->clk_trace.cap_clk_en)) { | ||
653 | error = clk_prepare_enable(ch_clk); | ||
654 | if (error) { | ||
655 | dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n", | ||
656 | __func__, error); | ||
657 | return error; | ||
658 | } | ||
659 | aio->clk_trace.cap_clk_en = true; | ||
660 | } | ||
661 | |||
662 | if ((aio->clk_trace.play_en) && (!aio->clk_trace.play_clk_en)) { | ||
663 | error = clk_prepare_enable(ch_clk); | ||
664 | if (error) { | ||
665 | dev_err(cygaud->dev, "%s clk_prepare_enable failed %d\n", | ||
666 | __func__, error); | ||
667 | return error; | ||
668 | } | ||
669 | aio->clk_trace.play_clk_en = true; | ||
670 | } | ||
671 | |||
672 | error = clk_set_rate(ch_clk, mclk); | ||
673 | if (error) { | ||
674 | dev_err(cygaud->dev, "%s Set MCLK rate failed: %d\n", | ||
675 | __func__, error); | ||
676 | return error; | ||
677 | } | ||
678 | |||
679 | return p_entry->pll_ch_num; | ||
680 | } | ||
681 | |||
682 | static int cygnus_ssp_set_clocks(struct cygnus_aio_port *aio, | ||
683 | struct cygnus_audio *cygaud) | ||
684 | { | ||
685 | u32 value, i = 0; | ||
686 | u32 mask = 0xf; | ||
687 | u32 sclk; | ||
688 | bool found = false; | ||
689 | const struct _ssp_clk_coeff *p_entry = NULL; | ||
690 | |||
691 | for (i = 0; i < ARRAY_SIZE(ssp_clk_coeff); i++) { | ||
692 | p_entry = &ssp_clk_coeff[i]; | ||
693 | if ((p_entry->rate == aio->lrclk) && | ||
694 | (p_entry->sclk_rate == aio->bit_per_frame) && | ||
695 | (p_entry->mclk == aio->mclk)) { | ||
696 | found = true; | ||
697 | break; | ||
698 | } | ||
699 | } | ||
700 | if (!found) { | ||
701 | dev_err(aio->cygaud->dev, | ||
702 | "No valid match found in ssp_clk_coeff array\n"); | ||
703 | dev_err(aio->cygaud->dev, "lrclk = %u, bits/frame = %u, mclk = %u\n", | ||
704 | aio->lrclk, aio->bit_per_frame, aio->mclk); | ||
705 | return -EINVAL; | ||
706 | } | ||
707 | |||
708 | sclk = aio->bit_per_frame; | ||
709 | if (sclk == 512) | ||
710 | sclk = 0; | ||
711 | /* sclks_per_1fs_div = sclk cycles/32 */ | ||
712 | sclk /= 32; | ||
713 | /* Set sclk rate */ | ||
714 | switch (aio->port_type) { | ||
715 | case PORT_TDM: | ||
716 | /* Set number of bitclks per frame */ | ||
717 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
718 | value &= ~(mask << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32); | ||
719 | value |= sclk << I2S_OUT_CFGX_SCLKS_PER_1FS_DIV32; | ||
720 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
721 | dev_dbg(aio->cygaud->dev, | ||
722 | "SCLKS_PER_1FS_DIV32 = 0x%x\n", value); | ||
723 | break; | ||
724 | case PORT_SPDIF: | ||
725 | break; | ||
726 | default: | ||
727 | dev_err(aio->cygaud->dev, "Unknown port type\n"); | ||
728 | return -EINVAL; | ||
729 | } | ||
730 | |||
731 | /* Set MCLK_RATE ssp port (spdif and ssp are the same) */ | ||
732 | value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
733 | value &= ~(0xf << I2S_OUT_MCLKRATE_SHIFT); | ||
734 | value |= (p_entry->mclk_rate << I2S_OUT_MCLKRATE_SHIFT); | ||
735 | writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
736 | |||
737 | dev_dbg(aio->cygaud->dev, "mclk cfg reg = 0x%x\n", value); | ||
738 | dev_dbg(aio->cygaud->dev, "bits per frame = %u, mclk = %u Hz, lrclk = %u Hz\n", | ||
739 | aio->bit_per_frame, aio->mclk, aio->lrclk); | ||
740 | return 0; | ||
741 | } | ||
742 | |||
743 | static int cygnus_ssp_hw_params(struct snd_pcm_substream *substream, | ||
744 | struct snd_pcm_hw_params *params, | ||
745 | struct snd_soc_dai *dai) | ||
746 | { | ||
747 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); | ||
748 | struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); | ||
749 | int rate, bitres; | ||
750 | u32 value; | ||
751 | u32 mask = 0x1f; | ||
752 | int ret = 0; | ||
753 | |||
754 | dev_dbg(aio->cygaud->dev, "%s port = %d\n", __func__, aio->portnum); | ||
755 | dev_dbg(aio->cygaud->dev, "params_channels %d\n", | ||
756 | params_channels(params)); | ||
757 | dev_dbg(aio->cygaud->dev, "rate %d\n", params_rate(params)); | ||
758 | dev_dbg(aio->cygaud->dev, "format %d\n", params_format(params)); | ||
759 | |||
760 | rate = params_rate(params); | ||
761 | |||
762 | switch (aio->mode) { | ||
763 | case CYGNUS_SSPMODE_TDM: | ||
764 | if ((rate == 192000) && (params_channels(params) > 4)) { | ||
765 | dev_err(aio->cygaud->dev, "Cannot run %d channels at %dHz\n", | ||
766 | params_channels(params), rate); | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | break; | ||
770 | case CYGNUS_SSPMODE_I2S: | ||
771 | aio->bit_per_frame = 64; /* I2S must be 64 bit per frame */ | ||
772 | break; | ||
773 | default: | ||
774 | dev_err(aio->cygaud->dev, | ||
775 | "%s port running in unknown mode\n", __func__); | ||
776 | return -EINVAL; | ||
777 | } | ||
778 | |||
779 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
780 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
781 | value &= ~BIT(BF_SRC_CFGX_BUFFER_PAIR_ENABLE); | ||
782 | /* Configure channels as mono or stereo/TDM */ | ||
783 | if (params_channels(params) == 1) | ||
784 | value |= BIT(BF_SRC_CFGX_SAMPLE_CH_MODE); | ||
785 | else | ||
786 | value &= ~BIT(BF_SRC_CFGX_SAMPLE_CH_MODE); | ||
787 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
788 | |||
789 | switch (params_format(params)) { | ||
790 | case SNDRV_PCM_FORMAT_S8: | ||
791 | if (aio->port_type == PORT_SPDIF) { | ||
792 | dev_err(aio->cygaud->dev, | ||
793 | "SPDIF does not support 8bit format\n"); | ||
794 | return -EINVAL; | ||
795 | } | ||
796 | bitres = 8; | ||
797 | break; | ||
798 | |||
799 | case SNDRV_PCM_FORMAT_S16_LE: | ||
800 | bitres = 16; | ||
801 | break; | ||
802 | |||
803 | case SNDRV_PCM_FORMAT_S32_LE: | ||
804 | /* 32 bit mode is coded as 0 */ | ||
805 | bitres = 0; | ||
806 | break; | ||
807 | |||
808 | default: | ||
809 | return -EINVAL; | ||
810 | } | ||
811 | |||
812 | value = readl(aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
813 | value &= ~(mask << BF_SRC_CFGX_BIT_RES); | ||
814 | value |= (bitres << BF_SRC_CFGX_BIT_RES); | ||
815 | writel(value, aio->cygaud->audio + aio->regs.bf_sourcech_cfg); | ||
816 | |||
817 | } else { | ||
818 | |||
819 | switch (params_format(params)) { | ||
820 | case SNDRV_PCM_FORMAT_S16_LE: | ||
821 | value = readl(aio->cygaud->audio + | ||
822 | aio->regs.bf_destch_cfg); | ||
823 | value |= BIT(BF_DST_CFGX_CAP_MODE); | ||
824 | writel(value, aio->cygaud->audio + | ||
825 | aio->regs.bf_destch_cfg); | ||
826 | break; | ||
827 | |||
828 | case SNDRV_PCM_FORMAT_S32_LE: | ||
829 | value = readl(aio->cygaud->audio + | ||
830 | aio->regs.bf_destch_cfg); | ||
831 | value &= ~BIT(BF_DST_CFGX_CAP_MODE); | ||
832 | writel(value, aio->cygaud->audio + | ||
833 | aio->regs.bf_destch_cfg); | ||
834 | break; | ||
835 | |||
836 | default: | ||
837 | return -EINVAL; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | aio->lrclk = rate; | ||
842 | |||
843 | if (!aio->is_slave) | ||
844 | ret = cygnus_ssp_set_clocks(aio, cygaud); | ||
845 | |||
846 | return ret; | ||
847 | } | ||
848 | |||
849 | /* | ||
850 | * This function sets the mclk frequency for pll clock | ||
851 | */ | ||
852 | static int cygnus_ssp_set_sysclk(struct snd_soc_dai *dai, | ||
853 | int clk_id, unsigned int freq, int dir) | ||
854 | { | ||
855 | int sel; | ||
856 | u32 value; | ||
857 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); | ||
858 | struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); | ||
859 | |||
860 | dev_dbg(aio->cygaud->dev, | ||
861 | "%s Enter port = %d\n", __func__, aio->portnum); | ||
862 | sel = pll_configure_mclk(cygaud, freq, aio); | ||
863 | if (sel < 0) { | ||
864 | dev_err(aio->cygaud->dev, | ||
865 | "%s Setting mclk failed.\n", __func__); | ||
866 | return -EINVAL; | ||
867 | } | ||
868 | |||
869 | aio->mclk = freq; | ||
870 | |||
871 | dev_dbg(aio->cygaud->dev, "%s Setting MCLKSEL to %d\n", __func__, sel); | ||
872 | value = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
873 | value &= ~(0xf << I2S_OUT_PLLCLKSEL_SHIFT); | ||
874 | value |= (sel << I2S_OUT_PLLCLKSEL_SHIFT); | ||
875 | writel(value, aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
876 | |||
877 | return 0; | ||
878 | } | ||
879 | |||
880 | static int cygnus_ssp_startup(struct snd_pcm_substream *substream, | ||
881 | struct snd_soc_dai *dai) | ||
882 | { | ||
883 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); | ||
884 | |||
885 | snd_soc_dai_set_dma_data(dai, substream, aio); | ||
886 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
887 | aio->clk_trace.play_en = true; | ||
888 | else | ||
889 | aio->clk_trace.cap_en = true; | ||
890 | |||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static void cygnus_ssp_shutdown(struct snd_pcm_substream *substream, | ||
895 | struct snd_soc_dai *dai) | ||
896 | { | ||
897 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); | ||
898 | |||
899 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
900 | aio->clk_trace.play_en = false; | ||
901 | else | ||
902 | aio->clk_trace.cap_en = false; | ||
903 | |||
904 | if (!aio->is_slave) { | ||
905 | u32 val; | ||
906 | |||
907 | val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
908 | val &= CYGNUS_PLLCLKSEL_MASK; | ||
909 | if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) { | ||
910 | dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n", | ||
911 | val); | ||
912 | return; | ||
913 | } | ||
914 | |||
915 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
916 | if (aio->clk_trace.play_clk_en) { | ||
917 | clk_disable_unprepare(aio->cygaud-> | ||
918 | audio_clk[val]); | ||
919 | aio->clk_trace.play_clk_en = false; | ||
920 | } | ||
921 | } else { | ||
922 | if (aio->clk_trace.cap_clk_en) { | ||
923 | clk_disable_unprepare(aio->cygaud-> | ||
924 | audio_clk[val]); | ||
925 | aio->clk_trace.cap_clk_en = false; | ||
926 | } | ||
927 | } | ||
928 | } | ||
929 | } | ||
930 | |||
931 | /* | ||
932 | * Bit Update Notes | ||
933 | * 31 Yes TDM Mode (1 = TDM, 0 = i2s) | ||
934 | * 30 Yes Slave Mode (1 = Slave, 0 = Master) | ||
935 | * 29:26 No Sclks per frame | ||
936 | * 25:18 Yes FS Width | ||
937 | * 17:14 No Valid Slots | ||
938 | * 13 No Bits (1 = 16 bits, 0 = 32 bits) | ||
939 | * 12:08 No Bits per samp | ||
940 | * 07 Yes Justifcation (1 = LSB, 0 = MSB) | ||
941 | * 06 Yes Alignment (1 = Delay 1 clk, 0 = no delay | ||
942 | * 05 Yes SCLK polarity (1 = Rising, 0 = Falling) | ||
943 | * 04 Yes LRCLK Polarity (1 = High for left, 0 = Low for left) | ||
944 | * 03:02 Yes Reserved - write as zero | ||
945 | * 01 No Data Enable | ||
946 | * 00 No CLK Enable | ||
947 | */ | ||
948 | #define I2S_OUT_CFG_REG_UPDATE_MASK 0x3C03FF03 | ||
949 | |||
950 | /* Input cfg is same as output, but the FS width is not a valid field */ | ||
951 | #define I2S_IN_CFG_REG_UPDATE_MASK (I2S_OUT_CFG_REG_UPDATE_MASK | 0x03FC0000) | ||
952 | |||
953 | int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, int len) | ||
954 | { | ||
955 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); | ||
956 | |||
957 | if ((len > 0) && (len < 256)) { | ||
958 | aio->fsync_width = len; | ||
959 | return 0; | ||
960 | } else { | ||
961 | return -EINVAL; | ||
962 | } | ||
963 | } | ||
964 | |||
965 | static int cygnus_ssp_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | ||
966 | { | ||
967 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); | ||
968 | u32 ssp_curcfg; | ||
969 | u32 ssp_newcfg; | ||
970 | u32 ssp_outcfg; | ||
971 | u32 ssp_incfg; | ||
972 | u32 val; | ||
973 | u32 mask; | ||
974 | |||
975 | dev_dbg(aio->cygaud->dev, "%s Enter fmt: %x\n", __func__, fmt); | ||
976 | |||
977 | if (aio->port_type == PORT_SPDIF) | ||
978 | return -EINVAL; | ||
979 | |||
980 | ssp_newcfg = 0; | ||
981 | |||
982 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
983 | case SND_SOC_DAIFMT_CBM_CFM: | ||
984 | ssp_newcfg |= BIT(I2S_OUT_CFGX_SLAVE_MODE); | ||
985 | aio->is_slave = 1; | ||
986 | break; | ||
987 | case SND_SOC_DAIFMT_CBS_CFS: | ||
988 | ssp_newcfg &= ~BIT(I2S_OUT_CFGX_SLAVE_MODE); | ||
989 | aio->is_slave = 0; | ||
990 | break; | ||
991 | default: | ||
992 | return -EINVAL; | ||
993 | } | ||
994 | |||
995 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
996 | case SND_SOC_DAIFMT_I2S: | ||
997 | ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT); | ||
998 | ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH); | ||
999 | aio->mode = CYGNUS_SSPMODE_I2S; | ||
1000 | break; | ||
1001 | |||
1002 | case SND_SOC_DAIFMT_DSP_A: | ||
1003 | case SND_SOC_DAIFMT_DSP_B: | ||
1004 | ssp_newcfg |= BIT(I2S_OUT_CFGX_TDM_MODE); | ||
1005 | |||
1006 | /* DSP_A = data after FS, DSP_B = data during FS */ | ||
1007 | if ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_A) | ||
1008 | ssp_newcfg |= BIT(I2S_OUT_CFGX_DATA_ALIGNMENT); | ||
1009 | |||
1010 | if ((aio->fsync_width > 0) && (aio->fsync_width < 256)) | ||
1011 | ssp_newcfg |= | ||
1012 | (aio->fsync_width << I2S_OUT_CFGX_FSYNC_WIDTH); | ||
1013 | else | ||
1014 | ssp_newcfg |= BIT(I2S_OUT_CFGX_FSYNC_WIDTH); | ||
1015 | |||
1016 | aio->mode = CYGNUS_SSPMODE_TDM; | ||
1017 | break; | ||
1018 | |||
1019 | default: | ||
1020 | return -EINVAL; | ||
1021 | } | ||
1022 | |||
1023 | /* | ||
1024 | * SSP out cfg. | ||
1025 | * Retain bits we do not want to update, then OR in new bits | ||
1026 | */ | ||
1027 | ssp_curcfg = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
1028 | ssp_outcfg = (ssp_curcfg & I2S_OUT_CFG_REG_UPDATE_MASK) | ssp_newcfg; | ||
1029 | writel(ssp_outcfg, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
1030 | |||
1031 | /* | ||
1032 | * SSP in cfg. | ||
1033 | * Retain bits we do not want to update, then OR in new bits | ||
1034 | */ | ||
1035 | ssp_curcfg = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg); | ||
1036 | ssp_incfg = (ssp_curcfg & I2S_IN_CFG_REG_UPDATE_MASK) | ssp_newcfg; | ||
1037 | writel(ssp_incfg, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg); | ||
1038 | |||
1039 | val = readl(aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
1040 | |||
1041 | /* | ||
1042 | * Configure the word clk and bit clk as output or tristate | ||
1043 | * Each port has 4 bits for controlling its pins. | ||
1044 | * Shift the mask based upon port number. | ||
1045 | */ | ||
1046 | mask = BIT(AUD_MISC_SEROUT_LRCK_OE) | ||
1047 | | BIT(AUD_MISC_SEROUT_SCLK_OE) | ||
1048 | | BIT(AUD_MISC_SEROUT_MCLK_OE); | ||
1049 | mask = mask << (aio->portnum * 4); | ||
1050 | if (aio->is_slave) | ||
1051 | /* Set bit for tri-state */ | ||
1052 | val |= mask; | ||
1053 | else | ||
1054 | /* Clear bit for drive */ | ||
1055 | val &= ~mask; | ||
1056 | |||
1057 | dev_dbg(aio->cygaud->dev, "%s Set OE bits 0x%x\n", __func__, val); | ||
1058 | writel(val, aio->cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
1059 | |||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | static int cygnus_ssp_trigger(struct snd_pcm_substream *substream, int cmd, | ||
1064 | struct snd_soc_dai *dai) | ||
1065 | { | ||
1066 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(dai); | ||
1067 | struct cygnus_audio *cygaud = snd_soc_dai_get_drvdata(dai); | ||
1068 | |||
1069 | dev_dbg(aio->cygaud->dev, | ||
1070 | "%s cmd %d at port = %d\n", __func__, cmd, aio->portnum); | ||
1071 | |||
1072 | switch (cmd) { | ||
1073 | case SNDRV_PCM_TRIGGER_START: | ||
1074 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1075 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1076 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1077 | audio_ssp_out_enable(aio); | ||
1078 | else | ||
1079 | audio_ssp_in_enable(aio); | ||
1080 | cygaud->active_ports++; | ||
1081 | |||
1082 | break; | ||
1083 | |||
1084 | case SNDRV_PCM_TRIGGER_STOP: | ||
1085 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1086 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1087 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1088 | audio_ssp_out_disable(aio); | ||
1089 | else | ||
1090 | audio_ssp_in_disable(aio); | ||
1091 | cygaud->active_ports--; | ||
1092 | break; | ||
1093 | |||
1094 | default: | ||
1095 | return -EINVAL; | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | static int cygnus_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, | ||
1102 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) | ||
1103 | { | ||
1104 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); | ||
1105 | u32 value; | ||
1106 | int bits_per_slot = 0; /* default to 32-bits per slot */ | ||
1107 | int frame_bits; | ||
1108 | unsigned int active_slots; | ||
1109 | bool found = false; | ||
1110 | int i; | ||
1111 | |||
1112 | if (tx_mask != rx_mask) { | ||
1113 | dev_err(aio->cygaud->dev, | ||
1114 | "%s tx_mask must equal rx_mask\n", __func__); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | active_slots = hweight32(tx_mask); | ||
1119 | |||
1120 | if ((active_slots < 0) || (active_slots > 16)) | ||
1121 | return -EINVAL; | ||
1122 | |||
1123 | /* Slot value must be even */ | ||
1124 | if (active_slots % 2) | ||
1125 | return -EINVAL; | ||
1126 | |||
1127 | /* We encode 16 slots as 0 in the reg */ | ||
1128 | if (active_slots == 16) | ||
1129 | active_slots = 0; | ||
1130 | |||
1131 | /* Slot Width is either 16 or 32 */ | ||
1132 | switch (slot_width) { | ||
1133 | case 16: | ||
1134 | bits_per_slot = 1; | ||
1135 | break; | ||
1136 | case 32: | ||
1137 | bits_per_slot = 0; | ||
1138 | break; | ||
1139 | default: | ||
1140 | bits_per_slot = 0; | ||
1141 | dev_warn(aio->cygaud->dev, | ||
1142 | "%s Defaulting Slot Width to 32\n", __func__); | ||
1143 | } | ||
1144 | |||
1145 | frame_bits = slots * slot_width; | ||
1146 | |||
1147 | for (i = 0; i < ARRAY_SIZE(ssp_valid_tdm_framesize); i++) { | ||
1148 | if (ssp_valid_tdm_framesize[i] == frame_bits) { | ||
1149 | found = true; | ||
1150 | break; | ||
1151 | } | ||
1152 | } | ||
1153 | |||
1154 | if (!found) { | ||
1155 | dev_err(aio->cygaud->dev, | ||
1156 | "%s In TDM mode, frame bits INVALID (%d)\n", | ||
1157 | __func__, frame_bits); | ||
1158 | return -EINVAL; | ||
1159 | } | ||
1160 | |||
1161 | aio->bit_per_frame = frame_bits; | ||
1162 | |||
1163 | dev_dbg(aio->cygaud->dev, "%s active_slots %u, bits per frame %d\n", | ||
1164 | __func__, active_slots, frame_bits); | ||
1165 | |||
1166 | /* Set capture side of ssp port */ | ||
1167 | value = readl(aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg); | ||
1168 | value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT); | ||
1169 | value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT); | ||
1170 | value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT); | ||
1171 | value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT); | ||
1172 | writel(value, aio->cygaud->i2s_in + aio->regs.i2s_cap_cfg); | ||
1173 | |||
1174 | /* Set playback side of ssp port */ | ||
1175 | value = readl(aio->cygaud->audio + aio->regs.i2s_cfg); | ||
1176 | value &= ~(0xf << I2S_OUT_CFGX_VALID_SLOT); | ||
1177 | value |= (active_slots << I2S_OUT_CFGX_VALID_SLOT); | ||
1178 | value &= ~BIT(I2S_OUT_CFGX_BITS_PER_SLOT); | ||
1179 | value |= (bits_per_slot << I2S_OUT_CFGX_BITS_PER_SLOT); | ||
1180 | writel(value, aio->cygaud->audio + aio->regs.i2s_cfg); | ||
1181 | |||
1182 | return 0; | ||
1183 | } | ||
1184 | |||
1185 | #ifdef CONFIG_PM_SLEEP | ||
1186 | static int cygnus_ssp_suspend(struct snd_soc_dai *cpu_dai) | ||
1187 | { | ||
1188 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); | ||
1189 | |||
1190 | if (!aio->is_slave) { | ||
1191 | u32 val; | ||
1192 | |||
1193 | val = readl(aio->cygaud->audio + aio->regs.i2s_mclk_cfg); | ||
1194 | val &= CYGNUS_PLLCLKSEL_MASK; | ||
1195 | if (val >= ARRAY_SIZE(aio->cygaud->audio_clk)) { | ||
1196 | dev_err(aio->cygaud->dev, "Clk index %u is out of bounds\n", | ||
1197 | val); | ||
1198 | return -EINVAL; | ||
1199 | } | ||
1200 | |||
1201 | if (aio->clk_trace.cap_clk_en) | ||
1202 | clk_disable_unprepare(aio->cygaud->audio_clk[val]); | ||
1203 | if (aio->clk_trace.play_clk_en) | ||
1204 | clk_disable_unprepare(aio->cygaud->audio_clk[val]); | ||
1205 | |||
1206 | aio->pll_clk_num = val; | ||
1207 | } | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | static int cygnus_ssp_resume(struct snd_soc_dai *cpu_dai) | ||
1213 | { | ||
1214 | struct cygnus_aio_port *aio = cygnus_dai_get_portinfo(cpu_dai); | ||
1215 | int error; | ||
1216 | |||
1217 | if (!aio->is_slave) { | ||
1218 | if (aio->clk_trace.cap_clk_en) { | ||
1219 | error = clk_prepare_enable(aio->cygaud-> | ||
1220 | audio_clk[aio->pll_clk_num]); | ||
1221 | if (error) { | ||
1222 | dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n", | ||
1223 | __func__); | ||
1224 | return -EINVAL; | ||
1225 | } | ||
1226 | } | ||
1227 | if (aio->clk_trace.play_clk_en) { | ||
1228 | error = clk_prepare_enable(aio->cygaud-> | ||
1229 | audio_clk[aio->pll_clk_num]); | ||
1230 | if (error) { | ||
1231 | if (aio->clk_trace.cap_clk_en) | ||
1232 | clk_disable_unprepare(aio->cygaud-> | ||
1233 | audio_clk[aio->pll_clk_num]); | ||
1234 | dev_err(aio->cygaud->dev, "%s clk_prepare_enable failed\n", | ||
1235 | __func__); | ||
1236 | return -EINVAL; | ||
1237 | } | ||
1238 | } | ||
1239 | } | ||
1240 | |||
1241 | return 0; | ||
1242 | } | ||
1243 | #else | ||
1244 | #define cygnus_ssp_suspend NULL | ||
1245 | #define cygnus_ssp_resume NULL | ||
1246 | #endif | ||
1247 | |||
1248 | static const struct snd_soc_dai_ops cygnus_ssp_dai_ops = { | ||
1249 | .startup = cygnus_ssp_startup, | ||
1250 | .shutdown = cygnus_ssp_shutdown, | ||
1251 | .trigger = cygnus_ssp_trigger, | ||
1252 | .hw_params = cygnus_ssp_hw_params, | ||
1253 | .set_fmt = cygnus_ssp_set_fmt, | ||
1254 | .set_sysclk = cygnus_ssp_set_sysclk, | ||
1255 | .set_tdm_slot = cygnus_set_dai_tdm_slot, | ||
1256 | }; | ||
1257 | |||
1258 | |||
1259 | #define INIT_CPU_DAI(num) { \ | ||
1260 | .name = "cygnus-ssp" #num, \ | ||
1261 | .playback = { \ | ||
1262 | .channels_min = 1, \ | ||
1263 | .channels_max = 16, \ | ||
1264 | .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \ | ||
1265 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ | ||
1266 | SNDRV_PCM_RATE_192000, \ | ||
1267 | .formats = SNDRV_PCM_FMTBIT_S8 | \ | ||
1268 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
1269 | SNDRV_PCM_FMTBIT_S32_LE, \ | ||
1270 | }, \ | ||
1271 | .capture = { \ | ||
1272 | .channels_min = 2, \ | ||
1273 | .channels_max = 16, \ | ||
1274 | .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | \ | ||
1275 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ | ||
1276 | SNDRV_PCM_RATE_192000, \ | ||
1277 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ | ||
1278 | SNDRV_PCM_FMTBIT_S32_LE, \ | ||
1279 | }, \ | ||
1280 | .ops = &cygnus_ssp_dai_ops, \ | ||
1281 | .suspend = cygnus_ssp_suspend, \ | ||
1282 | .resume = cygnus_ssp_resume, \ | ||
1283 | } | ||
1284 | |||
1285 | static const struct snd_soc_dai_driver cygnus_ssp_dai_info[] = { | ||
1286 | INIT_CPU_DAI(0), | ||
1287 | INIT_CPU_DAI(1), | ||
1288 | INIT_CPU_DAI(2), | ||
1289 | }; | ||
1290 | |||
1291 | static struct snd_soc_dai_driver cygnus_spdif_dai_info = { | ||
1292 | .name = "cygnus-spdif", | ||
1293 | .playback = { | ||
1294 | .channels_min = 2, | ||
1295 | .channels_max = 2, | ||
1296 | .rates = CYGNUS_TDM_RATE | SNDRV_PCM_RATE_88200 | | ||
1297 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | | ||
1298 | SNDRV_PCM_RATE_192000, | ||
1299 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
1300 | SNDRV_PCM_FMTBIT_S32_LE, | ||
1301 | }, | ||
1302 | .ops = &cygnus_ssp_dai_ops, | ||
1303 | .suspend = cygnus_ssp_suspend, | ||
1304 | .resume = cygnus_ssp_resume, | ||
1305 | }; | ||
1306 | |||
1307 | static struct snd_soc_dai_driver cygnus_ssp_dai[CYGNUS_MAX_PORTS]; | ||
1308 | |||
1309 | static const struct snd_soc_component_driver cygnus_ssp_component = { | ||
1310 | .name = "cygnus-audio", | ||
1311 | }; | ||
1312 | |||
1313 | /* | ||
1314 | * Return < 0 if error | ||
1315 | * Return 0 if disabled | ||
1316 | * Return 1 if enabled and node is parsed successfully | ||
1317 | */ | ||
1318 | static int parse_ssp_child_node(struct platform_device *pdev, | ||
1319 | struct device_node *dn, | ||
1320 | struct cygnus_audio *cygaud, | ||
1321 | struct snd_soc_dai_driver *p_dai) | ||
1322 | { | ||
1323 | struct cygnus_aio_port *aio; | ||
1324 | struct cygnus_ssp_regs ssp_regs[3]; | ||
1325 | u32 rawval; | ||
1326 | int portnum = -1; | ||
1327 | enum cygnus_audio_port_type port_type; | ||
1328 | |||
1329 | if (of_property_read_u32(dn, "reg", &rawval)) { | ||
1330 | dev_err(&pdev->dev, "Missing reg property\n"); | ||
1331 | return -EINVAL; | ||
1332 | } | ||
1333 | |||
1334 | portnum = rawval; | ||
1335 | switch (rawval) { | ||
1336 | case 0: | ||
1337 | ssp_regs[0] = INIT_SSP_REGS(0); | ||
1338 | port_type = PORT_TDM; | ||
1339 | break; | ||
1340 | case 1: | ||
1341 | ssp_regs[1] = INIT_SSP_REGS(1); | ||
1342 | port_type = PORT_TDM; | ||
1343 | break; | ||
1344 | case 2: | ||
1345 | ssp_regs[2] = INIT_SSP_REGS(2); | ||
1346 | port_type = PORT_TDM; | ||
1347 | break; | ||
1348 | case 3: | ||
1349 | port_type = PORT_SPDIF; | ||
1350 | break; | ||
1351 | default: | ||
1352 | dev_err(&pdev->dev, "Bad value for reg %u\n", rawval); | ||
1353 | return -EINVAL; | ||
1354 | } | ||
1355 | |||
1356 | aio = &cygaud->portinfo[portnum]; | ||
1357 | aio->cygaud = cygaud; | ||
1358 | aio->portnum = portnum; | ||
1359 | aio->port_type = port_type; | ||
1360 | aio->fsync_width = -1; | ||
1361 | |||
1362 | switch (port_type) { | ||
1363 | case PORT_TDM: | ||
1364 | aio->regs = ssp_regs[portnum]; | ||
1365 | *p_dai = cygnus_ssp_dai_info[portnum]; | ||
1366 | aio->mode = CYGNUS_SSPMODE_UNKNOWN; | ||
1367 | break; | ||
1368 | |||
1369 | case PORT_SPDIF: | ||
1370 | aio->regs.bf_sourcech_cfg = BF_SRC_CFG3_OFFSET; | ||
1371 | aio->regs.bf_sourcech_ctrl = BF_SRC_CTRL3_OFFSET; | ||
1372 | aio->regs.i2s_mclk_cfg = SPDIF_MCLK_CFG_OFFSET; | ||
1373 | aio->regs.i2s_stream_cfg = SPDIF_STREAM_CFG_OFFSET; | ||
1374 | *p_dai = cygnus_spdif_dai_info; | ||
1375 | |||
1376 | /* For the purposes of this code SPDIF can be I2S mode */ | ||
1377 | aio->mode = CYGNUS_SSPMODE_I2S; | ||
1378 | break; | ||
1379 | default: | ||
1380 | dev_err(&pdev->dev, "Bad value for port_type %d\n", port_type); | ||
1381 | return -EINVAL; | ||
1382 | } | ||
1383 | |||
1384 | dev_dbg(&pdev->dev, "%s portnum = %d\n", __func__, aio->portnum); | ||
1385 | aio->streams_on = 0; | ||
1386 | aio->cygaud->dev = &pdev->dev; | ||
1387 | aio->clk_trace.play_en = false; | ||
1388 | aio->clk_trace.cap_en = false; | ||
1389 | |||
1390 | audio_ssp_init_portregs(aio); | ||
1391 | return 0; | ||
1392 | } | ||
1393 | |||
1394 | static int audio_clk_init(struct platform_device *pdev, | ||
1395 | struct cygnus_audio *cygaud) | ||
1396 | { | ||
1397 | int i; | ||
1398 | char clk_name[PROP_LEN_MAX]; | ||
1399 | |||
1400 | for (i = 0; i < ARRAY_SIZE(cygaud->audio_clk); i++) { | ||
1401 | snprintf(clk_name, PROP_LEN_MAX, "ch%d_audio", i); | ||
1402 | |||
1403 | cygaud->audio_clk[i] = devm_clk_get(&pdev->dev, clk_name); | ||
1404 | if (IS_ERR(cygaud->audio_clk[i])) | ||
1405 | return PTR_ERR(cygaud->audio_clk[i]); | ||
1406 | } | ||
1407 | |||
1408 | return 0; | ||
1409 | } | ||
1410 | |||
1411 | static int cygnus_ssp_probe(struct platform_device *pdev) | ||
1412 | { | ||
1413 | struct device *dev = &pdev->dev; | ||
1414 | struct device_node *child_node; | ||
1415 | struct resource *res = pdev->resource; | ||
1416 | struct cygnus_audio *cygaud; | ||
1417 | int err = -EINVAL; | ||
1418 | int node_count; | ||
1419 | int active_port_count; | ||
1420 | |||
1421 | cygaud = devm_kzalloc(dev, sizeof(struct cygnus_audio), GFP_KERNEL); | ||
1422 | if (!cygaud) | ||
1423 | return -ENOMEM; | ||
1424 | |||
1425 | dev_set_drvdata(dev, cygaud); | ||
1426 | |||
1427 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "aud"); | ||
1428 | cygaud->audio = devm_ioremap_resource(dev, res); | ||
1429 | if (IS_ERR(cygaud->audio)) | ||
1430 | return PTR_ERR(cygaud->audio); | ||
1431 | |||
1432 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "i2s_in"); | ||
1433 | cygaud->i2s_in = devm_ioremap_resource(dev, res); | ||
1434 | if (IS_ERR(cygaud->i2s_in)) | ||
1435 | return PTR_ERR(cygaud->i2s_in); | ||
1436 | |||
1437 | /* Tri-state all controlable pins until we know that we need them */ | ||
1438 | writel(CYGNUS_SSP_TRISTATE_MASK, | ||
1439 | cygaud->audio + AUD_MISC_SEROUT_OE_REG_BASE); | ||
1440 | |||
1441 | node_count = of_get_child_count(pdev->dev.of_node); | ||
1442 | if ((node_count < 1) || (node_count > CYGNUS_MAX_PORTS)) { | ||
1443 | dev_err(dev, "child nodes is %d. Must be between 1 and %d\n", | ||
1444 | node_count, CYGNUS_MAX_PORTS); | ||
1445 | return -EINVAL; | ||
1446 | } | ||
1447 | |||
1448 | active_port_count = 0; | ||
1449 | |||
1450 | for_each_available_child_of_node(pdev->dev.of_node, child_node) { | ||
1451 | err = parse_ssp_child_node(pdev, child_node, cygaud, | ||
1452 | &cygnus_ssp_dai[active_port_count]); | ||
1453 | |||
1454 | /* negative is err, 0 is active and good, 1 is disabled */ | ||
1455 | if (err < 0) | ||
1456 | return err; | ||
1457 | else if (!err) { | ||
1458 | dev_dbg(dev, "Activating DAI: %s\n", | ||
1459 | cygnus_ssp_dai[active_port_count].name); | ||
1460 | active_port_count++; | ||
1461 | } | ||
1462 | } | ||
1463 | |||
1464 | cygaud->dev = dev; | ||
1465 | cygaud->active_ports = 0; | ||
1466 | |||
1467 | dev_dbg(dev, "Registering %d DAIs\n", active_port_count); | ||
1468 | err = snd_soc_register_component(dev, &cygnus_ssp_component, | ||
1469 | cygnus_ssp_dai, active_port_count); | ||
1470 | if (err) { | ||
1471 | dev_err(dev, "snd_soc_register_dai failed\n"); | ||
1472 | return err; | ||
1473 | } | ||
1474 | |||
1475 | cygaud->irq_num = platform_get_irq(pdev, 0); | ||
1476 | if (cygaud->irq_num <= 0) { | ||
1477 | dev_err(dev, "platform_get_irq failed\n"); | ||
1478 | err = cygaud->irq_num; | ||
1479 | goto err_irq; | ||
1480 | } | ||
1481 | |||
1482 | err = audio_clk_init(pdev, cygaud); | ||
1483 | if (err) { | ||
1484 | dev_err(dev, "audio clock initialization failed\n"); | ||
1485 | goto err_irq; | ||
1486 | } | ||
1487 | |||
1488 | err = cygnus_soc_platform_register(dev, cygaud); | ||
1489 | if (err) { | ||
1490 | dev_err(dev, "platform reg error %d\n", err); | ||
1491 | goto err_irq; | ||
1492 | } | ||
1493 | |||
1494 | return 0; | ||
1495 | |||
1496 | err_irq: | ||
1497 | snd_soc_unregister_component(dev); | ||
1498 | return err; | ||
1499 | } | ||
1500 | |||
1501 | static int cygnus_ssp_remove(struct platform_device *pdev) | ||
1502 | { | ||
1503 | cygnus_soc_platform_unregister(&pdev->dev); | ||
1504 | snd_soc_unregister_component(&pdev->dev); | ||
1505 | |||
1506 | return 0; | ||
1507 | } | ||
1508 | |||
1509 | static const struct of_device_id cygnus_ssp_of_match[] = { | ||
1510 | { .compatible = "brcm,cygnus-audio" }, | ||
1511 | {}, | ||
1512 | }; | ||
1513 | MODULE_DEVICE_TABLE(of, cygnus_ssp_of_match); | ||
1514 | |||
1515 | static struct platform_driver cygnus_ssp_driver = { | ||
1516 | .probe = cygnus_ssp_probe, | ||
1517 | .remove = cygnus_ssp_remove, | ||
1518 | .driver = { | ||
1519 | .name = "cygnus-ssp", | ||
1520 | .of_match_table = cygnus_ssp_of_match, | ||
1521 | }, | ||
1522 | }; | ||
1523 | |||
1524 | module_platform_driver(cygnus_ssp_driver); | ||
1525 | |||
1526 | MODULE_ALIAS("platform:cygnus-ssp"); | ||
1527 | MODULE_LICENSE("GPL v2"); | ||
1528 | MODULE_AUTHOR("Broadcom"); | ||
1529 | MODULE_DESCRIPTION("Cygnus ASoC SSP Interface"); | ||
diff --git a/sound/soc/bcm/cygnus-ssp.h b/sound/soc/bcm/cygnus-ssp.h new file mode 100644 index 000000000000..33dd34305928 --- /dev/null +++ b/sound/soc/bcm/cygnus-ssp.h | |||
@@ -0,0 +1,139 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014-2015 Broadcom Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License as | ||
6 | * published by the Free Software Foundation version 2. | ||
7 | * | ||
8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
9 | * kind, whether express or implied; without even the implied warranty | ||
10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | #ifndef __CYGNUS_SSP_H__ | ||
14 | #define __CYGNUS_SSP_H__ | ||
15 | |||
16 | #define CYGNUS_TDM_DAI_MAX_SLOTS 16 | ||
17 | |||
18 | #define CYGNUS_MAX_PLAYBACK_PORTS 4 | ||
19 | #define CYGNUS_MAX_CAPTURE_PORTS 3 | ||
20 | #define CYGNUS_MAX_I2S_PORTS 3 | ||
21 | #define CYGNUS_MAX_PORTS CYGNUS_MAX_PLAYBACK_PORTS | ||
22 | #define CYGNUS_AUIDO_MAX_NUM_CLKS 3 | ||
23 | |||
24 | #define CYGNUS_SSP_FRAMEBITS_DIV 1 | ||
25 | |||
26 | #define CYGNUS_SSPMODE_I2S 0 | ||
27 | #define CYGNUS_SSPMODE_TDM 1 | ||
28 | #define CYGNUS_SSPMODE_UNKNOWN -1 | ||
29 | |||
30 | #define CYGNUS_SSP_CLKSRC_PLL 0 | ||
31 | |||
32 | /* Max string length of our dt property names */ | ||
33 | #define PROP_LEN_MAX 40 | ||
34 | |||
35 | struct ringbuf_regs { | ||
36 | unsigned rdaddr; | ||
37 | unsigned wraddr; | ||
38 | unsigned baseaddr; | ||
39 | unsigned endaddr; | ||
40 | unsigned fmark; /* freemark for play, fullmark for caputure */ | ||
41 | unsigned period_bytes; | ||
42 | unsigned buf_size; | ||
43 | }; | ||
44 | |||
45 | #define RINGBUF_REG_PLAYBACK(num) ((struct ringbuf_regs) { \ | ||
46 | .rdaddr = SRC_RBUF_ ##num## _RDADDR_OFFSET, \ | ||
47 | .wraddr = SRC_RBUF_ ##num## _WRADDR_OFFSET, \ | ||
48 | .baseaddr = SRC_RBUF_ ##num## _BASEADDR_OFFSET, \ | ||
49 | .endaddr = SRC_RBUF_ ##num## _ENDADDR_OFFSET, \ | ||
50 | .fmark = SRC_RBUF_ ##num## _FREE_MARK_OFFSET, \ | ||
51 | .period_bytes = 0, \ | ||
52 | .buf_size = 0, \ | ||
53 | }) | ||
54 | |||
55 | #define RINGBUF_REG_CAPTURE(num) ((struct ringbuf_regs) { \ | ||
56 | .rdaddr = DST_RBUF_ ##num## _RDADDR_OFFSET, \ | ||
57 | .wraddr = DST_RBUF_ ##num## _WRADDR_OFFSET, \ | ||
58 | .baseaddr = DST_RBUF_ ##num## _BASEADDR_OFFSET, \ | ||
59 | .endaddr = DST_RBUF_ ##num## _ENDADDR_OFFSET, \ | ||
60 | .fmark = DST_RBUF_ ##num## _FULL_MARK_OFFSET, \ | ||
61 | .period_bytes = 0, \ | ||
62 | .buf_size = 0, \ | ||
63 | }) | ||
64 | |||
65 | enum cygnus_audio_port_type { | ||
66 | PORT_TDM, | ||
67 | PORT_SPDIF, | ||
68 | }; | ||
69 | |||
70 | struct cygnus_ssp_regs { | ||
71 | u32 i2s_stream_cfg; | ||
72 | u32 i2s_cfg; | ||
73 | u32 i2s_cap_stream_cfg; | ||
74 | u32 i2s_cap_cfg; | ||
75 | u32 i2s_mclk_cfg; | ||
76 | |||
77 | u32 bf_destch_ctrl; | ||
78 | u32 bf_destch_cfg; | ||
79 | u32 bf_sourcech_ctrl; | ||
80 | u32 bf_sourcech_cfg; | ||
81 | u32 bf_sourcech_grp; | ||
82 | }; | ||
83 | |||
84 | struct cygnus_track_clk { | ||
85 | bool cap_en; | ||
86 | bool play_en; | ||
87 | bool cap_clk_en; | ||
88 | bool play_clk_en; | ||
89 | }; | ||
90 | |||
91 | struct cygnus_aio_port { | ||
92 | int portnum; | ||
93 | int mode; | ||
94 | bool is_slave; | ||
95 | int streams_on; /* will be 0 if both capture and play are off */ | ||
96 | int fsync_width; | ||
97 | int port_type; | ||
98 | |||
99 | u32 mclk; | ||
100 | u32 lrclk; | ||
101 | u32 bit_per_frame; | ||
102 | u32 pll_clk_num; | ||
103 | |||
104 | struct cygnus_audio *cygaud; | ||
105 | struct cygnus_ssp_regs regs; | ||
106 | |||
107 | struct ringbuf_regs play_rb_regs; | ||
108 | struct ringbuf_regs capture_rb_regs; | ||
109 | |||
110 | struct snd_pcm_substream *play_stream; | ||
111 | struct snd_pcm_substream *capture_stream; | ||
112 | |||
113 | struct cygnus_track_clk clk_trace; | ||
114 | }; | ||
115 | |||
116 | |||
117 | struct cygnus_audio { | ||
118 | struct cygnus_aio_port portinfo[CYGNUS_MAX_PORTS]; | ||
119 | |||
120 | int irq_num; | ||
121 | void __iomem *audio; | ||
122 | struct device *dev; | ||
123 | void __iomem *i2s_in; | ||
124 | |||
125 | struct clk *audio_clk[CYGNUS_AUIDO_MAX_NUM_CLKS]; | ||
126 | int active_ports; | ||
127 | unsigned long vco_rate; | ||
128 | }; | ||
129 | |||
130 | extern int cygnus_ssp_get_mode(struct snd_soc_dai *cpu_dai); | ||
131 | extern int cygnus_ssp_add_pll_tweak_controls(struct snd_soc_pcm_runtime *rtd); | ||
132 | extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, | ||
133 | int len); | ||
134 | extern int cygnus_soc_platform_register(struct device *dev, | ||
135 | struct cygnus_audio *cygaud); | ||
136 | extern int cygnus_soc_platform_unregister(struct device *dev); | ||
137 | extern int cygnus_ssp_set_custom_fsync_width(struct snd_soc_dai *cpu_dai, | ||
138 | int len); | ||
139 | #endif | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index f3fb98f0a995..1cd6ab344d67 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -32,6 +32,7 @@ config SND_SOC_ALL_CODECS | |||
32 | select SND_SOC_ADAU1977_SPI if SPI_MASTER | 32 | select SND_SOC_ADAU1977_SPI if SPI_MASTER |
33 | select SND_SOC_ADAU1977_I2C if I2C | 33 | select SND_SOC_ADAU1977_I2C if I2C |
34 | select SND_SOC_ADAU1701 if I2C | 34 | select SND_SOC_ADAU1701 if I2C |
35 | select SND_SOC_ADAU7002 | ||
35 | select SND_SOC_ADS117X | 36 | select SND_SOC_ADS117X |
36 | select SND_SOC_AK4104 if SPI_MASTER | 37 | select SND_SOC_AK4104 if SPI_MASTER |
37 | select SND_SOC_AK4535 if I2C | 38 | select SND_SOC_AK4535 if I2C |
@@ -46,6 +47,7 @@ config SND_SOC_ALL_CODECS | |||
46 | select SND_SOC_BT_SCO | 47 | select SND_SOC_BT_SCO |
47 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 48 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
48 | select SND_SOC_CS35L32 if I2C | 49 | select SND_SOC_CS35L32 if I2C |
50 | select SND_SOC_CS35L33 if I2C | ||
49 | select SND_SOC_CS42L51_I2C if I2C | 51 | select SND_SOC_CS42L51_I2C if I2C |
50 | select SND_SOC_CS42L52 if I2C && INPUT | 52 | select SND_SOC_CS42L52 if I2C && INPUT |
51 | select SND_SOC_CS42L56 if I2C && INPUT | 53 | select SND_SOC_CS42L56 if I2C && INPUT |
@@ -57,6 +59,7 @@ config SND_SOC_ALL_CODECS | |||
57 | select SND_SOC_CS42XX8_I2C if I2C | 59 | select SND_SOC_CS42XX8_I2C if I2C |
58 | select SND_SOC_CS4349 if I2C | 60 | select SND_SOC_CS4349 if I2C |
59 | select SND_SOC_CS47L24 if MFD_CS47L24 | 61 | select SND_SOC_CS47L24 if MFD_CS47L24 |
62 | select SND_SOC_CS53L30 if I2C | ||
60 | select SND_SOC_CX20442 if TTY | 63 | select SND_SOC_CX20442 if TTY |
61 | select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI | 64 | select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI |
62 | select SND_SOC_DA7213 if I2C | 65 | select SND_SOC_DA7213 if I2C |
@@ -84,6 +87,7 @@ config SND_SOC_ALL_CODECS | |||
84 | select SND_SOC_MAX98925 if I2C | 87 | select SND_SOC_MAX98925 if I2C |
85 | select SND_SOC_MAX98926 if I2C | 88 | select SND_SOC_MAX98926 if I2C |
86 | select SND_SOC_MAX9850 if I2C | 89 | select SND_SOC_MAX9850 if I2C |
90 | select SND_SOC_MAX9860 if I2C | ||
87 | select SND_SOC_MAX9768 if I2C | 91 | select SND_SOC_MAX9768 if I2C |
88 | select SND_SOC_MAX9877 if I2C | 92 | select SND_SOC_MAX9877 if I2C |
89 | select SND_SOC_MC13783 if MFD_MC13XXX | 93 | select SND_SOC_MC13783 if MFD_MC13XXX |
@@ -269,8 +273,12 @@ config SND_SOC_AD1980 | |||
269 | config SND_SOC_AD73311 | 273 | config SND_SOC_AD73311 |
270 | tristate | 274 | tristate |
271 | 275 | ||
276 | config SND_SOC_ADAU_UTILS | ||
277 | tristate | ||
278 | |||
272 | config SND_SOC_ADAU1373 | 279 | config SND_SOC_ADAU1373 |
273 | tristate | 280 | tristate |
281 | select SND_SOC_ADAU_UTILS | ||
274 | 282 | ||
275 | config SND_SOC_ADAU1701 | 283 | config SND_SOC_ADAU1701 |
276 | tristate "Analog Devices ADAU1701 CODEC" | 284 | tristate "Analog Devices ADAU1701 CODEC" |
@@ -280,6 +288,7 @@ config SND_SOC_ADAU1701 | |||
280 | config SND_SOC_ADAU17X1 | 288 | config SND_SOC_ADAU17X1 |
281 | tristate | 289 | tristate |
282 | select SND_SOC_SIGMADSP_REGMAP | 290 | select SND_SOC_SIGMADSP_REGMAP |
291 | select SND_SOC_ADAU_UTILS | ||
283 | 292 | ||
284 | config SND_SOC_ADAU1761 | 293 | config SND_SOC_ADAU1761 |
285 | tristate | 294 | tristate |
@@ -322,6 +331,9 @@ config SND_SOC_ADAU1977_I2C | |||
322 | select SND_SOC_ADAU1977 | 331 | select SND_SOC_ADAU1977 |
323 | select REGMAP_I2C | 332 | select REGMAP_I2C |
324 | 333 | ||
334 | config SND_SOC_ADAU7002 | ||
335 | tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter" | ||
336 | |||
325 | config SND_SOC_ADAV80X | 337 | config SND_SOC_ADAV80X |
326 | tristate | 338 | tristate |
327 | 339 | ||
@@ -371,7 +383,7 @@ config SND_SOC_ALC5632 | |||
371 | tristate | 383 | tristate |
372 | 384 | ||
373 | config SND_SOC_BT_SCO | 385 | config SND_SOC_BT_SCO |
374 | tristate | 386 | tristate "Dummy BT SCO codec driver" |
375 | 387 | ||
376 | config SND_SOC_CQ0093VC | 388 | config SND_SOC_CQ0093VC |
377 | tristate | 389 | tristate |
@@ -380,6 +392,10 @@ config SND_SOC_CS35L32 | |||
380 | tristate "Cirrus Logic CS35L32 CODEC" | 392 | tristate "Cirrus Logic CS35L32 CODEC" |
381 | depends on I2C | 393 | depends on I2C |
382 | 394 | ||
395 | config SND_SOC_CS35L33 | ||
396 | tristate "Cirrus Logic CS35L33 CODEC" | ||
397 | depends on I2C | ||
398 | |||
383 | config SND_SOC_CS42L51 | 399 | config SND_SOC_CS42L51 |
384 | tristate | 400 | tristate |
385 | 401 | ||
@@ -450,6 +466,11 @@ config SND_SOC_CS4349 | |||
450 | config SND_SOC_CS47L24 | 466 | config SND_SOC_CS47L24 |
451 | tristate | 467 | tristate |
452 | 468 | ||
469 | # Cirrus Logic Quad-Channel ADC | ||
470 | config SND_SOC_CS53L30 | ||
471 | tristate "Cirrus Logic CS53L30 CODEC" | ||
472 | depends on I2C | ||
473 | |||
453 | config SND_SOC_CX20442 | 474 | config SND_SOC_CX20442 |
454 | tristate | 475 | tristate |
455 | depends on TTY | 476 | depends on TTY |
@@ -536,6 +557,10 @@ config SND_SOC_MAX98357A | |||
536 | config SND_SOC_MAX98371 | 557 | config SND_SOC_MAX98371 |
537 | tristate | 558 | tristate |
538 | 559 | ||
560 | config SND_SOC_MAX98504 | ||
561 | tristate "Maxim MAX98504 speaker amplifier" | ||
562 | depends on I2C | ||
563 | |||
539 | config SND_SOC_MAX9867 | 564 | config SND_SOC_MAX9867 |
540 | tristate | 565 | tristate |
541 | 566 | ||
@@ -548,6 +573,11 @@ config SND_SOC_MAX98926 | |||
548 | config SND_SOC_MAX9850 | 573 | config SND_SOC_MAX9850 |
549 | tristate | 574 | tristate |
550 | 575 | ||
576 | config SND_SOC_MAX9860 | ||
577 | tristate "Maxim MAX9860 Mono Audio Voice Codec" | ||
578 | depends on I2C | ||
579 | select REGMAP_I2C | ||
580 | |||
551 | config SND_SOC_PCM1681 | 581 | config SND_SOC_PCM1681 |
552 | tristate "Texas Instruments PCM1681 CODEC" | 582 | tristate "Texas Instruments PCM1681 CODEC" |
553 | depends on I2C | 583 | depends on I2C |
@@ -644,6 +674,9 @@ config SND_SOC_RT298 | |||
644 | config SND_SOC_RT5514 | 674 | config SND_SOC_RT5514 |
645 | tristate | 675 | tristate |
646 | 676 | ||
677 | config SND_SOC_RT5514_SPI | ||
678 | tristate | ||
679 | |||
647 | config SND_SOC_RT5616 | 680 | config SND_SOC_RT5616 |
648 | tristate "Realtek RT5616 CODEC" | 681 | tristate "Realtek RT5616 CODEC" |
649 | depends on I2C | 682 | depends on I2C |
@@ -969,7 +1002,8 @@ config SND_SOC_WM8983 | |||
969 | tristate | 1002 | tristate |
970 | 1003 | ||
971 | config SND_SOC_WM8985 | 1004 | config SND_SOC_WM8985 |
972 | tristate | 1005 | tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver" |
1006 | depends on SND_SOC_I2C_AND_SPI | ||
973 | 1007 | ||
974 | config SND_SOC_WM8988 | 1008 | config SND_SOC_WM8988 |
975 | tristate | 1009 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 0f548fd34ca3..58036af2c7d9 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -7,6 +7,7 @@ snd-soc-ad193x-spi-objs := ad193x-spi.o | |||
7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o | 7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o |
8 | snd-soc-ad1980-objs := ad1980.o | 8 | snd-soc-ad1980-objs := ad1980.o |
9 | snd-soc-ad73311-objs := ad73311.o | 9 | snd-soc-ad73311-objs := ad73311.o |
10 | snd-soc-adau-utils-objs := adau-utils.o | ||
10 | snd-soc-adau1373-objs := adau1373.o | 11 | snd-soc-adau1373-objs := adau1373.o |
11 | snd-soc-adau1701-objs := adau1701.o | 12 | snd-soc-adau1701-objs := adau1701.o |
12 | snd-soc-adau17x1-objs := adau17x1.o | 13 | snd-soc-adau17x1-objs := adau17x1.o |
@@ -19,6 +20,7 @@ snd-soc-adau1781-spi-objs := adau1781-spi.o | |||
19 | snd-soc-adau1977-objs := adau1977.o | 20 | snd-soc-adau1977-objs := adau1977.o |
20 | snd-soc-adau1977-spi-objs := adau1977-spi.o | 21 | snd-soc-adau1977-spi-objs := adau1977-spi.o |
21 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o | 22 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o |
23 | snd-soc-adau7002-objs := adau7002.o | ||
22 | snd-soc-adav80x-objs := adav80x.o | 24 | snd-soc-adav80x-objs := adav80x.o |
23 | snd-soc-adav801-objs := adav801.o | 25 | snd-soc-adav801-objs := adav801.o |
24 | snd-soc-adav803-objs := adav803.o | 26 | snd-soc-adav803-objs := adav803.o |
@@ -35,6 +37,7 @@ snd-soc-arizona-objs := arizona.o | |||
35 | snd-soc-bt-sco-objs := bt-sco.o | 37 | snd-soc-bt-sco-objs := bt-sco.o |
36 | snd-soc-cq93vc-objs := cq93vc.o | 38 | snd-soc-cq93vc-objs := cq93vc.o |
37 | snd-soc-cs35l32-objs := cs35l32.o | 39 | snd-soc-cs35l32-objs := cs35l32.o |
40 | snd-soc-cs35l33-objs := cs35l33.o | ||
38 | snd-soc-cs42l51-objs := cs42l51.o | 41 | snd-soc-cs42l51-objs := cs42l51.o |
39 | snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o | 42 | snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o |
40 | snd-soc-cs42l52-objs := cs42l52.o | 43 | snd-soc-cs42l52-objs := cs42l52.o |
@@ -49,6 +52,7 @@ snd-soc-cs42xx8-objs := cs42xx8.o | |||
49 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o | 52 | snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o |
50 | snd-soc-cs4349-objs := cs4349.o | 53 | snd-soc-cs4349-objs := cs4349.o |
51 | snd-soc-cs47l24-objs := cs47l24.o | 54 | snd-soc-cs47l24-objs := cs47l24.o |
55 | snd-soc-cs53l30-objs := cs53l30.o | ||
52 | snd-soc-cx20442-objs := cx20442.o | 56 | snd-soc-cx20442-objs := cx20442.o |
53 | snd-soc-da7210-objs := da7210.o | 57 | snd-soc-da7210-objs := da7210.o |
54 | snd-soc-da7213-objs := da7213.o | 58 | snd-soc-da7213-objs := da7213.o |
@@ -79,6 +83,7 @@ snd-soc-max9867-objs := max9867.o | |||
79 | snd-soc-max98925-objs := max98925.o | 83 | snd-soc-max98925-objs := max98925.o |
80 | snd-soc-max98926-objs := max98926.o | 84 | snd-soc-max98926-objs := max98926.o |
81 | snd-soc-max9850-objs := max9850.o | 85 | snd-soc-max9850-objs := max9850.o |
86 | snd-soc-max9860-objs := max9860.o | ||
82 | snd-soc-mc13783-objs := mc13783.o | 87 | snd-soc-mc13783-objs := mc13783.o |
83 | snd-soc-ml26124-objs := ml26124.o | 88 | snd-soc-ml26124-objs := ml26124.o |
84 | snd-soc-nau8825-objs := nau8825.o | 89 | snd-soc-nau8825-objs := nau8825.o |
@@ -100,6 +105,7 @@ snd-soc-rl6347a-objs := rl6347a.o | |||
100 | snd-soc-rt286-objs := rt286.o | 105 | snd-soc-rt286-objs := rt286.o |
101 | snd-soc-rt298-objs := rt298.o | 106 | snd-soc-rt298-objs := rt298.o |
102 | snd-soc-rt5514-objs := rt5514.o | 107 | snd-soc-rt5514-objs := rt5514.o |
108 | snd-soc-rt5514-spi-objs := rt5514-spi.o | ||
103 | snd-soc-rt5616-objs := rt5616.o | 109 | snd-soc-rt5616-objs := rt5616.o |
104 | snd-soc-rt5631-objs := rt5631.o | 110 | snd-soc-rt5631-objs := rt5631.o |
105 | snd-soc-rt5640-objs := rt5640.o | 111 | snd-soc-rt5640-objs := rt5640.o |
@@ -208,6 +214,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o | |||
208 | 214 | ||
209 | # Amp | 215 | # Amp |
210 | snd-soc-max9877-objs := max9877.o | 216 | snd-soc-max9877-objs := max9877.o |
217 | snd-soc-max98504-objs := max98504.o | ||
211 | snd-soc-tpa6130a2-objs := tpa6130a2.o | 218 | snd-soc-tpa6130a2-objs := tpa6130a2.o |
212 | snd-soc-tas2552-objs := tas2552.o | 219 | snd-soc-tas2552-objs := tas2552.o |
213 | 220 | ||
@@ -220,6 +227,7 @@ obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o | |||
220 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o | 227 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o |
221 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 228 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
222 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 229 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
230 | obj-$(CONFIG_SND_SOC_ADAU_UTILS) += snd-soc-adau-utils.o | ||
223 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o | 231 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o |
224 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o | 232 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o |
225 | obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o | 233 | obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o |
@@ -232,6 +240,7 @@ obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o | |||
232 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o | 240 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o |
233 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o | 241 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o |
234 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o | 242 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o |
243 | obj-$(CONFIG_SND_SOC_ADAU7002) += snd-soc-adau7002.o | ||
235 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | 244 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o |
236 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o | 245 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o |
237 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o | 246 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o |
@@ -250,6 +259,7 @@ obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o | |||
250 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | 259 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o |
251 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 260 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
252 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o | 261 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o |
262 | obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o | ||
253 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 263 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
254 | obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o | 264 | obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o |
255 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o | 265 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o |
@@ -264,6 +274,7 @@ obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o | |||
264 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o | 274 | obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o |
265 | obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o | 275 | obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o |
266 | obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o | 276 | obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o |
277 | obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o | ||
267 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 278 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
268 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | 279 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o |
269 | obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o | 280 | obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o |
@@ -293,6 +304,7 @@ obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o | |||
293 | obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o | 304 | obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o |
294 | obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o | 305 | obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o |
295 | obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o | 306 | obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o |
307 | obj-$(CONFIG_SND_SOC_MAX9860) += snd-soc-max9860.o | ||
296 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o | 308 | obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o |
297 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o | 309 | obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o |
298 | obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o | 310 | obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o |
@@ -314,6 +326,7 @@ obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o | |||
314 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o | 326 | obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o |
315 | obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o | 327 | obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o |
316 | obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o | 328 | obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o |
329 | obj-$(CONFIG_SND_SOC_RT5514_SPI) += snd-soc-rt5514-spi.o | ||
317 | obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o | 330 | obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o |
318 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 331 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
319 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 332 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
@@ -419,4 +432,5 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o | |||
419 | 432 | ||
420 | # Amp | 433 | # Amp |
421 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o | 434 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o |
435 | obj-$(CONFIG_SND_SOC_MAX98504) += snd-soc-max98504.o | ||
422 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o | 436 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o |
diff --git a/sound/soc/codecs/adau-utils.c b/sound/soc/codecs/adau-utils.c new file mode 100644 index 000000000000..19d6a6f41b12 --- /dev/null +++ b/sound/soc/codecs/adau-utils.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Shared helper functions for devices from the ADAU family | ||
3 | * | ||
4 | * Copyright 2011-2016 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2 or later. | ||
8 | */ | ||
9 | |||
10 | #include <linux/gcd.h> | ||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include "adau-utils.h" | ||
15 | |||
16 | int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, | ||
17 | uint8_t regs[5]) | ||
18 | { | ||
19 | unsigned int r, n, m, i, j; | ||
20 | unsigned int div; | ||
21 | |||
22 | if (!freq_out) { | ||
23 | r = 0; | ||
24 | n = 0; | ||
25 | m = 0; | ||
26 | div = 0; | ||
27 | } else { | ||
28 | if (freq_out % freq_in != 0) { | ||
29 | div = DIV_ROUND_UP(freq_in, 13500000); | ||
30 | freq_in /= div; | ||
31 | r = freq_out / freq_in; | ||
32 | i = freq_out % freq_in; | ||
33 | j = gcd(i, freq_in); | ||
34 | n = i / j; | ||
35 | m = freq_in / j; | ||
36 | div--; | ||
37 | } else { | ||
38 | r = freq_out / freq_in; | ||
39 | n = 0; | ||
40 | m = 0; | ||
41 | div = 0; | ||
42 | } | ||
43 | if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) | ||
44 | return -EINVAL; | ||
45 | } | ||
46 | |||
47 | regs[0] = m >> 8; | ||
48 | regs[1] = m & 0xff; | ||
49 | regs[2] = n >> 8; | ||
50 | regs[3] = n & 0xff; | ||
51 | regs[4] = (r << 3) | (div << 1); | ||
52 | if (m != 0) | ||
53 | regs[4] |= 1; /* Fractional mode */ | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(adau_calc_pll_cfg); | ||
58 | |||
59 | MODULE_DESCRIPTION("ASoC ADAU audio CODECs shared helper functions"); | ||
60 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
61 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/adau-utils.h b/sound/soc/codecs/adau-utils.h new file mode 100644 index 000000000000..939b5f37762f --- /dev/null +++ b/sound/soc/codecs/adau-utils.h | |||
@@ -0,0 +1,7 @@ | |||
1 | #ifndef SOUND_SOC_CODECS_ADAU_PLL_H | ||
2 | #define SOUND_SOC_CODECS_ADAU_PLL_H | ||
3 | |||
4 | int adau_calc_pll_cfg(unsigned int freq_in, unsigned int freq_out, | ||
5 | uint8_t regs[5]); | ||
6 | |||
7 | #endif | ||
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index fe1353a797b9..1556b360fa15 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <sound/adau1373.h> | 23 | #include <sound/adau1373.h> |
24 | 24 | ||
25 | #include "adau1373.h" | 25 | #include "adau1373.h" |
26 | #include "adau-utils.h" | ||
26 | 27 | ||
27 | struct adau1373_dai { | 28 | struct adau1373_dai { |
28 | unsigned int clk_src; | 29 | unsigned int clk_src; |
@@ -1254,7 +1255,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1254 | { | 1255 | { |
1255 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 1256 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
1256 | unsigned int dpll_div = 0; | 1257 | unsigned int dpll_div = 0; |
1257 | unsigned int x, r, n, m, i, j, mode; | 1258 | uint8_t pll_regs[5]; |
1259 | int ret; | ||
1258 | 1260 | ||
1259 | switch (pll_id) { | 1261 | switch (pll_id) { |
1260 | case ADAU1373_PLL1: | 1262 | case ADAU1373_PLL1: |
@@ -1295,27 +1297,8 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1295 | dpll_div++; | 1297 | dpll_div++; |
1296 | } | 1298 | } |
1297 | 1299 | ||
1298 | if (freq_out % freq_in != 0) { | 1300 | ret = adau_calc_pll_cfg(freq_in, freq_out, pll_regs); |
1299 | /* fout = fin * (r + (n/m)) / x */ | 1301 | if (ret) |
1300 | x = DIV_ROUND_UP(freq_in, 13500000); | ||
1301 | freq_in /= x; | ||
1302 | r = freq_out / freq_in; | ||
1303 | i = freq_out % freq_in; | ||
1304 | j = gcd(i, freq_in); | ||
1305 | n = i / j; | ||
1306 | m = freq_in / j; | ||
1307 | x--; | ||
1308 | mode = 1; | ||
1309 | } else { | ||
1310 | /* fout = fin / r */ | ||
1311 | r = freq_out / freq_in; | ||
1312 | n = 0; | ||
1313 | m = 0; | ||
1314 | x = 0; | ||
1315 | mode = 0; | ||
1316 | } | ||
1317 | |||
1318 | if (r < 2 || r > 8 || x > 3 || m > 0xffff || n > 0xffff) | ||
1319 | return -EINVAL; | 1302 | return -EINVAL; |
1320 | 1303 | ||
1321 | if (dpll_div) { | 1304 | if (dpll_div) { |
@@ -1330,12 +1313,11 @@ static int adau1373_set_pll(struct snd_soc_codec *codec, int pll_id, | |||
1330 | 1313 | ||
1331 | regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), | 1314 | regmap_write(adau1373->regmap, ADAU1373_DPLL_CTRL(pll_id), |
1332 | (source << 4) | dpll_div); | 1315 | (source << 4) | dpll_div); |
1333 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), (m >> 8) & 0xff); | 1316 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL1(pll_id), pll_regs[0]); |
1334 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), m & 0xff); | 1317 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL2(pll_id), pll_regs[1]); |
1335 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), (n >> 8) & 0xff); | 1318 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL3(pll_id), pll_regs[2]); |
1336 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), n & 0xff); | 1319 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL4(pll_id), pll_regs[3]); |
1337 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), | 1320 | regmap_write(adau1373->regmap, ADAU1373_PLL_CTRL5(pll_id), pll_regs[4]); |
1338 | (r << 3) | (x << 1) | mode); | ||
1339 | 1321 | ||
1340 | /* Set sysclk to pll_rate / 4 */ | 1322 | /* Set sysclk to pll_rate / 4 */ |
1341 | regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); | 1323 | regmap_update_bits(adau1373->regmap, ADAU1373_CLK_SRC_DIV(pll_id), 0x3f, 0x09); |
diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 8de010f758cd..9e7f257f17f8 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c | |||
@@ -31,7 +31,7 @@ static int adau1761_i2c_probe(struct i2c_client *client, | |||
31 | 31 | ||
32 | static int adau1761_i2c_remove(struct i2c_client *client) | 32 | static int adau1761_i2c_remove(struct i2c_client *client) |
33 | { | 33 | { |
34 | snd_soc_unregister_codec(&client->dev); | 34 | adau17x1_remove(&client->dev); |
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/sound/soc/codecs/adau1761-spi.c b/sound/soc/codecs/adau1761-spi.c index d9171245bd9f..a0b214be759a 100644 --- a/sound/soc/codecs/adau1761-spi.c +++ b/sound/soc/codecs/adau1761-spi.c | |||
@@ -48,7 +48,7 @@ static int adau1761_spi_probe(struct spi_device *spi) | |||
48 | 48 | ||
49 | static int adau1761_spi_remove(struct spi_device *spi) | 49 | static int adau1761_spi_remove(struct spi_device *spi) |
50 | { | 50 | { |
51 | snd_soc_unregister_codec(&spi->dev); | 51 | adau17x1_remove(&spi->dev); |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 06cbca84cf02..7b9d1802d159 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c | |||
@@ -31,7 +31,7 @@ static int adau1781_i2c_probe(struct i2c_client *client, | |||
31 | 31 | ||
32 | static int adau1781_i2c_remove(struct i2c_client *client) | 32 | static int adau1781_i2c_remove(struct i2c_client *client) |
33 | { | 33 | { |
34 | snd_soc_unregister_codec(&client->dev); | 34 | adau17x1_remove(&client->dev); |
35 | return 0; | 35 | return 0; |
36 | } | 36 | } |
37 | 37 | ||
diff --git a/sound/soc/codecs/adau1781-spi.c b/sound/soc/codecs/adau1781-spi.c index 3d965a01b99c..9b233544d2e8 100644 --- a/sound/soc/codecs/adau1781-spi.c +++ b/sound/soc/codecs/adau1781-spi.c | |||
@@ -48,7 +48,7 @@ static int adau1781_spi_probe(struct spi_device *spi) | |||
48 | 48 | ||
49 | static int adau1781_spi_remove(struct spi_device *spi) | 49 | static int adau1781_spi_remove(struct spi_device *spi) |
50 | { | 50 | { |
51 | snd_soc_unregister_codec(&spi->dev); | 51 | adau17x1_remove(&spi->dev); |
52 | return 0; | 52 | return 0; |
53 | } | 53 | } |
54 | 54 | ||
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index fcf05b254ecd..439aa3ff1f99 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/init.h> | 11 | #include <linux/init.h> |
12 | #include <linux/clk.h> | ||
12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
13 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
14 | #include <sound/core.h> | 15 | #include <sound/core.h> |
@@ -23,6 +24,7 @@ | |||
23 | 24 | ||
24 | #include "sigmadsp.h" | 25 | #include "sigmadsp.h" |
25 | #include "adau17x1.h" | 26 | #include "adau17x1.h" |
27 | #include "adau-utils.h" | ||
26 | 28 | ||
27 | static const char * const adau17x1_capture_mixer_boost_text[] = { | 29 | static const char * const adau17x1_capture_mixer_boost_text[] = { |
28 | "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", | 30 | "Normal operation", "Boost Level 1", "Boost Level 2", "Boost Level 3", |
@@ -302,6 +304,116 @@ bool adau17x1_has_dsp(struct adau *adau) | |||
302 | } | 304 | } |
303 | EXPORT_SYMBOL_GPL(adau17x1_has_dsp); | 305 | EXPORT_SYMBOL_GPL(adau17x1_has_dsp); |
304 | 306 | ||
307 | static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, | ||
308 | int source, unsigned int freq_in, unsigned int freq_out) | ||
309 | { | ||
310 | struct snd_soc_codec *codec = dai->codec; | ||
311 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
312 | int ret; | ||
313 | |||
314 | if (freq_in < 8000000 || freq_in > 27000000) | ||
315 | return -EINVAL; | ||
316 | |||
317 | ret = adau_calc_pll_cfg(freq_in, freq_out, adau->pll_regs); | ||
318 | if (ret < 0) | ||
319 | return ret; | ||
320 | |||
321 | /* The PLL register is 6 bytes long and can only be written at once. */ | ||
322 | ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, | ||
323 | adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); | ||
324 | if (ret) | ||
325 | return ret; | ||
326 | |||
327 | adau->pll_freq = freq_out; | ||
328 | |||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, | ||
333 | int clk_id, unsigned int freq, int dir) | ||
334 | { | ||
335 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec); | ||
336 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
337 | bool is_pll; | ||
338 | bool was_pll; | ||
339 | |||
340 | switch (clk_id) { | ||
341 | case ADAU17X1_CLK_SRC_MCLK: | ||
342 | is_pll = false; | ||
343 | break; | ||
344 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
345 | if (!adau->mclk) | ||
346 | return -EINVAL; | ||
347 | /* Fall-through */ | ||
348 | case ADAU17X1_CLK_SRC_PLL: | ||
349 | is_pll = true; | ||
350 | break; | ||
351 | default: | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | switch (adau->clk_src) { | ||
356 | case ADAU17X1_CLK_SRC_MCLK: | ||
357 | was_pll = false; | ||
358 | break; | ||
359 | case ADAU17X1_CLK_SRC_PLL: | ||
360 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
361 | was_pll = true; | ||
362 | break; | ||
363 | default: | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | adau->sysclk = freq; | ||
368 | |||
369 | if (is_pll != was_pll) { | ||
370 | if (is_pll) { | ||
371 | snd_soc_dapm_add_routes(dapm, | ||
372 | &adau17x1_dapm_pll_route, 1); | ||
373 | } else { | ||
374 | snd_soc_dapm_del_routes(dapm, | ||
375 | &adau17x1_dapm_pll_route, 1); | ||
376 | } | ||
377 | } | ||
378 | |||
379 | adau->clk_src = clk_id; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static int adau17x1_auto_pll(struct snd_soc_dai *dai, | ||
385 | struct snd_pcm_hw_params *params) | ||
386 | { | ||
387 | struct adau *adau = snd_soc_dai_get_drvdata(dai); | ||
388 | unsigned int pll_rate; | ||
389 | |||
390 | switch (params_rate(params)) { | ||
391 | case 48000: | ||
392 | case 8000: | ||
393 | case 12000: | ||
394 | case 16000: | ||
395 | case 24000: | ||
396 | case 32000: | ||
397 | case 96000: | ||
398 | pll_rate = 48000 * 1024; | ||
399 | break; | ||
400 | case 44100: | ||
401 | case 7350: | ||
402 | case 11025: | ||
403 | case 14700: | ||
404 | case 22050: | ||
405 | case 29400: | ||
406 | case 88200: | ||
407 | pll_rate = 44100 * 1024; | ||
408 | break; | ||
409 | default: | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | |||
413 | return adau17x1_set_dai_pll(dai, ADAU17X1_PLL, ADAU17X1_PLL_SRC_MCLK, | ||
414 | clk_get_rate(adau->mclk), pll_rate); | ||
415 | } | ||
416 | |||
305 | static int adau17x1_hw_params(struct snd_pcm_substream *substream, | 417 | static int adau17x1_hw_params(struct snd_pcm_substream *substream, |
306 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 418 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
307 | { | 419 | { |
@@ -311,10 +423,19 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
311 | unsigned int freq; | 423 | unsigned int freq; |
312 | int ret; | 424 | int ret; |
313 | 425 | ||
314 | if (adau->clk_src == ADAU17X1_CLK_SRC_PLL) | 426 | switch (adau->clk_src) { |
427 | case ADAU17X1_CLK_SRC_PLL_AUTO: | ||
428 | ret = adau17x1_auto_pll(dai, params); | ||
429 | if (ret) | ||
430 | return ret; | ||
431 | /* Fall-through */ | ||
432 | case ADAU17X1_CLK_SRC_PLL: | ||
315 | freq = adau->pll_freq; | 433 | freq = adau->pll_freq; |
316 | else | 434 | break; |
435 | default: | ||
317 | freq = adau->sysclk; | 436 | freq = adau->sysclk; |
437 | break; | ||
438 | } | ||
318 | 439 | ||
319 | if (freq % params_rate(params) != 0) | 440 | if (freq % params_rate(params) != 0) |
320 | return -EINVAL; | 441 | return -EINVAL; |
@@ -386,93 +507,6 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream, | |||
386 | ADAU17X1_SERIAL_PORT1_DELAY_MASK, val); | 507 | ADAU17X1_SERIAL_PORT1_DELAY_MASK, val); |
387 | } | 508 | } |
388 | 509 | ||
389 | static int adau17x1_set_dai_pll(struct snd_soc_dai *dai, int pll_id, | ||
390 | int source, unsigned int freq_in, unsigned int freq_out) | ||
391 | { | ||
392 | struct snd_soc_codec *codec = dai->codec; | ||
393 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | ||
394 | unsigned int r, n, m, i, j; | ||
395 | unsigned int div; | ||
396 | int ret; | ||
397 | |||
398 | if (freq_in < 8000000 || freq_in > 27000000) | ||
399 | return -EINVAL; | ||
400 | |||
401 | if (!freq_out) { | ||
402 | r = 0; | ||
403 | n = 0; | ||
404 | m = 0; | ||
405 | div = 0; | ||
406 | } else { | ||
407 | if (freq_out % freq_in != 0) { | ||
408 | div = DIV_ROUND_UP(freq_in, 13500000); | ||
409 | freq_in /= div; | ||
410 | r = freq_out / freq_in; | ||
411 | i = freq_out % freq_in; | ||
412 | j = gcd(i, freq_in); | ||
413 | n = i / j; | ||
414 | m = freq_in / j; | ||
415 | div--; | ||
416 | } else { | ||
417 | r = freq_out / freq_in; | ||
418 | n = 0; | ||
419 | m = 0; | ||
420 | div = 0; | ||
421 | } | ||
422 | if (n > 0xffff || m > 0xffff || div > 3 || r > 8 || r < 2) | ||
423 | return -EINVAL; | ||
424 | } | ||
425 | |||
426 | adau->pll_regs[0] = m >> 8; | ||
427 | adau->pll_regs[1] = m & 0xff; | ||
428 | adau->pll_regs[2] = n >> 8; | ||
429 | adau->pll_regs[3] = n & 0xff; | ||
430 | adau->pll_regs[4] = (r << 3) | (div << 1); | ||
431 | if (m != 0) | ||
432 | adau->pll_regs[4] |= 1; /* Fractional mode */ | ||
433 | |||
434 | /* The PLL register is 6 bytes long and can only be written at once. */ | ||
435 | ret = regmap_raw_write(adau->regmap, ADAU17X1_PLL_CONTROL, | ||
436 | adau->pll_regs, ARRAY_SIZE(adau->pll_regs)); | ||
437 | if (ret) | ||
438 | return ret; | ||
439 | |||
440 | adau->pll_freq = freq_out; | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static int adau17x1_set_dai_sysclk(struct snd_soc_dai *dai, | ||
446 | int clk_id, unsigned int freq, int dir) | ||
447 | { | ||
448 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(dai->codec); | ||
449 | struct adau *adau = snd_soc_codec_get_drvdata(dai->codec); | ||
450 | |||
451 | switch (clk_id) { | ||
452 | case ADAU17X1_CLK_SRC_MCLK: | ||
453 | case ADAU17X1_CLK_SRC_PLL: | ||
454 | break; | ||
455 | default: | ||
456 | return -EINVAL; | ||
457 | } | ||
458 | |||
459 | adau->sysclk = freq; | ||
460 | |||
461 | if (adau->clk_src != clk_id) { | ||
462 | if (clk_id == ADAU17X1_CLK_SRC_PLL) { | ||
463 | snd_soc_dapm_add_routes(dapm, | ||
464 | &adau17x1_dapm_pll_route, 1); | ||
465 | } else { | ||
466 | snd_soc_dapm_del_routes(dapm, | ||
467 | &adau17x1_dapm_pll_route, 1); | ||
468 | } | ||
469 | } | ||
470 | |||
471 | adau->clk_src = clk_id; | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, | 510 | static int adau17x1_set_dai_fmt(struct snd_soc_dai *dai, |
477 | unsigned int fmt) | 511 | unsigned int fmt) |
478 | { | 512 | { |
@@ -857,6 +891,10 @@ int adau17x1_add_routes(struct snd_soc_codec *codec) | |||
857 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes, | 891 | ret = snd_soc_dapm_add_routes(dapm, adau17x1_no_dsp_dapm_routes, |
858 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); | 892 | ARRAY_SIZE(adau17x1_no_dsp_dapm_routes)); |
859 | } | 893 | } |
894 | |||
895 | if (adau->clk_src != ADAU17X1_CLK_SRC_MCLK) | ||
896 | snd_soc_dapm_add_routes(dapm, &adau17x1_dapm_pll_route, 1); | ||
897 | |||
860 | return ret; | 898 | return ret; |
861 | } | 899 | } |
862 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); | 900 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); |
@@ -879,6 +917,7 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
879 | const char *firmware_name) | 917 | const char *firmware_name) |
880 | { | 918 | { |
881 | struct adau *adau; | 919 | struct adau *adau; |
920 | int ret; | ||
882 | 921 | ||
883 | if (IS_ERR(regmap)) | 922 | if (IS_ERR(regmap)) |
884 | return PTR_ERR(regmap); | 923 | return PTR_ERR(regmap); |
@@ -887,6 +926,30 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
887 | if (!adau) | 926 | if (!adau) |
888 | return -ENOMEM; | 927 | return -ENOMEM; |
889 | 928 | ||
929 | adau->mclk = devm_clk_get(dev, "mclk"); | ||
930 | if (IS_ERR(adau->mclk)) { | ||
931 | if (PTR_ERR(adau->mclk) != -ENOENT) | ||
932 | return PTR_ERR(adau->mclk); | ||
933 | /* Clock is optional (for the driver) */ | ||
934 | adau->mclk = NULL; | ||
935 | } else if (adau->mclk) { | ||
936 | adau->clk_src = ADAU17X1_CLK_SRC_PLL_AUTO; | ||
937 | |||
938 | /* | ||
939 | * Any valid PLL output rate will work at this point, use one | ||
940 | * that is likely to be chosen later as well. The register will | ||
941 | * be written when the PLL is powered up for the first time. | ||
942 | */ | ||
943 | ret = adau_calc_pll_cfg(clk_get_rate(adau->mclk), 48000 * 1024, | ||
944 | adau->pll_regs); | ||
945 | if (ret < 0) | ||
946 | return ret; | ||
947 | |||
948 | ret = clk_prepare_enable(adau->mclk); | ||
949 | if (ret) | ||
950 | return ret; | ||
951 | } | ||
952 | |||
890 | adau->regmap = regmap; | 953 | adau->regmap = regmap; |
891 | adau->switch_mode = switch_mode; | 954 | adau->switch_mode = switch_mode; |
892 | adau->type = type; | 955 | adau->type = type; |
@@ -910,6 +973,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap, | |||
910 | } | 973 | } |
911 | EXPORT_SYMBOL_GPL(adau17x1_probe); | 974 | EXPORT_SYMBOL_GPL(adau17x1_probe); |
912 | 975 | ||
976 | void adau17x1_remove(struct device *dev) | ||
977 | { | ||
978 | struct adau *adau = dev_get_drvdata(dev); | ||
979 | |||
980 | snd_soc_unregister_codec(dev); | ||
981 | if (adau->mclk) | ||
982 | clk_disable_unprepare(adau->mclk); | ||
983 | } | ||
984 | EXPORT_SYMBOL_GPL(adau17x1_remove); | ||
985 | |||
913 | MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code"); | 986 | MODULE_DESCRIPTION("ASoC ADAU1X61/ADAU1X81 common code"); |
914 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 987 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
915 | MODULE_LICENSE("GPL"); | 988 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 5ae87a084d97..bf04b7efee40 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h | |||
@@ -22,13 +22,18 @@ enum adau17x1_pll_src { | |||
22 | }; | 22 | }; |
23 | 23 | ||
24 | enum adau17x1_clk_src { | 24 | enum adau17x1_clk_src { |
25 | /* Automatically configure PLL based on the sample rate */ | ||
26 | ADAU17X1_CLK_SRC_PLL_AUTO, | ||
25 | ADAU17X1_CLK_SRC_MCLK, | 27 | ADAU17X1_CLK_SRC_MCLK, |
26 | ADAU17X1_CLK_SRC_PLL, | 28 | ADAU17X1_CLK_SRC_PLL, |
27 | }; | 29 | }; |
28 | 30 | ||
31 | struct clk; | ||
32 | |||
29 | struct adau { | 33 | struct adau { |
30 | unsigned int sysclk; | 34 | unsigned int sysclk; |
31 | unsigned int pll_freq; | 35 | unsigned int pll_freq; |
36 | struct clk *mclk; | ||
32 | 37 | ||
33 | enum adau17x1_clk_src clk_src; | 38 | enum adau17x1_clk_src clk_src; |
34 | enum adau17x1_type type; | 39 | enum adau17x1_type type; |
@@ -52,6 +57,7 @@ int adau17x1_add_routes(struct snd_soc_codec *codec); | |||
52 | int adau17x1_probe(struct device *dev, struct regmap *regmap, | 57 | int adau17x1_probe(struct device *dev, struct regmap *regmap, |
53 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), | 58 | enum adau17x1_type type, void (*switch_mode)(struct device *dev), |
54 | const char *firmware_name); | 59 | const char *firmware_name); |
60 | void adau17x1_remove(struct device *dev); | ||
55 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | 61 | int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, |
56 | enum adau17x1_micbias_voltage micbias); | 62 | enum adau17x1_micbias_voltage micbias); |
57 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); | 63 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); |
diff --git a/sound/soc/codecs/adau7002.c b/sound/soc/codecs/adau7002.c new file mode 100644 index 000000000000..9df72c6adcca --- /dev/null +++ b/sound/soc/codecs/adau7002.c | |||
@@ -0,0 +1,80 @@ | |||
1 | /* | ||
2 | * ADAU7002 Stereo PDM-to-I2S/TDM converter driver | ||
3 | * | ||
4 | * Copyright 2014-2016 Analog Devices | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/init.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/of.h> | ||
13 | #include <linux/platform_device.h> | ||
14 | |||
15 | #include <sound/soc.h> | ||
16 | |||
17 | static const struct snd_soc_dapm_widget adau7002_widgets[] = { | ||
18 | SND_SOC_DAPM_INPUT("PDM_DAT"), | ||
19 | SND_SOC_DAPM_REGULATOR_SUPPLY("IOVDD", 0, 0), | ||
20 | }; | ||
21 | |||
22 | static const struct snd_soc_dapm_route adau7002_routes[] = { | ||
23 | { "Capture", NULL, "PDM_DAT" }, | ||
24 | { "Capture", NULL, "IOVDD" }, | ||
25 | }; | ||
26 | |||
27 | static struct snd_soc_dai_driver adau7002_dai = { | ||
28 | .name = "adau7002-hifi", | ||
29 | .capture = { | ||
30 | .stream_name = "Capture", | ||
31 | .channels_min = 2, | ||
32 | .channels_max = 2, | ||
33 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE | | ||
35 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | | ||
36 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE, | ||
37 | .sig_bits = 20, | ||
38 | }, | ||
39 | }; | ||
40 | |||
41 | static const struct snd_soc_codec_driver adau7002_codec_driver = { | ||
42 | .dapm_widgets = adau7002_widgets, | ||
43 | .num_dapm_widgets = ARRAY_SIZE(adau7002_widgets), | ||
44 | .dapm_routes = adau7002_routes, | ||
45 | .num_dapm_routes = ARRAY_SIZE(adau7002_routes), | ||
46 | }; | ||
47 | |||
48 | static int adau7002_probe(struct platform_device *pdev) | ||
49 | { | ||
50 | return snd_soc_register_codec(&pdev->dev, &adau7002_codec_driver, | ||
51 | &adau7002_dai, 1); | ||
52 | } | ||
53 | |||
54 | static int adau7002_remove(struct platform_device *pdev) | ||
55 | { | ||
56 | snd_soc_unregister_codec(&pdev->dev); | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_OF | ||
61 | static const struct of_device_id adau7002_dt_ids[] = { | ||
62 | { .compatible = "adi,adau7002", }, | ||
63 | { } | ||
64 | }; | ||
65 | MODULE_DEVICE_TABLE(of, adau7002_dt_ids); | ||
66 | #endif | ||
67 | |||
68 | static struct platform_driver adau7002_driver = { | ||
69 | .driver = { | ||
70 | .name = "adau7002", | ||
71 | .of_match_table = of_match_ptr(adau7002_dt_ids), | ||
72 | }, | ||
73 | .probe = adau7002_probe, | ||
74 | .remove = adau7002_remove, | ||
75 | }; | ||
76 | module_platform_driver(adau7002_driver); | ||
77 | |||
78 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
79 | MODULE_DESCRIPTION("ADAU7002 Stereo PDM-to-I2S/TDM Converter driver"); | ||
80 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/ak4613.c b/sound/soc/codecs/ak4613.c index 5013d2ba0c10..97798d250f08 100644 --- a/sound/soc/codecs/ak4613.c +++ b/sound/soc/codecs/ak4613.c | |||
@@ -437,15 +437,25 @@ static struct snd_soc_dai_driver ak4613_dai = { | |||
437 | .symmetric_rates = 1, | 437 | .symmetric_rates = 1, |
438 | }; | 438 | }; |
439 | 439 | ||
440 | static int ak4613_resume(struct snd_soc_codec *codec) | 440 | static int ak4613_suspend(struct snd_soc_codec *codec) |
441 | { | 441 | { |
442 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | 442 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); |
443 | 443 | ||
444 | regcache_cache_only(regmap, true); | ||
444 | regcache_mark_dirty(regmap); | 445 | regcache_mark_dirty(regmap); |
446 | return 0; | ||
447 | } | ||
448 | |||
449 | static int ak4613_resume(struct snd_soc_codec *codec) | ||
450 | { | ||
451 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
452 | |||
453 | regcache_cache_only(regmap, false); | ||
445 | return regcache_sync(regmap); | 454 | return regcache_sync(regmap); |
446 | } | 455 | } |
447 | 456 | ||
448 | static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { | 457 | static struct snd_soc_codec_driver soc_codec_dev_ak4613 = { |
458 | .suspend = ak4613_suspend, | ||
449 | .resume = ak4613_resume, | 459 | .resume = ak4613_resume, |
450 | .set_bias_level = ak4613_set_bias_level, | 460 | .set_bias_level = ak4613_set_bias_level, |
451 | .controls = ak4613_snd_controls, | 461 | .controls = ak4613_snd_controls, |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 4d8b9e49e8d6..cc941d66ec3d 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -523,15 +523,23 @@ static struct snd_soc_dai_driver ak4642_dai = { | |||
523 | .symmetric_rates = 1, | 523 | .symmetric_rates = 1, |
524 | }; | 524 | }; |
525 | 525 | ||
526 | static int ak4642_resume(struct snd_soc_codec *codec) | 526 | static int ak4642_suspend(struct snd_soc_codec *codec) |
527 | { | 527 | { |
528 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | 528 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); |
529 | 529 | ||
530 | regcache_cache_only(regmap, true); | ||
530 | regcache_mark_dirty(regmap); | 531 | regcache_mark_dirty(regmap); |
531 | regcache_sync(regmap); | ||
532 | return 0; | 532 | return 0; |
533 | } | 533 | } |
534 | 534 | ||
535 | static int ak4642_resume(struct snd_soc_codec *codec) | ||
536 | { | ||
537 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
538 | |||
539 | regcache_cache_only(regmap, false); | ||
540 | regcache_sync(regmap); | ||
541 | return 0; | ||
542 | } | ||
535 | static int ak4642_probe(struct snd_soc_codec *codec) | 543 | static int ak4642_probe(struct snd_soc_codec *codec) |
536 | { | 544 | { |
537 | struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); | 545 | struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); |
@@ -544,6 +552,7 @@ static int ak4642_probe(struct snd_soc_codec *codec) | |||
544 | 552 | ||
545 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { | 553 | static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { |
546 | .probe = ak4642_probe, | 554 | .probe = ak4642_probe, |
555 | .suspend = ak4642_suspend, | ||
547 | .resume = ak4642_resume, | 556 | .resume = ak4642_resume, |
548 | .set_bias_level = ak4642_set_bias_level, | 557 | .set_bias_level = ak4642_set_bias_level, |
549 | .controls = ak4642_snd_controls, | 558 | .controls = ak4642_snd_controls, |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 664a8c044ffb..ecfdbfcae366 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -85,30 +85,9 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, | |||
85 | { | 85 | { |
86 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | 86 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
87 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 87 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
88 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
89 | bool manual_ena = false; | ||
90 | int val; | 88 | int val; |
91 | 89 | ||
92 | switch (arizona->type) { | ||
93 | case WM5102: | ||
94 | switch (arizona->rev) { | ||
95 | case 0: | ||
96 | break; | ||
97 | default: | ||
98 | manual_ena = true; | ||
99 | break; | ||
100 | } | ||
101 | default: | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | switch (event) { | 90 | switch (event) { |
106 | case SND_SOC_DAPM_PRE_PMU: | ||
107 | if (!priv->spk_ena && manual_ena) { | ||
108 | regmap_write_async(arizona->regmap, 0x4f5, 0x25a); | ||
109 | priv->spk_ena_pending = true; | ||
110 | } | ||
111 | break; | ||
112 | case SND_SOC_DAPM_POST_PMU: | 91 | case SND_SOC_DAPM_POST_PMU: |
113 | val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); | 92 | val = snd_soc_read(codec, ARIZONA_INTERRUPT_RAW_STATUS_3); |
114 | if (val & ARIZONA_SPK_OVERHEAT_STS) { | 93 | if (val & ARIZONA_SPK_OVERHEAT_STS) { |
@@ -120,33 +99,12 @@ static int arizona_spk_ev(struct snd_soc_dapm_widget *w, | |||
120 | regmap_update_bits_async(arizona->regmap, | 99 | regmap_update_bits_async(arizona->regmap, |
121 | ARIZONA_OUTPUT_ENABLES_1, | 100 | ARIZONA_OUTPUT_ENABLES_1, |
122 | 1 << w->shift, 1 << w->shift); | 101 | 1 << w->shift, 1 << w->shift); |
123 | |||
124 | if (priv->spk_ena_pending) { | ||
125 | msleep(75); | ||
126 | regmap_write_async(arizona->regmap, 0x4f5, 0xda); | ||
127 | priv->spk_ena_pending = false; | ||
128 | priv->spk_ena++; | ||
129 | } | ||
130 | break; | 102 | break; |
131 | case SND_SOC_DAPM_PRE_PMD: | 103 | case SND_SOC_DAPM_PRE_PMD: |
132 | if (manual_ena) { | ||
133 | priv->spk_ena--; | ||
134 | if (!priv->spk_ena) | ||
135 | regmap_write_async(arizona->regmap, | ||
136 | 0x4f5, 0x25a); | ||
137 | } | ||
138 | |||
139 | regmap_update_bits_async(arizona->regmap, | 104 | regmap_update_bits_async(arizona->regmap, |
140 | ARIZONA_OUTPUT_ENABLES_1, | 105 | ARIZONA_OUTPUT_ENABLES_1, |
141 | 1 << w->shift, 0); | 106 | 1 << w->shift, 0); |
142 | break; | 107 | break; |
143 | case SND_SOC_DAPM_POST_PMD: | ||
144 | if (manual_ena) { | ||
145 | if (!priv->spk_ena) | ||
146 | regmap_write_async(arizona->regmap, | ||
147 | 0x4f5, 0x0da); | ||
148 | } | ||
149 | break; | ||
150 | default: | 108 | default: |
151 | break; | 109 | break; |
152 | } | 110 | } |
@@ -324,6 +282,17 @@ int arizona_init_gpio(struct snd_soc_codec *codec) | |||
324 | } | 282 | } |
325 | EXPORT_SYMBOL_GPL(arizona_init_gpio); | 283 | EXPORT_SYMBOL_GPL(arizona_init_gpio); |
326 | 284 | ||
285 | int arizona_init_notifiers(struct snd_soc_codec *codec) | ||
286 | { | ||
287 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
288 | struct arizona *arizona = priv->arizona; | ||
289 | |||
290 | BLOCKING_INIT_NOTIFIER_HEAD(&arizona->notifier); | ||
291 | |||
292 | return 0; | ||
293 | } | ||
294 | EXPORT_SYMBOL_GPL(arizona_init_notifiers); | ||
295 | |||
327 | const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | 296 | const char * const arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { |
328 | "None", | 297 | "None", |
329 | "Tone Generator 1", | 298 | "Tone Generator 1", |
@@ -619,7 +588,7 @@ const struct soc_enum arizona_asrc_rate1 = | |||
619 | arizona_rate_text, arizona_rate_val); | 588 | arizona_rate_text, arizona_rate_val); |
620 | EXPORT_SYMBOL_GPL(arizona_asrc_rate1); | 589 | EXPORT_SYMBOL_GPL(arizona_asrc_rate1); |
621 | 590 | ||
622 | static const char *arizona_vol_ramp_text[] = { | 591 | static const char * const arizona_vol_ramp_text[] = { |
623 | "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", | 592 | "0ms/6dB", "0.5ms/6dB", "1ms/6dB", "2ms/6dB", "4ms/6dB", "8ms/6dB", |
624 | "15ms/6dB", "30ms/6dB", | 593 | "15ms/6dB", "30ms/6dB", |
625 | }; | 594 | }; |
@@ -648,7 +617,7 @@ SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp, | |||
648 | arizona_vol_ramp_text); | 617 | arizona_vol_ramp_text); |
649 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); | 618 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); |
650 | 619 | ||
651 | static const char *arizona_lhpf_mode_text[] = { | 620 | static const char * const arizona_lhpf_mode_text[] = { |
652 | "Low-pass", "High-pass" | 621 | "Low-pass", "High-pass" |
653 | }; | 622 | }; |
654 | 623 | ||
@@ -676,7 +645,7 @@ SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode, | |||
676 | arizona_lhpf_mode_text); | 645 | arizona_lhpf_mode_text); |
677 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); | 646 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); |
678 | 647 | ||
679 | static const char *arizona_ng_hold_text[] = { | 648 | static const char * const arizona_ng_hold_text[] = { |
680 | "30ms", "120ms", "250ms", "500ms", | 649 | "30ms", "120ms", "250ms", "500ms", |
681 | }; | 650 | }; |
682 | 651 | ||
@@ -810,6 +779,14 @@ const struct soc_enum arizona_output_anc_src[] = { | |||
810 | }; | 779 | }; |
811 | EXPORT_SYMBOL_GPL(arizona_output_anc_src); | 780 | EXPORT_SYMBOL_GPL(arizona_output_anc_src); |
812 | 781 | ||
782 | const struct snd_kcontrol_new arizona_voice_trigger_switch[] = { | ||
783 | SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0), | ||
784 | SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 1, 1, 0), | ||
785 | SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 2, 1, 0), | ||
786 | SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 3, 1, 0), | ||
787 | }; | ||
788 | EXPORT_SYMBOL_GPL(arizona_voice_trigger_switch); | ||
789 | |||
813 | static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) | 790 | static void arizona_in_set_vu(struct snd_soc_codec *codec, int ena) |
814 | { | 791 | { |
815 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | 792 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); |
@@ -2573,6 +2550,30 @@ int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, | |||
2573 | } | 2550 | } |
2574 | EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); | 2551 | EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); |
2575 | 2552 | ||
2553 | int arizona_register_notifier(struct snd_soc_codec *codec, | ||
2554 | struct notifier_block *nb, | ||
2555 | int (*notify)(struct notifier_block *nb, | ||
2556 | unsigned long action, void *data)) | ||
2557 | { | ||
2558 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
2559 | struct arizona *arizona = priv->arizona; | ||
2560 | |||
2561 | nb->notifier_call = notify; | ||
2562 | |||
2563 | return blocking_notifier_chain_register(&arizona->notifier, nb); | ||
2564 | } | ||
2565 | EXPORT_SYMBOL_GPL(arizona_register_notifier); | ||
2566 | |||
2567 | int arizona_unregister_notifier(struct snd_soc_codec *codec, | ||
2568 | struct notifier_block *nb) | ||
2569 | { | ||
2570 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
2571 | struct arizona *arizona = priv->arizona; | ||
2572 | |||
2573 | return blocking_notifier_chain_unregister(&arizona->notifier, nb); | ||
2574 | } | ||
2575 | EXPORT_SYMBOL_GPL(arizona_unregister_notifier); | ||
2576 | |||
2576 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); | 2577 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); |
2577 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 2578 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
2578 | MODULE_LICENSE("GPL"); | 2579 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index ce0531b8c632..69da1ef3a17c 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h | |||
@@ -63,6 +63,9 @@ | |||
63 | #define ARIZONA_DVFS_SR1_RQ 0x001 | 63 | #define ARIZONA_DVFS_SR1_RQ 0x001 |
64 | #define ARIZONA_DVFS_ADSP1_RQ 0x100 | 64 | #define ARIZONA_DVFS_ADSP1_RQ 0x100 |
65 | 65 | ||
66 | /* Notifier events */ | ||
67 | #define ARIZONA_NOTIFY_VOICE_TRIGGER 0x1 | ||
68 | |||
66 | struct arizona; | 69 | struct arizona; |
67 | struct wm_adsp; | 70 | struct wm_adsp; |
68 | 71 | ||
@@ -87,14 +90,15 @@ struct arizona_priv { | |||
87 | unsigned int out_down_pending; | 90 | unsigned int out_down_pending; |
88 | unsigned int out_down_delay; | 91 | unsigned int out_down_delay; |
89 | 92 | ||
90 | unsigned int spk_ena:2; | ||
91 | unsigned int spk_ena_pending:1; | ||
92 | |||
93 | unsigned int dvfs_reqs; | 93 | unsigned int dvfs_reqs; |
94 | struct mutex dvfs_lock; | 94 | struct mutex dvfs_lock; |
95 | bool dvfs_cached; | 95 | bool dvfs_cached; |
96 | }; | 96 | }; |
97 | 97 | ||
98 | struct arizona_voice_trigger_info { | ||
99 | int core; | ||
100 | }; | ||
101 | |||
98 | #define ARIZONA_NUM_MIXER_INPUTS 104 | 102 | #define ARIZONA_NUM_MIXER_INPUTS 104 |
99 | 103 | ||
100 | extern const unsigned int arizona_mixer_tlv[]; | 104 | extern const unsigned int arizona_mixer_tlv[]; |
@@ -248,6 +252,8 @@ extern const struct soc_enum arizona_anc_input_src[]; | |||
248 | extern const struct soc_enum arizona_anc_ng_enum; | 252 | extern const struct soc_enum arizona_anc_ng_enum; |
249 | extern const struct soc_enum arizona_output_anc_src[]; | 253 | extern const struct soc_enum arizona_output_anc_src[]; |
250 | 254 | ||
255 | extern const struct snd_kcontrol_new arizona_voice_trigger_switch[]; | ||
256 | |||
251 | extern int arizona_in_ev(struct snd_soc_dapm_widget *w, | 257 | extern int arizona_in_ev(struct snd_soc_dapm_widget *w, |
252 | struct snd_kcontrol *kcontrol, | 258 | struct snd_kcontrol *kcontrol, |
253 | int event); | 259 | int event); |
@@ -306,6 +312,7 @@ extern int arizona_set_fll(struct arizona_fll *fll, int source, | |||
306 | extern int arizona_init_spk(struct snd_soc_codec *codec); | 312 | extern int arizona_init_spk(struct snd_soc_codec *codec); |
307 | extern int arizona_init_gpio(struct snd_soc_codec *codec); | 313 | extern int arizona_init_gpio(struct snd_soc_codec *codec); |
308 | extern int arizona_init_mono(struct snd_soc_codec *codec); | 314 | extern int arizona_init_mono(struct snd_soc_codec *codec); |
315 | extern int arizona_init_notifiers(struct snd_soc_codec *codec); | ||
309 | 316 | ||
310 | extern int arizona_free_spk(struct snd_soc_codec *codec); | 317 | extern int arizona_free_spk(struct snd_soc_codec *codec); |
311 | 318 | ||
@@ -317,4 +324,13 @@ int arizona_set_output_mode(struct snd_soc_codec *codec, int output, | |||
317 | extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); | 324 | extern bool arizona_input_analog(struct snd_soc_codec *codec, int shift); |
318 | 325 | ||
319 | extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); | 326 | extern const char *arizona_sample_rate_val_to_name(unsigned int rate_val); |
327 | |||
328 | extern int arizona_register_notifier(struct snd_soc_codec *codec, | ||
329 | struct notifier_block *nb, | ||
330 | int (*notify)(struct notifier_block *nb, | ||
331 | unsigned long action, | ||
332 | void *data)); | ||
333 | extern int arizona_unregister_notifier(struct snd_soc_codec *codec, | ||
334 | struct notifier_block *nb); | ||
335 | |||
320 | #endif | 336 | #endif |
diff --git a/sound/soc/codecs/bt-sco.c b/sound/soc/codecs/bt-sco.c index b084ad113e96..2a8d0ee141d4 100644 --- a/sound/soc/codecs/bt-sco.c +++ b/sound/soc/codecs/bt-sco.c | |||
@@ -25,22 +25,41 @@ static const struct snd_soc_dapm_route bt_sco_routes[] = { | |||
25 | { "TX", NULL, "Playback" }, | 25 | { "TX", NULL, "Playback" }, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | static struct snd_soc_dai_driver bt_sco_dai = { | 28 | static struct snd_soc_dai_driver bt_sco_dai[] = { |
29 | .name = "bt-sco-pcm", | 29 | { |
30 | .playback = { | 30 | .name = "bt-sco-pcm", |
31 | .stream_name = "Playback", | 31 | .playback = { |
32 | .channels_min = 1, | 32 | .stream_name = "Playback", |
33 | .channels_max = 1, | 33 | .channels_min = 1, |
34 | .rates = SNDRV_PCM_RATE_8000, | 34 | .channels_max = 1, |
35 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 35 | .rates = SNDRV_PCM_RATE_8000, |
36 | }, | 36 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
37 | .capture = { | 37 | }, |
38 | .stream_name = "Capture", | 38 | .capture = { |
39 | .channels_min = 1, | 39 | .stream_name = "Capture", |
40 | .channels_max = 1, | 40 | .channels_min = 1, |
41 | .rates = SNDRV_PCM_RATE_8000, | 41 | .channels_max = 1, |
42 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 42 | .rates = SNDRV_PCM_RATE_8000, |
43 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
44 | }, | ||
43 | }, | 45 | }, |
46 | { | ||
47 | .name = "bt-sco-pcm-wb", | ||
48 | .playback = { | ||
49 | .stream_name = "Playback", | ||
50 | .channels_min = 1, | ||
51 | .channels_max = 1, | ||
52 | .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, | ||
53 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
54 | }, | ||
55 | .capture = { | ||
56 | .stream_name = "Capture", | ||
57 | .channels_min = 1, | ||
58 | .channels_max = 1, | ||
59 | .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000, | ||
60 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
61 | }, | ||
62 | } | ||
44 | }; | 63 | }; |
45 | 64 | ||
46 | static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { | 65 | static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { |
@@ -53,7 +72,7 @@ static struct snd_soc_codec_driver soc_codec_dev_bt_sco = { | |||
53 | static int bt_sco_probe(struct platform_device *pdev) | 72 | static int bt_sco_probe(struct platform_device *pdev) |
54 | { | 73 | { |
55 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco, | 74 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_bt_sco, |
56 | &bt_sco_dai, 1); | 75 | bt_sco_dai, ARRAY_SIZE(bt_sco_dai)); |
57 | } | 76 | } |
58 | 77 | ||
59 | static int bt_sco_remove(struct platform_device *pdev) | 78 | static int bt_sco_remove(struct platform_device *pdev) |
@@ -77,6 +96,7 @@ MODULE_DEVICE_TABLE(platform, bt_sco_driver_ids); | |||
77 | #if defined(CONFIG_OF) | 96 | #if defined(CONFIG_OF) |
78 | static const struct of_device_id bt_sco_codec_of_match[] = { | 97 | static const struct of_device_id bt_sco_codec_of_match[] = { |
79 | { .compatible = "delta,dfbmcs320", }, | 98 | { .compatible = "delta,dfbmcs320", }, |
99 | { .compatible = "linux,bt-sco", }, | ||
80 | {}, | 100 | {}, |
81 | }; | 101 | }; |
82 | MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match); | 102 | MODULE_DEVICE_TABLE(of, bt_sco_codec_of_match); |
diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c new file mode 100644 index 000000000000..6f9c1addcd7f --- /dev/null +++ b/sound/soc/codecs/cs35l33.c | |||
@@ -0,0 +1,1303 @@ | |||
1 | /* | ||
2 | * cs35l33.c -- CS35L33 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2016 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Paul Handrigan <paul.handrigan@cirrus.com> | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/workqueue.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/soc-dapm.h> | ||
27 | #include <sound/initval.h> | ||
28 | #include <sound/tlv.h> | ||
29 | #include <linux/gpio.h> | ||
30 | #include <linux/gpio/consumer.h> | ||
31 | #include <sound/cs35l33.h> | ||
32 | #include <linux/pm_runtime.h> | ||
33 | #include <linux/regulator/consumer.h> | ||
34 | #include <linux/regulator/machine.h> | ||
35 | #include <linux/of_gpio.h> | ||
36 | #include <linux/of.h> | ||
37 | #include <linux/of_device.h> | ||
38 | #include <linux/of_irq.h> | ||
39 | |||
40 | #include "cs35l33.h" | ||
41 | |||
42 | #define CS35L33_BOOT_DELAY 50 | ||
43 | |||
44 | struct cs35l33_private { | ||
45 | struct snd_soc_codec *codec; | ||
46 | struct cs35l33_pdata pdata; | ||
47 | struct regmap *regmap; | ||
48 | struct gpio_desc *reset_gpio; | ||
49 | bool amp_cal; | ||
50 | int mclk_int; | ||
51 | struct regulator_bulk_data core_supplies[2]; | ||
52 | int num_core_supplies; | ||
53 | bool is_tdm_mode; | ||
54 | bool enable_soft_ramp; | ||
55 | }; | ||
56 | |||
57 | static const struct reg_default cs35l33_reg[] = { | ||
58 | {CS35L33_PWRCTL1, 0x85}, | ||
59 | {CS35L33_PWRCTL2, 0xFE}, | ||
60 | {CS35L33_CLK_CTL, 0x0C}, | ||
61 | {CS35L33_BST_PEAK_CTL, 0x90}, | ||
62 | {CS35L33_PROTECT_CTL, 0x55}, | ||
63 | {CS35L33_BST_CTL1, 0x00}, | ||
64 | {CS35L33_BST_CTL2, 0x01}, | ||
65 | {CS35L33_ADSP_CTL, 0x00}, | ||
66 | {CS35L33_ADC_CTL, 0xC8}, | ||
67 | {CS35L33_DAC_CTL, 0x14}, | ||
68 | {CS35L33_DIG_VOL_CTL, 0x00}, | ||
69 | {CS35L33_CLASSD_CTL, 0x04}, | ||
70 | {CS35L33_AMP_CTL, 0x90}, | ||
71 | {CS35L33_INT_MASK_1, 0xFF}, | ||
72 | {CS35L33_INT_MASK_2, 0xFF}, | ||
73 | {CS35L33_DIAG_LOCK, 0x00}, | ||
74 | {CS35L33_DIAG_CTRL_1, 0x40}, | ||
75 | {CS35L33_DIAG_CTRL_2, 0x00}, | ||
76 | {CS35L33_HG_MEMLDO_CTL, 0x62}, | ||
77 | {CS35L33_HG_REL_RATE, 0x03}, | ||
78 | {CS35L33_LDO_DEL, 0x12}, | ||
79 | {CS35L33_HG_HEAD, 0x0A}, | ||
80 | {CS35L33_HG_EN, 0x05}, | ||
81 | {CS35L33_TX_VMON, 0x00}, | ||
82 | {CS35L33_TX_IMON, 0x03}, | ||
83 | {CS35L33_TX_VPMON, 0x02}, | ||
84 | {CS35L33_TX_VBSTMON, 0x05}, | ||
85 | {CS35L33_TX_FLAG, 0x06}, | ||
86 | {CS35L33_TX_EN1, 0x00}, | ||
87 | {CS35L33_TX_EN2, 0x00}, | ||
88 | {CS35L33_TX_EN3, 0x00}, | ||
89 | {CS35L33_TX_EN4, 0x00}, | ||
90 | {CS35L33_RX_AUD, 0x40}, | ||
91 | {CS35L33_RX_SPLY, 0x03}, | ||
92 | {CS35L33_RX_ALIVE, 0x04}, | ||
93 | {CS35L33_BST_CTL4, 0x63}, | ||
94 | }; | ||
95 | |||
96 | static const struct reg_sequence cs35l33_patch[] = { | ||
97 | { 0x00, 0x99, 0 }, | ||
98 | { 0x59, 0x02, 0 }, | ||
99 | { 0x52, 0x30, 0 }, | ||
100 | { 0x39, 0x45, 0 }, | ||
101 | { 0x57, 0x30, 0 }, | ||
102 | { 0x2C, 0x68, 0 }, | ||
103 | { 0x00, 0x00, 0 }, | ||
104 | }; | ||
105 | |||
106 | static bool cs35l33_volatile_register(struct device *dev, unsigned int reg) | ||
107 | { | ||
108 | switch (reg) { | ||
109 | case CS35L33_DEVID_AB: | ||
110 | case CS35L33_DEVID_CD: | ||
111 | case CS35L33_DEVID_E: | ||
112 | case CS35L33_REV_ID: | ||
113 | case CS35L33_INT_STATUS_1: | ||
114 | case CS35L33_INT_STATUS_2: | ||
115 | case CS35L33_HG_STATUS: | ||
116 | return true; | ||
117 | default: | ||
118 | return false; | ||
119 | } | ||
120 | } | ||
121 | |||
122 | static bool cs35l33_writeable_register(struct device *dev, unsigned int reg) | ||
123 | { | ||
124 | switch (reg) { | ||
125 | /* these are read only registers */ | ||
126 | case CS35L33_DEVID_AB: | ||
127 | case CS35L33_DEVID_CD: | ||
128 | case CS35L33_DEVID_E: | ||
129 | case CS35L33_REV_ID: | ||
130 | case CS35L33_INT_STATUS_1: | ||
131 | case CS35L33_INT_STATUS_2: | ||
132 | case CS35L33_HG_STATUS: | ||
133 | return false; | ||
134 | default: | ||
135 | return true; | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static bool cs35l33_readable_register(struct device *dev, unsigned int reg) | ||
140 | { | ||
141 | switch (reg) { | ||
142 | case CS35L33_DEVID_AB: | ||
143 | case CS35L33_DEVID_CD: | ||
144 | case CS35L33_DEVID_E: | ||
145 | case CS35L33_REV_ID: | ||
146 | case CS35L33_PWRCTL1: | ||
147 | case CS35L33_PWRCTL2: | ||
148 | case CS35L33_CLK_CTL: | ||
149 | case CS35L33_BST_PEAK_CTL: | ||
150 | case CS35L33_PROTECT_CTL: | ||
151 | case CS35L33_BST_CTL1: | ||
152 | case CS35L33_BST_CTL2: | ||
153 | case CS35L33_ADSP_CTL: | ||
154 | case CS35L33_ADC_CTL: | ||
155 | case CS35L33_DAC_CTL: | ||
156 | case CS35L33_DIG_VOL_CTL: | ||
157 | case CS35L33_CLASSD_CTL: | ||
158 | case CS35L33_AMP_CTL: | ||
159 | case CS35L33_INT_MASK_1: | ||
160 | case CS35L33_INT_MASK_2: | ||
161 | case CS35L33_INT_STATUS_1: | ||
162 | case CS35L33_INT_STATUS_2: | ||
163 | case CS35L33_DIAG_LOCK: | ||
164 | case CS35L33_DIAG_CTRL_1: | ||
165 | case CS35L33_DIAG_CTRL_2: | ||
166 | case CS35L33_HG_MEMLDO_CTL: | ||
167 | case CS35L33_HG_REL_RATE: | ||
168 | case CS35L33_LDO_DEL: | ||
169 | case CS35L33_HG_HEAD: | ||
170 | case CS35L33_HG_EN: | ||
171 | case CS35L33_TX_VMON: | ||
172 | case CS35L33_TX_IMON: | ||
173 | case CS35L33_TX_VPMON: | ||
174 | case CS35L33_TX_VBSTMON: | ||
175 | case CS35L33_TX_FLAG: | ||
176 | case CS35L33_TX_EN1: | ||
177 | case CS35L33_TX_EN2: | ||
178 | case CS35L33_TX_EN3: | ||
179 | case CS35L33_TX_EN4: | ||
180 | case CS35L33_RX_AUD: | ||
181 | case CS35L33_RX_SPLY: | ||
182 | case CS35L33_RX_ALIVE: | ||
183 | case CS35L33_BST_CTL4: | ||
184 | return true; | ||
185 | default: | ||
186 | return false; | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 100, 0); | ||
191 | static DECLARE_TLV_DB_SCALE(dac_tlv, -10200, 50, 0); | ||
192 | |||
193 | static const struct snd_kcontrol_new cs35l33_snd_controls[] = { | ||
194 | |||
195 | SOC_SINGLE_TLV("SPK Amp Volume", CS35L33_AMP_CTL, | ||
196 | 4, 0x09, 0, classd_ctl_tlv), | ||
197 | SOC_SINGLE_SX_TLV("DAC Volume", CS35L33_DIG_VOL_CTL, | ||
198 | 0, 0x34, 0xE4, dac_tlv), | ||
199 | }; | ||
200 | |||
201 | static int cs35l33_spkrdrv_event(struct snd_soc_dapm_widget *w, | ||
202 | struct snd_kcontrol *kcontrol, int event) | ||
203 | { | ||
204 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
205 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
206 | |||
207 | switch (event) { | ||
208 | case SND_SOC_DAPM_POST_PMU: | ||
209 | if (!priv->amp_cal) { | ||
210 | usleep_range(8000, 9000); | ||
211 | priv->amp_cal = true; | ||
212 | regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL, | ||
213 | CS35L33_AMP_CAL, 0); | ||
214 | dev_dbg(codec->dev, "Amp calibration done\n"); | ||
215 | } | ||
216 | dev_dbg(codec->dev, "Amp turned on\n"); | ||
217 | break; | ||
218 | case SND_SOC_DAPM_POST_PMD: | ||
219 | dev_dbg(codec->dev, "Amp turned off\n"); | ||
220 | break; | ||
221 | default: | ||
222 | dev_err(codec->dev, "Invalid event = 0x%x\n", event); | ||
223 | break; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int cs35l33_sdin_event(struct snd_soc_dapm_widget *w, | ||
230 | struct snd_kcontrol *kcontrol, int event) | ||
231 | { | ||
232 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
233 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
234 | unsigned int val; | ||
235 | |||
236 | switch (event) { | ||
237 | case SND_SOC_DAPM_PRE_PMU: | ||
238 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, | ||
239 | CS35L33_PDN_BST, 0); | ||
240 | val = priv->is_tdm_mode ? 0 : CS35L33_PDN_TDM; | ||
241 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, | ||
242 | CS35L33_PDN_TDM, val); | ||
243 | dev_dbg(codec->dev, "BST turned on\n"); | ||
244 | break; | ||
245 | case SND_SOC_DAPM_POST_PMU: | ||
246 | dev_dbg(codec->dev, "SDIN turned on\n"); | ||
247 | if (!priv->amp_cal) { | ||
248 | regmap_update_bits(priv->regmap, CS35L33_CLASSD_CTL, | ||
249 | CS35L33_AMP_CAL, CS35L33_AMP_CAL); | ||
250 | dev_dbg(codec->dev, "Amp calibration started\n"); | ||
251 | usleep_range(10000, 11000); | ||
252 | } | ||
253 | break; | ||
254 | case SND_SOC_DAPM_POST_PMD: | ||
255 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, | ||
256 | CS35L33_PDN_TDM, CS35L33_PDN_TDM); | ||
257 | usleep_range(4000, 4100); | ||
258 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, | ||
259 | CS35L33_PDN_BST, CS35L33_PDN_BST); | ||
260 | dev_dbg(codec->dev, "BST and SDIN turned off\n"); | ||
261 | break; | ||
262 | default: | ||
263 | dev_err(codec->dev, "Invalid event = 0x%x\n", event); | ||
264 | |||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int cs35l33_sdout_event(struct snd_soc_dapm_widget *w, | ||
271 | struct snd_kcontrol *kcontrol, int event) | ||
272 | { | ||
273 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
274 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
275 | unsigned int mask = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM; | ||
276 | unsigned int mask2 = CS35L33_SDOUT_3ST_TDM; | ||
277 | unsigned int val, val2; | ||
278 | |||
279 | switch (event) { | ||
280 | case SND_SOC_DAPM_PRE_PMU: | ||
281 | if (priv->is_tdm_mode) { | ||
282 | /* set sdout_3st_i2s and reset pdn_tdm */ | ||
283 | val = CS35L33_SDOUT_3ST_I2S; | ||
284 | /* reset sdout_3st_tdm */ | ||
285 | val2 = 0; | ||
286 | } else { | ||
287 | /* reset sdout_3st_i2s and set pdn_tdm */ | ||
288 | val = CS35L33_PDN_TDM; | ||
289 | /* set sdout_3st_tdm */ | ||
290 | val2 = CS35L33_SDOUT_3ST_TDM; | ||
291 | } | ||
292 | dev_dbg(codec->dev, "SDOUT turned on\n"); | ||
293 | break; | ||
294 | case SND_SOC_DAPM_PRE_PMD: | ||
295 | val = CS35L33_SDOUT_3ST_I2S | CS35L33_PDN_TDM; | ||
296 | val2 = CS35L33_SDOUT_3ST_TDM; | ||
297 | dev_dbg(codec->dev, "SDOUT turned off\n"); | ||
298 | break; | ||
299 | default: | ||
300 | dev_err(codec->dev, "Invalid event = 0x%x\n", event); | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, | ||
305 | mask, val); | ||
306 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
307 | mask2, val2); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static const struct snd_soc_dapm_widget cs35l33_dapm_widgets[] = { | ||
313 | |||
314 | SND_SOC_DAPM_OUTPUT("SPK"), | ||
315 | SND_SOC_DAPM_OUT_DRV_E("SPKDRV", CS35L33_PWRCTL1, 7, 1, NULL, 0, | ||
316 | cs35l33_spkrdrv_event, | ||
317 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
318 | SND_SOC_DAPM_AIF_IN_E("SDIN", NULL, 0, CS35L33_PWRCTL2, | ||
319 | 2, 1, cs35l33_sdin_event, SND_SOC_DAPM_PRE_PMU | | ||
320 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
321 | |||
322 | SND_SOC_DAPM_INPUT("MON"), | ||
323 | |||
324 | SND_SOC_DAPM_ADC("VMON", NULL, | ||
325 | CS35L33_PWRCTL2, CS35L33_PDN_VMON_SHIFT, 1), | ||
326 | SND_SOC_DAPM_ADC("IMON", NULL, | ||
327 | CS35L33_PWRCTL2, CS35L33_PDN_IMON_SHIFT, 1), | ||
328 | SND_SOC_DAPM_ADC("VPMON", NULL, | ||
329 | CS35L33_PWRCTL2, CS35L33_PDN_VPMON_SHIFT, 1), | ||
330 | SND_SOC_DAPM_ADC("VBSTMON", NULL, | ||
331 | CS35L33_PWRCTL2, CS35L33_PDN_VBSTMON_SHIFT, 1), | ||
332 | |||
333 | SND_SOC_DAPM_AIF_OUT_E("SDOUT", NULL, 0, SND_SOC_NOPM, 0, 0, | ||
334 | cs35l33_sdout_event, SND_SOC_DAPM_PRE_PMU | | ||
335 | SND_SOC_DAPM_PRE_PMD), | ||
336 | }; | ||
337 | |||
338 | static const struct snd_soc_dapm_route cs35l33_audio_map[] = { | ||
339 | {"SDIN", NULL, "CS35L33 Playback"}, | ||
340 | {"SPKDRV", NULL, "SDIN"}, | ||
341 | {"SPK", NULL, "SPKDRV"}, | ||
342 | |||
343 | {"VMON", NULL, "MON"}, | ||
344 | {"IMON", NULL, "MON"}, | ||
345 | |||
346 | {"SDOUT", NULL, "VMON"}, | ||
347 | {"SDOUT", NULL, "IMON"}, | ||
348 | {"CS35L33 Capture", NULL, "SDOUT"}, | ||
349 | }; | ||
350 | |||
351 | static const struct snd_soc_dapm_route cs35l33_vphg_auto_route[] = { | ||
352 | {"SPKDRV", NULL, "VPMON"}, | ||
353 | {"VPMON", NULL, "CS35L33 Playback"}, | ||
354 | }; | ||
355 | |||
356 | static const struct snd_soc_dapm_route cs35l33_vp_vbst_mon_route[] = { | ||
357 | {"SDOUT", NULL, "VPMON"}, | ||
358 | {"VPMON", NULL, "MON"}, | ||
359 | {"SDOUT", NULL, "VBSTMON"}, | ||
360 | {"VBSTMON", NULL, "MON"}, | ||
361 | }; | ||
362 | |||
363 | static int cs35l33_set_bias_level(struct snd_soc_codec *codec, | ||
364 | enum snd_soc_bias_level level) | ||
365 | { | ||
366 | unsigned int val; | ||
367 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
368 | |||
369 | switch (level) { | ||
370 | case SND_SOC_BIAS_ON: | ||
371 | break; | ||
372 | case SND_SOC_BIAS_PREPARE: | ||
373 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, | ||
374 | CS35L33_PDN_ALL, 0); | ||
375 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
376 | CS35L33_MCLKDIS, 0); | ||
377 | break; | ||
378 | case SND_SOC_BIAS_STANDBY: | ||
379 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL1, | ||
380 | CS35L33_PDN_ALL, CS35L33_PDN_ALL); | ||
381 | regmap_read(priv->regmap, CS35L33_INT_STATUS_2, &val); | ||
382 | usleep_range(1000, 1100); | ||
383 | if (val & CS35L33_PDN_DONE) | ||
384 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
385 | CS35L33_MCLKDIS, CS35L33_MCLKDIS); | ||
386 | break; | ||
387 | case SND_SOC_BIAS_OFF: | ||
388 | break; | ||
389 | default: | ||
390 | return -EINVAL; | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | struct cs35l33_mclk_div { | ||
397 | int mclk; | ||
398 | int srate; | ||
399 | u8 adsp_rate; | ||
400 | u8 int_fs_ratio; | ||
401 | }; | ||
402 | |||
403 | static const struct cs35l33_mclk_div cs35l33_mclk_coeffs[] = { | ||
404 | /* MCLK, Sample Rate, adsp_rate, int_fs_ratio */ | ||
405 | {5644800, 11025, 0x4, CS35L33_INT_FS_RATE}, | ||
406 | {5644800, 22050, 0x8, CS35L33_INT_FS_RATE}, | ||
407 | {5644800, 44100, 0xC, CS35L33_INT_FS_RATE}, | ||
408 | |||
409 | {6000000, 8000, 0x1, 0}, | ||
410 | {6000000, 11025, 0x2, 0}, | ||
411 | {6000000, 11029, 0x3, 0}, | ||
412 | {6000000, 12000, 0x4, 0}, | ||
413 | {6000000, 16000, 0x5, 0}, | ||
414 | {6000000, 22050, 0x6, 0}, | ||
415 | {6000000, 22059, 0x7, 0}, | ||
416 | {6000000, 24000, 0x8, 0}, | ||
417 | {6000000, 32000, 0x9, 0}, | ||
418 | {6000000, 44100, 0xA, 0}, | ||
419 | {6000000, 44118, 0xB, 0}, | ||
420 | {6000000, 48000, 0xC, 0}, | ||
421 | |||
422 | {6144000, 8000, 0x1, CS35L33_INT_FS_RATE}, | ||
423 | {6144000, 12000, 0x4, CS35L33_INT_FS_RATE}, | ||
424 | {6144000, 16000, 0x5, CS35L33_INT_FS_RATE}, | ||
425 | {6144000, 24000, 0x8, CS35L33_INT_FS_RATE}, | ||
426 | {6144000, 32000, 0x9, CS35L33_INT_FS_RATE}, | ||
427 | {6144000, 48000, 0xC, CS35L33_INT_FS_RATE}, | ||
428 | }; | ||
429 | |||
430 | static int cs35l33_get_mclk_coeff(int mclk, int srate) | ||
431 | { | ||
432 | int i; | ||
433 | |||
434 | for (i = 0; i < ARRAY_SIZE(cs35l33_mclk_coeffs); i++) { | ||
435 | if (cs35l33_mclk_coeffs[i].mclk == mclk && | ||
436 | cs35l33_mclk_coeffs[i].srate == srate) | ||
437 | return i; | ||
438 | } | ||
439 | return -EINVAL; | ||
440 | } | ||
441 | |||
442 | static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
443 | { | ||
444 | struct snd_soc_codec *codec = codec_dai->codec; | ||
445 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
446 | |||
447 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
448 | case SND_SOC_DAIFMT_CBM_CFM: | ||
449 | regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, | ||
450 | CS35L33_MS_MASK, CS35L33_MS_MASK); | ||
451 | dev_dbg(codec->dev, "Audio port in master mode\n"); | ||
452 | break; | ||
453 | case SND_SOC_DAIFMT_CBS_CFS: | ||
454 | regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, | ||
455 | CS35L33_MS_MASK, 0); | ||
456 | dev_dbg(codec->dev, "Audio port in slave mode\n"); | ||
457 | break; | ||
458 | default: | ||
459 | return -EINVAL; | ||
460 | } | ||
461 | |||
462 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
463 | case SND_SOC_DAIFMT_DSP_A: | ||
464 | /* | ||
465 | * tdm mode in cs35l33 resembles dsp-a mode very | ||
466 | * closely, it is dsp-a with fsync shifted left by half bclk | ||
467 | */ | ||
468 | priv->is_tdm_mode = true; | ||
469 | dev_dbg(codec->dev, "Audio port in TDM mode\n"); | ||
470 | break; | ||
471 | case SND_SOC_DAIFMT_I2S: | ||
472 | priv->is_tdm_mode = false; | ||
473 | dev_dbg(codec->dev, "Audio port in I2S mode\n"); | ||
474 | break; | ||
475 | default: | ||
476 | return -EINVAL; | ||
477 | } | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static int cs35l33_pcm_hw_params(struct snd_pcm_substream *substream, | ||
483 | struct snd_pcm_hw_params *params, | ||
484 | struct snd_soc_dai *dai) | ||
485 | { | ||
486 | struct snd_soc_codec *codec = dai->codec; | ||
487 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
488 | int sample_size = params_width(params); | ||
489 | int coeff = cs35l33_get_mclk_coeff(priv->mclk_int, params_rate(params)); | ||
490 | |||
491 | if (coeff < 0) | ||
492 | return coeff; | ||
493 | |||
494 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
495 | CS35L33_ADSP_FS | CS35L33_INT_FS_RATE, | ||
496 | cs35l33_mclk_coeffs[coeff].int_fs_ratio | ||
497 | | cs35l33_mclk_coeffs[coeff].adsp_rate); | ||
498 | |||
499 | if (priv->is_tdm_mode) { | ||
500 | sample_size = (sample_size / 8) - 1; | ||
501 | if (sample_size > 2) | ||
502 | sample_size = 2; | ||
503 | regmap_update_bits(priv->regmap, CS35L33_RX_AUD, | ||
504 | CS35L33_AUDIN_RX_DEPTH, | ||
505 | sample_size << CS35L33_AUDIN_RX_DEPTH_SHIFT); | ||
506 | } | ||
507 | |||
508 | dev_dbg(codec->dev, "sample rate=%d, bits per sample=%d\n", | ||
509 | params_rate(params), params_width(params)); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static const unsigned int cs35l33_src_rates[] = { | ||
515 | 8000, 11025, 11029, 12000, 16000, 22050, | ||
516 | 22059, 24000, 32000, 44100, 44118, 48000 | ||
517 | }; | ||
518 | |||
519 | static const struct snd_pcm_hw_constraint_list cs35l33_constraints = { | ||
520 | .count = ARRAY_SIZE(cs35l33_src_rates), | ||
521 | .list = cs35l33_src_rates, | ||
522 | }; | ||
523 | |||
524 | static int cs35l33_pcm_startup(struct snd_pcm_substream *substream, | ||
525 | struct snd_soc_dai *dai) | ||
526 | { | ||
527 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
528 | SNDRV_PCM_HW_PARAM_RATE, | ||
529 | &cs35l33_constraints); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int cs35l33_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
534 | { | ||
535 | struct snd_soc_codec *codec = dai->codec; | ||
536 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
537 | |||
538 | if (tristate) { | ||
539 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, | ||
540 | CS35L33_SDOUT_3ST_I2S, CS35L33_SDOUT_3ST_I2S); | ||
541 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
542 | CS35L33_SDOUT_3ST_TDM, CS35L33_SDOUT_3ST_TDM); | ||
543 | } else { | ||
544 | regmap_update_bits(priv->regmap, CS35L33_PWRCTL2, | ||
545 | CS35L33_SDOUT_3ST_I2S, 0); | ||
546 | regmap_update_bits(priv->regmap, CS35L33_CLK_CTL, | ||
547 | CS35L33_SDOUT_3ST_TDM, 0); | ||
548 | } | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | static int cs35l33_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
554 | unsigned int rx_mask, int slots, int slot_width) | ||
555 | { | ||
556 | struct snd_soc_codec *codec = dai->codec; | ||
557 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
558 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
559 | unsigned int reg, bit_pos, i; | ||
560 | int slot, slot_num; | ||
561 | |||
562 | if (slot_width != 8) | ||
563 | return -EINVAL; | ||
564 | |||
565 | /* scan rx_mask for aud slot */ | ||
566 | slot = ffs(rx_mask) - 1; | ||
567 | if (slot >= 0) { | ||
568 | regmap_update_bits(priv->regmap, CS35L33_RX_AUD, | ||
569 | CS35L33_X_LOC, slot); | ||
570 | dev_dbg(codec->dev, "Audio starts from slots %d", slot); | ||
571 | } | ||
572 | |||
573 | /* | ||
574 | * scan tx_mask: vmon(2 slots); imon (2 slots); | ||
575 | * vpmon (1 slot) vbstmon (1 slot) | ||
576 | */ | ||
577 | slot = ffs(tx_mask) - 1; | ||
578 | slot_num = 0; | ||
579 | |||
580 | for (i = 0; i < 2 ; i++) { | ||
581 | /* disable vpmon/vbstmon: enable later if set in tx_mask */ | ||
582 | regmap_update_bits(priv->regmap, CS35L33_TX_VPMON + i, | ||
583 | CS35L33_X_STATE | CS35L33_X_LOC, CS35L33_X_STATE | ||
584 | | CS35L33_X_LOC); | ||
585 | } | ||
586 | |||
587 | /* disconnect {vp,vbst}_mon routes: eanble later if set in tx_mask*/ | ||
588 | snd_soc_dapm_del_routes(dapm, cs35l33_vp_vbst_mon_route, | ||
589 | ARRAY_SIZE(cs35l33_vp_vbst_mon_route)); | ||
590 | |||
591 | while (slot >= 0) { | ||
592 | /* configure VMON_TX_LOC */ | ||
593 | if (slot_num == 0) { | ||
594 | regmap_update_bits(priv->regmap, CS35L33_TX_VMON, | ||
595 | CS35L33_X_STATE | CS35L33_X_LOC, slot); | ||
596 | dev_dbg(codec->dev, "VMON enabled in slots %d-%d", | ||
597 | slot, slot + 1); | ||
598 | } | ||
599 | |||
600 | /* configure IMON_TX_LOC */ | ||
601 | if (slot_num == 3) { | ||
602 | regmap_update_bits(priv->regmap, CS35L33_TX_IMON, | ||
603 | CS35L33_X_STATE | CS35L33_X_LOC, slot); | ||
604 | dev_dbg(codec->dev, "IMON enabled in slots %d-%d", | ||
605 | slot, slot + 1); | ||
606 | } | ||
607 | |||
608 | /* configure VPMON_TX_LOC */ | ||
609 | if (slot_num == 4) { | ||
610 | regmap_update_bits(priv->regmap, CS35L33_TX_VPMON, | ||
611 | CS35L33_X_STATE | CS35L33_X_LOC, slot); | ||
612 | snd_soc_dapm_add_routes(dapm, | ||
613 | &cs35l33_vp_vbst_mon_route[0], 2); | ||
614 | dev_dbg(codec->dev, "VPMON enabled in slots %d", slot); | ||
615 | } | ||
616 | |||
617 | /* configure VBSTMON_TX_LOC */ | ||
618 | if (slot_num == 5) { | ||
619 | regmap_update_bits(priv->regmap, CS35L33_TX_VBSTMON, | ||
620 | CS35L33_X_STATE | CS35L33_X_LOC, slot); | ||
621 | snd_soc_dapm_add_routes(dapm, | ||
622 | &cs35l33_vp_vbst_mon_route[2], 2); | ||
623 | dev_dbg(codec->dev, | ||
624 | "VBSTMON enabled in slots %d", slot); | ||
625 | } | ||
626 | |||
627 | /* Enable the relevant tx slot */ | ||
628 | reg = CS35L33_TX_EN4 - (slot/8); | ||
629 | bit_pos = slot - ((slot / 8) * (8)); | ||
630 | regmap_update_bits(priv->regmap, reg, | ||
631 | 1 << bit_pos, 1 << bit_pos); | ||
632 | |||
633 | tx_mask &= ~(1 << slot); | ||
634 | slot = ffs(tx_mask) - 1; | ||
635 | slot_num++; | ||
636 | } | ||
637 | |||
638 | return 0; | ||
639 | } | ||
640 | |||
641 | static int cs35l33_codec_set_sysclk(struct snd_soc_codec *codec, | ||
642 | int clk_id, int source, unsigned int freq, int dir) | ||
643 | { | ||
644 | struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec); | ||
645 | |||
646 | switch (freq) { | ||
647 | case CS35L33_MCLK_5644: | ||
648 | case CS35L33_MCLK_6: | ||
649 | case CS35L33_MCLK_6144: | ||
650 | regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, | ||
651 | CS35L33_MCLKDIV2, 0); | ||
652 | cs35l33->mclk_int = freq; | ||
653 | break; | ||
654 | case CS35L33_MCLK_11289: | ||
655 | case CS35L33_MCLK_12: | ||
656 | case CS35L33_MCLK_12288: | ||
657 | regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, | ||
658 | CS35L33_MCLKDIV2, CS35L33_MCLKDIV2); | ||
659 | cs35l33->mclk_int = freq/2; | ||
660 | break; | ||
661 | default: | ||
662 | cs35l33->mclk_int = 0; | ||
663 | return -EINVAL; | ||
664 | } | ||
665 | |||
666 | dev_dbg(codec->dev, "external mclk freq=%d, internal mclk freq=%d\n", | ||
667 | freq, cs35l33->mclk_int); | ||
668 | |||
669 | return 0; | ||
670 | } | ||
671 | |||
672 | static const struct snd_soc_dai_ops cs35l33_ops = { | ||
673 | .startup = cs35l33_pcm_startup, | ||
674 | .set_tristate = cs35l33_set_tristate, | ||
675 | .set_fmt = cs35l33_set_dai_fmt, | ||
676 | .hw_params = cs35l33_pcm_hw_params, | ||
677 | .set_tdm_slot = cs35l33_set_tdm_slot, | ||
678 | }; | ||
679 | |||
680 | static struct snd_soc_dai_driver cs35l33_dai = { | ||
681 | .name = "cs35l33-dai", | ||
682 | .id = 0, | ||
683 | .playback = { | ||
684 | .stream_name = "CS35L33 Playback", | ||
685 | .channels_min = 1, | ||
686 | .channels_max = 1, | ||
687 | .rates = CS35L33_RATES, | ||
688 | .formats = CS35L33_FORMATS, | ||
689 | }, | ||
690 | .capture = { | ||
691 | .stream_name = "CS35L33 Capture", | ||
692 | .channels_min = 2, | ||
693 | .channels_max = 2, | ||
694 | .rates = CS35L33_RATES, | ||
695 | .formats = CS35L33_FORMATS, | ||
696 | }, | ||
697 | .ops = &cs35l33_ops, | ||
698 | .symmetric_rates = 1, | ||
699 | }; | ||
700 | |||
701 | static int cs35l33_set_hg_data(struct snd_soc_codec *codec, | ||
702 | struct cs35l33_pdata *pdata) | ||
703 | { | ||
704 | struct cs35l33_hg *hg_config = &pdata->hg_config; | ||
705 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
706 | struct cs35l33_private *priv = snd_soc_codec_get_drvdata(codec); | ||
707 | |||
708 | if (hg_config->enable_hg_algo) { | ||
709 | regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, | ||
710 | CS35L33_MEM_DEPTH_MASK, | ||
711 | hg_config->mem_depth << CS35L33_MEM_DEPTH_SHIFT); | ||
712 | regmap_write(priv->regmap, CS35L33_HG_REL_RATE, | ||
713 | hg_config->release_rate); | ||
714 | regmap_update_bits(priv->regmap, CS35L33_HG_HEAD, | ||
715 | CS35L33_HD_RM_MASK, | ||
716 | hg_config->hd_rm << CS35L33_HD_RM_SHIFT); | ||
717 | regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, | ||
718 | CS35L33_LDO_THLD_MASK, | ||
719 | hg_config->ldo_thld << CS35L33_LDO_THLD_SHIFT); | ||
720 | regmap_update_bits(priv->regmap, CS35L33_HG_MEMLDO_CTL, | ||
721 | CS35L33_LDO_DISABLE_MASK, | ||
722 | hg_config->ldo_path_disable << | ||
723 | CS35L33_LDO_DISABLE_SHIFT); | ||
724 | regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, | ||
725 | CS35L33_LDO_ENTRY_DELAY_MASK, | ||
726 | hg_config->ldo_entry_delay << | ||
727 | CS35L33_LDO_ENTRY_DELAY_SHIFT); | ||
728 | if (hg_config->vp_hg_auto) { | ||
729 | regmap_update_bits(priv->regmap, CS35L33_HG_EN, | ||
730 | CS35L33_VP_HG_AUTO_MASK, | ||
731 | CS35L33_VP_HG_AUTO_MASK); | ||
732 | snd_soc_dapm_add_routes(dapm, cs35l33_vphg_auto_route, | ||
733 | ARRAY_SIZE(cs35l33_vphg_auto_route)); | ||
734 | } | ||
735 | regmap_update_bits(priv->regmap, CS35L33_HG_EN, | ||
736 | CS35L33_VP_HG_MASK, | ||
737 | hg_config->vp_hg << CS35L33_VP_HG_SHIFT); | ||
738 | regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, | ||
739 | CS35L33_VP_HG_RATE_MASK, | ||
740 | hg_config->vp_hg_rate << CS35L33_VP_HG_RATE_SHIFT); | ||
741 | regmap_update_bits(priv->regmap, CS35L33_LDO_DEL, | ||
742 | CS35L33_VP_HG_VA_MASK, | ||
743 | hg_config->vp_hg_va << CS35L33_VP_HG_VA_SHIFT); | ||
744 | regmap_update_bits(priv->regmap, CS35L33_HG_EN, | ||
745 | CS35L33_CLASS_HG_EN_MASK, CS35L33_CLASS_HG_EN_MASK); | ||
746 | } | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | static int cs35l33_set_bst_ipk(struct snd_soc_codec *codec, unsigned int bst) | ||
751 | { | ||
752 | struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec); | ||
753 | int ret = 0, steps = 0; | ||
754 | |||
755 | /* Boost current in uA */ | ||
756 | if (bst > 3600000 || bst < 1850000) { | ||
757 | dev_err(codec->dev, "Invalid boost current %d\n", bst); | ||
758 | ret = -EINVAL; | ||
759 | goto err; | ||
760 | } | ||
761 | |||
762 | if (bst % 15625) { | ||
763 | dev_err(codec->dev, "Current not a multiple of 15625uA (%d)\n", | ||
764 | bst); | ||
765 | ret = -EINVAL; | ||
766 | goto err; | ||
767 | } | ||
768 | |||
769 | while (bst > 1850000) { | ||
770 | bst -= 15625; | ||
771 | steps++; | ||
772 | } | ||
773 | |||
774 | regmap_write(cs35l33->regmap, CS35L33_BST_PEAK_CTL, | ||
775 | steps+0x70); | ||
776 | |||
777 | err: | ||
778 | return ret; | ||
779 | } | ||
780 | |||
781 | static int cs35l33_probe(struct snd_soc_codec *codec) | ||
782 | { | ||
783 | struct cs35l33_private *cs35l33 = snd_soc_codec_get_drvdata(codec); | ||
784 | |||
785 | cs35l33->codec = codec; | ||
786 | pm_runtime_get_sync(codec->dev); | ||
787 | |||
788 | regmap_update_bits(cs35l33->regmap, CS35L33_PROTECT_CTL, | ||
789 | CS35L33_ALIVE_WD_DIS, 0x8); | ||
790 | regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL2, | ||
791 | CS35L33_ALIVE_WD_DIS2, | ||
792 | CS35L33_ALIVE_WD_DIS2); | ||
793 | |||
794 | /* Set Platform Data */ | ||
795 | regmap_update_bits(cs35l33->regmap, CS35L33_BST_CTL1, | ||
796 | CS35L33_BST_CTL_MASK, cs35l33->pdata.boost_ctl); | ||
797 | regmap_update_bits(cs35l33->regmap, CS35L33_CLASSD_CTL, | ||
798 | CS35L33_AMP_DRV_SEL_MASK, | ||
799 | cs35l33->pdata.amp_drv_sel << CS35L33_AMP_DRV_SEL_SHIFT); | ||
800 | |||
801 | if (cs35l33->pdata.boost_ipk) | ||
802 | cs35l33_set_bst_ipk(codec, cs35l33->pdata.boost_ipk); | ||
803 | |||
804 | if (cs35l33->enable_soft_ramp) { | ||
805 | snd_soc_update_bits(codec, CS35L33_DAC_CTL, | ||
806 | CS35L33_DIGSFT, CS35L33_DIGSFT); | ||
807 | snd_soc_update_bits(codec, CS35L33_DAC_CTL, | ||
808 | CS35L33_DSR_RATE, cs35l33->pdata.ramp_rate); | ||
809 | } else { | ||
810 | snd_soc_update_bits(codec, CS35L33_DAC_CTL, | ||
811 | CS35L33_DIGSFT, 0); | ||
812 | } | ||
813 | |||
814 | /* update IMON scaling rate if different from default of 0x8 */ | ||
815 | if (cs35l33->pdata.imon_adc_scale != 0x8) | ||
816 | snd_soc_update_bits(codec, CS35L33_ADC_CTL, | ||
817 | CS35L33_IMON_SCALE, cs35l33->pdata.imon_adc_scale); | ||
818 | |||
819 | cs35l33_set_hg_data(codec, &(cs35l33->pdata)); | ||
820 | |||
821 | /* | ||
822 | * unmask important interrupts that causes the chip to enter | ||
823 | * speaker safe mode and hence deserves user attention | ||
824 | */ | ||
825 | regmap_update_bits(cs35l33->regmap, CS35L33_INT_MASK_1, | ||
826 | CS35L33_M_OTE | CS35L33_M_OTW | CS35L33_M_AMP_SHORT | | ||
827 | CS35L33_M_CAL_ERR, 0); | ||
828 | |||
829 | pm_runtime_put_sync(codec->dev); | ||
830 | |||
831 | return 0; | ||
832 | } | ||
833 | |||
834 | static struct snd_soc_codec_driver soc_codec_dev_cs35l33 = { | ||
835 | .probe = cs35l33_probe, | ||
836 | |||
837 | .set_bias_level = cs35l33_set_bias_level, | ||
838 | .set_sysclk = cs35l33_codec_set_sysclk, | ||
839 | |||
840 | .dapm_widgets = cs35l33_dapm_widgets, | ||
841 | .num_dapm_widgets = ARRAY_SIZE(cs35l33_dapm_widgets), | ||
842 | .dapm_routes = cs35l33_audio_map, | ||
843 | .num_dapm_routes = ARRAY_SIZE(cs35l33_audio_map), | ||
844 | .controls = cs35l33_snd_controls, | ||
845 | .num_controls = ARRAY_SIZE(cs35l33_snd_controls), | ||
846 | |||
847 | .idle_bias_off = true, | ||
848 | }; | ||
849 | |||
850 | static const struct regmap_config cs35l33_regmap = { | ||
851 | .reg_bits = 8, | ||
852 | .val_bits = 8, | ||
853 | |||
854 | .max_register = CS35L33_MAX_REGISTER, | ||
855 | .reg_defaults = cs35l33_reg, | ||
856 | .num_reg_defaults = ARRAY_SIZE(cs35l33_reg), | ||
857 | .volatile_reg = cs35l33_volatile_register, | ||
858 | .readable_reg = cs35l33_readable_register, | ||
859 | .writeable_reg = cs35l33_writeable_register, | ||
860 | .cache_type = REGCACHE_RBTREE, | ||
861 | .use_single_rw = true, | ||
862 | }; | ||
863 | |||
864 | static int __maybe_unused cs35l33_runtime_resume(struct device *dev) | ||
865 | { | ||
866 | struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); | ||
867 | int ret; | ||
868 | |||
869 | dev_dbg(dev, "%s\n", __func__); | ||
870 | |||
871 | if (cs35l33->reset_gpio) | ||
872 | gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); | ||
873 | |||
874 | ret = regulator_bulk_enable(cs35l33->num_core_supplies, | ||
875 | cs35l33->core_supplies); | ||
876 | if (ret != 0) { | ||
877 | dev_err(dev, "Failed to enable core supplies: %d\n", ret); | ||
878 | return ret; | ||
879 | } | ||
880 | |||
881 | regcache_cache_only(cs35l33->regmap, false); | ||
882 | |||
883 | if (cs35l33->reset_gpio) | ||
884 | gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); | ||
885 | |||
886 | msleep(CS35L33_BOOT_DELAY); | ||
887 | |||
888 | ret = regcache_sync(cs35l33->regmap); | ||
889 | if (ret != 0) { | ||
890 | dev_err(dev, "Failed to restore register cache\n"); | ||
891 | goto err; | ||
892 | } | ||
893 | |||
894 | return 0; | ||
895 | |||
896 | err: | ||
897 | regcache_cache_only(cs35l33->regmap, true); | ||
898 | regulator_bulk_disable(cs35l33->num_core_supplies, | ||
899 | cs35l33->core_supplies); | ||
900 | |||
901 | return ret; | ||
902 | } | ||
903 | |||
904 | static int __maybe_unused cs35l33_runtime_suspend(struct device *dev) | ||
905 | { | ||
906 | struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); | ||
907 | |||
908 | dev_dbg(dev, "%s\n", __func__); | ||
909 | |||
910 | /* redo the calibration in next power up */ | ||
911 | cs35l33->amp_cal = false; | ||
912 | |||
913 | regcache_cache_only(cs35l33->regmap, true); | ||
914 | regcache_mark_dirty(cs35l33->regmap); | ||
915 | regulator_bulk_disable(cs35l33->num_core_supplies, | ||
916 | cs35l33->core_supplies); | ||
917 | |||
918 | return 0; | ||
919 | } | ||
920 | |||
921 | static const struct dev_pm_ops cs35l33_pm_ops = { | ||
922 | SET_RUNTIME_PM_OPS(cs35l33_runtime_suspend, | ||
923 | cs35l33_runtime_resume, | ||
924 | NULL) | ||
925 | }; | ||
926 | |||
927 | static int cs35l33_get_hg_data(const struct device_node *np, | ||
928 | struct cs35l33_pdata *pdata) | ||
929 | { | ||
930 | struct device_node *hg; | ||
931 | struct cs35l33_hg *hg_config = &pdata->hg_config; | ||
932 | u32 val32; | ||
933 | |||
934 | hg = of_get_child_by_name(np, "cirrus,hg-algo"); | ||
935 | hg_config->enable_hg_algo = hg ? true : false; | ||
936 | |||
937 | if (hg_config->enable_hg_algo) { | ||
938 | if (of_property_read_u32(hg, "cirrus,mem-depth", &val32) >= 0) | ||
939 | hg_config->mem_depth = val32; | ||
940 | if (of_property_read_u32(hg, "cirrus,release-rate", | ||
941 | &val32) >= 0) | ||
942 | hg_config->release_rate = val32; | ||
943 | if (of_property_read_u32(hg, "cirrus,ldo-thld", &val32) >= 0) | ||
944 | hg_config->ldo_thld = val32; | ||
945 | if (of_property_read_u32(hg, "cirrus,ldo-path-disable", | ||
946 | &val32) >= 0) | ||
947 | hg_config->ldo_path_disable = val32; | ||
948 | if (of_property_read_u32(hg, "cirrus,ldo-entry-delay", | ||
949 | &val32) >= 0) | ||
950 | hg_config->ldo_entry_delay = val32; | ||
951 | |||
952 | hg_config->vp_hg_auto = of_property_read_bool(hg, | ||
953 | "cirrus,vp-hg-auto"); | ||
954 | |||
955 | if (of_property_read_u32(hg, "cirrus,vp-hg", &val32) >= 0) | ||
956 | hg_config->vp_hg = val32; | ||
957 | if (of_property_read_u32(hg, "cirrus,vp-hg-rate", &val32) >= 0) | ||
958 | hg_config->vp_hg_rate = val32; | ||
959 | if (of_property_read_u32(hg, "cirrus,vp-hg-va", &val32) >= 0) | ||
960 | hg_config->vp_hg_va = val32; | ||
961 | } | ||
962 | |||
963 | of_node_put(hg); | ||
964 | |||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static irqreturn_t cs35l33_irq_thread(int irq, void *data) | ||
969 | { | ||
970 | struct cs35l33_private *cs35l33 = data; | ||
971 | struct snd_soc_codec *codec = cs35l33->codec; | ||
972 | unsigned int sticky_val1, sticky_val2, current_val, mask1, mask2; | ||
973 | |||
974 | regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_2, | ||
975 | &sticky_val2); | ||
976 | regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1, | ||
977 | &sticky_val1); | ||
978 | regmap_read(cs35l33->regmap, CS35L33_INT_MASK_2, &mask2); | ||
979 | regmap_read(cs35l33->regmap, CS35L33_INT_MASK_1, &mask1); | ||
980 | |||
981 | /* Check to see if the unmasked bits are active, | ||
982 | * if not then exit. | ||
983 | */ | ||
984 | if (!(sticky_val1 & ~mask1) && !(sticky_val2 & ~mask2)) | ||
985 | return IRQ_NONE; | ||
986 | |||
987 | regmap_read(cs35l33->regmap, CS35L33_INT_STATUS_1, | ||
988 | ¤t_val); | ||
989 | |||
990 | /* handle the interrupts */ | ||
991 | |||
992 | if (sticky_val1 & CS35L33_AMP_SHORT) { | ||
993 | dev_crit(codec->dev, "Amp short error\n"); | ||
994 | if (!(current_val & CS35L33_AMP_SHORT)) { | ||
995 | dev_dbg(codec->dev, | ||
996 | "Amp short error release\n"); | ||
997 | regmap_update_bits(cs35l33->regmap, | ||
998 | CS35L33_AMP_CTL, | ||
999 | CS35L33_AMP_SHORT_RLS, 0); | ||
1000 | regmap_update_bits(cs35l33->regmap, | ||
1001 | CS35L33_AMP_CTL, | ||
1002 | CS35L33_AMP_SHORT_RLS, | ||
1003 | CS35L33_AMP_SHORT_RLS); | ||
1004 | regmap_update_bits(cs35l33->regmap, | ||
1005 | CS35L33_AMP_CTL, CS35L33_AMP_SHORT_RLS, | ||
1006 | 0); | ||
1007 | } | ||
1008 | } | ||
1009 | |||
1010 | if (sticky_val1 & CS35L33_CAL_ERR) { | ||
1011 | dev_err(codec->dev, "Cal error\n"); | ||
1012 | |||
1013 | /* redo the calibration in next power up */ | ||
1014 | cs35l33->amp_cal = false; | ||
1015 | |||
1016 | if (!(current_val & CS35L33_CAL_ERR)) { | ||
1017 | dev_dbg(codec->dev, "Cal error release\n"); | ||
1018 | regmap_update_bits(cs35l33->regmap, | ||
1019 | CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, | ||
1020 | 0); | ||
1021 | regmap_update_bits(cs35l33->regmap, | ||
1022 | CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, | ||
1023 | CS35L33_CAL_ERR_RLS); | ||
1024 | regmap_update_bits(cs35l33->regmap, | ||
1025 | CS35L33_AMP_CTL, CS35L33_CAL_ERR_RLS, | ||
1026 | 0); | ||
1027 | } | ||
1028 | } | ||
1029 | |||
1030 | if (sticky_val1 & CS35L33_OTE) { | ||
1031 | dev_crit(codec->dev, "Over temperature error\n"); | ||
1032 | if (!(current_val & CS35L33_OTE)) { | ||
1033 | dev_dbg(codec->dev, | ||
1034 | "Over temperature error release\n"); | ||
1035 | regmap_update_bits(cs35l33->regmap, | ||
1036 | CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0); | ||
1037 | regmap_update_bits(cs35l33->regmap, | ||
1038 | CS35L33_AMP_CTL, CS35L33_OTE_RLS, | ||
1039 | CS35L33_OTE_RLS); | ||
1040 | regmap_update_bits(cs35l33->regmap, | ||
1041 | CS35L33_AMP_CTL, CS35L33_OTE_RLS, 0); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | if (sticky_val1 & CS35L33_OTW) { | ||
1046 | dev_err(codec->dev, "Over temperature warning\n"); | ||
1047 | if (!(current_val & CS35L33_OTW)) { | ||
1048 | dev_dbg(codec->dev, | ||
1049 | "Over temperature warning release\n"); | ||
1050 | regmap_update_bits(cs35l33->regmap, | ||
1051 | CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0); | ||
1052 | regmap_update_bits(cs35l33->regmap, | ||
1053 | CS35L33_AMP_CTL, CS35L33_OTW_RLS, | ||
1054 | CS35L33_OTW_RLS); | ||
1055 | regmap_update_bits(cs35l33->regmap, | ||
1056 | CS35L33_AMP_CTL, CS35L33_OTW_RLS, 0); | ||
1057 | } | ||
1058 | } | ||
1059 | if (CS35L33_ALIVE_ERR & sticky_val1) | ||
1060 | dev_err(codec->dev, "ERROR: ADSPCLK Interrupt\n"); | ||
1061 | |||
1062 | if (CS35L33_MCLK_ERR & sticky_val1) | ||
1063 | dev_err(codec->dev, "ERROR: MCLK Interrupt\n"); | ||
1064 | |||
1065 | if (CS35L33_VMON_OVFL & sticky_val2) | ||
1066 | dev_err(codec->dev, | ||
1067 | "ERROR: VMON Overflow Interrupt\n"); | ||
1068 | |||
1069 | if (CS35L33_IMON_OVFL & sticky_val2) | ||
1070 | dev_err(codec->dev, | ||
1071 | "ERROR: IMON Overflow Interrupt\n"); | ||
1072 | |||
1073 | if (CS35L33_VPMON_OVFL & sticky_val2) | ||
1074 | dev_err(codec->dev, | ||
1075 | "ERROR: VPMON Overflow Interrupt\n"); | ||
1076 | |||
1077 | return IRQ_HANDLED; | ||
1078 | } | ||
1079 | |||
1080 | static const char * const cs35l33_core_supplies[] = { | ||
1081 | "VA", | ||
1082 | "VP", | ||
1083 | }; | ||
1084 | |||
1085 | static int cs35l33_of_get_pdata(struct device *dev, | ||
1086 | struct cs35l33_private *cs35l33) | ||
1087 | { | ||
1088 | struct device_node *np = dev->of_node; | ||
1089 | struct cs35l33_pdata *pdata = &cs35l33->pdata; | ||
1090 | u32 val32; | ||
1091 | |||
1092 | if (!np) | ||
1093 | return 0; | ||
1094 | |||
1095 | if (of_property_read_u32(np, "cirrus,boost-ctl", &val32) >= 0) { | ||
1096 | pdata->boost_ctl = val32; | ||
1097 | pdata->amp_drv_sel = 1; | ||
1098 | } | ||
1099 | |||
1100 | if (of_property_read_u32(np, "cirrus,ramp-rate", &val32) >= 0) { | ||
1101 | pdata->ramp_rate = val32; | ||
1102 | cs35l33->enable_soft_ramp = true; | ||
1103 | } | ||
1104 | |||
1105 | if (of_property_read_u32(np, "cirrus,boost-ipk", &val32) >= 0) | ||
1106 | pdata->boost_ipk = val32; | ||
1107 | |||
1108 | if (of_property_read_u32(np, "cirrus,imon-adc-scale", &val32) >= 0) { | ||
1109 | if ((val32 == 0x0) || (val32 == 0x7) || (val32 == 0x6)) | ||
1110 | pdata->imon_adc_scale = val32; | ||
1111 | else | ||
1112 | /* use default value */ | ||
1113 | pdata->imon_adc_scale = 0x8; | ||
1114 | } else { | ||
1115 | /* use default value */ | ||
1116 | pdata->imon_adc_scale = 0x8; | ||
1117 | } | ||
1118 | |||
1119 | cs35l33_get_hg_data(np, pdata); | ||
1120 | |||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | static int cs35l33_i2c_probe(struct i2c_client *i2c_client, | ||
1125 | const struct i2c_device_id *id) | ||
1126 | { | ||
1127 | struct cs35l33_private *cs35l33; | ||
1128 | struct cs35l33_pdata *pdata = dev_get_platdata(&i2c_client->dev); | ||
1129 | int ret, devid, i; | ||
1130 | unsigned int reg; | ||
1131 | |||
1132 | cs35l33 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l33_private), | ||
1133 | GFP_KERNEL); | ||
1134 | if (!cs35l33) | ||
1135 | return -ENOMEM; | ||
1136 | |||
1137 | i2c_set_clientdata(i2c_client, cs35l33); | ||
1138 | cs35l33->regmap = devm_regmap_init_i2c(i2c_client, &cs35l33_regmap); | ||
1139 | if (IS_ERR(cs35l33->regmap)) { | ||
1140 | ret = PTR_ERR(cs35l33->regmap); | ||
1141 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | ||
1142 | return ret; | ||
1143 | } | ||
1144 | |||
1145 | regcache_cache_only(cs35l33->regmap, true); | ||
1146 | |||
1147 | for (i = 0; i < ARRAY_SIZE(cs35l33_core_supplies); i++) | ||
1148 | cs35l33->core_supplies[i].supply | ||
1149 | = cs35l33_core_supplies[i]; | ||
1150 | cs35l33->num_core_supplies = ARRAY_SIZE(cs35l33_core_supplies); | ||
1151 | |||
1152 | ret = devm_regulator_bulk_get(&i2c_client->dev, | ||
1153 | cs35l33->num_core_supplies, | ||
1154 | cs35l33->core_supplies); | ||
1155 | if (ret != 0) { | ||
1156 | dev_err(&i2c_client->dev, | ||
1157 | "Failed to request core supplies: %d\n", | ||
1158 | ret); | ||
1159 | return ret; | ||
1160 | } | ||
1161 | |||
1162 | if (pdata) { | ||
1163 | cs35l33->pdata = *pdata; | ||
1164 | } else { | ||
1165 | cs35l33_of_get_pdata(&i2c_client->dev, cs35l33); | ||
1166 | pdata = &cs35l33->pdata; | ||
1167 | } | ||
1168 | |||
1169 | ret = devm_request_threaded_irq(&i2c_client->dev, i2c_client->irq, NULL, | ||
1170 | cs35l33_irq_thread, IRQF_ONESHOT | IRQF_TRIGGER_LOW, | ||
1171 | "cs35l33", cs35l33); | ||
1172 | if (ret != 0) | ||
1173 | dev_warn(&i2c_client->dev, "Failed to request IRQ: %d\n", ret); | ||
1174 | |||
1175 | /* We could issue !RST or skip it based on AMP topology */ | ||
1176 | cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev, | ||
1177 | "reset-gpios", GPIOD_OUT_HIGH); | ||
1178 | if (IS_ERR(cs35l33->reset_gpio)) { | ||
1179 | dev_err(&i2c_client->dev, "%s ERROR: Can't get reset GPIO\n", | ||
1180 | __func__); | ||
1181 | return PTR_ERR(cs35l33->reset_gpio); | ||
1182 | } | ||
1183 | |||
1184 | ret = regulator_bulk_enable(cs35l33->num_core_supplies, | ||
1185 | cs35l33->core_supplies); | ||
1186 | if (ret != 0) { | ||
1187 | dev_err(&i2c_client->dev, | ||
1188 | "Failed to enable core supplies: %d\n", | ||
1189 | ret); | ||
1190 | return ret; | ||
1191 | } | ||
1192 | |||
1193 | if (cs35l33->reset_gpio) | ||
1194 | gpiod_set_value_cansleep(cs35l33->reset_gpio, 1); | ||
1195 | |||
1196 | msleep(CS35L33_BOOT_DELAY); | ||
1197 | regcache_cache_only(cs35l33->regmap, false); | ||
1198 | |||
1199 | /* initialize codec */ | ||
1200 | ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_AB, ®); | ||
1201 | devid = (reg & 0xFF) << 12; | ||
1202 | ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_CD, ®); | ||
1203 | devid |= (reg & 0xFF) << 4; | ||
1204 | ret = regmap_read(cs35l33->regmap, CS35L33_DEVID_E, ®); | ||
1205 | devid |= (reg & 0xF0) >> 4; | ||
1206 | |||
1207 | if (devid != CS35L33_CHIP_ID) { | ||
1208 | dev_err(&i2c_client->dev, | ||
1209 | "CS35L33 Device ID (%X). Expected ID %X\n", | ||
1210 | devid, CS35L33_CHIP_ID); | ||
1211 | goto err_enable; | ||
1212 | } | ||
1213 | |||
1214 | ret = regmap_read(cs35l33->regmap, CS35L33_REV_ID, ®); | ||
1215 | if (ret < 0) { | ||
1216 | dev_err(&i2c_client->dev, "Get Revision ID failed\n"); | ||
1217 | goto err_enable; | ||
1218 | } | ||
1219 | |||
1220 | dev_info(&i2c_client->dev, | ||
1221 | "Cirrus Logic CS35L33, Revision: %02X\n", reg & 0xFF); | ||
1222 | |||
1223 | ret = regmap_register_patch(cs35l33->regmap, | ||
1224 | cs35l33_patch, ARRAY_SIZE(cs35l33_patch)); | ||
1225 | if (ret < 0) { | ||
1226 | dev_err(&i2c_client->dev, | ||
1227 | "Error in applying regmap patch: %d\n", ret); | ||
1228 | goto err_enable; | ||
1229 | } | ||
1230 | |||
1231 | /* disable mclk and tdm */ | ||
1232 | regmap_update_bits(cs35l33->regmap, CS35L33_CLK_CTL, | ||
1233 | CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM, | ||
1234 | CS35L33_MCLKDIS | CS35L33_SDOUT_3ST_TDM); | ||
1235 | |||
1236 | pm_runtime_set_autosuspend_delay(&i2c_client->dev, 100); | ||
1237 | pm_runtime_use_autosuspend(&i2c_client->dev); | ||
1238 | pm_runtime_set_active(&i2c_client->dev); | ||
1239 | pm_runtime_enable(&i2c_client->dev); | ||
1240 | |||
1241 | ret = snd_soc_register_codec(&i2c_client->dev, | ||
1242 | &soc_codec_dev_cs35l33, &cs35l33_dai, 1); | ||
1243 | if (ret < 0) { | ||
1244 | dev_err(&i2c_client->dev, "%s: Register codec failed\n", | ||
1245 | __func__); | ||
1246 | goto err_enable; | ||
1247 | } | ||
1248 | |||
1249 | return 0; | ||
1250 | |||
1251 | err_enable: | ||
1252 | regulator_bulk_disable(cs35l33->num_core_supplies, | ||
1253 | cs35l33->core_supplies); | ||
1254 | |||
1255 | return ret; | ||
1256 | } | ||
1257 | |||
1258 | static int cs35l33_i2c_remove(struct i2c_client *client) | ||
1259 | { | ||
1260 | struct cs35l33_private *cs35l33 = i2c_get_clientdata(client); | ||
1261 | |||
1262 | snd_soc_unregister_codec(&client->dev); | ||
1263 | |||
1264 | if (cs35l33->reset_gpio) | ||
1265 | gpiod_set_value_cansleep(cs35l33->reset_gpio, 0); | ||
1266 | |||
1267 | pm_runtime_disable(&client->dev); | ||
1268 | regulator_bulk_disable(cs35l33->num_core_supplies, | ||
1269 | cs35l33->core_supplies); | ||
1270 | |||
1271 | return 0; | ||
1272 | } | ||
1273 | |||
1274 | static const struct of_device_id cs35l33_of_match[] = { | ||
1275 | { .compatible = "cirrus,cs35l33", }, | ||
1276 | {}, | ||
1277 | }; | ||
1278 | MODULE_DEVICE_TABLE(of, cs35l33_of_match); | ||
1279 | |||
1280 | static const struct i2c_device_id cs35l33_id[] = { | ||
1281 | {"cs35l33", 0}, | ||
1282 | {} | ||
1283 | }; | ||
1284 | |||
1285 | MODULE_DEVICE_TABLE(i2c, cs35l33_id); | ||
1286 | |||
1287 | static struct i2c_driver cs35l33_i2c_driver = { | ||
1288 | .driver = { | ||
1289 | .name = "cs35l33", | ||
1290 | .pm = &cs35l33_pm_ops, | ||
1291 | .of_match_table = cs35l33_of_match, | ||
1292 | |||
1293 | }, | ||
1294 | .id_table = cs35l33_id, | ||
1295 | .probe = cs35l33_i2c_probe, | ||
1296 | .remove = cs35l33_i2c_remove, | ||
1297 | |||
1298 | }; | ||
1299 | module_i2c_driver(cs35l33_i2c_driver); | ||
1300 | |||
1301 | MODULE_DESCRIPTION("ASoC CS35L33 driver"); | ||
1302 | MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <paul.handrigan@cirrus.com>"); | ||
1303 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs35l33.h b/sound/soc/codecs/cs35l33.h new file mode 100644 index 000000000000..c045737d1a5f --- /dev/null +++ b/sound/soc/codecs/cs35l33.h | |||
@@ -0,0 +1,221 @@ | |||
1 | /* | ||
2 | * cs35l33.h -- CS35L33 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2016 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Paul Handrigan <paul.handrigan@cirrus.com> | ||
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 version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __CS35L33_H__ | ||
15 | #define __CS35L33_H__ | ||
16 | |||
17 | #define CS35L33_CHIP_ID 0x00035A33 | ||
18 | #define CS35L33_DEVID_AB 0x01 /* Device ID A & B [RO] */ | ||
19 | #define CS35L33_DEVID_CD 0x02 /* Device ID C & D [RO] */ | ||
20 | #define CS35L33_DEVID_E 0x03 /* Device ID E [RO] */ | ||
21 | #define CS35L33_FAB_ID 0x04 /* Fab ID [RO] */ | ||
22 | #define CS35L33_REV_ID 0x05 /* Revision ID [RO] */ | ||
23 | #define CS35L33_PWRCTL1 0x06 /* Power Ctl 1 */ | ||
24 | #define CS35L33_PWRCTL2 0x07 /* Power Ctl 2 */ | ||
25 | #define CS35L33_CLK_CTL 0x08 /* Clock Ctl */ | ||
26 | #define CS35L33_BST_PEAK_CTL 0x09 /* Max Current for Boost */ | ||
27 | #define CS35L33_PROTECT_CTL 0x0A /* Amp Protection Parameters */ | ||
28 | #define CS35L33_BST_CTL1 0x0B /* Boost Converter CTL1 */ | ||
29 | #define CS35L33_BST_CTL2 0x0C /* Boost Converter CTL2 */ | ||
30 | #define CS35L33_ADSP_CTL 0x0D /* Serial Port Control */ | ||
31 | #define CS35L33_ADC_CTL 0x0E /* ADC Control */ | ||
32 | #define CS35L33_DAC_CTL 0x0F /* DAC Control */ | ||
33 | #define CS35L33_DIG_VOL_CTL 0x10 /* Digital Volume CTL */ | ||
34 | #define CS35L33_CLASSD_CTL 0x11 /* Class D Amp CTL */ | ||
35 | #define CS35L33_AMP_CTL 0x12 /* Amp Gain/Protecton Release CTL */ | ||
36 | #define CS35L33_INT_MASK_1 0x13 /* Interrupt Mask 1 */ | ||
37 | #define CS35L33_INT_MASK_2 0x14 /* Interrupt Mask 2 */ | ||
38 | #define CS35L33_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */ | ||
39 | #define CS35L33_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */ | ||
40 | #define CS35L33_DIAG_LOCK 0x17 /* Diagnostic Mode Register Lock */ | ||
41 | #define CS35L33_DIAG_CTRL_1 0x18 /* Diagnostic Mode Register Control */ | ||
42 | #define CS35L33_DIAG_CTRL_2 0x19 /* Diagnostic Mode Register Control 2 */ | ||
43 | #define CS35L33_HG_MEMLDO_CTL 0x23 /* H/G Memory/LDO CTL */ | ||
44 | #define CS35L33_HG_REL_RATE 0x24 /* H/G Release Rate */ | ||
45 | #define CS35L33_LDO_DEL 0x25 /* LDO Entry Delay/VPhg Control 1 */ | ||
46 | #define CS35L33_HG_HEAD 0x29 /* H/G Headroom */ | ||
47 | #define CS35L33_HG_EN 0x2A /* H/G Enable/VPhg CNT2 */ | ||
48 | #define CS35L33_TX_VMON 0x2D /* TDM TX Control 1 (VMON) */ | ||
49 | #define CS35L33_TX_IMON 0x2E /* TDM TX Control 2 (IMON) */ | ||
50 | #define CS35L33_TX_VPMON 0x2F /* TDM TX Control 3 (VPMON) */ | ||
51 | #define CS35L33_TX_VBSTMON 0x30 /* TDM TX Control 4 (VBSTMON) */ | ||
52 | #define CS35L33_TX_FLAG 0x31 /* TDM TX Control 5 (FLAG) */ | ||
53 | #define CS35L33_TX_EN1 0x32 /* TDM TX Enable 1 */ | ||
54 | #define CS35L33_TX_EN2 0x33 /* TDM TX Enable 2 */ | ||
55 | #define CS35L33_TX_EN3 0x34 /* TDM TX Enable 3 */ | ||
56 | #define CS35L33_TX_EN4 0x35 /* TDM TX Enable 4 */ | ||
57 | #define CS35L33_RX_AUD 0x36 /* TDM RX Control 1 */ | ||
58 | #define CS35L33_RX_SPLY 0x37 /* TDM RX Control 2 */ | ||
59 | #define CS35L33_RX_ALIVE 0x38 /* TDM RX Control 3 */ | ||
60 | #define CS35L33_BST_CTL4 0x39 /* Boost Converter Control 4 */ | ||
61 | #define CS35L33_HG_STATUS 0x3F /* H/G Status */ | ||
62 | #define CS35L33_MAX_REGISTER 0x59 | ||
63 | |||
64 | #define CS35L33_MCLK_5644 5644800 | ||
65 | #define CS35L33_MCLK_6144 6144000 | ||
66 | #define CS35L33_MCLK_6 6000000 | ||
67 | #define CS35L33_MCLK_11289 11289600 | ||
68 | #define CS35L33_MCLK_12 12000000 | ||
69 | #define CS35L33_MCLK_12288 12288000 | ||
70 | |||
71 | /* CS35L33_PWRCTL1 */ | ||
72 | #define CS35L33_PDN_AMP (1 << 7) | ||
73 | #define CS35L33_PDN_BST (1 << 2) | ||
74 | #define CS35L33_PDN_ALL 1 | ||
75 | |||
76 | /* CS35L33_PWRCTL2 */ | ||
77 | #define CS35L33_PDN_VMON_SHIFT 7 | ||
78 | #define CS35L33_PDN_VMON (1 << CS35L33_PDN_VMON_SHIFT) | ||
79 | #define CS35L33_PDN_IMON_SHIFT 6 | ||
80 | #define CS35L33_PDN_IMON (1 << CS35L33_PDN_IMON_SHIFT) | ||
81 | #define CS35L33_PDN_VPMON_SHIFT 5 | ||
82 | #define CS35L33_PDN_VPMON (1 << CS35L33_PDN_VPMON_SHIFT) | ||
83 | #define CS35L33_PDN_VBSTMON_SHIFT 4 | ||
84 | #define CS35L33_PDN_VBSTMON (1 << CS35L33_PDN_VBSTMON_SHIFT) | ||
85 | #define CS35L33_SDOUT_3ST_I2S_SHIFT 3 | ||
86 | #define CS35L33_SDOUT_3ST_I2S (1 << CS35L33_SDOUT_3ST_I2S_SHIFT) | ||
87 | #define CS35L33_PDN_SDIN_SHIFT 2 | ||
88 | #define CS35L33_PDN_SDIN (1 << CS35L33_PDN_SDIN_SHIFT) | ||
89 | #define CS35L33_PDN_TDM_SHIFT 1 | ||
90 | #define CS35L33_PDN_TDM (1 << CS35L33_PDN_TDM_SHIFT) | ||
91 | |||
92 | /* CS35L33_CLK_CTL */ | ||
93 | #define CS35L33_MCLKDIS (1 << 7) | ||
94 | #define CS35L33_MCLKDIV2 (1 << 6) | ||
95 | #define CS35L33_SDOUT_3ST_TDM (1 << 5) | ||
96 | #define CS35L33_INT_FS_RATE (1 << 4) | ||
97 | #define CS35L33_ADSP_FS 0xF | ||
98 | |||
99 | /* CS35L33_PROTECT_CTL */ | ||
100 | #define CS35L33_ALIVE_WD_DIS (3 << 2) | ||
101 | |||
102 | /* CS35L33_BST_CTL1 */ | ||
103 | #define CS35L33_BST_CTL_SRC (1 << 6) | ||
104 | #define CS35L33_BST_CTL_SHIFT (1 << 5) | ||
105 | #define CS35L33_BST_CTL_MASK 0x3F | ||
106 | |||
107 | /* CS35L33_BST_CTL2 */ | ||
108 | #define CS35L33_TDM_WD_SEL (1 << 4) | ||
109 | #define CS35L33_ALIVE_WD_DIS2 (1 << 3) | ||
110 | #define CS35L33_VBST_SR_STEP 0x3 | ||
111 | |||
112 | /* CS35L33_ADSP_CTL */ | ||
113 | #define CS35L33_ADSP_DRIVE (1 << 7) | ||
114 | #define CS35L33_MS_MASK (1 << 6) | ||
115 | #define CS35L33_SDIN_LOC (3 << 4) | ||
116 | #define CS35L33_ALIVE_RATE 0x3 | ||
117 | |||
118 | /* CS35L33_ADC_CTL */ | ||
119 | #define CS35L33_INV_VMON (1 << 7) | ||
120 | #define CS35L33_INV_IMON (1 << 6) | ||
121 | #define CS35L33_ADC_NOTCH_DIS (1 << 5) | ||
122 | #define CS35L33_IMON_SCALE 0xF | ||
123 | |||
124 | /* CS35L33_DAC_CTL */ | ||
125 | #define CS35L33_INV_DAC (1 << 7) | ||
126 | #define CS35L33_DAC_NOTCH_DIS (1 << 5) | ||
127 | #define CS35L33_DIGSFT (1 << 4) | ||
128 | #define CS35L33_DSR_RATE 0xF | ||
129 | |||
130 | /* CS35L33_CLASSD_CTL */ | ||
131 | #define CS35L33_AMP_SD (1 << 6) | ||
132 | #define CS35L33_AMP_DRV_SEL_SRC (1 << 5) | ||
133 | #define CS35L33_AMP_DRV_SEL_MASK 0x10 | ||
134 | #define CS35L33_AMP_DRV_SEL_SHIFT 4 | ||
135 | #define CS35L33_AMP_CAL (1 << 3) | ||
136 | #define CS35L33_GAIN_CHG_ZC_MASK 0x04 | ||
137 | #define CS35L33_GAIN_CHG_ZC_SHIFT 2 | ||
138 | #define CS35L33_CLASS_D_CTL_MASK 0x3F | ||
139 | |||
140 | /* CS35L33_AMP_CTL */ | ||
141 | #define CS35L33_AMP_GAIN 0xF0 | ||
142 | #define CS35L33_CAL_ERR_RLS (1 << 3) | ||
143 | #define CS35L33_AMP_SHORT_RLS (1 << 2) | ||
144 | #define CS35L33_OTW_RLS (1 << 1) | ||
145 | #define CS35L33_OTE_RLS 1 | ||
146 | |||
147 | /* CS35L33_INT_MASK_1 */ | ||
148 | #define CS35L33_M_CAL_ERR_SHIFT 6 | ||
149 | #define CS35L33_M_CAL_ERR (1 << CS35L33_M_CAL_ERR_SHIFT) | ||
150 | #define CS35L33_M_ALIVE_ERR_SHIFT 5 | ||
151 | #define CS35L33_M_ALIVE_ERR (1 << CS35L33_M_ALIVE_ERR_SHIFT) | ||
152 | #define CS35L33_M_AMP_SHORT_SHIFT 2 | ||
153 | #define CS35L33_M_AMP_SHORT (1 << CS35L33_M_AMP_SHORT_SHIFT) | ||
154 | #define CS35L33_M_OTW_SHIFT 1 | ||
155 | #define CS35L33_M_OTW (1 << CS35L33_M_OTW_SHIFT) | ||
156 | #define CS35L33_M_OTE_SHIFT 0 | ||
157 | #define CS35L33_M_OTE (1 << CS35L33_M_OTE_SHIFT) | ||
158 | |||
159 | /* CS35L33_INT_STATUS_1 */ | ||
160 | #define CS35L33_CAL_ERR (1 << 6) | ||
161 | #define CS35L33_ALIVE_ERR (1 << 5) | ||
162 | #define CS35L33_ADSPCLK_ERR (1 << 4) | ||
163 | #define CS35L33_MCLK_ERR (1 << 3) | ||
164 | #define CS35L33_AMP_SHORT (1 << 2) | ||
165 | #define CS35L33_OTW (1 << 1) | ||
166 | #define CS35L33_OTE (1 << 0) | ||
167 | |||
168 | /* CS35L33_INT_STATUS_2 */ | ||
169 | #define CS35L33_VMON_OVFL (1 << 7) | ||
170 | #define CS35L33_IMON_OVFL (1 << 6) | ||
171 | #define CS35L33_VPMON_OVFL (1 << 5) | ||
172 | #define CS35L33_VBSTMON_OVFL (1 << 4) | ||
173 | #define CS35L33_PDN_DONE 1 | ||
174 | |||
175 | /* CS35L33_BST_CTL4 */ | ||
176 | #define CS35L33_BST_RGS 0x70 | ||
177 | #define CS35L33_BST_COEFF3 0xF | ||
178 | |||
179 | /* CS35L33_HG_MEMLDO_CTL */ | ||
180 | #define CS35L33_MEM_DEPTH_SHIFT 5 | ||
181 | #define CS35L33_MEM_DEPTH_MASK (0x3 << CS35L33_MEM_DEPTH_SHIFT) | ||
182 | #define CS35L33_LDO_THLD_SHIFT 1 | ||
183 | #define CS35L33_LDO_THLD_MASK (0xF << CS35L33_LDO_THLD_SHIFT) | ||
184 | #define CS35L33_LDO_DISABLE_SHIFT 0 | ||
185 | #define CS35L33_LDO_DISABLE_MASK (0x1 << CS35L33_LDO_DISABLE_SHIFT) | ||
186 | |||
187 | /* CS35L33_LDO_DEL */ | ||
188 | #define CS35L33_VP_HG_VA_SHIFT 5 | ||
189 | #define CS35L33_VP_HG_VA_MASK (0x7 << CS35L33_VP_HG_VA_SHIFT) | ||
190 | #define CS35L33_LDO_ENTRY_DELAY_SHIFT 2 | ||
191 | #define CS35L33_LDO_ENTRY_DELAY_MASK (0x7 << CS35L33_LDO_ENTRY_DELAY_SHIFT) | ||
192 | #define CS35L33_VP_HG_RATE_SHIFT 0 | ||
193 | #define CS35L33_VP_HG_RATE_MASK (0x3 << CS35L33_VP_HG_RATE_SHIFT) | ||
194 | |||
195 | /* CS35L33_HG_HEAD */ | ||
196 | #define CS35L33_HD_RM_SHIFT 0 | ||
197 | #define CS35L33_HD_RM_MASK (0x7F << CS35L33_HD_RM_SHIFT) | ||
198 | |||
199 | /* CS35L33_HG_EN */ | ||
200 | #define CS35L33_CLASS_HG_ENA_SHIFT 7 | ||
201 | #define CS35L33_CLASS_HG_EN_MASK (0x1 << CS35L33_CLASS_HG_ENA_SHIFT) | ||
202 | #define CS35L33_VP_HG_AUTO_SHIFT 6 | ||
203 | #define CS35L33_VP_HG_AUTO_MASK (0x1 << 6) | ||
204 | #define CS35L33_VP_HG_SHIFT 0 | ||
205 | #define CS35L33_VP_HG_MASK (0x1F << CS35L33_VP_HG_SHIFT) | ||
206 | |||
207 | #define CS35L33_RATES (SNDRV_PCM_RATE_8000_48000) | ||
208 | #define CS35L33_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
209 | SNDRV_PCM_FMTBIT_S24_LE) | ||
210 | |||
211 | /* CS35L33_{RX,TX}_X */ | ||
212 | #define CS35L33_X_STATE_SHIFT 7 | ||
213 | #define CS35L33_X_STATE (1 << CS35L33_X_STATE_SHIFT) | ||
214 | #define CS35L33_X_LOC_SHIFT 0 | ||
215 | #define CS35L33_X_LOC (0x1F << CS35L33_X_LOC_SHIFT) | ||
216 | |||
217 | /* CS35L33_RX_AUD */ | ||
218 | #define CS35L33_AUDIN_RX_DEPTH_SHIFT 5 | ||
219 | #define CS35L33_AUDIN_RX_DEPTH (0x7 << CS35L33_AUDIN_RX_DEPTH_SHIFT) | ||
220 | |||
221 | #endif | ||
diff --git a/sound/soc/codecs/cs47l24.c b/sound/soc/codecs/cs47l24.c index 5ec5a682d186..954a4f5d3338 100644 --- a/sound/soc/codecs/cs47l24.c +++ b/sound/soc/codecs/cs47l24.c | |||
@@ -359,6 +359,11 @@ SND_SOC_DAPM_INPUT("IN2R"), | |||
359 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), | 359 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), |
360 | SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), | 360 | SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), |
361 | 361 | ||
362 | SND_SOC_DAPM_OUTPUT("DSP Voice Trigger"), | ||
363 | |||
364 | SND_SOC_DAPM_SWITCH("DSP3 Voice Trigger", SND_SOC_NOPM, 2, 0, | ||
365 | &arizona_voice_trigger_switch[2]), | ||
366 | |||
362 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | 367 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, |
363 | 0, NULL, 0, arizona_in_ev, | 368 | 0, NULL, 0, arizona_in_ev, |
364 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | 369 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | |
@@ -899,10 +904,16 @@ static const struct snd_soc_dapm_route cs47l24_dapm_routes[] = { | |||
899 | 904 | ||
900 | { "MICSUPP", NULL, "SYSCLK" }, | 905 | { "MICSUPP", NULL, "SYSCLK" }, |
901 | 906 | ||
907 | { "DRC1 Signal Activity", NULL, "SYSCLK" }, | ||
908 | { "DRC2 Signal Activity", NULL, "SYSCLK" }, | ||
902 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | 909 | { "DRC1 Signal Activity", NULL, "DRC1L" }, |
903 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | 910 | { "DRC1 Signal Activity", NULL, "DRC1R" }, |
904 | { "DRC2 Signal Activity", NULL, "DRC2L" }, | 911 | { "DRC2 Signal Activity", NULL, "DRC2L" }, |
905 | { "DRC2 Signal Activity", NULL, "DRC2R" }, | 912 | { "DRC2 Signal Activity", NULL, "DRC2R" }, |
913 | |||
914 | { "DSP Voice Trigger", NULL, "SYSCLK" }, | ||
915 | { "DSP Voice Trigger", NULL, "DSP3 Voice Trigger" }, | ||
916 | { "DSP3 Voice Trigger", "Switch", "DSP3" }, | ||
906 | }; | 917 | }; |
907 | 918 | ||
908 | static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | 919 | static int cs47l24_set_fll(struct snd_soc_codec *codec, int fll_id, int source, |
@@ -1067,6 +1078,7 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
1067 | { | 1078 | { |
1068 | struct cs47l24_priv *priv = data; | 1079 | struct cs47l24_priv *priv = data; |
1069 | struct arizona *arizona = priv->core.arizona; | 1080 | struct arizona *arizona = priv->core.arizona; |
1081 | struct arizona_voice_trigger_info info; | ||
1070 | int serviced = 0; | 1082 | int serviced = 0; |
1071 | int i, ret; | 1083 | int i, ret; |
1072 | 1084 | ||
@@ -1074,6 +1086,12 @@ static irqreturn_t cs47l24_adsp2_irq(int irq, void *data) | |||
1074 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); | 1086 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); |
1075 | if (ret != -ENODEV) | 1087 | if (ret != -ENODEV) |
1076 | serviced++; | 1088 | serviced++; |
1089 | if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) { | ||
1090 | info.core = i; | ||
1091 | arizona_call_notifiers(arizona, | ||
1092 | ARIZONA_NOTIFY_VOICE_TRIGGER, | ||
1093 | &info); | ||
1094 | } | ||
1077 | } | 1095 | } |
1078 | 1096 | ||
1079 | if (!serviced) { | 1097 | if (!serviced) { |
@@ -1096,6 +1114,7 @@ static int cs47l24_codec_probe(struct snd_soc_codec *codec) | |||
1096 | arizona_init_spk(codec); | 1114 | arizona_init_spk(codec); |
1097 | arizona_init_gpio(codec); | 1115 | arizona_init_gpio(codec); |
1098 | arizona_init_mono(codec); | 1116 | arizona_init_mono(codec); |
1117 | arizona_init_notifiers(codec); | ||
1099 | 1118 | ||
1100 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, | 1119 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, |
1101 | "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, | 1120 | "ADSP2 Compressed IRQ", cs47l24_adsp2_irq, |
diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c new file mode 100644 index 000000000000..2c0d9c430a8c --- /dev/null +++ b/sound/soc/codecs/cs53l30.c | |||
@@ -0,0 +1,1143 @@ | |||
1 | /* | ||
2 | * cs53l30.c -- CS53l30 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2015 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Authors: Paul Handrigan <Paul.Handrigan@cirrus.com>, | ||
7 | * Tim Howe <Tim.Howe@cirrus.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 version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/clk.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/of_gpio.h> | ||
20 | #include <linux/gpio/consumer.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/tlv.h> | ||
25 | |||
26 | #include "cs53l30.h" | ||
27 | |||
28 | #define CS53L30_NUM_SUPPLIES 2 | ||
29 | static const char *const cs53l30_supply_names[CS53L30_NUM_SUPPLIES] = { | ||
30 | "VA", | ||
31 | "VP", | ||
32 | }; | ||
33 | |||
34 | struct cs53l30_private { | ||
35 | struct regulator_bulk_data supplies[CS53L30_NUM_SUPPLIES]; | ||
36 | struct regmap *regmap; | ||
37 | struct gpio_desc *reset_gpio; | ||
38 | struct gpio_desc *mute_gpio; | ||
39 | struct clk *mclk; | ||
40 | bool use_sdout2; | ||
41 | u32 mclk_rate; | ||
42 | }; | ||
43 | |||
44 | static const struct reg_default cs53l30_reg_defaults[] = { | ||
45 | { CS53L30_PWRCTL, CS53L30_PWRCTL_DEFAULT }, | ||
46 | { CS53L30_MCLKCTL, CS53L30_MCLKCTL_DEFAULT }, | ||
47 | { CS53L30_INT_SR_CTL, CS53L30_INT_SR_CTL_DEFAULT }, | ||
48 | { CS53L30_MICBIAS_CTL, CS53L30_MICBIAS_CTL_DEFAULT }, | ||
49 | { CS53L30_ASPCFG_CTL, CS53L30_ASPCFG_CTL_DEFAULT }, | ||
50 | { CS53L30_ASP_CTL1, CS53L30_ASP_CTL1_DEFAULT }, | ||
51 | { CS53L30_ASP_TDMTX_CTL1, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, | ||
52 | { CS53L30_ASP_TDMTX_CTL2, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, | ||
53 | { CS53L30_ASP_TDMTX_CTL3, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, | ||
54 | { CS53L30_ASP_TDMTX_CTL4, CS53L30_ASP_TDMTX_CTLx_DEFAULT }, | ||
55 | { CS53L30_ASP_TDMTX_EN1, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
56 | { CS53L30_ASP_TDMTX_EN2, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
57 | { CS53L30_ASP_TDMTX_EN3, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
58 | { CS53L30_ASP_TDMTX_EN4, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
59 | { CS53L30_ASP_TDMTX_EN5, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
60 | { CS53L30_ASP_TDMTX_EN6, CS53L30_ASP_TDMTX_ENx_DEFAULT }, | ||
61 | { CS53L30_ASP_CTL2, CS53L30_ASP_CTL2_DEFAULT }, | ||
62 | { CS53L30_SFT_RAMP, CS53L30_SFT_RMP_DEFAULT }, | ||
63 | { CS53L30_LRCK_CTL1, CS53L30_LRCK_CTLx_DEFAULT }, | ||
64 | { CS53L30_LRCK_CTL2, CS53L30_LRCK_CTLx_DEFAULT }, | ||
65 | { CS53L30_MUTEP_CTL1, CS53L30_MUTEP_CTL1_DEFAULT }, | ||
66 | { CS53L30_MUTEP_CTL2, CS53L30_MUTEP_CTL2_DEFAULT }, | ||
67 | { CS53L30_INBIAS_CTL1, CS53L30_INBIAS_CTL1_DEFAULT }, | ||
68 | { CS53L30_INBIAS_CTL2, CS53L30_INBIAS_CTL2_DEFAULT }, | ||
69 | { CS53L30_DMIC1_STR_CTL, CS53L30_DMIC1_STR_CTL_DEFAULT }, | ||
70 | { CS53L30_DMIC2_STR_CTL, CS53L30_DMIC2_STR_CTL_DEFAULT }, | ||
71 | { CS53L30_ADCDMIC1_CTL1, CS53L30_ADCDMICx_CTL1_DEFAULT }, | ||
72 | { CS53L30_ADCDMIC1_CTL2, CS53L30_ADCDMIC1_CTL2_DEFAULT }, | ||
73 | { CS53L30_ADC1_CTL3, CS53L30_ADCx_CTL3_DEFAULT }, | ||
74 | { CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_CTL_DEFAULT }, | ||
75 | { CS53L30_ADC1A_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, | ||
76 | { CS53L30_ADC1B_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, | ||
77 | { CS53L30_ADC1A_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, | ||
78 | { CS53L30_ADC1B_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, | ||
79 | { CS53L30_ADCDMIC2_CTL1, CS53L30_ADCDMICx_CTL1_DEFAULT }, | ||
80 | { CS53L30_ADCDMIC2_CTL2, CS53L30_ADCDMIC1_CTL2_DEFAULT }, | ||
81 | { CS53L30_ADC2_CTL3, CS53L30_ADCx_CTL3_DEFAULT }, | ||
82 | { CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_CTL_DEFAULT }, | ||
83 | { CS53L30_ADC2A_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, | ||
84 | { CS53L30_ADC2B_AFE_CTL, CS53L30_ADCxy_AFE_CTL_DEFAULT }, | ||
85 | { CS53L30_ADC2A_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, | ||
86 | { CS53L30_ADC2B_DIG_VOL, CS53L30_ADCxy_DIG_VOL_DEFAULT }, | ||
87 | { CS53L30_INT_MASK, CS53L30_DEVICE_INT_MASK }, | ||
88 | }; | ||
89 | |||
90 | static bool cs53l30_volatile_register(struct device *dev, unsigned int reg) | ||
91 | { | ||
92 | if (reg == CS53L30_IS) | ||
93 | return true; | ||
94 | else | ||
95 | return false; | ||
96 | } | ||
97 | |||
98 | static bool cs53l30_writeable_register(struct device *dev, unsigned int reg) | ||
99 | { | ||
100 | switch (reg) { | ||
101 | case CS53L30_DEVID_AB: | ||
102 | case CS53L30_DEVID_CD: | ||
103 | case CS53L30_DEVID_E: | ||
104 | case CS53L30_REVID: | ||
105 | case CS53L30_IS: | ||
106 | return false; | ||
107 | default: | ||
108 | return true; | ||
109 | } | ||
110 | } | ||
111 | |||
112 | static bool cs53l30_readable_register(struct device *dev, unsigned int reg) | ||
113 | { | ||
114 | switch (reg) { | ||
115 | case CS53L30_DEVID_AB: | ||
116 | case CS53L30_DEVID_CD: | ||
117 | case CS53L30_DEVID_E: | ||
118 | case CS53L30_REVID: | ||
119 | case CS53L30_PWRCTL: | ||
120 | case CS53L30_MCLKCTL: | ||
121 | case CS53L30_INT_SR_CTL: | ||
122 | case CS53L30_MICBIAS_CTL: | ||
123 | case CS53L30_ASPCFG_CTL: | ||
124 | case CS53L30_ASP_CTL1: | ||
125 | case CS53L30_ASP_TDMTX_CTL1: | ||
126 | case CS53L30_ASP_TDMTX_CTL2: | ||
127 | case CS53L30_ASP_TDMTX_CTL3: | ||
128 | case CS53L30_ASP_TDMTX_CTL4: | ||
129 | case CS53L30_ASP_TDMTX_EN1: | ||
130 | case CS53L30_ASP_TDMTX_EN2: | ||
131 | case CS53L30_ASP_TDMTX_EN3: | ||
132 | case CS53L30_ASP_TDMTX_EN4: | ||
133 | case CS53L30_ASP_TDMTX_EN5: | ||
134 | case CS53L30_ASP_TDMTX_EN6: | ||
135 | case CS53L30_ASP_CTL2: | ||
136 | case CS53L30_SFT_RAMP: | ||
137 | case CS53L30_LRCK_CTL1: | ||
138 | case CS53L30_LRCK_CTL2: | ||
139 | case CS53L30_MUTEP_CTL1: | ||
140 | case CS53L30_MUTEP_CTL2: | ||
141 | case CS53L30_INBIAS_CTL1: | ||
142 | case CS53L30_INBIAS_CTL2: | ||
143 | case CS53L30_DMIC1_STR_CTL: | ||
144 | case CS53L30_DMIC2_STR_CTL: | ||
145 | case CS53L30_ADCDMIC1_CTL1: | ||
146 | case CS53L30_ADCDMIC1_CTL2: | ||
147 | case CS53L30_ADC1_CTL3: | ||
148 | case CS53L30_ADC1_NG_CTL: | ||
149 | case CS53L30_ADC1A_AFE_CTL: | ||
150 | case CS53L30_ADC1B_AFE_CTL: | ||
151 | case CS53L30_ADC1A_DIG_VOL: | ||
152 | case CS53L30_ADC1B_DIG_VOL: | ||
153 | case CS53L30_ADCDMIC2_CTL1: | ||
154 | case CS53L30_ADCDMIC2_CTL2: | ||
155 | case CS53L30_ADC2_CTL3: | ||
156 | case CS53L30_ADC2_NG_CTL: | ||
157 | case CS53L30_ADC2A_AFE_CTL: | ||
158 | case CS53L30_ADC2B_AFE_CTL: | ||
159 | case CS53L30_ADC2A_DIG_VOL: | ||
160 | case CS53L30_ADC2B_DIG_VOL: | ||
161 | case CS53L30_INT_MASK: | ||
162 | return true; | ||
163 | default: | ||
164 | return false; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static DECLARE_TLV_DB_SCALE(adc_boost_tlv, 0, 2000, 0); | ||
169 | static DECLARE_TLV_DB_SCALE(adc_ng_boost_tlv, 0, 3000, 0); | ||
170 | static DECLARE_TLV_DB_SCALE(pga_tlv, -600, 50, 0); | ||
171 | static DECLARE_TLV_DB_SCALE(dig_tlv, -9600, 100, 1); | ||
172 | static DECLARE_TLV_DB_SCALE(pga_preamp_tlv, 0, 10000, 0); | ||
173 | |||
174 | static const char * const input1_sel_text[] = { | ||
175 | "DMIC1 On AB In", | ||
176 | "DMIC1 On A In", | ||
177 | "DMIC1 On B In", | ||
178 | "ADC1 On AB In", | ||
179 | "ADC1 On A In", | ||
180 | "ADC1 On B In", | ||
181 | "DMIC1 Off ADC1 Off", | ||
182 | }; | ||
183 | |||
184 | static unsigned int const input1_sel_values[] = { | ||
185 | CS53L30_CH_TYPE, | ||
186 | CS53L30_ADCxB_PDN | CS53L30_CH_TYPE, | ||
187 | CS53L30_ADCxA_PDN | CS53L30_CH_TYPE, | ||
188 | CS53L30_DMICx_PDN, | ||
189 | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, | ||
190 | CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN, | ||
191 | CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, | ||
192 | }; | ||
193 | |||
194 | static const char * const input2_sel_text[] = { | ||
195 | "DMIC2 On AB In", | ||
196 | "DMIC2 On A In", | ||
197 | "DMIC2 On B In", | ||
198 | "ADC2 On AB In", | ||
199 | "ADC2 On A In", | ||
200 | "ADC2 On B In", | ||
201 | "DMIC2 Off ADC2 Off", | ||
202 | }; | ||
203 | |||
204 | static unsigned int const input2_sel_values[] = { | ||
205 | 0x0, | ||
206 | CS53L30_ADCxB_PDN, | ||
207 | CS53L30_ADCxA_PDN, | ||
208 | CS53L30_DMICx_PDN, | ||
209 | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, | ||
210 | CS53L30_ADCxA_PDN | CS53L30_DMICx_PDN, | ||
211 | CS53L30_ADCxA_PDN | CS53L30_ADCxB_PDN | CS53L30_DMICx_PDN, | ||
212 | }; | ||
213 | |||
214 | static const char * const input1_route_sel_text[] = { | ||
215 | "ADC1_SEL", "DMIC1_SEL", | ||
216 | }; | ||
217 | |||
218 | static const struct soc_enum input1_route_sel_enum = | ||
219 | SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, CS53L30_CH_TYPE_SHIFT, | ||
220 | ARRAY_SIZE(input1_route_sel_text), | ||
221 | input1_route_sel_text); | ||
222 | |||
223 | static SOC_VALUE_ENUM_SINGLE_DECL(input1_sel_enum, CS53L30_ADCDMIC1_CTL1, 0, | ||
224 | CS53L30_ADCDMICx_PDN_MASK, input1_sel_text, | ||
225 | input1_sel_values); | ||
226 | |||
227 | static const struct snd_kcontrol_new input1_route_sel_mux = | ||
228 | SOC_DAPM_ENUM("Input 1 Route", input1_route_sel_enum); | ||
229 | |||
230 | static const char * const input2_route_sel_text[] = { | ||
231 | "ADC2_SEL", "DMIC2_SEL", | ||
232 | }; | ||
233 | |||
234 | /* Note: CS53L30_ADCDMIC1_CTL1 CH_TYPE controls inputs 1 and 2 */ | ||
235 | static const struct soc_enum input2_route_sel_enum = | ||
236 | SOC_ENUM_SINGLE(CS53L30_ADCDMIC1_CTL1, 0, | ||
237 | ARRAY_SIZE(input2_route_sel_text), | ||
238 | input2_route_sel_text); | ||
239 | |||
240 | static SOC_VALUE_ENUM_SINGLE_DECL(input2_sel_enum, CS53L30_ADCDMIC2_CTL1, 0, | ||
241 | CS53L30_ADCDMICx_PDN_MASK, input2_sel_text, | ||
242 | input2_sel_values); | ||
243 | |||
244 | static const struct snd_kcontrol_new input2_route_sel_mux = | ||
245 | SOC_DAPM_ENUM("Input 2 Route", input2_route_sel_enum); | ||
246 | |||
247 | /* | ||
248 | * TB = 6144*(MCLK(int) scaling factor)/MCLK(internal) | ||
249 | * TB - Time base | ||
250 | * NOTE: If MCLK_INT_SCALE = 0, then TB=1 | ||
251 | */ | ||
252 | static const char * const cs53l30_ng_delay_text[] = { | ||
253 | "TB*50ms", "TB*100ms", "TB*150ms", "TB*200ms", | ||
254 | }; | ||
255 | |||
256 | static const struct soc_enum adc1_ng_delay_enum = | ||
257 | SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT, | ||
258 | ARRAY_SIZE(cs53l30_ng_delay_text), | ||
259 | cs53l30_ng_delay_text); | ||
260 | |||
261 | static const struct soc_enum adc2_ng_delay_enum = | ||
262 | SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_DELAY_SHIFT, | ||
263 | ARRAY_SIZE(cs53l30_ng_delay_text), | ||
264 | cs53l30_ng_delay_text); | ||
265 | |||
266 | /* The noise gate threshold selected will depend on NG Boost */ | ||
267 | static const char * const cs53l30_ng_thres_text[] = { | ||
268 | "-64dB/-34dB", "-66dB/-36dB", "-70dB/-40dB", "-73dB/-43dB", | ||
269 | "-76dB/-46dB", "-82dB/-52dB", "-58dB", "-64dB", | ||
270 | }; | ||
271 | |||
272 | static const struct soc_enum adc1_ng_thres_enum = | ||
273 | SOC_ENUM_SINGLE(CS53L30_ADC1_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT, | ||
274 | ARRAY_SIZE(cs53l30_ng_thres_text), | ||
275 | cs53l30_ng_thres_text); | ||
276 | |||
277 | static const struct soc_enum adc2_ng_thres_enum = | ||
278 | SOC_ENUM_SINGLE(CS53L30_ADC2_NG_CTL, CS53L30_ADCx_NG_THRESH_SHIFT, | ||
279 | ARRAY_SIZE(cs53l30_ng_thres_text), | ||
280 | cs53l30_ng_thres_text); | ||
281 | |||
282 | /* Corner frequencies are with an Fs of 48kHz. */ | ||
283 | static const char * const hpf_corner_freq_text[] = { | ||
284 | "1.86Hz", "120Hz", "235Hz", "466Hz", | ||
285 | }; | ||
286 | |||
287 | static const struct soc_enum adc1_hpf_enum = | ||
288 | SOC_ENUM_SINGLE(CS53L30_ADC1_CTL3, CS53L30_ADCx_HPF_CF_SHIFT, | ||
289 | ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text); | ||
290 | |||
291 | static const struct soc_enum adc2_hpf_enum = | ||
292 | SOC_ENUM_SINGLE(CS53L30_ADC2_CTL3, CS53L30_ADCx_HPF_CF_SHIFT, | ||
293 | ARRAY_SIZE(hpf_corner_freq_text), hpf_corner_freq_text); | ||
294 | |||
295 | static const struct snd_kcontrol_new cs53l30_snd_controls[] = { | ||
296 | SOC_SINGLE("Digital Soft-Ramp Switch", CS53L30_SFT_RAMP, | ||
297 | CS53L30_DIGSFT_SHIFT, 1, 0), | ||
298 | SOC_SINGLE("ADC1 Noise Gate Ganging Switch", CS53L30_ADC1_CTL3, | ||
299 | CS53L30_ADCx_NG_ALL_SHIFT, 1, 0), | ||
300 | SOC_SINGLE("ADC2 Noise Gate Ganging Switch", CS53L30_ADC2_CTL3, | ||
301 | CS53L30_ADCx_NG_ALL_SHIFT, 1, 0), | ||
302 | SOC_SINGLE("ADC1A Noise Gate Enable Switch", CS53L30_ADC1_NG_CTL, | ||
303 | CS53L30_ADCxA_NG_SHIFT, 1, 0), | ||
304 | SOC_SINGLE("ADC1B Noise Gate Enable Switch", CS53L30_ADC1_NG_CTL, | ||
305 | CS53L30_ADCxB_NG_SHIFT, 1, 0), | ||
306 | SOC_SINGLE("ADC2A Noise Gate Enable Switch", CS53L30_ADC2_NG_CTL, | ||
307 | CS53L30_ADCxA_NG_SHIFT, 1, 0), | ||
308 | SOC_SINGLE("ADC2B Noise Gate Enable Switch", CS53L30_ADC2_NG_CTL, | ||
309 | CS53L30_ADCxB_NG_SHIFT, 1, 0), | ||
310 | SOC_SINGLE("ADC1 Notch Filter Switch", CS53L30_ADCDMIC1_CTL2, | ||
311 | CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1), | ||
312 | SOC_SINGLE("ADC2 Notch Filter Switch", CS53L30_ADCDMIC2_CTL2, | ||
313 | CS53L30_ADCx_NOTCH_DIS_SHIFT, 1, 1), | ||
314 | SOC_SINGLE("ADC1A Invert Switch", CS53L30_ADCDMIC1_CTL2, | ||
315 | CS53L30_ADCxA_INV_SHIFT, 1, 0), | ||
316 | SOC_SINGLE("ADC1B Invert Switch", CS53L30_ADCDMIC1_CTL2, | ||
317 | CS53L30_ADCxB_INV_SHIFT, 1, 0), | ||
318 | SOC_SINGLE("ADC2A Invert Switch", CS53L30_ADCDMIC2_CTL2, | ||
319 | CS53L30_ADCxA_INV_SHIFT, 1, 0), | ||
320 | SOC_SINGLE("ADC2B Invert Switch", CS53L30_ADCDMIC2_CTL2, | ||
321 | CS53L30_ADCxB_INV_SHIFT, 1, 0), | ||
322 | |||
323 | SOC_SINGLE_TLV("ADC1A Digital Boost Volume", CS53L30_ADCDMIC1_CTL2, | ||
324 | CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), | ||
325 | SOC_SINGLE_TLV("ADC1B Digital Boost Volume", CS53L30_ADCDMIC1_CTL2, | ||
326 | CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), | ||
327 | SOC_SINGLE_TLV("ADC2A Digital Boost Volume", CS53L30_ADCDMIC2_CTL2, | ||
328 | CS53L30_ADCxA_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), | ||
329 | SOC_SINGLE_TLV("ADC2B Digital Boost Volume", CS53L30_ADCDMIC2_CTL2, | ||
330 | CS53L30_ADCxB_DIG_BOOST_SHIFT, 1, 0, adc_boost_tlv), | ||
331 | SOC_SINGLE_TLV("ADC1 NG Boost Volume", CS53L30_ADC1_NG_CTL, | ||
332 | CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv), | ||
333 | SOC_SINGLE_TLV("ADC2 NG Boost Volume", CS53L30_ADC2_NG_CTL, | ||
334 | CS53L30_ADCx_NG_BOOST_SHIFT, 1, 0, adc_ng_boost_tlv), | ||
335 | |||
336 | SOC_DOUBLE_R_TLV("ADC1 Preamplifier Volume", CS53L30_ADC1A_AFE_CTL, | ||
337 | CS53L30_ADC1B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT, | ||
338 | 2, 0, pga_preamp_tlv), | ||
339 | SOC_DOUBLE_R_TLV("ADC2 Preamplifier Volume", CS53L30_ADC2A_AFE_CTL, | ||
340 | CS53L30_ADC2B_AFE_CTL, CS53L30_ADCxy_PREAMP_SHIFT, | ||
341 | 2, 0, pga_preamp_tlv), | ||
342 | |||
343 | SOC_ENUM("Input 1 Channel Select", input1_sel_enum), | ||
344 | SOC_ENUM("Input 2 Channel Select", input2_sel_enum), | ||
345 | |||
346 | SOC_ENUM("ADC1 HPF Select", adc1_hpf_enum), | ||
347 | SOC_ENUM("ADC2 HPF Select", adc2_hpf_enum), | ||
348 | SOC_ENUM("ADC1 NG Threshold", adc1_ng_thres_enum), | ||
349 | SOC_ENUM("ADC2 NG Threshold", adc2_ng_thres_enum), | ||
350 | SOC_ENUM("ADC1 NG Delay", adc1_ng_delay_enum), | ||
351 | SOC_ENUM("ADC2 NG Delay", adc2_ng_delay_enum), | ||
352 | |||
353 | SOC_SINGLE_SX_TLV("ADC1A PGA Volume", | ||
354 | CS53L30_ADC1A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), | ||
355 | SOC_SINGLE_SX_TLV("ADC1B PGA Volume", | ||
356 | CS53L30_ADC1B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), | ||
357 | SOC_SINGLE_SX_TLV("ADC2A PGA Volume", | ||
358 | CS53L30_ADC2A_AFE_CTL, 0, 0x34, 0x18, pga_tlv), | ||
359 | SOC_SINGLE_SX_TLV("ADC2B PGA Volume", | ||
360 | CS53L30_ADC2B_AFE_CTL, 0, 0x34, 0x18, pga_tlv), | ||
361 | |||
362 | SOC_SINGLE_SX_TLV("ADC1A Digital Volume", | ||
363 | CS53L30_ADC1A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), | ||
364 | SOC_SINGLE_SX_TLV("ADC1B Digital Volume", | ||
365 | CS53L30_ADC1B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), | ||
366 | SOC_SINGLE_SX_TLV("ADC2A Digital Volume", | ||
367 | CS53L30_ADC2A_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), | ||
368 | SOC_SINGLE_SX_TLV("ADC2B Digital Volume", | ||
369 | CS53L30_ADC2B_DIG_VOL, 0, 0xA0, 0x0C, dig_tlv), | ||
370 | }; | ||
371 | |||
372 | static const struct snd_soc_dapm_widget cs53l30_dapm_widgets[] = { | ||
373 | SND_SOC_DAPM_INPUT("IN1_DMIC1"), | ||
374 | SND_SOC_DAPM_INPUT("IN2"), | ||
375 | SND_SOC_DAPM_INPUT("IN3_DMIC2"), | ||
376 | SND_SOC_DAPM_INPUT("IN4"), | ||
377 | SND_SOC_DAPM_SUPPLY("MIC1 Bias", CS53L30_MICBIAS_CTL, | ||
378 | CS53L30_MIC1_BIAS_PDN_SHIFT, 1, NULL, 0), | ||
379 | SND_SOC_DAPM_SUPPLY("MIC2 Bias", CS53L30_MICBIAS_CTL, | ||
380 | CS53L30_MIC2_BIAS_PDN_SHIFT, 1, NULL, 0), | ||
381 | SND_SOC_DAPM_SUPPLY("MIC3 Bias", CS53L30_MICBIAS_CTL, | ||
382 | CS53L30_MIC3_BIAS_PDN_SHIFT, 1, NULL, 0), | ||
383 | SND_SOC_DAPM_SUPPLY("MIC4 Bias", CS53L30_MICBIAS_CTL, | ||
384 | CS53L30_MIC4_BIAS_PDN_SHIFT, 1, NULL, 0), | ||
385 | |||
386 | SND_SOC_DAPM_AIF_OUT("ASP_SDOUT1", NULL, 0, CS53L30_ASP_CTL1, | ||
387 | CS53L30_ASP_SDOUTx_PDN_SHIFT, 1), | ||
388 | SND_SOC_DAPM_AIF_OUT("ASP_SDOUT2", NULL, 0, CS53L30_ASP_CTL2, | ||
389 | CS53L30_ASP_SDOUTx_PDN_SHIFT, 1), | ||
390 | |||
391 | SND_SOC_DAPM_MUX("Input Mux 1", SND_SOC_NOPM, 0, 0, | ||
392 | &input1_route_sel_mux), | ||
393 | SND_SOC_DAPM_MUX("Input Mux 2", SND_SOC_NOPM, 0, 0, | ||
394 | &input2_route_sel_mux), | ||
395 | |||
396 | SND_SOC_DAPM_ADC("ADC1A", NULL, CS53L30_ADCDMIC1_CTL1, | ||
397 | CS53L30_ADCxA_PDN_SHIFT, 1), | ||
398 | SND_SOC_DAPM_ADC("ADC1B", NULL, CS53L30_ADCDMIC1_CTL1, | ||
399 | CS53L30_ADCxB_PDN_SHIFT, 1), | ||
400 | SND_SOC_DAPM_ADC("ADC2A", NULL, CS53L30_ADCDMIC2_CTL1, | ||
401 | CS53L30_ADCxA_PDN_SHIFT, 1), | ||
402 | SND_SOC_DAPM_ADC("ADC2B", NULL, CS53L30_ADCDMIC2_CTL1, | ||
403 | CS53L30_ADCxB_PDN_SHIFT, 1), | ||
404 | SND_SOC_DAPM_ADC("DMIC1", NULL, CS53L30_ADCDMIC1_CTL1, | ||
405 | CS53L30_DMICx_PDN_SHIFT, 1), | ||
406 | SND_SOC_DAPM_ADC("DMIC2", NULL, CS53L30_ADCDMIC2_CTL1, | ||
407 | CS53L30_DMICx_PDN_SHIFT, 1), | ||
408 | }; | ||
409 | |||
410 | static const struct snd_soc_dapm_route cs53l30_dapm_routes[] = { | ||
411 | /* ADC Input Paths */ | ||
412 | {"ADC1A", NULL, "IN1_DMIC1"}, | ||
413 | {"Input Mux 1", "ADC1_SEL", "ADC1A"}, | ||
414 | {"ADC1B", NULL, "IN2"}, | ||
415 | |||
416 | {"ADC2A", NULL, "IN3_DMIC2"}, | ||
417 | {"Input Mux 2", "ADC2_SEL", "ADC2A"}, | ||
418 | {"ADC2B", NULL, "IN4"}, | ||
419 | |||
420 | /* MIC Bias Paths */ | ||
421 | {"ADC1A", NULL, "MIC1 Bias"}, | ||
422 | {"ADC1B", NULL, "MIC2 Bias"}, | ||
423 | {"ADC2A", NULL, "MIC3 Bias"}, | ||
424 | {"ADC2B", NULL, "MIC4 Bias"}, | ||
425 | |||
426 | /* DMIC Paths */ | ||
427 | {"DMIC1", NULL, "IN1_DMIC1"}, | ||
428 | {"Input Mux 1", "DMIC1_SEL", "DMIC1"}, | ||
429 | |||
430 | {"DMIC2", NULL, "IN3_DMIC2"}, | ||
431 | {"Input Mux 2", "DMIC2_SEL", "DMIC2"}, | ||
432 | }; | ||
433 | |||
434 | static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout1[] = { | ||
435 | /* Output Paths when using SDOUT1 only */ | ||
436 | {"ASP_SDOUT1", NULL, "ADC1A" }, | ||
437 | {"ASP_SDOUT1", NULL, "Input Mux 1"}, | ||
438 | {"ASP_SDOUT1", NULL, "ADC1B"}, | ||
439 | |||
440 | {"ASP_SDOUT1", NULL, "ADC2A"}, | ||
441 | {"ASP_SDOUT1", NULL, "Input Mux 2"}, | ||
442 | {"ASP_SDOUT1", NULL, "ADC2B"}, | ||
443 | |||
444 | {"Capture", NULL, "ASP_SDOUT1"}, | ||
445 | }; | ||
446 | |||
447 | static const struct snd_soc_dapm_route cs53l30_dapm_routes_sdout2[] = { | ||
448 | /* Output Paths when using both SDOUT1 and SDOUT2 */ | ||
449 | {"ASP_SDOUT1", NULL, "ADC1A" }, | ||
450 | {"ASP_SDOUT1", NULL, "Input Mux 1"}, | ||
451 | {"ASP_SDOUT1", NULL, "ADC1B"}, | ||
452 | |||
453 | {"ASP_SDOUT2", NULL, "ADC2A"}, | ||
454 | {"ASP_SDOUT2", NULL, "Input Mux 2"}, | ||
455 | {"ASP_SDOUT2", NULL, "ADC2B"}, | ||
456 | |||
457 | {"Capture", NULL, "ASP_SDOUT1"}, | ||
458 | {"Capture", NULL, "ASP_SDOUT2"}, | ||
459 | }; | ||
460 | |||
461 | struct cs53l30_mclk_div { | ||
462 | u32 mclk_rate; | ||
463 | u32 srate; | ||
464 | u8 asp_rate; | ||
465 | u8 internal_fs_ratio; | ||
466 | u8 mclk_int_scale; | ||
467 | }; | ||
468 | |||
469 | static struct cs53l30_mclk_div cs53l30_mclk_coeffs[] = { | ||
470 | /* NOTE: Enable MCLK_INT_SCALE to save power. */ | ||
471 | |||
472 | /* MCLK, Sample Rate, asp_rate, internal_fs_ratio, mclk_int_scale */ | ||
473 | {5644800, 11025, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
474 | {5644800, 22050, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
475 | {5644800, 44100, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
476 | |||
477 | {6000000, 8000, 0x1, 0, CS53L30_MCLK_INT_SCALE}, | ||
478 | {6000000, 11025, 0x2, 0, CS53L30_MCLK_INT_SCALE}, | ||
479 | {6000000, 12000, 0x4, 0, CS53L30_MCLK_INT_SCALE}, | ||
480 | {6000000, 16000, 0x5, 0, CS53L30_MCLK_INT_SCALE}, | ||
481 | {6000000, 22050, 0x6, 0, CS53L30_MCLK_INT_SCALE}, | ||
482 | {6000000, 24000, 0x8, 0, CS53L30_MCLK_INT_SCALE}, | ||
483 | {6000000, 32000, 0x9, 0, CS53L30_MCLK_INT_SCALE}, | ||
484 | {6000000, 44100, 0xA, 0, CS53L30_MCLK_INT_SCALE}, | ||
485 | {6000000, 48000, 0xC, 0, CS53L30_MCLK_INT_SCALE}, | ||
486 | |||
487 | {6144000, 8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
488 | {6144000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
489 | {6144000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
490 | {6144000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
491 | {6144000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
492 | {6144000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
493 | {6144000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
494 | {6144000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
495 | {6144000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
496 | |||
497 | {6400000, 8000, 0x1, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
498 | {6400000, 11025, 0x2, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
499 | {6400000, 12000, 0x4, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
500 | {6400000, 16000, 0x5, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
501 | {6400000, 22050, 0x6, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
502 | {6400000, 24000, 0x8, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
503 | {6400000, 32000, 0x9, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
504 | {6400000, 44100, 0xA, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
505 | {6400000, 48000, 0xC, CS53L30_INTRNL_FS_RATIO, CS53L30_MCLK_INT_SCALE}, | ||
506 | }; | ||
507 | |||
508 | struct cs53l30_mclkx_div { | ||
509 | u32 mclkx; | ||
510 | u8 ratio; | ||
511 | u8 mclkdiv; | ||
512 | }; | ||
513 | |||
514 | static struct cs53l30_mclkx_div cs53l30_mclkx_coeffs[] = { | ||
515 | {5644800, 1, CS53L30_MCLK_DIV_BY_1}, | ||
516 | {6000000, 1, CS53L30_MCLK_DIV_BY_1}, | ||
517 | {6144000, 1, CS53L30_MCLK_DIV_BY_1}, | ||
518 | {11289600, 2, CS53L30_MCLK_DIV_BY_2}, | ||
519 | {12288000, 2, CS53L30_MCLK_DIV_BY_2}, | ||
520 | {12000000, 2, CS53L30_MCLK_DIV_BY_2}, | ||
521 | {19200000, 3, CS53L30_MCLK_DIV_BY_3}, | ||
522 | }; | ||
523 | |||
524 | static int cs53l30_get_mclkx_coeff(int mclkx) | ||
525 | { | ||
526 | int i; | ||
527 | |||
528 | for (i = 0; i < ARRAY_SIZE(cs53l30_mclkx_coeffs); i++) { | ||
529 | if (cs53l30_mclkx_coeffs[i].mclkx == mclkx) | ||
530 | return i; | ||
531 | } | ||
532 | |||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | static int cs53l30_get_mclk_coeff(int mclk_rate, int srate) | ||
537 | { | ||
538 | int i; | ||
539 | |||
540 | for (i = 0; i < ARRAY_SIZE(cs53l30_mclk_coeffs); i++) { | ||
541 | if (cs53l30_mclk_coeffs[i].mclk_rate == mclk_rate && | ||
542 | cs53l30_mclk_coeffs[i].srate == srate) | ||
543 | return i; | ||
544 | } | ||
545 | |||
546 | return -EINVAL; | ||
547 | } | ||
548 | |||
549 | static int cs53l30_set_sysclk(struct snd_soc_dai *dai, | ||
550 | int clk_id, unsigned int freq, int dir) | ||
551 | { | ||
552 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
553 | int mclkx_coeff; | ||
554 | u32 mclk_rate; | ||
555 | |||
556 | /* MCLKX -> MCLK */ | ||
557 | mclkx_coeff = cs53l30_get_mclkx_coeff(freq); | ||
558 | if (mclkx_coeff < 0) | ||
559 | return mclkx_coeff; | ||
560 | |||
561 | mclk_rate = cs53l30_mclkx_coeffs[mclkx_coeff].mclkx / | ||
562 | cs53l30_mclkx_coeffs[mclkx_coeff].ratio; | ||
563 | |||
564 | regmap_update_bits(priv->regmap, CS53L30_MCLKCTL, | ||
565 | CS53L30_MCLK_DIV_MASK, | ||
566 | cs53l30_mclkx_coeffs[mclkx_coeff].mclkdiv); | ||
567 | |||
568 | priv->mclk_rate = mclk_rate; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
574 | { | ||
575 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
576 | u8 aspcfg = 0, aspctl1 = 0; | ||
577 | |||
578 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
579 | case SND_SOC_DAIFMT_CBM_CFM: | ||
580 | aspcfg |= CS53L30_ASP_MS; | ||
581 | break; | ||
582 | case SND_SOC_DAIFMT_CBS_CFS: | ||
583 | break; | ||
584 | default: | ||
585 | return -EINVAL; | ||
586 | } | ||
587 | |||
588 | /* DAI mode */ | ||
589 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
590 | case SND_SOC_DAIFMT_I2S: | ||
591 | /* Set TDM_PDN to turn off TDM mode -- Reset default */ | ||
592 | aspctl1 |= CS53L30_ASP_TDM_PDN; | ||
593 | break; | ||
594 | case SND_SOC_DAIFMT_DSP_A: | ||
595 | /* | ||
596 | * Clear TDM_PDN to turn on TDM mode; Use ASP_SCLK_INV = 0 | ||
597 | * with SHIFT_LEFT = 1 combination as Figure 4-13 shows in | ||
598 | * the CS53L30 datasheet | ||
599 | */ | ||
600 | aspctl1 |= CS53L30_SHIFT_LEFT; | ||
601 | break; | ||
602 | default: | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | /* Check to see if the SCLK is inverted */ | ||
607 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
608 | case SND_SOC_DAIFMT_IB_NF: | ||
609 | case SND_SOC_DAIFMT_IB_IF: | ||
610 | aspcfg ^= CS53L30_ASP_SCLK_INV; | ||
611 | break; | ||
612 | default: | ||
613 | break; | ||
614 | } | ||
615 | |||
616 | regmap_update_bits(priv->regmap, CS53L30_ASPCFG_CTL, | ||
617 | CS53L30_ASP_MS | CS53L30_ASP_SCLK_INV, aspcfg); | ||
618 | |||
619 | regmap_update_bits(priv->regmap, CS53L30_ASP_CTL1, | ||
620 | CS53L30_ASP_TDM_PDN | CS53L30_SHIFT_LEFT, aspctl1); | ||
621 | |||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static int cs53l30_pcm_hw_params(struct snd_pcm_substream *substream, | ||
626 | struct snd_pcm_hw_params *params, | ||
627 | struct snd_soc_dai *dai) | ||
628 | { | ||
629 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
630 | int srate = params_rate(params); | ||
631 | int mclk_coeff; | ||
632 | |||
633 | /* MCLK -> srate */ | ||
634 | mclk_coeff = cs53l30_get_mclk_coeff(priv->mclk_rate, srate); | ||
635 | if (mclk_coeff < 0) | ||
636 | return -EINVAL; | ||
637 | |||
638 | regmap_update_bits(priv->regmap, CS53L30_INT_SR_CTL, | ||
639 | CS53L30_INTRNL_FS_RATIO_MASK, | ||
640 | cs53l30_mclk_coeffs[mclk_coeff].internal_fs_ratio); | ||
641 | |||
642 | regmap_update_bits(priv->regmap, CS53L30_MCLKCTL, | ||
643 | CS53L30_MCLK_INT_SCALE_MASK, | ||
644 | cs53l30_mclk_coeffs[mclk_coeff].mclk_int_scale); | ||
645 | |||
646 | regmap_update_bits(priv->regmap, CS53L30_ASPCFG_CTL, | ||
647 | CS53L30_ASP_RATE_MASK, | ||
648 | cs53l30_mclk_coeffs[mclk_coeff].asp_rate); | ||
649 | |||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int cs53l30_set_bias_level(struct snd_soc_codec *codec, | ||
654 | enum snd_soc_bias_level level) | ||
655 | { | ||
656 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
657 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(codec); | ||
658 | unsigned int reg; | ||
659 | int i, inter_max_check, ret; | ||
660 | |||
661 | switch (level) { | ||
662 | case SND_SOC_BIAS_ON: | ||
663 | break; | ||
664 | case SND_SOC_BIAS_PREPARE: | ||
665 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) | ||
666 | regmap_update_bits(priv->regmap, CS53L30_PWRCTL, | ||
667 | CS53L30_PDN_LP_MASK, 0); | ||
668 | break; | ||
669 | case SND_SOC_BIAS_STANDBY: | ||
670 | if (dapm->bias_level == SND_SOC_BIAS_OFF) { | ||
671 | ret = clk_prepare_enable(priv->mclk); | ||
672 | if (ret) { | ||
673 | dev_err(codec->dev, | ||
674 | "failed to enable MCLK: %d\n", ret); | ||
675 | return ret; | ||
676 | } | ||
677 | regmap_update_bits(priv->regmap, CS53L30_MCLKCTL, | ||
678 | CS53L30_MCLK_DIS_MASK, 0); | ||
679 | regmap_update_bits(priv->regmap, CS53L30_PWRCTL, | ||
680 | CS53L30_PDN_ULP_MASK, 0); | ||
681 | msleep(50); | ||
682 | } else { | ||
683 | regmap_update_bits(priv->regmap, CS53L30_PWRCTL, | ||
684 | CS53L30_PDN_ULP_MASK, | ||
685 | CS53L30_PDN_ULP); | ||
686 | } | ||
687 | break; | ||
688 | case SND_SOC_BIAS_OFF: | ||
689 | regmap_update_bits(priv->regmap, CS53L30_INT_MASK, | ||
690 | CS53L30_PDN_DONE, 0); | ||
691 | /* | ||
692 | * If digital softramp is set, the amount of time required | ||
693 | * for power down increases and depends on the digital | ||
694 | * volume setting. | ||
695 | */ | ||
696 | |||
697 | /* Set the max possible time if digsft is set */ | ||
698 | regmap_read(priv->regmap, CS53L30_SFT_RAMP, ®); | ||
699 | if (reg & CS53L30_DIGSFT_MASK) | ||
700 | inter_max_check = CS53L30_PDN_POLL_MAX; | ||
701 | else | ||
702 | inter_max_check = 10; | ||
703 | |||
704 | regmap_update_bits(priv->regmap, CS53L30_PWRCTL, | ||
705 | CS53L30_PDN_ULP_MASK, | ||
706 | CS53L30_PDN_ULP); | ||
707 | /* PDN_DONE will take a min of 20ms to be set.*/ | ||
708 | msleep(20); | ||
709 | /* Clr status */ | ||
710 | regmap_read(priv->regmap, CS53L30_IS, ®); | ||
711 | for (i = 0; i < inter_max_check; i++) { | ||
712 | if (inter_max_check < 10) { | ||
713 | usleep_range(1000, 1100); | ||
714 | regmap_read(priv->regmap, CS53L30_IS, ®); | ||
715 | if (reg & CS53L30_PDN_DONE) | ||
716 | break; | ||
717 | } else { | ||
718 | usleep_range(10000, 10100); | ||
719 | regmap_read(priv->regmap, CS53L30_IS, ®); | ||
720 | if (reg & CS53L30_PDN_DONE) | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | /* PDN_DONE is set. We now can disable the MCLK */ | ||
725 | regmap_update_bits(priv->regmap, CS53L30_INT_MASK, | ||
726 | CS53L30_PDN_DONE, CS53L30_PDN_DONE); | ||
727 | regmap_update_bits(priv->regmap, CS53L30_MCLKCTL, | ||
728 | CS53L30_MCLK_DIS_MASK, | ||
729 | CS53L30_MCLK_DIS); | ||
730 | clk_disable_unprepare(priv->mclk); | ||
731 | break; | ||
732 | } | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static int cs53l30_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
738 | { | ||
739 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
740 | u8 val = tristate ? CS53L30_ASP_3ST : 0; | ||
741 | |||
742 | return regmap_update_bits(priv->regmap, CS53L30_ASP_CTL1, | ||
743 | CS53L30_ASP_3ST_MASK, val); | ||
744 | } | ||
745 | |||
746 | static unsigned int const cs53l30_src_rates[] = { | ||
747 | 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 | ||
748 | }; | ||
749 | |||
750 | static struct snd_pcm_hw_constraint_list src_constraints = { | ||
751 | .count = ARRAY_SIZE(cs53l30_src_rates), | ||
752 | .list = cs53l30_src_rates, | ||
753 | }; | ||
754 | |||
755 | static int cs53l30_pcm_startup(struct snd_pcm_substream *substream, | ||
756 | struct snd_soc_dai *dai) | ||
757 | { | ||
758 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
759 | SNDRV_PCM_HW_PARAM_RATE, &src_constraints); | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * Note: CS53L30 counts the slot number per byte while ASoC counts the slot | ||
766 | * number per slot_width. So there is a difference between the slots of ASoC | ||
767 | * and the slots of CS53L30. | ||
768 | */ | ||
769 | static int cs53l30_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
770 | unsigned int tx_mask, unsigned int rx_mask, | ||
771 | int slots, int slot_width) | ||
772 | { | ||
773 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
774 | unsigned int loc[CS53L30_TDM_SLOT_MAX] = {48, 48, 48, 48}; | ||
775 | unsigned int slot_next, slot_step; | ||
776 | u64 tx_enable = 0; | ||
777 | int i; | ||
778 | |||
779 | if (!rx_mask) { | ||
780 | dev_err(dai->dev, "rx masks must not be 0\n"); | ||
781 | return -EINVAL; | ||
782 | } | ||
783 | |||
784 | /* Assuming slot_width is not supposed to be greater than 64 */ | ||
785 | if (slots <= 0 || slot_width <= 0 || slot_width > 64) { | ||
786 | dev_err(dai->dev, "invalid slot number or slot width\n"); | ||
787 | return -EINVAL; | ||
788 | } | ||
789 | |||
790 | if (slot_width & 0x7) { | ||
791 | dev_err(dai->dev, "slot width must count in byte\n"); | ||
792 | return -EINVAL; | ||
793 | } | ||
794 | |||
795 | /* How many bytes in each ASoC slot */ | ||
796 | slot_step = slot_width >> 3; | ||
797 | |||
798 | for (i = 0; rx_mask && i < CS53L30_TDM_SLOT_MAX; i++) { | ||
799 | /* Find the first slot from LSB */ | ||
800 | slot_next = __ffs(rx_mask); | ||
801 | /* Save the slot location by converting to CS53L30 slot */ | ||
802 | loc[i] = slot_next * slot_step; | ||
803 | /* Create the mask of CS53L30 slot */ | ||
804 | tx_enable |= (u64)((u64)(1 << slot_step) - 1) << (u64)loc[i]; | ||
805 | /* Clear this slot from rx_mask */ | ||
806 | rx_mask &= ~(1 << slot_next); | ||
807 | } | ||
808 | |||
809 | /* Error out to avoid slot shift */ | ||
810 | if (rx_mask && i == CS53L30_TDM_SLOT_MAX) { | ||
811 | dev_err(dai->dev, "rx_mask exceeds max slot number: %d\n", | ||
812 | CS53L30_TDM_SLOT_MAX); | ||
813 | return -EINVAL; | ||
814 | } | ||
815 | |||
816 | /* Validate the last active CS53L30 slot */ | ||
817 | slot_next = loc[i - 1] + slot_step - 1; | ||
818 | if (slot_next > 47) { | ||
819 | dev_err(dai->dev, "slot selection out of bounds: %u\n", | ||
820 | slot_next); | ||
821 | return -EINVAL; | ||
822 | } | ||
823 | |||
824 | for (i = 0; i < CS53L30_TDM_SLOT_MAX && loc[i] != 48; i++) { | ||
825 | regmap_update_bits(priv->regmap, CS53L30_ASP_TDMTX_CTL(i), | ||
826 | CS53L30_ASP_CHx_TX_LOC_MASK, loc[i]); | ||
827 | dev_dbg(dai->dev, "loc[%d]=%x\n", i, loc[i]); | ||
828 | } | ||
829 | |||
830 | for (i = 0; i < CS53L30_ASP_TDMTX_ENx_MAX && tx_enable; i++) { | ||
831 | regmap_write(priv->regmap, CS53L30_ASP_TDMTX_ENx(i), | ||
832 | tx_enable & 0xff); | ||
833 | tx_enable >>= 8; | ||
834 | dev_dbg(dai->dev, "en_reg=%x, tx_enable=%llx\n", | ||
835 | CS53L30_ASP_TDMTX_ENx(i), tx_enable & 0xff); | ||
836 | } | ||
837 | |||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | static int cs53l30_mute_stream(struct snd_soc_dai *dai, int mute, int stream) | ||
842 | { | ||
843 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(dai->codec); | ||
844 | |||
845 | if (priv->mute_gpio) | ||
846 | gpiod_set_value_cansleep(priv->mute_gpio, mute); | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | /* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ | ||
852 | #define CS53L30_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) | ||
853 | |||
854 | #define CS53L30_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
855 | SNDRV_PCM_FMTBIT_S24_LE) | ||
856 | |||
857 | static const struct snd_soc_dai_ops cs53l30_ops = { | ||
858 | .startup = cs53l30_pcm_startup, | ||
859 | .hw_params = cs53l30_pcm_hw_params, | ||
860 | .set_fmt = cs53l30_set_dai_fmt, | ||
861 | .set_sysclk = cs53l30_set_sysclk, | ||
862 | .set_tristate = cs53l30_set_tristate, | ||
863 | .set_tdm_slot = cs53l30_set_dai_tdm_slot, | ||
864 | .mute_stream = cs53l30_mute_stream, | ||
865 | }; | ||
866 | |||
867 | static struct snd_soc_dai_driver cs53l30_dai = { | ||
868 | .name = "cs53l30", | ||
869 | .capture = { | ||
870 | .stream_name = "Capture", | ||
871 | .channels_min = 1, | ||
872 | .channels_max = 4, | ||
873 | .rates = CS53L30_RATES, | ||
874 | .formats = CS53L30_FORMATS, | ||
875 | }, | ||
876 | .ops = &cs53l30_ops, | ||
877 | .symmetric_rates = 1, | ||
878 | }; | ||
879 | |||
880 | static int cs53l30_codec_probe(struct snd_soc_codec *codec) | ||
881 | { | ||
882 | struct cs53l30_private *priv = snd_soc_codec_get_drvdata(codec); | ||
883 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
884 | |||
885 | if (priv->use_sdout2) | ||
886 | snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout2, | ||
887 | ARRAY_SIZE(cs53l30_dapm_routes_sdout2)); | ||
888 | else | ||
889 | snd_soc_dapm_add_routes(dapm, cs53l30_dapm_routes_sdout1, | ||
890 | ARRAY_SIZE(cs53l30_dapm_routes_sdout1)); | ||
891 | |||
892 | return 0; | ||
893 | } | ||
894 | |||
895 | static struct snd_soc_codec_driver cs53l30_driver = { | ||
896 | .probe = cs53l30_codec_probe, | ||
897 | .set_bias_level = cs53l30_set_bias_level, | ||
898 | .idle_bias_off = true, | ||
899 | |||
900 | .dapm_widgets = cs53l30_dapm_widgets, | ||
901 | .num_dapm_widgets = ARRAY_SIZE(cs53l30_dapm_widgets), | ||
902 | .dapm_routes = cs53l30_dapm_routes, | ||
903 | .num_dapm_routes = ARRAY_SIZE(cs53l30_dapm_routes), | ||
904 | |||
905 | .controls = cs53l30_snd_controls, | ||
906 | .num_controls = ARRAY_SIZE(cs53l30_snd_controls), | ||
907 | }; | ||
908 | |||
909 | static struct regmap_config cs53l30_regmap = { | ||
910 | .reg_bits = 8, | ||
911 | .val_bits = 8, | ||
912 | |||
913 | .max_register = CS53L30_MAX_REGISTER, | ||
914 | .reg_defaults = cs53l30_reg_defaults, | ||
915 | .num_reg_defaults = ARRAY_SIZE(cs53l30_reg_defaults), | ||
916 | .volatile_reg = cs53l30_volatile_register, | ||
917 | .writeable_reg = cs53l30_writeable_register, | ||
918 | .readable_reg = cs53l30_readable_register, | ||
919 | .cache_type = REGCACHE_RBTREE, | ||
920 | }; | ||
921 | |||
922 | static int cs53l30_i2c_probe(struct i2c_client *client, | ||
923 | const struct i2c_device_id *id) | ||
924 | { | ||
925 | const struct device_node *np = client->dev.of_node; | ||
926 | struct device *dev = &client->dev; | ||
927 | struct cs53l30_private *cs53l30; | ||
928 | unsigned int devid = 0; | ||
929 | unsigned int reg; | ||
930 | int ret = 0, i; | ||
931 | u8 val; | ||
932 | |||
933 | cs53l30 = devm_kzalloc(dev, sizeof(*cs53l30), GFP_KERNEL); | ||
934 | if (!cs53l30) | ||
935 | return -ENOMEM; | ||
936 | |||
937 | for (i = 0; i < ARRAY_SIZE(cs53l30->supplies); i++) | ||
938 | cs53l30->supplies[i].supply = cs53l30_supply_names[i]; | ||
939 | |||
940 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(cs53l30->supplies), | ||
941 | cs53l30->supplies); | ||
942 | if (ret) { | ||
943 | dev_err(dev, "failed to get supplies: %d\n", ret); | ||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies), | ||
948 | cs53l30->supplies); | ||
949 | if (ret) { | ||
950 | dev_err(dev, "failed to enable supplies: %d\n", ret); | ||
951 | return ret; | ||
952 | } | ||
953 | |||
954 | /* Reset the Device */ | ||
955 | cs53l30->reset_gpio = devm_gpiod_get_optional(dev, "reset", | ||
956 | GPIOD_OUT_LOW); | ||
957 | if (IS_ERR(cs53l30->reset_gpio)) { | ||
958 | ret = PTR_ERR(cs53l30->reset_gpio); | ||
959 | goto error; | ||
960 | } | ||
961 | |||
962 | if (cs53l30->reset_gpio) | ||
963 | gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); | ||
964 | |||
965 | i2c_set_clientdata(client, cs53l30); | ||
966 | |||
967 | cs53l30->mclk_rate = 0; | ||
968 | |||
969 | cs53l30->regmap = devm_regmap_init_i2c(client, &cs53l30_regmap); | ||
970 | if (IS_ERR(cs53l30->regmap)) { | ||
971 | ret = PTR_ERR(cs53l30->regmap); | ||
972 | dev_err(dev, "regmap_init() failed: %d\n", ret); | ||
973 | goto error; | ||
974 | } | ||
975 | |||
976 | /* Initialize codec */ | ||
977 | ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_AB, ®); | ||
978 | devid = reg << 12; | ||
979 | |||
980 | ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_CD, ®); | ||
981 | devid |= reg << 4; | ||
982 | |||
983 | ret = regmap_read(cs53l30->regmap, CS53L30_DEVID_E, ®); | ||
984 | devid |= (reg & 0xF0) >> 4; | ||
985 | |||
986 | if (devid != CS53L30_DEVID) { | ||
987 | ret = -ENODEV; | ||
988 | dev_err(dev, "Device ID (%X). Expected %X\n", | ||
989 | devid, CS53L30_DEVID); | ||
990 | goto error; | ||
991 | } | ||
992 | |||
993 | ret = regmap_read(cs53l30->regmap, CS53L30_REVID, ®); | ||
994 | if (ret < 0) { | ||
995 | dev_err(dev, "failed to get Revision ID: %d\n", ret); | ||
996 | goto error; | ||
997 | } | ||
998 | |||
999 | /* Check if MCLK provided */ | ||
1000 | cs53l30->mclk = devm_clk_get(dev, "mclk"); | ||
1001 | if (IS_ERR(cs53l30->mclk)) { | ||
1002 | if (PTR_ERR(cs53l30->mclk) == -EPROBE_DEFER) { | ||
1003 | ret = -EPROBE_DEFER; | ||
1004 | goto error; | ||
1005 | } | ||
1006 | /* Otherwise mark the mclk pointer to NULL */ | ||
1007 | cs53l30->mclk = NULL; | ||
1008 | } | ||
1009 | |||
1010 | /* Fetch the MUTE control */ | ||
1011 | cs53l30->mute_gpio = devm_gpiod_get_optional(dev, "mute", | ||
1012 | GPIOD_OUT_HIGH); | ||
1013 | if (IS_ERR(cs53l30->mute_gpio)) { | ||
1014 | ret = PTR_ERR(cs53l30->mute_gpio); | ||
1015 | goto error; | ||
1016 | } | ||
1017 | |||
1018 | if (cs53l30->mute_gpio) { | ||
1019 | /* Enable MUTE controls via MUTE pin */ | ||
1020 | regmap_write(cs53l30->regmap, CS53L30_MUTEP_CTL1, | ||
1021 | CS53L30_MUTEP_CTL1_MUTEALL); | ||
1022 | /* Flip the polarity of MUTE pin */ | ||
1023 | if (gpiod_is_active_low(cs53l30->mute_gpio)) | ||
1024 | regmap_update_bits(cs53l30->regmap, CS53L30_MUTEP_CTL2, | ||
1025 | CS53L30_MUTE_PIN_POLARITY, 0); | ||
1026 | } | ||
1027 | |||
1028 | if (!of_property_read_u8(np, "cirrus,micbias-lvl", &val)) | ||
1029 | regmap_update_bits(cs53l30->regmap, CS53L30_MICBIAS_CTL, | ||
1030 | CS53L30_MIC_BIAS_CTRL_MASK, val); | ||
1031 | |||
1032 | if (of_property_read_bool(np, "cirrus,use-sdout2")) | ||
1033 | cs53l30->use_sdout2 = true; | ||
1034 | |||
1035 | dev_info(dev, "Cirrus Logic CS53L30, Revision: %02X\n", reg & 0xFF); | ||
1036 | |||
1037 | ret = snd_soc_register_codec(dev, &cs53l30_driver, &cs53l30_dai, 1); | ||
1038 | if (ret) { | ||
1039 | dev_err(dev, "failed to register codec: %d\n", ret); | ||
1040 | goto error; | ||
1041 | } | ||
1042 | |||
1043 | return 0; | ||
1044 | |||
1045 | error: | ||
1046 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), | ||
1047 | cs53l30->supplies); | ||
1048 | return ret; | ||
1049 | } | ||
1050 | |||
1051 | static int cs53l30_i2c_remove(struct i2c_client *client) | ||
1052 | { | ||
1053 | struct cs53l30_private *cs53l30 = i2c_get_clientdata(client); | ||
1054 | |||
1055 | snd_soc_unregister_codec(&client->dev); | ||
1056 | |||
1057 | /* Hold down reset */ | ||
1058 | if (cs53l30->reset_gpio) | ||
1059 | gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); | ||
1060 | |||
1061 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), | ||
1062 | cs53l30->supplies); | ||
1063 | |||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | #ifdef CONFIG_PM | ||
1068 | static int cs53l30_runtime_suspend(struct device *dev) | ||
1069 | { | ||
1070 | struct cs53l30_private *cs53l30 = dev_get_drvdata(dev); | ||
1071 | |||
1072 | regcache_cache_only(cs53l30->regmap, true); | ||
1073 | |||
1074 | /* Hold down reset */ | ||
1075 | if (cs53l30->reset_gpio) | ||
1076 | gpiod_set_value_cansleep(cs53l30->reset_gpio, 0); | ||
1077 | |||
1078 | regulator_bulk_disable(ARRAY_SIZE(cs53l30->supplies), | ||
1079 | cs53l30->supplies); | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int cs53l30_runtime_resume(struct device *dev) | ||
1085 | { | ||
1086 | struct cs53l30_private *cs53l30 = dev_get_drvdata(dev); | ||
1087 | int ret; | ||
1088 | |||
1089 | ret = regulator_bulk_enable(ARRAY_SIZE(cs53l30->supplies), | ||
1090 | cs53l30->supplies); | ||
1091 | if (ret) { | ||
1092 | dev_err(dev, "failed to enable supplies: %d\n", ret); | ||
1093 | return ret; | ||
1094 | } | ||
1095 | |||
1096 | if (cs53l30->reset_gpio) | ||
1097 | gpiod_set_value_cansleep(cs53l30->reset_gpio, 1); | ||
1098 | |||
1099 | regcache_cache_only(cs53l30->regmap, false); | ||
1100 | ret = regcache_sync(cs53l30->regmap); | ||
1101 | if (ret) { | ||
1102 | dev_err(dev, "failed to synchronize regcache: %d\n", ret); | ||
1103 | return ret; | ||
1104 | } | ||
1105 | |||
1106 | return 0; | ||
1107 | } | ||
1108 | #endif | ||
1109 | |||
1110 | static const struct dev_pm_ops cs53l30_runtime_pm = { | ||
1111 | SET_RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume, | ||
1112 | NULL) | ||
1113 | }; | ||
1114 | |||
1115 | static const struct of_device_id cs53l30_of_match[] = { | ||
1116 | { .compatible = "cirrus,cs53l30", }, | ||
1117 | {}, | ||
1118 | }; | ||
1119 | |||
1120 | MODULE_DEVICE_TABLE(of, cs53l30_of_match); | ||
1121 | |||
1122 | static const struct i2c_device_id cs53l30_id[] = { | ||
1123 | { "cs53l30", 0 }, | ||
1124 | {} | ||
1125 | }; | ||
1126 | |||
1127 | MODULE_DEVICE_TABLE(i2c, cs53l30_id); | ||
1128 | |||
1129 | static struct i2c_driver cs53l30_i2c_driver = { | ||
1130 | .driver = { | ||
1131 | .name = "cs53l30", | ||
1132 | .pm = &cs53l30_runtime_pm, | ||
1133 | }, | ||
1134 | .id_table = cs53l30_id, | ||
1135 | .probe = cs53l30_i2c_probe, | ||
1136 | .remove = cs53l30_i2c_remove, | ||
1137 | }; | ||
1138 | |||
1139 | module_i2c_driver(cs53l30_i2c_driver); | ||
1140 | |||
1141 | MODULE_DESCRIPTION("ASoC CS53L30 driver"); | ||
1142 | MODULE_AUTHOR("Paul Handrigan, Cirrus Logic Inc, <Paul.Handrigan@cirrus.com>"); | ||
1143 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs53l30.h b/sound/soc/codecs/cs53l30.h new file mode 100644 index 000000000000..5e39da568749 --- /dev/null +++ b/sound/soc/codecs/cs53l30.h | |||
@@ -0,0 +1,459 @@ | |||
1 | /* | ||
2 | * ALSA SoC CS53L30 codec driver | ||
3 | * | ||
4 | * Copyright 2015 Cirrus Logic, Inc. | ||
5 | * | ||
6 | * Author: Paul Handrigan <Paul.Handrigan@cirrus.com>, | ||
7 | * Tim Howe <Tim.Howe@cirrus.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 version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #ifndef __CS53L30_H__ | ||
16 | #define __CS53L30_H__ | ||
17 | |||
18 | /* I2C Registers */ | ||
19 | #define CS53L30_DEVID_AB 0x01 /* Device ID A & B [RO]. */ | ||
20 | #define CS53L30_DEVID_CD 0x02 /* Device ID C & D [RO]. */ | ||
21 | #define CS53L30_DEVID_E 0x03 /* Device ID E [RO]. */ | ||
22 | #define CS53L30_REVID 0x05 /* Revision ID [RO]. */ | ||
23 | #define CS53L30_PWRCTL 0x06 /* Power Control. */ | ||
24 | #define CS53L30_MCLKCTL 0x07 /* MCLK Control. */ | ||
25 | #define CS53L30_INT_SR_CTL 0x08 /* Internal Sample Rate Control. */ | ||
26 | #define CS53L30_MICBIAS_CTL 0x0A /* Mic Bias Control. */ | ||
27 | #define CS53L30_ASPCFG_CTL 0x0C /* ASP Config Control. */ | ||
28 | #define CS53L30_ASP_CTL1 0x0D /* ASP1 Control. */ | ||
29 | #define CS53L30_ASP_TDMTX_CTL1 0x0E /* ASP1 TDM TX Control 1 */ | ||
30 | #define CS53L30_ASP_TDMTX_CTL2 0x0F /* ASP1 TDM TX Control 2 */ | ||
31 | #define CS53L30_ASP_TDMTX_CTL3 0x10 /* ASP1 TDM TX Control 3 */ | ||
32 | #define CS53L30_ASP_TDMTX_CTL4 0x11 /* ASP1 TDM TX Control 4 */ | ||
33 | #define CS53L30_ASP_TDMTX_EN1 0x12 /* ASP1 TDM TX Enable 1 */ | ||
34 | #define CS53L30_ASP_TDMTX_EN2 0x13 /* ASP1 TDM TX Enable 2 */ | ||
35 | #define CS53L30_ASP_TDMTX_EN3 0x14 /* ASP1 TDM TX Enable 3 */ | ||
36 | #define CS53L30_ASP_TDMTX_EN4 0x15 /* ASP1 TDM TX Enable 4 */ | ||
37 | #define CS53L30_ASP_TDMTX_EN5 0x16 /* ASP1 TDM TX Enable 5 */ | ||
38 | #define CS53L30_ASP_TDMTX_EN6 0x17 /* ASP1 TDM TX Enable 6 */ | ||
39 | #define CS53L30_ASP_CTL2 0x18 /* ASP2 Control. */ | ||
40 | #define CS53L30_SFT_RAMP 0x1A /* Soft Ramp Control. */ | ||
41 | #define CS53L30_LRCK_CTL1 0x1B /* LRCK Control 1. */ | ||
42 | #define CS53L30_LRCK_CTL2 0x1C /* LRCK Control 2. */ | ||
43 | #define CS53L30_MUTEP_CTL1 0x1F /* Mute Pin Control 1. */ | ||
44 | #define CS53L30_MUTEP_CTL2 0x20 /* Mute Pin Control 2. */ | ||
45 | #define CS53L30_INBIAS_CTL1 0x21 /* Input Bias Control 1. */ | ||
46 | #define CS53L30_INBIAS_CTL2 0x22 /* Input Bias Control 2. */ | ||
47 | #define CS53L30_DMIC1_STR_CTL 0x23 /* DMIC1 Stereo Control. */ | ||
48 | #define CS53L30_DMIC2_STR_CTL 0x24 /* DMIC2 Stereo Control. */ | ||
49 | #define CS53L30_ADCDMIC1_CTL1 0x25 /* ADC1/DMIC1 Control 1. */ | ||
50 | #define CS53L30_ADCDMIC1_CTL2 0x26 /* ADC1/DMIC1 Control 2. */ | ||
51 | #define CS53L30_ADC1_CTL3 0x27 /* ADC1 Control 3. */ | ||
52 | #define CS53L30_ADC1_NG_CTL 0x28 /* ADC1 Noise Gate Control. */ | ||
53 | #define CS53L30_ADC1A_AFE_CTL 0x29 /* ADC1A AFE Control. */ | ||
54 | #define CS53L30_ADC1B_AFE_CTL 0x2A /* ADC1B AFE Control. */ | ||
55 | #define CS53L30_ADC1A_DIG_VOL 0x2B /* ADC1A Digital Volume. */ | ||
56 | #define CS53L30_ADC1B_DIG_VOL 0x2C /* ADC1B Digital Volume. */ | ||
57 | #define CS53L30_ADCDMIC2_CTL1 0x2D /* ADC2/DMIC2 Control 1. */ | ||
58 | #define CS53L30_ADCDMIC2_CTL2 0x2E /* ADC2/DMIC2 Control 2. */ | ||
59 | #define CS53L30_ADC2_CTL3 0x2F /* ADC2 Control 3. */ | ||
60 | #define CS53L30_ADC2_NG_CTL 0x30 /* ADC2 Noise Gate Control. */ | ||
61 | #define CS53L30_ADC2A_AFE_CTL 0x31 /* ADC2A AFE Control. */ | ||
62 | #define CS53L30_ADC2B_AFE_CTL 0x32 /* ADC2B AFE Control. */ | ||
63 | #define CS53L30_ADC2A_DIG_VOL 0x33 /* ADC2A Digital Volume. */ | ||
64 | #define CS53L30_ADC2B_DIG_VOL 0x34 /* ADC2B Digital Volume. */ | ||
65 | #define CS53L30_INT_MASK 0x35 /* Interrupt Mask. */ | ||
66 | #define CS53L30_IS 0x36 /* Interrupt Status. */ | ||
67 | #define CS53L30_MAX_REGISTER 0x36 | ||
68 | |||
69 | #define CS53L30_TDM_SLOT_MAX 4 | ||
70 | #define CS53L30_ASP_TDMTX_CTL(x) (CS53L30_ASP_TDMTX_CTL1 + (x)) | ||
71 | /* x : index for registers; n : index for slot; 8 slots per register */ | ||
72 | #define CS53L30_ASP_TDMTX_ENx(x) (CS53L30_ASP_TDMTX_EN6 - (x)) | ||
73 | #define CS53L30_ASP_TDMTX_ENn(n) CS53L30_ASP_TDMTX_ENx((n) >> 3) | ||
74 | #define CS53L30_ASP_TDMTX_ENx_MAX 6 | ||
75 | |||
76 | /* Device ID */ | ||
77 | #define CS53L30_DEVID 0x53A30 | ||
78 | |||
79 | /* PDN_DONE Poll Maximum | ||
80 | * If soft ramp is set it will take much longer to power down | ||
81 | * the system. | ||
82 | */ | ||
83 | #define CS53L30_PDN_POLL_MAX 90 | ||
84 | |||
85 | /* Bitfield Definitions */ | ||
86 | |||
87 | /* R6 (0x06) CS53L30_PWRCTL - Power Control */ | ||
88 | #define CS53L30_PDN_ULP_SHIFT 7 | ||
89 | #define CS53L30_PDN_ULP_MASK (1 << CS53L30_PDN_ULP_SHIFT) | ||
90 | #define CS53L30_PDN_ULP (1 << CS53L30_PDN_ULP_SHIFT) | ||
91 | #define CS53L30_PDN_LP_SHIFT 6 | ||
92 | #define CS53L30_PDN_LP_MASK (1 << CS53L30_PDN_LP_SHIFT) | ||
93 | #define CS53L30_PDN_LP (1 << CS53L30_PDN_LP_SHIFT) | ||
94 | #define CS53L30_DISCHARGE_FILT_SHIFT 5 | ||
95 | #define CS53L30_DISCHARGE_FILT_MASK (1 << CS53L30_DISCHARGE_FILT_SHIFT) | ||
96 | #define CS53L30_DISCHARGE_FILT (1 << CS53L30_DISCHARGE_FILT_SHIFT) | ||
97 | #define CS53L30_THMS_PDN_SHIFT 4 | ||
98 | #define CS53L30_THMS_PDN_MASK (1 << CS53L30_THMS_PDN_SHIFT) | ||
99 | #define CS53L30_THMS_PDN (1 << CS53L30_THMS_PDN_SHIFT) | ||
100 | |||
101 | #define CS53L30_PWRCTL_DEFAULT (CS53L30_THMS_PDN) | ||
102 | |||
103 | /* R7 (0x07) CS53L30_MCLKCTL - MCLK Control */ | ||
104 | #define CS53L30_MCLK_DIS_SHIFT 7 | ||
105 | #define CS53L30_MCLK_DIS_MASK (1 << CS53L30_MCLK_DIS_SHIFT) | ||
106 | #define CS53L30_MCLK_DIS (1 << CS53L30_MCLK_DIS_SHIFT) | ||
107 | #define CS53L30_MCLK_INT_SCALE_SHIFT 6 | ||
108 | #define CS53L30_MCLK_INT_SCALE_MASK (1 << CS53L30_MCLK_INT_SCALE_SHIFT) | ||
109 | #define CS53L30_MCLK_INT_SCALE (1 << CS53L30_MCLK_INT_SCALE_SHIFT) | ||
110 | #define CS53L30_DMIC_DRIVE_SHIFT 5 | ||
111 | #define CS53L30_DMIC_DRIVE_MASK (1 << CS53L30_DMIC_DRIVE_SHIFT) | ||
112 | #define CS53L30_DMIC_DRIVE (1 << CS53L30_DMIC_DRIVE_SHIFT) | ||
113 | #define CS53L30_MCLK_DIV_SHIFT 2 | ||
114 | #define CS53L30_MCLK_DIV_WIDTH 2 | ||
115 | #define CS53L30_MCLK_DIV_MASK (((1 << CS53L30_MCLK_DIV_WIDTH) - 1) << CS53L30_MCLK_DIV_SHIFT) | ||
116 | #define CS53L30_MCLK_DIV_BY_1 (0x0 << CS53L30_MCLK_DIV_SHIFT) | ||
117 | #define CS53L30_MCLK_DIV_BY_2 (0x1 << CS53L30_MCLK_DIV_SHIFT) | ||
118 | #define CS53L30_MCLK_DIV_BY_3 (0x2 << CS53L30_MCLK_DIV_SHIFT) | ||
119 | #define CS53L30_SYNC_EN_SHIFT 1 | ||
120 | #define CS53L30_SYNC_EN_MASK (1 << CS53L30_SYNC_EN_SHIFT) | ||
121 | #define CS53L30_SYNC_EN (1 << CS53L30_SYNC_EN_SHIFT) | ||
122 | |||
123 | #define CS53L30_MCLKCTL_DEFAULT (CS53L30_MCLK_DIV_BY_2) | ||
124 | |||
125 | /* R8 (0x08) CS53L30_INT_SR_CTL - Internal Sample Rate Control */ | ||
126 | #define CS53L30_INTRNL_FS_RATIO_SHIFT 4 | ||
127 | #define CS53L30_INTRNL_FS_RATIO_MASK (1 << CS53L30_INTRNL_FS_RATIO_SHIFT) | ||
128 | #define CS53L30_INTRNL_FS_RATIO (1 << CS53L30_INTRNL_FS_RATIO_SHIFT) | ||
129 | #define CS53L30_MCLK_19MHZ_EN_SHIFT 0 | ||
130 | #define CS53L30_MCLK_19MHZ_EN_MASK (1 << CS53L30_MCLK_19MHZ_EN_SHIFT) | ||
131 | #define CS53L30_MCLK_19MHZ_EN (1 << CS53L30_MCLK_19MHZ_EN_SHIFT) | ||
132 | |||
133 | /* 0x6 << 1 is reserved bits */ | ||
134 | #define CS53L30_INT_SR_CTL_DEFAULT (CS53L30_INTRNL_FS_RATIO | 0x6 << 1) | ||
135 | |||
136 | /* R10 (0x0A) CS53L30_MICBIAS_CTL - Mic Bias Control */ | ||
137 | #define CS53L30_MIC4_BIAS_PDN_SHIFT 7 | ||
138 | #define CS53L30_MIC4_BIAS_PDN_MASK (1 << CS53L30_MIC4_BIAS_PDN_SHIFT) | ||
139 | #define CS53L30_MIC4_BIAS_PDN (1 << CS53L30_MIC4_BIAS_PDN_SHIFT) | ||
140 | #define CS53L30_MIC3_BIAS_PDN_SHIFT 6 | ||
141 | #define CS53L30_MIC3_BIAS_PDN_MASK (1 << CS53L30_MIC3_BIAS_PDN_SHIFT) | ||
142 | #define CS53L30_MIC3_BIAS_PDN (1 << CS53L30_MIC3_BIAS_PDN_SHIFT) | ||
143 | #define CS53L30_MIC2_BIAS_PDN_SHIFT 5 | ||
144 | #define CS53L30_MIC2_BIAS_PDN_MASK (1 << CS53L30_MIC2_BIAS_PDN_SHIFT) | ||
145 | #define CS53L30_MIC2_BIAS_PDN (1 << CS53L30_MIC2_BIAS_PDN_SHIFT) | ||
146 | #define CS53L30_MIC1_BIAS_PDN_SHIFT 4 | ||
147 | #define CS53L30_MIC1_BIAS_PDN_MASK (1 << CS53L30_MIC1_BIAS_PDN_SHIFT) | ||
148 | #define CS53L30_MIC1_BIAS_PDN (1 << CS53L30_MIC1_BIAS_PDN_SHIFT) | ||
149 | #define CS53L30_MICx_BIAS_PDN (0xf << CS53L30_MIC1_BIAS_PDN_SHIFT) | ||
150 | #define CS53L30_VP_MIN_SHIFT 2 | ||
151 | #define CS53L30_VP_MIN_MASK (1 << CS53L30_VP_MIN_SHIFT) | ||
152 | #define CS53L30_VP_MIN (1 << CS53L30_VP_MIN_SHIFT) | ||
153 | #define CS53L30_MIC_BIAS_CTRL_SHIFT 0 | ||
154 | #define CS53L30_MIC_BIAS_CTRL_WIDTH 2 | ||
155 | #define CS53L30_MIC_BIAS_CTRL_MASK (((1 << CS53L30_MIC_BIAS_CTRL_WIDTH) - 1) << CS53L30_MIC_BIAS_CTRL_SHIFT) | ||
156 | #define CS53L30_MIC_BIAS_CTRL_HIZ (0 << CS53L30_MIC_BIAS_CTRL_SHIFT) | ||
157 | #define CS53L30_MIC_BIAS_CTRL_1V8 (1 << CS53L30_MIC_BIAS_CTRL_SHIFT) | ||
158 | #define CS53L30_MIC_BIAS_CTRL_2V75 (2 << CS53L30_MIC_BIAS_CTRL_SHIFT) | ||
159 | |||
160 | #define CS53L30_MICBIAS_CTL_DEFAULT (CS53L30_MICx_BIAS_PDN | CS53L30_VP_MIN) | ||
161 | |||
162 | /* R12 (0x0C) CS53L30_ASPCFG_CTL - ASP Configuration Control */ | ||
163 | #define CS53L30_ASP_MS_SHIFT 7 | ||
164 | #define CS53L30_ASP_MS_MASK (1 << CS53L30_ASP_MS_SHIFT) | ||
165 | #define CS53L30_ASP_MS (1 << CS53L30_ASP_MS_SHIFT) | ||
166 | #define CS53L30_ASP_SCLK_INV_SHIFT 4 | ||
167 | #define CS53L30_ASP_SCLK_INV_MASK (1 << CS53L30_ASP_SCLK_INV_SHIFT) | ||
168 | #define CS53L30_ASP_SCLK_INV (1 << CS53L30_ASP_SCLK_INV_SHIFT) | ||
169 | #define CS53L30_ASP_RATE_SHIFT 0 | ||
170 | #define CS53L30_ASP_RATE_WIDTH 4 | ||
171 | #define CS53L30_ASP_RATE_MASK (((1 << CS53L30_ASP_RATE_WIDTH) - 1) << CS53L30_ASP_RATE_SHIFT) | ||
172 | #define CS53L30_ASP_RATE_48K (0xc << CS53L30_ASP_RATE_SHIFT) | ||
173 | |||
174 | #define CS53L30_ASPCFG_CTL_DEFAULT (CS53L30_ASP_RATE_48K) | ||
175 | |||
176 | /* R13/R24 (0x0D/0x18) CS53L30_ASP_CTL1 & CS53L30_ASP_CTL2 - ASP Control 1~2 */ | ||
177 | #define CS53L30_ASP_TDM_PDN_SHIFT 7 | ||
178 | #define CS53L30_ASP_TDM_PDN_MASK (1 << CS53L30_ASP_TDM_PDN_SHIFT) | ||
179 | #define CS53L30_ASP_TDM_PDN (1 << CS53L30_ASP_TDM_PDN_SHIFT) | ||
180 | #define CS53L30_ASP_SDOUTx_PDN_SHIFT 6 | ||
181 | #define CS53L30_ASP_SDOUTx_PDN_MASK (1 << CS53L30_ASP_SDOUTx_PDN_SHIFT) | ||
182 | #define CS53L30_ASP_SDOUTx_PDN (1 << CS53L30_ASP_SDOUTx_PDN_SHIFT) | ||
183 | #define CS53L30_ASP_3ST_SHIFT 5 | ||
184 | #define CS53L30_ASP_3ST_MASK (1 << CS53L30_ASP_3ST_SHIFT) | ||
185 | #define CS53L30_ASP_3ST (1 << CS53L30_ASP_3ST_SHIFT) | ||
186 | #define CS53L30_SHIFT_LEFT_SHIFT 4 | ||
187 | #define CS53L30_SHIFT_LEFT_MASK (1 << CS53L30_SHIFT_LEFT_SHIFT) | ||
188 | #define CS53L30_SHIFT_LEFT (1 << CS53L30_SHIFT_LEFT_SHIFT) | ||
189 | #define CS53L30_ASP_SDOUTx_DRIVE_SHIFT 0 | ||
190 | #define CS53L30_ASP_SDOUTx_DRIVE_MASK (1 << CS53L30_ASP_SDOUTx_DRIVE_SHIFT) | ||
191 | #define CS53L30_ASP_SDOUTx_DRIVE (1 << CS53L30_ASP_SDOUTx_DRIVE_SHIFT) | ||
192 | |||
193 | #define CS53L30_ASP_CTL1_DEFAULT (CS53L30_ASP_TDM_PDN) | ||
194 | #define CS53L30_ASP_CTL2_DEFAULT (0) | ||
195 | |||
196 | /* R14 (0x0E) ~ R17 (0x11) CS53L30_ASP_TDMTX_CTLx - ASP TDM TX Control 1~4 */ | ||
197 | #define CS53L30_ASP_CHx_TX_STATE_SHIFT 7 | ||
198 | #define CS53L30_ASP_CHx_TX_STATE_MASK (1 << CS53L30_ASP_CHx_TX_STATE_SHIFT) | ||
199 | #define CS53L30_ASP_CHx_TX_STATE (1 << CS53L30_ASP_CHx_TX_STATE_SHIFT) | ||
200 | #define CS53L30_ASP_CHx_TX_LOC_SHIFT 0 | ||
201 | #define CS53L30_ASP_CHx_TX_LOC_WIDTH 6 | ||
202 | #define CS53L30_ASP_CHx_TX_LOC_MASK (((1 << CS53L30_ASP_CHx_TX_LOC_WIDTH) - 1) << CS53L30_ASP_CHx_TX_LOC_SHIFT) | ||
203 | #define CS53L30_ASP_CHx_TX_LOC_MAX (47 << CS53L30_ASP_CHx_TX_LOC_SHIFT) | ||
204 | #define CS53L30_ASP_CHx_TX_LOC(x) ((x) << CS53L30_ASP_CHx_TX_LOC_SHIFT) | ||
205 | |||
206 | #define CS53L30_ASP_TDMTX_CTLx_DEFAULT (CS53L30_ASP_CHx_TX_LOC_MAX) | ||
207 | |||
208 | /* R18 (0x12) ~ R23 (0x17) CS53L30_ASP_TDMTX_ENx - ASP TDM TX Enable 1~6 */ | ||
209 | #define CS53L30_ASP_TDMTX_ENx_DEFAULT (0) | ||
210 | |||
211 | /* R26 (0x1A) CS53L30_SFT_RAMP - Soft Ramp Control */ | ||
212 | #define CS53L30_DIGSFT_SHIFT 5 | ||
213 | #define CS53L30_DIGSFT_MASK (1 << CS53L30_DIGSFT_SHIFT) | ||
214 | #define CS53L30_DIGSFT (1 << CS53L30_DIGSFT_SHIFT) | ||
215 | |||
216 | #define CS53L30_SFT_RMP_DEFAULT (0) | ||
217 | |||
218 | /* R28 (0x1C) CS53L30_LRCK_CTL2 - LRCK Control 2 */ | ||
219 | #define CS53L30_LRCK_50_NPW_SHIFT 3 | ||
220 | #define CS53L30_LRCK_50_NPW_MASK (1 << CS53L30_LRCK_50_NPW_SHIFT) | ||
221 | #define CS53L30_LRCK_50_NPW (1 << CS53L30_LRCK_50_NPW_SHIFT) | ||
222 | #define CS53L30_LRCK_TPWH_SHIFT 0 | ||
223 | #define CS53L30_LRCK_TPWH_WIDTH 3 | ||
224 | #define CS53L30_LRCK_TPWH_MASK (((1 << CS53L30_LRCK_TPWH_WIDTH) - 1) << CS53L30_LRCK_TPWH_SHIFT) | ||
225 | #define CS53L30_LRCK_TPWH(x) (((x) << CS53L30_LRCK_TPWH_SHIFT) & CS53L30_LRCK_TPWH_MASK) | ||
226 | |||
227 | #define CS53L30_LRCK_CTLx_DEFAULT (0) | ||
228 | |||
229 | /* R31 (0x1F) CS53L30_MUTEP_CTL1 - MUTE Pin Control 1 */ | ||
230 | #define CS53L30_MUTE_PDN_ULP_SHIFT 7 | ||
231 | #define CS53L30_MUTE_PDN_ULP_MASK (1 << CS53L30_MUTE_PDN_ULP_SHIFT) | ||
232 | #define CS53L30_MUTE_PDN_ULP (1 << CS53L30_MUTE_PDN_ULP_SHIFT) | ||
233 | #define CS53L30_MUTE_PDN_LP_SHIFT 6 | ||
234 | #define CS53L30_MUTE_PDN_LP_MASK (1 << CS53L30_MUTE_PDN_LP_SHIFT) | ||
235 | #define CS53L30_MUTE_PDN_LP (1 << CS53L30_MUTE_PDN_LP_SHIFT) | ||
236 | #define CS53L30_MUTE_M4B_PDN_SHIFT 4 | ||
237 | #define CS53L30_MUTE_M4B_PDN_MASK (1 << CS53L30_MUTE_M4B_PDN_SHIFT) | ||
238 | #define CS53L30_MUTE_M4B_PDN (1 << CS53L30_MUTE_M4B_PDN_SHIFT) | ||
239 | #define CS53L30_MUTE_M3B_PDN_SHIFT 3 | ||
240 | #define CS53L30_MUTE_M3B_PDN_MASK (1 << CS53L30_MUTE_M3B_PDN_SHIFT) | ||
241 | #define CS53L30_MUTE_M3B_PDN (1 << CS53L30_MUTE_M3B_PDN_SHIFT) | ||
242 | #define CS53L30_MUTE_M2B_PDN_SHIFT 2 | ||
243 | #define CS53L30_MUTE_M2B_PDN_MASK (1 << CS53L30_MUTE_M2B_PDN_SHIFT) | ||
244 | #define CS53L30_MUTE_M2B_PDN (1 << CS53L30_MUTE_M2B_PDN_SHIFT) | ||
245 | #define CS53L30_MUTE_M1B_PDN_SHIFT 1 | ||
246 | #define CS53L30_MUTE_M1B_PDN_MASK (1 << CS53L30_MUTE_M1B_PDN_SHIFT) | ||
247 | #define CS53L30_MUTE_M1B_PDN (1 << CS53L30_MUTE_M1B_PDN_SHIFT) | ||
248 | /* Note: be careful - x starts from 0 */ | ||
249 | #define CS53L30_MUTE_MxB_PDN_SHIFT(x) (CS53L30_MUTE_M1B_PDN_SHIFT + (x)) | ||
250 | #define CS53L30_MUTE_MxB_PDN_MASK(x) (1 << CS53L30_MUTE_MxB_PDN_SHIFT(x)) | ||
251 | #define CS53L30_MUTE_MxB_PDN(x) (1 << CS53L30_MUTE_MxB_PDN_SHIFT(x)) | ||
252 | #define CS53L30_MUTE_MB_ALL_PDN_SHIFT 0 | ||
253 | #define CS53L30_MUTE_MB_ALL_PDN_MASK (1 << CS53L30_MUTE_MB_ALL_PDN_SHIFT) | ||
254 | #define CS53L30_MUTE_MB_ALL_PDN (1 << CS53L30_MUTE_MB_ALL_PDN_SHIFT) | ||
255 | |||
256 | #define CS53L30_MUTEP_CTL1_MUTEALL (0xdf) | ||
257 | #define CS53L30_MUTEP_CTL1_DEFAULT (0) | ||
258 | |||
259 | /* R32 (0x20) CS53L30_MUTEP_CTL2 - MUTE Pin Control 2 */ | ||
260 | #define CS53L30_MUTE_PIN_POLARITY_SHIFT 7 | ||
261 | #define CS53L30_MUTE_PIN_POLARITY_MASK (1 << CS53L30_MUTE_PIN_POLARITY_SHIFT) | ||
262 | #define CS53L30_MUTE_PIN_POLARITY (1 << CS53L30_MUTE_PIN_POLARITY_SHIFT) | ||
263 | #define CS53L30_MUTE_ASP_TDM_PDN_SHIFT 6 | ||
264 | #define CS53L30_MUTE_ASP_TDM_PDN_MASK (1 << CS53L30_MUTE_ASP_TDM_PDN_SHIFT) | ||
265 | #define CS53L30_MUTE_ASP_TDM_PDN (1 << CS53L30_MUTE_ASP_TDM_PDN_SHIFT) | ||
266 | #define CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT 5 | ||
267 | #define CS53L30_MUTE_ASP_SDOUT2_PDN_MASK (1 << CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT) | ||
268 | #define CS53L30_MUTE_ASP_SDOUT2_PDN (1 << CS53L30_MUTE_ASP_SDOUT2_PDN_SHIFT) | ||
269 | #define CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT 4 | ||
270 | #define CS53L30_MUTE_ASP_SDOUT1_PDN_MASK (1 << CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT) | ||
271 | #define CS53L30_MUTE_ASP_SDOUT1_PDN (1 << CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT) | ||
272 | /* Note: be careful - x starts from 0 */ | ||
273 | #define CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x) ((x) + CS53L30_MUTE_ASP_SDOUT1_PDN_SHIFT) | ||
274 | #define CS53L30_MUTE_ASP_SDOUTx_PDN_MASK(x) (1 << CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x)) | ||
275 | #define CS53L30_MUTE_ASP_SDOUTx_PDN (1 << CS53L30_MUTE_ASP_SDOUTx_PDN_SHIFT(x)) | ||
276 | #define CS53L30_MUTE_ADC2B_PDN_SHIFT 3 | ||
277 | #define CS53L30_MUTE_ADC2B_PDN_MASK (1 << CS53L30_MUTE_ADC2B_PDN_SHIFT) | ||
278 | #define CS53L30_MUTE_ADC2B_PDN (1 << CS53L30_MUTE_ADC2B_PDN_SHIFT) | ||
279 | #define CS53L30_MUTE_ADC2A_PDN_SHIFT 2 | ||
280 | #define CS53L30_MUTE_ADC2A_PDN_MASK (1 << CS53L30_MUTE_ADC2A_PDN_SHIFT) | ||
281 | #define CS53L30_MUTE_ADC2A_PDN (1 << CS53L30_MUTE_ADC2A_PDN_SHIFT) | ||
282 | #define CS53L30_MUTE_ADC1B_PDN_SHIFT 1 | ||
283 | #define CS53L30_MUTE_ADC1B_PDN_MASK (1 << CS53L30_MUTE_ADC1B_PDN_SHIFT) | ||
284 | #define CS53L30_MUTE_ADC1B_PDN (1 << CS53L30_MUTE_ADC1B_PDN_SHIFT) | ||
285 | #define CS53L30_MUTE_ADC1A_PDN_SHIFT 0 | ||
286 | #define CS53L30_MUTE_ADC1A_PDN_MASK (1 << CS53L30_MUTE_ADC1A_PDN_SHIFT) | ||
287 | #define CS53L30_MUTE_ADC1A_PDN (1 << CS53L30_MUTE_ADC1A_PDN_SHIFT) | ||
288 | |||
289 | #define CS53L30_MUTEP_CTL2_DEFAULT (CS53L30_MUTE_PIN_POLARITY) | ||
290 | |||
291 | /* R33 (0x21) CS53L30_INBIAS_CTL1 - Input Bias Control 1 */ | ||
292 | #define CS53L30_IN4M_BIAS_SHIFT 6 | ||
293 | #define CS53L30_IN4M_BIAS_WIDTH 2 | ||
294 | #define CS53L30_IN4M_BIAS_MASK (((1 << CS53L30_IN4M_BIAS_WIDTH) - 1) << CS53L30_IN4M_BIAS_SHIFT) | ||
295 | #define CS53L30_IN4M_BIAS_OPEN (0 << CS53L30_IN4M_BIAS_SHIFT) | ||
296 | #define CS53L30_IN4M_BIAS_PULL_DOWN (1 << CS53L30_IN4M_BIAS_SHIFT) | ||
297 | #define CS53L30_IN4M_BIAS_VCM (2 << CS53L30_IN4M_BIAS_SHIFT) | ||
298 | #define CS53L30_IN4P_BIAS_SHIFT 4 | ||
299 | #define CS53L30_IN4P_BIAS_WIDTH 2 | ||
300 | #define CS53L30_IN4P_BIAS_MASK (((1 << CS53L30_IN4P_BIAS_WIDTH) - 1) << CS53L30_IN4P_BIAS_SHIFT) | ||
301 | #define CS53L30_IN4P_BIAS_OPEN (0 << CS53L30_IN4P_BIAS_SHIFT) | ||
302 | #define CS53L30_IN4P_BIAS_PULL_DOWN (1 << CS53L30_IN4P_BIAS_SHIFT) | ||
303 | #define CS53L30_IN4P_BIAS_VCM (2 << CS53L30_IN4P_BIAS_SHIFT) | ||
304 | #define CS53L30_IN3M_BIAS_SHIFT 2 | ||
305 | #define CS53L30_IN3M_BIAS_WIDTH 2 | ||
306 | #define CS53L30_IN3M_BIAS_MASK (((1 << CS53L30_IN3M_BIAS_WIDTH) - 1) << CS53L30_IN4M_BIAS_SHIFT) | ||
307 | #define CS53L30_IN3M_BIAS_OPEN (0 << CS53L30_IN3M_BIAS_SHIFT) | ||
308 | #define CS53L30_IN3M_BIAS_PULL_DOWN (1 << CS53L30_IN3M_BIAS_SHIFT) | ||
309 | #define CS53L30_IN3M_BIAS_VCM (2 << CS53L30_IN3M_BIAS_SHIFT) | ||
310 | #define CS53L30_IN3P_BIAS_SHIFT 0 | ||
311 | #define CS53L30_IN3P_BIAS_WIDTH 2 | ||
312 | #define CS53L30_IN3P_BIAS_MASK (((1 << CS53L30_IN3P_BIAS_WIDTH) - 1) << CS53L30_IN3P_BIAS_SHIFT) | ||
313 | #define CS53L30_IN3P_BIAS_OPEN (0 << CS53L30_IN3P_BIAS_SHIFT) | ||
314 | #define CS53L30_IN3P_BIAS_PULL_DOWN (1 << CS53L30_IN3P_BIAS_SHIFT) | ||
315 | #define CS53L30_IN3P_BIAS_VCM (2 << CS53L30_IN3P_BIAS_SHIFT) | ||
316 | |||
317 | #define CS53L30_INBIAS_CTL1_DEFAULT (CS53L30_IN4M_BIAS_VCM | CS53L30_IN4P_BIAS_VCM |\ | ||
318 | CS53L30_IN3M_BIAS_VCM | CS53L30_IN3P_BIAS_VCM) | ||
319 | |||
320 | /* R34 (0x22) CS53L30_INBIAS_CTL2 - Input Bias Control 2 */ | ||
321 | #define CS53L30_IN2M_BIAS_SHIFT 6 | ||
322 | #define CS53L30_IN2M_BIAS_WIDTH 2 | ||
323 | #define CS53L30_IN2M_BIAS_MASK (((1 << CS53L30_IN2M_BIAS_WIDTH) - 1) << CS53L30_IN2M_BIAS_SHIFT) | ||
324 | #define CS53L30_IN2M_BIAS_OPEN (0 << CS53L30_IN2M_BIAS_SHIFT) | ||
325 | #define CS53L30_IN2M_BIAS_PULL_DOWN (1 << CS53L30_IN2M_BIAS_SHIFT) | ||
326 | #define CS53L30_IN2M_BIAS_VCM (2 << CS53L30_IN2M_BIAS_SHIFT) | ||
327 | #define CS53L30_IN2P_BIAS_SHIFT 4 | ||
328 | #define CS53L30_IN2P_BIAS_WIDTH 2 | ||
329 | #define CS53L30_IN2P_BIAS_MASK (((1 << CS53L30_IN2P_BIAS_WIDTH) - 1) << CS53L30_IN2P_BIAS_SHIFT) | ||
330 | #define CS53L30_IN2P_BIAS_OPEN (0 << CS53L30_IN2P_BIAS_SHIFT) | ||
331 | #define CS53L30_IN2P_BIAS_PULL_DOWN (1 << CS53L30_IN2P_BIAS_SHIFT) | ||
332 | #define CS53L30_IN2P_BIAS_VCM (2 << CS53L30_IN2P_BIAS_SHIFT) | ||
333 | #define CS53L30_IN1M_BIAS_SHIFT 2 | ||
334 | #define CS53L30_IN1M_BIAS_WIDTH 2 | ||
335 | #define CS53L30_IN1M_BIAS_MASK (((1 << CS53L30_IN1M_BIAS_WIDTH) - 1) << CS53L30_IN1M_BIAS_SHIFT) | ||
336 | #define CS53L30_IN1M_BIAS_OPEN (0 << CS53L30_IN1M_BIAS_SHIFT) | ||
337 | #define CS53L30_IN1M_BIAS_PULL_DOWN (1 << CS53L30_IN1M_BIAS_SHIFT) | ||
338 | #define CS53L30_IN1M_BIAS_VCM (2 << CS53L30_IN1M_BIAS_SHIFT) | ||
339 | #define CS53L30_IN1P_BIAS_SHIFT 0 | ||
340 | #define CS53L30_IN1P_BIAS_WIDTH 2 | ||
341 | #define CS53L30_IN1P_BIAS_MASK (((1 << CS53L30_IN1P_BIAS_WIDTH) - 1) << CS53L30_IN1P_BIAS_SHIFT) | ||
342 | #define CS53L30_IN1P_BIAS_OPEN (0 << CS53L30_IN1P_BIAS_SHIFT) | ||
343 | #define CS53L30_IN1P_BIAS_PULL_DOWN (1 << CS53L30_IN1P_BIAS_SHIFT) | ||
344 | #define CS53L30_IN1P_BIAS_VCM (2 << CS53L30_IN1P_BIAS_SHIFT) | ||
345 | |||
346 | #define CS53L30_INBIAS_CTL2_DEFAULT (CS53L30_IN2M_BIAS_VCM | CS53L30_IN2P_BIAS_VCM |\ | ||
347 | CS53L30_IN1M_BIAS_VCM | CS53L30_IN1P_BIAS_VCM) | ||
348 | |||
349 | /* R35 (0x23) & R36 (0x24) CS53L30_DMICx_STR_CTL - DMIC1 & DMIC2 Stereo Control */ | ||
350 | #define CS53L30_DMICx_STEREO_ENB_SHIFT 5 | ||
351 | #define CS53L30_DMICx_STEREO_ENB_MASK (1 << CS53L30_DMICx_STEREO_ENB_SHIFT) | ||
352 | #define CS53L30_DMICx_STEREO_ENB (1 << CS53L30_DMICx_STEREO_ENB_SHIFT) | ||
353 | |||
354 | /* 0x88 and 0xCC are reserved bits */ | ||
355 | #define CS53L30_DMIC1_STR_CTL_DEFAULT (CS53L30_DMICx_STEREO_ENB | 0x88) | ||
356 | #define CS53L30_DMIC2_STR_CTL_DEFAULT (CS53L30_DMICx_STEREO_ENB | 0xCC) | ||
357 | |||
358 | /* R37/R45 (0x25/0x2D) CS53L30_ADCDMICx_CTL1 - ADC1/DMIC1 & ADC2/DMIC2 Control 1 */ | ||
359 | #define CS53L30_ADCxB_PDN_SHIFT 7 | ||
360 | #define CS53L30_ADCxB_PDN_MASK (1 << CS53L30_ADCxB_PDN_SHIFT) | ||
361 | #define CS53L30_ADCxB_PDN (1 << CS53L30_ADCxB_PDN_SHIFT) | ||
362 | #define CS53L30_ADCxA_PDN_SHIFT 6 | ||
363 | #define CS53L30_ADCxA_PDN_MASK (1 << CS53L30_ADCxA_PDN_SHIFT) | ||
364 | #define CS53L30_ADCxA_PDN (1 << CS53L30_ADCxA_PDN_SHIFT) | ||
365 | #define CS53L30_DMICx_PDN_SHIFT 2 | ||
366 | #define CS53L30_DMICx_PDN_MASK (1 << CS53L30_DMICx_PDN_SHIFT) | ||
367 | #define CS53L30_DMICx_PDN (1 << CS53L30_DMICx_PDN_SHIFT) | ||
368 | #define CS53L30_DMICx_SCLK_DIV_SHIFT 1 | ||
369 | #define CS53L30_DMICx_SCLK_DIV_MASK (1 << CS53L30_DMICx_SCLK_DIV_SHIFT) | ||
370 | #define CS53L30_DMICx_SCLK_DIV (1 << CS53L30_DMICx_SCLK_DIV_SHIFT) | ||
371 | #define CS53L30_CH_TYPE_SHIFT 0 | ||
372 | #define CS53L30_CH_TYPE_MASK (1 << CS53L30_CH_TYPE_SHIFT) | ||
373 | #define CS53L30_CH_TYPE (1 << CS53L30_CH_TYPE_SHIFT) | ||
374 | |||
375 | #define CS53L30_ADCDMICx_PDN_MASK 0xFF | ||
376 | #define CS53L30_ADCDMICx_CTL1_DEFAULT (CS53L30_DMICx_PDN) | ||
377 | |||
378 | /* R38/R46 (0x26/0x2E) CS53L30_ADCDMICx_CTL2 - ADC1/DMIC1 & ADC2/DMIC2 Control 2 */ | ||
379 | #define CS53L30_ADCx_NOTCH_DIS_SHIFT 7 | ||
380 | #define CS53L30_ADCx_NOTCH_DIS_MASK (1 << CS53L30_ADCx_NOTCH_DIS_SHIFT) | ||
381 | #define CS53L30_ADCx_NOTCH_DIS (1 << CS53L30_ADCx_NOTCH_DIS_SHIFT) | ||
382 | #define CS53L30_ADCxB_INV_SHIFT 5 | ||
383 | #define CS53L30_ADCxB_INV_MASK (1 << CS53L30_ADCxB_INV_SHIFT) | ||
384 | #define CS53L30_ADCxB_INV (1 << CS53L30_ADCxB_INV_SHIFT) | ||
385 | #define CS53L30_ADCxA_INV_SHIFT 4 | ||
386 | #define CS53L30_ADCxA_INV_MASK (1 << CS53L30_ADCxA_INV_SHIFT) | ||
387 | #define CS53L30_ADCxA_INV (1 << CS53L30_ADCxA_INV_SHIFT) | ||
388 | #define CS53L30_ADCxB_DIG_BOOST_SHIFT 1 | ||
389 | #define CS53L30_ADCxB_DIG_BOOST_MASK (1 << CS53L30_ADCxB_DIG_BOOST_SHIFT) | ||
390 | #define CS53L30_ADCxB_DIG_BOOST (1 << CS53L30_ADCxB_DIG_BOOST_SHIFT) | ||
391 | #define CS53L30_ADCxA_DIG_BOOST_SHIFT 0 | ||
392 | #define CS53L30_ADCxA_DIG_BOOST_MASK (1 << CS53L30_ADCxA_DIG_BOOST_SHIFT) | ||
393 | #define CS53L30_ADCxA_DIG_BOOST (1 << CS53L30_ADCxA_DIG_BOOST_SHIFT) | ||
394 | |||
395 | #define CS53L30_ADCDMIC1_CTL2_DEFAULT (0) | ||
396 | |||
397 | /* R39/R47 (0x27/0x2F) CS53L30_ADCx_CTL3 - ADC1/ADC2 Control 3 */ | ||
398 | #define CS53L30_ADCx_HPF_EN_SHIFT 3 | ||
399 | #define CS53L30_ADCx_HPF_EN_MASK (1 << CS53L30_ADCx_HPF_EN_SHIFT) | ||
400 | #define CS53L30_ADCx_HPF_EN (1 << CS53L30_ADCx_HPF_EN_SHIFT) | ||
401 | #define CS53L30_ADCx_HPF_CF_SHIFT 1 | ||
402 | #define CS53L30_ADCx_HPF_CF_WIDTH 2 | ||
403 | #define CS53L30_ADCx_HPF_CF_MASK (((1 << CS53L30_ADCx_HPF_CF_WIDTH) - 1) << CS53L30_ADCx_HPF_CF_SHIFT) | ||
404 | #define CS53L30_ADCx_HPF_CF_1HZ86 (0 << CS53L30_ADCx_HPF_CF_SHIFT) | ||
405 | #define CS53L30_ADCx_HPF_CF_120HZ (1 << CS53L30_ADCx_HPF_CF_SHIFT) | ||
406 | #define CS53L30_ADCx_HPF_CF_235HZ (2 << CS53L30_ADCx_HPF_CF_SHIFT) | ||
407 | #define CS53L30_ADCx_HPF_CF_466HZ (3 << CS53L30_ADCx_HPF_CF_SHIFT) | ||
408 | #define CS53L30_ADCx_NG_ALL_SHIFT 0 | ||
409 | #define CS53L30_ADCx_NG_ALL_MASK (1 << CS53L30_ADCx_NG_ALL_SHIFT) | ||
410 | #define CS53L30_ADCx_NG_ALL (1 << CS53L30_ADCx_NG_ALL_SHIFT) | ||
411 | |||
412 | #define CS53L30_ADCx_CTL3_DEFAULT (CS53L30_ADCx_HPF_EN) | ||
413 | |||
414 | /* R40/R48 (0x28/0x30) CS53L30_ADCx_NG_CTL - ADC1/ADC2 Noise Gate Control */ | ||
415 | #define CS53L30_ADCxB_NG_SHIFT 7 | ||
416 | #define CS53L30_ADCxB_NG_MASK (1 << CS53L30_ADCxB_NG_SHIFT) | ||
417 | #define CS53L30_ADCxB_NG (1 << CS53L30_ADCxB_NG_SHIFT) | ||
418 | #define CS53L30_ADCxA_NG_SHIFT 6 | ||
419 | #define CS53L30_ADCxA_NG_MASK (1 << CS53L30_ADCxA_NG_SHIFT) | ||
420 | #define CS53L30_ADCxA_NG (1 << CS53L30_ADCxA_NG_SHIFT) | ||
421 | #define CS53L30_ADCx_NG_BOOST_SHIFT 5 | ||
422 | #define CS53L30_ADCx_NG_BOOST_MASK (1 << CS53L30_ADCx_NG_BOOST_SHIFT) | ||
423 | #define CS53L30_ADCx_NG_BOOST (1 << CS53L30_ADCx_NG_BOOST_SHIFT) | ||
424 | #define CS53L30_ADCx_NG_THRESH_SHIFT 2 | ||
425 | #define CS53L30_ADCx_NG_THRESH_WIDTH 3 | ||
426 | #define CS53L30_ADCx_NG_THRESH_MASK (((1 << CS53L30_ADCx_NG_THRESH_WIDTH) - 1) << CS53L30_ADCx_NG_THRESH_SHIFT) | ||
427 | #define CS53L30_ADCx_NG_DELAY_SHIFT 0 | ||
428 | #define CS53L30_ADCx_NG_DELAY_WIDTH 2 | ||
429 | #define CS53L30_ADCx_NG_DELAY_MASK (((1 << CS53L30_ADCx_NG_DELAY_WIDTH) - 1) << CS53L30_ADCx_NG_DELAY_SHIFT) | ||
430 | |||
431 | #define CS53L30_ADCx_NG_CTL_DEFAULT (0) | ||
432 | |||
433 | /* R41/R42/R49/R50 (0x29/0x2A/0x31/0x32) CS53L30_ADCxy_AFE_CTL - ADC1A/1B/2A/2B AFE Control */ | ||
434 | #define CS53L30_ADCxy_PREAMP_SHIFT 6 | ||
435 | #define CS53L30_ADCxy_PREAMP_WIDTH 2 | ||
436 | #define CS53L30_ADCxy_PREAMP_MASK (((1 << CS53L30_ADCxy_PREAMP_WIDTH) - 1) << CS53L30_ADCxy_PREAMP_SHIFT) | ||
437 | #define CS53L30_ADCxy_PGA_VOL_SHIFT 0 | ||
438 | #define CS53L30_ADCxy_PGA_VOL_WIDTH 6 | ||
439 | #define CS53L30_ADCxy_PGA_VOL_MASK (((1 << CS53L30_ADCxy_PGA_VOL_WIDTH) - 1) << CS53L30_ADCxy_PGA_VOL_SHIFT) | ||
440 | |||
441 | #define CS53L30_ADCxy_AFE_CTL_DEFAULT (0) | ||
442 | |||
443 | /* R43/R44/R51/R52 (0x2B/0x2C/0x33/0x34) CS53L30_ADCxy_DIG_VOL - ADC1A/1B/2A/2B Digital Volume */ | ||
444 | #define CS53L30_ADCxy_VOL_MUTE (0x80) | ||
445 | |||
446 | #define CS53L30_ADCxy_DIG_VOL_DEFAULT (0x0) | ||
447 | |||
448 | /* CS53L30_INT */ | ||
449 | #define CS53L30_PDN_DONE (1 << 7) | ||
450 | #define CS53L30_THMS_TRIP (1 << 6) | ||
451 | #define CS53L30_SYNC_DONE (1 << 5) | ||
452 | #define CS53L30_ADC2B_OVFL (1 << 4) | ||
453 | #define CS53L30_ADC2A_OVFL (1 << 3) | ||
454 | #define CS53L30_ADC1B_OVFL (1 << 2) | ||
455 | #define CS53L30_ADC1A_OVFL (1 << 1) | ||
456 | #define CS53L30_MUTE_PIN (1 << 0) | ||
457 | #define CS53L30_DEVICE_INT_MASK 0xFF | ||
458 | |||
459 | #endif /* __CS53L30_H__ */ | ||
diff --git a/sound/soc/codecs/da7219-aad.c b/sound/soc/codecs/da7219-aad.c index 9459593eef13..f0057cd223a4 100644 --- a/sound/soc/codecs/da7219-aad.c +++ b/sound/soc/codecs/da7219-aad.c | |||
@@ -13,8 +13,8 @@ | |||
13 | 13 | ||
14 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/platform_device.h> | 15 | #include <linux/platform_device.h> |
16 | #include <linux/of_device.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/of_irq.h> | 17 | #include <linux/property.h> |
18 | #include <linux/pm_wakeirq.h> | 18 | #include <linux/pm_wakeirq.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
@@ -382,11 +382,11 @@ static irqreturn_t da7219_aad_irq_thread(int irq, void *data) | |||
382 | } | 382 | } |
383 | 383 | ||
384 | /* | 384 | /* |
385 | * DT to pdata conversion | 385 | * DT/ACPI to pdata conversion |
386 | */ | 386 | */ |
387 | 387 | ||
388 | static enum da7219_aad_micbias_pulse_lvl | 388 | static enum da7219_aad_micbias_pulse_lvl |
389 | da7219_aad_of_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val) | 389 | da7219_aad_fw_micbias_pulse_lvl(struct snd_soc_codec *codec, u32 val) |
390 | { | 390 | { |
391 | switch (val) { | 391 | switch (val) { |
392 | case 2800: | 392 | case 2800: |
@@ -400,7 +400,7 @@ static enum da7219_aad_micbias_pulse_lvl | |||
400 | } | 400 | } |
401 | 401 | ||
402 | static enum da7219_aad_btn_cfg | 402 | static enum da7219_aad_btn_cfg |
403 | da7219_aad_of_btn_cfg(struct snd_soc_codec *codec, u32 val) | 403 | da7219_aad_fw_btn_cfg(struct snd_soc_codec *codec, u32 val) |
404 | { | 404 | { |
405 | switch (val) { | 405 | switch (val) { |
406 | case 2: | 406 | case 2: |
@@ -424,7 +424,7 @@ static enum da7219_aad_btn_cfg | |||
424 | } | 424 | } |
425 | 425 | ||
426 | static enum da7219_aad_mic_det_thr | 426 | static enum da7219_aad_mic_det_thr |
427 | da7219_aad_of_mic_det_thr(struct snd_soc_codec *codec, u32 val) | 427 | da7219_aad_fw_mic_det_thr(struct snd_soc_codec *codec, u32 val) |
428 | { | 428 | { |
429 | switch (val) { | 429 | switch (val) { |
430 | case 200: | 430 | case 200: |
@@ -442,7 +442,7 @@ static enum da7219_aad_mic_det_thr | |||
442 | } | 442 | } |
443 | 443 | ||
444 | static enum da7219_aad_jack_ins_deb | 444 | static enum da7219_aad_jack_ins_deb |
445 | da7219_aad_of_jack_ins_deb(struct snd_soc_codec *codec, u32 val) | 445 | da7219_aad_fw_jack_ins_deb(struct snd_soc_codec *codec, u32 val) |
446 | { | 446 | { |
447 | switch (val) { | 447 | switch (val) { |
448 | case 5: | 448 | case 5: |
@@ -468,7 +468,7 @@ static enum da7219_aad_jack_ins_deb | |||
468 | } | 468 | } |
469 | 469 | ||
470 | static enum da7219_aad_jack_det_rate | 470 | static enum da7219_aad_jack_det_rate |
471 | da7219_aad_of_jack_det_rate(struct snd_soc_codec *codec, const char *str) | 471 | da7219_aad_fw_jack_det_rate(struct snd_soc_codec *codec, const char *str) |
472 | { | 472 | { |
473 | if (!strcmp(str, "32ms_64ms")) { | 473 | if (!strcmp(str, "32ms_64ms")) { |
474 | return DA7219_AAD_JACK_DET_RATE_32_64MS; | 474 | return DA7219_AAD_JACK_DET_RATE_32_64MS; |
@@ -485,7 +485,7 @@ static enum da7219_aad_jack_det_rate | |||
485 | } | 485 | } |
486 | 486 | ||
487 | static enum da7219_aad_jack_rem_deb | 487 | static enum da7219_aad_jack_rem_deb |
488 | da7219_aad_of_jack_rem_deb(struct snd_soc_codec *codec, u32 val) | 488 | da7219_aad_fw_jack_rem_deb(struct snd_soc_codec *codec, u32 val) |
489 | { | 489 | { |
490 | switch (val) { | 490 | switch (val) { |
491 | case 1: | 491 | case 1: |
@@ -503,7 +503,7 @@ static enum da7219_aad_jack_rem_deb | |||
503 | } | 503 | } |
504 | 504 | ||
505 | static enum da7219_aad_btn_avg | 505 | static enum da7219_aad_btn_avg |
506 | da7219_aad_of_btn_avg(struct snd_soc_codec *codec, u32 val) | 506 | da7219_aad_fw_btn_avg(struct snd_soc_codec *codec, u32 val) |
507 | { | 507 | { |
508 | switch (val) { | 508 | switch (val) { |
509 | case 1: | 509 | case 1: |
@@ -521,7 +521,7 @@ static enum da7219_aad_btn_avg | |||
521 | } | 521 | } |
522 | 522 | ||
523 | static enum da7219_aad_adc_1bit_rpt | 523 | static enum da7219_aad_adc_1bit_rpt |
524 | da7219_aad_of_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val) | 524 | da7219_aad_fw_adc_1bit_rpt(struct snd_soc_codec *codec, u32 val) |
525 | { | 525 | { |
526 | switch (val) { | 526 | switch (val) { |
527 | case 1: | 527 | case 1: |
@@ -538,97 +538,96 @@ static enum da7219_aad_adc_1bit_rpt | |||
538 | } | 538 | } |
539 | } | 539 | } |
540 | 540 | ||
541 | static struct da7219_aad_pdata *da7219_aad_of_to_pdata(struct snd_soc_codec *codec) | 541 | static struct da7219_aad_pdata *da7219_aad_fw_to_pdata(struct snd_soc_codec *codec) |
542 | { | 542 | { |
543 | struct device_node *np = codec->dev->of_node; | 543 | struct device *dev = codec->dev; |
544 | struct device_node *aad_np = of_find_node_by_name(np, "da7219_aad"); | 544 | struct i2c_client *i2c = to_i2c_client(dev); |
545 | struct fwnode_handle *aad_np; | ||
545 | struct da7219_aad_pdata *aad_pdata; | 546 | struct da7219_aad_pdata *aad_pdata; |
546 | const char *of_str; | 547 | const char *fw_str; |
547 | u32 of_val32; | 548 | u32 fw_val32; |
548 | 549 | ||
550 | aad_np = device_get_named_child_node(dev, "da7219_aad"); | ||
549 | if (!aad_np) | 551 | if (!aad_np) |
550 | return NULL; | 552 | return NULL; |
551 | 553 | ||
552 | aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL); | 554 | aad_pdata = devm_kzalloc(codec->dev, sizeof(*aad_pdata), GFP_KERNEL); |
553 | if (!aad_pdata) | 555 | if (!aad_pdata) |
554 | goto out; | 556 | return NULL; |
555 | 557 | ||
556 | aad_pdata->irq = irq_of_parse_and_map(np, 0); | 558 | aad_pdata->irq = i2c->irq; |
557 | 559 | ||
558 | if (of_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", | 560 | if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-lvl", |
559 | &of_val32) >= 0) | 561 | &fw_val32) >= 0) |
560 | aad_pdata->micbias_pulse_lvl = | 562 | aad_pdata->micbias_pulse_lvl = |
561 | da7219_aad_of_micbias_pulse_lvl(codec, of_val32); | 563 | da7219_aad_fw_micbias_pulse_lvl(codec, fw_val32); |
562 | else | 564 | else |
563 | aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; | 565 | aad_pdata->micbias_pulse_lvl = DA7219_AAD_MICBIAS_PULSE_LVL_OFF; |
564 | 566 | ||
565 | if (of_property_read_u32(aad_np, "dlg,micbias-pulse-time", | 567 | if (fwnode_property_read_u32(aad_np, "dlg,micbias-pulse-time", |
566 | &of_val32) >= 0) | 568 | &fw_val32) >= 0) |
567 | aad_pdata->micbias_pulse_time = of_val32; | 569 | aad_pdata->micbias_pulse_time = fw_val32; |
568 | 570 | ||
569 | if (of_property_read_u32(aad_np, "dlg,btn-cfg", &of_val32) >= 0) | 571 | if (fwnode_property_read_u32(aad_np, "dlg,btn-cfg", &fw_val32) >= 0) |
570 | aad_pdata->btn_cfg = da7219_aad_of_btn_cfg(codec, of_val32); | 572 | aad_pdata->btn_cfg = da7219_aad_fw_btn_cfg(codec, fw_val32); |
571 | else | 573 | else |
572 | aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; | 574 | aad_pdata->btn_cfg = DA7219_AAD_BTN_CFG_10MS; |
573 | 575 | ||
574 | if (of_property_read_u32(aad_np, "dlg,mic-det-thr", &of_val32) >= 0) | 576 | if (fwnode_property_read_u32(aad_np, "dlg,mic-det-thr", &fw_val32) >= 0) |
575 | aad_pdata->mic_det_thr = | 577 | aad_pdata->mic_det_thr = |
576 | da7219_aad_of_mic_det_thr(codec, of_val32); | 578 | da7219_aad_fw_mic_det_thr(codec, fw_val32); |
577 | else | 579 | else |
578 | aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS; | 580 | aad_pdata->mic_det_thr = DA7219_AAD_MIC_DET_THR_500_OHMS; |
579 | 581 | ||
580 | if (of_property_read_u32(aad_np, "dlg,jack-ins-deb", &of_val32) >= 0) | 582 | if (fwnode_property_read_u32(aad_np, "dlg,jack-ins-deb", &fw_val32) >= 0) |
581 | aad_pdata->jack_ins_deb = | 583 | aad_pdata->jack_ins_deb = |
582 | da7219_aad_of_jack_ins_deb(codec, of_val32); | 584 | da7219_aad_fw_jack_ins_deb(codec, fw_val32); |
583 | else | 585 | else |
584 | aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; | 586 | aad_pdata->jack_ins_deb = DA7219_AAD_JACK_INS_DEB_20MS; |
585 | 587 | ||
586 | if (!of_property_read_string(aad_np, "dlg,jack-det-rate", &of_str)) | 588 | if (!fwnode_property_read_string(aad_np, "dlg,jack-det-rate", &fw_str)) |
587 | aad_pdata->jack_det_rate = | 589 | aad_pdata->jack_det_rate = |
588 | da7219_aad_of_jack_det_rate(codec, of_str); | 590 | da7219_aad_fw_jack_det_rate(codec, fw_str); |
589 | else | 591 | else |
590 | aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; | 592 | aad_pdata->jack_det_rate = DA7219_AAD_JACK_DET_RATE_256_512MS; |
591 | 593 | ||
592 | if (of_property_read_u32(aad_np, "dlg,jack-rem-deb", &of_val32) >= 0) | 594 | if (fwnode_property_read_u32(aad_np, "dlg,jack-rem-deb", &fw_val32) >= 0) |
593 | aad_pdata->jack_rem_deb = | 595 | aad_pdata->jack_rem_deb = |
594 | da7219_aad_of_jack_rem_deb(codec, of_val32); | 596 | da7219_aad_fw_jack_rem_deb(codec, fw_val32); |
595 | else | 597 | else |
596 | aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; | 598 | aad_pdata->jack_rem_deb = DA7219_AAD_JACK_REM_DEB_1MS; |
597 | 599 | ||
598 | if (of_property_read_u32(aad_np, "dlg,a-d-btn-thr", &of_val32) >= 0) | 600 | if (fwnode_property_read_u32(aad_np, "dlg,a-d-btn-thr", &fw_val32) >= 0) |
599 | aad_pdata->a_d_btn_thr = (u8) of_val32; | 601 | aad_pdata->a_d_btn_thr = (u8) fw_val32; |
600 | else | 602 | else |
601 | aad_pdata->a_d_btn_thr = 0xA; | 603 | aad_pdata->a_d_btn_thr = 0xA; |
602 | 604 | ||
603 | if (of_property_read_u32(aad_np, "dlg,d-b-btn-thr", &of_val32) >= 0) | 605 | if (fwnode_property_read_u32(aad_np, "dlg,d-b-btn-thr", &fw_val32) >= 0) |
604 | aad_pdata->d_b_btn_thr = (u8) of_val32; | 606 | aad_pdata->d_b_btn_thr = (u8) fw_val32; |
605 | else | 607 | else |
606 | aad_pdata->d_b_btn_thr = 0x16; | 608 | aad_pdata->d_b_btn_thr = 0x16; |
607 | 609 | ||
608 | if (of_property_read_u32(aad_np, "dlg,b-c-btn-thr", &of_val32) >= 0) | 610 | if (fwnode_property_read_u32(aad_np, "dlg,b-c-btn-thr", &fw_val32) >= 0) |
609 | aad_pdata->b_c_btn_thr = (u8) of_val32; | 611 | aad_pdata->b_c_btn_thr = (u8) fw_val32; |
610 | else | 612 | else |
611 | aad_pdata->b_c_btn_thr = 0x21; | 613 | aad_pdata->b_c_btn_thr = 0x21; |
612 | 614 | ||
613 | if (of_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &of_val32) >= 0) | 615 | if (fwnode_property_read_u32(aad_np, "dlg,c-mic-btn-thr", &fw_val32) >= 0) |
614 | aad_pdata->c_mic_btn_thr = (u8) of_val32; | 616 | aad_pdata->c_mic_btn_thr = (u8) fw_val32; |
615 | else | 617 | else |
616 | aad_pdata->c_mic_btn_thr = 0x3E; | 618 | aad_pdata->c_mic_btn_thr = 0x3E; |
617 | 619 | ||
618 | if (of_property_read_u32(aad_np, "dlg,btn-avg", &of_val32) >= 0) | 620 | if (fwnode_property_read_u32(aad_np, "dlg,btn-avg", &fw_val32) >= 0) |
619 | aad_pdata->btn_avg = da7219_aad_of_btn_avg(codec, of_val32); | 621 | aad_pdata->btn_avg = da7219_aad_fw_btn_avg(codec, fw_val32); |
620 | else | 622 | else |
621 | aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; | 623 | aad_pdata->btn_avg = DA7219_AAD_BTN_AVG_2; |
622 | 624 | ||
623 | if (of_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &of_val32) >= 0) | 625 | if (fwnode_property_read_u32(aad_np, "dlg,adc-1bit-rpt", &fw_val32) >= 0) |
624 | aad_pdata->adc_1bit_rpt = | 626 | aad_pdata->adc_1bit_rpt = |
625 | da7219_aad_of_adc_1bit_rpt(codec, of_val32); | 627 | da7219_aad_fw_adc_1bit_rpt(codec, fw_val32); |
626 | else | 628 | else |
627 | aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; | 629 | aad_pdata->adc_1bit_rpt = DA7219_AAD_ADC_1BIT_RPT_1; |
628 | 630 | ||
629 | out: | ||
630 | of_node_put(aad_np); | ||
631 | |||
632 | return aad_pdata; | 631 | return aad_pdata; |
633 | } | 632 | } |
634 | 633 | ||
@@ -769,9 +768,9 @@ int da7219_aad_init(struct snd_soc_codec *codec) | |||
769 | da7219->aad = da7219_aad; | 768 | da7219->aad = da7219_aad; |
770 | da7219_aad->codec = codec; | 769 | da7219_aad->codec = codec; |
771 | 770 | ||
772 | /* Handle any DT/platform data */ | 771 | /* Handle any DT/ACPI/platform data */ |
773 | if ((codec->dev->of_node) && (da7219->pdata)) | 772 | if (da7219->pdata && !da7219->pdata->aad_pdata) |
774 | da7219->pdata->aad_pdata = da7219_aad_of_to_pdata(codec); | 773 | da7219->pdata->aad_pdata = da7219_aad_fw_to_pdata(codec); |
775 | 774 | ||
776 | da7219_aad_handle_pdata(codec); | 775 | da7219_aad_handle_pdata(codec); |
777 | 776 | ||
diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index 5c93899f1f0e..50ea94317cb3 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/of_device.h> | 17 | #include <linux/of_device.h> |
18 | #include <linux/property.h> | ||
18 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> | 20 | #include <linux/slab.h> |
20 | #include <linux/pm.h> | 21 | #include <linux/pm.h> |
@@ -1418,7 +1419,7 @@ static struct snd_soc_dai_driver da7219_dai = { | |||
1418 | 1419 | ||
1419 | 1420 | ||
1420 | /* | 1421 | /* |
1421 | * DT | 1422 | * DT/ACPI |
1422 | */ | 1423 | */ |
1423 | 1424 | ||
1424 | static const struct of_device_id da7219_of_match[] = { | 1425 | static const struct of_device_id da7219_of_match[] = { |
@@ -1434,7 +1435,7 @@ static const struct acpi_device_id da7219_acpi_match[] = { | |||
1434 | MODULE_DEVICE_TABLE(acpi, da7219_acpi_match); | 1435 | MODULE_DEVICE_TABLE(acpi, da7219_acpi_match); |
1435 | 1436 | ||
1436 | static enum da7219_micbias_voltage | 1437 | static enum da7219_micbias_voltage |
1437 | da7219_of_micbias_lvl(struct snd_soc_codec *codec, u32 val) | 1438 | da7219_fw_micbias_lvl(struct device *dev, u32 val) |
1438 | { | 1439 | { |
1439 | switch (val) { | 1440 | switch (val) { |
1440 | case 1600: | 1441 | case 1600: |
@@ -1450,13 +1451,13 @@ static enum da7219_micbias_voltage | |||
1450 | case 2600: | 1451 | case 2600: |
1451 | return DA7219_MICBIAS_2_6V; | 1452 | return DA7219_MICBIAS_2_6V; |
1452 | default: | 1453 | default: |
1453 | dev_warn(codec->dev, "Invalid micbias level"); | 1454 | dev_warn(dev, "Invalid micbias level"); |
1454 | return DA7219_MICBIAS_2_2V; | 1455 | return DA7219_MICBIAS_2_2V; |
1455 | } | 1456 | } |
1456 | } | 1457 | } |
1457 | 1458 | ||
1458 | static enum da7219_mic_amp_in_sel | 1459 | static enum da7219_mic_amp_in_sel |
1459 | da7219_of_mic_amp_in_sel(struct snd_soc_codec *codec, const char *str) | 1460 | da7219_fw_mic_amp_in_sel(struct device *dev, const char *str) |
1460 | { | 1461 | { |
1461 | if (!strcmp(str, "diff")) { | 1462 | if (!strcmp(str, "diff")) { |
1462 | return DA7219_MIC_AMP_IN_SEL_DIFF; | 1463 | return DA7219_MIC_AMP_IN_SEL_DIFF; |
@@ -1465,29 +1466,29 @@ static enum da7219_mic_amp_in_sel | |||
1465 | } else if (!strcmp(str, "se_n")) { | 1466 | } else if (!strcmp(str, "se_n")) { |
1466 | return DA7219_MIC_AMP_IN_SEL_SE_N; | 1467 | return DA7219_MIC_AMP_IN_SEL_SE_N; |
1467 | } else { | 1468 | } else { |
1468 | dev_warn(codec->dev, "Invalid mic input type selection"); | 1469 | dev_warn(dev, "Invalid mic input type selection"); |
1469 | return DA7219_MIC_AMP_IN_SEL_DIFF; | 1470 | return DA7219_MIC_AMP_IN_SEL_DIFF; |
1470 | } | 1471 | } |
1471 | } | 1472 | } |
1472 | 1473 | ||
1473 | static struct da7219_pdata *da7219_of_to_pdata(struct snd_soc_codec *codec) | 1474 | static struct da7219_pdata *da7219_fw_to_pdata(struct snd_soc_codec *codec) |
1474 | { | 1475 | { |
1475 | struct device_node *np = codec->dev->of_node; | 1476 | struct device *dev = codec->dev; |
1476 | struct da7219_pdata *pdata; | 1477 | struct da7219_pdata *pdata; |
1477 | const char *of_str; | 1478 | const char *of_str; |
1478 | u32 of_val32; | 1479 | u32 of_val32; |
1479 | 1480 | ||
1480 | pdata = devm_kzalloc(codec->dev, sizeof(*pdata), GFP_KERNEL); | 1481 | pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); |
1481 | if (!pdata) | 1482 | if (!pdata) |
1482 | return NULL; | 1483 | return NULL; |
1483 | 1484 | ||
1484 | if (of_property_read_u32(np, "dlg,micbias-lvl", &of_val32) >= 0) | 1485 | if (device_property_read_u32(dev, "dlg,micbias-lvl", &of_val32) >= 0) |
1485 | pdata->micbias_lvl = da7219_of_micbias_lvl(codec, of_val32); | 1486 | pdata->micbias_lvl = da7219_fw_micbias_lvl(dev, of_val32); |
1486 | else | 1487 | else |
1487 | pdata->micbias_lvl = DA7219_MICBIAS_2_2V; | 1488 | pdata->micbias_lvl = DA7219_MICBIAS_2_2V; |
1488 | 1489 | ||
1489 | if (!of_property_read_string(np, "dlg,mic-amp-in-sel", &of_str)) | 1490 | if (!device_property_read_string(dev, "dlg,mic-amp-in-sel", &of_str)) |
1490 | pdata->mic_amp_in_sel = da7219_of_mic_amp_in_sel(codec, of_str); | 1491 | pdata->mic_amp_in_sel = da7219_fw_mic_amp_in_sel(dev, of_str); |
1491 | else | 1492 | else |
1492 | pdata->mic_amp_in_sel = DA7219_MIC_AMP_IN_SEL_DIFF; | 1493 | pdata->mic_amp_in_sel = DA7219_MIC_AMP_IN_SEL_DIFF; |
1493 | 1494 | ||
@@ -1662,11 +1663,10 @@ static int da7219_probe(struct snd_soc_codec *codec) | |||
1662 | break; | 1663 | break; |
1663 | } | 1664 | } |
1664 | 1665 | ||
1665 | /* Handle DT/Platform data */ | 1666 | /* Handle DT/ACPI/Platform data */ |
1666 | if (codec->dev->of_node) | 1667 | da7219->pdata = dev_get_platdata(codec->dev); |
1667 | da7219->pdata = da7219_of_to_pdata(codec); | 1668 | if (!da7219->pdata) |
1668 | else | 1669 | da7219->pdata = da7219_fw_to_pdata(codec); |
1669 | da7219->pdata = dev_get_platdata(codec->dev); | ||
1670 | 1670 | ||
1671 | da7219_handle_pdata(codec); | 1671 | da7219_handle_pdata(codec); |
1672 | 1672 | ||
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index 2abb742fc47b..4e181b270d95 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c | |||
@@ -1124,8 +1124,10 @@ static void hdac_hdmi_present_sense(struct hdac_hdmi_pin *pin, int repoll) | |||
1124 | } | 1124 | } |
1125 | hdac_hdmi_parse_eld(edev, pin); | 1125 | hdac_hdmi_parse_eld(edev, pin); |
1126 | 1126 | ||
1127 | print_hex_dump_bytes("ELD: ", DUMP_PREFIX_OFFSET, | 1127 | print_hex_dump_debug("ELD: ", |
1128 | pin->eld.eld_buffer, pin->eld.eld_size); | 1128 | DUMP_PREFIX_OFFSET, 16, 1, |
1129 | pin->eld.eld_buffer, pin->eld.eld_size, | ||
1130 | true); | ||
1129 | } else { | 1131 | } else { |
1130 | pin->eld.monitor_present = false; | 1132 | pin->eld.monitor_present = false; |
1131 | pin->eld.eld_valid = false; | 1133 | pin->eld.eld_valid = false; |
@@ -1816,6 +1818,7 @@ static const struct dev_pm_ops hdac_hdmi_pm = { | |||
1816 | static const struct hda_device_id hdmi_list[] = { | 1818 | static const struct hda_device_id hdmi_list[] = { |
1817 | HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), | 1819 | HDA_CODEC_EXT_ENTRY(0x80862809, 0x100000, "Skylake HDMI", 0), |
1818 | HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), | 1820 | HDA_CODEC_EXT_ENTRY(0x8086280a, 0x100000, "Broxton HDMI", 0), |
1821 | HDA_CODEC_EXT_ENTRY(0x8086280b, 0x100000, "Kabylake HDMI", 0), | ||
1819 | {} | 1822 | {} |
1820 | }; | 1823 | }; |
1821 | 1824 | ||
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 8e36e883e453..f27d115626db 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c | |||
@@ -112,7 +112,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, | |||
112 | return ret; | 112 | return ret; |
113 | 113 | ||
114 | if (hcp->hcd.ops->audio_startup) { | 114 | if (hcp->hcd.ops->audio_startup) { |
115 | ret = hcp->hcd.ops->audio_startup(dai->dev->parent); | 115 | ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); |
116 | if (ret) { | 116 | if (ret) { |
117 | mutex_lock(&hcp->current_stream_lock); | 117 | mutex_lock(&hcp->current_stream_lock); |
118 | hcp->current_stream = NULL; | 118 | hcp->current_stream = NULL; |
@@ -122,8 +122,8 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, | |||
122 | } | 122 | } |
123 | 123 | ||
124 | if (hcp->hcd.ops->get_eld) { | 124 | if (hcp->hcd.ops->get_eld) { |
125 | ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->eld, | 125 | ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, |
126 | sizeof(hcp->eld)); | 126 | hcp->eld, sizeof(hcp->eld)); |
127 | 127 | ||
128 | if (!ret) { | 128 | if (!ret) { |
129 | ret = snd_pcm_hw_constraint_eld(substream->runtime, | 129 | ret = snd_pcm_hw_constraint_eld(substream->runtime, |
@@ -144,7 +144,7 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, | |||
144 | 144 | ||
145 | WARN_ON(hcp->current_stream != substream); | 145 | WARN_ON(hcp->current_stream != substream); |
146 | 146 | ||
147 | hcp->hcd.ops->audio_shutdown(dai->dev->parent); | 147 | hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); |
148 | 148 | ||
149 | mutex_lock(&hcp->current_stream_lock); | 149 | mutex_lock(&hcp->current_stream_lock); |
150 | hcp->current_stream = NULL; | 150 | hcp->current_stream = NULL; |
@@ -195,8 +195,8 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, | |||
195 | hp.sample_rate = params_rate(params); | 195 | hp.sample_rate = params_rate(params); |
196 | hp.channels = params_channels(params); | 196 | hp.channels = params_channels(params); |
197 | 197 | ||
198 | return hcp->hcd.ops->hw_params(dai->dev->parent, &hcp->daifmt[dai->id], | 198 | return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, |
199 | &hp); | 199 | &hcp->daifmt[dai->id], &hp); |
200 | } | 200 | } |
201 | 201 | ||
202 | static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, | 202 | static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, |
@@ -280,7 +280,8 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) | |||
280 | dev_dbg(dai->dev, "%s()\n", __func__); | 280 | dev_dbg(dai->dev, "%s()\n", __func__); |
281 | 281 | ||
282 | if (hcp->hcd.ops->digital_mute) | 282 | if (hcp->hcd.ops->digital_mute) |
283 | return hcp->hcd.ops->digital_mute(dai->dev->parent, mute); | 283 | return hcp->hcd.ops->digital_mute(dai->dev->parent, |
284 | hcp->hcd.data, mute); | ||
284 | 285 | ||
285 | return 0; | 286 | return 0; |
286 | } | 287 | } |
diff --git a/sound/soc/codecs/max98504.c b/sound/soc/codecs/max98504.c new file mode 100644 index 000000000000..a7320e709890 --- /dev/null +++ b/sound/soc/codecs/max98504.c | |||
@@ -0,0 +1,383 @@ | |||
1 | /* | ||
2 | * MAX98504 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2013 - 2014 Maxim Integrated Products | ||
5 | * Copyright 2016 Samsung Electronics Co., Ltd. | ||
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/delay.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/regulator/consumer.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/types.h> | ||
18 | #include <sound/soc.h> | ||
19 | |||
20 | #include "max98504.h" | ||
21 | |||
22 | static const char * const max98504_supply_names[] = { | ||
23 | "DVDD", | ||
24 | "DIOVDD", | ||
25 | "PVDD", | ||
26 | }; | ||
27 | #define MAX98504_NUM_SUPPLIES ARRAY_SIZE(max98504_supply_names) | ||
28 | |||
29 | struct max98504_priv { | ||
30 | struct regmap *regmap; | ||
31 | struct regulator_bulk_data supplies[MAX98504_NUM_SUPPLIES]; | ||
32 | unsigned int pcm_rx_channels; | ||
33 | bool brownout_enable; | ||
34 | unsigned int brownout_threshold; | ||
35 | unsigned int brownout_attenuation; | ||
36 | unsigned int brownout_attack_hold; | ||
37 | unsigned int brownout_timed_hold; | ||
38 | unsigned int brownout_release_rate; | ||
39 | }; | ||
40 | |||
41 | static struct reg_default max98504_reg_defaults[] = { | ||
42 | { 0x01, 0}, | ||
43 | { 0x02, 0}, | ||
44 | { 0x03, 0}, | ||
45 | { 0x04, 0}, | ||
46 | { 0x10, 0}, | ||
47 | { 0x11, 0}, | ||
48 | { 0x12, 0}, | ||
49 | { 0x13, 0}, | ||
50 | { 0x14, 0}, | ||
51 | { 0x15, 0}, | ||
52 | { 0x16, 0}, | ||
53 | { 0x17, 0}, | ||
54 | { 0x18, 0}, | ||
55 | { 0x19, 0}, | ||
56 | { 0x1A, 0}, | ||
57 | { 0x20, 0}, | ||
58 | { 0x21, 0}, | ||
59 | { 0x22, 0}, | ||
60 | { 0x23, 0}, | ||
61 | { 0x24, 0}, | ||
62 | { 0x25, 0}, | ||
63 | { 0x26, 0}, | ||
64 | { 0x27, 0}, | ||
65 | { 0x28, 0}, | ||
66 | { 0x30, 0}, | ||
67 | { 0x31, 0}, | ||
68 | { 0x32, 0}, | ||
69 | { 0x33, 0}, | ||
70 | { 0x34, 0}, | ||
71 | { 0x35, 0}, | ||
72 | { 0x36, 0}, | ||
73 | { 0x37, 0}, | ||
74 | { 0x38, 0}, | ||
75 | { 0x39, 0}, | ||
76 | { 0x40, 0}, | ||
77 | { 0x41, 0}, | ||
78 | }; | ||
79 | |||
80 | static bool max98504_volatile_register(struct device *dev, unsigned int reg) | ||
81 | { | ||
82 | switch (reg) { | ||
83 | case MAX98504_INTERRUPT_STATUS: | ||
84 | case MAX98504_INTERRUPT_FLAGS: | ||
85 | case MAX98504_INTERRUPT_FLAG_CLEARS: | ||
86 | case MAX98504_WATCHDOG_CLEAR: | ||
87 | case MAX98504_GLOBAL_ENABLE: | ||
88 | case MAX98504_SOFTWARE_RESET: | ||
89 | return true; | ||
90 | default: | ||
91 | return false; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | static bool max98504_readable_register(struct device *dev, unsigned int reg) | ||
96 | { | ||
97 | switch (reg) { | ||
98 | case MAX98504_SOFTWARE_RESET: | ||
99 | case MAX98504_WATCHDOG_CLEAR: | ||
100 | case MAX98504_INTERRUPT_FLAG_CLEARS: | ||
101 | return false; | ||
102 | default: | ||
103 | return true; | ||
104 | } | ||
105 | } | ||
106 | |||
107 | static int max98504_pcm_rx_ev(struct snd_soc_dapm_widget *w, | ||
108 | struct snd_kcontrol *kcontrol, int event) | ||
109 | { | ||
110 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); | ||
111 | struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c); | ||
112 | |||
113 | switch (event) { | ||
114 | case SND_SOC_DAPM_PRE_PMU: | ||
115 | regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE, | ||
116 | max98504->pcm_rx_channels); | ||
117 | break; | ||
118 | case SND_SOC_DAPM_POST_PMD: | ||
119 | regmap_write(max98504->regmap, MAX98504_PCM_RX_ENABLE, 0); | ||
120 | break; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int max98504_component_probe(struct snd_soc_component *c) | ||
127 | { | ||
128 | struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c); | ||
129 | struct regmap *map = max98504->regmap; | ||
130 | int ret; | ||
131 | |||
132 | ret = regulator_bulk_enable(MAX98504_NUM_SUPPLIES, max98504->supplies); | ||
133 | if (ret < 0) | ||
134 | return ret; | ||
135 | |||
136 | regmap_write(map, MAX98504_SOFTWARE_RESET, 0x1); | ||
137 | msleep(20); | ||
138 | |||
139 | if (!max98504->brownout_enable) | ||
140 | return 0; | ||
141 | |||
142 | regmap_write(map, MAX98504_PVDD_BROWNOUT_ENABLE, 0x1); | ||
143 | |||
144 | regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_1, | ||
145 | (max98504->brownout_threshold & 0x1f) << 3 | | ||
146 | (max98504->brownout_attenuation & 0x3)); | ||
147 | |||
148 | regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_2, | ||
149 | max98504->brownout_attack_hold & 0xff); | ||
150 | |||
151 | regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_3, | ||
152 | max98504->brownout_timed_hold & 0xff); | ||
153 | |||
154 | regmap_write(map, MAX98504_PVDD_BROWNOUT_CONFIG_4, | ||
155 | max98504->brownout_release_rate & 0xff); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void max98504_component_remove(struct snd_soc_component *c) | ||
161 | { | ||
162 | struct max98504_priv *max98504 = snd_soc_component_get_drvdata(c); | ||
163 | |||
164 | regulator_bulk_disable(MAX98504_NUM_SUPPLIES, max98504->supplies); | ||
165 | } | ||
166 | |||
167 | static const char *spk_source_mux_text[] = { | ||
168 | "PCM Monomix", "Analog In", "PDM Left", "PDM Right" | ||
169 | }; | ||
170 | |||
171 | static const struct soc_enum spk_source_mux_enum = | ||
172 | SOC_ENUM_SINGLE(MAX98504_SPEAKER_SOURCE_SELECT, | ||
173 | 0, ARRAY_SIZE(spk_source_mux_text), | ||
174 | spk_source_mux_text); | ||
175 | |||
176 | static const struct snd_kcontrol_new spk_source_mux = | ||
177 | SOC_DAPM_ENUM("SPK Source", spk_source_mux_enum); | ||
178 | |||
179 | static const struct snd_soc_dapm_route max98504_dapm_routes[] = { | ||
180 | { "SPKOUT", NULL, "Global Enable" }, | ||
181 | { "SPK Source", "PCM Monomix", "DAC PCM" }, | ||
182 | { "SPK Source", "Analog In", "AIN" }, | ||
183 | { "SPK Source", "PDM Left", "DAC PDM" }, | ||
184 | { "SPK Source", "PDM Right", "DAC PDM" }, | ||
185 | }; | ||
186 | |||
187 | static const struct snd_soc_dapm_widget max98504_dapm_widgets[] = { | ||
188 | SND_SOC_DAPM_SUPPLY("Global Enable", MAX98504_GLOBAL_ENABLE, | ||
189 | 0, 0, NULL, 0), | ||
190 | SND_SOC_DAPM_INPUT("AIN"), | ||
191 | SND_SOC_DAPM_AIF_OUT("AIF2OUTL", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), | ||
192 | SND_SOC_DAPM_AIF_OUT("AIF2OUTR", "AIF2 Capture", 1, SND_SOC_NOPM, 0, 0), | ||
193 | SND_SOC_DAPM_DAC_E("DAC PCM", NULL, SND_SOC_NOPM, 0, 0, | ||
194 | max98504_pcm_rx_ev, | ||
195 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
196 | SND_SOC_DAPM_DAC("DAC PDM", NULL, MAX98504_PDM_RX_ENABLE, 0, 0), | ||
197 | SND_SOC_DAPM_MUX("SPK Source", SND_SOC_NOPM, 0, 0, &spk_source_mux), | ||
198 | SND_SOC_DAPM_REG(snd_soc_dapm_spk, "SPKOUT", | ||
199 | MAX98504_SPEAKER_ENABLE, 0, 1, 1, 0), | ||
200 | }; | ||
201 | |||
202 | static int max98504_set_tdm_slot(struct snd_soc_dai *dai, | ||
203 | unsigned int tx_mask, unsigned int rx_mask, | ||
204 | int slots, int slot_width) | ||
205 | { | ||
206 | struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai); | ||
207 | struct regmap *map = max98504->regmap; | ||
208 | |||
209 | |||
210 | switch (dai->id) { | ||
211 | case MAX98504_DAI_ID_PCM: | ||
212 | regmap_write(map, MAX98504_PCM_TX_ENABLE, tx_mask); | ||
213 | max98504->pcm_rx_channels = rx_mask; | ||
214 | break; | ||
215 | |||
216 | case MAX98504_DAI_ID_PDM: | ||
217 | regmap_write(map, MAX98504_PDM_TX_ENABLE, tx_mask); | ||
218 | break; | ||
219 | default: | ||
220 | WARN_ON(1); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | static int max98504_set_channel_map(struct snd_soc_dai *dai, | ||
226 | unsigned int tx_num, unsigned int *tx_slot, | ||
227 | unsigned int rx_num, unsigned int *rx_slot) | ||
228 | { | ||
229 | struct max98504_priv *max98504 = snd_soc_dai_get_drvdata(dai); | ||
230 | struct regmap *map = max98504->regmap; | ||
231 | unsigned int i, sources = 0; | ||
232 | |||
233 | for (i = 0; i < tx_num; i++) | ||
234 | if (tx_slot[i]) | ||
235 | sources |= (1 << i); | ||
236 | |||
237 | switch (dai->id) { | ||
238 | case MAX98504_DAI_ID_PCM: | ||
239 | regmap_write(map, MAX98504_PCM_TX_CHANNEL_SOURCES, | ||
240 | sources); | ||
241 | break; | ||
242 | |||
243 | case MAX98504_DAI_ID_PDM: | ||
244 | regmap_write(map, MAX98504_PDM_TX_CONTROL, sources); | ||
245 | break; | ||
246 | default: | ||
247 | WARN_ON(1); | ||
248 | } | ||
249 | |||
250 | regmap_write(map, MAX98504_MEASUREMENT_ENABLE, sources ? 0x3 : 0x01); | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | static const struct snd_soc_dai_ops max98504_dai_ops = { | ||
256 | .set_tdm_slot = max98504_set_tdm_slot, | ||
257 | .set_channel_map = max98504_set_channel_map, | ||
258 | }; | ||
259 | |||
260 | #define MAX98504_FORMATS (SNDRV_PCM_FMTBIT_S8|SNDRV_PCM_FMTBIT_S16_LE|\ | ||
261 | SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE) | ||
262 | #define MAX98504_PDM_RATES (SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|\ | ||
263 | SNDRV_PCM_RATE_32000|SNDRV_PCM_RATE_44100|\ | ||
264 | SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_88200|\ | ||
265 | SNDRV_PCM_RATE_96000) | ||
266 | |||
267 | static struct snd_soc_dai_driver max98504_dai[] = { | ||
268 | /* TODO: Add the PCM interface definitions */ | ||
269 | { | ||
270 | .name = "max98504-aif2", | ||
271 | .id = MAX98504_DAI_ID_PDM, | ||
272 | .playback = { | ||
273 | .stream_name = "AIF2 Playback", | ||
274 | .channels_min = 1, | ||
275 | .channels_max = 2, | ||
276 | .rates = MAX98504_PDM_RATES, | ||
277 | .formats = MAX98504_FORMATS, | ||
278 | }, | ||
279 | .capture = { | ||
280 | .stream_name = "AIF2 Capture", | ||
281 | .channels_min = 1, | ||
282 | .channels_max = 2, | ||
283 | .rates = MAX98504_PDM_RATES, | ||
284 | .formats = MAX98504_FORMATS, | ||
285 | }, | ||
286 | .ops = &max98504_dai_ops, | ||
287 | }, | ||
288 | }; | ||
289 | |||
290 | static const struct snd_soc_component_driver max98504_component_driver = { | ||
291 | .probe = max98504_component_probe, | ||
292 | .remove = max98504_component_remove, | ||
293 | .dapm_widgets = max98504_dapm_widgets, | ||
294 | .num_dapm_widgets = ARRAY_SIZE(max98504_dapm_widgets), | ||
295 | .dapm_routes = max98504_dapm_routes, | ||
296 | .num_dapm_routes = ARRAY_SIZE(max98504_dapm_routes), | ||
297 | }; | ||
298 | |||
299 | static const struct regmap_config max98504_regmap = { | ||
300 | .reg_bits = 16, | ||
301 | .val_bits = 8, | ||
302 | .max_register = MAX98504_MAX_REGISTER, | ||
303 | .reg_defaults = max98504_reg_defaults, | ||
304 | .num_reg_defaults = ARRAY_SIZE(max98504_reg_defaults), | ||
305 | .volatile_reg = max98504_volatile_register, | ||
306 | .readable_reg = max98504_readable_register, | ||
307 | .cache_type = REGCACHE_RBTREE, | ||
308 | }; | ||
309 | |||
310 | static int max98504_i2c_probe(struct i2c_client *client, | ||
311 | const struct i2c_device_id *id) | ||
312 | { | ||
313 | struct device *dev = &client->dev; | ||
314 | struct device_node *node = dev->of_node; | ||
315 | struct max98504_priv *max98504; | ||
316 | int i, ret; | ||
317 | |||
318 | max98504 = devm_kzalloc(dev, sizeof(*max98504), GFP_KERNEL); | ||
319 | if (!max98504) | ||
320 | return -ENOMEM; | ||
321 | |||
322 | if (node) { | ||
323 | if (!of_property_read_u32(node, "maxim,brownout-threshold", | ||
324 | &max98504->brownout_threshold)) | ||
325 | max98504->brownout_enable = true; | ||
326 | |||
327 | of_property_read_u32(node, "maxim,brownout-attenuation", | ||
328 | &max98504->brownout_attenuation); | ||
329 | of_property_read_u32(node, "maxim,brownout-attack-hold-ms", | ||
330 | &max98504->brownout_attack_hold); | ||
331 | of_property_read_u32(node, "maxim,brownout-timed-hold-ms", | ||
332 | &max98504->brownout_timed_hold); | ||
333 | of_property_read_u32(node, "maxim,brownout-release-rate-ms", | ||
334 | &max98504->brownout_release_rate); | ||
335 | } | ||
336 | |||
337 | max98504->regmap = devm_regmap_init_i2c(client, &max98504_regmap); | ||
338 | if (IS_ERR(max98504->regmap)) { | ||
339 | ret = PTR_ERR(max98504->regmap); | ||
340 | dev_err(&client->dev, "regmap initialization failed: %d\n", ret); | ||
341 | return ret; | ||
342 | } | ||
343 | |||
344 | for (i = 0; i < MAX98504_NUM_SUPPLIES; i++) | ||
345 | max98504->supplies[i].supply = max98504_supply_names[i]; | ||
346 | |||
347 | ret = devm_regulator_bulk_get(dev, MAX98504_NUM_SUPPLIES, | ||
348 | max98504->supplies); | ||
349 | if (ret < 0) | ||
350 | return ret; | ||
351 | |||
352 | i2c_set_clientdata(client, max98504); | ||
353 | |||
354 | return devm_snd_soc_register_component(dev, &max98504_component_driver, | ||
355 | max98504_dai, ARRAY_SIZE(max98504_dai)); | ||
356 | } | ||
357 | |||
358 | #ifdef CONFIG_OF | ||
359 | static const struct of_device_id max98504_of_match[] = { | ||
360 | { .compatible = "maxim,max98504" }, | ||
361 | { }, | ||
362 | }; | ||
363 | MODULE_DEVICE_TABLE(of, max98504_of_match); | ||
364 | #endif | ||
365 | |||
366 | static const struct i2c_device_id max98504_i2c_id[] = { | ||
367 | { "max98504" }, | ||
368 | { } | ||
369 | }; | ||
370 | MODULE_DEVICE_TABLE(i2c, max98504_i2c_id); | ||
371 | |||
372 | static struct i2c_driver max98504_i2c_driver = { | ||
373 | .driver = { | ||
374 | .name = "max98504", | ||
375 | .of_match_table = of_match_ptr(max98504_of_match), | ||
376 | }, | ||
377 | .probe = max98504_i2c_probe, | ||
378 | .id_table = max98504_i2c_id, | ||
379 | }; | ||
380 | module_i2c_driver(max98504_i2c_driver); | ||
381 | |||
382 | MODULE_DESCRIPTION("ASoC MAX98504 driver"); | ||
383 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/max98504.h b/sound/soc/codecs/max98504.h new file mode 100644 index 000000000000..afbefad2d5ce --- /dev/null +++ b/sound/soc/codecs/max98504.h | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * MAX98504 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2011 - 2012 Maxim Integrated Products | ||
5 | * Copyright 2016 Samsung Electronics Co., Ltd. | ||
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 | #ifndef MAX98504_H_ | ||
12 | #define MAX98504_H_ | ||
13 | |||
14 | /* | ||
15 | * MAX98504 Register Definitions | ||
16 | */ | ||
17 | #define MAX98504_INTERRUPT_STATUS 0x01 | ||
18 | #define MAX98504_INTERRUPT_FLAGS 0x02 | ||
19 | #define MAX98504_INTERRUPT_ENABLE 0x03 | ||
20 | #define MAX98504_INTERRUPT_FLAG_CLEARS 0x04 | ||
21 | #define MAX98504_GPIO_ENABLE 0x10 | ||
22 | #define MAX98504_GPIO_CONFIG 0x11 | ||
23 | #define MAX98504_WATCHDOG_ENABLE 0x12 | ||
24 | #define MAX98504_WATCHDOG_CONFIG 0x13 | ||
25 | #define MAX98504_WATCHDOG_CLEAR 0x14 | ||
26 | #define MAX98504_CLOCK_MONITOR_ENABLE 0x15 | ||
27 | #define MAX98504_PVDD_BROWNOUT_ENABLE 0x16 | ||
28 | #define MAX98504_PVDD_BROWNOUT_CONFIG_1 0x17 | ||
29 | #define MAX98504_PVDD_BROWNOUT_CONFIG_2 0x18 | ||
30 | #define MAX98504_PVDD_BROWNOUT_CONFIG_3 0x19 | ||
31 | #define MAX98504_PVDD_BROWNOUT_CONFIG_4 0x1a | ||
32 | #define MAX98504_PCM_RX_ENABLE 0x20 | ||
33 | #define MAX98504_PCM_TX_ENABLE 0x21 | ||
34 | #define MAX98504_PCM_TX_HIZ_CONTROL 0x22 | ||
35 | #define MAX98504_PCM_TX_CHANNEL_SOURCES 0x23 | ||
36 | #define MAX98504_PCM_MODE_CONFIG 0x24 | ||
37 | #define MAX98504_PCM_DSP_CONFIG 0x25 | ||
38 | #define MAX98504_PCM_CLOCK_SETUP 0x26 | ||
39 | #define MAX98504_PCM_SAMPLE_RATE_SETUP 0x27 | ||
40 | #define MAX98504_PCM_TO_SPEAKER_MONOMIX 0x28 | ||
41 | #define MAX98504_PDM_TX_ENABLE 0x30 | ||
42 | #define MAX98504_PDM_TX_HIZ_CONTROL 0x31 | ||
43 | #define MAX98504_PDM_TX_CONTROL 0x32 | ||
44 | #define MAX98504_PDM_RX_ENABLE 0x33 | ||
45 | #define MAX98504_SPEAKER_ENABLE 0x34 | ||
46 | #define MAX98504_SPEAKER_SOURCE_SELECT 0x35 | ||
47 | #define MAX98504_MEASUREMENT_ENABLE 0x36 | ||
48 | #define MAX98504_ANALOGUE_INPUT_GAIN 0x37 | ||
49 | #define MAX98504_TEMPERATURE_LIMIT_CONFIG 0x38 | ||
50 | #define MAX98504_GLOBAL_ENABLE 0x40 | ||
51 | #define MAX98504_SOFTWARE_RESET 0x41 | ||
52 | #define MAX98504_REV_ID 0x7fff | ||
53 | |||
54 | #define MAX98504_MAX_REGISTER 0x7fff | ||
55 | |||
56 | #define MAX98504_DAI_ID_PCM 1 | ||
57 | #define MAX98504_DAI_ID_PDM 2 | ||
58 | |||
59 | #endif /* MAX98504_H_ */ | ||
diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c new file mode 100644 index 000000000000..68074c92a7c0 --- /dev/null +++ b/sound/soc/codecs/max9860.c | |||
@@ -0,0 +1,753 @@ | |||
1 | /* | ||
2 | * Driver for the MAX9860 Mono Audio Voice Codec | ||
3 | * | ||
4 | * https://datasheets.maximintegrated.com/en/ds/MAX9860.pdf | ||
5 | * | ||
6 | * The driver does not support sidetone since the DVST register field is | ||
7 | * backwards with the mute near the maximum level instead of the minimum. | ||
8 | * | ||
9 | * Author: Peter Rosin <peda@axentia.s> | ||
10 | * Copyright 2016 Axentia Technologies | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * version 2 as published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, but | ||
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/regmap.h> | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/regulator/consumer.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/tlv.h> | ||
34 | |||
35 | #include "max9860.h" | ||
36 | |||
37 | struct max9860_priv { | ||
38 | struct regmap *regmap; | ||
39 | struct regulator *dvddio; | ||
40 | struct notifier_block dvddio_nb; | ||
41 | u8 psclk; | ||
42 | unsigned long pclk_rate; | ||
43 | int fmt; | ||
44 | }; | ||
45 | |||
46 | static int max9860_dvddio_event(struct notifier_block *nb, | ||
47 | unsigned long event, void *data) | ||
48 | { | ||
49 | struct max9860_priv *max9860 = container_of(nb, struct max9860_priv, | ||
50 | dvddio_nb); | ||
51 | if (event & REGULATOR_EVENT_DISABLE) { | ||
52 | regcache_mark_dirty(max9860->regmap); | ||
53 | regcache_cache_only(max9860->regmap, true); | ||
54 | } | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static const struct reg_default max9860_reg_defaults[] = { | ||
60 | { MAX9860_PWRMAN, 0x00 }, | ||
61 | { MAX9860_INTEN, 0x00 }, | ||
62 | { MAX9860_SYSCLK, 0x00 }, | ||
63 | { MAX9860_AUDIOCLKHIGH, 0x00 }, | ||
64 | { MAX9860_AUDIOCLKLOW, 0x00 }, | ||
65 | { MAX9860_IFC1A, 0x00 }, | ||
66 | { MAX9860_IFC1B, 0x00 }, | ||
67 | { MAX9860_VOICEFLTR, 0x00 }, | ||
68 | { MAX9860_DACATTN, 0x00 }, | ||
69 | { MAX9860_ADCLEVEL, 0x00 }, | ||
70 | { MAX9860_DACGAIN, 0x00 }, | ||
71 | { MAX9860_MICGAIN, 0x00 }, | ||
72 | { MAX9860_MICADC, 0x00 }, | ||
73 | { MAX9860_NOISEGATE, 0x00 }, | ||
74 | }; | ||
75 | |||
76 | static bool max9860_readable(struct device *dev, unsigned int reg) | ||
77 | { | ||
78 | switch (reg) { | ||
79 | case MAX9860_INTRSTATUS ... MAX9860_MICGAIN: | ||
80 | case MAX9860_MICADC ... MAX9860_PWRMAN: | ||
81 | case MAX9860_REVISION: | ||
82 | return true; | ||
83 | } | ||
84 | |||
85 | return false; | ||
86 | } | ||
87 | |||
88 | static bool max9860_writeable(struct device *dev, unsigned int reg) | ||
89 | { | ||
90 | switch (reg) { | ||
91 | case MAX9860_INTEN ... MAX9860_MICGAIN: | ||
92 | case MAX9860_MICADC ... MAX9860_PWRMAN: | ||
93 | return true; | ||
94 | } | ||
95 | |||
96 | return false; | ||
97 | } | ||
98 | |||
99 | static bool max9860_volatile(struct device *dev, unsigned int reg) | ||
100 | { | ||
101 | switch (reg) { | ||
102 | case MAX9860_INTRSTATUS: | ||
103 | case MAX9860_MICREADBACK: | ||
104 | return true; | ||
105 | } | ||
106 | |||
107 | return false; | ||
108 | } | ||
109 | |||
110 | static bool max9860_precious(struct device *dev, unsigned int reg) | ||
111 | { | ||
112 | switch (reg) { | ||
113 | case MAX9860_INTRSTATUS: | ||
114 | return true; | ||
115 | } | ||
116 | |||
117 | return false; | ||
118 | } | ||
119 | |||
120 | static const struct regmap_config max9860_regmap = { | ||
121 | .reg_bits = 8, | ||
122 | .val_bits = 8, | ||
123 | |||
124 | .readable_reg = max9860_readable, | ||
125 | .writeable_reg = max9860_writeable, | ||
126 | .volatile_reg = max9860_volatile, | ||
127 | .precious_reg = max9860_precious, | ||
128 | |||
129 | .max_register = MAX9860_MAX_REGISTER, | ||
130 | .reg_defaults = max9860_reg_defaults, | ||
131 | .num_reg_defaults = ARRAY_SIZE(max9860_reg_defaults), | ||
132 | .cache_type = REGCACHE_RBTREE, | ||
133 | }; | ||
134 | |||
135 | static const DECLARE_TLV_DB_SCALE(dva_tlv, -9100, 100, 1); | ||
136 | static const DECLARE_TLV_DB_SCALE(dvg_tlv, 0, 600, 0); | ||
137 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0); | ||
138 | static const DECLARE_TLV_DB_RANGE(pam_tlv, | ||
139 | 0, MAX9860_PAM_MAX - 1, TLV_DB_SCALE_ITEM(-2000, 2000, 1), | ||
140 | MAX9860_PAM_MAX, MAX9860_PAM_MAX, TLV_DB_SCALE_ITEM(3000, 0, 0)); | ||
141 | static const DECLARE_TLV_DB_SCALE(pgam_tlv, 0, 100, 0); | ||
142 | static const DECLARE_TLV_DB_SCALE(anth_tlv, -7600, 400, 1); | ||
143 | static const DECLARE_TLV_DB_SCALE(agcth_tlv, -1800, 100, 0); | ||
144 | |||
145 | static const char * const agchld_text[] = { | ||
146 | "AGC Disabled", "50ms", "100ms", "400ms" | ||
147 | }; | ||
148 | |||
149 | static SOC_ENUM_SINGLE_DECL(agchld_enum, MAX9860_MICADC, | ||
150 | MAX9860_AGCHLD_SHIFT, agchld_text); | ||
151 | |||
152 | static const char * const agcsrc_text[] = { | ||
153 | "Left ADC", "Left/Right ADC" | ||
154 | }; | ||
155 | |||
156 | static SOC_ENUM_SINGLE_DECL(agcsrc_enum, MAX9860_MICADC, | ||
157 | MAX9860_AGCSRC_SHIFT, agcsrc_text); | ||
158 | |||
159 | static const char * const agcatk_text[] = { | ||
160 | "3ms", "12ms", "50ms", "200ms" | ||
161 | }; | ||
162 | |||
163 | static SOC_ENUM_SINGLE_DECL(agcatk_enum, MAX9860_MICADC, | ||
164 | MAX9860_AGCATK_SHIFT, agcatk_text); | ||
165 | |||
166 | static const char * const agcrls_text[] = { | ||
167 | "78ms", "156ms", "312ms", "625ms", | ||
168 | "1.25s", "2.5s", "5s", "10s" | ||
169 | }; | ||
170 | |||
171 | static SOC_ENUM_SINGLE_DECL(agcrls_enum, MAX9860_MICADC, | ||
172 | MAX9860_AGCRLS_SHIFT, agcrls_text); | ||
173 | |||
174 | static const char * const filter_text[] = { | ||
175 | "Disabled", | ||
176 | "Elliptical HP 217Hz notch (16kHz)", | ||
177 | "Butterworth HP 500Hz (16kHz)", | ||
178 | "Elliptical HP 217Hz notch (8kHz)", | ||
179 | "Butterworth HP 500Hz (8kHz)", | ||
180 | "Butterworth HP 200Hz (48kHz)" | ||
181 | }; | ||
182 | |||
183 | static SOC_ENUM_SINGLE_DECL(avflt_enum, MAX9860_VOICEFLTR, | ||
184 | MAX9860_AVFLT_SHIFT, filter_text); | ||
185 | |||
186 | static SOC_ENUM_SINGLE_DECL(dvflt_enum, MAX9860_VOICEFLTR, | ||
187 | MAX9860_DVFLT_SHIFT, filter_text); | ||
188 | |||
189 | static const struct snd_kcontrol_new max9860_controls[] = { | ||
190 | SOC_SINGLE_TLV("Master Playback Volume", MAX9860_DACATTN, | ||
191 | MAX9860_DVA_SHIFT, MAX9860_DVA_MUTE, 1, dva_tlv), | ||
192 | SOC_SINGLE_TLV("DAC Gain Volume", MAX9860_DACGAIN, | ||
193 | MAX9860_DVG_SHIFT, MAX9860_DVG_MAX, 0, dvg_tlv), | ||
194 | SOC_DOUBLE_TLV("Line Capture Volume", MAX9860_ADCLEVEL, | ||
195 | MAX9860_ADCLL_SHIFT, MAX9860_ADCRL_SHIFT, MAX9860_ADCxL_MIN, 1, | ||
196 | adc_tlv), | ||
197 | |||
198 | SOC_ENUM("AGC Hold Time", agchld_enum), | ||
199 | SOC_ENUM("AGC/Noise Gate Source", agcsrc_enum), | ||
200 | SOC_ENUM("AGC Attack Time", agcatk_enum), | ||
201 | SOC_ENUM("AGC Release Time", agcrls_enum), | ||
202 | |||
203 | SOC_SINGLE_TLV("Noise Gate Threshold Volume", MAX9860_NOISEGATE, | ||
204 | MAX9860_ANTH_SHIFT, MAX9860_ANTH_MAX, 0, anth_tlv), | ||
205 | SOC_SINGLE_TLV("AGC Signal Threshold Volume", MAX9860_NOISEGATE, | ||
206 | MAX9860_AGCTH_SHIFT, MAX9860_AGCTH_MIN, 1, agcth_tlv), | ||
207 | |||
208 | SOC_SINGLE_TLV("Mic PGA Volume", MAX9860_MICGAIN, | ||
209 | MAX9860_PGAM_SHIFT, MAX9860_PGAM_MIN, 1, pgam_tlv), | ||
210 | SOC_SINGLE_TLV("Mic Preamp Volume", MAX9860_MICGAIN, | ||
211 | MAX9860_PAM_SHIFT, MAX9860_PAM_MAX, 0, pam_tlv), | ||
212 | |||
213 | SOC_ENUM("ADC Filter", avflt_enum), | ||
214 | SOC_ENUM("DAC Filter", dvflt_enum), | ||
215 | }; | ||
216 | |||
217 | static const struct snd_soc_dapm_widget max9860_dapm_widgets[] = { | ||
218 | SND_SOC_DAPM_INPUT("MICL"), | ||
219 | SND_SOC_DAPM_INPUT("MICR"), | ||
220 | |||
221 | SND_SOC_DAPM_ADC("ADCL", NULL, MAX9860_PWRMAN, MAX9860_ADCLEN_SHIFT, 0), | ||
222 | SND_SOC_DAPM_ADC("ADCR", NULL, MAX9860_PWRMAN, MAX9860_ADCREN_SHIFT, 0), | ||
223 | |||
224 | SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), | ||
225 | SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), | ||
226 | |||
227 | SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
228 | SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), | ||
229 | |||
230 | SND_SOC_DAPM_DAC("DAC", NULL, MAX9860_PWRMAN, MAX9860_DACEN_SHIFT, 0), | ||
231 | |||
232 | SND_SOC_DAPM_OUTPUT("OUT"), | ||
233 | |||
234 | SND_SOC_DAPM_SUPPLY("Supply", SND_SOC_NOPM, 0, 0, | ||
235 | NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
236 | SND_SOC_DAPM_REGULATOR_SUPPLY("AVDD", 0, 0), | ||
237 | SND_SOC_DAPM_REGULATOR_SUPPLY("DVDD", 0, 0), | ||
238 | SND_SOC_DAPM_CLOCK_SUPPLY("mclk"), | ||
239 | }; | ||
240 | |||
241 | static const struct snd_soc_dapm_route max9860_dapm_routes[] = { | ||
242 | { "ADCL", NULL, "MICL" }, | ||
243 | { "ADCR", NULL, "MICR" }, | ||
244 | { "AIFOUTL", NULL, "ADCL" }, | ||
245 | { "AIFOUTR", NULL, "ADCR" }, | ||
246 | |||
247 | { "DAC", NULL, "AIFINL" }, | ||
248 | { "DAC", NULL, "AIFINR" }, | ||
249 | { "OUT", NULL, "DAC" }, | ||
250 | |||
251 | { "Supply", NULL, "AVDD" }, | ||
252 | { "Supply", NULL, "DVDD" }, | ||
253 | { "Supply", NULL, "mclk" }, | ||
254 | |||
255 | { "DAC", NULL, "Supply" }, | ||
256 | { "ADCL", NULL, "Supply" }, | ||
257 | { "ADCR", NULL, "Supply" }, | ||
258 | }; | ||
259 | |||
260 | static int max9860_hw_params(struct snd_pcm_substream *substream, | ||
261 | struct snd_pcm_hw_params *params, | ||
262 | struct snd_soc_dai *dai) | ||
263 | { | ||
264 | struct snd_soc_codec *codec = dai->codec; | ||
265 | struct max9860_priv *max9860 = snd_soc_codec_get_drvdata(codec); | ||
266 | u8 master; | ||
267 | u8 ifc1a = 0; | ||
268 | u8 ifc1b = 0; | ||
269 | u8 sysclk = 0; | ||
270 | unsigned long n; | ||
271 | int ret; | ||
272 | |||
273 | dev_dbg(codec->dev, "hw_params %u Hz, %u channels\n", | ||
274 | params_rate(params), | ||
275 | params_channels(params)); | ||
276 | |||
277 | if (params_channels(params) == 2) | ||
278 | ifc1b |= MAX9860_ST; | ||
279 | |||
280 | switch (max9860->fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
281 | case SND_SOC_DAIFMT_CBS_CFS: | ||
282 | master = 0; | ||
283 | break; | ||
284 | case SND_SOC_DAIFMT_CBM_CFM: | ||
285 | master = MAX9860_MASTER; | ||
286 | break; | ||
287 | default: | ||
288 | return -EINVAL; | ||
289 | } | ||
290 | ifc1a |= master; | ||
291 | |||
292 | if (master) { | ||
293 | if (params_width(params) * params_channels(params) > 48) | ||
294 | ifc1b |= MAX9860_BSEL_64X; | ||
295 | else | ||
296 | ifc1b |= MAX9860_BSEL_48X; | ||
297 | } | ||
298 | |||
299 | switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
300 | case SND_SOC_DAIFMT_I2S: | ||
301 | ifc1a |= MAX9860_DDLY; | ||
302 | ifc1b |= MAX9860_ADLY; | ||
303 | break; | ||
304 | case SND_SOC_DAIFMT_LEFT_J: | ||
305 | ifc1a |= MAX9860_WCI; | ||
306 | break; | ||
307 | case SND_SOC_DAIFMT_DSP_A: | ||
308 | if (params_width(params) != 16) { | ||
309 | dev_err(codec->dev, | ||
310 | "DSP_A works for 16 bits per sample only.\n"); | ||
311 | return -EINVAL; | ||
312 | } | ||
313 | ifc1a |= MAX9860_DDLY | MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM; | ||
314 | ifc1b |= MAX9860_ADLY; | ||
315 | break; | ||
316 | case SND_SOC_DAIFMT_DSP_B: | ||
317 | if (params_width(params) != 16) { | ||
318 | dev_err(codec->dev, | ||
319 | "DSP_B works for 16 bits per sample only.\n"); | ||
320 | return -EINVAL; | ||
321 | } | ||
322 | ifc1a |= MAX9860_WCI | MAX9860_HIZ | MAX9860_TDM; | ||
323 | break; | ||
324 | default: | ||
325 | return -EINVAL; | ||
326 | } | ||
327 | |||
328 | switch (max9860->fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
329 | case SND_SOC_DAIFMT_NB_NF: | ||
330 | break; | ||
331 | case SND_SOC_DAIFMT_NB_IF: | ||
332 | switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
333 | case SND_SOC_DAIFMT_DSP_A: | ||
334 | case SND_SOC_DAIFMT_DSP_B: | ||
335 | return -EINVAL; | ||
336 | } | ||
337 | ifc1a ^= MAX9860_WCI; | ||
338 | break; | ||
339 | case SND_SOC_DAIFMT_IB_IF: | ||
340 | switch (max9860->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
341 | case SND_SOC_DAIFMT_DSP_A: | ||
342 | case SND_SOC_DAIFMT_DSP_B: | ||
343 | return -EINVAL; | ||
344 | } | ||
345 | ifc1a ^= MAX9860_WCI; | ||
346 | /* fall through */ | ||
347 | case SND_SOC_DAIFMT_IB_NF: | ||
348 | ifc1a ^= MAX9860_DBCI; | ||
349 | ifc1b ^= MAX9860_ABCI; | ||
350 | break; | ||
351 | default: | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | dev_dbg(codec->dev, "IFC1A %02x\n", ifc1a); | ||
356 | ret = regmap_write(max9860->regmap, MAX9860_IFC1A, ifc1a); | ||
357 | if (ret) { | ||
358 | dev_err(codec->dev, "Failed to set IFC1A: %d\n", ret); | ||
359 | return ret; | ||
360 | } | ||
361 | dev_dbg(codec->dev, "IFC1B %02x\n", ifc1b); | ||
362 | ret = regmap_write(max9860->regmap, MAX9860_IFC1B, ifc1b); | ||
363 | if (ret) { | ||
364 | dev_err(codec->dev, "Failed to set IFC1B: %d\n", ret); | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | /* | ||
369 | * Check if Integer Clock Mode is possible, but avoid it in slave mode | ||
370 | * since we then do not know if lrclk is derived from pclk and the | ||
371 | * datasheet mentions that the frequencies have to match exactly in | ||
372 | * order for this to work. | ||
373 | */ | ||
374 | if (params_rate(params) == 8000 || params_rate(params) == 16000) { | ||
375 | if (master) { | ||
376 | switch (max9860->pclk_rate) { | ||
377 | case 12000000: | ||
378 | sysclk = MAX9860_FREQ_12MHZ; | ||
379 | break; | ||
380 | case 13000000: | ||
381 | sysclk = MAX9860_FREQ_13MHZ; | ||
382 | break; | ||
383 | case 19200000: | ||
384 | sysclk = MAX9860_FREQ_19_2MHZ; | ||
385 | break; | ||
386 | default: | ||
387 | /* | ||
388 | * Integer Clock Mode not possible. Leave | ||
389 | * sysclk at zero and fall through to the | ||
390 | * code below for PLL mode. | ||
391 | */ | ||
392 | break; | ||
393 | } | ||
394 | |||
395 | if (sysclk && params_rate(params) == 16000) | ||
396 | sysclk |= MAX9860_16KHZ; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | /* | ||
401 | * Largest possible n: | ||
402 | * 65536 * 96 * 48kHz / 10MHz -> 30199 | ||
403 | * Smallest possible n: | ||
404 | * 65536 * 96 * 8kHz / 20MHz -> 2517 | ||
405 | * Both fit nicely in the available 15 bits, no need to apply any mask. | ||
406 | */ | ||
407 | n = DIV_ROUND_CLOSEST_ULL(65536ULL * 96 * params_rate(params), | ||
408 | max9860->pclk_rate); | ||
409 | |||
410 | if (!sysclk) { | ||
411 | /* PLL mode */ | ||
412 | if (params_rate(params) > 24000) | ||
413 | sysclk |= MAX9860_16KHZ; | ||
414 | |||
415 | if (!master) | ||
416 | n |= 1; /* trigger rapid pll lock mode */ | ||
417 | } | ||
418 | |||
419 | sysclk |= max9860->psclk; | ||
420 | dev_dbg(codec->dev, "SYSCLK %02x\n", sysclk); | ||
421 | ret = regmap_write(max9860->regmap, | ||
422 | MAX9860_SYSCLK, sysclk); | ||
423 | if (ret) { | ||
424 | dev_err(codec->dev, "Failed to set SYSCLK: %d\n", ret); | ||
425 | return ret; | ||
426 | } | ||
427 | dev_dbg(codec->dev, "N %lu\n", n); | ||
428 | ret = regmap_write(max9860->regmap, | ||
429 | MAX9860_AUDIOCLKHIGH, n >> 8); | ||
430 | if (ret) { | ||
431 | dev_err(codec->dev, "Failed to set NHI: %d\n", ret); | ||
432 | return ret; | ||
433 | } | ||
434 | ret = regmap_write(max9860->regmap, | ||
435 | MAX9860_AUDIOCLKLOW, n & 0xff); | ||
436 | if (ret) { | ||
437 | dev_err(codec->dev, "Failed to set NLO: %d\n", ret); | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | if (!master) { | ||
442 | dev_dbg(codec->dev, "Enable PLL\n"); | ||
443 | ret = regmap_update_bits(max9860->regmap, MAX9860_AUDIOCLKHIGH, | ||
444 | MAX9860_PLL, MAX9860_PLL); | ||
445 | if (ret) { | ||
446 | dev_err(codec->dev, "Failed to enable PLL: %d\n", ret); | ||
447 | return ret; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int max9860_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
455 | { | ||
456 | struct snd_soc_codec *codec = dai->codec; | ||
457 | struct max9860_priv *max9860 = snd_soc_codec_get_drvdata(codec); | ||
458 | |||
459 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
460 | case SND_SOC_DAIFMT_CBM_CFM: | ||
461 | case SND_SOC_DAIFMT_CBS_CFS: | ||
462 | max9860->fmt = fmt; | ||
463 | return 0; | ||
464 | |||
465 | default: | ||
466 | return -EINVAL; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | static const struct snd_soc_dai_ops max9860_dai_ops = { | ||
471 | .hw_params = max9860_hw_params, | ||
472 | .set_fmt = max9860_set_fmt, | ||
473 | }; | ||
474 | |||
475 | static struct snd_soc_dai_driver max9860_dai = { | ||
476 | .name = "max9860-hifi", | ||
477 | .playback = { | ||
478 | .stream_name = "Playback", | ||
479 | .channels_min = 1, | ||
480 | .channels_max = 2, | ||
481 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
482 | .rate_min = 8000, | ||
483 | .rate_max = 48000, | ||
484 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
485 | SNDRV_PCM_FMTBIT_S24_LE | | ||
486 | SNDRV_PCM_FMTBIT_S32_LE, | ||
487 | }, | ||
488 | .capture = { | ||
489 | .stream_name = "Capture", | ||
490 | .channels_min = 1, | ||
491 | .channels_max = 2, | ||
492 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
493 | .rate_min = 8000, | ||
494 | .rate_max = 48000, | ||
495 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
496 | SNDRV_PCM_FMTBIT_S24_LE | | ||
497 | SNDRV_PCM_FMTBIT_S32_LE, | ||
498 | }, | ||
499 | .ops = &max9860_dai_ops, | ||
500 | .symmetric_rates = 1, | ||
501 | }; | ||
502 | |||
503 | static int max9860_set_bias_level(struct snd_soc_codec *codec, | ||
504 | enum snd_soc_bias_level level) | ||
505 | { | ||
506 | struct max9860_priv *max9860 = dev_get_drvdata(codec->dev); | ||
507 | int ret; | ||
508 | |||
509 | switch (level) { | ||
510 | case SND_SOC_BIAS_ON: | ||
511 | case SND_SOC_BIAS_PREPARE: | ||
512 | break; | ||
513 | |||
514 | case SND_SOC_BIAS_STANDBY: | ||
515 | ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN, | ||
516 | MAX9860_SHDN, MAX9860_SHDN); | ||
517 | if (ret) { | ||
518 | dev_err(codec->dev, "Failed to remove SHDN: %d\n", ret); | ||
519 | return ret; | ||
520 | } | ||
521 | break; | ||
522 | |||
523 | case SND_SOC_BIAS_OFF: | ||
524 | ret = regmap_update_bits(max9860->regmap, MAX9860_PWRMAN, | ||
525 | MAX9860_SHDN, 0); | ||
526 | if (ret) { | ||
527 | dev_err(codec->dev, "Failed to request SHDN: %d\n", | ||
528 | ret); | ||
529 | return ret; | ||
530 | } | ||
531 | break; | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static struct snd_soc_codec_driver max9860_codec_driver = { | ||
538 | .set_bias_level = max9860_set_bias_level, | ||
539 | .idle_bias_off = true, | ||
540 | |||
541 | .controls = max9860_controls, | ||
542 | .num_controls = ARRAY_SIZE(max9860_controls), | ||
543 | .dapm_widgets = max9860_dapm_widgets, | ||
544 | .num_dapm_widgets = ARRAY_SIZE(max9860_dapm_widgets), | ||
545 | .dapm_routes = max9860_dapm_routes, | ||
546 | .num_dapm_routes = ARRAY_SIZE(max9860_dapm_routes), | ||
547 | }; | ||
548 | |||
549 | #ifdef CONFIG_PM | ||
550 | static int max9860_suspend(struct device *dev) | ||
551 | { | ||
552 | struct max9860_priv *max9860 = dev_get_drvdata(dev); | ||
553 | int ret; | ||
554 | |||
555 | ret = regmap_update_bits(max9860->regmap, MAX9860_SYSCLK, | ||
556 | MAX9860_PSCLK, MAX9860_PSCLK_OFF); | ||
557 | if (ret) { | ||
558 | dev_err(dev, "Failed to disable clock: %d\n", ret); | ||
559 | return ret; | ||
560 | } | ||
561 | |||
562 | regulator_disable(max9860->dvddio); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | static int max9860_resume(struct device *dev) | ||
568 | { | ||
569 | struct max9860_priv *max9860 = dev_get_drvdata(dev); | ||
570 | int ret; | ||
571 | |||
572 | ret = regulator_enable(max9860->dvddio); | ||
573 | if (ret) { | ||
574 | dev_err(dev, "Failed to enable DVDDIO: %d\n", ret); | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | regcache_cache_only(max9860->regmap, false); | ||
579 | ret = regcache_sync(max9860->regmap); | ||
580 | if (ret) { | ||
581 | dev_err(dev, "Failed to sync cache: %d\n", ret); | ||
582 | return ret; | ||
583 | } | ||
584 | |||
585 | ret = regmap_update_bits(max9860->regmap, MAX9860_SYSCLK, | ||
586 | MAX9860_PSCLK, max9860->psclk); | ||
587 | if (ret) { | ||
588 | dev_err(dev, "Failed to enable clock: %d\n", ret); | ||
589 | return ret; | ||
590 | } | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | #endif | ||
595 | |||
596 | static const struct dev_pm_ops max9860_pm_ops = { | ||
597 | SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL) | ||
598 | }; | ||
599 | |||
600 | static int max9860_probe(struct i2c_client *i2c, | ||
601 | const struct i2c_device_id *id) | ||
602 | { | ||
603 | struct device *dev = &i2c->dev; | ||
604 | struct max9860_priv *max9860; | ||
605 | int ret; | ||
606 | struct clk *mclk; | ||
607 | unsigned long mclk_rate; | ||
608 | int i; | ||
609 | int intr; | ||
610 | |||
611 | max9860 = devm_kzalloc(dev, sizeof(struct max9860_priv), GFP_KERNEL); | ||
612 | if (!max9860) | ||
613 | return -ENOMEM; | ||
614 | |||
615 | max9860->dvddio = devm_regulator_get(dev, "DVDDIO"); | ||
616 | if (IS_ERR(max9860->dvddio)) { | ||
617 | ret = PTR_ERR(max9860->dvddio); | ||
618 | if (ret != -EPROBE_DEFER) | ||
619 | dev_err(dev, "Failed to get DVDDIO supply: %d\n", ret); | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | max9860->dvddio_nb.notifier_call = max9860_dvddio_event; | ||
624 | |||
625 | ret = regulator_register_notifier(max9860->dvddio, &max9860->dvddio_nb); | ||
626 | if (ret) | ||
627 | dev_err(dev, "Failed to register DVDDIO notifier: %d\n", ret); | ||
628 | |||
629 | ret = regulator_enable(max9860->dvddio); | ||
630 | if (ret != 0) { | ||
631 | dev_err(dev, "Failed to enable DVDDIO: %d\n", ret); | ||
632 | return ret; | ||
633 | } | ||
634 | |||
635 | max9860->regmap = devm_regmap_init_i2c(i2c, &max9860_regmap); | ||
636 | if (IS_ERR(max9860->regmap)) { | ||
637 | ret = PTR_ERR(max9860->regmap); | ||
638 | goto err_regulator; | ||
639 | } | ||
640 | |||
641 | dev_set_drvdata(dev, max9860); | ||
642 | |||
643 | /* | ||
644 | * mclk has to be in the 10MHz to 60MHz range. | ||
645 | * psclk is used to scale mclk into pclk so that | ||
646 | * pclk is in the 10MHz to 20MHz range. | ||
647 | */ | ||
648 | mclk = clk_get(dev, "mclk"); | ||
649 | |||
650 | if (IS_ERR(mclk)) { | ||
651 | ret = PTR_ERR(mclk); | ||
652 | if (ret != -EPROBE_DEFER) | ||
653 | dev_err(dev, "Failed to get MCLK: %d\n", ret); | ||
654 | goto err_regulator; | ||
655 | } | ||
656 | |||
657 | mclk_rate = clk_get_rate(mclk); | ||
658 | clk_put(mclk); | ||
659 | |||
660 | if (mclk_rate > 60000000 || mclk_rate < 10000000) { | ||
661 | dev_err(dev, "Bad mclk %luHz (needs 10MHz - 60MHz)\n", | ||
662 | mclk_rate); | ||
663 | ret = -EINVAL; | ||
664 | goto err_regulator; | ||
665 | } | ||
666 | if (mclk_rate >= 40000000) | ||
667 | max9860->psclk = 3; | ||
668 | else if (mclk_rate >= 20000000) | ||
669 | max9860->psclk = 2; | ||
670 | else | ||
671 | max9860->psclk = 1; | ||
672 | max9860->pclk_rate = mclk_rate >> (max9860->psclk - 1); | ||
673 | max9860->psclk <<= MAX9860_PSCLK_SHIFT; | ||
674 | dev_dbg(dev, "mclk %lu pclk %lu\n", mclk_rate, max9860->pclk_rate); | ||
675 | |||
676 | regcache_cache_bypass(max9860->regmap, true); | ||
677 | for (i = 0; i < max9860_regmap.num_reg_defaults; ++i) { | ||
678 | ret = regmap_write(max9860->regmap, | ||
679 | max9860_regmap.reg_defaults[i].reg, | ||
680 | max9860_regmap.reg_defaults[i].def); | ||
681 | if (ret) { | ||
682 | dev_err(dev, "Failed to initialize register %u: %d\n", | ||
683 | max9860_regmap.reg_defaults[i].reg, ret); | ||
684 | goto err_regulator; | ||
685 | } | ||
686 | } | ||
687 | regcache_cache_bypass(max9860->regmap, false); | ||
688 | |||
689 | ret = regmap_read(max9860->regmap, MAX9860_INTRSTATUS, &intr); | ||
690 | if (ret) { | ||
691 | dev_err(dev, "Failed to clear INTRSTATUS: %d\n", ret); | ||
692 | goto err_regulator; | ||
693 | } | ||
694 | |||
695 | pm_runtime_set_active(dev); | ||
696 | pm_runtime_enable(dev); | ||
697 | pm_runtime_idle(dev); | ||
698 | |||
699 | ret = snd_soc_register_codec(dev, &max9860_codec_driver, | ||
700 | &max9860_dai, 1); | ||
701 | if (ret) { | ||
702 | dev_err(dev, "Failed to register CODEC: %d\n", ret); | ||
703 | goto err_pm; | ||
704 | } | ||
705 | |||
706 | return 0; | ||
707 | |||
708 | err_pm: | ||
709 | pm_runtime_disable(dev); | ||
710 | err_regulator: | ||
711 | regulator_disable(max9860->dvddio); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | static int max9860_remove(struct i2c_client *i2c) | ||
716 | { | ||
717 | struct device *dev = &i2c->dev; | ||
718 | struct max9860_priv *max9860 = dev_get_drvdata(dev); | ||
719 | |||
720 | snd_soc_unregister_codec(dev); | ||
721 | pm_runtime_disable(dev); | ||
722 | regulator_disable(max9860->dvddio); | ||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | static const struct i2c_device_id max9860_i2c_id[] = { | ||
727 | { "max9860", }, | ||
728 | { } | ||
729 | }; | ||
730 | MODULE_DEVICE_TABLE(i2c, max9860_i2c_id); | ||
731 | |||
732 | static const struct of_device_id max9860_of_match[] = { | ||
733 | { .compatible = "maxim,max9860", }, | ||
734 | { } | ||
735 | }; | ||
736 | MODULE_DEVICE_TABLE(of, max9860_of_match); | ||
737 | |||
738 | static struct i2c_driver max9860_i2c_driver = { | ||
739 | .probe = max9860_probe, | ||
740 | .remove = max9860_remove, | ||
741 | .id_table = max9860_i2c_id, | ||
742 | .driver = { | ||
743 | .name = "max9860", | ||
744 | .of_match_table = max9860_of_match, | ||
745 | .pm = &max9860_pm_ops, | ||
746 | }, | ||
747 | }; | ||
748 | |||
749 | module_i2c_driver(max9860_i2c_driver); | ||
750 | |||
751 | MODULE_DESCRIPTION("ASoC MAX9860 Mono Audio Voice Codec driver"); | ||
752 | MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); | ||
753 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/max9860.h b/sound/soc/codecs/max9860.h new file mode 100644 index 000000000000..22041bd67a7d --- /dev/null +++ b/sound/soc/codecs/max9860.h | |||
@@ -0,0 +1,162 @@ | |||
1 | /* | ||
2 | * Driver for the MAX9860 Mono Audio Voice Codec | ||
3 | * | ||
4 | * Author: Peter Rosin <peda@axentia.s> | ||
5 | * Copyright 2016 Axentia Technologies | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _SND_SOC_MAX9860 | ||
18 | #define _SND_SOC_MAX9860 | ||
19 | |||
20 | #define MAX9860_INTRSTATUS 0x00 | ||
21 | #define MAX9860_MICREADBACK 0x01 | ||
22 | #define MAX9860_INTEN 0x02 | ||
23 | #define MAX9860_SYSCLK 0x03 | ||
24 | #define MAX9860_AUDIOCLKHIGH 0x04 | ||
25 | #define MAX9860_AUDIOCLKLOW 0x05 | ||
26 | #define MAX9860_IFC1A 0x06 | ||
27 | #define MAX9860_IFC1B 0x07 | ||
28 | #define MAX9860_VOICEFLTR 0x08 | ||
29 | #define MAX9860_DACATTN 0x09 | ||
30 | #define MAX9860_ADCLEVEL 0x0a | ||
31 | #define MAX9860_DACGAIN 0x0b | ||
32 | #define MAX9860_MICGAIN 0x0c | ||
33 | #define MAX9860_RESERVED 0x0d | ||
34 | #define MAX9860_MICADC 0x0e | ||
35 | #define MAX9860_NOISEGATE 0x0f | ||
36 | #define MAX9860_PWRMAN 0x10 | ||
37 | #define MAX9860_REVISION 0xff | ||
38 | |||
39 | #define MAX9860_MAX_REGISTER 0xff | ||
40 | |||
41 | /* INTRSTATUS */ | ||
42 | #define MAX9860_CLD 0x80 | ||
43 | #define MAX9860_SLD 0x40 | ||
44 | #define MAX9860_ULK 0x20 | ||
45 | |||
46 | /* MICREADBACK */ | ||
47 | #define MAX9860_NG 0xe0 | ||
48 | #define MAX9860_AGC 0x1f | ||
49 | |||
50 | /* INTEN */ | ||
51 | #define MAX9860_ICLD 0x80 | ||
52 | #define MAX9860_ISLD 0x40 | ||
53 | #define MAX9860_IULK 0x20 | ||
54 | |||
55 | /* SYSCLK */ | ||
56 | #define MAX9860_PSCLK 0x30 | ||
57 | #define MAX9860_PSCLK_OFF 0x00 | ||
58 | #define MAX9860_PSCLK_SHIFT 4 | ||
59 | #define MAX9860_FREQ 0x06 | ||
60 | #define MAX9860_FREQ_NORMAL 0x00 | ||
61 | #define MAX9860_FREQ_12MHZ 0x02 | ||
62 | #define MAX9860_FREQ_13MHZ 0x04 | ||
63 | #define MAX9860_FREQ_19_2MHZ 0x06 | ||
64 | #define MAX9860_16KHZ 0x01 | ||
65 | |||
66 | /* AUDIOCLKHIGH */ | ||
67 | #define MAX9860_PLL 0x80 | ||
68 | #define MAX9860_NHI 0x7f | ||
69 | |||
70 | /* AUDIOCLKLOW */ | ||
71 | #define MAX9860_NLO 0xff | ||
72 | |||
73 | /* IFC1A */ | ||
74 | #define MAX9860_MASTER 0x80 | ||
75 | #define MAX9860_WCI 0x40 | ||
76 | #define MAX9860_DBCI 0x20 | ||
77 | #define MAX9860_DDLY 0x10 | ||
78 | #define MAX9860_HIZ 0x08 | ||
79 | #define MAX9860_TDM 0x04 | ||
80 | |||
81 | /* IFC1B */ | ||
82 | #define MAX9860_ABCI 0x20 | ||
83 | #define MAX9860_ADLY 0x10 | ||
84 | #define MAX9860_ST 0x08 | ||
85 | #define MAX9860_BSEL 0x07 | ||
86 | #define MAX9860_BSEL_OFF 0x00 | ||
87 | #define MAX9860_BSEL_64X 0x01 | ||
88 | #define MAX9860_BSEL_48X 0x02 | ||
89 | #define MAX9860_BSEL_PCLK_2 0x04 | ||
90 | #define MAX9860_BSEL_PCLK_4 0x05 | ||
91 | #define MAX9860_BSEL_PCLK_8 0x06 | ||
92 | #define MAX9860_BSEL_PCLK_16 0x07 | ||
93 | |||
94 | /* VOICEFLTR */ | ||
95 | #define MAX9860_AVFLT 0xf0 | ||
96 | #define MAX9860_AVFLT_SHIFT 4 | ||
97 | #define MAX9860_AVFLT_COUNT 6 | ||
98 | #define MAX9860_DVFLT 0x0f | ||
99 | #define MAX9860_DVFLT_SHIFT 0 | ||
100 | #define MAX9860_DVFLT_COUNT 6 | ||
101 | |||
102 | /* DACATTN */ | ||
103 | #define MAX9860_DVA 0xfe | ||
104 | #define MAX9860_DVA_SHIFT 1 | ||
105 | #define MAX9860_DVA_MUTE 0x5e | ||
106 | |||
107 | /* ADCLEVEL */ | ||
108 | #define MAX9860_ADCRL 0xf0 | ||
109 | #define MAX9860_ADCRL_SHIFT 4 | ||
110 | #define MAX9860_ADCLL 0x0f | ||
111 | #define MAX9860_ADCLL_SHIFT 0 | ||
112 | #define MAX9860_ADCxL_MIN 15 | ||
113 | |||
114 | /* DACGAIN */ | ||
115 | #define MAX9860_DVG 0x60 | ||
116 | #define MAX9860_DVG_SHIFT 5 | ||
117 | #define MAX9860_DVG_MAX 3 | ||
118 | #define MAX9860_DVST 0x1f | ||
119 | #define MAX9860_DVST_SHIFT 0 | ||
120 | #define MAX9860_DVST_MIN 31 | ||
121 | |||
122 | /* MICGAIN */ | ||
123 | #define MAX9860_PAM 0x60 | ||
124 | #define MAX9860_PAM_SHIFT 5 | ||
125 | #define MAX9860_PAM_MAX 3 | ||
126 | #define MAX9860_PGAM 0x1f | ||
127 | #define MAX9860_PGAM_SHIFT 0 | ||
128 | #define MAX9860_PGAM_MIN 20 | ||
129 | |||
130 | /* MICADC */ | ||
131 | #define MAX9860_AGCSRC 0x80 | ||
132 | #define MAX9860_AGCSRC_SHIFT 7 | ||
133 | #define MAX9860_AGCSRC_COUNT 2 | ||
134 | #define MAX9860_AGCRLS 0x70 | ||
135 | #define MAX9860_AGCRLS_SHIFT 4 | ||
136 | #define MAX9860_AGCRLS_COUNT 8 | ||
137 | #define MAX9860_AGCATK 0x0c | ||
138 | #define MAX9860_AGCATK_SHIFT 2 | ||
139 | #define MAX9860_AGCATK_COUNT 4 | ||
140 | #define MAX9860_AGCHLD 0x03 | ||
141 | #define MAX9860_AGCHLD_OFF 0x00 | ||
142 | #define MAX9860_AGCHLD_SHIFT 0 | ||
143 | #define MAX9860_AGCHLD_COUNT 4 | ||
144 | |||
145 | /* NOISEGATE */ | ||
146 | #define MAX9860_ANTH 0xf0 | ||
147 | #define MAX9860_ANTH_SHIFT 4 | ||
148 | #define MAX9860_ANTH_MAX 15 | ||
149 | #define MAX9860_AGCTH 0x0f | ||
150 | #define MAX9860_AGCTH_SHIFT 0 | ||
151 | #define MAX9860_AGCTH_MIN 15 | ||
152 | |||
153 | /* PWRMAN */ | ||
154 | #define MAX9860_SHDN 0x80 | ||
155 | #define MAX9860_DACEN 0x08 | ||
156 | #define MAX9860_DACEN_SHIFT 3 | ||
157 | #define MAX9860_ADCLEN 0x02 | ||
158 | #define MAX9860_ADCLEN_SHIFT 1 | ||
159 | #define MAX9860_ADCREN 0x01 | ||
160 | #define MAX9860_ADCREN_SHIFT 0 | ||
161 | |||
162 | #endif /* _SND_SOC_MAX9860 */ | ||
diff --git a/sound/soc/codecs/max9867.c b/sound/soc/codecs/max9867.c index 2a22fddeb6af..2a22fddeb6af 100755..100644 --- a/sound/soc/codecs/max9867.c +++ b/sound/soc/codecs/max9867.c | |||
diff --git a/sound/soc/codecs/max9867.h b/sound/soc/codecs/max9867.h index 65590b4ad62a..65590b4ad62a 100755..100644 --- a/sound/soc/codecs/max9867.h +++ b/sound/soc/codecs/max9867.h | |||
diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index 683769f0f246..5c9707ac4bbf 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
19 | #include <linux/acpi.h> | 19 | #include <linux/acpi.h> |
20 | #include <linux/math64.h> | 20 | #include <linux/math64.h> |
21 | #include <linux/semaphore.h> | ||
21 | 22 | ||
22 | #include <sound/initval.h> | 23 | #include <sound/initval.h> |
23 | #include <sound/tlv.h> | 24 | #include <sound/tlv.h> |
@@ -30,10 +31,22 @@ | |||
30 | 31 | ||
31 | #include "nau8825.h" | 32 | #include "nau8825.h" |
32 | 33 | ||
34 | |||
35 | #define NUVOTON_CODEC_DAI "nau8825-hifi" | ||
36 | |||
33 | #define NAU_FREF_MAX 13500000 | 37 | #define NAU_FREF_MAX 13500000 |
34 | #define NAU_FVCO_MAX 100000000 | 38 | #define NAU_FVCO_MAX 124000000 |
35 | #define NAU_FVCO_MIN 90000000 | 39 | #define NAU_FVCO_MIN 90000000 |
36 | 40 | ||
41 | /* cross talk suppression detection */ | ||
42 | #define LOG10_MAGIC 646456993 | ||
43 | #define GAIN_AUGMENT 22500 | ||
44 | #define SIDETONE_BASE 207000 | ||
45 | |||
46 | |||
47 | static int nau8825_configure_sysclk(struct nau8825 *nau8825, | ||
48 | int clk_id, unsigned int freq); | ||
49 | |||
37 | struct nau8825_fll { | 50 | struct nau8825_fll { |
38 | int mclk_src; | 51 | int mclk_src; |
39 | int ratio; | 52 | int ratio; |
@@ -156,6 +169,661 @@ static const struct reg_default nau8825_reg_defaults[] = { | |||
156 | { NAU8825_REG_CHARGE_PUMP, 0x0 }, | 169 | { NAU8825_REG_CHARGE_PUMP, 0x0 }, |
157 | }; | 170 | }; |
158 | 171 | ||
172 | /* register backup table when cross talk detection */ | ||
173 | static struct reg_default nau8825_xtalk_baktab[] = { | ||
174 | { NAU8825_REG_ADC_DGAIN_CTRL, 0 }, | ||
175 | { NAU8825_REG_HSVOL_CTRL, 0 }, | ||
176 | { NAU8825_REG_DACL_CTRL, 0 }, | ||
177 | { NAU8825_REG_DACR_CTRL, 0 }, | ||
178 | }; | ||
179 | |||
180 | static const unsigned short logtable[256] = { | ||
181 | 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, | ||
182 | 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, | ||
183 | 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, | ||
184 | 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, | ||
185 | 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, | ||
186 | 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, | ||
187 | 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, | ||
188 | 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, | ||
189 | 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, | ||
190 | 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, | ||
191 | 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, | ||
192 | 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, | ||
193 | 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, | ||
194 | 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, | ||
195 | 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, | ||
196 | 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, | ||
197 | 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, | ||
198 | 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, | ||
199 | 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, | ||
200 | 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, | ||
201 | 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, | ||
202 | 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, | ||
203 | 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, | ||
204 | 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, | ||
205 | 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, | ||
206 | 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, | ||
207 | 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, | ||
208 | 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, | ||
209 | 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, | ||
210 | 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, | ||
211 | 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, | ||
212 | 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 | ||
213 | }; | ||
214 | |||
215 | static struct snd_soc_dai *nau8825_get_codec_dai(struct nau8825 *nau8825) | ||
216 | { | ||
217 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(nau8825->dapm); | ||
218 | struct snd_soc_component *component = &codec->component; | ||
219 | struct snd_soc_dai *codec_dai, *_dai; | ||
220 | |||
221 | list_for_each_entry_safe(codec_dai, _dai, &component->dai_list, list) { | ||
222 | if (!strncmp(codec_dai->name, NUVOTON_CODEC_DAI, | ||
223 | strlen(NUVOTON_CODEC_DAI))) | ||
224 | return codec_dai; | ||
225 | } | ||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | static bool nau8825_dai_is_active(struct nau8825 *nau8825) | ||
230 | { | ||
231 | struct snd_soc_dai *codec_dai = nau8825_get_codec_dai(nau8825); | ||
232 | |||
233 | if (codec_dai) { | ||
234 | if (codec_dai->playback_active || codec_dai->capture_active) | ||
235 | return true; | ||
236 | } | ||
237 | return false; | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * nau8825_sema_acquire - acquire the semaphore of nau88l25 | ||
242 | * @nau8825: component to register the codec private data with | ||
243 | * @timeout: how long in jiffies to wait before failure or zero to wait | ||
244 | * until release | ||
245 | * | ||
246 | * Attempts to acquire the semaphore with number of jiffies. If no more | ||
247 | * tasks are allowed to acquire the semaphore, calling this function will | ||
248 | * put the task to sleep. If the semaphore is not released within the | ||
249 | * specified number of jiffies, this function returns. | ||
250 | * Acquires the semaphore without jiffies. If no more tasks are allowed | ||
251 | * to acquire the semaphore, calling this function will put the task to | ||
252 | * sleep until the semaphore is released. | ||
253 | * It returns if the semaphore was acquired. | ||
254 | */ | ||
255 | static void nau8825_sema_acquire(struct nau8825 *nau8825, long timeout) | ||
256 | { | ||
257 | int ret; | ||
258 | |||
259 | if (timeout) | ||
260 | ret = down_timeout(&nau8825->xtalk_sem, timeout); | ||
261 | else | ||
262 | ret = down_interruptible(&nau8825->xtalk_sem); | ||
263 | |||
264 | if (ret < 0) | ||
265 | dev_warn(nau8825->dev, "Acquire semaphone fail\n"); | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * nau8825_sema_release - release the semaphore of nau88l25 | ||
270 | * @nau8825: component to register the codec private data with | ||
271 | * | ||
272 | * Release the semaphore which may be called from any context and | ||
273 | * even by tasks which have never called down(). | ||
274 | */ | ||
275 | static inline void nau8825_sema_release(struct nau8825 *nau8825) | ||
276 | { | ||
277 | up(&nau8825->xtalk_sem); | ||
278 | } | ||
279 | |||
280 | /** | ||
281 | * nau8825_sema_reset - reset the semaphore for nau88l25 | ||
282 | * @nau8825: component to register the codec private data with | ||
283 | * | ||
284 | * Reset the counter of the semaphore. Call this function to restart | ||
285 | * a new round task management. | ||
286 | */ | ||
287 | static inline void nau8825_sema_reset(struct nau8825 *nau8825) | ||
288 | { | ||
289 | nau8825->xtalk_sem.count = 1; | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * Ramp up the headphone volume change gradually to target level. | ||
294 | * | ||
295 | * @nau8825: component to register the codec private data with | ||
296 | * @vol_from: the volume to start up | ||
297 | * @vol_to: the target volume | ||
298 | * @step: the volume span to move on | ||
299 | * | ||
300 | * The headphone volume is from 0dB to minimum -54dB and -1dB per step. | ||
301 | * If the volume changes sharp, there is a pop noise heard in headphone. We | ||
302 | * provide the function to ramp up the volume up or down by delaying 10ms | ||
303 | * per step. | ||
304 | */ | ||
305 | static void nau8825_hpvol_ramp(struct nau8825 *nau8825, | ||
306 | unsigned int vol_from, unsigned int vol_to, unsigned int step) | ||
307 | { | ||
308 | unsigned int value, volume, ramp_up, from, to; | ||
309 | |||
310 | if (vol_from == vol_to || step == 0) { | ||
311 | return; | ||
312 | } else if (vol_from < vol_to) { | ||
313 | ramp_up = true; | ||
314 | from = vol_from; | ||
315 | to = vol_to; | ||
316 | } else { | ||
317 | ramp_up = false; | ||
318 | from = vol_to; | ||
319 | to = vol_from; | ||
320 | } | ||
321 | /* only handle volume from 0dB to minimum -54dB */ | ||
322 | if (to > NAU8825_HP_VOL_MIN) | ||
323 | to = NAU8825_HP_VOL_MIN; | ||
324 | |||
325 | for (volume = from; volume < to; volume += step) { | ||
326 | if (ramp_up) | ||
327 | value = volume; | ||
328 | else | ||
329 | value = to - volume + from; | ||
330 | regmap_update_bits(nau8825->regmap, NAU8825_REG_HSVOL_CTRL, | ||
331 | NAU8825_HPL_VOL_MASK | NAU8825_HPR_VOL_MASK, | ||
332 | (value << NAU8825_HPL_VOL_SFT) | value); | ||
333 | usleep_range(10000, 10500); | ||
334 | } | ||
335 | if (ramp_up) | ||
336 | value = to; | ||
337 | else | ||
338 | value = from; | ||
339 | regmap_update_bits(nau8825->regmap, NAU8825_REG_HSVOL_CTRL, | ||
340 | NAU8825_HPL_VOL_MASK | NAU8825_HPR_VOL_MASK, | ||
341 | (value << NAU8825_HPL_VOL_SFT) | value); | ||
342 | } | ||
343 | |||
344 | /** | ||
345 | * Computes log10 of a value; the result is round off to 3 decimal. This func- | ||
346 | * tion takes reference to dvb-math. The source code locates as the following. | ||
347 | * Linux/drivers/media/dvb-core/dvb_math.c | ||
348 | * | ||
349 | * return log10(value) * 1000 | ||
350 | */ | ||
351 | static u32 nau8825_intlog10_dec3(u32 value) | ||
352 | { | ||
353 | u32 msb, logentry, significand, interpolation, log10val; | ||
354 | u64 log2val; | ||
355 | |||
356 | /* first detect the msb (count begins at 0) */ | ||
357 | msb = fls(value) - 1; | ||
358 | /** | ||
359 | * now we use a logtable after the following method: | ||
360 | * | ||
361 | * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 | ||
362 | * where x = msb and therefore 1 <= y < 2 | ||
363 | * first y is determined by shifting the value left | ||
364 | * so that msb is bit 31 | ||
365 | * 0x00231f56 -> 0x8C7D5800 | ||
366 | * the result is y * 2^31 -> "significand" | ||
367 | * then the highest 9 bits are used for a table lookup | ||
368 | * the highest bit is discarded because it's always set | ||
369 | * the highest nine bits in our example are 100011000 | ||
370 | * so we would use the entry 0x18 | ||
371 | */ | ||
372 | significand = value << (31 - msb); | ||
373 | logentry = (significand >> 23) & 0xff; | ||
374 | /** | ||
375 | * last step we do is interpolation because of the | ||
376 | * limitations of the log table the error is that part of | ||
377 | * the significand which isn't used for lookup then we | ||
378 | * compute the ratio between the error and the next table entry | ||
379 | * and interpolate it between the log table entry used and the | ||
380 | * next one the biggest error possible is 0x7fffff | ||
381 | * (in our example it's 0x7D5800) | ||
382 | * needed value for next table entry is 0x800000 | ||
383 | * so the interpolation is | ||
384 | * (error / 0x800000) * (logtable_next - logtable_current) | ||
385 | * in the implementation the division is moved to the end for | ||
386 | * better accuracy there is also an overflow correction if | ||
387 | * logtable_next is 256 | ||
388 | */ | ||
389 | interpolation = ((significand & 0x7fffff) * | ||
390 | ((logtable[(logentry + 1) & 0xff] - | ||
391 | logtable[logentry]) & 0xffff)) >> 15; | ||
392 | |||
393 | log2val = ((msb << 24) + (logtable[logentry] << 8) + interpolation); | ||
394 | /** | ||
395 | * log10(x) = log2(x) * log10(2) | ||
396 | */ | ||
397 | log10val = (log2val * LOG10_MAGIC) >> 31; | ||
398 | /** | ||
399 | * the result is round off to 3 decimal | ||
400 | */ | ||
401 | return log10val / ((1 << 24) / 1000); | ||
402 | } | ||
403 | |||
404 | /** | ||
405 | * computes cross talk suppression sidetone gain. | ||
406 | * | ||
407 | * @sig_org: orignal signal level | ||
408 | * @sig_cros: cross talk signal level | ||
409 | * | ||
410 | * The orignal and cross talk signal vlues need to be characterized. | ||
411 | * Once these values have been characterized, this sidetone value | ||
412 | * can be converted to decibel with the equation below. | ||
413 | * sidetone = 20 * log (original signal level / crosstalk signal level) | ||
414 | * | ||
415 | * return cross talk sidetone gain | ||
416 | */ | ||
417 | static u32 nau8825_xtalk_sidetone(u32 sig_org, u32 sig_cros) | ||
418 | { | ||
419 | u32 gain, sidetone; | ||
420 | |||
421 | if (unlikely(sig_org == 0) || unlikely(sig_cros == 0)) { | ||
422 | WARN_ON(1); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | sig_org = nau8825_intlog10_dec3(sig_org); | ||
427 | sig_cros = nau8825_intlog10_dec3(sig_cros); | ||
428 | if (sig_org >= sig_cros) | ||
429 | gain = (sig_org - sig_cros) * 20 + GAIN_AUGMENT; | ||
430 | else | ||
431 | gain = (sig_cros - sig_org) * 20 + GAIN_AUGMENT; | ||
432 | sidetone = SIDETONE_BASE - gain * 2; | ||
433 | sidetone /= 1000; | ||
434 | |||
435 | return sidetone; | ||
436 | } | ||
437 | |||
438 | static int nau8825_xtalk_baktab_index_by_reg(unsigned int reg) | ||
439 | { | ||
440 | int index; | ||
441 | |||
442 | for (index = 0; index < ARRAY_SIZE(nau8825_xtalk_baktab); index++) | ||
443 | if (nau8825_xtalk_baktab[index].reg == reg) | ||
444 | return index; | ||
445 | return -EINVAL; | ||
446 | } | ||
447 | |||
448 | static void nau8825_xtalk_backup(struct nau8825 *nau8825) | ||
449 | { | ||
450 | int i; | ||
451 | |||
452 | /* Backup some register values to backup table */ | ||
453 | for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) | ||
454 | regmap_read(nau8825->regmap, nau8825_xtalk_baktab[i].reg, | ||
455 | &nau8825_xtalk_baktab[i].def); | ||
456 | } | ||
457 | |||
458 | static void nau8825_xtalk_restore(struct nau8825 *nau8825) | ||
459 | { | ||
460 | int i, volume; | ||
461 | |||
462 | /* Restore register values from backup table; When the driver restores | ||
463 | * the headphone volumem, it needs recover to original level gradually | ||
464 | * with 3dB per step for less pop noise. | ||
465 | */ | ||
466 | for (i = 0; i < ARRAY_SIZE(nau8825_xtalk_baktab); i++) { | ||
467 | if (nau8825_xtalk_baktab[i].reg == NAU8825_REG_HSVOL_CTRL) { | ||
468 | /* Ramping up the volume change to reduce pop noise */ | ||
469 | volume = nau8825_xtalk_baktab[i].def & | ||
470 | NAU8825_HPR_VOL_MASK; | ||
471 | nau8825_hpvol_ramp(nau8825, 0, volume, 3); | ||
472 | continue; | ||
473 | } | ||
474 | regmap_write(nau8825->regmap, nau8825_xtalk_baktab[i].reg, | ||
475 | nau8825_xtalk_baktab[i].def); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | static void nau8825_xtalk_prepare_dac(struct nau8825 *nau8825) | ||
480 | { | ||
481 | /* Enable power of DAC path */ | ||
482 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL, | ||
483 | NAU8825_ENABLE_DACR | NAU8825_ENABLE_DACL | | ||
484 | NAU8825_ENABLE_ADC | NAU8825_ENABLE_ADC_CLK | | ||
485 | NAU8825_ENABLE_DAC_CLK, NAU8825_ENABLE_DACR | | ||
486 | NAU8825_ENABLE_DACL | NAU8825_ENABLE_ADC | | ||
487 | NAU8825_ENABLE_ADC_CLK | NAU8825_ENABLE_DAC_CLK); | ||
488 | /* Prevent startup click by letting charge pump to ramp up and | ||
489 | * change bump enable | ||
490 | */ | ||
491 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, | ||
492 | NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN, | ||
493 | NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN); | ||
494 | /* Enable clock sync of DAC and DAC clock */ | ||
495 | regmap_update_bits(nau8825->regmap, NAU8825_REG_RDAC, | ||
496 | NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN | | ||
497 | NAU8825_RDAC_FS_BCLK_ENB, | ||
498 | NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN); | ||
499 | /* Power up output driver with 2 stage */ | ||
500 | regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL, | ||
501 | NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L | | ||
502 | NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L, | ||
503 | NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L | | ||
504 | NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L); | ||
505 | regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL, | ||
506 | NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L, | ||
507 | NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L); | ||
508 | /* HP outputs not shouted to ground */ | ||
509 | regmap_update_bits(nau8825->regmap, NAU8825_REG_HSD_CTRL, | ||
510 | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L, 0); | ||
511 | /* Enable HP boost driver */ | ||
512 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST, | ||
513 | NAU8825_HP_BOOST_DIS, NAU8825_HP_BOOST_DIS); | ||
514 | /* Enable class G compare path to supply 1.8V or 0.9V. */ | ||
515 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLASSG_CTRL, | ||
516 | NAU8825_CLASSG_LDAC_EN | NAU8825_CLASSG_RDAC_EN, | ||
517 | NAU8825_CLASSG_LDAC_EN | NAU8825_CLASSG_RDAC_EN); | ||
518 | } | ||
519 | |||
520 | static void nau8825_xtalk_prepare_adc(struct nau8825 *nau8825) | ||
521 | { | ||
522 | /* Power up left ADC and raise 5dB than Vmid for Vref */ | ||
523 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ANALOG_ADC_2, | ||
524 | NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, | ||
525 | NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_VMID_PLUS_0_5DB); | ||
526 | } | ||
527 | |||
528 | static void nau8825_xtalk_clock(struct nau8825 *nau8825) | ||
529 | { | ||
530 | /* Recover FLL default value */ | ||
531 | regmap_write(nau8825->regmap, NAU8825_REG_FLL1, 0x0); | ||
532 | regmap_write(nau8825->regmap, NAU8825_REG_FLL2, 0x3126); | ||
533 | regmap_write(nau8825->regmap, NAU8825_REG_FLL3, 0x0008); | ||
534 | regmap_write(nau8825->regmap, NAU8825_REG_FLL4, 0x0010); | ||
535 | regmap_write(nau8825->regmap, NAU8825_REG_FLL5, 0x0); | ||
536 | regmap_write(nau8825->regmap, NAU8825_REG_FLL6, 0x6000); | ||
537 | /* Enable internal VCO clock for detection signal generated */ | ||
538 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, | ||
539 | NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); | ||
540 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, | ||
541 | NAU8825_DCO_EN); | ||
542 | /* Given specific clock frequency of internal clock to | ||
543 | * generate signal. | ||
544 | */ | ||
545 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, | ||
546 | NAU8825_CLK_MCLK_SRC_MASK, 0xf); | ||
547 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, | ||
548 | NAU8825_FLL_RATIO_MASK, 0x10); | ||
549 | } | ||
550 | |||
551 | static void nau8825_xtalk_prepare(struct nau8825 *nau8825) | ||
552 | { | ||
553 | int volume, index; | ||
554 | |||
555 | /* Backup those registers changed by cross talk detection */ | ||
556 | nau8825_xtalk_backup(nau8825); | ||
557 | /* Config IIS as master to output signal by codec */ | ||
558 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
559 | NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK | | ||
560 | NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_MASTER | | ||
561 | (0x2 << NAU8825_I2S_DRV_SFT) | 0x1); | ||
562 | /* Ramp up headphone volume to 0dB to get better performance and | ||
563 | * avoid pop noise in headphone. | ||
564 | */ | ||
565 | index = nau8825_xtalk_baktab_index_by_reg(NAU8825_REG_HSVOL_CTRL); | ||
566 | if (index != -EINVAL) { | ||
567 | volume = nau8825_xtalk_baktab[index].def & | ||
568 | NAU8825_HPR_VOL_MASK; | ||
569 | nau8825_hpvol_ramp(nau8825, volume, 0, 3); | ||
570 | } | ||
571 | nau8825_xtalk_clock(nau8825); | ||
572 | nau8825_xtalk_prepare_dac(nau8825); | ||
573 | nau8825_xtalk_prepare_adc(nau8825); | ||
574 | /* Config channel path and digital gain */ | ||
575 | regmap_update_bits(nau8825->regmap, NAU8825_REG_DACL_CTRL, | ||
576 | NAU8825_DACL_CH_SEL_MASK | NAU8825_DACL_CH_VOL_MASK, | ||
577 | NAU8825_DACL_CH_SEL_L | 0xab); | ||
578 | regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL, | ||
579 | NAU8825_DACR_CH_SEL_MASK | NAU8825_DACR_CH_VOL_MASK, | ||
580 | NAU8825_DACR_CH_SEL_R | 0xab); | ||
581 | /* Config cross talk parameters and generate the 23Hz sine wave with | ||
582 | * 1/16 full scale of signal level for impedance measurement. | ||
583 | */ | ||
584 | regmap_update_bits(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL, | ||
585 | NAU8825_IMM_THD_MASK | NAU8825_IMM_GEN_VOL_MASK | | ||
586 | NAU8825_IMM_CYC_MASK | NAU8825_IMM_DAC_SRC_MASK, | ||
587 | (0x9 << NAU8825_IMM_THD_SFT) | NAU8825_IMM_GEN_VOL_1_16th | | ||
588 | NAU8825_IMM_CYC_8192 | NAU8825_IMM_DAC_SRC_SIN); | ||
589 | /* RMS intrruption enable */ | ||
590 | regmap_update_bits(nau8825->regmap, | ||
591 | NAU8825_REG_INTERRUPT_MASK, NAU8825_IRQ_RMS_EN, 0); | ||
592 | /* Power up left and right DAC */ | ||
593 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, | ||
594 | NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, 0); | ||
595 | } | ||
596 | |||
597 | static void nau8825_xtalk_clean_dac(struct nau8825 *nau8825) | ||
598 | { | ||
599 | /* Disable HP boost driver */ | ||
600 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BOOST, | ||
601 | NAU8825_HP_BOOST_DIS, 0); | ||
602 | /* HP outputs shouted to ground */ | ||
603 | regmap_update_bits(nau8825->regmap, NAU8825_REG_HSD_CTRL, | ||
604 | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L, | ||
605 | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L); | ||
606 | /* Power down left and right DAC */ | ||
607 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, | ||
608 | NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL, | ||
609 | NAU8825_POWER_DOWN_DACR | NAU8825_POWER_DOWN_DACL); | ||
610 | /* Enable the TESTDAC and disable L/R HP impedance */ | ||
611 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, | ||
612 | NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP | | ||
613 | NAU8825_BIAS_TESTDAC_EN, NAU8825_BIAS_TESTDAC_EN); | ||
614 | /* Power down output driver with 2 stage */ | ||
615 | regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL, | ||
616 | NAU8825_POWERUP_HP_DRV_R | NAU8825_POWERUP_HP_DRV_L, 0); | ||
617 | regmap_update_bits(nau8825->regmap, NAU8825_REG_POWER_UP_CONTROL, | ||
618 | NAU8825_POWERUP_INTEGR_R | NAU8825_POWERUP_INTEGR_L | | ||
619 | NAU8825_POWERUP_DRV_IN_R | NAU8825_POWERUP_DRV_IN_L, 0); | ||
620 | /* Disable clock sync of DAC and DAC clock */ | ||
621 | regmap_update_bits(nau8825->regmap, NAU8825_REG_RDAC, | ||
622 | NAU8825_RDAC_EN | NAU8825_RDAC_CLK_EN, 0); | ||
623 | /* Disable charge pump ramp up function and change bump */ | ||
624 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CHARGE_PUMP, | ||
625 | NAU8825_JAMNODCLOW | NAU8825_CHANRGE_PUMP_EN, 0); | ||
626 | /* Disable power of DAC path */ | ||
627 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL, | ||
628 | NAU8825_ENABLE_DACR | NAU8825_ENABLE_DACL | | ||
629 | NAU8825_ENABLE_ADC_CLK | NAU8825_ENABLE_DAC_CLK, 0); | ||
630 | if (!nau8825->irq) | ||
631 | regmap_update_bits(nau8825->regmap, | ||
632 | NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_ADC, 0); | ||
633 | } | ||
634 | |||
635 | static void nau8825_xtalk_clean_adc(struct nau8825 *nau8825) | ||
636 | { | ||
637 | /* Power down left ADC and restore voltage to Vmid */ | ||
638 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ANALOG_ADC_2, | ||
639 | NAU8825_POWERUP_ADCL | NAU8825_ADC_VREFSEL_MASK, 0); | ||
640 | } | ||
641 | |||
642 | static void nau8825_xtalk_clean(struct nau8825 *nau8825) | ||
643 | { | ||
644 | /* Enable internal VCO needed for interruptions */ | ||
645 | nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); | ||
646 | nau8825_xtalk_clean_dac(nau8825); | ||
647 | nau8825_xtalk_clean_adc(nau8825); | ||
648 | /* Clear cross talk parameters and disable */ | ||
649 | regmap_write(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL, 0); | ||
650 | /* RMS intrruption disable */ | ||
651 | regmap_update_bits(nau8825->regmap, NAU8825_REG_INTERRUPT_MASK, | ||
652 | NAU8825_IRQ_RMS_EN, NAU8825_IRQ_RMS_EN); | ||
653 | /* Recover default value for IIS */ | ||
654 | regmap_update_bits(nau8825->regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
655 | NAU8825_I2S_MS_MASK | NAU8825_I2S_DRV_MASK | | ||
656 | NAU8825_I2S_BLK_DIV_MASK, NAU8825_I2S_MS_SLAVE); | ||
657 | /* Restore value of specific register for cross talk */ | ||
658 | nau8825_xtalk_restore(nau8825); | ||
659 | } | ||
660 | |||
661 | static void nau8825_xtalk_imm_start(struct nau8825 *nau8825, int vol) | ||
662 | { | ||
663 | /* Apply ADC volume for better cross talk performance */ | ||
664 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ADC_DGAIN_CTRL, | ||
665 | NAU8825_ADC_DIG_VOL_MASK, vol); | ||
666 | /* Disables JKTIP(HPL) DAC channel for right to left measurement. | ||
667 | * Do it before sending signal in order to erase pop noise. | ||
668 | */ | ||
669 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, | ||
670 | NAU8825_BIAS_TESTDACR_EN | NAU8825_BIAS_TESTDACL_EN, | ||
671 | NAU8825_BIAS_TESTDACL_EN); | ||
672 | switch (nau8825->xtalk_state) { | ||
673 | case NAU8825_XTALK_HPR_R2L: | ||
674 | /* Enable right headphone impedance */ | ||
675 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, | ||
676 | NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP, | ||
677 | NAU8825_BIAS_HPR_IMP); | ||
678 | break; | ||
679 | case NAU8825_XTALK_HPL_R2L: | ||
680 | /* Enable left headphone impedance */ | ||
681 | regmap_update_bits(nau8825->regmap, NAU8825_REG_BIAS_ADJ, | ||
682 | NAU8825_BIAS_HPR_IMP | NAU8825_BIAS_HPL_IMP, | ||
683 | NAU8825_BIAS_HPL_IMP); | ||
684 | break; | ||
685 | default: | ||
686 | break; | ||
687 | } | ||
688 | msleep(100); | ||
689 | /* Impedance measurement mode enable */ | ||
690 | regmap_update_bits(nau8825->regmap, NAU8825_REG_IMM_MODE_CTRL, | ||
691 | NAU8825_IMM_EN, NAU8825_IMM_EN); | ||
692 | } | ||
693 | |||
694 | static void nau8825_xtalk_imm_stop(struct nau8825 *nau8825) | ||
695 | { | ||
696 | /* Impedance measurement mode disable */ | ||
697 | regmap_update_bits(nau8825->regmap, | ||
698 | NAU8825_REG_IMM_MODE_CTRL, NAU8825_IMM_EN, 0); | ||
699 | } | ||
700 | |||
701 | /* The cross talk measurement function can reduce cross talk across the | ||
702 | * JKTIP(HPL) and JKR1(HPR) outputs which measures the cross talk signal | ||
703 | * level to determine what cross talk reduction gain is. This system works by | ||
704 | * sending a 23Hz -24dBV sine wave into the headset output DAC and through | ||
705 | * the PGA. The output of the PGA is then connected to an internal current | ||
706 | * sense which measures the attenuated 23Hz signal and passing the output to | ||
707 | * an ADC which converts the measurement to a binary code. With two separated | ||
708 | * measurement, one for JKR1(HPR) and the other JKTIP(HPL), measurement data | ||
709 | * can be separated read in IMM_RMS_L for HSR and HSL after each measurement. | ||
710 | * Thus, the measurement function has four states to complete whole sequence. | ||
711 | * 1. Prepare state : Prepare the resource for detection and transfer to HPR | ||
712 | * IMM stat to make JKR1(HPR) impedance measure. | ||
713 | * 2. HPR IMM state : Read out orignal signal level of JKR1(HPR) and transfer | ||
714 | * to HPL IMM state to make JKTIP(HPL) impedance measure. | ||
715 | * 3. HPL IMM state : Read out cross talk signal level of JKTIP(HPL) and | ||
716 | * transfer to IMM state to determine suppression sidetone gain. | ||
717 | * 4. IMM state : Computes cross talk suppression sidetone gain with orignal | ||
718 | * and cross talk signal level. Apply this gain and then restore codec | ||
719 | * configuration. Then transfer to Done state for ending. | ||
720 | */ | ||
721 | static void nau8825_xtalk_measure(struct nau8825 *nau8825) | ||
722 | { | ||
723 | u32 sidetone; | ||
724 | |||
725 | switch (nau8825->xtalk_state) { | ||
726 | case NAU8825_XTALK_PREPARE: | ||
727 | /* In prepare state, set up clock, intrruption, DAC path, ADC | ||
728 | * path and cross talk detection parameters for preparation. | ||
729 | */ | ||
730 | nau8825_xtalk_prepare(nau8825); | ||
731 | msleep(280); | ||
732 | /* Trigger right headphone impedance detection */ | ||
733 | nau8825->xtalk_state = NAU8825_XTALK_HPR_R2L; | ||
734 | nau8825_xtalk_imm_start(nau8825, 0x00d2); | ||
735 | break; | ||
736 | case NAU8825_XTALK_HPR_R2L: | ||
737 | /* In right headphone IMM state, read out right headphone | ||
738 | * impedance measure result, and then start up left side. | ||
739 | */ | ||
740 | regmap_read(nau8825->regmap, NAU8825_REG_IMM_RMS_L, | ||
741 | &nau8825->imp_rms[NAU8825_XTALK_HPR_R2L]); | ||
742 | dev_dbg(nau8825->dev, "HPR_R2L imm: %x\n", | ||
743 | nau8825->imp_rms[NAU8825_XTALK_HPR_R2L]); | ||
744 | /* Disable then re-enable IMM mode to update */ | ||
745 | nau8825_xtalk_imm_stop(nau8825); | ||
746 | /* Trigger left headphone impedance detection */ | ||
747 | nau8825->xtalk_state = NAU8825_XTALK_HPL_R2L; | ||
748 | nau8825_xtalk_imm_start(nau8825, 0x00ff); | ||
749 | break; | ||
750 | case NAU8825_XTALK_HPL_R2L: | ||
751 | /* In left headphone IMM state, read out left headphone | ||
752 | * impedance measure result, and delay some time to wait | ||
753 | * detection sine wave output finish. Then, we can calculate | ||
754 | * the cross talk suppresstion side tone according to the L/R | ||
755 | * headphone imedance. | ||
756 | */ | ||
757 | regmap_read(nau8825->regmap, NAU8825_REG_IMM_RMS_L, | ||
758 | &nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]); | ||
759 | dev_dbg(nau8825->dev, "HPL_R2L imm: %x\n", | ||
760 | nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]); | ||
761 | nau8825_xtalk_imm_stop(nau8825); | ||
762 | msleep(150); | ||
763 | nau8825->xtalk_state = NAU8825_XTALK_IMM; | ||
764 | break; | ||
765 | case NAU8825_XTALK_IMM: | ||
766 | /* In impedance measure state, the orignal and cross talk | ||
767 | * signal level vlues are ready. The side tone gain is deter- | ||
768 | * mined with these signal level. After all, restore codec | ||
769 | * configuration. | ||
770 | */ | ||
771 | sidetone = nau8825_xtalk_sidetone( | ||
772 | nau8825->imp_rms[NAU8825_XTALK_HPR_R2L], | ||
773 | nau8825->imp_rms[NAU8825_XTALK_HPL_R2L]); | ||
774 | dev_dbg(nau8825->dev, "cross talk sidetone: %x\n", sidetone); | ||
775 | regmap_write(nau8825->regmap, NAU8825_REG_DAC_DGAIN_CTRL, | ||
776 | (sidetone << 8) | sidetone); | ||
777 | nau8825_xtalk_clean(nau8825); | ||
778 | nau8825->xtalk_state = NAU8825_XTALK_DONE; | ||
779 | break; | ||
780 | default: | ||
781 | break; | ||
782 | } | ||
783 | } | ||
784 | |||
785 | static void nau8825_xtalk_work(struct work_struct *work) | ||
786 | { | ||
787 | struct nau8825 *nau8825 = container_of( | ||
788 | work, struct nau8825, xtalk_work); | ||
789 | |||
790 | nau8825_xtalk_measure(nau8825); | ||
791 | /* To determine the cross talk side tone gain when reach | ||
792 | * the impedance measure state. | ||
793 | */ | ||
794 | if (nau8825->xtalk_state == NAU8825_XTALK_IMM) | ||
795 | nau8825_xtalk_measure(nau8825); | ||
796 | |||
797 | /* Delay jack report until cross talk detection process | ||
798 | * completed. It can avoid application to do playback | ||
799 | * preparation before cross talk detection is still working. | ||
800 | * Meanwhile, the protection of the cross talk detection | ||
801 | * is released. | ||
802 | */ | ||
803 | if (nau8825->xtalk_state == NAU8825_XTALK_DONE) { | ||
804 | snd_soc_jack_report(nau8825->jack, nau8825->xtalk_event, | ||
805 | nau8825->xtalk_event_mask); | ||
806 | nau8825_sema_release(nau8825); | ||
807 | nau8825->xtalk_protect = false; | ||
808 | } | ||
809 | } | ||
810 | |||
811 | static void nau8825_xtalk_cancel(struct nau8825 *nau8825) | ||
812 | { | ||
813 | /* If the xtalk_protect is true, that means the process is still | ||
814 | * on going. The driver forces to cancel the cross talk task and | ||
815 | * restores the configuration to original status. | ||
816 | */ | ||
817 | if (nau8825->xtalk_protect) { | ||
818 | cancel_work_sync(&nau8825->xtalk_work); | ||
819 | nau8825_xtalk_clean(nau8825); | ||
820 | } | ||
821 | /* Reset parameters for cross talk suppression function */ | ||
822 | nau8825_sema_reset(nau8825); | ||
823 | nau8825->xtalk_state = NAU8825_XTALK_DONE; | ||
824 | nau8825->xtalk_protect = false; | ||
825 | } | ||
826 | |||
159 | static bool nau8825_readable_reg(struct device *dev, unsigned int reg) | 827 | static bool nau8825_readable_reg(struct device *dev, unsigned int reg) |
160 | { | 828 | { |
161 | switch (reg) { | 829 | switch (reg) { |
@@ -217,12 +885,36 @@ static bool nau8825_volatile_reg(struct device *dev, unsigned int reg) | |||
217 | case NAU8825_REG_SARDOUT_RAM_STATUS: | 885 | case NAU8825_REG_SARDOUT_RAM_STATUS: |
218 | case NAU8825_REG_CHARGE_PUMP_INPUT_READ: | 886 | case NAU8825_REG_CHARGE_PUMP_INPUT_READ: |
219 | case NAU8825_REG_GENERAL_STATUS: | 887 | case NAU8825_REG_GENERAL_STATUS: |
888 | case NAU8825_REG_BIQ_CTRL ... NAU8825_REG_BIQ_COF10: | ||
220 | return true; | 889 | return true; |
221 | default: | 890 | default: |
222 | return false; | 891 | return false; |
223 | } | 892 | } |
224 | } | 893 | } |
225 | 894 | ||
895 | static int nau8825_adc_event(struct snd_soc_dapm_widget *w, | ||
896 | struct snd_kcontrol *kcontrol, int event) | ||
897 | { | ||
898 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
899 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | ||
900 | |||
901 | switch (event) { | ||
902 | case SND_SOC_DAPM_POST_PMU: | ||
903 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL, | ||
904 | NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC); | ||
905 | break; | ||
906 | case SND_SOC_DAPM_POST_PMD: | ||
907 | if (!nau8825->irq) | ||
908 | regmap_update_bits(nau8825->regmap, | ||
909 | NAU8825_REG_ENA_CTRL, NAU8825_ENABLE_ADC, 0); | ||
910 | break; | ||
911 | default: | ||
912 | return -EINVAL; | ||
913 | } | ||
914 | |||
915 | return 0; | ||
916 | } | ||
917 | |||
226 | static int nau8825_pump_event(struct snd_soc_dapm_widget *w, | 918 | static int nau8825_pump_event(struct snd_soc_dapm_widget *w, |
227 | struct snd_kcontrol *kcontrol, int event) | 919 | struct snd_kcontrol *kcontrol, int event) |
228 | { | 920 | { |
@@ -270,6 +962,54 @@ static int nau8825_output_dac_event(struct snd_soc_dapm_widget *w, | |||
270 | return 0; | 962 | return 0; |
271 | } | 963 | } |
272 | 964 | ||
965 | static int nau8825_biq_coeff_get(struct snd_kcontrol *kcontrol, | ||
966 | struct snd_ctl_elem_value *ucontrol) | ||
967 | { | ||
968 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
969 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
970 | |||
971 | if (!component->regmap) | ||
972 | return -EINVAL; | ||
973 | |||
974 | regmap_raw_read(component->regmap, NAU8825_REG_BIQ_COF1, | ||
975 | ucontrol->value.bytes.data, params->max); | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static int nau8825_biq_coeff_put(struct snd_kcontrol *kcontrol, | ||
980 | struct snd_ctl_elem_value *ucontrol) | ||
981 | { | ||
982 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
983 | struct soc_bytes_ext *params = (void *)kcontrol->private_value; | ||
984 | void *data; | ||
985 | |||
986 | if (!component->regmap) | ||
987 | return -EINVAL; | ||
988 | |||
989 | data = kmemdup(ucontrol->value.bytes.data, | ||
990 | params->max, GFP_KERNEL | GFP_DMA); | ||
991 | if (!data) | ||
992 | return -ENOMEM; | ||
993 | |||
994 | regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL, | ||
995 | NAU8825_BIQ_WRT_EN, 0); | ||
996 | regmap_raw_write(component->regmap, NAU8825_REG_BIQ_COF1, | ||
997 | data, params->max); | ||
998 | regmap_update_bits(component->regmap, NAU8825_REG_BIQ_CTRL, | ||
999 | NAU8825_BIQ_WRT_EN, NAU8825_BIQ_WRT_EN); | ||
1000 | |||
1001 | kfree(data); | ||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | static const char * const nau8825_biq_path[] = { | ||
1006 | "ADC", "DAC" | ||
1007 | }; | ||
1008 | |||
1009 | static const struct soc_enum nau8825_biq_path_enum = | ||
1010 | SOC_ENUM_SINGLE(NAU8825_REG_BIQ_CTRL, NAU8825_BIQ_PATH_SFT, | ||
1011 | ARRAY_SIZE(nau8825_biq_path), nau8825_biq_path); | ||
1012 | |||
273 | static const char * const nau8825_adc_decimation[] = { | 1013 | static const char * const nau8825_adc_decimation[] = { |
274 | "32", "64", "128", "256" | 1014 | "32", "64", "128", "256" |
275 | }; | 1015 | }; |
@@ -306,6 +1046,10 @@ static const struct snd_kcontrol_new nau8825_controls[] = { | |||
306 | 1046 | ||
307 | SOC_ENUM("ADC Decimation Rate", nau8825_adc_decimation_enum), | 1047 | SOC_ENUM("ADC Decimation Rate", nau8825_adc_decimation_enum), |
308 | SOC_ENUM("DAC Oversampling Rate", nau8825_dac_oversampl_enum), | 1048 | SOC_ENUM("DAC Oversampling Rate", nau8825_dac_oversampl_enum), |
1049 | /* programmable biquad filter */ | ||
1050 | SOC_ENUM("BIQ Path Select", nau8825_biq_path_enum), | ||
1051 | SND_SOC_BYTES_EXT("BIQ Coefficients", 20, | ||
1052 | nau8825_biq_coeff_get, nau8825_biq_coeff_put), | ||
309 | }; | 1053 | }; |
310 | 1054 | ||
311 | /* DAC Mux 0x33[9] and 0x34[9] */ | 1055 | /* DAC Mux 0x33[9] and 0x34[9] */ |
@@ -338,7 +1082,9 @@ static const struct snd_soc_dapm_widget nau8825_dapm_widgets[] = { | |||
338 | SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0, | 1082 | SND_SOC_DAPM_PGA("Frontend PGA", NAU8825_REG_POWER_UP_CONTROL, 14, 0, |
339 | NULL, 0), | 1083 | NULL, 0), |
340 | 1084 | ||
341 | SND_SOC_DAPM_ADC("ADC", NULL, NAU8825_REG_ENA_CTRL, 8, 0), | 1085 | SND_SOC_DAPM_ADC_E("ADC", NULL, SND_SOC_NOPM, 0, 0, |
1086 | nau8825_adc_event, SND_SOC_DAPM_POST_PMU | | ||
1087 | SND_SOC_DAPM_POST_PMD), | ||
342 | SND_SOC_DAPM_SUPPLY("ADC Clock", NAU8825_REG_ENA_CTRL, 7, 0, NULL, 0), | 1088 | SND_SOC_DAPM_SUPPLY("ADC Clock", NAU8825_REG_ENA_CTRL, 7, 0, NULL, 0), |
343 | SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL, | 1089 | SND_SOC_DAPM_SUPPLY("ADC Power", NAU8825_REG_ANALOG_ADC_2, 6, 0, NULL, |
344 | 0), | 1090 | 0), |
@@ -592,9 +1338,6 @@ int nau8825_enable_jack_detect(struct snd_soc_codec *codec, | |||
592 | NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L, | 1338 | NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L, |
593 | NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L); | 1339 | NAU8825_HSD_AUTO_MODE | NAU8825_SPKR_DWN1R | NAU8825_SPKR_DWN1L); |
594 | 1340 | ||
595 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
596 | NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_EJECT_EN, 0); | ||
597 | |||
598 | return 0; | 1341 | return 0; |
599 | } | 1342 | } |
600 | EXPORT_SYMBOL_GPL(nau8825_enable_jack_detect); | 1343 | EXPORT_SYMBOL_GPL(nau8825_enable_jack_detect); |
@@ -602,24 +1345,21 @@ EXPORT_SYMBOL_GPL(nau8825_enable_jack_detect); | |||
602 | 1345 | ||
603 | static bool nau8825_is_jack_inserted(struct regmap *regmap) | 1346 | static bool nau8825_is_jack_inserted(struct regmap *regmap) |
604 | { | 1347 | { |
605 | int status; | 1348 | bool active_high, is_high; |
1349 | int status, jkdet; | ||
606 | 1350 | ||
1351 | regmap_read(regmap, NAU8825_REG_JACK_DET_CTRL, &jkdet); | ||
1352 | active_high = jkdet & NAU8825_JACK_POLARITY; | ||
607 | regmap_read(regmap, NAU8825_REG_I2C_DEVICE_ID, &status); | 1353 | regmap_read(regmap, NAU8825_REG_I2C_DEVICE_ID, &status); |
608 | return !(status & NAU8825_GPIO2JD1); | 1354 | is_high = status & NAU8825_GPIO2JD1; |
1355 | /* return jack connection status according to jack insertion logic | ||
1356 | * active high or active low. | ||
1357 | */ | ||
1358 | return active_high == is_high; | ||
609 | } | 1359 | } |
610 | 1360 | ||
611 | static void nau8825_restart_jack_detection(struct regmap *regmap) | 1361 | static void nau8825_restart_jack_detection(struct regmap *regmap) |
612 | { | 1362 | { |
613 | /* Chip needs one FSCLK cycle in order to generate interrupts, | ||
614 | * as we cannot guarantee one will be provided by the system. Turning | ||
615 | * master mode on then off enables us to generate that FSCLK cycle | ||
616 | * with a minimum of contention on the clock bus. | ||
617 | */ | ||
618 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
619 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER); | ||
620 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
621 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE); | ||
622 | |||
623 | /* this will restart the entire jack detection process including MIC/GND | 1363 | /* this will restart the entire jack detection process including MIC/GND |
624 | * switching and create interrupts. We have to go from 0 to 1 and back | 1364 | * switching and create interrupts. We have to go from 0 to 1 and back |
625 | * to 0 to restart. | 1365 | * to 0 to restart. |
@@ -630,11 +1370,30 @@ static void nau8825_restart_jack_detection(struct regmap *regmap) | |||
630 | NAU8825_JACK_DET_RESTART, 0); | 1370 | NAU8825_JACK_DET_RESTART, 0); |
631 | } | 1371 | } |
632 | 1372 | ||
1373 | static void nau8825_int_status_clear_all(struct regmap *regmap) | ||
1374 | { | ||
1375 | int active_irq, clear_irq, i; | ||
1376 | |||
1377 | /* Reset the intrruption status from rightmost bit if the corres- | ||
1378 | * ponding irq event occurs. | ||
1379 | */ | ||
1380 | regmap_read(regmap, NAU8825_REG_IRQ_STATUS, &active_irq); | ||
1381 | for (i = 0; i < NAU8825_REG_DATA_LEN; i++) { | ||
1382 | clear_irq = (0x1 << i); | ||
1383 | if (active_irq & clear_irq) | ||
1384 | regmap_write(regmap, | ||
1385 | NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq); | ||
1386 | } | ||
1387 | } | ||
1388 | |||
633 | static void nau8825_eject_jack(struct nau8825 *nau8825) | 1389 | static void nau8825_eject_jack(struct nau8825 *nau8825) |
634 | { | 1390 | { |
635 | struct snd_soc_dapm_context *dapm = nau8825->dapm; | 1391 | struct snd_soc_dapm_context *dapm = nau8825->dapm; |
636 | struct regmap *regmap = nau8825->regmap; | 1392 | struct regmap *regmap = nau8825->regmap; |
637 | 1393 | ||
1394 | /* Force to cancel the cross talk detection process */ | ||
1395 | nau8825_xtalk_cancel(nau8825); | ||
1396 | |||
638 | snd_soc_dapm_disable_pin(dapm, "SAR"); | 1397 | snd_soc_dapm_disable_pin(dapm, "SAR"); |
639 | snd_soc_dapm_disable_pin(dapm, "MICBIAS"); | 1398 | snd_soc_dapm_disable_pin(dapm, "MICBIAS"); |
640 | /* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */ | 1399 | /* Detach 2kOhm Resistors from MICBIAS to MICGND1/2 */ |
@@ -644,6 +1403,69 @@ static void nau8825_eject_jack(struct nau8825 *nau8825) | |||
644 | regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0xf, 0xf); | 1403 | regmap_update_bits(regmap, NAU8825_REG_HSD_CTRL, 0xf, 0xf); |
645 | 1404 | ||
646 | snd_soc_dapm_sync(dapm); | 1405 | snd_soc_dapm_sync(dapm); |
1406 | |||
1407 | /* Clear all interruption status */ | ||
1408 | nau8825_int_status_clear_all(regmap); | ||
1409 | |||
1410 | /* Enable the insertion interruption, disable the ejection inter- | ||
1411 | * ruption, and then bypass de-bounce circuit. | ||
1412 | */ | ||
1413 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, | ||
1414 | NAU8825_IRQ_EJECT_DIS | NAU8825_IRQ_INSERT_DIS, | ||
1415 | NAU8825_IRQ_EJECT_DIS); | ||
1416 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
1417 | NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_EJECT_EN | | ||
1418 | NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_INSERT_EN, | ||
1419 | NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_EJECT_EN | | ||
1420 | NAU8825_IRQ_HEADSET_COMPLETE_EN); | ||
1421 | regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL, | ||
1422 | NAU8825_JACK_DET_DB_BYPASS, NAU8825_JACK_DET_DB_BYPASS); | ||
1423 | |||
1424 | /* Disable ADC needed for interruptions at audo mode */ | ||
1425 | regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, | ||
1426 | NAU8825_ENABLE_ADC, 0); | ||
1427 | |||
1428 | /* Close clock for jack type detection at manual mode */ | ||
1429 | nau8825_configure_sysclk(nau8825, NAU8825_CLK_DIS, 0); | ||
1430 | } | ||
1431 | |||
1432 | /* Enable audo mode interruptions with internal clock. */ | ||
1433 | static void nau8825_setup_auto_irq(struct nau8825 *nau8825) | ||
1434 | { | ||
1435 | struct regmap *regmap = nau8825->regmap; | ||
1436 | |||
1437 | /* Enable headset jack type detection complete interruption and | ||
1438 | * jack ejection interruption. | ||
1439 | */ | ||
1440 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
1441 | NAU8825_IRQ_HEADSET_COMPLETE_EN | NAU8825_IRQ_EJECT_EN, 0); | ||
1442 | |||
1443 | /* Enable internal VCO needed for interruptions */ | ||
1444 | nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); | ||
1445 | |||
1446 | /* Enable ADC needed for interruptions */ | ||
1447 | regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, | ||
1448 | NAU8825_ENABLE_ADC, NAU8825_ENABLE_ADC); | ||
1449 | |||
1450 | /* Chip needs one FSCLK cycle in order to generate interruptions, | ||
1451 | * as we cannot guarantee one will be provided by the system. Turning | ||
1452 | * master mode on then off enables us to generate that FSCLK cycle | ||
1453 | * with a minimum of contention on the clock bus. | ||
1454 | */ | ||
1455 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
1456 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_MASTER); | ||
1457 | regmap_update_bits(regmap, NAU8825_REG_I2S_PCM_CTRL2, | ||
1458 | NAU8825_I2S_MS_MASK, NAU8825_I2S_MS_SLAVE); | ||
1459 | |||
1460 | /* Not bypass de-bounce circuit */ | ||
1461 | regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL, | ||
1462 | NAU8825_JACK_DET_DB_BYPASS, 0); | ||
1463 | |||
1464 | /* Unmask all interruptions */ | ||
1465 | regmap_write(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, 0); | ||
1466 | |||
1467 | /* Restart the jack detection process at auto mode */ | ||
1468 | nau8825_restart_jack_detection(regmap); | ||
647 | } | 1469 | } |
648 | 1470 | ||
649 | static int nau8825_button_decode(int value) | 1471 | static int nau8825_button_decode(int value) |
@@ -676,6 +1498,11 @@ static int nau8825_jack_insert(struct nau8825 *nau8825) | |||
676 | 1498 | ||
677 | regmap_read(regmap, NAU8825_REG_GENERAL_STATUS, &jack_status_reg); | 1499 | regmap_read(regmap, NAU8825_REG_GENERAL_STATUS, &jack_status_reg); |
678 | mic_detected = (jack_status_reg >> 10) & 3; | 1500 | mic_detected = (jack_status_reg >> 10) & 3; |
1501 | /* The JKSLV and JKR2 all detected in high impedance headset */ | ||
1502 | if (mic_detected == 0x3) | ||
1503 | nau8825->high_imped = true; | ||
1504 | else | ||
1505 | nau8825->high_imped = false; | ||
679 | 1506 | ||
680 | switch (mic_detected) { | 1507 | switch (mic_detected) { |
681 | case 0: | 1508 | case 0: |
@@ -773,6 +1600,33 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) | |||
773 | } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { | 1600 | } else if (active_irq & NAU8825_HEADSET_COMPLETION_IRQ) { |
774 | if (nau8825_is_jack_inserted(regmap)) { | 1601 | if (nau8825_is_jack_inserted(regmap)) { |
775 | event |= nau8825_jack_insert(nau8825); | 1602 | event |= nau8825_jack_insert(nau8825); |
1603 | if (!nau8825->high_imped) { | ||
1604 | /* Apply the cross talk suppression in the | ||
1605 | * headset without high impedance. | ||
1606 | */ | ||
1607 | if (!nau8825->xtalk_protect) { | ||
1608 | /* Raise protection for cross talk de- | ||
1609 | * tection if no protection before. | ||
1610 | * The driver has to cancel the pro- | ||
1611 | * cess and restore changes if process | ||
1612 | * is ongoing when ejection. | ||
1613 | */ | ||
1614 | nau8825->xtalk_protect = true; | ||
1615 | nau8825_sema_acquire(nau8825, 0); | ||
1616 | } | ||
1617 | /* Startup cross talk detection process */ | ||
1618 | nau8825->xtalk_state = NAU8825_XTALK_PREPARE; | ||
1619 | schedule_work(&nau8825->xtalk_work); | ||
1620 | } else { | ||
1621 | /* The cross talk suppression shouldn't apply | ||
1622 | * in the headset with high impedance. Thus, | ||
1623 | * relieve the protection raised before. | ||
1624 | */ | ||
1625 | if (nau8825->xtalk_protect) { | ||
1626 | nau8825_sema_release(nau8825); | ||
1627 | nau8825->xtalk_protect = false; | ||
1628 | } | ||
1629 | } | ||
776 | } else { | 1630 | } else { |
777 | dev_warn(nau8825->dev, "Headset completion IRQ fired but no headset connected\n"); | 1631 | dev_warn(nau8825->dev, "Headset completion IRQ fired but no headset connected\n"); |
778 | nau8825_eject_jack(nau8825); | 1632 | nau8825_eject_jack(nau8825); |
@@ -780,6 +1634,37 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) | |||
780 | 1634 | ||
781 | event_mask |= SND_JACK_HEADSET; | 1635 | event_mask |= SND_JACK_HEADSET; |
782 | clear_irq = NAU8825_HEADSET_COMPLETION_IRQ; | 1636 | clear_irq = NAU8825_HEADSET_COMPLETION_IRQ; |
1637 | /* Record the interruption report event for driver to report | ||
1638 | * the event later. The jack report will delay until cross | ||
1639 | * talk detection process is done. | ||
1640 | */ | ||
1641 | if (nau8825->xtalk_state == NAU8825_XTALK_PREPARE) { | ||
1642 | nau8825->xtalk_event = event; | ||
1643 | nau8825->xtalk_event_mask = event_mask; | ||
1644 | } | ||
1645 | } else if (active_irq & NAU8825_IMPEDANCE_MEAS_IRQ) { | ||
1646 | schedule_work(&nau8825->xtalk_work); | ||
1647 | clear_irq = NAU8825_IMPEDANCE_MEAS_IRQ; | ||
1648 | } else if ((active_irq & NAU8825_JACK_INSERTION_IRQ_MASK) == | ||
1649 | NAU8825_JACK_INSERTION_DETECTED) { | ||
1650 | /* One more step to check GPIO status directly. Thus, the | ||
1651 | * driver can confirm the real insertion interruption because | ||
1652 | * the intrruption at manual mode has bypassed debounce | ||
1653 | * circuit which can get rid of unstable status. | ||
1654 | */ | ||
1655 | if (nau8825_is_jack_inserted(regmap)) { | ||
1656 | /* Turn off insertion interruption at manual mode */ | ||
1657 | regmap_update_bits(regmap, | ||
1658 | NAU8825_REG_INTERRUPT_DIS_CTRL, | ||
1659 | NAU8825_IRQ_INSERT_DIS, | ||
1660 | NAU8825_IRQ_INSERT_DIS); | ||
1661 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
1662 | NAU8825_IRQ_INSERT_EN, NAU8825_IRQ_INSERT_EN); | ||
1663 | /* Enable interruption for jack type detection at audo | ||
1664 | * mode which can detect microphone and jack type. | ||
1665 | */ | ||
1666 | nau8825_setup_auto_irq(nau8825); | ||
1667 | } | ||
783 | } | 1668 | } |
784 | 1669 | ||
785 | if (!clear_irq) | 1670 | if (!clear_irq) |
@@ -787,7 +1672,12 @@ static irqreturn_t nau8825_interrupt(int irq, void *data) | |||
787 | /* clears the rightmost interruption */ | 1672 | /* clears the rightmost interruption */ |
788 | regmap_write(regmap, NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq); | 1673 | regmap_write(regmap, NAU8825_REG_INT_CLR_KEY_STATUS, clear_irq); |
789 | 1674 | ||
790 | if (event_mask) | 1675 | /* Delay jack report until cross talk detection is done. It can avoid |
1676 | * application to do playback preparation when cross talk detection | ||
1677 | * process is still working. Otherwise, the resource like clock and | ||
1678 | * power will be issued by them at the same time and conflict happens. | ||
1679 | */ | ||
1680 | if (event_mask && nau8825->xtalk_state == NAU8825_XTALK_DONE) | ||
791 | snd_soc_jack_report(nau8825->jack, event, event_mask); | 1681 | snd_soc_jack_report(nau8825->jack, event, event_mask); |
792 | 1682 | ||
793 | return IRQ_HANDLED; | 1683 | return IRQ_HANDLED; |
@@ -921,11 +1811,16 @@ static void nau8825_init_regs(struct nau8825 *nau8825) | |||
921 | NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK, | 1811 | NAU8825_RDAC_CLK_DELAY_MASK | NAU8825_RDAC_VREF_MASK, |
922 | (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) | | 1812 | (0x2 << NAU8825_RDAC_CLK_DELAY_SFT) | |
923 | (0x3 << NAU8825_RDAC_VREF_SFT)); | 1813 | (0x3 << NAU8825_RDAC_VREF_SFT)); |
1814 | /* Config L/R channel */ | ||
1815 | regmap_update_bits(nau8825->regmap, NAU8825_REG_DACL_CTRL, | ||
1816 | NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_L); | ||
1817 | regmap_update_bits(nau8825->regmap, NAU8825_REG_DACR_CTRL, | ||
1818 | NAU8825_DACL_CH_SEL_MASK, NAU8825_DACL_CH_SEL_R); | ||
924 | } | 1819 | } |
925 | 1820 | ||
926 | static const struct regmap_config nau8825_regmap_config = { | 1821 | static const struct regmap_config nau8825_regmap_config = { |
927 | .val_bits = 16, | 1822 | .val_bits = NAU8825_REG_DATA_LEN, |
928 | .reg_bits = 16, | 1823 | .reg_bits = NAU8825_REG_ADDR_LEN, |
929 | 1824 | ||
930 | .max_register = NAU8825_REG_MAX, | 1825 | .max_register = NAU8825_REG_MAX, |
931 | .readable_reg = nau8825_readable_reg, | 1826 | .readable_reg = nau8825_readable_reg, |
@@ -944,18 +1839,15 @@ static int nau8825_codec_probe(struct snd_soc_codec *codec) | |||
944 | 1839 | ||
945 | nau8825->dapm = dapm; | 1840 | nau8825->dapm = dapm; |
946 | 1841 | ||
947 | /* The interrupt clock is gated by x1[10:8], | 1842 | return 0; |
948 | * one of them needs to be enabled all the time for | 1843 | } |
949 | * interrupts to happen. | ||
950 | */ | ||
951 | snd_soc_dapm_force_enable_pin(dapm, "DDACR"); | ||
952 | snd_soc_dapm_sync(dapm); | ||
953 | 1844 | ||
954 | /* Unmask interruptions. Handler uses dapm object so we can enable | 1845 | static int nau8825_codec_remove(struct snd_soc_codec *codec) |
955 | * interruptions only after dapm is fully initialized. | 1846 | { |
956 | */ | 1847 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); |
957 | regmap_write(nau8825->regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, 0); | 1848 | |
958 | nau8825_restart_jack_detection(nau8825->regmap); | 1849 | /* Cancel and reset cross tak suppresstion detection funciton */ |
1850 | nau8825_xtalk_cancel(nau8825); | ||
959 | 1851 | ||
960 | return 0; | 1852 | return 0; |
961 | } | 1853 | } |
@@ -973,8 +1865,8 @@ static int nau8825_codec_probe(struct snd_soc_codec *codec) | |||
973 | static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, | 1865 | static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, |
974 | struct nau8825_fll *fll_param) | 1866 | struct nau8825_fll *fll_param) |
975 | { | 1867 | { |
976 | u64 fvco; | 1868 | u64 fvco, fvco_max; |
977 | unsigned int fref, i; | 1869 | unsigned int fref, i, fvco_sel; |
978 | 1870 | ||
979 | /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing | 1871 | /* Ensure the reference clock frequency (FREF) is <= 13.5MHz by dividing |
980 | * freq_in by 1, 2, 4, or 8 using FLL pre-scalar. | 1872 | * freq_in by 1, 2, 4, or 8 using FLL pre-scalar. |
@@ -999,18 +1891,23 @@ static int nau8825_calc_fll_param(unsigned int fll_in, unsigned int fs, | |||
999 | fll_param->ratio = fll_ratio[i].val; | 1891 | fll_param->ratio = fll_ratio[i].val; |
1000 | 1892 | ||
1001 | /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs. | 1893 | /* Calculate the frequency of DCO (FDCO) given freq_out = 256 * Fs. |
1002 | * FDCO must be within the 90MHz - 100MHz or the FFL cannot be | 1894 | * FDCO must be within the 90MHz - 124MHz or the FFL cannot be |
1003 | * guaranteed across the full range of operation. | 1895 | * guaranteed across the full range of operation. |
1004 | * FDCO = freq_out * 2 * mclk_src_scaling | 1896 | * FDCO = freq_out * 2 * mclk_src_scaling |
1005 | */ | 1897 | */ |
1898 | fvco_max = 0; | ||
1899 | fvco_sel = ARRAY_SIZE(mclk_src_scaling); | ||
1006 | for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { | 1900 | for (i = 0; i < ARRAY_SIZE(mclk_src_scaling); i++) { |
1007 | fvco = 256 * fs * 2 * mclk_src_scaling[i].param; | 1901 | fvco = 256 * fs * 2 * mclk_src_scaling[i].param; |
1008 | if (NAU_FVCO_MIN < fvco && fvco < NAU_FVCO_MAX) | 1902 | if (fvco > NAU_FVCO_MIN && fvco < NAU_FVCO_MAX && |
1009 | break; | 1903 | fvco_max < fvco) { |
1904 | fvco_max = fvco; | ||
1905 | fvco_sel = i; | ||
1906 | } | ||
1010 | } | 1907 | } |
1011 | if (i == ARRAY_SIZE(mclk_src_scaling)) | 1908 | if (ARRAY_SIZE(mclk_src_scaling) == fvco_sel) |
1012 | return -EINVAL; | 1909 | return -EINVAL; |
1013 | fll_param->mclk_src = mclk_src_scaling[i].val; | 1910 | fll_param->mclk_src = mclk_src_scaling[fvco_sel].val; |
1014 | 1911 | ||
1015 | /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional | 1912 | /* Calculate the FLL 10-bit integer input and the FLL 16-bit fractional |
1016 | * input based on FDCO, FREF and FLL ratio. | 1913 | * input based on FDCO, FREF and FLL ratio. |
@@ -1025,7 +1922,8 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, | |||
1025 | struct nau8825_fll *fll_param) | 1922 | struct nau8825_fll *fll_param) |
1026 | { | 1923 | { |
1027 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, | 1924 | regmap_update_bits(nau8825->regmap, NAU8825_REG_CLK_DIVIDER, |
1028 | NAU8825_CLK_MCLK_SRC_MASK, fll_param->mclk_src); | 1925 | NAU8825_CLK_SRC_MASK | NAU8825_CLK_MCLK_SRC_MASK, |
1926 | NAU8825_CLK_SRC_MCLK | fll_param->mclk_src); | ||
1029 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, | 1927 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL1, |
1030 | NAU8825_FLL_RATIO_MASK, fll_param->ratio); | 1928 | NAU8825_FLL_RATIO_MASK, fll_param->ratio); |
1031 | /* FLL 16-bit fractional input */ | 1929 | /* FLL 16-bit fractional input */ |
@@ -1038,10 +1936,25 @@ static void nau8825_fll_apply(struct nau8825 *nau8825, | |||
1038 | NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div); | 1936 | NAU8825_FLL_REF_DIV_MASK, fll_param->clk_ref_div); |
1039 | /* select divided VCO input */ | 1937 | /* select divided VCO input */ |
1040 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, | 1938 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, |
1041 | NAU8825_FLL_FILTER_SW_MASK, 0x0000); | 1939 | NAU8825_FLL_CLK_SW_MASK, NAU8825_FLL_CLK_SW_REF); |
1042 | /* FLL sigma delta modulator enable */ | 1940 | /* Disable free-running mode */ |
1043 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, | 1941 | regmap_update_bits(nau8825->regmap, |
1044 | NAU8825_SDM_EN_MASK, NAU8825_SDM_EN); | 1942 | NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); |
1943 | if (fll_param->fll_frac) { | ||
1944 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, | ||
1945 | NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | | ||
1946 | NAU8825_FLL_FTR_SW_MASK, | ||
1947 | NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | | ||
1948 | NAU8825_FLL_FTR_SW_FILTER); | ||
1949 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL6, | ||
1950 | NAU8825_SDM_EN, NAU8825_SDM_EN); | ||
1951 | } else { | ||
1952 | regmap_update_bits(nau8825->regmap, NAU8825_REG_FLL5, | ||
1953 | NAU8825_FLL_PDB_DAC_EN | NAU8825_FLL_LOOP_FTR_EN | | ||
1954 | NAU8825_FLL_FTR_SW_MASK, NAU8825_FLL_FTR_SW_ACCU); | ||
1955 | regmap_update_bits(nau8825->regmap, | ||
1956 | NAU8825_REG_FLL6, NAU8825_SDM_EN, 0); | ||
1957 | } | ||
1045 | } | 1958 | } |
1046 | 1959 | ||
1047 | /* freq_out must be 256*Fs in order to achieve the best performance */ | 1960 | /* freq_out must be 256*Fs in order to achieve the best performance */ |
@@ -1069,6 +1982,45 @@ static int nau8825_set_pll(struct snd_soc_codec *codec, int pll_id, int source, | |||
1069 | return 0; | 1982 | return 0; |
1070 | } | 1983 | } |
1071 | 1984 | ||
1985 | static int nau8825_mclk_prepare(struct nau8825 *nau8825, unsigned int freq) | ||
1986 | { | ||
1987 | int ret = 0; | ||
1988 | |||
1989 | nau8825->mclk = devm_clk_get(nau8825->dev, "mclk"); | ||
1990 | if (IS_ERR(nau8825->mclk)) { | ||
1991 | dev_info(nau8825->dev, "No 'mclk' clock found, assume MCLK is managed externally"); | ||
1992 | return 0; | ||
1993 | } | ||
1994 | |||
1995 | if (!nau8825->mclk_freq) { | ||
1996 | ret = clk_prepare_enable(nau8825->mclk); | ||
1997 | if (ret) { | ||
1998 | dev_err(nau8825->dev, "Unable to prepare codec mclk\n"); | ||
1999 | return ret; | ||
2000 | } | ||
2001 | } | ||
2002 | |||
2003 | if (nau8825->mclk_freq != freq) { | ||
2004 | freq = clk_round_rate(nau8825->mclk, freq); | ||
2005 | ret = clk_set_rate(nau8825->mclk, freq); | ||
2006 | if (ret) { | ||
2007 | dev_err(nau8825->dev, "Unable to set mclk rate\n"); | ||
2008 | return ret; | ||
2009 | } | ||
2010 | nau8825->mclk_freq = freq; | ||
2011 | } | ||
2012 | |||
2013 | return 0; | ||
2014 | } | ||
2015 | |||
2016 | static void nau8825_configure_mclk_as_sysclk(struct regmap *regmap) | ||
2017 | { | ||
2018 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, | ||
2019 | NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK); | ||
2020 | regmap_update_bits(regmap, NAU8825_REG_FLL6, | ||
2021 | NAU8825_DCO_EN, 0); | ||
2022 | } | ||
2023 | |||
1072 | static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, | 2024 | static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, |
1073 | unsigned int freq) | 2025 | unsigned int freq) |
1074 | { | 2026 | { |
@@ -1076,40 +2028,106 @@ static int nau8825_configure_sysclk(struct nau8825 *nau8825, int clk_id, | |||
1076 | int ret; | 2028 | int ret; |
1077 | 2029 | ||
1078 | switch (clk_id) { | 2030 | switch (clk_id) { |
2031 | case NAU8825_CLK_DIS: | ||
2032 | /* Clock provided externally and disable internal VCO clock */ | ||
2033 | nau8825_configure_mclk_as_sysclk(regmap); | ||
2034 | if (nau8825->mclk_freq) { | ||
2035 | clk_disable_unprepare(nau8825->mclk); | ||
2036 | nau8825->mclk_freq = 0; | ||
2037 | } | ||
2038 | |||
2039 | break; | ||
1079 | case NAU8825_CLK_MCLK: | 2040 | case NAU8825_CLK_MCLK: |
2041 | /* Acquire the semaphone to synchronize the playback and | ||
2042 | * interrupt handler. In order to avoid the playback inter- | ||
2043 | * fered by cross talk process, the driver make the playback | ||
2044 | * preparation halted until cross talk process finish. | ||
2045 | */ | ||
2046 | nau8825_sema_acquire(nau8825, 2 * HZ); | ||
2047 | nau8825_configure_mclk_as_sysclk(regmap); | ||
2048 | /* MCLK not changed by clock tree */ | ||
1080 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, | 2049 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, |
1081 | NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_MCLK); | 2050 | NAU8825_CLK_MCLK_SRC_MASK, 0); |
1082 | regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, 0); | 2051 | /* Release the semaphone. */ |
2052 | nau8825_sema_release(nau8825); | ||
1083 | 2053 | ||
1084 | /* We selected MCLK source but the clock itself managed externally */ | 2054 | ret = nau8825_mclk_prepare(nau8825, freq); |
1085 | if (!nau8825->mclk) | 2055 | if (ret) |
1086 | break; | 2056 | return ret; |
1087 | 2057 | ||
1088 | if (!nau8825->mclk_freq) { | 2058 | break; |
1089 | ret = clk_prepare_enable(nau8825->mclk); | 2059 | case NAU8825_CLK_INTERNAL: |
1090 | if (ret) { | 2060 | if (nau8825_is_jack_inserted(nau8825->regmap)) { |
1091 | dev_err(nau8825->dev, "Unable to prepare codec mclk\n"); | 2061 | regmap_update_bits(regmap, NAU8825_REG_FLL6, |
1092 | return ret; | 2062 | NAU8825_DCO_EN, NAU8825_DCO_EN); |
1093 | } | 2063 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, |
2064 | NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); | ||
2065 | /* Decrease the VCO frequency for power saving */ | ||
2066 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, | ||
2067 | NAU8825_CLK_MCLK_SRC_MASK, 0xf); | ||
2068 | regmap_update_bits(regmap, NAU8825_REG_FLL1, | ||
2069 | NAU8825_FLL_RATIO_MASK, 0x10); | ||
2070 | regmap_update_bits(regmap, NAU8825_REG_FLL6, | ||
2071 | NAU8825_SDM_EN, NAU8825_SDM_EN); | ||
2072 | } else { | ||
2073 | /* The clock turns off intentionally for power saving | ||
2074 | * when no headset connected. | ||
2075 | */ | ||
2076 | nau8825_configure_mclk_as_sysclk(regmap); | ||
2077 | dev_warn(nau8825->dev, "Disable clock for power saving when no headset connected\n"); | ||
2078 | } | ||
2079 | if (nau8825->mclk_freq) { | ||
2080 | clk_disable_unprepare(nau8825->mclk); | ||
2081 | nau8825->mclk_freq = 0; | ||
1094 | } | 2082 | } |
1095 | 2083 | ||
1096 | if (nau8825->mclk_freq != freq) { | 2084 | break; |
1097 | nau8825->mclk_freq = freq; | 2085 | case NAU8825_CLK_FLL_MCLK: |
2086 | /* Acquire the semaphone to synchronize the playback and | ||
2087 | * interrupt handler. In order to avoid the playback inter- | ||
2088 | * fered by cross talk process, the driver make the playback | ||
2089 | * preparation halted until cross talk process finish. | ||
2090 | */ | ||
2091 | nau8825_sema_acquire(nau8825, 2 * HZ); | ||
2092 | regmap_update_bits(regmap, NAU8825_REG_FLL3, | ||
2093 | NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_MCLK); | ||
2094 | /* Release the semaphone. */ | ||
2095 | nau8825_sema_release(nau8825); | ||
1098 | 2096 | ||
1099 | freq = clk_round_rate(nau8825->mclk, freq); | 2097 | ret = nau8825_mclk_prepare(nau8825, freq); |
1100 | ret = clk_set_rate(nau8825->mclk, freq); | 2098 | if (ret) |
1101 | if (ret) { | 2099 | return ret; |
1102 | dev_err(nau8825->dev, "Unable to set mclk rate\n"); | 2100 | |
1103 | return ret; | 2101 | break; |
1104 | } | 2102 | case NAU8825_CLK_FLL_BLK: |
2103 | /* Acquire the semaphone to synchronize the playback and | ||
2104 | * interrupt handler. In order to avoid the playback inter- | ||
2105 | * fered by cross talk process, the driver make the playback | ||
2106 | * preparation halted until cross talk process finish. | ||
2107 | */ | ||
2108 | nau8825_sema_acquire(nau8825, 2 * HZ); | ||
2109 | regmap_update_bits(regmap, NAU8825_REG_FLL3, | ||
2110 | NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_BLK); | ||
2111 | /* Release the semaphone. */ | ||
2112 | nau8825_sema_release(nau8825); | ||
2113 | |||
2114 | if (nau8825->mclk_freq) { | ||
2115 | clk_disable_unprepare(nau8825->mclk); | ||
2116 | nau8825->mclk_freq = 0; | ||
1105 | } | 2117 | } |
1106 | 2118 | ||
1107 | break; | 2119 | break; |
1108 | case NAU8825_CLK_INTERNAL: | 2120 | case NAU8825_CLK_FLL_FS: |
1109 | regmap_update_bits(regmap, NAU8825_REG_FLL6, NAU8825_DCO_EN, | 2121 | /* Acquire the semaphone to synchronize the playback and |
1110 | NAU8825_DCO_EN); | 2122 | * interrupt handler. In order to avoid the playback inter- |
1111 | regmap_update_bits(regmap, NAU8825_REG_CLK_DIVIDER, | 2123 | * fered by cross talk process, the driver make the playback |
1112 | NAU8825_CLK_SRC_MASK, NAU8825_CLK_SRC_VCO); | 2124 | * preparation halted until cross talk process finish. |
2125 | */ | ||
2126 | nau8825_sema_acquire(nau8825, 2 * HZ); | ||
2127 | regmap_update_bits(regmap, NAU8825_REG_FLL3, | ||
2128 | NAU8825_FLL_CLK_SRC_MASK, NAU8825_FLL_CLK_SRC_FS); | ||
2129 | /* Release the semaphone. */ | ||
2130 | nau8825_sema_release(nau8825); | ||
1113 | 2131 | ||
1114 | if (nau8825->mclk_freq) { | 2132 | if (nau8825->mclk_freq) { |
1115 | clk_disable_unprepare(nau8825->mclk); | 2133 | clk_disable_unprepare(nau8825->mclk); |
@@ -1135,6 +2153,31 @@ static int nau8825_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
1135 | return nau8825_configure_sysclk(nau8825, clk_id, freq); | 2153 | return nau8825_configure_sysclk(nau8825, clk_id, freq); |
1136 | } | 2154 | } |
1137 | 2155 | ||
2156 | static int nau8825_resume_setup(struct nau8825 *nau8825) | ||
2157 | { | ||
2158 | struct regmap *regmap = nau8825->regmap; | ||
2159 | |||
2160 | /* Close clock when jack type detection at manual mode */ | ||
2161 | nau8825_configure_sysclk(nau8825, NAU8825_CLK_DIS, 0); | ||
2162 | |||
2163 | /* Clear all interruption status */ | ||
2164 | nau8825_int_status_clear_all(regmap); | ||
2165 | |||
2166 | /* Enable both insertion and ejection interruptions, and then | ||
2167 | * bypass de-bounce circuit. | ||
2168 | */ | ||
2169 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
2170 | NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_HEADSET_COMPLETE_EN | | ||
2171 | NAU8825_IRQ_EJECT_EN | NAU8825_IRQ_INSERT_EN, | ||
2172 | NAU8825_IRQ_OUTPUT_EN | NAU8825_IRQ_HEADSET_COMPLETE_EN); | ||
2173 | regmap_update_bits(regmap, NAU8825_REG_JACK_DET_CTRL, | ||
2174 | NAU8825_JACK_DET_DB_BYPASS, NAU8825_JACK_DET_DB_BYPASS); | ||
2175 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_DIS_CTRL, | ||
2176 | NAU8825_IRQ_INSERT_DIS | NAU8825_IRQ_EJECT_DIS, 0); | ||
2177 | |||
2178 | return 0; | ||
2179 | } | ||
2180 | |||
1138 | static int nau8825_set_bias_level(struct snd_soc_codec *codec, | 2181 | static int nau8825_set_bias_level(struct snd_soc_codec *codec, |
1139 | enum snd_soc_bias_level level) | 2182 | enum snd_soc_bias_level level) |
1140 | { | 2183 | { |
@@ -1157,10 +2200,22 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, | |||
1157 | return ret; | 2200 | return ret; |
1158 | } | 2201 | } |
1159 | } | 2202 | } |
2203 | /* Setup codec configuration after resume */ | ||
2204 | nau8825_resume_setup(nau8825); | ||
1160 | } | 2205 | } |
1161 | break; | 2206 | break; |
1162 | 2207 | ||
1163 | case SND_SOC_BIAS_OFF: | 2208 | case SND_SOC_BIAS_OFF: |
2209 | /* Cancel and reset cross talk detection funciton */ | ||
2210 | nau8825_xtalk_cancel(nau8825); | ||
2211 | /* Turn off all interruptions before system shutdown. Keep the | ||
2212 | * interruption quiet before resume setup completes. | ||
2213 | */ | ||
2214 | regmap_write(nau8825->regmap, | ||
2215 | NAU8825_REG_INTERRUPT_DIS_CTRL, 0xffff); | ||
2216 | /* Disable ADC needed for interruptions at audo mode */ | ||
2217 | regmap_update_bits(nau8825->regmap, NAU8825_REG_ENA_CTRL, | ||
2218 | NAU8825_ENABLE_ADC, 0); | ||
1164 | if (nau8825->mclk_freq) | 2219 | if (nau8825->mclk_freq) |
1165 | clk_disable_unprepare(nau8825->mclk); | 2220 | clk_disable_unprepare(nau8825->mclk); |
1166 | break; | 2221 | break; |
@@ -1168,57 +2223,46 @@ static int nau8825_set_bias_level(struct snd_soc_codec *codec, | |||
1168 | return 0; | 2223 | return 0; |
1169 | } | 2224 | } |
1170 | 2225 | ||
1171 | #ifdef CONFIG_PM | 2226 | static int __maybe_unused nau8825_suspend(struct snd_soc_codec *codec) |
1172 | static int nau8825_suspend(struct snd_soc_codec *codec) | ||
1173 | { | 2227 | { |
1174 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | 2228 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); |
1175 | 2229 | ||
1176 | disable_irq(nau8825->irq); | 2230 | disable_irq(nau8825->irq); |
2231 | snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1177 | regcache_cache_only(nau8825->regmap, true); | 2232 | regcache_cache_only(nau8825->regmap, true); |
1178 | regcache_mark_dirty(nau8825->regmap); | 2233 | regcache_mark_dirty(nau8825->regmap); |
1179 | 2234 | ||
1180 | return 0; | 2235 | return 0; |
1181 | } | 2236 | } |
1182 | 2237 | ||
1183 | static int nau8825_resume(struct snd_soc_codec *codec) | 2238 | static int __maybe_unused nau8825_resume(struct snd_soc_codec *codec) |
1184 | { | 2239 | { |
1185 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); | 2240 | struct nau8825 *nau8825 = snd_soc_codec_get_drvdata(codec); |
1186 | 2241 | ||
1187 | /* The chip may lose power and reset in S3. regcache_sync restores | ||
1188 | * register values including configurations for sysclk, irq, and | ||
1189 | * jack/button detection. | ||
1190 | */ | ||
1191 | regcache_cache_only(nau8825->regmap, false); | 2242 | regcache_cache_only(nau8825->regmap, false); |
1192 | regcache_sync(nau8825->regmap); | 2243 | regcache_sync(nau8825->regmap); |
1193 | 2244 | if (nau8825_is_jack_inserted(nau8825->regmap)) { | |
1194 | /* Check the jack plug status directly. If the headset is unplugged | 2245 | /* If the jack is inserted, we need to check whether the play- |
1195 | * during S3 when the chip has no power, there will be no jack | 2246 | * back is active before suspend. If active, the driver has to |
1196 | * detection irq even after the nau8825_restart_jack_detection below, | 2247 | * raise the protection for cross talk function to avoid the |
1197 | * because the chip just thinks no headset has ever been plugged in. | 2248 | * playback recovers before cross talk process finish. Other- |
1198 | */ | 2249 | * wise, the playback will be interfered by cross talk func- |
1199 | if (!nau8825_is_jack_inserted(nau8825->regmap)) { | 2250 | * tion. It is better to apply hardware related parameters |
1200 | nau8825_eject_jack(nau8825); | 2251 | * before starting playback or record. |
1201 | snd_soc_jack_report(nau8825->jack, 0, SND_JACK_HEADSET); | 2252 | */ |
2253 | if (nau8825_dai_is_active(nau8825)) { | ||
2254 | nau8825->xtalk_protect = true; | ||
2255 | nau8825_sema_acquire(nau8825, 0); | ||
2256 | } | ||
1202 | } | 2257 | } |
1203 | |||
1204 | enable_irq(nau8825->irq); | 2258 | enable_irq(nau8825->irq); |
1205 | 2259 | ||
1206 | /* Run jack detection to check the type (OMTP or CTIA) of the headset | ||
1207 | * if there is one. This handles the case where a different type of | ||
1208 | * headset is plugged in during S3. This triggers an IRQ iff a headset | ||
1209 | * is already plugged in. | ||
1210 | */ | ||
1211 | nau8825_restart_jack_detection(nau8825->regmap); | ||
1212 | |||
1213 | return 0; | 2260 | return 0; |
1214 | } | 2261 | } |
1215 | #else | ||
1216 | #define nau8825_suspend NULL | ||
1217 | #define nau8825_resume NULL | ||
1218 | #endif | ||
1219 | 2262 | ||
1220 | static struct snd_soc_codec_driver nau8825_codec_driver = { | 2263 | static struct snd_soc_codec_driver nau8825_codec_driver = { |
1221 | .probe = nau8825_codec_probe, | 2264 | .probe = nau8825_codec_probe, |
2265 | .remove = nau8825_codec_remove, | ||
1222 | .set_sysclk = nau8825_set_sysclk, | 2266 | .set_sysclk = nau8825_set_sysclk, |
1223 | .set_pll = nau8825_set_pll, | 2267 | .set_pll = nau8825_set_pll, |
1224 | .set_bias_level = nau8825_set_bias_level, | 2268 | .set_bias_level = nau8825_set_bias_level, |
@@ -1318,22 +2362,8 @@ static int nau8825_read_device_properties(struct device *dev, | |||
1318 | 2362 | ||
1319 | static int nau8825_setup_irq(struct nau8825 *nau8825) | 2363 | static int nau8825_setup_irq(struct nau8825 *nau8825) |
1320 | { | 2364 | { |
1321 | struct regmap *regmap = nau8825->regmap; | ||
1322 | int ret; | 2365 | int ret; |
1323 | 2366 | ||
1324 | /* IRQ Output Enable */ | ||
1325 | regmap_update_bits(regmap, NAU8825_REG_INTERRUPT_MASK, | ||
1326 | NAU8825_IRQ_OUTPUT_EN, NAU8825_IRQ_OUTPUT_EN); | ||
1327 | |||
1328 | /* Enable internal VCO needed for interruptions */ | ||
1329 | nau8825_configure_sysclk(nau8825, NAU8825_CLK_INTERNAL, 0); | ||
1330 | |||
1331 | /* Enable DDACR needed for interrupts | ||
1332 | * It is the same as force_enable_pin("DDACR") we do later | ||
1333 | */ | ||
1334 | regmap_update_bits(regmap, NAU8825_REG_ENA_CTRL, | ||
1335 | NAU8825_ENABLE_DACR, NAU8825_ENABLE_DACR); | ||
1336 | |||
1337 | ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL, | 2367 | ret = devm_request_threaded_irq(nau8825->dev, nau8825->irq, NULL, |
1338 | nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, | 2368 | nau8825_interrupt, IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
1339 | "nau8825", nau8825); | 2369 | "nau8825", nau8825); |
@@ -1370,6 +2400,13 @@ static int nau8825_i2c_probe(struct i2c_client *i2c, | |||
1370 | return PTR_ERR(nau8825->regmap); | 2400 | return PTR_ERR(nau8825->regmap); |
1371 | nau8825->dev = dev; | 2401 | nau8825->dev = dev; |
1372 | nau8825->irq = i2c->irq; | 2402 | nau8825->irq = i2c->irq; |
2403 | /* Initiate parameters, semaphone and work queue which are needed in | ||
2404 | * cross talk suppression measurment function. | ||
2405 | */ | ||
2406 | nau8825->xtalk_state = NAU8825_XTALK_DONE; | ||
2407 | nau8825->xtalk_protect = false; | ||
2408 | sema_init(&nau8825->xtalk_sem, 1); | ||
2409 | INIT_WORK(&nau8825->xtalk_work, nau8825_xtalk_work); | ||
1373 | 2410 | ||
1374 | nau8825_print_device_properties(nau8825); | 2411 | nau8825_print_device_properties(nau8825); |
1375 | 2412 | ||
@@ -1405,6 +2442,7 @@ static const struct i2c_device_id nau8825_i2c_ids[] = { | |||
1405 | { "nau8825", 0 }, | 2442 | { "nau8825", 0 }, |
1406 | { } | 2443 | { } |
1407 | }; | 2444 | }; |
2445 | MODULE_DEVICE_TABLE(i2c, nau8825_i2c_ids); | ||
1408 | 2446 | ||
1409 | #ifdef CONFIG_OF | 2447 | #ifdef CONFIG_OF |
1410 | static const struct of_device_id nau8825_of_ids[] = { | 2448 | static const struct of_device_id nau8825_of_ids[] = { |
diff --git a/sound/soc/codecs/nau8825.h b/sound/soc/codecs/nau8825.h index 8ceb5f385478..1c63e2abafa9 100644 --- a/sound/soc/codecs/nau8825.h +++ b/sound/soc/codecs/nau8825.h | |||
@@ -93,12 +93,21 @@ | |||
93 | #define NAU8825_REG_CHARGE_PUMP_INPUT_READ 0x81 | 93 | #define NAU8825_REG_CHARGE_PUMP_INPUT_READ 0x81 |
94 | #define NAU8825_REG_GENERAL_STATUS 0x82 | 94 | #define NAU8825_REG_GENERAL_STATUS 0x82 |
95 | #define NAU8825_REG_MAX NAU8825_REG_GENERAL_STATUS | 95 | #define NAU8825_REG_MAX NAU8825_REG_GENERAL_STATUS |
96 | /* 16-bit control register address, and 16-bits control register data */ | ||
97 | #define NAU8825_REG_ADDR_LEN 16 | ||
98 | #define NAU8825_REG_DATA_LEN 16 | ||
96 | 99 | ||
97 | /* ENA_CTRL (0x1) */ | 100 | /* ENA_CTRL (0x1) */ |
98 | #define NAU8825_ENABLE_DACR_SFT 10 | 101 | #define NAU8825_ENABLE_DACR_SFT 10 |
99 | #define NAU8825_ENABLE_DACR (1 << NAU8825_ENABLE_DACR_SFT) | 102 | #define NAU8825_ENABLE_DACR (1 << NAU8825_ENABLE_DACR_SFT) |
100 | #define NAU8825_ENABLE_DACL_SFT 9 | 103 | #define NAU8825_ENABLE_DACL_SFT 9 |
104 | #define NAU8825_ENABLE_DACL (1 << NAU8825_ENABLE_DACL_SFT) | ||
101 | #define NAU8825_ENABLE_ADC_SFT 8 | 105 | #define NAU8825_ENABLE_ADC_SFT 8 |
106 | #define NAU8825_ENABLE_ADC (1 << NAU8825_ENABLE_ADC_SFT) | ||
107 | #define NAU8825_ENABLE_ADC_CLK_SFT 7 | ||
108 | #define NAU8825_ENABLE_ADC_CLK (1 << NAU8825_ENABLE_ADC_CLK_SFT) | ||
109 | #define NAU8825_ENABLE_DAC_CLK_SFT 6 | ||
110 | #define NAU8825_ENABLE_DAC_CLK (1 << NAU8825_ENABLE_DAC_CLK_SFT) | ||
102 | #define NAU8825_ENABLE_SAR_SFT 1 | 111 | #define NAU8825_ENABLE_SAR_SFT 1 |
103 | 112 | ||
104 | /* CLK_DIVIDER (0x3) */ | 113 | /* CLK_DIVIDER (0x3) */ |
@@ -113,20 +122,28 @@ | |||
113 | 122 | ||
114 | /* FLL3 (0x06) */ | 123 | /* FLL3 (0x06) */ |
115 | #define NAU8825_FLL_INTEGER_MASK (0x3ff << 0) | 124 | #define NAU8825_FLL_INTEGER_MASK (0x3ff << 0) |
125 | #define NAU8825_FLL_CLK_SRC_SFT 10 | ||
126 | #define NAU8825_FLL_CLK_SRC_MASK (0x3 << NAU8825_FLL_CLK_SRC_SFT) | ||
127 | #define NAU8825_FLL_CLK_SRC_MCLK (0 << NAU8825_FLL_CLK_SRC_SFT) | ||
128 | #define NAU8825_FLL_CLK_SRC_BLK (0x2 << NAU8825_FLL_CLK_SRC_SFT) | ||
129 | #define NAU8825_FLL_CLK_SRC_FS (0x3 << NAU8825_FLL_CLK_SRC_SFT) | ||
116 | 130 | ||
117 | /* FLL4 (0x07) */ | 131 | /* FLL4 (0x07) */ |
118 | #define NAU8825_FLL_REF_DIV_MASK (0x3 << 10) | 132 | #define NAU8825_FLL_REF_DIV_MASK (0x3 << 10) |
119 | 133 | ||
120 | /* FLL5 (0x08) */ | 134 | /* FLL5 (0x08) */ |
121 | #define NAU8825_FLL_FILTER_SW_MASK (0x1 << 14) | 135 | #define NAU8825_FLL_PDB_DAC_EN (0x1 << 15) |
136 | #define NAU8825_FLL_LOOP_FTR_EN (0x1 << 14) | ||
137 | #define NAU8825_FLL_CLK_SW_MASK (0x1 << 13) | ||
138 | #define NAU8825_FLL_CLK_SW_N2 (0x1 << 13) | ||
139 | #define NAU8825_FLL_CLK_SW_REF (0x0 << 13) | ||
140 | #define NAU8825_FLL_FTR_SW_MASK (0x1 << 12) | ||
141 | #define NAU8825_FLL_FTR_SW_ACCU (0x1 << 12) | ||
142 | #define NAU8825_FLL_FTR_SW_FILTER (0x0 << 12) | ||
122 | 143 | ||
123 | /* FLL6 (0x9) */ | 144 | /* FLL6 (0x9) */ |
124 | #define NAU8825_DCO_EN_MASK (0x1 << 15) | ||
125 | #define NAU8825_DCO_EN (0x1 << 15) | 145 | #define NAU8825_DCO_EN (0x1 << 15) |
126 | #define NAU8825_DCO_DIS (0x0 << 15) | ||
127 | #define NAU8825_SDM_EN_MASK (0x1 << 14) | ||
128 | #define NAU8825_SDM_EN (0x1 << 14) | 146 | #define NAU8825_SDM_EN (0x1 << 14) |
129 | #define NAU8825_SDM_DIS (0x0 << 14) | ||
130 | 147 | ||
131 | /* HSD_CTRL (0xc) */ | 148 | /* HSD_CTRL (0xc) */ |
132 | #define NAU8825_HSD_AUTO_MODE (1 << 6) | 149 | #define NAU8825_HSD_AUTO_MODE (1 << 6) |
@@ -136,6 +153,7 @@ | |||
136 | 153 | ||
137 | /* JACK_DET_CTRL (0xd) */ | 154 | /* JACK_DET_CTRL (0xd) */ |
138 | #define NAU8825_JACK_DET_RESTART (1 << 9) | 155 | #define NAU8825_JACK_DET_RESTART (1 << 9) |
156 | #define NAU8825_JACK_DET_DB_BYPASS (1 << 8) | ||
139 | #define NAU8825_JACK_INSERT_DEBOUNCE_SFT 5 | 157 | #define NAU8825_JACK_INSERT_DEBOUNCE_SFT 5 |
140 | #define NAU8825_JACK_INSERT_DEBOUNCE_MASK (0x7 << NAU8825_JACK_INSERT_DEBOUNCE_SFT) | 158 | #define NAU8825_JACK_INSERT_DEBOUNCE_MASK (0x7 << NAU8825_JACK_INSERT_DEBOUNCE_SFT) |
141 | #define NAU8825_JACK_EJECT_DEBOUNCE_SFT 2 | 159 | #define NAU8825_JACK_EJECT_DEBOUNCE_SFT 2 |
@@ -145,9 +163,11 @@ | |||
145 | /* INTERRUPT_MASK (0xf) */ | 163 | /* INTERRUPT_MASK (0xf) */ |
146 | #define NAU8825_IRQ_OUTPUT_EN (1 << 11) | 164 | #define NAU8825_IRQ_OUTPUT_EN (1 << 11) |
147 | #define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10) | 165 | #define NAU8825_IRQ_HEADSET_COMPLETE_EN (1 << 10) |
166 | #define NAU8825_IRQ_RMS_EN (1 << 8) | ||
148 | #define NAU8825_IRQ_KEY_RELEASE_EN (1 << 7) | 167 | #define NAU8825_IRQ_KEY_RELEASE_EN (1 << 7) |
149 | #define NAU8825_IRQ_KEY_SHORT_PRESS_EN (1 << 5) | 168 | #define NAU8825_IRQ_KEY_SHORT_PRESS_EN (1 << 5) |
150 | #define NAU8825_IRQ_EJECT_EN (1 << 2) | 169 | #define NAU8825_IRQ_EJECT_EN (1 << 2) |
170 | #define NAU8825_IRQ_INSERT_EN (1 << 0) | ||
151 | 171 | ||
152 | /* IRQ_STATUS (0x10) */ | 172 | /* IRQ_STATUS (0x10) */ |
153 | #define NAU8825_HEADSET_COMPLETION_IRQ (1 << 10) | 173 | #define NAU8825_HEADSET_COMPLETION_IRQ (1 << 10) |
@@ -168,6 +188,7 @@ | |||
168 | #define NAU8825_IRQ_KEY_RELEASE_DIS (1 << 7) | 188 | #define NAU8825_IRQ_KEY_RELEASE_DIS (1 << 7) |
169 | #define NAU8825_IRQ_KEY_SHORT_PRESS_DIS (1 << 5) | 189 | #define NAU8825_IRQ_KEY_SHORT_PRESS_DIS (1 << 5) |
170 | #define NAU8825_IRQ_EJECT_DIS (1 << 2) | 190 | #define NAU8825_IRQ_EJECT_DIS (1 << 2) |
191 | #define NAU8825_IRQ_INSERT_DIS (1 << 0) | ||
171 | 192 | ||
172 | /* SAR_CTRL (0x13) */ | 193 | /* SAR_CTRL (0x13) */ |
173 | #define NAU8825_SAR_ADC_EN_SFT 12 | 194 | #define NAU8825_SAR_ADC_EN_SFT 12 |
@@ -217,10 +238,21 @@ | |||
217 | 238 | ||
218 | /* I2S_PCM_CTRL2 (0x1d) */ | 239 | /* I2S_PCM_CTRL2 (0x1d) */ |
219 | #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ | 240 | #define NAU8825_I2S_TRISTATE (1 << 15) /* 0 - normal mode, 1 - Hi-Z output */ |
241 | #define NAU8825_I2S_DRV_SFT 12 | ||
242 | #define NAU8825_I2S_DRV_MASK (0x3 << NAU8825_I2S_DRV_SFT) | ||
220 | #define NAU8825_I2S_MS_SFT 3 | 243 | #define NAU8825_I2S_MS_SFT 3 |
221 | #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) | 244 | #define NAU8825_I2S_MS_MASK (1 << NAU8825_I2S_MS_SFT) |
222 | #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) | 245 | #define NAU8825_I2S_MS_MASTER (1 << NAU8825_I2S_MS_SFT) |
223 | #define NAU8825_I2S_MS_SLAVE (0 << NAU8825_I2S_MS_SFT) | 246 | #define NAU8825_I2S_MS_SLAVE (0 << NAU8825_I2S_MS_SFT) |
247 | #define NAU8825_I2S_BLK_DIV_MASK 0x7 | ||
248 | |||
249 | /* BIQ_CTRL (0x20) */ | ||
250 | #define NAU8825_BIQ_WRT_SFT 4 | ||
251 | #define NAU8825_BIQ_WRT_EN (1 << NAU8825_BIQ_WRT_SFT) | ||
252 | #define NAU8825_BIQ_PATH_SFT 0 | ||
253 | #define NAU8825_BIQ_PATH_MASK (1 << NAU8825_BIQ_PATH_SFT) | ||
254 | #define NAU8825_BIQ_PATH_ADC (0 << NAU8825_BIQ_PATH_SFT) | ||
255 | #define NAU8825_BIQ_PATH_DAC (1 << NAU8825_BIQ_PATH_SFT) | ||
224 | 256 | ||
225 | /* ADC_RATE (0x2b) */ | 257 | /* ADC_RATE (0x2b) */ |
226 | #define NAU8825_ADC_SYNC_DOWN_SFT 0 | 258 | #define NAU8825_ADC_SYNC_DOWN_SFT 0 |
@@ -239,22 +271,72 @@ | |||
239 | #define NAU8825_DAC_OVERSAMPLE_128 2 | 271 | #define NAU8825_DAC_OVERSAMPLE_128 2 |
240 | #define NAU8825_DAC_OVERSAMPLE_32 4 | 272 | #define NAU8825_DAC_OVERSAMPLE_32 4 |
241 | 273 | ||
274 | /* ADC_DGAIN_CTRL (0x30) */ | ||
275 | #define NAU8825_ADC_DIG_VOL_MASK 0xff | ||
276 | |||
242 | /* MUTE_CTRL (0x31) */ | 277 | /* MUTE_CTRL (0x31) */ |
243 | #define NAU8825_DAC_ZERO_CROSSING_EN (1 << 9) | 278 | #define NAU8825_DAC_ZERO_CROSSING_EN (1 << 9) |
244 | #define NAU8825_DAC_SOFT_MUTE (1 << 9) | 279 | #define NAU8825_DAC_SOFT_MUTE (1 << 9) |
245 | 280 | ||
246 | /* HSVOL_CTRL (0x32) */ | 281 | /* HSVOL_CTRL (0x32) */ |
247 | #define NAU8825_HP_MUTE (1 << 15) | 282 | #define NAU8825_HP_MUTE (1 << 15) |
283 | #define NAU8825_HP_MUTE_AUTO (1 << 14) | ||
284 | #define NAU8825_HPL_MUTE (1 << 13) | ||
285 | #define NAU8825_HPR_MUTE (1 << 12) | ||
286 | #define NAU8825_HPL_VOL_SFT 6 | ||
287 | #define NAU8825_HPL_VOL_MASK (0x3f << NAU8825_HPL_VOL_SFT) | ||
288 | #define NAU8825_HPR_VOL_SFT 0 | ||
289 | #define NAU8825_HPR_VOL_MASK (0x3f << NAU8825_HPR_VOL_SFT) | ||
290 | #define NAU8825_HP_VOL_MIN 0x36 | ||
248 | 291 | ||
249 | /* DACL_CTRL (0x33) */ | 292 | /* DACL_CTRL (0x33) */ |
250 | #define NAU8825_DACL_CH_SEL_SFT 9 | 293 | #define NAU8825_DACL_CH_SEL_SFT 9 |
294 | #define NAU8825_DACL_CH_SEL_MASK (0x1 << NAU8825_DACL_CH_SEL_SFT) | ||
295 | #define NAU8825_DACL_CH_SEL_L (0x0 << NAU8825_DACL_CH_SEL_SFT) | ||
296 | #define NAU8825_DACL_CH_SEL_R (0x1 << NAU8825_DACL_CH_SEL_SFT) | ||
297 | #define NAU8825_DACL_CH_VOL_MASK 0xff | ||
251 | 298 | ||
252 | /* DACR_CTRL (0x34) */ | 299 | /* DACR_CTRL (0x34) */ |
253 | #define NAU8825_DACR_CH_SEL_SFT 9 | 300 | #define NAU8825_DACR_CH_SEL_SFT 9 |
301 | #define NAU8825_DACR_CH_SEL_MASK (0x1 << NAU8825_DACR_CH_SEL_SFT) | ||
302 | #define NAU8825_DACR_CH_SEL_L (0x0 << NAU8825_DACR_CH_SEL_SFT) | ||
303 | #define NAU8825_DACR_CH_SEL_R (0x1 << NAU8825_DACR_CH_SEL_SFT) | ||
304 | #define NAU8825_DACR_CH_VOL_MASK 0xff | ||
305 | |||
306 | /* IMM_MODE_CTRL (0x4C) */ | ||
307 | #define NAU8825_IMM_THD_SFT 8 | ||
308 | #define NAU8825_IMM_THD_MASK (0x3f << NAU8825_IMM_THD_SFT) | ||
309 | #define NAU8825_IMM_GEN_VOL_SFT 6 | ||
310 | #define NAU8825_IMM_GEN_VOL_MASK (0x3 << NAU8825_IMM_GEN_VOL_SFT) | ||
311 | #define NAU8825_IMM_GEN_VOL_1_2nd (0x0 << NAU8825_IMM_GEN_VOL_SFT) | ||
312 | #define NAU8825_IMM_GEN_VOL_1_4th (0x1 << NAU8825_IMM_GEN_VOL_SFT) | ||
313 | #define NAU8825_IMM_GEN_VOL_1_8th (0x2 << NAU8825_IMM_GEN_VOL_SFT) | ||
314 | #define NAU8825_IMM_GEN_VOL_1_16th (0x3 << NAU8825_IMM_GEN_VOL_SFT) | ||
315 | |||
316 | #define NAU8825_IMM_CYC_SFT 4 | ||
317 | #define NAU8825_IMM_CYC_MASK (0x3 << NAU8825_IMM_CYC_SFT) | ||
318 | #define NAU8825_IMM_CYC_1024 (0x0 << NAU8825_IMM_CYC_SFT) | ||
319 | #define NAU8825_IMM_CYC_2048 (0x1 << NAU8825_IMM_CYC_SFT) | ||
320 | #define NAU8825_IMM_CYC_4096 (0x2 << NAU8825_IMM_CYC_SFT) | ||
321 | #define NAU8825_IMM_CYC_8192 (0x3 << NAU8825_IMM_CYC_SFT) | ||
322 | #define NAU8825_IMM_EN (1 << 3) | ||
323 | #define NAU8825_IMM_DAC_SRC_MASK 0x7 | ||
324 | #define NAU8825_IMM_DAC_SRC_BIQ 0x0 | ||
325 | #define NAU8825_IMM_DAC_SRC_DRC 0x1 | ||
326 | #define NAU8825_IMM_DAC_SRC_MIX 0x2 | ||
327 | #define NAU8825_IMM_DAC_SRC_SIN 0x3 | ||
254 | 328 | ||
255 | /* CLASSG_CTRL (0x50) */ | 329 | /* CLASSG_CTRL (0x50) */ |
256 | #define NAU8825_CLASSG_TIMER_SFT 8 | 330 | #define NAU8825_CLASSG_TIMER_SFT 8 |
257 | #define NAU8825_CLASSG_TIMER_MASK (0x3f << NAU8825_CLASSG_TIMER_SFT) | 331 | #define NAU8825_CLASSG_TIMER_MASK (0x3f << NAU8825_CLASSG_TIMER_SFT) |
332 | #define NAU8825_CLASSG_TIMER_1ms (0x1 << NAU8825_CLASSG_TIMER_SFT) | ||
333 | #define NAU8825_CLASSG_TIMER_2ms (0x2 << NAU8825_CLASSG_TIMER_SFT) | ||
334 | #define NAU8825_CLASSG_TIMER_8ms (0x4 << NAU8825_CLASSG_TIMER_SFT) | ||
335 | #define NAU8825_CLASSG_TIMER_16ms (0x8 << NAU8825_CLASSG_TIMER_SFT) | ||
336 | #define NAU8825_CLASSG_TIMER_32ms (0x10 << NAU8825_CLASSG_TIMER_SFT) | ||
337 | #define NAU8825_CLASSG_TIMER_64ms (0x20 << NAU8825_CLASSG_TIMER_SFT) | ||
338 | #define NAU8825_CLASSG_LDAC_EN (0x1 << 2) | ||
339 | #define NAU8825_CLASSG_RDAC_EN (0x1 << 1) | ||
258 | #define NAU8825_CLASSG_EN (1 << 0) | 340 | #define NAU8825_CLASSG_EN (1 << 0) |
259 | 341 | ||
260 | /* I2C_DEVICE_ID (0x58) */ | 342 | /* I2C_DEVICE_ID (0x58) */ |
@@ -263,7 +345,12 @@ | |||
263 | #define NAU8825_SOFTWARE_ID_NAU8825 0x0 | 345 | #define NAU8825_SOFTWARE_ID_NAU8825 0x0 |
264 | 346 | ||
265 | /* BIAS_ADJ (0x66) */ | 347 | /* BIAS_ADJ (0x66) */ |
266 | #define NAU8825_BIAS_TESTDAC_EN (0x3 << 8) | 348 | #define NAU8825_BIAS_HPR_IMP (1 << 15) |
349 | #define NAU8825_BIAS_HPL_IMP (1 << 14) | ||
350 | #define NAU8825_BIAS_TESTDAC_SFT 8 | ||
351 | #define NAU8825_BIAS_TESTDAC_EN (0x3 << NAU8825_BIAS_TESTDAC_SFT) | ||
352 | #define NAU8825_BIAS_TESTDACR_EN (0x2 << NAU8825_BIAS_TESTDAC_SFT) | ||
353 | #define NAU8825_BIAS_TESTDACL_EN (0x1 << NAU8825_BIAS_TESTDAC_SFT) | ||
267 | #define NAU8825_BIAS_VMID (1 << 6) | 354 | #define NAU8825_BIAS_VMID (1 << 6) |
268 | #define NAU8825_BIAS_VMID_SEL_SFT 4 | 355 | #define NAU8825_BIAS_VMID_SEL_SFT 4 |
269 | #define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT) | 356 | #define NAU8825_BIAS_VMID_SEL_MASK (3 << NAU8825_BIAS_VMID_SEL_SFT) |
@@ -282,6 +369,11 @@ | |||
282 | #define NAU8825_POWERUP_ADCL (1 << 6) | 369 | #define NAU8825_POWERUP_ADCL (1 << 6) |
283 | 370 | ||
284 | /* RDAC (0x73) */ | 371 | /* RDAC (0x73) */ |
372 | #define NAU8825_RDAC_FS_BCLK_ENB (1 << 15) | ||
373 | #define NAU8825_RDAC_EN_SFT 12 | ||
374 | #define NAU8825_RDAC_EN (0x3 << NAU8825_RDAC_EN_SFT) | ||
375 | #define NAU8825_RDAC_CLK_EN_SFT 8 | ||
376 | #define NAU8825_RDAC_CLK_EN (0x3 << NAU8825_RDAC_CLK_EN_SFT) | ||
285 | #define NAU8825_RDAC_CLK_DELAY_SFT 4 | 377 | #define NAU8825_RDAC_CLK_DELAY_SFT 4 |
286 | #define NAU8825_RDAC_CLK_DELAY_MASK (0x7 << NAU8825_RDAC_CLK_DELAY_SFT) | 378 | #define NAU8825_RDAC_CLK_DELAY_MASK (0x7 << NAU8825_RDAC_CLK_DELAY_SFT) |
287 | #define NAU8825_RDAC_VREF_SFT 2 | 379 | #define NAU8825_RDAC_VREF_SFT 2 |
@@ -318,8 +410,21 @@ | |||
318 | 410 | ||
319 | /* System Clock Source */ | 411 | /* System Clock Source */ |
320 | enum { | 412 | enum { |
321 | NAU8825_CLK_MCLK = 0, | 413 | NAU8825_CLK_DIS = 0, |
414 | NAU8825_CLK_MCLK, | ||
322 | NAU8825_CLK_INTERNAL, | 415 | NAU8825_CLK_INTERNAL, |
416 | NAU8825_CLK_FLL_MCLK, | ||
417 | NAU8825_CLK_FLL_BLK, | ||
418 | NAU8825_CLK_FLL_FS, | ||
419 | }; | ||
420 | |||
421 | /* Cross talk detection state */ | ||
422 | enum { | ||
423 | NAU8825_XTALK_PREPARE = 0, | ||
424 | NAU8825_XTALK_HPR_R2L, | ||
425 | NAU8825_XTALK_HPL_R2L, | ||
426 | NAU8825_XTALK_IMM, | ||
427 | NAU8825_XTALK_DONE, | ||
323 | }; | 428 | }; |
324 | 429 | ||
325 | struct nau8825 { | 430 | struct nau8825 { |
@@ -328,6 +433,8 @@ struct nau8825 { | |||
328 | struct snd_soc_dapm_context *dapm; | 433 | struct snd_soc_dapm_context *dapm; |
329 | struct snd_soc_jack *jack; | 434 | struct snd_soc_jack *jack; |
330 | struct clk *mclk; | 435 | struct clk *mclk; |
436 | struct work_struct xtalk_work; | ||
437 | struct semaphore xtalk_sem; | ||
331 | int irq; | 438 | int irq; |
332 | int mclk_freq; /* 0 - mclk is disabled */ | 439 | int mclk_freq; /* 0 - mclk is disabled */ |
333 | int button_pressed; | 440 | int button_pressed; |
@@ -346,6 +453,12 @@ struct nau8825 { | |||
346 | int key_debounce; | 453 | int key_debounce; |
347 | int jack_insert_debounce; | 454 | int jack_insert_debounce; |
348 | int jack_eject_debounce; | 455 | int jack_eject_debounce; |
456 | int high_imped; | ||
457 | int xtalk_state; | ||
458 | int xtalk_event; | ||
459 | int xtalk_event_mask; | ||
460 | bool xtalk_protect; | ||
461 | int imp_rms[NAU8825_XTALK_IMM]; | ||
349 | }; | 462 | }; |
350 | 463 | ||
351 | int nau8825_enable_jack_detect(struct snd_soc_codec *codec, | 464 | int nau8825_enable_jack_detect(struct snd_soc_codec *codec, |
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 58325234285c..33e1fc2d1598 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c | |||
@@ -73,7 +73,7 @@ static bool pcm1681_accessible_reg(struct device *dev, unsigned int reg) | |||
73 | return !((reg == 0x00) || (reg == 0x0f)); | 73 | return !((reg == 0x00) || (reg == 0x0f)); |
74 | } | 74 | } |
75 | 75 | ||
76 | static bool pcm1681_writeable_reg(struct device *dev, unsigned register reg) | 76 | static bool pcm1681_writeable_reg(struct device *dev, unsigned int reg) |
77 | { | 77 | { |
78 | return pcm1681_accessible_reg(dev, reg) && | 78 | return pcm1681_accessible_reg(dev, reg) && |
79 | (reg != PCM1681_ZERO_DETECT_STATUS); | 79 | (reg != PCM1681_ZERO_DETECT_STATUS); |
diff --git a/sound/soc/codecs/pcm179x.c b/sound/soc/codecs/pcm179x.c index 06a66579ca6d..88fbdd184aa0 100644 --- a/sound/soc/codecs/pcm179x.c +++ b/sound/soc/codecs/pcm179x.c | |||
@@ -59,7 +59,7 @@ static bool pcm179x_accessible_reg(struct device *dev, unsigned int reg) | |||
59 | return reg >= 0x10 && reg <= 0x17; | 59 | return reg >= 0x10 && reg <= 0x17; |
60 | } | 60 | } |
61 | 61 | ||
62 | static bool pcm179x_writeable_reg(struct device *dev, unsigned register reg) | 62 | static bool pcm179x_writeable_reg(struct device *dev, unsigned int reg) |
63 | { | 63 | { |
64 | bool accessible; | 64 | bool accessible; |
65 | 65 | ||
diff --git a/sound/soc/codecs/pcm5102a.c b/sound/soc/codecs/pcm5102a.c index ed515677409b..8ba322a00363 100644 --- a/sound/soc/codecs/pcm5102a.c +++ b/sound/soc/codecs/pcm5102a.c | |||
@@ -57,7 +57,6 @@ static struct platform_driver pcm5102a_codec_driver = { | |||
57 | .remove = pcm5102a_remove, | 57 | .remove = pcm5102a_remove, |
58 | .driver = { | 58 | .driver = { |
59 | .name = "pcm5102a-codec", | 59 | .name = "pcm5102a-codec", |
60 | .owner = THIS_MODULE, | ||
61 | .of_match_table = pcm5102a_of_match, | 60 | .of_match_table = pcm5102a_of_match, |
62 | }, | 61 | }, |
63 | }; | 62 | }; |
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 1bd31644a782..74c0e4eb3788 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
@@ -1100,6 +1100,13 @@ static const struct dmi_system_id force_combo_jack_table[] = { | |||
1100 | DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform") | 1100 | DMI_MATCH(DMI_PRODUCT_NAME, "Skylake Client platform") |
1101 | } | 1101 | } |
1102 | }, | 1102 | }, |
1103 | { | ||
1104 | .ident = "Intel Kabylake RVP", | ||
1105 | .matches = { | ||
1106 | DMI_MATCH(DMI_PRODUCT_NAME, "Kabylake Client platform") | ||
1107 | } | ||
1108 | }, | ||
1109 | |||
1103 | { } | 1110 | { } |
1104 | }; | 1111 | }; |
1105 | 1112 | ||
diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c new file mode 100644 index 000000000000..77ff8ebe6dfb --- /dev/null +++ b/sound/soc/codecs/rt5514-spi.c | |||
@@ -0,0 +1,447 @@ | |||
1 | /* | ||
2 | * rt5514-spi.c -- RT5514 SPI driver | ||
3 | * | ||
4 | * Copyright 2015 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 <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/tlv.h> | ||
37 | |||
38 | #include "rt5514-spi.h" | ||
39 | |||
40 | static struct spi_device *rt5514_spi; | ||
41 | |||
42 | struct rt5514_dsp { | ||
43 | struct device *dev; | ||
44 | struct delayed_work copy_work; | ||
45 | struct mutex dma_lock; | ||
46 | struct snd_pcm_substream *substream; | ||
47 | unsigned int buf_base, buf_limit, buf_rp; | ||
48 | size_t buf_size; | ||
49 | size_t dma_offset; | ||
50 | size_t dsp_offset; | ||
51 | }; | ||
52 | |||
53 | static const struct snd_pcm_hardware rt5514_spi_pcm_hardware = { | ||
54 | .info = SNDRV_PCM_INFO_MMAP | | ||
55 | SNDRV_PCM_INFO_MMAP_VALID | | ||
56 | SNDRV_PCM_INFO_INTERLEAVED, | ||
57 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
58 | .period_bytes_min = PAGE_SIZE, | ||
59 | .period_bytes_max = 0x20000 / 8, | ||
60 | .periods_min = 8, | ||
61 | .periods_max = 8, | ||
62 | .channels_min = 1, | ||
63 | .channels_max = 1, | ||
64 | .buffer_bytes_max = 0x20000, | ||
65 | }; | ||
66 | |||
67 | static struct snd_soc_dai_driver rt5514_spi_dai = { | ||
68 | .name = "rt5514-dsp-cpu-dai", | ||
69 | .id = 0, | ||
70 | .capture = { | ||
71 | .stream_name = "DSP Capture", | ||
72 | .channels_min = 1, | ||
73 | .channels_max = 1, | ||
74 | .rates = SNDRV_PCM_RATE_16000, | ||
75 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
76 | }, | ||
77 | }; | ||
78 | |||
79 | static void rt5514_spi_copy_work(struct work_struct *work) | ||
80 | { | ||
81 | struct rt5514_dsp *rt5514_dsp = | ||
82 | container_of(work, struct rt5514_dsp, copy_work.work); | ||
83 | struct snd_pcm_runtime *runtime; | ||
84 | size_t period_bytes, truncated_bytes = 0; | ||
85 | |||
86 | mutex_lock(&rt5514_dsp->dma_lock); | ||
87 | if (!rt5514_dsp->substream) { | ||
88 | dev_err(rt5514_dsp->dev, "No pcm substream\n"); | ||
89 | goto done; | ||
90 | } | ||
91 | |||
92 | runtime = rt5514_dsp->substream->runtime; | ||
93 | period_bytes = snd_pcm_lib_period_bytes(rt5514_dsp->substream); | ||
94 | |||
95 | if (rt5514_dsp->buf_size - rt5514_dsp->dsp_offset < period_bytes) | ||
96 | period_bytes = rt5514_dsp->buf_size - rt5514_dsp->dsp_offset; | ||
97 | |||
98 | if (rt5514_dsp->buf_rp + period_bytes <= rt5514_dsp->buf_limit) { | ||
99 | rt5514_spi_burst_read(rt5514_dsp->buf_rp, | ||
100 | runtime->dma_area + rt5514_dsp->dma_offset, | ||
101 | period_bytes); | ||
102 | |||
103 | if (rt5514_dsp->buf_rp + period_bytes == rt5514_dsp->buf_limit) | ||
104 | rt5514_dsp->buf_rp = rt5514_dsp->buf_base; | ||
105 | else | ||
106 | rt5514_dsp->buf_rp += period_bytes; | ||
107 | } else { | ||
108 | truncated_bytes = rt5514_dsp->buf_limit - rt5514_dsp->buf_rp; | ||
109 | rt5514_spi_burst_read(rt5514_dsp->buf_rp, | ||
110 | runtime->dma_area + rt5514_dsp->dma_offset, | ||
111 | truncated_bytes); | ||
112 | |||
113 | rt5514_spi_burst_read(rt5514_dsp->buf_base, | ||
114 | runtime->dma_area + rt5514_dsp->dma_offset + | ||
115 | truncated_bytes, period_bytes - truncated_bytes); | ||
116 | |||
117 | rt5514_dsp->buf_rp = rt5514_dsp->buf_base + | ||
118 | period_bytes - truncated_bytes; | ||
119 | } | ||
120 | |||
121 | rt5514_dsp->dma_offset += period_bytes; | ||
122 | if (rt5514_dsp->dma_offset >= runtime->dma_bytes) | ||
123 | rt5514_dsp->dma_offset = 0; | ||
124 | |||
125 | rt5514_dsp->dsp_offset += period_bytes; | ||
126 | |||
127 | snd_pcm_period_elapsed(rt5514_dsp->substream); | ||
128 | |||
129 | if (rt5514_dsp->dsp_offset < rt5514_dsp->buf_size) | ||
130 | schedule_delayed_work(&rt5514_dsp->copy_work, 5); | ||
131 | done: | ||
132 | mutex_unlock(&rt5514_dsp->dma_lock); | ||
133 | } | ||
134 | |||
135 | /* PCM for streaming audio from the DSP buffer */ | ||
136 | static int rt5514_spi_pcm_open(struct snd_pcm_substream *substream) | ||
137 | { | ||
138 | snd_soc_set_runtime_hwparams(substream, &rt5514_spi_pcm_hardware); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int rt5514_spi_hw_params(struct snd_pcm_substream *substream, | ||
144 | struct snd_pcm_hw_params *hw_params) | ||
145 | { | ||
146 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
147 | struct rt5514_dsp *rt5514_dsp = | ||
148 | snd_soc_platform_get_drvdata(rtd->platform); | ||
149 | int ret; | ||
150 | |||
151 | mutex_lock(&rt5514_dsp->dma_lock); | ||
152 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
153 | params_buffer_bytes(hw_params)); | ||
154 | rt5514_dsp->substream = substream; | ||
155 | mutex_unlock(&rt5514_dsp->dma_lock); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static int rt5514_spi_hw_free(struct snd_pcm_substream *substream) | ||
161 | { | ||
162 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
163 | struct rt5514_dsp *rt5514_dsp = | ||
164 | snd_soc_platform_get_drvdata(rtd->platform); | ||
165 | |||
166 | mutex_lock(&rt5514_dsp->dma_lock); | ||
167 | rt5514_dsp->substream = NULL; | ||
168 | mutex_unlock(&rt5514_dsp->dma_lock); | ||
169 | |||
170 | cancel_delayed_work_sync(&rt5514_dsp->copy_work); | ||
171 | |||
172 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
173 | } | ||
174 | |||
175 | static int rt5514_spi_prepare(struct snd_pcm_substream *substream) | ||
176 | { | ||
177 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
178 | struct rt5514_dsp *rt5514_dsp = | ||
179 | snd_soc_platform_get_drvdata(rtd->platform); | ||
180 | u8 buf[8]; | ||
181 | |||
182 | rt5514_dsp->dma_offset = 0; | ||
183 | rt5514_dsp->dsp_offset = 0; | ||
184 | |||
185 | /** | ||
186 | * The address area x1800XXXX is the register address, and it cannot | ||
187 | * support spi burst read perfectly. So we use the spi burst read | ||
188 | * individually to make sure the data correctly. | ||
189 | */ | ||
190 | rt5514_spi_burst_read(RT5514_BUFFER_VOICE_BASE, (u8 *)&buf, | ||
191 | sizeof(buf)); | ||
192 | rt5514_dsp->buf_base = buf[0] | buf[1] << 8 | buf[2] << 16 | | ||
193 | buf[3] << 24; | ||
194 | |||
195 | rt5514_spi_burst_read(RT5514_BUFFER_VOICE_LIMIT, (u8 *)&buf, | ||
196 | sizeof(buf)); | ||
197 | rt5514_dsp->buf_limit = buf[0] | buf[1] << 8 | buf[2] << 16 | | ||
198 | buf[3] << 24; | ||
199 | |||
200 | rt5514_spi_burst_read(RT5514_BUFFER_VOICE_RP, (u8 *)&buf, | ||
201 | sizeof(buf)); | ||
202 | rt5514_dsp->buf_rp = buf[0] | buf[1] << 8 | buf[2] << 16 | | ||
203 | buf[3] << 24; | ||
204 | |||
205 | rt5514_spi_burst_read(RT5514_BUFFER_VOICE_SIZE, (u8 *)&buf, | ||
206 | sizeof(buf)); | ||
207 | rt5514_dsp->buf_size = buf[0] | buf[1] << 8 | buf[2] << 16 | | ||
208 | buf[3] << 24; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int rt5514_spi_trigger(struct snd_pcm_substream *substream, int cmd) | ||
214 | { | ||
215 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
216 | struct rt5514_dsp *rt5514_dsp = | ||
217 | snd_soc_platform_get_drvdata(rtd->platform); | ||
218 | |||
219 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
220 | if (rt5514_dsp->buf_base && rt5514_dsp->buf_limit && | ||
221 | rt5514_dsp->buf_rp && rt5514_dsp->buf_size) | ||
222 | schedule_delayed_work(&rt5514_dsp->copy_work, 0); | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static snd_pcm_uframes_t rt5514_spi_pcm_pointer( | ||
229 | struct snd_pcm_substream *substream) | ||
230 | { | ||
231 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
232 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
233 | struct rt5514_dsp *rt5514_dsp = | ||
234 | snd_soc_platform_get_drvdata(rtd->platform); | ||
235 | |||
236 | return bytes_to_frames(runtime, rt5514_dsp->dma_offset); | ||
237 | } | ||
238 | |||
239 | static struct snd_pcm_ops rt5514_spi_pcm_ops = { | ||
240 | .open = rt5514_spi_pcm_open, | ||
241 | .hw_params = rt5514_spi_hw_params, | ||
242 | .hw_free = rt5514_spi_hw_free, | ||
243 | .trigger = rt5514_spi_trigger, | ||
244 | .prepare = rt5514_spi_prepare, | ||
245 | .pointer = rt5514_spi_pcm_pointer, | ||
246 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
247 | .page = snd_pcm_lib_get_vmalloc_page, | ||
248 | }; | ||
249 | |||
250 | static int rt5514_spi_pcm_probe(struct snd_soc_platform *platform) | ||
251 | { | ||
252 | struct rt5514_dsp *rt5514_dsp; | ||
253 | |||
254 | rt5514_dsp = devm_kzalloc(platform->dev, sizeof(*rt5514_dsp), | ||
255 | GFP_KERNEL); | ||
256 | |||
257 | rt5514_dsp->dev = &rt5514_spi->dev; | ||
258 | mutex_init(&rt5514_dsp->dma_lock); | ||
259 | INIT_DELAYED_WORK(&rt5514_dsp->copy_work, rt5514_spi_copy_work); | ||
260 | snd_soc_platform_set_drvdata(platform, rt5514_dsp); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static struct snd_soc_platform_driver rt5514_spi_platform = { | ||
266 | .probe = rt5514_spi_pcm_probe, | ||
267 | .ops = &rt5514_spi_pcm_ops, | ||
268 | }; | ||
269 | |||
270 | static const struct snd_soc_component_driver rt5514_spi_dai_component = { | ||
271 | .name = "rt5514-spi-dai", | ||
272 | }; | ||
273 | |||
274 | /** | ||
275 | * rt5514_spi_burst_read - Read data from SPI by rt5514 address. | ||
276 | * @addr: Start address. | ||
277 | * @rxbuf: Data Buffer for reading. | ||
278 | * @len: Data length, it must be a multiple of 8. | ||
279 | * | ||
280 | * | ||
281 | * Returns true for success. | ||
282 | */ | ||
283 | int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len) | ||
284 | { | ||
285 | u8 spi_cmd = RT5514_SPI_CMD_BURST_READ; | ||
286 | int status; | ||
287 | u8 write_buf[8]; | ||
288 | unsigned int i, end, offset = 0; | ||
289 | |||
290 | struct spi_message message; | ||
291 | struct spi_transfer x[3]; | ||
292 | |||
293 | while (offset < len) { | ||
294 | if (offset + RT5514_SPI_BUF_LEN <= len) | ||
295 | end = RT5514_SPI_BUF_LEN; | ||
296 | else | ||
297 | end = len % RT5514_SPI_BUF_LEN; | ||
298 | |||
299 | write_buf[0] = spi_cmd; | ||
300 | write_buf[1] = ((addr + offset) & 0xff000000) >> 24; | ||
301 | write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; | ||
302 | write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; | ||
303 | write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; | ||
304 | |||
305 | spi_message_init(&message); | ||
306 | memset(x, 0, sizeof(x)); | ||
307 | |||
308 | x[0].len = 5; | ||
309 | x[0].tx_buf = write_buf; | ||
310 | spi_message_add_tail(&x[0], &message); | ||
311 | |||
312 | x[1].len = 4; | ||
313 | x[1].tx_buf = write_buf; | ||
314 | spi_message_add_tail(&x[1], &message); | ||
315 | |||
316 | x[2].len = end; | ||
317 | x[2].rx_buf = rxbuf + offset; | ||
318 | spi_message_add_tail(&x[2], &message); | ||
319 | |||
320 | status = spi_sync(rt5514_spi, &message); | ||
321 | |||
322 | if (status) | ||
323 | return false; | ||
324 | |||
325 | offset += RT5514_SPI_BUF_LEN; | ||
326 | } | ||
327 | |||
328 | for (i = 0; i < len; i += 8) { | ||
329 | write_buf[0] = rxbuf[i + 0]; | ||
330 | write_buf[1] = rxbuf[i + 1]; | ||
331 | write_buf[2] = rxbuf[i + 2]; | ||
332 | write_buf[3] = rxbuf[i + 3]; | ||
333 | write_buf[4] = rxbuf[i + 4]; | ||
334 | write_buf[5] = rxbuf[i + 5]; | ||
335 | write_buf[6] = rxbuf[i + 6]; | ||
336 | write_buf[7] = rxbuf[i + 7]; | ||
337 | |||
338 | rxbuf[i + 0] = write_buf[7]; | ||
339 | rxbuf[i + 1] = write_buf[6]; | ||
340 | rxbuf[i + 2] = write_buf[5]; | ||
341 | rxbuf[i + 3] = write_buf[4]; | ||
342 | rxbuf[i + 4] = write_buf[3]; | ||
343 | rxbuf[i + 5] = write_buf[2]; | ||
344 | rxbuf[i + 6] = write_buf[1]; | ||
345 | rxbuf[i + 7] = write_buf[0]; | ||
346 | } | ||
347 | |||
348 | return true; | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * rt5514_spi_burst_write - Write data to SPI by rt5514 address. | ||
353 | * @addr: Start address. | ||
354 | * @txbuf: Data Buffer for writng. | ||
355 | * @len: Data length, it must be a multiple of 8. | ||
356 | * | ||
357 | * | ||
358 | * Returns true for success. | ||
359 | */ | ||
360 | int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len) | ||
361 | { | ||
362 | u8 spi_cmd = RT5514_SPI_CMD_BURST_WRITE; | ||
363 | u8 *write_buf; | ||
364 | unsigned int i, end, offset = 0; | ||
365 | |||
366 | write_buf = kmalloc(RT5514_SPI_BUF_LEN + 6, GFP_KERNEL); | ||
367 | |||
368 | if (write_buf == NULL) | ||
369 | return -ENOMEM; | ||
370 | |||
371 | while (offset < len) { | ||
372 | if (offset + RT5514_SPI_BUF_LEN <= len) | ||
373 | end = RT5514_SPI_BUF_LEN; | ||
374 | else | ||
375 | end = len % RT5514_SPI_BUF_LEN; | ||
376 | |||
377 | write_buf[0] = spi_cmd; | ||
378 | write_buf[1] = ((addr + offset) & 0xff000000) >> 24; | ||
379 | write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; | ||
380 | write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; | ||
381 | write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; | ||
382 | |||
383 | for (i = 0; i < end; i += 8) { | ||
384 | write_buf[i + 12] = txbuf[offset + i + 0]; | ||
385 | write_buf[i + 11] = txbuf[offset + i + 1]; | ||
386 | write_buf[i + 10] = txbuf[offset + i + 2]; | ||
387 | write_buf[i + 9] = txbuf[offset + i + 3]; | ||
388 | write_buf[i + 8] = txbuf[offset + i + 4]; | ||
389 | write_buf[i + 7] = txbuf[offset + i + 5]; | ||
390 | write_buf[i + 6] = txbuf[offset + i + 6]; | ||
391 | write_buf[i + 5] = txbuf[offset + i + 7]; | ||
392 | } | ||
393 | |||
394 | write_buf[end + 5] = spi_cmd; | ||
395 | |||
396 | spi_write(rt5514_spi, write_buf, end + 6); | ||
397 | |||
398 | offset += RT5514_SPI_BUF_LEN; | ||
399 | } | ||
400 | |||
401 | kfree(write_buf); | ||
402 | |||
403 | return 0; | ||
404 | } | ||
405 | EXPORT_SYMBOL_GPL(rt5514_spi_burst_write); | ||
406 | |||
407 | static int rt5514_spi_probe(struct spi_device *spi) | ||
408 | { | ||
409 | int ret; | ||
410 | |||
411 | rt5514_spi = spi; | ||
412 | |||
413 | ret = devm_snd_soc_register_platform(&spi->dev, &rt5514_spi_platform); | ||
414 | if (ret < 0) { | ||
415 | dev_err(&spi->dev, "Failed to register platform.\n"); | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | ret = devm_snd_soc_register_component(&spi->dev, | ||
420 | &rt5514_spi_dai_component, | ||
421 | &rt5514_spi_dai, 1); | ||
422 | if (ret < 0) { | ||
423 | dev_err(&spi->dev, "Failed to register component.\n"); | ||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static const struct of_device_id rt5514_of_match[] = { | ||
431 | { .compatible = "realtek,rt5514", }, | ||
432 | {}, | ||
433 | }; | ||
434 | MODULE_DEVICE_TABLE(of, rt5514_of_match); | ||
435 | |||
436 | static struct spi_driver rt5514_spi_driver = { | ||
437 | .driver = { | ||
438 | .name = "rt5514", | ||
439 | .of_match_table = of_match_ptr(rt5514_of_match), | ||
440 | }, | ||
441 | .probe = rt5514_spi_probe, | ||
442 | }; | ||
443 | module_spi_driver(rt5514_spi_driver); | ||
444 | |||
445 | MODULE_DESCRIPTION("RT5514 SPI driver"); | ||
446 | MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>"); | ||
447 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/rt5514-spi.h b/sound/soc/codecs/rt5514-spi.h new file mode 100644 index 000000000000..f69b1cdf2f9b --- /dev/null +++ b/sound/soc/codecs/rt5514-spi.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * rt5514-spi.h -- RT5514 driver | ||
3 | * | ||
4 | * Copyright 2015 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 __RT5514_SPI_H__ | ||
13 | #define __RT5514_SPI_H__ | ||
14 | |||
15 | /** | ||
16 | * RT5514_SPI_BUF_LEN is the buffer size of SPI master controller. | ||
17 | */ | ||
18 | #define RT5514_SPI_BUF_LEN 240 | ||
19 | |||
20 | #define RT5514_BUFFER_VOICE_BASE 0x18001034 | ||
21 | #define RT5514_BUFFER_VOICE_LIMIT 0x18001038 | ||
22 | #define RT5514_BUFFER_VOICE_RP 0x1800103c | ||
23 | #define RT5514_BUFFER_VOICE_SIZE 0x18001040 | ||
24 | |||
25 | /* SPI Command */ | ||
26 | enum { | ||
27 | RT5514_SPI_CMD_16_READ = 0, | ||
28 | RT5514_SPI_CMD_16_WRITE, | ||
29 | RT5514_SPI_CMD_32_READ, | ||
30 | RT5514_SPI_CMD_32_WRITE, | ||
31 | RT5514_SPI_CMD_BURST_READ, | ||
32 | RT5514_SPI_CMD_BURST_WRITE, | ||
33 | }; | ||
34 | |||
35 | int rt5514_spi_burst_read(unsigned int addr, u8 *rxbuf, size_t len); | ||
36 | int rt5514_spi_burst_write(u32 addr, const u8 *txbuf, size_t len); | ||
37 | |||
38 | #endif /* __RT5514_SPI_H__ */ | ||
diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 879bf60f4965..7162f05101d9 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c | |||
@@ -30,6 +30,9 @@ | |||
30 | 30 | ||
31 | #include "rl6231.h" | 31 | #include "rl6231.h" |
32 | #include "rt5514.h" | 32 | #include "rt5514.h" |
33 | #if defined(CONFIG_SND_SOC_RT5514_SPI) | ||
34 | #include "rt5514-spi.h" | ||
35 | #endif | ||
33 | 36 | ||
34 | static const struct reg_sequence rt5514_i2c_patch[] = { | 37 | static const struct reg_sequence rt5514_i2c_patch[] = { |
35 | {0x1800101c, 0x00000000}, | 38 | {0x1800101c, 0x00000000}, |
@@ -110,6 +113,35 @@ static const struct reg_default rt5514_reg[] = { | |||
110 | {RT5514_VENDOR_ID2, 0x10ec5514}, | 113 | {RT5514_VENDOR_ID2, 0x10ec5514}, |
111 | }; | 114 | }; |
112 | 115 | ||
116 | static void rt5514_enable_dsp_prepare(struct rt5514_priv *rt5514) | ||
117 | { | ||
118 | /* Reset */ | ||
119 | regmap_write(rt5514->i2c_regmap, 0x18002000, 0x000010ec); | ||
120 | /* LDO_I_limit */ | ||
121 | regmap_write(rt5514->i2c_regmap, 0x18002200, 0x00028604); | ||
122 | /* I2C bypass enable */ | ||
123 | regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000001); | ||
124 | /* mini-core reset */ | ||
125 | regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x0005514b); | ||
126 | regmap_write(rt5514->i2c_regmap, 0x18002f00, 0x00055149); | ||
127 | /* I2C bypass disable */ | ||
128 | regmap_write(rt5514->i2c_regmap, 0xfafafafa, 0x00000000); | ||
129 | /* PIN config */ | ||
130 | regmap_write(rt5514->i2c_regmap, 0x18002070, 0x00000040); | ||
131 | /* PLL3(QN)=RCOSC*(10+2) */ | ||
132 | regmap_write(rt5514->i2c_regmap, 0x18002240, 0x0000000a); | ||
133 | /* PLL3 source=RCOSC, fsi=rt_clk */ | ||
134 | regmap_write(rt5514->i2c_regmap, 0x18002100, 0x0000000b); | ||
135 | /* Power on RCOSC, pll3 */ | ||
136 | regmap_write(rt5514->i2c_regmap, 0x18002004, 0x00808b81); | ||
137 | /* DSP clk source = pll3, ENABLE DSP clk */ | ||
138 | regmap_write(rt5514->i2c_regmap, 0x18002f08, 0x00000005); | ||
139 | /* Enable DSP clk auto switch */ | ||
140 | regmap_write(rt5514->i2c_regmap, 0x18001114, 0x00000001); | ||
141 | /* Reduce DSP power */ | ||
142 | regmap_write(rt5514->i2c_regmap, 0x18001118, 0x00000001); | ||
143 | } | ||
144 | |||
113 | static bool rt5514_volatile_register(struct device *dev, unsigned int reg) | 145 | static bool rt5514_volatile_register(struct device *dev, unsigned int reg) |
114 | { | 146 | { |
115 | switch (reg) { | 147 | switch (reg) { |
@@ -248,6 +280,74 @@ static const DECLARE_TLV_DB_RANGE(bst_tlv, | |||
248 | 280 | ||
249 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); | 281 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); |
250 | 282 | ||
283 | static int rt5514_dsp_voice_wake_up_get(struct snd_kcontrol *kcontrol, | ||
284 | struct snd_ctl_elem_value *ucontrol) | ||
285 | { | ||
286 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
287 | struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); | ||
288 | |||
289 | ucontrol->value.integer.value[0] = rt5514->dsp_enabled; | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int rt5514_dsp_voice_wake_up_put(struct snd_kcontrol *kcontrol, | ||
295 | struct snd_ctl_elem_value *ucontrol) | ||
296 | { | ||
297 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
298 | struct rt5514_priv *rt5514 = snd_soc_component_get_drvdata(component); | ||
299 | struct snd_soc_codec *codec = rt5514->codec; | ||
300 | const struct firmware *fw = NULL; | ||
301 | |||
302 | if (ucontrol->value.integer.value[0] == rt5514->dsp_enabled) | ||
303 | return 0; | ||
304 | |||
305 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { | ||
306 | rt5514->dsp_enabled = ucontrol->value.integer.value[0]; | ||
307 | |||
308 | if (rt5514->dsp_enabled) { | ||
309 | rt5514_enable_dsp_prepare(rt5514); | ||
310 | |||
311 | request_firmware(&fw, RT5514_FIRMWARE1, codec->dev); | ||
312 | if (fw) { | ||
313 | #if defined(CONFIG_SND_SOC_RT5514_SPI) | ||
314 | rt5514_spi_burst_write(0x4ff60000, fw->data, | ||
315 | ((fw->size/8)+1)*8); | ||
316 | #else | ||
317 | dev_err(codec->dev, "There is no SPI driver for" | ||
318 | " loading the firmware\n"); | ||
319 | #endif | ||
320 | release_firmware(fw); | ||
321 | fw = NULL; | ||
322 | } | ||
323 | |||
324 | request_firmware(&fw, RT5514_FIRMWARE2, codec->dev); | ||
325 | if (fw) { | ||
326 | #if defined(CONFIG_SND_SOC_RT5514_SPI) | ||
327 | rt5514_spi_burst_write(0x4ffc0000, fw->data, | ||
328 | ((fw->size/8)+1)*8); | ||
329 | #else | ||
330 | dev_err(codec->dev, "There is no SPI driver for" | ||
331 | " loading the firmware\n"); | ||
332 | #endif | ||
333 | release_firmware(fw); | ||
334 | fw = NULL; | ||
335 | } | ||
336 | |||
337 | /* DSP run */ | ||
338 | regmap_write(rt5514->i2c_regmap, 0x18002f00, | ||
339 | 0x00055148); | ||
340 | } else { | ||
341 | regmap_multi_reg_write(rt5514->i2c_regmap, | ||
342 | rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch)); | ||
343 | regcache_mark_dirty(rt5514->regmap); | ||
344 | regcache_sync(rt5514->regmap); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
251 | static const struct snd_kcontrol_new rt5514_snd_controls[] = { | 351 | static const struct snd_kcontrol_new rt5514_snd_controls[] = { |
252 | SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, | 352 | SOC_DOUBLE_TLV("MIC Boost Volume", RT5514_ANA_CTRL_MICBST, |
253 | RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), | 353 | RT5514_SEL_BSTL_SFT, RT5514_SEL_BSTR_SFT, 8, 0, bst_tlv), |
@@ -257,6 +357,8 @@ static const struct snd_kcontrol_new rt5514_snd_controls[] = { | |||
257 | SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, | 357 | SOC_DOUBLE_R_TLV("ADC2 Capture Volume", RT5514_DOWNFILTER1_CTRL1, |
258 | RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, | 358 | RT5514_DOWNFILTER1_CTRL2, RT5514_AD_GAIN_SFT, 127, 0, |
259 | adc_vol_tlv), | 359 | adc_vol_tlv), |
360 | SOC_SINGLE_EXT("DSP Voice Wake Up", SND_SOC_NOPM, 0, 1, 0, | ||
361 | rt5514_dsp_voice_wake_up_get, rt5514_dsp_voice_wake_up_put), | ||
260 | }; | 362 | }; |
261 | 363 | ||
262 | /* ADC Mixer*/ | 364 | /* ADC Mixer*/ |
@@ -365,6 +467,35 @@ static int rt5514_is_sys_clk_from_pll(struct snd_soc_dapm_widget *source, | |||
365 | return 0; | 467 | return 0; |
366 | } | 468 | } |
367 | 469 | ||
470 | static int rt5514_pre_event(struct snd_soc_dapm_widget *w, | ||
471 | struct snd_kcontrol *kcontrol, int event) | ||
472 | { | ||
473 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
474 | struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); | ||
475 | |||
476 | switch (event) { | ||
477 | case SND_SOC_DAPM_PRE_PMU: | ||
478 | /** | ||
479 | * If the DSP is enabled in start of recording, the DSP | ||
480 | * should be disabled, and sync back to normal recording | ||
481 | * settings to make sure recording properly. | ||
482 | */ | ||
483 | if (rt5514->dsp_enabled) { | ||
484 | rt5514->dsp_enabled = 0; | ||
485 | regmap_multi_reg_write(rt5514->i2c_regmap, | ||
486 | rt5514_i2c_patch, ARRAY_SIZE(rt5514_i2c_patch)); | ||
487 | regcache_mark_dirty(rt5514->regmap); | ||
488 | regcache_sync(rt5514->regmap); | ||
489 | } | ||
490 | break; | ||
491 | |||
492 | default: | ||
493 | return 0; | ||
494 | } | ||
495 | |||
496 | return 0; | ||
497 | } | ||
498 | |||
368 | static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { | 499 | static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { |
369 | /* Input Lines */ | 500 | /* Input Lines */ |
370 | SND_SOC_DAPM_INPUT("DMIC1L"), | 501 | SND_SOC_DAPM_INPUT("DMIC1L"), |
@@ -472,6 +603,8 @@ static const struct snd_soc_dapm_widget rt5514_dapm_widgets[] = { | |||
472 | 603 | ||
473 | /* Audio Interface */ | 604 | /* Audio Interface */ |
474 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), | 605 | SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), |
606 | |||
607 | SND_SOC_DAPM_PRE("DAPM Pre", rt5514_pre_event), | ||
475 | }; | 608 | }; |
476 | 609 | ||
477 | static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { | 610 | static const struct snd_soc_dapm_route rt5514_dapm_routes[] = { |
@@ -799,10 +932,41 @@ static int rt5514_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | |||
799 | return 0; | 932 | return 0; |
800 | } | 933 | } |
801 | 934 | ||
935 | static int rt5514_set_bias_level(struct snd_soc_codec *codec, | ||
936 | enum snd_soc_bias_level level) | ||
937 | { | ||
938 | struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); | ||
939 | int ret; | ||
940 | |||
941 | switch (level) { | ||
942 | case SND_SOC_BIAS_PREPARE: | ||
943 | if (IS_ERR(rt5514->mclk)) | ||
944 | break; | ||
945 | |||
946 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { | ||
947 | clk_disable_unprepare(rt5514->mclk); | ||
948 | } else { | ||
949 | ret = clk_prepare_enable(rt5514->mclk); | ||
950 | if (ret) | ||
951 | return ret; | ||
952 | } | ||
953 | break; | ||
954 | |||
955 | default: | ||
956 | break; | ||
957 | } | ||
958 | |||
959 | return 0; | ||
960 | } | ||
961 | |||
802 | static int rt5514_probe(struct snd_soc_codec *codec) | 962 | static int rt5514_probe(struct snd_soc_codec *codec) |
803 | { | 963 | { |
804 | struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); | 964 | struct rt5514_priv *rt5514 = snd_soc_codec_get_drvdata(codec); |
805 | 965 | ||
966 | rt5514->mclk = devm_clk_get(codec->dev, "mclk"); | ||
967 | if (PTR_ERR(rt5514->mclk) == -EPROBE_DEFER) | ||
968 | return -EPROBE_DEFER; | ||
969 | |||
806 | rt5514->codec = codec; | 970 | rt5514->codec = codec; |
807 | 971 | ||
808 | return 0; | 972 | return 0; |
@@ -858,6 +1022,7 @@ struct snd_soc_dai_driver rt5514_dai[] = { | |||
858 | static struct snd_soc_codec_driver soc_codec_dev_rt5514 = { | 1022 | static struct snd_soc_codec_driver soc_codec_dev_rt5514 = { |
859 | .probe = rt5514_probe, | 1023 | .probe = rt5514_probe, |
860 | .idle_bias_off = true, | 1024 | .idle_bias_off = true, |
1025 | .set_bias_level = rt5514_set_bias_level, | ||
861 | .controls = rt5514_snd_controls, | 1026 | .controls = rt5514_snd_controls, |
862 | .num_controls = ARRAY_SIZE(rt5514_snd_controls), | 1027 | .num_controls = ARRAY_SIZE(rt5514_snd_controls), |
863 | .dapm_widgets = rt5514_dapm_widgets, | 1028 | .dapm_widgets = rt5514_dapm_widgets, |
@@ -871,7 +1036,6 @@ static const struct regmap_config rt5514_i2c_regmap = { | |||
871 | .reg_bits = 32, | 1036 | .reg_bits = 32, |
872 | .val_bits = 32, | 1037 | .val_bits = 32, |
873 | 1038 | ||
874 | .max_register = RT5514_DSP_MAPPING | RT5514_VENDOR_ID2, | ||
875 | .readable_reg = rt5514_i2c_readable_register, | 1039 | .readable_reg = rt5514_i2c_readable_register, |
876 | 1040 | ||
877 | .cache_type = REGCACHE_NONE, | 1041 | .cache_type = REGCACHE_NONE, |
@@ -944,7 +1108,7 @@ static int rt5514_i2c_probe(struct i2c_client *i2c, | |||
944 | return -ENODEV; | 1108 | return -ENODEV; |
945 | } | 1109 | } |
946 | 1110 | ||
947 | ret = regmap_register_patch(rt5514->i2c_regmap, rt5514_i2c_patch, | 1111 | ret = regmap_multi_reg_write(rt5514->i2c_regmap, rt5514_i2c_patch, |
948 | ARRAY_SIZE(rt5514_i2c_patch)); | 1112 | ARRAY_SIZE(rt5514_i2c_patch)); |
949 | if (ret != 0) | 1113 | if (ret != 0) |
950 | dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n", | 1114 | dev_warn(&i2c->dev, "Failed to apply i2c_regmap patch: %d\n", |
diff --git a/sound/soc/codecs/rt5514.h b/sound/soc/codecs/rt5514.h index 6ad8a612f659..68883c68e999 100644 --- a/sound/soc/codecs/rt5514.h +++ b/sound/soc/codecs/rt5514.h | |||
@@ -12,6 +12,8 @@ | |||
12 | #ifndef __RT5514_H__ | 12 | #ifndef __RT5514_H__ |
13 | #define __RT5514_H__ | 13 | #define __RT5514_H__ |
14 | 14 | ||
15 | #include <linux/clk.h> | ||
16 | |||
15 | #define RT5514_DEVICE_ID 0x10ec5514 | 17 | #define RT5514_DEVICE_ID 0x10ec5514 |
16 | 18 | ||
17 | #define RT5514_RESET 0x2000 | 19 | #define RT5514_RESET 0x2000 |
@@ -225,6 +227,9 @@ | |||
225 | #define RT5514_PLL_INP_MAX 40000000 | 227 | #define RT5514_PLL_INP_MAX 40000000 |
226 | #define RT5514_PLL_INP_MIN 256000 | 228 | #define RT5514_PLL_INP_MIN 256000 |
227 | 229 | ||
230 | #define RT5514_FIRMWARE1 "rt5514_dsp_fw1.bin" | ||
231 | #define RT5514_FIRMWARE2 "rt5514_dsp_fw2.bin" | ||
232 | |||
228 | /* System Clock Source */ | 233 | /* System Clock Source */ |
229 | enum { | 234 | enum { |
230 | RT5514_SCLK_S_MCLK, | 235 | RT5514_SCLK_S_MCLK, |
@@ -240,6 +245,7 @@ enum { | |||
240 | struct rt5514_priv { | 245 | struct rt5514_priv { |
241 | struct snd_soc_codec *codec; | 246 | struct snd_soc_codec *codec; |
242 | struct regmap *i2c_regmap, *regmap; | 247 | struct regmap *i2c_regmap, *regmap; |
248 | struct clk *mclk; | ||
243 | int sysclk; | 249 | int sysclk; |
244 | int sysclk_src; | 250 | int sysclk_src; |
245 | int lrck; | 251 | int lrck; |
@@ -247,6 +253,7 @@ struct rt5514_priv { | |||
247 | int pll_src; | 253 | int pll_src; |
248 | int pll_in; | 254 | int pll_in; |
249 | int pll_out; | 255 | int pll_out; |
256 | int dsp_enabled; | ||
250 | }; | 257 | }; |
251 | 258 | ||
252 | #endif /* __RT5514_H__ */ | 259 | #endif /* __RT5514_H__ */ |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d70847c9eeb0..490bfe661346 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -63,6 +63,7 @@ static const struct reg_sequence init_list[] = { | |||
63 | {RT5645_PR_BASE + 0x20, 0x611f}, | 63 | {RT5645_PR_BASE + 0x20, 0x611f}, |
64 | {RT5645_PR_BASE + 0x21, 0x4040}, | 64 | {RT5645_PR_BASE + 0x21, 0x4040}, |
65 | {RT5645_PR_BASE + 0x23, 0x0004}, | 65 | {RT5645_PR_BASE + 0x23, 0x0004}, |
66 | {RT5645_ASRC_4, 0x0120}, | ||
66 | }; | 67 | }; |
67 | 68 | ||
68 | static const struct reg_sequence rt5650_init_list[] = { | 69 | static const struct reg_sequence rt5650_init_list[] = { |
@@ -157,7 +158,7 @@ static const struct reg_default rt5645_reg[] = { | |||
157 | { 0x83, 0x0000 }, | 158 | { 0x83, 0x0000 }, |
158 | { 0x84, 0x0000 }, | 159 | { 0x84, 0x0000 }, |
159 | { 0x85, 0x0000 }, | 160 | { 0x85, 0x0000 }, |
160 | { 0x8a, 0x0000 }, | 161 | { 0x8a, 0x0120 }, |
161 | { 0x8e, 0x0004 }, | 162 | { 0x8e, 0x0004 }, |
162 | { 0x8f, 0x1100 }, | 163 | { 0x8f, 0x1100 }, |
163 | { 0x90, 0x0646 }, | 164 | { 0x90, 0x0646 }, |
@@ -314,7 +315,7 @@ static const struct reg_default rt5650_reg[] = { | |||
314 | { 0x83, 0x0000 }, | 315 | { 0x83, 0x0000 }, |
315 | { 0x84, 0x0000 }, | 316 | { 0x84, 0x0000 }, |
316 | { 0x85, 0x0000 }, | 317 | { 0x85, 0x0000 }, |
317 | { 0x8a, 0x0000 }, | 318 | { 0x8a, 0x0120 }, |
318 | { 0x8e, 0x0004 }, | 319 | { 0x8e, 0x0004 }, |
319 | { 0x8f, 0x1100 }, | 320 | { 0x8f, 0x1100 }, |
320 | { 0x90, 0x0646 }, | 321 | { 0x90, 0x0646 }, |
@@ -440,6 +441,7 @@ static bool rt5645_volatile_register(struct device *dev, unsigned int reg) | |||
440 | 441 | ||
441 | switch (reg) { | 442 | switch (reg) { |
442 | case RT5645_RESET: | 443 | case RT5645_RESET: |
444 | case RT5645_PRIV_INDEX: | ||
443 | case RT5645_PRIV_DATA: | 445 | case RT5645_PRIV_DATA: |
444 | case RT5645_IN1_CTRL1: | 446 | case RT5645_IN1_CTRL1: |
445 | case RT5645_IN1_CTRL2: | 447 | case RT5645_IN1_CTRL2: |
@@ -740,6 +742,14 @@ static int rt5645_spk_put_volsw(struct snd_kcontrol *kcontrol, | |||
740 | return ret; | 742 | return ret; |
741 | } | 743 | } |
742 | 744 | ||
745 | static const char * const rt5645_dac1_vol_ctrl_mode_text[] = { | ||
746 | "immediately", "zero crossing", "soft ramp" | ||
747 | }; | ||
748 | |||
749 | static SOC_ENUM_SINGLE_DECL( | ||
750 | rt5645_dac1_vol_ctrl_mode, RT5645_PR_BASE, | ||
751 | RT5645_DA1_ZDET_SFT, rt5645_dac1_vol_ctrl_mode_text); | ||
752 | |||
743 | static const struct snd_kcontrol_new rt5645_snd_controls[] = { | 753 | static const struct snd_kcontrol_new rt5645_snd_controls[] = { |
744 | /* Speaker Output Volume */ | 754 | /* Speaker Output Volume */ |
745 | SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, | 755 | SOC_DOUBLE("Speaker Channel Switch", RT5645_SPK_VOL, |
@@ -806,6 +816,9 @@ static const struct snd_kcontrol_new rt5645_snd_controls[] = { | |||
806 | SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, | 816 | SOC_SINGLE("I2S2 Func Switch", RT5645_GPIO_CTRL1, RT5645_I2S2_SEL_SFT, |
807 | 1, 1), | 817 | 1, 1), |
808 | RT5645_HWEQ("Speaker HWEQ"), | 818 | RT5645_HWEQ("Speaker HWEQ"), |
819 | |||
820 | /* Digital Soft Volume Control */ | ||
821 | SOC_ENUM("DAC1 Digital Volume Control Func", rt5645_dac1_vol_ctrl_mode), | ||
809 | }; | 822 | }; |
810 | 823 | ||
811 | /** | 824 | /** |
@@ -3531,6 +3544,7 @@ MODULE_DEVICE_TABLE(i2c, rt5645_i2c_id); | |||
3531 | static const struct acpi_device_id rt5645_acpi_match[] = { | 3544 | static const struct acpi_device_id rt5645_acpi_match[] = { |
3532 | { "10EC5645", 0 }, | 3545 | { "10EC5645", 0 }, |
3533 | { "10EC5650", 0 }, | 3546 | { "10EC5650", 0 }, |
3547 | { "10EC5640", 0 }, | ||
3534 | {}, | 3548 | {}, |
3535 | }; | 3549 | }; |
3536 | MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); | 3550 | MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); |
@@ -3561,6 +3575,12 @@ static const struct dmi_system_id dmi_platform_intel_braswell[] = { | |||
3561 | DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"), | 3575 | DMI_MATCH(DMI_PRODUCT_NAME, "Setzer"), |
3562 | }, | 3576 | }, |
3563 | }, | 3577 | }, |
3578 | { | ||
3579 | .ident = "Microsoft Surface 3", | ||
3580 | .matches = { | ||
3581 | DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), | ||
3582 | }, | ||
3583 | }, | ||
3564 | { } | 3584 | { } |
3565 | }; | 3585 | }; |
3566 | 3586 | ||
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 205e0715c99a..cfc5f97549eb 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h | |||
@@ -2018,6 +2018,9 @@ | |||
2018 | 2018 | ||
2019 | 2019 | ||
2020 | /* Codec Private Register definition */ | 2020 | /* Codec Private Register definition */ |
2021 | /* DAC ADC Digital Volume (0x00) */ | ||
2022 | #define RT5645_DA1_ZDET_SFT 6 | ||
2023 | |||
2021 | /* 3D Speaker Control (0x63) */ | 2024 | /* 3D Speaker Control (0x63) */ |
2022 | #define RT5645_3D_SPK_MASK (0x1 << 15) | 2025 | #define RT5645_3D_SPK_MASK (0x1 << 15) |
2023 | #define RT5645_3D_SPK_SFT 15 | 2026 | #define RT5645_3D_SPK_SFT 15 |
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 0af5ddbef1da..8ef467f64f03 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c | |||
@@ -55,6 +55,7 @@ static const struct reg_sequence init_list[] = { | |||
55 | { RT5670_PR_BASE + 0x14, 0x9a8a }, | 55 | { RT5670_PR_BASE + 0x14, 0x9a8a }, |
56 | { RT5670_PR_BASE + 0x38, 0x3ba1 }, | 56 | { RT5670_PR_BASE + 0x38, 0x3ba1 }, |
57 | { RT5670_PR_BASE + 0x3d, 0x3640 }, | 57 | { RT5670_PR_BASE + 0x3d, 0x3640 }, |
58 | { 0x8a, 0x0123 }, | ||
58 | }; | 59 | }; |
59 | 60 | ||
60 | static const struct reg_default rt5670_reg[] = { | 61 | static const struct reg_default rt5670_reg[] = { |
@@ -131,7 +132,7 @@ static const struct reg_default rt5670_reg[] = { | |||
131 | { 0x87, 0x0000 }, | 132 | { 0x87, 0x0000 }, |
132 | { 0x88, 0x0000 }, | 133 | { 0x88, 0x0000 }, |
133 | { 0x89, 0x0000 }, | 134 | { 0x89, 0x0000 }, |
134 | { 0x8a, 0x0000 }, | 135 | { 0x8a, 0x0123 }, |
135 | { 0x8b, 0x0000 }, | 136 | { 0x8b, 0x0000 }, |
136 | { 0x8c, 0x0003 }, | 137 | { 0x8c, 0x0003 }, |
137 | { 0x8d, 0x0000 }, | 138 | { 0x8d, 0x0000 }, |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 08b40460663c..527b759c1562 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -38,7 +38,6 @@ | |||
38 | /* default value of sgtl5000 registers */ | 38 | /* default value of sgtl5000 registers */ |
39 | static const struct reg_default sgtl5000_reg_defaults[] = { | 39 | static const struct reg_default sgtl5000_reg_defaults[] = { |
40 | { SGTL5000_CHIP_DIG_POWER, 0x0000 }, | 40 | { SGTL5000_CHIP_DIG_POWER, 0x0000 }, |
41 | { SGTL5000_CHIP_CLK_CTRL, 0x0008 }, | ||
42 | { SGTL5000_CHIP_I2S_CTRL, 0x0010 }, | 41 | { SGTL5000_CHIP_I2S_CTRL, 0x0010 }, |
43 | { SGTL5000_CHIP_SSS_CTRL, 0x0010 }, | 42 | { SGTL5000_CHIP_SSS_CTRL, 0x0010 }, |
44 | { SGTL5000_CHIP_ADCDAC_CTRL, 0x020c }, | 43 | { SGTL5000_CHIP_ADCDAC_CTRL, 0x020c }, |
@@ -47,12 +46,10 @@ static const struct reg_default sgtl5000_reg_defaults[] = { | |||
47 | { SGTL5000_CHIP_ANA_ADC_CTRL, 0x0000 }, | 46 | { SGTL5000_CHIP_ANA_ADC_CTRL, 0x0000 }, |
48 | { SGTL5000_CHIP_ANA_HP_CTRL, 0x1818 }, | 47 | { SGTL5000_CHIP_ANA_HP_CTRL, 0x1818 }, |
49 | { SGTL5000_CHIP_ANA_CTRL, 0x0111 }, | 48 | { SGTL5000_CHIP_ANA_CTRL, 0x0111 }, |
50 | { SGTL5000_CHIP_LINREG_CTRL, 0x0000 }, | ||
51 | { SGTL5000_CHIP_REF_CTRL, 0x0000 }, | 49 | { SGTL5000_CHIP_REF_CTRL, 0x0000 }, |
52 | { SGTL5000_CHIP_MIC_CTRL, 0x0000 }, | 50 | { SGTL5000_CHIP_MIC_CTRL, 0x0000 }, |
53 | { SGTL5000_CHIP_LINE_OUT_CTRL, 0x0000 }, | 51 | { SGTL5000_CHIP_LINE_OUT_CTRL, 0x0000 }, |
54 | { SGTL5000_CHIP_LINE_OUT_VOL, 0x0404 }, | 52 | { SGTL5000_CHIP_LINE_OUT_VOL, 0x0404 }, |
55 | { SGTL5000_CHIP_ANA_POWER, 0x7060 }, | ||
56 | { SGTL5000_CHIP_PLL_CTRL, 0x5000 }, | 53 | { SGTL5000_CHIP_PLL_CTRL, 0x5000 }, |
57 | { SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 }, | 54 | { SGTL5000_CHIP_CLK_TOP_CTRL, 0x0000 }, |
58 | { SGTL5000_CHIP_ANA_STATUS, 0x0000 }, | 55 | { SGTL5000_CHIP_ANA_STATUS, 0x0000 }, |
@@ -92,35 +89,8 @@ static const char *supply_names[SGTL5000_SUPPLY_NUM] = { | |||
92 | "VDDD" | 89 | "VDDD" |
93 | }; | 90 | }; |
94 | 91 | ||
95 | #define LDO_CONSUMER_NAME "VDDD_LDO" | ||
96 | #define LDO_VOLTAGE 1200000 | 92 | #define LDO_VOLTAGE 1200000 |
97 | 93 | #define LINREG_VDDD ((1600 - LDO_VOLTAGE / 1000) / 50) | |
98 | static struct regulator_consumer_supply ldo_consumer[] = { | ||
99 | REGULATOR_SUPPLY(LDO_CONSUMER_NAME, NULL), | ||
100 | }; | ||
101 | |||
102 | static struct regulator_init_data ldo_init_data = { | ||
103 | .constraints = { | ||
104 | .min_uV = 1200000, | ||
105 | .max_uV = 1200000, | ||
106 | .valid_modes_mask = REGULATOR_MODE_NORMAL, | ||
107 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
108 | }, | ||
109 | .num_consumer_supplies = 1, | ||
110 | .consumer_supplies = &ldo_consumer[0], | ||
111 | }; | ||
112 | |||
113 | /* | ||
114 | * sgtl5000 internal ldo regulator, | ||
115 | * enabled when VDDD not provided | ||
116 | */ | ||
117 | struct ldo_regulator { | ||
118 | struct regulator_desc desc; | ||
119 | struct regulator_dev *dev; | ||
120 | int voltage; | ||
121 | void *codec_data; | ||
122 | bool enabled; | ||
123 | }; | ||
124 | 94 | ||
125 | enum sgtl5000_micbias_resistor { | 95 | enum sgtl5000_micbias_resistor { |
126 | SGTL5000_MICBIAS_OFF = 0, | 96 | SGTL5000_MICBIAS_OFF = 0, |
@@ -135,7 +105,7 @@ struct sgtl5000_priv { | |||
135 | int master; /* i2s master or not */ | 105 | int master; /* i2s master or not */ |
136 | int fmt; /* i2s data format */ | 106 | int fmt; /* i2s data format */ |
137 | struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM]; | 107 | struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM]; |
138 | struct ldo_regulator *ldo; | 108 | int num_supplies; |
139 | struct regmap *regmap; | 109 | struct regmap *regmap; |
140 | struct clk *mclk; | 110 | struct clk *mclk; |
141 | int revision; | 111 | int revision; |
@@ -415,6 +385,9 @@ static const DECLARE_TLV_DB_RANGE(mic_gain_tlv, | |||
415 | /* tlv for hp volume, -51.5db to 12.0db, step .5db */ | 385 | /* tlv for hp volume, -51.5db to 12.0db, step .5db */ |
416 | static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); | 386 | static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); |
417 | 387 | ||
388 | /* tlv for lineout volume, 31 steps of .5db each */ | ||
389 | static const DECLARE_TLV_DB_SCALE(lineout_volume, -1550, 50, 0); | ||
390 | |||
418 | static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { | 391 | static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { |
419 | /* SOC_DOUBLE_S8_TLV with invert */ | 392 | /* SOC_DOUBLE_S8_TLV with invert */ |
420 | { | 393 | { |
@@ -443,6 +416,13 @@ static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { | |||
443 | 416 | ||
444 | SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, | 417 | SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, |
445 | 0, 3, 0, mic_gain_tlv), | 418 | 0, 3, 0, mic_gain_tlv), |
419 | |||
420 | SOC_DOUBLE_TLV("Lineout Playback Volume", | ||
421 | SGTL5000_CHIP_LINE_OUT_VOL, | ||
422 | SGTL5000_LINE_OUT_VOL_LEFT_SHIFT, | ||
423 | SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT, | ||
424 | 0x1f, 1, | ||
425 | lineout_volume), | ||
446 | }; | 426 | }; |
447 | 427 | ||
448 | /* mute the codec used by alsa core */ | 428 | /* mute the codec used by alsa core */ |
@@ -778,155 +758,6 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, | |||
778 | return 0; | 758 | return 0; |
779 | } | 759 | } |
780 | 760 | ||
781 | #ifdef CONFIG_REGULATOR | ||
782 | static int ldo_regulator_is_enabled(struct regulator_dev *dev) | ||
783 | { | ||
784 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
785 | |||
786 | return ldo->enabled; | ||
787 | } | ||
788 | |||
789 | static int ldo_regulator_enable(struct regulator_dev *dev) | ||
790 | { | ||
791 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
792 | struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data; | ||
793 | int reg; | ||
794 | |||
795 | if (ldo_regulator_is_enabled(dev)) | ||
796 | return 0; | ||
797 | |||
798 | /* set regulator value firstly */ | ||
799 | reg = (1600 - ldo->voltage / 1000) / 50; | ||
800 | reg = clamp(reg, 0x0, 0xf); | ||
801 | |||
802 | /* amend the voltage value, unit: uV */ | ||
803 | ldo->voltage = (1600 - reg * 50) * 1000; | ||
804 | |||
805 | /* set voltage to register */ | ||
806 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
807 | SGTL5000_LINREG_VDDD_MASK, reg); | ||
808 | |||
809 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
810 | SGTL5000_LINEREG_D_POWERUP, | ||
811 | SGTL5000_LINEREG_D_POWERUP); | ||
812 | |||
813 | /* when internal ldo is enabled, simple digital power can be disabled */ | ||
814 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
815 | SGTL5000_LINREG_SIMPLE_POWERUP, | ||
816 | 0); | ||
817 | |||
818 | ldo->enabled = 1; | ||
819 | return 0; | ||
820 | } | ||
821 | |||
822 | static int ldo_regulator_disable(struct regulator_dev *dev) | ||
823 | { | ||
824 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
825 | struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data; | ||
826 | |||
827 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
828 | SGTL5000_LINEREG_D_POWERUP, | ||
829 | 0); | ||
830 | |||
831 | /* clear voltage info */ | ||
832 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
833 | SGTL5000_LINREG_VDDD_MASK, 0); | ||
834 | |||
835 | ldo->enabled = 0; | ||
836 | |||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | static int ldo_regulator_get_voltage(struct regulator_dev *dev) | ||
841 | { | ||
842 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
843 | |||
844 | return ldo->voltage; | ||
845 | } | ||
846 | |||
847 | static struct regulator_ops ldo_regulator_ops = { | ||
848 | .is_enabled = ldo_regulator_is_enabled, | ||
849 | .enable = ldo_regulator_enable, | ||
850 | .disable = ldo_regulator_disable, | ||
851 | .get_voltage = ldo_regulator_get_voltage, | ||
852 | }; | ||
853 | |||
854 | static int ldo_regulator_register(struct snd_soc_codec *codec, | ||
855 | struct regulator_init_data *init_data, | ||
856 | int voltage) | ||
857 | { | ||
858 | struct ldo_regulator *ldo; | ||
859 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
860 | struct regulator_config config = { }; | ||
861 | |||
862 | ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL); | ||
863 | |||
864 | if (!ldo) | ||
865 | return -ENOMEM; | ||
866 | |||
867 | ldo->desc.name = kstrdup(dev_name(codec->dev), GFP_KERNEL); | ||
868 | if (!ldo->desc.name) { | ||
869 | kfree(ldo); | ||
870 | dev_err(codec->dev, "failed to allocate decs name memory\n"); | ||
871 | return -ENOMEM; | ||
872 | } | ||
873 | |||
874 | ldo->desc.type = REGULATOR_VOLTAGE; | ||
875 | ldo->desc.owner = THIS_MODULE; | ||
876 | ldo->desc.ops = &ldo_regulator_ops; | ||
877 | ldo->desc.n_voltages = 1; | ||
878 | |||
879 | ldo->codec_data = codec; | ||
880 | ldo->voltage = voltage; | ||
881 | |||
882 | config.dev = codec->dev; | ||
883 | config.driver_data = ldo; | ||
884 | config.init_data = init_data; | ||
885 | |||
886 | ldo->dev = regulator_register(&ldo->desc, &config); | ||
887 | if (IS_ERR(ldo->dev)) { | ||
888 | int ret = PTR_ERR(ldo->dev); | ||
889 | |||
890 | dev_err(codec->dev, "failed to register regulator\n"); | ||
891 | kfree(ldo->desc.name); | ||
892 | kfree(ldo); | ||
893 | |||
894 | return ret; | ||
895 | } | ||
896 | sgtl5000->ldo = ldo; | ||
897 | |||
898 | return 0; | ||
899 | } | ||
900 | |||
901 | static int ldo_regulator_remove(struct snd_soc_codec *codec) | ||
902 | { | ||
903 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
904 | struct ldo_regulator *ldo = sgtl5000->ldo; | ||
905 | |||
906 | if (!ldo) | ||
907 | return 0; | ||
908 | |||
909 | regulator_unregister(ldo->dev); | ||
910 | kfree(ldo->desc.name); | ||
911 | kfree(ldo); | ||
912 | |||
913 | return 0; | ||
914 | } | ||
915 | #else | ||
916 | static int ldo_regulator_register(struct snd_soc_codec *codec, | ||
917 | struct regulator_init_data *init_data, | ||
918 | int voltage) | ||
919 | { | ||
920 | dev_err(codec->dev, "this setup needs regulator support in the kernel\n"); | ||
921 | return -EINVAL; | ||
922 | } | ||
923 | |||
924 | static int ldo_regulator_remove(struct snd_soc_codec *codec) | ||
925 | { | ||
926 | return 0; | ||
927 | } | ||
928 | #endif | ||
929 | |||
930 | /* | 761 | /* |
931 | * set dac bias | 762 | * set dac bias |
932 | * common state changes: | 763 | * common state changes: |
@@ -940,42 +771,17 @@ static int ldo_regulator_remove(struct snd_soc_codec *codec) | |||
940 | static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, | 771 | static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, |
941 | enum snd_soc_bias_level level) | 772 | enum snd_soc_bias_level level) |
942 | { | 773 | { |
943 | int ret; | ||
944 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
945 | |||
946 | switch (level) { | 774 | switch (level) { |
947 | case SND_SOC_BIAS_ON: | 775 | case SND_SOC_BIAS_ON: |
948 | case SND_SOC_BIAS_PREPARE: | 776 | case SND_SOC_BIAS_PREPARE: |
949 | break; | ||
950 | case SND_SOC_BIAS_STANDBY: | 777 | case SND_SOC_BIAS_STANDBY: |
951 | if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { | 778 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
952 | ret = regulator_bulk_enable( | 779 | SGTL5000_REFTOP_POWERUP, |
953 | ARRAY_SIZE(sgtl5000->supplies), | 780 | SGTL5000_REFTOP_POWERUP); |
954 | sgtl5000->supplies); | ||
955 | if (ret) | ||
956 | return ret; | ||
957 | udelay(10); | ||
958 | |||
959 | regcache_cache_only(sgtl5000->regmap, false); | ||
960 | |||
961 | ret = regcache_sync(sgtl5000->regmap); | ||
962 | if (ret != 0) { | ||
963 | dev_err(codec->dev, | ||
964 | "Failed to restore cache: %d\n", ret); | ||
965 | |||
966 | regcache_cache_only(sgtl5000->regmap, true); | ||
967 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
968 | sgtl5000->supplies); | ||
969 | |||
970 | return ret; | ||
971 | } | ||
972 | } | ||
973 | |||
974 | break; | 781 | break; |
975 | case SND_SOC_BIAS_OFF: | 782 | case SND_SOC_BIAS_OFF: |
976 | regcache_cache_only(sgtl5000->regmap, true); | 783 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, |
977 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | 784 | SGTL5000_REFTOP_POWERUP, 0); |
978 | sgtl5000->supplies); | ||
979 | break; | 785 | break; |
980 | } | 786 | } |
981 | 787 | ||
@@ -1113,7 +919,6 @@ static const u8 vol_quot_table[] = { | |||
1113 | * and should be set according to: | 919 | * and should be set according to: |
1114 | * 1. vddd provided by external or not | 920 | * 1. vddd provided by external or not |
1115 | * 2. vdda and vddio voltage value. > 3.1v or not | 921 | * 2. vdda and vddio voltage value. > 3.1v or not |
1116 | * 3. chip revision >=0x11 or not. If >=0x11, not use external vddd. | ||
1117 | */ | 922 | */ |
1118 | static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | 923 | static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) |
1119 | { | 924 | { |
@@ -1131,7 +936,9 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
1131 | 936 | ||
1132 | vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer); | 937 | vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer); |
1133 | vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer); | 938 | vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer); |
1134 | vddd = regulator_get_voltage(sgtl5000->supplies[VDDD].consumer); | 939 | vddd = (sgtl5000->num_supplies > VDDD) |
940 | ? regulator_get_voltage(sgtl5000->supplies[VDDD].consumer) | ||
941 | : LDO_VOLTAGE; | ||
1135 | 942 | ||
1136 | vdda = vdda / 1000; | 943 | vdda = vdda / 1000; |
1137 | vddio = vddio / 1000; | 944 | vddio = vddio / 1000; |
@@ -1178,25 +985,6 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
1178 | 985 | ||
1179 | snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr); | 986 | snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr); |
1180 | 987 | ||
1181 | /* set voltage to register */ | ||
1182 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
1183 | SGTL5000_LINREG_VDDD_MASK, 0x8); | ||
1184 | |||
1185 | /* | ||
1186 | * if vddd linear reg has been enabled, | ||
1187 | * simple digital supply should be clear to get | ||
1188 | * proper VDDD voltage. | ||
1189 | */ | ||
1190 | if (ana_pwr & SGTL5000_LINEREG_D_POWERUP) | ||
1191 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
1192 | SGTL5000_LINREG_SIMPLE_POWERUP, | ||
1193 | 0); | ||
1194 | else | ||
1195 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
1196 | SGTL5000_LINREG_SIMPLE_POWERUP | | ||
1197 | SGTL5000_STARTUP_POWERUP, | ||
1198 | 0); | ||
1199 | |||
1200 | /* | 988 | /* |
1201 | * set ADC/DAC VAG to vdda / 2, | 989 | * set ADC/DAC VAG to vdda / 2, |
1202 | * should stay in range (0.8v, 1.575v) | 990 | * should stay in range (0.8v, 1.575v) |
@@ -1256,78 +1044,43 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | |||
1256 | return 0; | 1044 | return 0; |
1257 | } | 1045 | } |
1258 | 1046 | ||
1259 | static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec) | 1047 | static int sgtl5000_enable_regulators(struct i2c_client *client) |
1260 | { | ||
1261 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1262 | int ret; | ||
1263 | |||
1264 | /* set internal ldo to 1.2v */ | ||
1265 | ret = ldo_regulator_register(codec, &ldo_init_data, LDO_VOLTAGE); | ||
1266 | if (ret) { | ||
1267 | dev_err(codec->dev, | ||
1268 | "Failed to register vddd internal supplies: %d\n", ret); | ||
1269 | return ret; | ||
1270 | } | ||
1271 | |||
1272 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
1273 | |||
1274 | dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); | ||
1275 | return 0; | ||
1276 | } | ||
1277 | |||
1278 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | ||
1279 | { | 1048 | { |
1280 | int ret; | 1049 | int ret; |
1281 | int i; | 1050 | int i; |
1282 | int external_vddd = 0; | 1051 | int external_vddd = 0; |
1283 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1284 | struct regulator *vddd; | 1052 | struct regulator *vddd; |
1053 | struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); | ||
1285 | 1054 | ||
1286 | for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) | 1055 | for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) |
1287 | sgtl5000->supplies[i].supply = supply_names[i]; | 1056 | sgtl5000->supplies[i].supply = supply_names[i]; |
1288 | 1057 | ||
1289 | /* External VDDD only works before revision 0x11 */ | 1058 | vddd = regulator_get_optional(&client->dev, "VDDD"); |
1290 | if (sgtl5000->revision < 0x11) { | 1059 | if (IS_ERR(vddd)) { |
1291 | vddd = regulator_get_optional(codec->dev, "VDDD"); | 1060 | /* See if it's just not registered yet */ |
1292 | if (IS_ERR(vddd)) { | 1061 | if (PTR_ERR(vddd) == -EPROBE_DEFER) |
1293 | /* See if it's just not registered yet */ | 1062 | return -EPROBE_DEFER; |
1294 | if (PTR_ERR(vddd) == -EPROBE_DEFER) | 1063 | } else { |
1295 | return -EPROBE_DEFER; | 1064 | external_vddd = 1; |
1296 | } else { | 1065 | regulator_put(vddd); |
1297 | external_vddd = 1; | ||
1298 | regulator_put(vddd); | ||
1299 | } | ||
1300 | } | ||
1301 | |||
1302 | if (!external_vddd) { | ||
1303 | ret = sgtl5000_replace_vddd_with_ldo(codec); | ||
1304 | if (ret) | ||
1305 | return ret; | ||
1306 | } | 1066 | } |
1307 | 1067 | ||
1308 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | 1068 | sgtl5000->num_supplies = ARRAY_SIZE(sgtl5000->supplies) |
1069 | - 1 + external_vddd; | ||
1070 | ret = regulator_bulk_get(&client->dev, sgtl5000->num_supplies, | ||
1309 | sgtl5000->supplies); | 1071 | sgtl5000->supplies); |
1310 | if (ret) | 1072 | if (ret) |
1311 | goto err_ldo_remove; | 1073 | return ret; |
1312 | |||
1313 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | ||
1314 | sgtl5000->supplies); | ||
1315 | if (ret) | ||
1316 | goto err_regulator_free; | ||
1317 | |||
1318 | /* wait for all power rails bring up */ | ||
1319 | udelay(10); | ||
1320 | 1074 | ||
1321 | return 0; | 1075 | ret = regulator_bulk_enable(sgtl5000->num_supplies, |
1076 | sgtl5000->supplies); | ||
1077 | if (!ret) | ||
1078 | usleep_range(10, 20); | ||
1079 | else | ||
1080 | regulator_bulk_free(sgtl5000->num_supplies, | ||
1081 | sgtl5000->supplies); | ||
1322 | 1082 | ||
1323 | err_regulator_free: | ||
1324 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1325 | sgtl5000->supplies); | ||
1326 | err_ldo_remove: | ||
1327 | if (!external_vddd) | ||
1328 | ldo_regulator_remove(codec); | ||
1329 | return ret; | 1083 | return ret; |
1330 | |||
1331 | } | 1084 | } |
1332 | 1085 | ||
1333 | static int sgtl5000_probe(struct snd_soc_codec *codec) | 1086 | static int sgtl5000_probe(struct snd_soc_codec *codec) |
@@ -1335,10 +1088,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1335 | int ret; | 1088 | int ret; |
1336 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | 1089 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); |
1337 | 1090 | ||
1338 | ret = sgtl5000_enable_regulators(codec); | ||
1339 | if (ret) | ||
1340 | return ret; | ||
1341 | |||
1342 | /* power up sgtl5000 */ | 1091 | /* power up sgtl5000 */ |
1343 | ret = sgtl5000_set_power_regs(codec); | 1092 | ret = sgtl5000_set_power_regs(codec); |
1344 | if (ret) | 1093 | if (ret) |
@@ -1389,25 +1138,11 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1389 | return 0; | 1138 | return 0; |
1390 | 1139 | ||
1391 | err: | 1140 | err: |
1392 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1393 | sgtl5000->supplies); | ||
1394 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1395 | sgtl5000->supplies); | ||
1396 | ldo_regulator_remove(codec); | ||
1397 | |||
1398 | return ret; | 1141 | return ret; |
1399 | } | 1142 | } |
1400 | 1143 | ||
1401 | static int sgtl5000_remove(struct snd_soc_codec *codec) | 1144 | static int sgtl5000_remove(struct snd_soc_codec *codec) |
1402 | { | 1145 | { |
1403 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1404 | |||
1405 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1406 | sgtl5000->supplies); | ||
1407 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1408 | sgtl5000->supplies); | ||
1409 | ldo_regulator_remove(codec); | ||
1410 | |||
1411 | return 0; | 1146 | return 0; |
1412 | } | 1147 | } |
1413 | 1148 | ||
@@ -1448,8 +1183,9 @@ static const struct regmap_config sgtl5000_regmap = { | |||
1448 | * and avoid problems like, not being able to probe after an audio playback | 1183 | * and avoid problems like, not being able to probe after an audio playback |
1449 | * followed by a system reset or a 'reboot' command in Linux | 1184 | * followed by a system reset or a 'reboot' command in Linux |
1450 | */ | 1185 | */ |
1451 | static int sgtl5000_fill_defaults(struct sgtl5000_priv *sgtl5000) | 1186 | static void sgtl5000_fill_defaults(struct i2c_client *client) |
1452 | { | 1187 | { |
1188 | struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); | ||
1453 | int i, ret, val, index; | 1189 | int i, ret, val, index; |
1454 | 1190 | ||
1455 | for (i = 0; i < ARRAY_SIZE(sgtl5000_reg_defaults); i++) { | 1191 | for (i = 0; i < ARRAY_SIZE(sgtl5000_reg_defaults); i++) { |
@@ -1457,10 +1193,10 @@ static int sgtl5000_fill_defaults(struct sgtl5000_priv *sgtl5000) | |||
1457 | index = sgtl5000_reg_defaults[i].reg; | 1193 | index = sgtl5000_reg_defaults[i].reg; |
1458 | ret = regmap_write(sgtl5000->regmap, index, val); | 1194 | ret = regmap_write(sgtl5000->regmap, index, val); |
1459 | if (ret) | 1195 | if (ret) |
1460 | return ret; | 1196 | dev_err(&client->dev, |
1197 | "%s: error %d setting reg 0x%02x to 0x%04x\n", | ||
1198 | __func__, ret, index, val); | ||
1461 | } | 1199 | } |
1462 | |||
1463 | return 0; | ||
1464 | } | 1200 | } |
1465 | 1201 | ||
1466 | static int sgtl5000_i2c_probe(struct i2c_client *client, | 1202 | static int sgtl5000_i2c_probe(struct i2c_client *client, |
@@ -1470,16 +1206,23 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1470 | int ret, reg, rev; | 1206 | int ret, reg, rev; |
1471 | struct device_node *np = client->dev.of_node; | 1207 | struct device_node *np = client->dev.of_node; |
1472 | u32 value; | 1208 | u32 value; |
1209 | u16 ana_pwr; | ||
1473 | 1210 | ||
1474 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL); | 1211 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL); |
1475 | if (!sgtl5000) | 1212 | if (!sgtl5000) |
1476 | return -ENOMEM; | 1213 | return -ENOMEM; |
1477 | 1214 | ||
1215 | i2c_set_clientdata(client, sgtl5000); | ||
1216 | |||
1217 | ret = sgtl5000_enable_regulators(client); | ||
1218 | if (ret) | ||
1219 | return ret; | ||
1220 | |||
1478 | sgtl5000->regmap = devm_regmap_init_i2c(client, &sgtl5000_regmap); | 1221 | sgtl5000->regmap = devm_regmap_init_i2c(client, &sgtl5000_regmap); |
1479 | if (IS_ERR(sgtl5000->regmap)) { | 1222 | if (IS_ERR(sgtl5000->regmap)) { |
1480 | ret = PTR_ERR(sgtl5000->regmap); | 1223 | ret = PTR_ERR(sgtl5000->regmap); |
1481 | dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret); | 1224 | dev_err(&client->dev, "Failed to allocate regmap: %d\n", ret); |
1482 | return ret; | 1225 | goto disable_regs; |
1483 | } | 1226 | } |
1484 | 1227 | ||
1485 | sgtl5000->mclk = devm_clk_get(&client->dev, NULL); | 1228 | sgtl5000->mclk = devm_clk_get(&client->dev, NULL); |
@@ -1488,21 +1231,25 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1488 | dev_err(&client->dev, "Failed to get mclock: %d\n", ret); | 1231 | dev_err(&client->dev, "Failed to get mclock: %d\n", ret); |
1489 | /* Defer the probe to see if the clk will be provided later */ | 1232 | /* Defer the probe to see if the clk will be provided later */ |
1490 | if (ret == -ENOENT) | 1233 | if (ret == -ENOENT) |
1491 | return -EPROBE_DEFER; | 1234 | ret = -EPROBE_DEFER; |
1492 | return ret; | 1235 | goto disable_regs; |
1493 | } | 1236 | } |
1494 | 1237 | ||
1495 | ret = clk_prepare_enable(sgtl5000->mclk); | 1238 | ret = clk_prepare_enable(sgtl5000->mclk); |
1496 | if (ret) | 1239 | if (ret) { |
1497 | return ret; | 1240 | dev_err(&client->dev, "Error enabling clock %d\n", ret); |
1241 | goto disable_regs; | ||
1242 | } | ||
1498 | 1243 | ||
1499 | /* Need 8 clocks before I2C accesses */ | 1244 | /* Need 8 clocks before I2C accesses */ |
1500 | udelay(1); | 1245 | udelay(1); |
1501 | 1246 | ||
1502 | /* read chip information */ | 1247 | /* read chip information */ |
1503 | ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, ®); | 1248 | ret = regmap_read(sgtl5000->regmap, SGTL5000_CHIP_ID, ®); |
1504 | if (ret) | 1249 | if (ret) { |
1250 | dev_err(&client->dev, "Error reading chip id %d\n", ret); | ||
1505 | goto disable_clk; | 1251 | goto disable_clk; |
1252 | } | ||
1506 | 1253 | ||
1507 | if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) != | 1254 | if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) != |
1508 | SGTL5000_PARTID_PART_ID) { | 1255 | SGTL5000_PARTID_PART_ID) { |
@@ -1516,6 +1263,44 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1516 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); | 1263 | dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev); |
1517 | sgtl5000->revision = rev; | 1264 | sgtl5000->revision = rev; |
1518 | 1265 | ||
1266 | /* reconfigure the clocks in case we're using the PLL */ | ||
1267 | ret = regmap_write(sgtl5000->regmap, | ||
1268 | SGTL5000_CHIP_CLK_CTRL, | ||
1269 | SGTL5000_CHIP_CLK_CTRL_DEFAULT); | ||
1270 | if (ret) | ||
1271 | dev_err(&client->dev, | ||
1272 | "Error %d initializing CHIP_CLK_CTRL\n", ret); | ||
1273 | |||
1274 | /* Follow section 2.2.1.1 of AN3663 */ | ||
1275 | ana_pwr = SGTL5000_ANA_POWER_DEFAULT; | ||
1276 | if (sgtl5000->num_supplies <= VDDD) { | ||
1277 | /* internal VDDD at 1.2V */ | ||
1278 | ret = regmap_update_bits(sgtl5000->regmap, | ||
1279 | SGTL5000_CHIP_LINREG_CTRL, | ||
1280 | SGTL5000_LINREG_VDDD_MASK, | ||
1281 | LINREG_VDDD); | ||
1282 | if (ret) | ||
1283 | dev_err(&client->dev, | ||
1284 | "Error %d setting LINREG_VDDD\n", ret); | ||
1285 | |||
1286 | ana_pwr |= SGTL5000_LINEREG_D_POWERUP; | ||
1287 | dev_info(&client->dev, | ||
1288 | "Using internal LDO instead of VDDD: check ER1\n"); | ||
1289 | } else { | ||
1290 | /* using external LDO for VDDD | ||
1291 | * Clear startup powerup and simple powerup | ||
1292 | * bits to save power | ||
1293 | */ | ||
1294 | ana_pwr &= ~(SGTL5000_STARTUP_POWERUP | ||
1295 | | SGTL5000_LINREG_SIMPLE_POWERUP); | ||
1296 | dev_dbg(&client->dev, "Using external VDDD\n"); | ||
1297 | } | ||
1298 | ret = regmap_write(sgtl5000->regmap, SGTL5000_CHIP_ANA_POWER, ana_pwr); | ||
1299 | if (ret) | ||
1300 | dev_err(&client->dev, | ||
1301 | "Error %d setting CHIP_ANA_POWER to %04x\n", | ||
1302 | ret, ana_pwr); | ||
1303 | |||
1519 | if (np) { | 1304 | if (np) { |
1520 | if (!of_property_read_u32(np, | 1305 | if (!of_property_read_u32(np, |
1521 | "micbias-resistor-k-ohms", &value)) { | 1306 | "micbias-resistor-k-ohms", &value)) { |
@@ -1557,12 +1342,8 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1557 | } | 1342 | } |
1558 | } | 1343 | } |
1559 | 1344 | ||
1560 | i2c_set_clientdata(client, sgtl5000); | ||
1561 | |||
1562 | /* Ensure sgtl5000 will start with sane register values */ | 1345 | /* Ensure sgtl5000 will start with sane register values */ |
1563 | ret = sgtl5000_fill_defaults(sgtl5000); | 1346 | sgtl5000_fill_defaults(client); |
1564 | if (ret) | ||
1565 | goto disable_clk; | ||
1566 | 1347 | ||
1567 | ret = snd_soc_register_codec(&client->dev, | 1348 | ret = snd_soc_register_codec(&client->dev, |
1568 | &sgtl5000_driver, &sgtl5000_dai, 1); | 1349 | &sgtl5000_driver, &sgtl5000_dai, 1); |
@@ -1573,6 +1354,11 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1573 | 1354 | ||
1574 | disable_clk: | 1355 | disable_clk: |
1575 | clk_disable_unprepare(sgtl5000->mclk); | 1356 | clk_disable_unprepare(sgtl5000->mclk); |
1357 | |||
1358 | disable_regs: | ||
1359 | regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies); | ||
1360 | regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies); | ||
1361 | |||
1576 | return ret; | 1362 | return ret; |
1577 | } | 1363 | } |
1578 | 1364 | ||
@@ -1582,6 +1368,9 @@ static int sgtl5000_i2c_remove(struct i2c_client *client) | |||
1582 | 1368 | ||
1583 | snd_soc_unregister_codec(&client->dev); | 1369 | snd_soc_unregister_codec(&client->dev); |
1584 | clk_disable_unprepare(sgtl5000->mclk); | 1370 | clk_disable_unprepare(sgtl5000->mclk); |
1371 | regulator_bulk_disable(sgtl5000->num_supplies, sgtl5000->supplies); | ||
1372 | regulator_bulk_free(sgtl5000->num_supplies, sgtl5000->supplies); | ||
1373 | |||
1585 | return 0; | 1374 | return 0; |
1586 | } | 1375 | } |
1587 | 1376 | ||
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h index 1c317de26176..22f3442af982 100644 --- a/sound/soc/codecs/sgtl5000.h +++ b/sound/soc/codecs/sgtl5000.h | |||
@@ -92,6 +92,7 @@ | |||
92 | /* | 92 | /* |
93 | * SGTL5000_CHIP_CLK_CTRL | 93 | * SGTL5000_CHIP_CLK_CTRL |
94 | */ | 94 | */ |
95 | #define SGTL5000_CHIP_CLK_CTRL_DEFAULT 0x0008 | ||
95 | #define SGTL5000_RATE_MODE_MASK 0x0030 | 96 | #define SGTL5000_RATE_MODE_MASK 0x0030 |
96 | #define SGTL5000_RATE_MODE_SHIFT 4 | 97 | #define SGTL5000_RATE_MODE_SHIFT 4 |
97 | #define SGTL5000_RATE_MODE_WIDTH 2 | 98 | #define SGTL5000_RATE_MODE_WIDTH 2 |
@@ -325,6 +326,7 @@ | |||
325 | /* | 326 | /* |
326 | * SGTL5000_CHIP_ANA_POWER | 327 | * SGTL5000_CHIP_ANA_POWER |
327 | */ | 328 | */ |
329 | #define SGTL5000_ANA_POWER_DEFAULT 0x7060 | ||
328 | #define SGTL5000_DAC_STEREO 0x4000 | 330 | #define SGTL5000_DAC_STEREO 0x4000 |
329 | #define SGTL5000_LINREG_SIMPLE_POWERUP 0x2000 | 331 | #define SGTL5000_LINREG_SIMPLE_POWERUP 0x2000 |
330 | #define SGTL5000_STARTUP_POWERUP 0x1000 | 332 | #define SGTL5000_STARTUP_POWERUP 0x1000 |
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index b8d19b77bde9..d8baca3f8413 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <sound/pcm_params.h> | 28 | #include <sound/pcm_params.h> |
29 | #include <sound/soc.h> | 29 | #include <sound/soc.h> |
30 | #include <sound/tlv.h> | 30 | #include <sound/tlv.h> |
31 | #include <asm/unaligned.h> | ||
31 | 32 | ||
32 | #include "tas571x.h" | 33 | #include "tas571x.h" |
33 | 34 | ||
@@ -63,6 +64,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) | |||
63 | case TAS571X_INPUT_MUX_REG: | 64 | case TAS571X_INPUT_MUX_REG: |
64 | case TAS571X_CH4_SRC_SELECT_REG: | 65 | case TAS571X_CH4_SRC_SELECT_REG: |
65 | case TAS571X_PWM_MUX_REG: | 66 | case TAS571X_PWM_MUX_REG: |
67 | case TAS5717_CH1_RIGHT_CH_MIX_REG: | ||
68 | case TAS5717_CH1_LEFT_CH_MIX_REG: | ||
69 | case TAS5717_CH2_LEFT_CH_MIX_REG: | ||
70 | case TAS5717_CH2_RIGHT_CH_MIX_REG: | ||
66 | return 4; | 71 | return 4; |
67 | default: | 72 | default: |
68 | return 1; | 73 | return 1; |
@@ -135,6 +140,129 @@ static int tas571x_reg_read(void *context, unsigned int reg, | |||
135 | return 0; | 140 | return 0; |
136 | } | 141 | } |
137 | 142 | ||
143 | /* | ||
144 | * register write for 8- and 20-byte registers | ||
145 | */ | ||
146 | static int tas571x_reg_write_multiword(struct i2c_client *client, | ||
147 | unsigned int reg, const long values[], size_t len) | ||
148 | { | ||
149 | size_t i; | ||
150 | uint8_t *buf, *p; | ||
151 | int ret; | ||
152 | size_t send_size = 1 + len * sizeof(uint32_t); | ||
153 | |||
154 | buf = kzalloc(send_size, GFP_KERNEL | GFP_DMA); | ||
155 | if (!buf) | ||
156 | return -ENOMEM; | ||
157 | buf[0] = reg; | ||
158 | |||
159 | for (i = 0, p = buf + 1; i < len; i++, p += sizeof(uint32_t)) | ||
160 | put_unaligned_be32(values[i], p); | ||
161 | |||
162 | ret = i2c_master_send(client, buf, send_size); | ||
163 | |||
164 | kfree(buf); | ||
165 | |||
166 | if (ret == send_size) | ||
167 | return 0; | ||
168 | else if (ret < 0) | ||
169 | return ret; | ||
170 | else | ||
171 | return -EIO; | ||
172 | } | ||
173 | |||
174 | /* | ||
175 | * register read for 8- and 20-byte registers | ||
176 | */ | ||
177 | static int tas571x_reg_read_multiword(struct i2c_client *client, | ||
178 | unsigned int reg, long values[], size_t len) | ||
179 | { | ||
180 | unsigned int i; | ||
181 | uint8_t send_buf; | ||
182 | uint8_t *recv_buf, *p; | ||
183 | struct i2c_msg msgs[2]; | ||
184 | unsigned int recv_size = len * sizeof(uint32_t); | ||
185 | int ret; | ||
186 | |||
187 | recv_buf = kzalloc(recv_size, GFP_KERNEL | GFP_DMA); | ||
188 | if (!recv_buf) | ||
189 | return -ENOMEM; | ||
190 | |||
191 | send_buf = reg; | ||
192 | |||
193 | msgs[0].addr = client->addr; | ||
194 | msgs[0].len = sizeof(send_buf); | ||
195 | msgs[0].buf = &send_buf; | ||
196 | msgs[0].flags = 0; | ||
197 | |||
198 | msgs[1].addr = client->addr; | ||
199 | msgs[1].len = recv_size; | ||
200 | msgs[1].buf = recv_buf; | ||
201 | msgs[1].flags = I2C_M_RD; | ||
202 | |||
203 | ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | ||
204 | if (ret < 0) | ||
205 | goto err_ret; | ||
206 | else if (ret != ARRAY_SIZE(msgs)) { | ||
207 | ret = -EIO; | ||
208 | goto err_ret; | ||
209 | } | ||
210 | |||
211 | for (i = 0, p = recv_buf; i < len; i++, p += sizeof(uint32_t)) | ||
212 | values[i] = get_unaligned_be32(p); | ||
213 | |||
214 | err_ret: | ||
215 | kfree(recv_buf); | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | /* | ||
220 | * Integer array controls for setting biquad, mixer, DRC coefficients. | ||
221 | * According to the datasheet each coefficient is effectively 26bits, | ||
222 | * i.e. stored as 32bits, where bits [31:26] are ignored. | ||
223 | * TI's TAS57xx Graphical Development Environment tool however produces | ||
224 | * coefficients with more than 26 bits. For this reason we allow values | ||
225 | * in the full 32-bits reange. | ||
226 | * The coefficients are ordered as given in the TAS571x data sheet: | ||
227 | * b0, b1, b2, a1, a2 | ||
228 | */ | ||
229 | |||
230 | static int tas571x_coefficient_info(struct snd_kcontrol *kcontrol, | ||
231 | struct snd_ctl_elem_info *uinfo) | ||
232 | { | ||
233 | int numcoef = kcontrol->private_value >> 16; | ||
234 | |||
235 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
236 | uinfo->count = numcoef; | ||
237 | uinfo->value.integer.min = 0; | ||
238 | uinfo->value.integer.max = 0xffffffff; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int tas571x_coefficient_get(struct snd_kcontrol *kcontrol, | ||
243 | struct snd_ctl_elem_value *ucontrol) | ||
244 | { | ||
245 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
246 | struct i2c_client *i2c = to_i2c_client(codec->dev); | ||
247 | int numcoef = kcontrol->private_value >> 16; | ||
248 | int index = kcontrol->private_value & 0xffff; | ||
249 | |||
250 | return tas571x_reg_read_multiword(i2c, index, | ||
251 | ucontrol->value.integer.value, numcoef); | ||
252 | } | ||
253 | |||
254 | static int tas571x_coefficient_put(struct snd_kcontrol *kcontrol, | ||
255 | struct snd_ctl_elem_value *ucontrol) | ||
256 | { | ||
257 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
258 | struct i2c_client *i2c = to_i2c_client(codec->dev); | ||
259 | int numcoef = kcontrol->private_value >> 16; | ||
260 | int index = kcontrol->private_value & 0xffff; | ||
261 | |||
262 | return tas571x_reg_write_multiword(i2c, index, | ||
263 | ucontrol->value.integer.value, numcoef); | ||
264 | } | ||
265 | |||
138 | static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) | 266 | static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) |
139 | { | 267 | { |
140 | struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); | 268 | struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); |
@@ -241,6 +369,15 @@ static const struct snd_soc_dai_ops tas571x_dai_ops = { | |||
241 | .digital_mute = tas571x_mute, | 369 | .digital_mute = tas571x_mute, |
242 | }; | 370 | }; |
243 | 371 | ||
372 | |||
373 | #define BIQUAD_COEFS(xname, reg) \ | ||
374 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
375 | .info = tas571x_coefficient_info, \ | ||
376 | .get = tas571x_coefficient_get,\ | ||
377 | .put = tas571x_coefficient_put, \ | ||
378 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ | ||
379 | .private_value = reg | (5 << 16) } | ||
380 | |||
244 | static const char *const tas5711_supply_names[] = { | 381 | static const char *const tas5711_supply_names[] = { |
245 | "AVDD", | 382 | "AVDD", |
246 | "DVDD", | 383 | "DVDD", |
@@ -264,6 +401,16 @@ static const struct snd_kcontrol_new tas5711_controls[] = { | |||
264 | TAS571X_SOFT_MUTE_REG, | 401 | TAS571X_SOFT_MUTE_REG, |
265 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | 402 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, |
266 | 1, 1), | 403 | 1, 1), |
404 | |||
405 | SOC_DOUBLE_R_RANGE("CH1 Mixer Volume", | ||
406 | TAS5717_CH1_LEFT_CH_MIX_REG, | ||
407 | TAS5717_CH1_RIGHT_CH_MIX_REG, | ||
408 | 16, 0, 0x80, 0), | ||
409 | |||
410 | SOC_DOUBLE_R_RANGE("CH2 Mixer Volume", | ||
411 | TAS5717_CH2_LEFT_CH_MIX_REG, | ||
412 | TAS5717_CH2_RIGHT_CH_MIX_REG, | ||
413 | 16, 0, 0x80, 0), | ||
267 | }; | 414 | }; |
268 | 415 | ||
269 | static const struct regmap_range tas571x_readonly_regs_range[] = { | 416 | static const struct regmap_range tas571x_readonly_regs_range[] = { |
@@ -340,6 +487,43 @@ static const struct snd_kcontrol_new tas5717_controls[] = { | |||
340 | TAS571X_SOFT_MUTE_REG, | 487 | TAS571X_SOFT_MUTE_REG, |
341 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | 488 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, |
342 | 1, 1), | 489 | 1, 1), |
490 | |||
491 | /* | ||
492 | * The biquads are named according to the register names. | ||
493 | * Please note that TI's TAS57xx Graphical Development Environment | ||
494 | * tool names them different. | ||
495 | */ | ||
496 | BIQUAD_COEFS("CH1 - Biquad 0", TAS5717_CH1_BQ0_REG), | ||
497 | BIQUAD_COEFS("CH1 - Biquad 1", TAS5717_CH1_BQ1_REG), | ||
498 | BIQUAD_COEFS("CH1 - Biquad 2", TAS5717_CH1_BQ2_REG), | ||
499 | BIQUAD_COEFS("CH1 - Biquad 3", TAS5717_CH1_BQ3_REG), | ||
500 | BIQUAD_COEFS("CH1 - Biquad 4", TAS5717_CH1_BQ4_REG), | ||
501 | BIQUAD_COEFS("CH1 - Biquad 5", TAS5717_CH1_BQ5_REG), | ||
502 | BIQUAD_COEFS("CH1 - Biquad 6", TAS5717_CH1_BQ6_REG), | ||
503 | BIQUAD_COEFS("CH1 - Biquad 7", TAS5717_CH1_BQ7_REG), | ||
504 | BIQUAD_COEFS("CH1 - Biquad 8", TAS5717_CH1_BQ8_REG), | ||
505 | BIQUAD_COEFS("CH1 - Biquad 9", TAS5717_CH1_BQ9_REG), | ||
506 | BIQUAD_COEFS("CH1 - Biquad 10", TAS5717_CH1_BQ10_REG), | ||
507 | BIQUAD_COEFS("CH1 - Biquad 11", TAS5717_CH1_BQ11_REG), | ||
508 | |||
509 | BIQUAD_COEFS("CH2 - Biquad 0", TAS5717_CH2_BQ0_REG), | ||
510 | BIQUAD_COEFS("CH2 - Biquad 1", TAS5717_CH2_BQ1_REG), | ||
511 | BIQUAD_COEFS("CH2 - Biquad 2", TAS5717_CH2_BQ2_REG), | ||
512 | BIQUAD_COEFS("CH2 - Biquad 3", TAS5717_CH2_BQ3_REG), | ||
513 | BIQUAD_COEFS("CH2 - Biquad 4", TAS5717_CH2_BQ4_REG), | ||
514 | BIQUAD_COEFS("CH2 - Biquad 5", TAS5717_CH2_BQ5_REG), | ||
515 | BIQUAD_COEFS("CH2 - Biquad 6", TAS5717_CH2_BQ6_REG), | ||
516 | BIQUAD_COEFS("CH2 - Biquad 7", TAS5717_CH2_BQ7_REG), | ||
517 | BIQUAD_COEFS("CH2 - Biquad 8", TAS5717_CH2_BQ8_REG), | ||
518 | BIQUAD_COEFS("CH2 - Biquad 9", TAS5717_CH2_BQ9_REG), | ||
519 | BIQUAD_COEFS("CH2 - Biquad 10", TAS5717_CH2_BQ10_REG), | ||
520 | BIQUAD_COEFS("CH2 - Biquad 11", TAS5717_CH2_BQ11_REG), | ||
521 | |||
522 | BIQUAD_COEFS("CH3 - Biquad 0", TAS5717_CH3_BQ0_REG), | ||
523 | BIQUAD_COEFS("CH3 - Biquad 1", TAS5717_CH3_BQ1_REG), | ||
524 | |||
525 | BIQUAD_COEFS("CH4 - Biquad 0", TAS5717_CH4_BQ0_REG), | ||
526 | BIQUAD_COEFS("CH4 - Biquad 1", TAS5717_CH4_BQ1_REG), | ||
343 | }; | 527 | }; |
344 | 528 | ||
345 | static const struct reg_default tas5717_reg_defaults[] = { | 529 | static const struct reg_default tas5717_reg_defaults[] = { |
@@ -350,6 +534,10 @@ static const struct reg_default tas5717_reg_defaults[] = { | |||
350 | { 0x08, 0x00c0 }, | 534 | { 0x08, 0x00c0 }, |
351 | { 0x09, 0x00c0 }, | 535 | { 0x09, 0x00c0 }, |
352 | { 0x1b, 0x82 }, | 536 | { 0x1b, 0x82 }, |
537 | { TAS5717_CH1_RIGHT_CH_MIX_REG, 0x0 }, | ||
538 | { TAS5717_CH1_LEFT_CH_MIX_REG, 0x800000}, | ||
539 | { TAS5717_CH2_LEFT_CH_MIX_REG, 0x0 }, | ||
540 | { TAS5717_CH2_RIGHT_CH_MIX_REG, 0x800000}, | ||
353 | }; | 541 | }; |
354 | 542 | ||
355 | static const struct regmap_config tas5717_regmap_config = { | 543 | static const struct regmap_config tas5717_regmap_config = { |
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h index cf800c364f0f..c45677bc26ad 100644 --- a/sound/soc/codecs/tas571x.h +++ b/sound/soc/codecs/tas571x.h | |||
@@ -52,4 +52,44 @@ | |||
52 | #define TAS571X_CH4_SRC_SELECT_REG 0x21 | 52 | #define TAS571X_CH4_SRC_SELECT_REG 0x21 |
53 | #define TAS571X_PWM_MUX_REG 0x25 | 53 | #define TAS571X_PWM_MUX_REG 0x25 |
54 | 54 | ||
55 | /* 20-byte biquad registers */ | ||
56 | #define TAS5717_CH1_BQ0_REG 0x26 | ||
57 | #define TAS5717_CH1_BQ1_REG 0x27 | ||
58 | #define TAS5717_CH1_BQ2_REG 0x28 | ||
59 | #define TAS5717_CH1_BQ3_REG 0x29 | ||
60 | #define TAS5717_CH1_BQ4_REG 0x2a | ||
61 | #define TAS5717_CH1_BQ5_REG 0x2b | ||
62 | #define TAS5717_CH1_BQ6_REG 0x2c | ||
63 | #define TAS5717_CH1_BQ7_REG 0x2d | ||
64 | #define TAS5717_CH1_BQ8_REG 0x2e | ||
65 | #define TAS5717_CH1_BQ9_REG 0x2f | ||
66 | |||
67 | #define TAS5717_CH2_BQ0_REG 0x30 | ||
68 | #define TAS5717_CH2_BQ1_REG 0x31 | ||
69 | #define TAS5717_CH2_BQ2_REG 0x32 | ||
70 | #define TAS5717_CH2_BQ3_REG 0x33 | ||
71 | #define TAS5717_CH2_BQ4_REG 0x34 | ||
72 | #define TAS5717_CH2_BQ5_REG 0x35 | ||
73 | #define TAS5717_CH2_BQ6_REG 0x36 | ||
74 | #define TAS5717_CH2_BQ7_REG 0x37 | ||
75 | #define TAS5717_CH2_BQ8_REG 0x38 | ||
76 | #define TAS5717_CH2_BQ9_REG 0x39 | ||
77 | |||
78 | #define TAS5717_CH1_BQ10_REG 0x58 | ||
79 | #define TAS5717_CH1_BQ11_REG 0x59 | ||
80 | |||
81 | #define TAS5717_CH4_BQ0_REG 0x5a | ||
82 | #define TAS5717_CH4_BQ1_REG 0x5b | ||
83 | |||
84 | #define TAS5717_CH2_BQ10_REG 0x5c | ||
85 | #define TAS5717_CH2_BQ11_REG 0x5d | ||
86 | |||
87 | #define TAS5717_CH3_BQ0_REG 0x5e | ||
88 | #define TAS5717_CH3_BQ1_REG 0x5f | ||
89 | |||
90 | #define TAS5717_CH1_RIGHT_CH_MIX_REG 0x72 | ||
91 | #define TAS5717_CH1_LEFT_CH_MIX_REG 0x73 | ||
92 | #define TAS5717_CH2_LEFT_CH_MIX_REG 0x76 | ||
93 | #define TAS5717_CH2_RIGHT_CH_MIX_REG 0x77 | ||
94 | |||
55 | #endif /* _TAS571X_H */ | 95 | #endif /* _TAS571X_H */ |
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index fe16c34607bb..ac9b146526eb 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h | |||
@@ -38,141 +38,143 @@ struct aic31xx_pdata { | |||
38 | int micbias_vg; | 38 | int micbias_vg; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | #define AIC31XX_REG(page, reg) ((page * 128) + reg) | ||
42 | |||
41 | /* Page Control Register */ | 43 | /* Page Control Register */ |
42 | #define AIC31XX_PAGECTL 0x00 | 44 | #define AIC31XX_PAGECTL AIC31XX_REG(0, 0) |
43 | 45 | ||
44 | /* Page 0 Registers */ | 46 | /* Page 0 Registers */ |
45 | /* Software reset register */ | 47 | /* Software reset register */ |
46 | #define AIC31XX_RESET 0x01 | 48 | #define AIC31XX_RESET AIC31XX_REG(0, 1) |
47 | /* OT FLAG register */ | 49 | /* OT FLAG register */ |
48 | #define AIC31XX_OT_FLAG 0x03 | 50 | #define AIC31XX_OT_FLAG AIC31XX_REG(0, 3) |
49 | /* Clock clock Gen muxing, Multiplexers*/ | 51 | /* Clock clock Gen muxing, Multiplexers*/ |
50 | #define AIC31XX_CLKMUX 0x04 | 52 | #define AIC31XX_CLKMUX AIC31XX_REG(0, 4) |
51 | /* PLL P and R-VAL register */ | 53 | /* PLL P and R-VAL register */ |
52 | #define AIC31XX_PLLPR 0x05 | 54 | #define AIC31XX_PLLPR AIC31XX_REG(0, 5) |
53 | /* PLL J-VAL register */ | 55 | /* PLL J-VAL register */ |
54 | #define AIC31XX_PLLJ 0x06 | 56 | #define AIC31XX_PLLJ AIC31XX_REG(0, 6) |
55 | /* PLL D-VAL MSB register */ | 57 | /* PLL D-VAL MSB register */ |
56 | #define AIC31XX_PLLDMSB 0x07 | 58 | #define AIC31XX_PLLDMSB AIC31XX_REG(0, 7) |
57 | /* PLL D-VAL LSB register */ | 59 | /* PLL D-VAL LSB register */ |
58 | #define AIC31XX_PLLDLSB 0x08 | 60 | #define AIC31XX_PLLDLSB AIC31XX_REG(0, 8) |
59 | /* DAC NDAC_VAL register*/ | 61 | /* DAC NDAC_VAL register*/ |
60 | #define AIC31XX_NDAC 0x0B | 62 | #define AIC31XX_NDAC AIC31XX_REG(0, 11) |
61 | /* DAC MDAC_VAL register */ | 63 | /* DAC MDAC_VAL register */ |
62 | #define AIC31XX_MDAC 0x0C | 64 | #define AIC31XX_MDAC AIC31XX_REG(0, 12) |
63 | /* DAC OSR setting register 1, MSB value */ | 65 | /* DAC OSR setting register 1, MSB value */ |
64 | #define AIC31XX_DOSRMSB 0x0D | 66 | #define AIC31XX_DOSRMSB AIC31XX_REG(0, 13) |
65 | /* DAC OSR setting register 2, LSB value */ | 67 | /* DAC OSR setting register 2, LSB value */ |
66 | #define AIC31XX_DOSRLSB 0x0E | 68 | #define AIC31XX_DOSRLSB AIC31XX_REG(0, 14) |
67 | #define AIC31XX_MINI_DSP_INPOL 0x10 | 69 | #define AIC31XX_MINI_DSP_INPOL AIC31XX_REG(0, 16) |
68 | /* Clock setting register 8, PLL */ | 70 | /* Clock setting register 8, PLL */ |
69 | #define AIC31XX_NADC 0x12 | 71 | #define AIC31XX_NADC AIC31XX_REG(0, 18) |
70 | /* Clock setting register 9, PLL */ | 72 | /* Clock setting register 9, PLL */ |
71 | #define AIC31XX_MADC 0x13 | 73 | #define AIC31XX_MADC AIC31XX_REG(0, 19) |
72 | /* ADC Oversampling (AOSR) Register */ | 74 | /* ADC Oversampling (AOSR) Register */ |
73 | #define AIC31XX_AOSR 0x14 | 75 | #define AIC31XX_AOSR AIC31XX_REG(0, 20) |
74 | /* Clock setting register 9, Multiplexers */ | 76 | /* Clock setting register 9, Multiplexers */ |
75 | #define AIC31XX_CLKOUTMUX 0x19 | 77 | #define AIC31XX_CLKOUTMUX AIC31XX_REG(0, 25) |
76 | /* Clock setting register 10, CLOCKOUT M divider value */ | 78 | /* Clock setting register 10, CLOCKOUT M divider value */ |
77 | #define AIC31XX_CLKOUTMVAL 0x1A | 79 | #define AIC31XX_CLKOUTMVAL AIC31XX_REG(0, 26) |
78 | /* Audio Interface Setting Register 1 */ | 80 | /* Audio Interface Setting Register 1 */ |
79 | #define AIC31XX_IFACE1 0x1B | 81 | #define AIC31XX_IFACE1 AIC31XX_REG(0, 27) |
80 | /* Audio Data Slot Offset Programming */ | 82 | /* Audio Data Slot Offset Programming */ |
81 | #define AIC31XX_DATA_OFFSET 0x1C | 83 | #define AIC31XX_DATA_OFFSET AIC31XX_REG(0, 28) |
82 | /* Audio Interface Setting Register 2 */ | 84 | /* Audio Interface Setting Register 2 */ |
83 | #define AIC31XX_IFACE2 0x1D | 85 | #define AIC31XX_IFACE2 AIC31XX_REG(0, 29) |
84 | /* Clock setting register 11, BCLK N Divider */ | 86 | /* Clock setting register 11, BCLK N Divider */ |
85 | #define AIC31XX_BCLKN 0x1E | 87 | #define AIC31XX_BCLKN AIC31XX_REG(0, 30) |
86 | /* Audio Interface Setting Register 3, Secondary Audio Interface */ | 88 | /* Audio Interface Setting Register 3, Secondary Audio Interface */ |
87 | #define AIC31XX_IFACESEC1 0x1F | 89 | #define AIC31XX_IFACESEC1 AIC31XX_REG(0, 31) |
88 | /* Audio Interface Setting Register 4 */ | 90 | /* Audio Interface Setting Register 4 */ |
89 | #define AIC31XX_IFACESEC2 0x20 | 91 | #define AIC31XX_IFACESEC2 AIC31XX_REG(0, 32) |
90 | /* Audio Interface Setting Register 5 */ | 92 | /* Audio Interface Setting Register 5 */ |
91 | #define AIC31XX_IFACESEC3 0x21 | 93 | #define AIC31XX_IFACESEC3 AIC31XX_REG(0, 33) |
92 | /* I2C Bus Condition */ | 94 | /* I2C Bus Condition */ |
93 | #define AIC31XX_I2C 0x22 | 95 | #define AIC31XX_I2C AIC31XX_REG(0, 34) |
94 | /* ADC FLAG */ | 96 | /* ADC FLAG */ |
95 | #define AIC31XX_ADCFLAG 0x24 | 97 | #define AIC31XX_ADCFLAG AIC31XX_REG(0, 36) |
96 | /* DAC Flag Registers */ | 98 | /* DAC Flag Registers */ |
97 | #define AIC31XX_DACFLAG1 0x25 | 99 | #define AIC31XX_DACFLAG1 AIC31XX_REG(0, 37) |
98 | #define AIC31XX_DACFLAG2 0x26 | 100 | #define AIC31XX_DACFLAG2 AIC31XX_REG(0, 38) |
99 | /* Sticky Interrupt flag (overflow) */ | 101 | /* Sticky Interrupt flag (overflow) */ |
100 | #define AIC31XX_OFFLAG 0x27 | 102 | #define AIC31XX_OFFLAG AIC31XX_REG(0, 39) |
101 | /* Sticy DAC Interrupt flags */ | 103 | /* Sticy DAC Interrupt flags */ |
102 | #define AIC31XX_INTRDACFLAG 0x2C | 104 | #define AIC31XX_INTRDACFLAG AIC31XX_REG(0, 44) |
103 | /* Sticy ADC Interrupt flags */ | 105 | /* Sticy ADC Interrupt flags */ |
104 | #define AIC31XX_INTRADCFLAG 0x2D | 106 | #define AIC31XX_INTRADCFLAG AIC31XX_REG(0, 45) |
105 | /* DAC Interrupt flags 2 */ | 107 | /* DAC Interrupt flags 2 */ |
106 | #define AIC31XX_INTRDACFLAG2 0x2E | 108 | #define AIC31XX_INTRDACFLAG2 AIC31XX_REG(0, 46) |
107 | /* ADC Interrupt flags 2 */ | 109 | /* ADC Interrupt flags 2 */ |
108 | #define AIC31XX_INTRADCFLAG2 0x2F | 110 | #define AIC31XX_INTRADCFLAG2 AIC31XX_REG(0, 47) |
109 | /* INT1 interrupt control */ | 111 | /* INT1 interrupt control */ |
110 | #define AIC31XX_INT1CTRL 0x30 | 112 | #define AIC31XX_INT1CTRL AIC31XX_REG(0, 48) |
111 | /* INT2 interrupt control */ | 113 | /* INT2 interrupt control */ |
112 | #define AIC31XX_INT2CTRL 0x31 | 114 | #define AIC31XX_INT2CTRL AIC31XX_REG(0, 49) |
113 | /* GPIO1 control */ | 115 | /* GPIO1 control */ |
114 | #define AIC31XX_GPIO1 0x33 | 116 | #define AIC31XX_GPIO1 AIC31XX_REG(0, 50) |
115 | 117 | ||
116 | #define AIC31XX_DACPRB 0x3C | 118 | #define AIC31XX_DACPRB AIC31XX_REG(0, 60) |
117 | /* ADC Instruction Set Register */ | 119 | /* ADC Instruction Set Register */ |
118 | #define AIC31XX_ADCPRB 0x3D | 120 | #define AIC31XX_ADCPRB AIC31XX_REG(0, 61) |
119 | /* DAC channel setup register */ | 121 | /* DAC channel setup register */ |
120 | #define AIC31XX_DACSETUP 0x3F | 122 | #define AIC31XX_DACSETUP AIC31XX_REG(0, 63) |
121 | /* DAC Mute and volume control register */ | 123 | /* DAC Mute and volume control register */ |
122 | #define AIC31XX_DACMUTE 0x40 | 124 | #define AIC31XX_DACMUTE AIC31XX_REG(0, 64) |
123 | /* Left DAC channel digital volume control */ | 125 | /* Left DAC channel digital volume control */ |
124 | #define AIC31XX_LDACVOL 0x41 | 126 | #define AIC31XX_LDACVOL AIC31XX_REG(0, 65) |
125 | /* Right DAC channel digital volume control */ | 127 | /* Right DAC channel digital volume control */ |
126 | #define AIC31XX_RDACVOL 0x42 | 128 | #define AIC31XX_RDACVOL AIC31XX_REG(0, 66) |
127 | /* Headset detection */ | 129 | /* Headset detection */ |
128 | #define AIC31XX_HSDETECT 0x43 | 130 | #define AIC31XX_HSDETECT AIC31XX_REG(0, 67) |
129 | /* ADC Digital Mic */ | 131 | /* ADC Digital Mic */ |
130 | #define AIC31XX_ADCSETUP 0x51 | 132 | #define AIC31XX_ADCSETUP AIC31XX_REG(0, 81) |
131 | /* ADC Digital Volume Control Fine Adjust */ | 133 | /* ADC Digital Volume Control Fine Adjust */ |
132 | #define AIC31XX_ADCFGA 0x52 | 134 | #define AIC31XX_ADCFGA AIC31XX_REG(0, 82) |
133 | /* ADC Digital Volume Control Coarse Adjust */ | 135 | /* ADC Digital Volume Control Coarse Adjust */ |
134 | #define AIC31XX_ADCVOL 0x53 | 136 | #define AIC31XX_ADCVOL AIC31XX_REG(0, 83) |
135 | 137 | ||
136 | 138 | ||
137 | /* Page 1 Registers */ | 139 | /* Page 1 Registers */ |
138 | /* Headphone drivers */ | 140 | /* Headphone drivers */ |
139 | #define AIC31XX_HPDRIVER 0x9F | 141 | #define AIC31XX_HPDRIVER AIC31XX_REG(1, 31) |
140 | /* Class-D Speakear Amplifier */ | 142 | /* Class-D Speakear Amplifier */ |
141 | #define AIC31XX_SPKAMP 0xA0 | 143 | #define AIC31XX_SPKAMP AIC31XX_REG(1, 32) |
142 | /* HP Output Drivers POP Removal Settings */ | 144 | /* HP Output Drivers POP Removal Settings */ |
143 | #define AIC31XX_HPPOP 0xA1 | 145 | #define AIC31XX_HPPOP AIC31XX_REG(1, 33) |
144 | /* Output Driver PGA Ramp-Down Period Control */ | 146 | /* Output Driver PGA Ramp-Down Period Control */ |
145 | #define AIC31XX_SPPGARAMP 0xA2 | 147 | #define AIC31XX_SPPGARAMP AIC31XX_REG(1, 34) |
146 | /* DAC_L and DAC_R Output Mixer Routing */ | 148 | /* DAC_L and DAC_R Output Mixer Routing */ |
147 | #define AIC31XX_DACMIXERROUTE 0xA3 | 149 | #define AIC31XX_DACMIXERROUTE AIC31XX_REG(1, 35) |
148 | /* Left Analog Vol to HPL */ | 150 | /* Left Analog Vol to HPL */ |
149 | #define AIC31XX_LANALOGHPL 0xA4 | 151 | #define AIC31XX_LANALOGHPL AIC31XX_REG(1, 36) |
150 | /* Right Analog Vol to HPR */ | 152 | /* Right Analog Vol to HPR */ |
151 | #define AIC31XX_RANALOGHPR 0xA5 | 153 | #define AIC31XX_RANALOGHPR AIC31XX_REG(1, 37) |
152 | /* Left Analog Vol to SPL */ | 154 | /* Left Analog Vol to SPL */ |
153 | #define AIC31XX_LANALOGSPL 0xA6 | 155 | #define AIC31XX_LANALOGSPL AIC31XX_REG(1, 38) |
154 | /* Right Analog Vol to SPR */ | 156 | /* Right Analog Vol to SPR */ |
155 | #define AIC31XX_RANALOGSPR 0xA7 | 157 | #define AIC31XX_RANALOGSPR AIC31XX_REG(1, 39) |
156 | /* HPL Driver */ | 158 | /* HPL Driver */ |
157 | #define AIC31XX_HPLGAIN 0xA8 | 159 | #define AIC31XX_HPLGAIN AIC31XX_REG(1, 40) |
158 | /* HPR Driver */ | 160 | /* HPR Driver */ |
159 | #define AIC31XX_HPRGAIN 0xA9 | 161 | #define AIC31XX_HPRGAIN AIC31XX_REG(1, 41) |
160 | /* SPL Driver */ | 162 | /* SPL Driver */ |
161 | #define AIC31XX_SPLGAIN 0xAA | 163 | #define AIC31XX_SPLGAIN AIC31XX_REG(1, 42) |
162 | /* SPR Driver */ | 164 | /* SPR Driver */ |
163 | #define AIC31XX_SPRGAIN 0xAB | 165 | #define AIC31XX_SPRGAIN AIC31XX_REG(1, 43) |
164 | /* HP Driver Control */ | 166 | /* HP Driver Control */ |
165 | #define AIC31XX_HPCONTROL 0xAC | 167 | #define AIC31XX_HPCONTROL AIC31XX_REG(1, 44) |
166 | /* MIC Bias Control */ | 168 | /* MIC Bias Control */ |
167 | #define AIC31XX_MICBIAS 0xAE | 169 | #define AIC31XX_MICBIAS AIC31XX_REG(1, 46) |
168 | /* MIC PGA*/ | 170 | /* MIC PGA*/ |
169 | #define AIC31XX_MICPGA 0xAF | 171 | #define AIC31XX_MICPGA AIC31XX_REG(1, 47) |
170 | /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */ | 172 | /* Delta-Sigma Mono ADC Channel Fine-Gain Input Selection for P-Terminal */ |
171 | #define AIC31XX_MICPGAPI 0xB0 | 173 | #define AIC31XX_MICPGAPI AIC31XX_REG(1, 48) |
172 | /* ADC Input Selection for M-Terminal */ | 174 | /* ADC Input Selection for M-Terminal */ |
173 | #define AIC31XX_MICPGAMI 0xB1 | 175 | #define AIC31XX_MICPGAMI AIC31XX_REG(1, 49) |
174 | /* Input CM Settings */ | 176 | /* Input CM Settings */ |
175 | #define AIC31XX_MICPGACM 0xB2 | 177 | #define AIC31XX_MICPGACM AIC31XX_REG(1, 50) |
176 | 178 | ||
177 | /* Bits, masks and shifts */ | 179 | /* Bits, masks and shifts */ |
178 | 180 | ||
diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 11d85c5c787a..f1ea052a822e 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <sound/tlv.h> | 32 | #include <sound/tlv.h> |
33 | #include <linux/of.h> | 33 | #include <linux/of.h> |
34 | #include <linux/of_gpio.h> | 34 | #include <linux/of_gpio.h> |
35 | #include <linux/regmap.h> | ||
35 | 36 | ||
36 | #include "tpa6130a2.h" | 37 | #include "tpa6130a2.h" |
37 | 38 | ||
@@ -40,219 +41,72 @@ enum tpa_model { | |||
40 | TPA6140A2, | 41 | TPA6140A2, |
41 | }; | 42 | }; |
42 | 43 | ||
43 | static struct i2c_client *tpa6130a2_client; | ||
44 | |||
45 | /* This struct is used to save the context */ | 44 | /* This struct is used to save the context */ |
46 | struct tpa6130a2_data { | 45 | struct tpa6130a2_data { |
47 | struct mutex mutex; | 46 | struct device *dev; |
48 | unsigned char regs[TPA6130A2_CACHEREGNUM]; | 47 | struct regmap *regmap; |
49 | struct regulator *supply; | 48 | struct regulator *supply; |
50 | int power_gpio; | 49 | int power_gpio; |
51 | u8 power_state:1; | ||
52 | enum tpa_model id; | 50 | enum tpa_model id; |
53 | }; | 51 | }; |
54 | 52 | ||
55 | static int tpa6130a2_i2c_read(int reg) | 53 | static int tpa6130a2_power(struct tpa6130a2_data *data, bool enable) |
56 | { | ||
57 | struct tpa6130a2_data *data; | ||
58 | int val; | ||
59 | |||
60 | if (WARN_ON(!tpa6130a2_client)) | ||
61 | return -EINVAL; | ||
62 | data = i2c_get_clientdata(tpa6130a2_client); | ||
63 | |||
64 | /* If powered off, return the cached value */ | ||
65 | if (data->power_state) { | ||
66 | val = i2c_smbus_read_byte_data(tpa6130a2_client, reg); | ||
67 | if (val < 0) | ||
68 | dev_err(&tpa6130a2_client->dev, "Read failed\n"); | ||
69 | else | ||
70 | data->regs[reg] = val; | ||
71 | } else { | ||
72 | val = data->regs[reg]; | ||
73 | } | ||
74 | |||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static int tpa6130a2_i2c_write(int reg, u8 value) | ||
79 | { | ||
80 | struct tpa6130a2_data *data; | ||
81 | int val = 0; | ||
82 | |||
83 | if (WARN_ON(!tpa6130a2_client)) | ||
84 | return -EINVAL; | ||
85 | data = i2c_get_clientdata(tpa6130a2_client); | ||
86 | |||
87 | if (data->power_state) { | ||
88 | val = i2c_smbus_write_byte_data(tpa6130a2_client, reg, value); | ||
89 | if (val < 0) { | ||
90 | dev_err(&tpa6130a2_client->dev, "Write failed\n"); | ||
91 | return val; | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* Either powered on or off, we save the context */ | ||
96 | data->regs[reg] = value; | ||
97 | |||
98 | return val; | ||
99 | } | ||
100 | |||
101 | static u8 tpa6130a2_read(int reg) | ||
102 | { | ||
103 | struct tpa6130a2_data *data; | ||
104 | |||
105 | if (WARN_ON(!tpa6130a2_client)) | ||
106 | return 0; | ||
107 | data = i2c_get_clientdata(tpa6130a2_client); | ||
108 | |||
109 | return data->regs[reg]; | ||
110 | } | ||
111 | |||
112 | static int tpa6130a2_initialize(void) | ||
113 | { | ||
114 | struct tpa6130a2_data *data; | ||
115 | int i, ret = 0; | ||
116 | |||
117 | if (WARN_ON(!tpa6130a2_client)) | ||
118 | return -EINVAL; | ||
119 | data = i2c_get_clientdata(tpa6130a2_client); | ||
120 | |||
121 | for (i = 1; i < TPA6130A2_REG_VERSION; i++) { | ||
122 | ret = tpa6130a2_i2c_write(i, data->regs[i]); | ||
123 | if (ret < 0) | ||
124 | break; | ||
125 | } | ||
126 | |||
127 | return ret; | ||
128 | } | ||
129 | |||
130 | static int tpa6130a2_power(u8 power) | ||
131 | { | 54 | { |
132 | struct tpa6130a2_data *data; | 55 | int ret; |
133 | u8 val; | ||
134 | int ret = 0; | ||
135 | |||
136 | if (WARN_ON(!tpa6130a2_client)) | ||
137 | return -EINVAL; | ||
138 | data = i2c_get_clientdata(tpa6130a2_client); | ||
139 | |||
140 | mutex_lock(&data->mutex); | ||
141 | if (power == data->power_state) | ||
142 | goto exit; | ||
143 | 56 | ||
144 | if (power) { | 57 | if (enable) { |
145 | ret = regulator_enable(data->supply); | 58 | ret = regulator_enable(data->supply); |
146 | if (ret != 0) { | 59 | if (ret != 0) { |
147 | dev_err(&tpa6130a2_client->dev, | 60 | dev_err(data->dev, |
148 | "Failed to enable supply: %d\n", ret); | 61 | "Failed to enable supply: %d\n", ret); |
149 | goto exit; | 62 | return ret; |
150 | } | 63 | } |
151 | /* Power on */ | 64 | /* Power on */ |
152 | if (data->power_gpio >= 0) | 65 | if (data->power_gpio >= 0) |
153 | gpio_set_value(data->power_gpio, 1); | 66 | gpio_set_value(data->power_gpio, 1); |
154 | |||
155 | data->power_state = 1; | ||
156 | ret = tpa6130a2_initialize(); | ||
157 | if (ret < 0) { | ||
158 | dev_err(&tpa6130a2_client->dev, | ||
159 | "Failed to initialize chip\n"); | ||
160 | if (data->power_gpio >= 0) | ||
161 | gpio_set_value(data->power_gpio, 0); | ||
162 | regulator_disable(data->supply); | ||
163 | data->power_state = 0; | ||
164 | goto exit; | ||
165 | } | ||
166 | } else { | 67 | } else { |
167 | /* set SWS */ | ||
168 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | ||
169 | val |= TPA6130A2_SWS; | ||
170 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); | ||
171 | |||
172 | /* Power off */ | 68 | /* Power off */ |
173 | if (data->power_gpio >= 0) | 69 | if (data->power_gpio >= 0) |
174 | gpio_set_value(data->power_gpio, 0); | 70 | gpio_set_value(data->power_gpio, 0); |
175 | 71 | ||
176 | ret = regulator_disable(data->supply); | 72 | ret = regulator_disable(data->supply); |
177 | if (ret != 0) { | 73 | if (ret != 0) { |
178 | dev_err(&tpa6130a2_client->dev, | 74 | dev_err(data->dev, |
179 | "Failed to disable supply: %d\n", ret); | 75 | "Failed to disable supply: %d\n", ret); |
180 | goto exit; | 76 | return ret; |
181 | } | 77 | } |
182 | 78 | ||
183 | data->power_state = 0; | 79 | /* device regs does not match the cache state anymore */ |
80 | regcache_mark_dirty(data->regmap); | ||
184 | } | 81 | } |
185 | 82 | ||
186 | exit: | ||
187 | mutex_unlock(&data->mutex); | ||
188 | return ret; | 83 | return ret; |
189 | } | 84 | } |
190 | 85 | ||
191 | static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol, | 86 | static int tpa6130a2_power_event(struct snd_soc_dapm_widget *w, |
192 | struct snd_ctl_elem_value *ucontrol) | 87 | struct snd_kcontrol *kctrl, int event) |
193 | { | 88 | { |
194 | struct soc_mixer_control *mc = | 89 | struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm); |
195 | (struct soc_mixer_control *)kcontrol->private_value; | 90 | struct tpa6130a2_data *data = snd_soc_component_get_drvdata(c); |
196 | struct tpa6130a2_data *data; | 91 | int ret; |
197 | unsigned int reg = mc->reg; | ||
198 | unsigned int shift = mc->shift; | ||
199 | int max = mc->max; | ||
200 | unsigned int mask = (1 << fls(max)) - 1; | ||
201 | unsigned int invert = mc->invert; | ||
202 | |||
203 | if (WARN_ON(!tpa6130a2_client)) | ||
204 | return -EINVAL; | ||
205 | data = i2c_get_clientdata(tpa6130a2_client); | ||
206 | |||
207 | mutex_lock(&data->mutex); | ||
208 | |||
209 | ucontrol->value.integer.value[0] = | ||
210 | (tpa6130a2_read(reg) >> shift) & mask; | ||
211 | |||
212 | if (invert) | ||
213 | ucontrol->value.integer.value[0] = | ||
214 | max - ucontrol->value.integer.value[0]; | ||
215 | |||
216 | mutex_unlock(&data->mutex); | ||
217 | return 0; | ||
218 | } | ||
219 | 92 | ||
220 | static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol, | 93 | /* before widget power up */ |
221 | struct snd_ctl_elem_value *ucontrol) | 94 | if (SND_SOC_DAPM_EVENT_ON(event)) { |
222 | { | 95 | /* Turn on the chip */ |
223 | struct soc_mixer_control *mc = | 96 | tpa6130a2_power(data, true); |
224 | (struct soc_mixer_control *)kcontrol->private_value; | 97 | /* Sync the registers */ |
225 | struct tpa6130a2_data *data; | 98 | ret = regcache_sync(data->regmap); |
226 | unsigned int reg = mc->reg; | 99 | if (ret < 0) { |
227 | unsigned int shift = mc->shift; | 100 | dev_err(c->dev, "Failed to initialize chip\n"); |
228 | int max = mc->max; | 101 | tpa6130a2_power(data, false); |
229 | unsigned int mask = (1 << fls(max)) - 1; | 102 | return ret; |
230 | unsigned int invert = mc->invert; | 103 | } |
231 | unsigned int val = (ucontrol->value.integer.value[0] & mask); | 104 | /* after widget power down */ |
232 | unsigned int val_reg; | 105 | } else { |
233 | 106 | tpa6130a2_power(data, false); | |
234 | if (WARN_ON(!tpa6130a2_client)) | ||
235 | return -EINVAL; | ||
236 | data = i2c_get_clientdata(tpa6130a2_client); | ||
237 | |||
238 | if (invert) | ||
239 | val = max - val; | ||
240 | |||
241 | mutex_lock(&data->mutex); | ||
242 | |||
243 | val_reg = tpa6130a2_read(reg); | ||
244 | if (((val_reg >> shift) & mask) == val) { | ||
245 | mutex_unlock(&data->mutex); | ||
246 | return 0; | ||
247 | } | 107 | } |
248 | 108 | ||
249 | val_reg &= ~(mask << shift); | 109 | return 0; |
250 | val_reg |= val << shift; | ||
251 | tpa6130a2_i2c_write(reg, val_reg); | ||
252 | |||
253 | mutex_unlock(&data->mutex); | ||
254 | |||
255 | return 1; | ||
256 | } | 110 | } |
257 | 111 | ||
258 | /* | 112 | /* |
@@ -273,9 +127,8 @@ static const DECLARE_TLV_DB_RANGE(tpa6130_tlv, | |||
273 | ); | 127 | ); |
274 | 128 | ||
275 | static const struct snd_kcontrol_new tpa6130a2_controls[] = { | 129 | static const struct snd_kcontrol_new tpa6130a2_controls[] = { |
276 | SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume", | 130 | SOC_SINGLE_TLV("Headphone Playback Volume", |
277 | TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, | 131 | TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0, |
278 | tpa6130a2_get_volsw, tpa6130a2_put_volsw, | ||
279 | tpa6130_tlv), | 132 | tpa6130_tlv), |
280 | }; | 133 | }; |
281 | 134 | ||
@@ -286,85 +139,79 @@ static const DECLARE_TLV_DB_RANGE(tpa6140_tlv, | |||
286 | ); | 139 | ); |
287 | 140 | ||
288 | static const struct snd_kcontrol_new tpa6140a2_controls[] = { | 141 | static const struct snd_kcontrol_new tpa6140a2_controls[] = { |
289 | SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume", | 142 | SOC_SINGLE_TLV("Headphone Playback Volume", |
290 | TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, | 143 | TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0, |
291 | tpa6130a2_get_volsw, tpa6130a2_put_volsw, | ||
292 | tpa6140_tlv), | 144 | tpa6140_tlv), |
293 | }; | 145 | }; |
294 | 146 | ||
295 | /* | 147 | static int tpa6130a2_component_probe(struct snd_soc_component *component) |
296 | * Enable or disable channel (left or right) | ||
297 | * The bit number for mute and amplifier are the same per channel: | ||
298 | * bit 6: Right channel | ||
299 | * bit 7: Left channel | ||
300 | * in both registers. | ||
301 | */ | ||
302 | static void tpa6130a2_channel_enable(u8 channel, int enable) | ||
303 | { | 148 | { |
304 | u8 val; | 149 | struct tpa6130a2_data *data = snd_soc_component_get_drvdata(component); |
305 | 150 | ||
306 | if (enable) { | 151 | if (data->id == TPA6140A2) |
307 | /* Enable channel */ | 152 | return snd_soc_add_component_controls(component, |
308 | /* Enable amplifier */ | 153 | tpa6140a2_controls, ARRAY_SIZE(tpa6140a2_controls)); |
309 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | 154 | else |
310 | val |= channel; | 155 | return snd_soc_add_component_controls(component, |
311 | val &= ~TPA6130A2_SWS; | 156 | tpa6130a2_controls, ARRAY_SIZE(tpa6130a2_controls)); |
312 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); | ||
313 | |||
314 | /* Unmute channel */ | ||
315 | val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE); | ||
316 | val &= ~channel; | ||
317 | tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val); | ||
318 | } else { | ||
319 | /* Disable channel */ | ||
320 | /* Mute channel */ | ||
321 | val = tpa6130a2_read(TPA6130A2_REG_VOL_MUTE); | ||
322 | val |= channel; | ||
323 | tpa6130a2_i2c_write(TPA6130A2_REG_VOL_MUTE, val); | ||
324 | |||
325 | /* Disable amplifier */ | ||
326 | val = tpa6130a2_read(TPA6130A2_REG_CONTROL); | ||
327 | val &= ~channel; | ||
328 | tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val); | ||
329 | } | ||
330 | } | 157 | } |
331 | 158 | ||
332 | int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable) | 159 | static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = { |
333 | { | 160 | SND_SOC_DAPM_INPUT("LEFTIN"), |
334 | int ret = 0; | 161 | SND_SOC_DAPM_INPUT("RIGHTIN"), |
335 | if (enable) { | 162 | SND_SOC_DAPM_OUTPUT("HPLEFT"), |
336 | ret = tpa6130a2_power(1); | 163 | SND_SOC_DAPM_OUTPUT("HPRIGHT"), |
337 | if (ret < 0) | 164 | |
338 | return ret; | 165 | SND_SOC_DAPM_PGA("Left Mute", TPA6130A2_REG_VOL_MUTE, |
339 | tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, | 166 | TPA6130A2_HP_EN_L_SHIFT, 1, NULL, 0), |
340 | 1); | 167 | SND_SOC_DAPM_PGA("Right Mute", TPA6130A2_REG_VOL_MUTE, |
341 | } else { | 168 | TPA6130A2_HP_EN_R_SHIFT, 1, NULL, 0), |
342 | tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L, | 169 | SND_SOC_DAPM_PGA("Left PGA", TPA6130A2_REG_CONTROL, |
343 | 0); | 170 | TPA6130A2_HP_EN_L_SHIFT, 0, NULL, 0), |
344 | ret = tpa6130a2_power(0); | 171 | SND_SOC_DAPM_PGA("Right PGA", TPA6130A2_REG_CONTROL, |
345 | } | 172 | TPA6130A2_HP_EN_R_SHIFT, 0, NULL, 0), |
173 | |||
174 | SND_SOC_DAPM_SUPPLY("Power", TPA6130A2_REG_CONTROL, | ||
175 | TPA6130A2_SWS_SHIFT, 1, tpa6130a2_power_event, | ||
176 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
177 | }; | ||
346 | 178 | ||
347 | return ret; | 179 | static const struct snd_soc_dapm_route tpa6130a2_dapm_routes[] = { |
348 | } | 180 | { "Left PGA", NULL, "LEFTIN" }, |
349 | EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable); | 181 | { "Right PGA", NULL, "RIGHTIN" }, |
350 | 182 | ||
351 | int tpa6130a2_add_controls(struct snd_soc_codec *codec) | 183 | { "Left Mute", NULL, "Left PGA" }, |
352 | { | 184 | { "Right Mute", NULL, "Right PGA" }, |
353 | struct tpa6130a2_data *data; | ||
354 | 185 | ||
355 | if (tpa6130a2_client == NULL) | 186 | { "HPLEFT", NULL, "Left Mute" }, |
356 | return -ENODEV; | 187 | { "HPRIGHT", NULL, "Right Mute" }, |
357 | 188 | ||
358 | data = i2c_get_clientdata(tpa6130a2_client); | 189 | { "Left PGA", NULL, "Power" }, |
190 | { "Right PGA", NULL, "Power" }, | ||
191 | }; | ||
359 | 192 | ||
360 | if (data->id == TPA6140A2) | 193 | struct snd_soc_component_driver tpa6130a2_component_driver = { |
361 | return snd_soc_add_codec_controls(codec, tpa6140a2_controls, | 194 | .name = "tpa6130a2", |
362 | ARRAY_SIZE(tpa6140a2_controls)); | 195 | .probe = tpa6130a2_component_probe, |
363 | else | 196 | .dapm_widgets = tpa6130a2_dapm_widgets, |
364 | return snd_soc_add_codec_controls(codec, tpa6130a2_controls, | 197 | .num_dapm_widgets = ARRAY_SIZE(tpa6130a2_dapm_widgets), |
365 | ARRAY_SIZE(tpa6130a2_controls)); | 198 | .dapm_routes = tpa6130a2_dapm_routes, |
366 | } | 199 | .num_dapm_routes = ARRAY_SIZE(tpa6130a2_dapm_routes), |
367 | EXPORT_SYMBOL_GPL(tpa6130a2_add_controls); | 200 | }; |
201 | |||
202 | static const struct reg_default tpa6130a2_reg_defaults[] = { | ||
203 | { TPA6130A2_REG_CONTROL, TPA6130A2_SWS }, | ||
204 | { TPA6130A2_REG_VOL_MUTE, TPA6130A2_MUTE_R | TPA6130A2_MUTE_L }, | ||
205 | }; | ||
206 | |||
207 | static const struct regmap_config tpa6130a2_regmap_config = { | ||
208 | .reg_bits = 8, | ||
209 | .val_bits = 8, | ||
210 | .max_register = TPA6130A2_REG_VERSION, | ||
211 | .reg_defaults = tpa6130a2_reg_defaults, | ||
212 | .num_reg_defaults = ARRAY_SIZE(tpa6130a2_reg_defaults), | ||
213 | .cache_type = REGCACHE_RBTREE, | ||
214 | }; | ||
368 | 215 | ||
369 | static int tpa6130a2_probe(struct i2c_client *client, | 216 | static int tpa6130a2_probe(struct i2c_client *client, |
370 | const struct i2c_device_id *id) | 217 | const struct i2c_device_id *id) |
@@ -374,6 +221,7 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
374 | struct tpa6130a2_platform_data *pdata = client->dev.platform_data; | 221 | struct tpa6130a2_platform_data *pdata = client->dev.platform_data; |
375 | struct device_node *np = client->dev.of_node; | 222 | struct device_node *np = client->dev.of_node; |
376 | const char *regulator; | 223 | const char *regulator; |
224 | unsigned int version; | ||
377 | int ret; | 225 | int ret; |
378 | 226 | ||
379 | dev = &client->dev; | 227 | dev = &client->dev; |
@@ -382,6 +230,12 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
382 | if (!data) | 230 | if (!data) |
383 | return -ENOMEM; | 231 | return -ENOMEM; |
384 | 232 | ||
233 | data->dev = dev; | ||
234 | |||
235 | data->regmap = devm_regmap_init_i2c(client, &tpa6130a2_regmap_config); | ||
236 | if (IS_ERR(data->regmap)) | ||
237 | return PTR_ERR(data->regmap); | ||
238 | |||
385 | if (pdata) { | 239 | if (pdata) { |
386 | data->power_gpio = pdata->power_gpio; | 240 | data->power_gpio = pdata->power_gpio; |
387 | } else if (np) { | 241 | } else if (np) { |
@@ -392,26 +246,17 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
392 | return -ENODEV; | 246 | return -ENODEV; |
393 | } | 247 | } |
394 | 248 | ||
395 | tpa6130a2_client = client; | 249 | i2c_set_clientdata(client, data); |
396 | |||
397 | i2c_set_clientdata(tpa6130a2_client, data); | ||
398 | 250 | ||
399 | data->id = id->driver_data; | 251 | data->id = id->driver_data; |
400 | 252 | ||
401 | mutex_init(&data->mutex); | ||
402 | |||
403 | /* Set default register values */ | ||
404 | data->regs[TPA6130A2_REG_CONTROL] = TPA6130A2_SWS; | ||
405 | data->regs[TPA6130A2_REG_VOL_MUTE] = TPA6130A2_MUTE_R | | ||
406 | TPA6130A2_MUTE_L; | ||
407 | |||
408 | if (data->power_gpio >= 0) { | 253 | if (data->power_gpio >= 0) { |
409 | ret = devm_gpio_request(dev, data->power_gpio, | 254 | ret = devm_gpio_request(dev, data->power_gpio, |
410 | "tpa6130a2 enable"); | 255 | "tpa6130a2 enable"); |
411 | if (ret < 0) { | 256 | if (ret < 0) { |
412 | dev_err(dev, "Failed to request power GPIO (%d)\n", | 257 | dev_err(dev, "Failed to request power GPIO (%d)\n", |
413 | data->power_gpio); | 258 | data->power_gpio); |
414 | goto err_gpio; | 259 | return ret; |
415 | } | 260 | } |
416 | gpio_direction_output(data->power_gpio, 0); | 261 | gpio_direction_output(data->power_gpio, 0); |
417 | } | 262 | } |
@@ -432,39 +277,27 @@ static int tpa6130a2_probe(struct i2c_client *client, | |||
432 | if (IS_ERR(data->supply)) { | 277 | if (IS_ERR(data->supply)) { |
433 | ret = PTR_ERR(data->supply); | 278 | ret = PTR_ERR(data->supply); |
434 | dev_err(dev, "Failed to request supply: %d\n", ret); | 279 | dev_err(dev, "Failed to request supply: %d\n", ret); |
435 | goto err_gpio; | 280 | return ret; |
436 | } | 281 | } |
437 | 282 | ||
438 | ret = tpa6130a2_power(1); | 283 | ret = tpa6130a2_power(data, true); |
439 | if (ret != 0) | 284 | if (ret != 0) |
440 | goto err_gpio; | 285 | return ret; |
441 | 286 | ||
442 | 287 | ||
443 | /* Read version */ | 288 | /* Read version */ |
444 | ret = tpa6130a2_i2c_read(TPA6130A2_REG_VERSION) & | 289 | regmap_read(data->regmap, TPA6130A2_REG_VERSION, &version); |
445 | TPA6130A2_VERSION_MASK; | 290 | version &= TPA6130A2_VERSION_MASK; |
446 | if ((ret != 1) && (ret != 2)) | 291 | if ((version != 1) && (version != 2)) |
447 | dev_warn(dev, "UNTESTED version detected (%d)\n", ret); | 292 | dev_warn(dev, "UNTESTED version detected (%d)\n", version); |
448 | 293 | ||
449 | /* Disable the chip */ | 294 | /* Disable the chip */ |
450 | ret = tpa6130a2_power(0); | 295 | ret = tpa6130a2_power(data, false); |
451 | if (ret != 0) | 296 | if (ret != 0) |
452 | goto err_gpio; | 297 | return ret; |
453 | |||
454 | return 0; | ||
455 | |||
456 | err_gpio: | ||
457 | tpa6130a2_client = NULL; | ||
458 | 298 | ||
459 | return ret; | 299 | return devm_snd_soc_register_component(&client->dev, |
460 | } | 300 | &tpa6130a2_component_driver, NULL, 0); |
461 | |||
462 | static int tpa6130a2_remove(struct i2c_client *client) | ||
463 | { | ||
464 | tpa6130a2_power(0); | ||
465 | tpa6130a2_client = NULL; | ||
466 | |||
467 | return 0; | ||
468 | } | 301 | } |
469 | 302 | ||
470 | static const struct i2c_device_id tpa6130a2_id[] = { | 303 | static const struct i2c_device_id tpa6130a2_id[] = { |
@@ -489,7 +322,6 @@ static struct i2c_driver tpa6130a2_i2c_driver = { | |||
489 | .of_match_table = of_match_ptr(tpa6130a2_of_match), | 322 | .of_match_table = of_match_ptr(tpa6130a2_of_match), |
490 | }, | 323 | }, |
491 | .probe = tpa6130a2_probe, | 324 | .probe = tpa6130a2_probe, |
492 | .remove = tpa6130a2_remove, | ||
493 | .id_table = tpa6130a2_id, | 325 | .id_table = tpa6130a2_id, |
494 | }; | 326 | }; |
495 | 327 | ||
diff --git a/sound/soc/codecs/tpa6130a2.h b/sound/soc/codecs/tpa6130a2.h index 417444020ba6..f19cad5d4172 100644 --- a/sound/soc/codecs/tpa6130a2.h +++ b/sound/soc/codecs/tpa6130a2.h | |||
@@ -30,19 +30,20 @@ | |||
30 | #define TPA6130A2_REG_OUT_IMPEDANCE 0x03 | 30 | #define TPA6130A2_REG_OUT_IMPEDANCE 0x03 |
31 | #define TPA6130A2_REG_VERSION 0x04 | 31 | #define TPA6130A2_REG_VERSION 0x04 |
32 | 32 | ||
33 | #define TPA6130A2_CACHEREGNUM (TPA6130A2_REG_VERSION + 1) | ||
34 | |||
35 | /* Register bits */ | 33 | /* Register bits */ |
36 | /* TPA6130A2_REG_CONTROL (0x01) */ | 34 | /* TPA6130A2_REG_CONTROL (0x01) */ |
37 | #define TPA6130A2_SWS (0x01 << 0) | 35 | #define TPA6130A2_SWS_SHIFT 0 |
36 | #define TPA6130A2_SWS (0x01 << TPA6130A2_SWS_SHIFT) | ||
38 | #define TPA6130A2_TERMAL (0x01 << 1) | 37 | #define TPA6130A2_TERMAL (0x01 << 1) |
39 | #define TPA6130A2_MODE(x) (x << 4) | 38 | #define TPA6130A2_MODE(x) (x << 4) |
40 | #define TPA6130A2_MODE_STEREO (0x00) | 39 | #define TPA6130A2_MODE_STEREO (0x00) |
41 | #define TPA6130A2_MODE_DUAL_MONO (0x01) | 40 | #define TPA6130A2_MODE_DUAL_MONO (0x01) |
42 | #define TPA6130A2_MODE_BRIDGE (0x02) | 41 | #define TPA6130A2_MODE_BRIDGE (0x02) |
43 | #define TPA6130A2_MODE_MASK (0x03) | 42 | #define TPA6130A2_MODE_MASK (0x03) |
44 | #define TPA6130A2_HP_EN_R (0x01 << 6) | 43 | #define TPA6130A2_HP_EN_R_SHIFT 6 |
45 | #define TPA6130A2_HP_EN_L (0x01 << 7) | 44 | #define TPA6130A2_HP_EN_R (0x01 << TPA6130A2_HP_EN_R_SHIFT) |
45 | #define TPA6130A2_HP_EN_L_SHIFT 7 | ||
46 | #define TPA6130A2_HP_EN_L (0x01 << TPA6130A2_HP_EN_L_SHIFT) | ||
46 | 47 | ||
47 | /* TPA6130A2_REG_VOL_MUTE (0x02) */ | 48 | /* TPA6130A2_REG_VOL_MUTE (0x02) */ |
48 | #define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0) | 49 | #define TPA6130A2_VOLUME(x) ((x & 0x3f) << 0) |
@@ -56,7 +57,4 @@ | |||
56 | /* TPA6130A2_REG_VERSION (0x04) */ | 57 | /* TPA6130A2_REG_VERSION (0x04) */ |
57 | #define TPA6130A2_VERSION_MASK (0x0f) | 58 | #define TPA6130A2_VERSION_MASK (0x0f) |
58 | 59 | ||
59 | extern int tpa6130a2_add_controls(struct snd_soc_codec *codec); | ||
60 | extern int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable); | ||
61 | |||
62 | #endif /* __TPA6130A2_H__ */ | 60 | #endif /* __TPA6130A2_H__ */ |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index e7fe6b7b95b7..846deed6af41 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -1713,6 +1713,7 @@ static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | |||
1713 | 1713 | ||
1714 | { "MICSUPP", NULL, "SYSCLK" }, | 1714 | { "MICSUPP", NULL, "SYSCLK" }, |
1715 | 1715 | ||
1716 | { "DRC1 Signal Activity", NULL, "SYSCLK" }, | ||
1716 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | 1717 | { "DRC1 Signal Activity", NULL, "DRC1L" }, |
1717 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | 1718 | { "DRC1 Signal Activity", NULL, "DRC1R" }, |
1718 | }; | 1719 | }; |
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index d54f1b46c9ec..156547026a40 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -1104,6 +1104,11 @@ SND_SOC_DAPM_INPUT("IN4R"), | |||
1104 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), | 1104 | SND_SOC_DAPM_OUTPUT("DRC1 Signal Activity"), |
1105 | SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), | 1105 | SND_SOC_DAPM_OUTPUT("DRC2 Signal Activity"), |
1106 | 1106 | ||
1107 | SND_SOC_DAPM_OUTPUT("DSP Voice Trigger"), | ||
1108 | |||
1109 | SND_SOC_DAPM_SWITCH("DSP3 Voice Trigger", SND_SOC_NOPM, 2, 0, | ||
1110 | &arizona_voice_trigger_switch[2]), | ||
1111 | |||
1107 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | 1112 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, |
1108 | 0, NULL, 0, wm5110_in_ev, | 1113 | 0, NULL, 0, wm5110_in_ev, |
1109 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | | 1114 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | |
@@ -1998,10 +2003,16 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { | |||
1998 | 2003 | ||
1999 | { "MICSUPP", NULL, "SYSCLK" }, | 2004 | { "MICSUPP", NULL, "SYSCLK" }, |
2000 | 2005 | ||
2006 | { "DRC1 Signal Activity", NULL, "SYSCLK" }, | ||
2007 | { "DRC2 Signal Activity", NULL, "SYSCLK" }, | ||
2001 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | 2008 | { "DRC1 Signal Activity", NULL, "DRC1L" }, |
2002 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | 2009 | { "DRC1 Signal Activity", NULL, "DRC1R" }, |
2003 | { "DRC2 Signal Activity", NULL, "DRC2L" }, | 2010 | { "DRC2 Signal Activity", NULL, "DRC2L" }, |
2004 | { "DRC2 Signal Activity", NULL, "DRC2R" }, | 2011 | { "DRC2 Signal Activity", NULL, "DRC2R" }, |
2012 | |||
2013 | { "DSP Voice Trigger", NULL, "SYSCLK" }, | ||
2014 | { "DSP Voice Trigger", NULL, "DSP3 Voice Trigger" }, | ||
2015 | { "DSP3 Voice Trigger", "Switch", "DSP3" }, | ||
2005 | }; | 2016 | }; |
2006 | 2017 | ||
2007 | static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | 2018 | static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, |
@@ -2223,6 +2234,7 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) | |||
2223 | { | 2234 | { |
2224 | struct wm5110_priv *priv = data; | 2235 | struct wm5110_priv *priv = data; |
2225 | struct arizona *arizona = priv->core.arizona; | 2236 | struct arizona *arizona = priv->core.arizona; |
2237 | struct arizona_voice_trigger_info info; | ||
2226 | int serviced = 0; | 2238 | int serviced = 0; |
2227 | int i, ret; | 2239 | int i, ret; |
2228 | 2240 | ||
@@ -2230,6 +2242,12 @@ static irqreturn_t wm5110_adsp2_irq(int irq, void *data) | |||
2230 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); | 2242 | ret = wm_adsp_compr_handle_irq(&priv->core.adsp[i]); |
2231 | if (ret != -ENODEV) | 2243 | if (ret != -ENODEV) |
2232 | serviced++; | 2244 | serviced++; |
2245 | if (ret == WM_ADSP_COMPR_VOICE_TRIGGER) { | ||
2246 | info.core = i; | ||
2247 | arizona_call_notifiers(arizona, | ||
2248 | ARIZONA_NOTIFY_VOICE_TRIGGER, | ||
2249 | &info); | ||
2250 | } | ||
2233 | } | 2251 | } |
2234 | 2252 | ||
2235 | if (!serviced) { | 2253 | if (!serviced) { |
@@ -2252,6 +2270,7 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) | |||
2252 | arizona_init_spk(codec); | 2270 | arizona_init_spk(codec); |
2253 | arizona_init_gpio(codec); | 2271 | arizona_init_gpio(codec); |
2254 | arizona_init_mono(codec); | 2272 | arizona_init_mono(codec); |
2273 | arizona_init_notifiers(codec); | ||
2255 | 2274 | ||
2256 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, | 2275 | ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, |
2257 | "ADSP2 Compressed IRQ", wm5110_adsp2_irq, | 2276 | "ADSP2 Compressed IRQ", wm5110_adsp2_irq, |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 4bcf5f8ece50..d18261a44256 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -358,6 +358,9 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, | |||
358 | case 24: | 358 | case 24: |
359 | iface |= 0x0008; | 359 | iface |= 0x0008; |
360 | break; | 360 | break; |
361 | case 32: | ||
362 | iface |= 0x000c; | ||
363 | break; | ||
361 | } | 364 | } |
362 | 365 | ||
363 | wm8731_set_deemph(codec); | 366 | wm8731_set_deemph(codec); |
@@ -541,7 +544,7 @@ static int wm8731_startup(struct snd_pcm_substream *substream, | |||
541 | #define WM8731_RATES SNDRV_PCM_RATE_8000_96000 | 544 | #define WM8731_RATES SNDRV_PCM_RATE_8000_96000 |
542 | 545 | ||
543 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 546 | #define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
544 | SNDRV_PCM_FMTBIT_S24_LE) | 547 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) |
545 | 548 | ||
546 | static const struct snd_soc_dai_ops wm8731_dai_ops = { | 549 | static const struct snd_soc_dai_ops wm8731_dai_ops = { |
547 | .startup = wm8731_startup, | 550 | .startup = wm8731_startup, |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 6f1024f48b19..cdcc91282e8a 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -32,7 +32,6 @@ | |||
32 | */ | 32 | */ |
33 | 33 | ||
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/moduleparam.h> | ||
36 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
37 | #include <linux/init.h> | 36 | #include <linux/init.h> |
38 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
@@ -486,7 +485,7 @@ SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", WM8753_PWR1, 4, 0), | |||
486 | SND_SOC_DAPM_OUTPUT("MONO1"), | 485 | SND_SOC_DAPM_OUTPUT("MONO1"), |
487 | SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls), | 486 | SND_SOC_DAPM_MUX("Mono 2 Mux", SND_SOC_NOPM, 0, 0, &wm8753_mono2_controls), |
488 | SND_SOC_DAPM_OUTPUT("MONO2"), | 487 | SND_SOC_DAPM_OUTPUT("MONO2"), |
489 | SND_SOC_DAPM_MIXER("Out3 Left + Right", -1, 0, 0, NULL, 0), | 488 | SND_SOC_DAPM_MIXER("Out3 Left + Right", SND_SOC_NOPM, 0, 0, NULL, 0), |
490 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls), | 489 | SND_SOC_DAPM_MUX("Out3 Mux", SND_SOC_NOPM, 0, 0, &wm8753_out3_controls), |
491 | SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0), | 490 | SND_SOC_DAPM_PGA("Out 3", WM8753_PWR3, 4, 0, NULL, 0), |
492 | SND_SOC_DAPM_OUTPUT("OUT3"), | 491 | SND_SOC_DAPM_OUTPUT("OUT3"), |
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 6ac76fe116b0..7347abff4b2c 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
@@ -1,10 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | * wm8985.c -- WM8985 ALSA SoC Audio driver | 2 | * wm8985.c -- WM8985 / WM8758 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2010 Wolfson Microelectronics plc | 4 | * Copyright 2010 Wolfson Microelectronics plc |
5 | * | ||
6 | * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> | 5 | * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> |
7 | * | 6 | * |
7 | * WM8758 support: | ||
8 | * Copyright: 2016 Barix AG | ||
9 | * Author: Petr Kulhavy <petr@barix.com> | ||
10 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
@@ -40,6 +43,11 @@ static const char *wm8985_supply_names[WM8985_NUM_SUPPLIES] = { | |||
40 | "AVDD2" | 43 | "AVDD2" |
41 | }; | 44 | }; |
42 | 45 | ||
46 | enum wm8985_type { | ||
47 | WM8985, | ||
48 | WM8758, | ||
49 | }; | ||
50 | |||
43 | static const struct reg_default wm8985_reg_defaults[] = { | 51 | static const struct reg_default wm8985_reg_defaults[] = { |
44 | { 1, 0x0000 }, /* R1 - Power management 1 */ | 52 | { 1, 0x0000 }, /* R1 - Power management 1 */ |
45 | { 2, 0x0000 }, /* R2 - Power management 2 */ | 53 | { 2, 0x0000 }, /* R2 - Power management 2 */ |
@@ -181,6 +189,7 @@ static const int volume_update_regs[] = { | |||
181 | struct wm8985_priv { | 189 | struct wm8985_priv { |
182 | struct regmap *regmap; | 190 | struct regmap *regmap; |
183 | struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES]; | 191 | struct regulator_bulk_data supplies[WM8985_NUM_SUPPLIES]; |
192 | enum wm8985_type dev_type; | ||
184 | unsigned int sysclk; | 193 | unsigned int sysclk; |
185 | unsigned int bclk; | 194 | unsigned int bclk; |
186 | }; | 195 | }; |
@@ -289,7 +298,7 @@ static const char *depth_3d_text[] = { | |||
289 | }; | 298 | }; |
290 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text); | 299 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text); |
291 | 300 | ||
292 | static const struct snd_kcontrol_new wm8985_snd_controls[] = { | 301 | static const struct snd_kcontrol_new wm8985_common_snd_controls[] = { |
293 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, | 302 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, |
294 | 0, 1, 0), | 303 | 0, 1, 0), |
295 | 304 | ||
@@ -355,10 +364,6 @@ static const struct snd_kcontrol_new wm8985_snd_controls[] = { | |||
355 | SOC_ENUM("High Pass Filter Mode", filter_mode), | 364 | SOC_ENUM("High Pass Filter Mode", filter_mode), |
356 | SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0), | 365 | SOC_SINGLE("High Pass Filter Cutoff", WM8985_ADC_CONTROL, 4, 7, 0), |
357 | 366 | ||
358 | SOC_DOUBLE_R_TLV("Aux Bypass Volume", | ||
359 | WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0, | ||
360 | aux_tlv), | ||
361 | |||
362 | SOC_DOUBLE_R_TLV("Input PGA Bypass Volume", | 367 | SOC_DOUBLE_R_TLV("Input PGA Bypass Volume", |
363 | WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0, | 368 | WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 2, 7, 0, |
364 | bypass_tlv), | 369 | bypass_tlv), |
@@ -379,20 +384,30 @@ static const struct snd_kcontrol_new wm8985_snd_controls[] = { | |||
379 | SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv), | 384 | SOC_SINGLE_TLV("EQ5 Volume", WM8985_EQ5_HIGH_SHELF, 0, 24, 1, eq_tlv), |
380 | 385 | ||
381 | SOC_ENUM("3D Depth", depth_3d), | 386 | SOC_ENUM("3D Depth", depth_3d), |
387 | }; | ||
388 | |||
389 | static const struct snd_kcontrol_new wm8985_specific_snd_controls[] = { | ||
390 | SOC_DOUBLE_R_TLV("Aux Bypass Volume", | ||
391 | WM8985_LEFT_MIXER_CTRL, WM8985_RIGHT_MIXER_CTRL, 6, 7, 0, | ||
392 | aux_tlv), | ||
382 | 393 | ||
383 | SOC_ENUM("Speaker Mode", speaker_mode) | 394 | SOC_ENUM("Speaker Mode", speaker_mode) |
384 | }; | 395 | }; |
385 | 396 | ||
386 | static const struct snd_kcontrol_new left_out_mixer[] = { | 397 | static const struct snd_kcontrol_new left_out_mixer[] = { |
387 | SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0), | 398 | SOC_DAPM_SINGLE("Line Switch", WM8985_LEFT_MIXER_CTRL, 1, 1, 0), |
388 | SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0), | ||
389 | SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0), | 399 | SOC_DAPM_SINGLE("PCM Switch", WM8985_LEFT_MIXER_CTRL, 0, 1, 0), |
400 | |||
401 | /* --- WM8985 only --- */ | ||
402 | SOC_DAPM_SINGLE("Aux Switch", WM8985_LEFT_MIXER_CTRL, 5, 1, 0), | ||
390 | }; | 403 | }; |
391 | 404 | ||
392 | static const struct snd_kcontrol_new right_out_mixer[] = { | 405 | static const struct snd_kcontrol_new right_out_mixer[] = { |
393 | SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0), | 406 | SOC_DAPM_SINGLE("Line Switch", WM8985_RIGHT_MIXER_CTRL, 1, 1, 0), |
394 | SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0), | ||
395 | SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0), | 407 | SOC_DAPM_SINGLE("PCM Switch", WM8985_RIGHT_MIXER_CTRL, 0, 1, 0), |
408 | |||
409 | /* --- WM8985 only --- */ | ||
410 | SOC_DAPM_SINGLE("Aux Switch", WM8985_RIGHT_MIXER_CTRL, 5, 1, 0), | ||
396 | }; | 411 | }; |
397 | 412 | ||
398 | static const struct snd_kcontrol_new left_input_mixer[] = { | 413 | static const struct snd_kcontrol_new left_input_mixer[] = { |
@@ -410,6 +425,8 @@ static const struct snd_kcontrol_new right_input_mixer[] = { | |||
410 | static const struct snd_kcontrol_new left_boost_mixer[] = { | 425 | static const struct snd_kcontrol_new left_boost_mixer[] = { |
411 | SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL, | 426 | SOC_DAPM_SINGLE_TLV("L2 Volume", WM8985_LEFT_ADC_BOOST_CTRL, |
412 | 4, 7, 0, boost_tlv), | 427 | 4, 7, 0, boost_tlv), |
428 | |||
429 | /* --- WM8985 only --- */ | ||
413 | SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL, | 430 | SOC_DAPM_SINGLE_TLV("AUXL Volume", WM8985_LEFT_ADC_BOOST_CTRL, |
414 | 0, 7, 0, boost_tlv) | 431 | 0, 7, 0, boost_tlv) |
415 | }; | 432 | }; |
@@ -417,11 +434,13 @@ static const struct snd_kcontrol_new left_boost_mixer[] = { | |||
417 | static const struct snd_kcontrol_new right_boost_mixer[] = { | 434 | static const struct snd_kcontrol_new right_boost_mixer[] = { |
418 | SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL, | 435 | SOC_DAPM_SINGLE_TLV("R2 Volume", WM8985_RIGHT_ADC_BOOST_CTRL, |
419 | 4, 7, 0, boost_tlv), | 436 | 4, 7, 0, boost_tlv), |
437 | |||
438 | /* --- WM8985 only --- */ | ||
420 | SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL, | 439 | SOC_DAPM_SINGLE_TLV("AUXR Volume", WM8985_RIGHT_ADC_BOOST_CTRL, |
421 | 0, 7, 0, boost_tlv) | 440 | 0, 7, 0, boost_tlv) |
422 | }; | 441 | }; |
423 | 442 | ||
424 | static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { | 443 | static const struct snd_soc_dapm_widget wm8985_common_dapm_widgets[] = { |
425 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3, | 444 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8985_POWER_MANAGEMENT_3, |
426 | 0, 0), | 445 | 0, 0), |
427 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3, | 446 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8985_POWER_MANAGEMENT_3, |
@@ -431,21 +450,11 @@ static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { | |||
431 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2, | 450 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8985_POWER_MANAGEMENT_2, |
432 | 1, 0), | 451 | 1, 0), |
433 | 452 | ||
434 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
435 | 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)), | ||
436 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
437 | 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)), | ||
438 | |||
439 | SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2, | 453 | SND_SOC_DAPM_MIXER("Left Input Mixer", WM8985_POWER_MANAGEMENT_2, |
440 | 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)), | 454 | 2, 0, left_input_mixer, ARRAY_SIZE(left_input_mixer)), |
441 | SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2, | 455 | SND_SOC_DAPM_MIXER("Right Input Mixer", WM8985_POWER_MANAGEMENT_2, |
442 | 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)), | 456 | 3, 0, right_input_mixer, ARRAY_SIZE(right_input_mixer)), |
443 | 457 | ||
444 | SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
445 | 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)), | ||
446 | SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
447 | 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)), | ||
448 | |||
449 | SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL, | 458 | SND_SOC_DAPM_PGA("Left Capture PGA", WM8985_LEFT_INP_PGA_GAIN_CTRL, |
450 | 6, 1, NULL, 0), | 459 | 6, 1, NULL, 0), |
451 | SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL, | 460 | SND_SOC_DAPM_PGA("Right Capture PGA", WM8985_RIGHT_INP_PGA_GAIN_CTRL, |
@@ -468,8 +477,6 @@ static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { | |||
468 | SND_SOC_DAPM_INPUT("LIP"), | 477 | SND_SOC_DAPM_INPUT("LIP"), |
469 | SND_SOC_DAPM_INPUT("RIN"), | 478 | SND_SOC_DAPM_INPUT("RIN"), |
470 | SND_SOC_DAPM_INPUT("RIP"), | 479 | SND_SOC_DAPM_INPUT("RIP"), |
471 | SND_SOC_DAPM_INPUT("AUXL"), | ||
472 | SND_SOC_DAPM_INPUT("AUXR"), | ||
473 | SND_SOC_DAPM_INPUT("L2"), | 480 | SND_SOC_DAPM_INPUT("L2"), |
474 | SND_SOC_DAPM_INPUT("R2"), | 481 | SND_SOC_DAPM_INPUT("R2"), |
475 | SND_SOC_DAPM_OUTPUT("HPL"), | 482 | SND_SOC_DAPM_OUTPUT("HPL"), |
@@ -478,13 +485,42 @@ static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { | |||
478 | SND_SOC_DAPM_OUTPUT("SPKR") | 485 | SND_SOC_DAPM_OUTPUT("SPKR") |
479 | }; | 486 | }; |
480 | 487 | ||
481 | static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { | 488 | static const struct snd_soc_dapm_widget wm8985_dapm_widgets[] = { |
489 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
490 | 2, 0, left_out_mixer, ARRAY_SIZE(left_out_mixer)), | ||
491 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
492 | 3, 0, right_out_mixer, ARRAY_SIZE(right_out_mixer)), | ||
493 | |||
494 | SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
495 | 4, 0, left_boost_mixer, ARRAY_SIZE(left_boost_mixer)), | ||
496 | SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
497 | 5, 0, right_boost_mixer, ARRAY_SIZE(right_boost_mixer)), | ||
498 | |||
499 | SND_SOC_DAPM_INPUT("AUXL"), | ||
500 | SND_SOC_DAPM_INPUT("AUXR"), | ||
501 | }; | ||
502 | |||
503 | static const struct snd_soc_dapm_widget wm8758_dapm_widgets[] = { | ||
504 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
505 | 2, 0, left_out_mixer, | ||
506 | ARRAY_SIZE(left_out_mixer) - 1), | ||
507 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8985_POWER_MANAGEMENT_3, | ||
508 | 3, 0, right_out_mixer, | ||
509 | ARRAY_SIZE(right_out_mixer) - 1), | ||
510 | |||
511 | SND_SOC_DAPM_MIXER("Left Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
512 | 4, 0, left_boost_mixer, | ||
513 | ARRAY_SIZE(left_boost_mixer) - 1), | ||
514 | SND_SOC_DAPM_MIXER("Right Boost Mixer", WM8985_POWER_MANAGEMENT_2, | ||
515 | 5, 0, right_boost_mixer, | ||
516 | ARRAY_SIZE(right_boost_mixer) - 1), | ||
517 | }; | ||
518 | |||
519 | static const struct snd_soc_dapm_route wm8985_common_dapm_routes[] = { | ||
482 | { "Right Output Mixer", "PCM Switch", "Right DAC" }, | 520 | { "Right Output Mixer", "PCM Switch", "Right DAC" }, |
483 | { "Right Output Mixer", "Aux Switch", "AUXR" }, | ||
484 | { "Right Output Mixer", "Line Switch", "Right Boost Mixer" }, | 521 | { "Right Output Mixer", "Line Switch", "Right Boost Mixer" }, |
485 | 522 | ||
486 | { "Left Output Mixer", "PCM Switch", "Left DAC" }, | 523 | { "Left Output Mixer", "PCM Switch", "Left DAC" }, |
487 | { "Left Output Mixer", "Aux Switch", "AUXL" }, | ||
488 | { "Left Output Mixer", "Line Switch", "Left Boost Mixer" }, | 524 | { "Left Output Mixer", "Line Switch", "Left Boost Mixer" }, |
489 | 525 | ||
490 | { "Right Headphone Out", NULL, "Right Output Mixer" }, | 526 | { "Right Headphone Out", NULL, "Right Output Mixer" }, |
@@ -501,13 +537,11 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { | |||
501 | 537 | ||
502 | { "Right ADC", NULL, "Right Boost Mixer" }, | 538 | { "Right ADC", NULL, "Right Boost Mixer" }, |
503 | 539 | ||
504 | { "Right Boost Mixer", "AUXR Volume", "AUXR" }, | ||
505 | { "Right Boost Mixer", NULL, "Right Capture PGA" }, | 540 | { "Right Boost Mixer", NULL, "Right Capture PGA" }, |
506 | { "Right Boost Mixer", "R2 Volume", "R2" }, | 541 | { "Right Boost Mixer", "R2 Volume", "R2" }, |
507 | 542 | ||
508 | { "Left ADC", NULL, "Left Boost Mixer" }, | 543 | { "Left ADC", NULL, "Left Boost Mixer" }, |
509 | 544 | ||
510 | { "Left Boost Mixer", "AUXL Volume", "AUXL" }, | ||
511 | { "Left Boost Mixer", NULL, "Left Capture PGA" }, | 545 | { "Left Boost Mixer", NULL, "Left Capture PGA" }, |
512 | { "Left Boost Mixer", "L2 Volume", "L2" }, | 546 | { "Left Boost Mixer", "L2 Volume", "L2" }, |
513 | 547 | ||
@@ -522,6 +556,38 @@ static const struct snd_soc_dapm_route wm8985_dapm_routes[] = { | |||
522 | { "Left Input Mixer", "MicN Switch", "LIN" }, | 556 | { "Left Input Mixer", "MicN Switch", "LIN" }, |
523 | { "Left Input Mixer", "MicP Switch", "LIP" }, | 557 | { "Left Input Mixer", "MicP Switch", "LIP" }, |
524 | }; | 558 | }; |
559 | static const struct snd_soc_dapm_route wm8985_aux_dapm_routes[] = { | ||
560 | { "Right Output Mixer", "Aux Switch", "AUXR" }, | ||
561 | { "Left Output Mixer", "Aux Switch", "AUXL" }, | ||
562 | |||
563 | { "Right Boost Mixer", "AUXR Volume", "AUXR" }, | ||
564 | { "Left Boost Mixer", "AUXL Volume", "AUXL" }, | ||
565 | }; | ||
566 | |||
567 | static int wm8985_add_widgets(struct snd_soc_codec *codec) | ||
568 | { | ||
569 | struct wm8985_priv *wm8985 = snd_soc_codec_get_drvdata(codec); | ||
570 | struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); | ||
571 | |||
572 | switch (wm8985->dev_type) { | ||
573 | case WM8758: | ||
574 | snd_soc_dapm_new_controls(dapm, wm8758_dapm_widgets, | ||
575 | ARRAY_SIZE(wm8758_dapm_widgets)); | ||
576 | break; | ||
577 | |||
578 | case WM8985: | ||
579 | snd_soc_add_codec_controls(codec, wm8985_specific_snd_controls, | ||
580 | ARRAY_SIZE(wm8985_specific_snd_controls)); | ||
581 | |||
582 | snd_soc_dapm_new_controls(dapm, wm8985_dapm_widgets, | ||
583 | ARRAY_SIZE(wm8985_dapm_widgets)); | ||
584 | snd_soc_dapm_add_routes(dapm, wm8985_aux_dapm_routes, | ||
585 | ARRAY_SIZE(wm8985_aux_dapm_routes)); | ||
586 | break; | ||
587 | } | ||
588 | |||
589 | return 0; | ||
590 | } | ||
525 | 591 | ||
526 | static int eqmode_get(struct snd_kcontrol *kcontrol, | 592 | static int eqmode_get(struct snd_kcontrol *kcontrol, |
527 | struct snd_ctl_elem_value *ucontrol) | 593 | struct snd_ctl_elem_value *ucontrol) |
@@ -999,6 +1065,8 @@ static int wm8985_probe(struct snd_soc_codec *codec) | |||
999 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, | 1065 | snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT, |
1000 | WM8985_BIASCUT); | 1066 | WM8985_BIASCUT); |
1001 | 1067 | ||
1068 | wm8985_add_widgets(codec); | ||
1069 | |||
1002 | return 0; | 1070 | return 0; |
1003 | 1071 | ||
1004 | err_reg_enable: | 1072 | err_reg_enable: |
@@ -1042,12 +1110,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8985 = { | |||
1042 | .set_bias_level = wm8985_set_bias_level, | 1110 | .set_bias_level = wm8985_set_bias_level, |
1043 | .suspend_bias_off = true, | 1111 | .suspend_bias_off = true, |
1044 | 1112 | ||
1045 | .controls = wm8985_snd_controls, | 1113 | .controls = wm8985_common_snd_controls, |
1046 | .num_controls = ARRAY_SIZE(wm8985_snd_controls), | 1114 | .num_controls = ARRAY_SIZE(wm8985_common_snd_controls), |
1047 | .dapm_widgets = wm8985_dapm_widgets, | 1115 | .dapm_widgets = wm8985_common_dapm_widgets, |
1048 | .num_dapm_widgets = ARRAY_SIZE(wm8985_dapm_widgets), | 1116 | .num_dapm_widgets = ARRAY_SIZE(wm8985_common_dapm_widgets), |
1049 | .dapm_routes = wm8985_dapm_routes, | 1117 | .dapm_routes = wm8985_common_dapm_routes, |
1050 | .num_dapm_routes = ARRAY_SIZE(wm8985_dapm_routes), | 1118 | .num_dapm_routes = ARRAY_SIZE(wm8985_common_dapm_routes), |
1051 | }; | 1119 | }; |
1052 | 1120 | ||
1053 | static const struct regmap_config wm8985_regmap = { | 1121 | static const struct regmap_config wm8985_regmap = { |
@@ -1074,6 +1142,8 @@ static int wm8985_spi_probe(struct spi_device *spi) | |||
1074 | 1142 | ||
1075 | spi_set_drvdata(spi, wm8985); | 1143 | spi_set_drvdata(spi, wm8985); |
1076 | 1144 | ||
1145 | wm8985->dev_type = WM8985; | ||
1146 | |||
1077 | wm8985->regmap = devm_regmap_init_spi(spi, &wm8985_regmap); | 1147 | wm8985->regmap = devm_regmap_init_spi(spi, &wm8985_regmap); |
1078 | if (IS_ERR(wm8985->regmap)) { | 1148 | if (IS_ERR(wm8985->regmap)) { |
1079 | ret = PTR_ERR(wm8985->regmap); | 1149 | ret = PTR_ERR(wm8985->regmap); |
@@ -1115,6 +1185,8 @@ static int wm8985_i2c_probe(struct i2c_client *i2c, | |||
1115 | 1185 | ||
1116 | i2c_set_clientdata(i2c, wm8985); | 1186 | i2c_set_clientdata(i2c, wm8985); |
1117 | 1187 | ||
1188 | wm8985->dev_type = id->driver_data; | ||
1189 | |||
1118 | wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap); | 1190 | wm8985->regmap = devm_regmap_init_i2c(i2c, &wm8985_regmap); |
1119 | if (IS_ERR(wm8985->regmap)) { | 1191 | if (IS_ERR(wm8985->regmap)) { |
1120 | ret = PTR_ERR(wm8985->regmap); | 1192 | ret = PTR_ERR(wm8985->regmap); |
@@ -1135,7 +1207,8 @@ static int wm8985_i2c_remove(struct i2c_client *i2c) | |||
1135 | } | 1207 | } |
1136 | 1208 | ||
1137 | static const struct i2c_device_id wm8985_i2c_id[] = { | 1209 | static const struct i2c_device_id wm8985_i2c_id[] = { |
1138 | { "wm8985", 0 }, | 1210 | { "wm8985", WM8985 }, |
1211 | { "wm8758", WM8758 }, | ||
1139 | { } | 1212 | { } |
1140 | }; | 1213 | }; |
1141 | MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id); | 1214 | MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id); |
@@ -1183,6 +1256,6 @@ static void __exit wm8985_exit(void) | |||
1183 | } | 1256 | } |
1184 | module_exit(wm8985_exit); | 1257 | module_exit(wm8985_exit); |
1185 | 1258 | ||
1186 | MODULE_DESCRIPTION("ASoC WM8985 driver"); | 1259 | MODULE_DESCRIPTION("ASoC WM8985 / WM8758 driver"); |
1187 | MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); | 1260 | MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); |
1188 | MODULE_LICENSE("GPL"); | 1261 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/wm8985.h b/sound/soc/codecs/wm8985.h index 2e71ff507638..41b1048e3c97 100644 --- a/sound/soc/codecs/wm8985.h +++ b/sound/soc/codecs/wm8985.h | |||
@@ -290,6 +290,9 @@ | |||
290 | #define WM8985_GPIO1GPD_MASK 0x0040 /* GPIO1GPD */ | 290 | #define WM8985_GPIO1GPD_MASK 0x0040 /* GPIO1GPD */ |
291 | #define WM8985_GPIO1GPD_SHIFT 6 /* GPIO1GPD */ | 291 | #define WM8985_GPIO1GPD_SHIFT 6 /* GPIO1GPD */ |
292 | #define WM8985_GPIO1GPD_WIDTH 1 /* GPIO1GPD */ | 292 | #define WM8985_GPIO1GPD_WIDTH 1 /* GPIO1GPD */ |
293 | #define WM8758_OPCLKDIV_MASK 0x0030 /* OPCLKDIV - [1:0] */ | ||
294 | #define WM8758_OPCLKDIV_SHIFT 4 /* OPCLKDIV - [1:0] */ | ||
295 | #define WM8758_OPCLKDIV_WIDTH 2 /* OPCLKDIV - [1:0] */ | ||
293 | #define WM8985_GPIO1POL 0x0008 /* GPIO1POL */ | 296 | #define WM8985_GPIO1POL 0x0008 /* GPIO1POL */ |
294 | #define WM8985_GPIO1POL_MASK 0x0008 /* GPIO1POL */ | 297 | #define WM8985_GPIO1POL_MASK 0x0008 /* GPIO1POL */ |
295 | #define WM8985_GPIO1POL_SHIFT 3 /* GPIO1POL */ | 298 | #define WM8985_GPIO1POL_SHIFT 3 /* GPIO1POL */ |
@@ -301,6 +304,12 @@ | |||
301 | /* | 304 | /* |
302 | * R9 (0x09) - Jack Detect Control 1 | 305 | * R9 (0x09) - Jack Detect Control 1 |
303 | */ | 306 | */ |
307 | #define WM8758_JD_VMID1_MASK 0x0100 /* JD_VMID1 */ | ||
308 | #define WM8758_JD_VMID1_SHIFT 8 /* JD_VMID1 */ | ||
309 | #define WM8758_JD_VMID1_WIDTH 1 /* JD_VMID1 */ | ||
310 | #define WM8758_JD_VMID0_MASK 0x0080 /* JD_VMID0 */ | ||
311 | #define WM8758_JD_VMID0_SHIFT 7 /* JD_VMID0 */ | ||
312 | #define WM8758_JD_VMID0_WIDTH 1 /* JD_VMID0 */ | ||
304 | #define WM8985_JD_EN 0x0040 /* JD_EN */ | 313 | #define WM8985_JD_EN 0x0040 /* JD_EN */ |
305 | #define WM8985_JD_EN_MASK 0x0040 /* JD_EN */ | 314 | #define WM8985_JD_EN_MASK 0x0040 /* JD_EN */ |
306 | #define WM8985_JD_EN_SHIFT 6 /* JD_EN */ | 315 | #define WM8985_JD_EN_SHIFT 6 /* JD_EN */ |
@@ -649,6 +658,12 @@ | |||
649 | #define WM8985_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */ | 658 | #define WM8985_OUT4_2LNR_MASK 0x0020 /* OUT4_2LNR */ |
650 | #define WM8985_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */ | 659 | #define WM8985_OUT4_2LNR_SHIFT 5 /* OUT4_2LNR */ |
651 | #define WM8985_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */ | 660 | #define WM8985_OUT4_2LNR_WIDTH 1 /* OUT4_2LNR */ |
661 | #define WM8758_VMIDTOG_MASK 0x0010 /* VMIDTOG */ | ||
662 | #define WM8758_VMIDTOG_SHIFT 4 /* VMIDTOG */ | ||
663 | #define WM8758_VMIDTOG_WIDTH 1 /* VMIDTOG */ | ||
664 | #define WM8758_OUT2DEL_MASK 0x0008 /* OUT2DEL */ | ||
665 | #define WM8758_OUT2DEL_SHIFT 3 /* OUT2DEL */ | ||
666 | #define WM8758_OUT2DEL_WIDTH 1 /* OUT2DEL */ | ||
652 | #define WM8985_POBCTRL 0x0004 /* POBCTRL */ | 667 | #define WM8985_POBCTRL 0x0004 /* POBCTRL */ |
653 | #define WM8985_POBCTRL_MASK 0x0004 /* POBCTRL */ | 668 | #define WM8985_POBCTRL_MASK 0x0004 /* POBCTRL */ |
654 | #define WM8985_POBCTRL_SHIFT 2 /* POBCTRL */ | 669 | #define WM8985_POBCTRL_SHIFT 2 /* POBCTRL */ |
@@ -684,6 +699,9 @@ | |||
684 | #define WM8985_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */ | 699 | #define WM8985_BEEPVOL_MASK 0x000E /* BEEPVOL - [3:1] */ |
685 | #define WM8985_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */ | 700 | #define WM8985_BEEPVOL_SHIFT 1 /* BEEPVOL - [3:1] */ |
686 | #define WM8985_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */ | 701 | #define WM8985_BEEPVOL_WIDTH 3 /* BEEPVOL - [3:1] */ |
702 | #define WM8758_DELEN2_MASK 0x0004 /* DELEN2 */ | ||
703 | #define WM8758_DELEN2_SHIFT 2 /* DELEN2 */ | ||
704 | #define WM8758_DELEN2_WIDTH 1 /* DELEN2 */ | ||
687 | #define WM8985_BEEPEN 0x0001 /* BEEPEN */ | 705 | #define WM8985_BEEPEN 0x0001 /* BEEPEN */ |
688 | #define WM8985_BEEPEN_MASK 0x0001 /* BEEPEN */ | 706 | #define WM8985_BEEPEN_MASK 0x0001 /* BEEPEN */ |
689 | #define WM8985_BEEPEN_SHIFT 0 /* BEEPEN */ | 707 | #define WM8985_BEEPEN_SHIFT 0 /* BEEPEN */ |
@@ -790,6 +808,14 @@ | |||
790 | /* | 808 | /* |
791 | * R49 (0x31) - Output ctrl | 809 | * R49 (0x31) - Output ctrl |
792 | */ | 810 | */ |
811 | #define WM8758_HP_COM 0x0100 /* HP_COM */ | ||
812 | #define WM8758_HP_COM_MASK 0x0100 /* HP_COM */ | ||
813 | #define WM8758_HP_COM_SHIFT 8 /* HP_COM */ | ||
814 | #define WM8758_HP_COM_WIDTH 1 /* HP_COM */ | ||
815 | #define WM8758_LINE_COM 0x0080 /* LINE_COM */ | ||
816 | #define WM8758_LINE_COM_MASK 0x0080 /* LINE_COM */ | ||
817 | #define WM8758_LINE_COM_SHIFT 7 /* LINE_COM */ | ||
818 | #define WM8758_LINE_COM_WIDTH 1 /* LINE_COM */ | ||
793 | #define WM8985_DACL2RMIX 0x0040 /* DACL2RMIX */ | 819 | #define WM8985_DACL2RMIX 0x0040 /* DACL2RMIX */ |
794 | #define WM8985_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */ | 820 | #define WM8985_DACL2RMIX_MASK 0x0040 /* DACL2RMIX */ |
795 | #define WM8985_DACL2RMIX_SHIFT 6 /* DACL2RMIX */ | 821 | #define WM8985_DACL2RMIX_SHIFT 6 /* DACL2RMIX */ |
@@ -806,6 +832,14 @@ | |||
806 | #define WM8985_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */ | 832 | #define WM8985_OUT3BOOST_MASK 0x0008 /* OUT3BOOST */ |
807 | #define WM8985_OUT3BOOST_SHIFT 3 /* OUT3BOOST */ | 833 | #define WM8985_OUT3BOOST_SHIFT 3 /* OUT3BOOST */ |
808 | #define WM8985_OUT3BOOST_WIDTH 1 /* OUT3BOOST */ | 834 | #define WM8985_OUT3BOOST_WIDTH 1 /* OUT3BOOST */ |
835 | #define WM8758_OUT4ENDEL 0x0010 /* OUT4ENDEL */ | ||
836 | #define WM8758_OUT4ENDEL_MASK 0x0010 /* OUT4ENDEL */ | ||
837 | #define WM8758_OUT4ENDEL_SHIFT 4 /* OUT4ENDEL */ | ||
838 | #define WM8758_OUT4ENDEL_WIDTH 1 /* OUT4ENDEL */ | ||
839 | #define WM8758_OUT3ENDEL 0x0008 /* OUT3ENDEL */ | ||
840 | #define WM8758_OUT3ENDEL_MASK 0x0008 /* OUT3ENDEL */ | ||
841 | #define WM8758_OUT3ENDEL_SHIFT 3 /* OUT3ENDEL */ | ||
842 | #define WM8758_OUT3ENDEL_WIDTH 1 /* OUT3ENDEL */ | ||
809 | #define WM8985_TSOPCTRL 0x0004 /* TSOPCTRL */ | 843 | #define WM8985_TSOPCTRL 0x0004 /* TSOPCTRL */ |
810 | #define WM8985_TSOPCTRL_MASK 0x0004 /* TSOPCTRL */ | 844 | #define WM8985_TSOPCTRL_MASK 0x0004 /* TSOPCTRL */ |
811 | #define WM8985_TSOPCTRL_SHIFT 2 /* TSOPCTRL */ | 845 | #define WM8985_TSOPCTRL_SHIFT 2 /* TSOPCTRL */ |
@@ -1021,6 +1055,10 @@ | |||
1021 | #define WM8985_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */ | 1055 | #define WM8985_HALFIPBIAS_MASK 0x0080 /* HALFIPBIAS */ |
1022 | #define WM8985_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */ | 1056 | #define WM8985_HALFIPBIAS_SHIFT 7 /* HALFIPBIAS */ |
1023 | #define WM8985_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */ | 1057 | #define WM8985_HALFIPBIAS_WIDTH 1 /* HALFIPBIAS */ |
1058 | #define WM8758_HALFIPBIAS 0x0040 /* HALFI_IPGA */ | ||
1059 | #define WM8758_HALFI_IPGA_MASK 0x0040 /* HALFI_IPGA */ | ||
1060 | #define WM8758_HALFI_IPGA_SHIFT 6 /* HALFI_IPGA */ | ||
1061 | #define WM8758_HALFI_IPGA_WIDTH 1 /* HALFI_IPGA */ | ||
1024 | #define WM8985_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */ | 1062 | #define WM8985_VBBIASTST_MASK 0x0060 /* VBBIASTST - [6:5] */ |
1025 | #define WM8985_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */ | 1063 | #define WM8985_VBBIASTST_SHIFT 5 /* VBBIASTST - [6:5] */ |
1026 | #define WM8985_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */ | 1064 | #define WM8985_VBBIASTST_WIDTH 2 /* VBBIASTST - [6:5] */ |
diff --git a/sound/soc/codecs/wm8998.c b/sound/soc/codecs/wm8998.c index 449f66636205..3a5c896a2d13 100644 --- a/sound/soc/codecs/wm8998.c +++ b/sound/soc/codecs/wm8998.c | |||
@@ -1166,6 +1166,7 @@ static const struct snd_soc_dapm_route wm8998_dapm_routes[] = { | |||
1166 | 1166 | ||
1167 | { "MICSUPP", NULL, "SYSCLK" }, | 1167 | { "MICSUPP", NULL, "SYSCLK" }, |
1168 | 1168 | ||
1169 | { "DRC1 Signal Activity", NULL, "SYSCLK" }, | ||
1169 | { "DRC1 Signal Activity", NULL, "DRC1L" }, | 1170 | { "DRC1 Signal Activity", NULL, "DRC1L" }, |
1170 | { "DRC1 Signal Activity", NULL, "DRC1R" }, | 1171 | { "DRC1 Signal Activity", NULL, "DRC1R" }, |
1171 | }; | 1172 | }; |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index a07bd7c2c587..21fbe7d07063 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -394,6 +394,7 @@ static const struct { | |||
394 | int compr_direction; | 394 | int compr_direction; |
395 | int num_caps; | 395 | int num_caps; |
396 | const struct wm_adsp_fw_caps *caps; | 396 | const struct wm_adsp_fw_caps *caps; |
397 | bool voice_trigger; | ||
397 | } wm_adsp_fw[WM_ADSP_NUM_FW] = { | 398 | } wm_adsp_fw[WM_ADSP_NUM_FW] = { |
398 | [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, | 399 | [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, |
399 | [WM_ADSP_FW_HIFI] = { .file = "hifi" }, | 400 | [WM_ADSP_FW_HIFI] = { .file = "hifi" }, |
@@ -406,6 +407,7 @@ static const struct { | |||
406 | .compr_direction = SND_COMPRESS_CAPTURE, | 407 | .compr_direction = SND_COMPRESS_CAPTURE, |
407 | .num_caps = ARRAY_SIZE(ctrl_caps), | 408 | .num_caps = ARRAY_SIZE(ctrl_caps), |
408 | .caps = ctrl_caps, | 409 | .caps = ctrl_caps, |
410 | .voice_trigger = true, | ||
409 | }, | 411 | }, |
410 | [WM_ADSP_FW_ASR] = { .file = "asr" }, | 412 | [WM_ADSP_FW_ASR] = { .file = "asr" }, |
411 | [WM_ADSP_FW_TRACE] = { | 413 | [WM_ADSP_FW_TRACE] = { |
@@ -2366,13 +2368,15 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
2366 | dsp->running = false; | 2368 | dsp->running = false; |
2367 | 2369 | ||
2368 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | 2370 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, |
2369 | ADSP2_SYS_ENA | ADSP2_CORE_ENA | | 2371 | ADSP2_CORE_ENA | ADSP2_START, 0); |
2370 | ADSP2_START, 0); | ||
2371 | 2372 | ||
2372 | /* Make sure DMAs are quiesced */ | 2373 | /* Make sure DMAs are quiesced */ |
2374 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); | ||
2373 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); | 2375 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_1, 0); |
2374 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); | 2376 | regmap_write(dsp->regmap, dsp->base + ADSP2_WDMA_CONFIG_2, 0); |
2375 | regmap_write(dsp->regmap, dsp->base + ADSP2_RDMA_CONFIG_1, 0); | 2377 | |
2378 | regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, | ||
2379 | ADSP2_SYS_ENA, 0); | ||
2376 | 2380 | ||
2377 | list_for_each_entry(ctl, &dsp->ctl_list, list) | 2381 | list_for_each_entry(ctl, &dsp->ctl_list, list) |
2378 | ctl->enabled = 0; | 2382 | ctl->enabled = 0; |
@@ -2998,6 +3002,9 @@ int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) | |||
2998 | goto out; | 3002 | goto out; |
2999 | } | 3003 | } |
3000 | 3004 | ||
3005 | if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) | ||
3006 | ret = WM_ADSP_COMPR_VOICE_TRIGGER; | ||
3007 | |||
3001 | out_notify: | 3008 | out_notify: |
3002 | if (compr && compr->stream) | 3009 | if (compr && compr->stream) |
3003 | snd_compr_fragment_elapsed(compr->stream); | 3010 | snd_compr_fragment_elapsed(compr->stream); |
@@ -3037,12 +3044,8 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
3037 | 3044 | ||
3038 | buf = compr->buf; | 3045 | buf = compr->buf; |
3039 | 3046 | ||
3040 | if (!compr->buf) { | 3047 | if (!compr->buf || compr->buf->error) { |
3041 | ret = -ENXIO; | 3048 | snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); |
3042 | goto out; | ||
3043 | } | ||
3044 | |||
3045 | if (compr->buf->error) { | ||
3046 | ret = -EIO; | 3049 | ret = -EIO; |
3047 | goto out; | 3050 | goto out; |
3048 | } | 3051 | } |
@@ -3060,8 +3063,12 @@ int wm_adsp_compr_pointer(struct snd_compr_stream *stream, | |||
3060 | */ | 3063 | */ |
3061 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { | 3064 | if (buf->avail < wm_adsp_compr_frag_words(compr)) { |
3062 | ret = wm_adsp_buffer_get_error(buf); | 3065 | ret = wm_adsp_buffer_get_error(buf); |
3063 | if (ret < 0) | 3066 | if (ret < 0) { |
3067 | if (compr->buf->error) | ||
3068 | snd_compr_stop_error(stream, | ||
3069 | SNDRV_PCM_STATE_XRUN); | ||
3064 | goto out; | 3070 | goto out; |
3071 | } | ||
3065 | 3072 | ||
3066 | ret = wm_adsp_buffer_reenable_irq(buf); | 3073 | ret = wm_adsp_buffer_reenable_irq(buf); |
3067 | if (ret < 0) { | 3074 | if (ret < 0) { |
@@ -3156,11 +3163,10 @@ static int wm_adsp_compr_read(struct wm_adsp_compr *compr, | |||
3156 | 3163 | ||
3157 | adsp_dbg(dsp, "Requested read of %zu bytes\n", count); | 3164 | adsp_dbg(dsp, "Requested read of %zu bytes\n", count); |
3158 | 3165 | ||
3159 | if (!compr->buf) | 3166 | if (!compr->buf || compr->buf->error) { |
3160 | return -ENXIO; | 3167 | snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); |
3161 | |||
3162 | if (compr->buf->error) | ||
3163 | return -EIO; | 3168 | return -EIO; |
3169 | } | ||
3164 | 3170 | ||
3165 | count /= WM_ADSP_DATA_WORD_SIZE; | 3171 | count /= WM_ADSP_DATA_WORD_SIZE; |
3166 | 3172 | ||
diff --git a/sound/soc/codecs/wm_adsp.h b/sound/soc/codecs/wm_adsp.h index feb61e2c4bb4..be3b5bcb7f17 100644 --- a/sound/soc/codecs/wm_adsp.h +++ b/sound/soc/codecs/wm_adsp.h | |||
@@ -19,6 +19,10 @@ | |||
19 | 19 | ||
20 | #include "wmfw.h" | 20 | #include "wmfw.h" |
21 | 21 | ||
22 | /* Return values for wm_adsp_compr_handle_irq */ | ||
23 | #define WM_ADSP_COMPR_OK 0 | ||
24 | #define WM_ADSP_COMPR_VOICE_TRIGGER 1 | ||
25 | |||
22 | struct wm_adsp_region { | 26 | struct wm_adsp_region { |
23 | int type; | 27 | int type; |
24 | unsigned int base; | 28 | unsigned int base; |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index 237dc67002ef..05c2d33aa74d 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -1599,7 +1599,14 @@ static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( | |||
1599 | pdata = pdev->dev.platform_data; | 1599 | pdata = pdev->dev.platform_data; |
1600 | return pdata; | 1600 | return pdata; |
1601 | } else if (match) { | 1601 | } else if (match) { |
1602 | pdata = (struct davinci_mcasp_pdata*) match->data; | 1602 | pdata = devm_kmemdup(&pdev->dev, match->data, sizeof(*pdata), |
1603 | GFP_KERNEL); | ||
1604 | if (!pdata) { | ||
1605 | dev_err(&pdev->dev, | ||
1606 | "Failed to allocate memory for pdata\n"); | ||
1607 | ret = -ENOMEM; | ||
1608 | return pdata; | ||
1609 | } | ||
1603 | } else { | 1610 | } else { |
1604 | /* control shouldn't reach here. something is wrong */ | 1611 | /* control shouldn't reach here. something is wrong */ |
1605 | ret = -EINVAL; | 1612 | ret = -EINVAL; |
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig index d50e08517dce..c297efe43861 100644 --- a/sound/soc/dwc/Kconfig +++ b/sound/soc/dwc/Kconfig | |||
@@ -7,4 +7,13 @@ config SND_DESIGNWARE_I2S | |||
7 | Synopsys desigwnware I2S device. The device supports upto | 7 | Synopsys desigwnware I2S device. The device supports upto |
8 | maximum of 8 channels each for play and record. | 8 | maximum of 8 channels each for play and record. |
9 | 9 | ||
10 | config SND_DESIGNWARE_PCM | ||
11 | tristate "PCM PIO extension for I2S driver" | ||
12 | depends on SND_DESIGNWARE_I2S | ||
13 | help | ||
14 | Say Y, M or N if you want to add a custom ALSA extension that registers | ||
15 | a PCM and uses PIO to transfer data. | ||
16 | |||
17 | This functionality is specially suited for I2S devices that don't have | ||
18 | DMA support. | ||
10 | 19 | ||
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile index 319371f690f4..38f1ca31c5fa 100644 --- a/sound/soc/dwc/Makefile +++ b/sound/soc/dwc/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | # SYNOPSYS Platform Support | 1 | # SYNOPSYS Platform Support |
2 | obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o | 2 | obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o |
3 | 3 | ifdef CONFIG_SND_DESIGNWARE_PCM | |
4 | obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_pcm.o | ||
5 | endif | ||
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 0db69b7e9617..dc97f4349e66 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -24,90 +24,7 @@ | |||
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/dmaengine_pcm.h> | 26 | #include <sound/dmaengine_pcm.h> |
27 | 27 | #include "local.h" | |
28 | /* common register for all channel */ | ||
29 | #define IER 0x000 | ||
30 | #define IRER 0x004 | ||
31 | #define ITER 0x008 | ||
32 | #define CER 0x00C | ||
33 | #define CCR 0x010 | ||
34 | #define RXFFR 0x014 | ||
35 | #define TXFFR 0x018 | ||
36 | |||
37 | /* I2STxRxRegisters for all channels */ | ||
38 | #define LRBR_LTHR(x) (0x40 * x + 0x020) | ||
39 | #define RRBR_RTHR(x) (0x40 * x + 0x024) | ||
40 | #define RER(x) (0x40 * x + 0x028) | ||
41 | #define TER(x) (0x40 * x + 0x02C) | ||
42 | #define RCR(x) (0x40 * x + 0x030) | ||
43 | #define TCR(x) (0x40 * x + 0x034) | ||
44 | #define ISR(x) (0x40 * x + 0x038) | ||
45 | #define IMR(x) (0x40 * x + 0x03C) | ||
46 | #define ROR(x) (0x40 * x + 0x040) | ||
47 | #define TOR(x) (0x40 * x + 0x044) | ||
48 | #define RFCR(x) (0x40 * x + 0x048) | ||
49 | #define TFCR(x) (0x40 * x + 0x04C) | ||
50 | #define RFF(x) (0x40 * x + 0x050) | ||
51 | #define TFF(x) (0x40 * x + 0x054) | ||
52 | |||
53 | /* I2SCOMPRegisters */ | ||
54 | #define I2S_COMP_PARAM_2 0x01F0 | ||
55 | #define I2S_COMP_PARAM_1 0x01F4 | ||
56 | #define I2S_COMP_VERSION 0x01F8 | ||
57 | #define I2S_COMP_TYPE 0x01FC | ||
58 | |||
59 | /* | ||
60 | * Component parameter register fields - define the I2S block's | ||
61 | * configuration. | ||
62 | */ | ||
63 | #define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25) | ||
64 | #define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22) | ||
65 | #define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19) | ||
66 | #define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16) | ||
67 | #define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9) | ||
68 | #define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7) | ||
69 | #define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6) | ||
70 | #define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5) | ||
71 | #define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4) | ||
72 | #define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2) | ||
73 | #define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0) | ||
74 | |||
75 | #define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10) | ||
76 | #define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7) | ||
77 | #define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3) | ||
78 | #define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0) | ||
79 | |||
80 | /* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */ | ||
81 | #define COMP_MAX_WORDSIZE (1 << 3) | ||
82 | #define COMP_MAX_DATA_WIDTH (1 << 2) | ||
83 | |||
84 | #define MAX_CHANNEL_NUM 8 | ||
85 | #define MIN_CHANNEL_NUM 2 | ||
86 | |||
87 | union dw_i2s_snd_dma_data { | ||
88 | struct i2s_dma_data pd; | ||
89 | struct snd_dmaengine_dai_dma_data dt; | ||
90 | }; | ||
91 | |||
92 | struct dw_i2s_dev { | ||
93 | void __iomem *i2s_base; | ||
94 | struct clk *clk; | ||
95 | int active; | ||
96 | unsigned int capability; | ||
97 | unsigned int quirks; | ||
98 | unsigned int i2s_reg_comp1; | ||
99 | unsigned int i2s_reg_comp2; | ||
100 | struct device *dev; | ||
101 | u32 ccr; | ||
102 | u32 xfer_resolution; | ||
103 | u32 fifo_th; | ||
104 | |||
105 | /* data related to DMA transfers b/w i2s and DMAC */ | ||
106 | union dw_i2s_snd_dma_data play_dma_data; | ||
107 | union dw_i2s_snd_dma_data capture_dma_data; | ||
108 | struct i2s_clk_config_data config; | ||
109 | int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); | ||
110 | }; | ||
111 | 28 | ||
112 | static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val) | 29 | static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val) |
113 | { | 30 | { |
@@ -145,51 +62,115 @@ static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream) | |||
145 | } | 62 | } |
146 | } | 63 | } |
147 | 64 | ||
148 | static void i2s_start(struct dw_i2s_dev *dev, | 65 | static inline void i2s_disable_irqs(struct dw_i2s_dev *dev, u32 stream, |
149 | struct snd_pcm_substream *substream) | 66 | int chan_nr) |
67 | { | ||
68 | u32 i, irq; | ||
69 | |||
70 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
71 | for (i = 0; i < (chan_nr / 2); i++) { | ||
72 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
73 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30); | ||
74 | } | ||
75 | } else { | ||
76 | for (i = 0; i < (chan_nr / 2); i++) { | ||
77 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
78 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03); | ||
79 | } | ||
80 | } | ||
81 | } | ||
82 | |||
83 | static inline void i2s_enable_irqs(struct dw_i2s_dev *dev, u32 stream, | ||
84 | int chan_nr) | ||
150 | { | 85 | { |
151 | struct i2s_clk_config_data *config = &dev->config; | ||
152 | u32 i, irq; | 86 | u32 i, irq; |
153 | i2s_write_reg(dev->i2s_base, IER, 1); | ||
154 | 87 | ||
155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 88 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { |
156 | for (i = 0; i < (config->chan_nr / 2); i++) { | 89 | for (i = 0; i < (chan_nr / 2); i++) { |
157 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | 90 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); |
158 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30); | 91 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x30); |
159 | } | 92 | } |
160 | i2s_write_reg(dev->i2s_base, ITER, 1); | ||
161 | } else { | 93 | } else { |
162 | for (i = 0; i < (config->chan_nr / 2); i++) { | 94 | for (i = 0; i < (chan_nr / 2); i++) { |
163 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | 95 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); |
164 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03); | 96 | i2s_write_reg(dev->i2s_base, IMR(i), irq & ~0x03); |
165 | } | 97 | } |
166 | i2s_write_reg(dev->i2s_base, IRER, 1); | 98 | } |
99 | } | ||
100 | |||
101 | static irqreturn_t i2s_irq_handler(int irq, void *dev_id) | ||
102 | { | ||
103 | struct dw_i2s_dev *dev = dev_id; | ||
104 | bool irq_valid = false; | ||
105 | u32 isr[4]; | ||
106 | int i; | ||
107 | |||
108 | for (i = 0; i < 4; i++) | ||
109 | isr[i] = i2s_read_reg(dev->i2s_base, ISR(i)); | ||
110 | |||
111 | i2s_clear_irqs(dev, SNDRV_PCM_STREAM_PLAYBACK); | ||
112 | i2s_clear_irqs(dev, SNDRV_PCM_STREAM_CAPTURE); | ||
113 | |||
114 | for (i = 0; i < 4; i++) { | ||
115 | /* | ||
116 | * Check if TX fifo is empty. If empty fill FIFO with samples | ||
117 | * NOTE: Only two channels supported | ||
118 | */ | ||
119 | if ((isr[i] & ISR_TXFE) && (i == 0) && dev->use_pio) { | ||
120 | dw_pcm_push_tx(dev); | ||
121 | irq_valid = true; | ||
122 | } | ||
123 | |||
124 | /* Data available. Record mode not supported in PIO mode */ | ||
125 | if (isr[i] & ISR_RXDA) | ||
126 | irq_valid = true; | ||
127 | |||
128 | /* Error Handling: TX */ | ||
129 | if (isr[i] & ISR_TXFO) { | ||
130 | dev_err(dev->dev, "TX overrun (ch_id=%d)\n", i); | ||
131 | irq_valid = true; | ||
132 | } | ||
133 | |||
134 | /* Error Handling: TX */ | ||
135 | if (isr[i] & ISR_RXFO) { | ||
136 | dev_err(dev->dev, "RX overrun (ch_id=%d)\n", i); | ||
137 | irq_valid = true; | ||
138 | } | ||
167 | } | 139 | } |
168 | 140 | ||
141 | if (irq_valid) | ||
142 | return IRQ_HANDLED; | ||
143 | else | ||
144 | return IRQ_NONE; | ||
145 | } | ||
146 | |||
147 | static void i2s_start(struct dw_i2s_dev *dev, | ||
148 | struct snd_pcm_substream *substream) | ||
149 | { | ||
150 | struct i2s_clk_config_data *config = &dev->config; | ||
151 | |||
152 | i2s_write_reg(dev->i2s_base, IER, 1); | ||
153 | i2s_enable_irqs(dev, substream->stream, config->chan_nr); | ||
154 | |||
155 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
156 | i2s_write_reg(dev->i2s_base, ITER, 1); | ||
157 | else | ||
158 | i2s_write_reg(dev->i2s_base, IRER, 1); | ||
159 | |||
169 | i2s_write_reg(dev->i2s_base, CER, 1); | 160 | i2s_write_reg(dev->i2s_base, CER, 1); |
170 | } | 161 | } |
171 | 162 | ||
172 | static void i2s_stop(struct dw_i2s_dev *dev, | 163 | static void i2s_stop(struct dw_i2s_dev *dev, |
173 | struct snd_pcm_substream *substream) | 164 | struct snd_pcm_substream *substream) |
174 | { | 165 | { |
175 | u32 i = 0, irq; | ||
176 | 166 | ||
177 | i2s_clear_irqs(dev, substream->stream); | 167 | i2s_clear_irqs(dev, substream->stream); |
178 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 168 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
179 | i2s_write_reg(dev->i2s_base, ITER, 0); | 169 | i2s_write_reg(dev->i2s_base, ITER, 0); |
180 | 170 | else | |
181 | for (i = 0; i < 4; i++) { | ||
182 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
183 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30); | ||
184 | } | ||
185 | } else { | ||
186 | i2s_write_reg(dev->i2s_base, IRER, 0); | 171 | i2s_write_reg(dev->i2s_base, IRER, 0); |
187 | 172 | ||
188 | for (i = 0; i < 4; i++) { | 173 | i2s_disable_irqs(dev, substream->stream, 8); |
189 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
190 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03); | ||
191 | } | ||
192 | } | ||
193 | 174 | ||
194 | if (!dev->active) { | 175 | if (!dev->active) { |
195 | i2s_write_reg(dev->i2s_base, CER, 0); | 176 | i2s_write_reg(dev->i2s_base, CER, 0); |
@@ -223,7 +204,7 @@ static int dw_i2s_startup(struct snd_pcm_substream *substream, | |||
223 | 204 | ||
224 | static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) | 205 | static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) |
225 | { | 206 | { |
226 | u32 ch_reg, irq; | 207 | u32 ch_reg; |
227 | struct i2s_clk_config_data *config = &dev->config; | 208 | struct i2s_clk_config_data *config = &dev->config; |
228 | 209 | ||
229 | 210 | ||
@@ -235,16 +216,12 @@ static void dw_i2s_config(struct dw_i2s_dev *dev, int stream) | |||
235 | dev->xfer_resolution); | 216 | dev->xfer_resolution); |
236 | i2s_write_reg(dev->i2s_base, TFCR(ch_reg), | 217 | i2s_write_reg(dev->i2s_base, TFCR(ch_reg), |
237 | dev->fifo_th - 1); | 218 | dev->fifo_th - 1); |
238 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | ||
239 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); | ||
240 | i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); | 219 | i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); |
241 | } else { | 220 | } else { |
242 | i2s_write_reg(dev->i2s_base, RCR(ch_reg), | 221 | i2s_write_reg(dev->i2s_base, RCR(ch_reg), |
243 | dev->xfer_resolution); | 222 | dev->xfer_resolution); |
244 | i2s_write_reg(dev->i2s_base, RFCR(ch_reg), | 223 | i2s_write_reg(dev->i2s_base, RFCR(ch_reg), |
245 | dev->fifo_th - 1); | 224 | dev->fifo_th - 1); |
246 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | ||
247 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); | ||
248 | i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); | 225 | i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); |
249 | } | 226 | } |
250 | 227 | ||
@@ -278,7 +255,7 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream, | |||
278 | break; | 255 | break; |
279 | 256 | ||
280 | default: | 257 | default: |
281 | dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt"); | 258 | dev_err(dev->dev, "designware-i2s: unsupported PCM fmt"); |
282 | return -EINVAL; | 259 | return -EINVAL; |
283 | } | 260 | } |
284 | 261 | ||
@@ -626,7 +603,7 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
626 | const struct i2s_platform_data *pdata = pdev->dev.platform_data; | 603 | const struct i2s_platform_data *pdata = pdev->dev.platform_data; |
627 | struct dw_i2s_dev *dev; | 604 | struct dw_i2s_dev *dev; |
628 | struct resource *res; | 605 | struct resource *res; |
629 | int ret; | 606 | int ret, irq; |
630 | struct snd_soc_dai_driver *dw_i2s_dai; | 607 | struct snd_soc_dai_driver *dw_i2s_dai; |
631 | const char *clk_id; | 608 | const char *clk_id; |
632 | 609 | ||
@@ -651,6 +628,16 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
651 | 628 | ||
652 | dev->dev = &pdev->dev; | 629 | dev->dev = &pdev->dev; |
653 | 630 | ||
631 | irq = platform_get_irq(pdev, 0); | ||
632 | if (irq >= 0) { | ||
633 | ret = devm_request_irq(&pdev->dev, irq, i2s_irq_handler, 0, | ||
634 | pdev->name, dev); | ||
635 | if (ret < 0) { | ||
636 | dev_err(&pdev->dev, "failed to request irq\n"); | ||
637 | return ret; | ||
638 | } | ||
639 | } | ||
640 | |||
654 | dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; | 641 | dev->i2s_reg_comp1 = I2S_COMP_PARAM_1; |
655 | dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; | 642 | dev->i2s_reg_comp2 = I2S_COMP_PARAM_2; |
656 | if (pdata) { | 643 | if (pdata) { |
@@ -697,12 +684,24 @@ static int dw_i2s_probe(struct platform_device *pdev) | |||
697 | 684 | ||
698 | if (!pdata) { | 685 | if (!pdata) { |
699 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | 686 | ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); |
700 | if (ret) { | 687 | if (ret == -EPROBE_DEFER) { |
688 | dev_err(&pdev->dev, | ||
689 | "failed to register PCM, deferring probe\n"); | ||
690 | return ret; | ||
691 | } else if (ret) { | ||
701 | dev_err(&pdev->dev, | 692 | dev_err(&pdev->dev, |
702 | "Could not register PCM: %d\n", ret); | 693 | "Could not register DMA PCM: %d\n" |
703 | goto err_clk_disable; | 694 | "falling back to PIO mode\n", ret); |
695 | ret = dw_pcm_register(pdev); | ||
696 | if (ret) { | ||
697 | dev_err(&pdev->dev, | ||
698 | "Could not register PIO PCM: %d\n", | ||
699 | ret); | ||
700 | goto err_clk_disable; | ||
701 | } | ||
704 | } | 702 | } |
705 | } | 703 | } |
704 | |||
706 | pm_runtime_enable(&pdev->dev); | 705 | pm_runtime_enable(&pdev->dev); |
707 | return 0; | 706 | return 0; |
708 | 707 | ||
diff --git a/sound/soc/dwc/designware_pcm.c b/sound/soc/dwc/designware_pcm.c new file mode 100644 index 000000000000..4a83a22fa3cb --- /dev/null +++ b/sound/soc/dwc/designware_pcm.c | |||
@@ -0,0 +1,225 @@ | |||
1 | /* | ||
2 | * ALSA SoC Synopsys PIO PCM for I2S driver | ||
3 | * | ||
4 | * sound/soc/dwc/designware_pcm.c | ||
5 | * | ||
6 | * Copyright (C) 2016 Synopsys | ||
7 | * Jose Abreu <joabreu@synopsys.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/io.h> | ||
15 | #include <linux/rcupdate.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include "local.h" | ||
19 | |||
20 | #define BUFFER_BYTES_MAX (3 * 2 * 8 * PERIOD_BYTES_MIN) | ||
21 | #define PERIOD_BYTES_MIN 4096 | ||
22 | #define PERIODS_MIN 2 | ||
23 | |||
24 | #define dw_pcm_tx_fn(sample_bits) \ | ||
25 | static unsigned int dw_pcm_tx_##sample_bits(struct dw_i2s_dev *dev, \ | ||
26 | struct snd_pcm_runtime *runtime, unsigned int tx_ptr, \ | ||
27 | bool *period_elapsed) \ | ||
28 | { \ | ||
29 | const u##sample_bits (*p)[2] = (void *)runtime->dma_area; \ | ||
30 | unsigned int period_pos = tx_ptr % runtime->period_size; \ | ||
31 | int i; \ | ||
32 | \ | ||
33 | for (i = 0; i < dev->fifo_th; i++) { \ | ||
34 | iowrite32(p[tx_ptr][0], dev->i2s_base + LRBR_LTHR(0)); \ | ||
35 | iowrite32(p[tx_ptr][1], dev->i2s_base + RRBR_RTHR(0)); \ | ||
36 | period_pos++; \ | ||
37 | if (++tx_ptr >= runtime->buffer_size) \ | ||
38 | tx_ptr = 0; \ | ||
39 | } \ | ||
40 | *period_elapsed = period_pos >= runtime->period_size; \ | ||
41 | return tx_ptr; \ | ||
42 | } | ||
43 | |||
44 | dw_pcm_tx_fn(16); | ||
45 | dw_pcm_tx_fn(32); | ||
46 | |||
47 | #undef dw_pcm_tx_fn | ||
48 | |||
49 | static const struct snd_pcm_hardware dw_pcm_hardware = { | ||
50 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
51 | SNDRV_PCM_INFO_MMAP | | ||
52 | SNDRV_PCM_INFO_MMAP_VALID | | ||
53 | SNDRV_PCM_INFO_BLOCK_TRANSFER, | ||
54 | .rates = SNDRV_PCM_RATE_32000 | | ||
55 | SNDRV_PCM_RATE_44100 | | ||
56 | SNDRV_PCM_RATE_48000, | ||
57 | .rate_min = 32000, | ||
58 | .rate_max = 48000, | ||
59 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
60 | SNDRV_PCM_FMTBIT_S32_LE, | ||
61 | .channels_min = 2, | ||
62 | .channels_max = 2, | ||
63 | .buffer_bytes_max = BUFFER_BYTES_MAX, | ||
64 | .period_bytes_min = PERIOD_BYTES_MIN, | ||
65 | .period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN, | ||
66 | .periods_min = PERIODS_MIN, | ||
67 | .periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN, | ||
68 | .fifo_size = 16, | ||
69 | }; | ||
70 | |||
71 | void dw_pcm_push_tx(struct dw_i2s_dev *dev) | ||
72 | { | ||
73 | struct snd_pcm_substream *tx_substream; | ||
74 | bool tx_active, period_elapsed; | ||
75 | |||
76 | rcu_read_lock(); | ||
77 | tx_substream = rcu_dereference(dev->tx_substream); | ||
78 | tx_active = tx_substream && snd_pcm_running(tx_substream); | ||
79 | if (tx_active) { | ||
80 | unsigned int tx_ptr = READ_ONCE(dev->tx_ptr); | ||
81 | unsigned int new_tx_ptr = dev->tx_fn(dev, tx_substream->runtime, | ||
82 | tx_ptr, &period_elapsed); | ||
83 | cmpxchg(&dev->tx_ptr, tx_ptr, new_tx_ptr); | ||
84 | |||
85 | if (period_elapsed) | ||
86 | snd_pcm_period_elapsed(tx_substream); | ||
87 | } | ||
88 | rcu_read_unlock(); | ||
89 | } | ||
90 | EXPORT_SYMBOL_GPL(dw_pcm_push_tx); | ||
91 | |||
92 | static int dw_pcm_open(struct snd_pcm_substream *substream) | ||
93 | { | ||
94 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
95 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
96 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
97 | |||
98 | snd_soc_set_runtime_hwparams(substream, &dw_pcm_hardware); | ||
99 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
100 | runtime->private_data = dev; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static int dw_pcm_close(struct snd_pcm_substream *substream) | ||
106 | { | ||
107 | synchronize_rcu(); | ||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int dw_pcm_hw_params(struct snd_pcm_substream *substream, | ||
112 | struct snd_pcm_hw_params *hw_params) | ||
113 | { | ||
114 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
115 | struct dw_i2s_dev *dev = runtime->private_data; | ||
116 | int ret; | ||
117 | |||
118 | switch (params_channels(hw_params)) { | ||
119 | case 2: | ||
120 | break; | ||
121 | default: | ||
122 | dev_err(dev->dev, "invalid channels number\n"); | ||
123 | return -EINVAL; | ||
124 | } | ||
125 | |||
126 | switch (params_format(hw_params)) { | ||
127 | case SNDRV_PCM_FORMAT_S16_LE: | ||
128 | dev->tx_fn = dw_pcm_tx_16; | ||
129 | break; | ||
130 | case SNDRV_PCM_FORMAT_S32_LE: | ||
131 | dev->tx_fn = dw_pcm_tx_32; | ||
132 | break; | ||
133 | default: | ||
134 | dev_err(dev->dev, "invalid format\n"); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) { | ||
139 | dev_err(dev->dev, "only playback is available\n"); | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | |||
143 | ret = snd_pcm_lib_malloc_pages(substream, | ||
144 | params_buffer_bytes(hw_params)); | ||
145 | if (ret < 0) | ||
146 | return ret; | ||
147 | else | ||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int dw_pcm_hw_free(struct snd_pcm_substream *substream) | ||
152 | { | ||
153 | return snd_pcm_lib_free_pages(substream); | ||
154 | } | ||
155 | |||
156 | static int dw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
157 | { | ||
158 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
159 | struct dw_i2s_dev *dev = runtime->private_data; | ||
160 | int ret = 0; | ||
161 | |||
162 | switch (cmd) { | ||
163 | case SNDRV_PCM_TRIGGER_START: | ||
164 | case SNDRV_PCM_TRIGGER_RESUME: | ||
165 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
166 | WRITE_ONCE(dev->tx_ptr, 0); | ||
167 | rcu_assign_pointer(dev->tx_substream, substream); | ||
168 | break; | ||
169 | case SNDRV_PCM_TRIGGER_STOP: | ||
170 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
171 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
172 | rcu_assign_pointer(dev->tx_substream, NULL); | ||
173 | break; | ||
174 | default: | ||
175 | ret = -EINVAL; | ||
176 | break; | ||
177 | } | ||
178 | |||
179 | return ret; | ||
180 | } | ||
181 | |||
182 | static snd_pcm_uframes_t dw_pcm_pointer(struct snd_pcm_substream *substream) | ||
183 | { | ||
184 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
185 | struct dw_i2s_dev *dev = runtime->private_data; | ||
186 | snd_pcm_uframes_t pos = READ_ONCE(dev->tx_ptr); | ||
187 | |||
188 | return pos < runtime->buffer_size ? pos : 0; | ||
189 | } | ||
190 | |||
191 | static int dw_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
192 | { | ||
193 | size_t size = dw_pcm_hardware.buffer_bytes_max; | ||
194 | |||
195 | return snd_pcm_lib_preallocate_pages_for_all(rtd->pcm, | ||
196 | SNDRV_DMA_TYPE_CONTINUOUS, | ||
197 | snd_dma_continuous_data(GFP_KERNEL), size, size); | ||
198 | } | ||
199 | |||
200 | static void dw_pcm_free(struct snd_pcm *pcm) | ||
201 | { | ||
202 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
203 | } | ||
204 | |||
205 | static const struct snd_pcm_ops dw_pcm_ops = { | ||
206 | .open = dw_pcm_open, | ||
207 | .close = dw_pcm_close, | ||
208 | .ioctl = snd_pcm_lib_ioctl, | ||
209 | .hw_params = dw_pcm_hw_params, | ||
210 | .hw_free = dw_pcm_hw_free, | ||
211 | .trigger = dw_pcm_trigger, | ||
212 | .pointer = dw_pcm_pointer, | ||
213 | }; | ||
214 | |||
215 | static const struct snd_soc_platform_driver dw_pcm_platform = { | ||
216 | .pcm_new = dw_pcm_new, | ||
217 | .pcm_free = dw_pcm_free, | ||
218 | .ops = &dw_pcm_ops, | ||
219 | }; | ||
220 | |||
221 | int dw_pcm_register(struct platform_device *pdev) | ||
222 | { | ||
223 | return devm_snd_soc_register_platform(&pdev->dev, &dw_pcm_platform); | ||
224 | } | ||
225 | EXPORT_SYMBOL_GPL(dw_pcm_register); | ||
diff --git a/sound/soc/dwc/local.h b/sound/soc/dwc/local.h new file mode 100644 index 000000000000..68afd7577343 --- /dev/null +++ b/sound/soc/dwc/local.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * Copyright (ST) 2012 Rajeev Kumar (rajeevkumar.linux@gmail.com) | ||
3 | * | ||
4 | * This file is licensed under the terms of the GNU General Public | ||
5 | * License version 2. This program is licensed "as is" without any | ||
6 | * warranty of any kind, whether express or implied. | ||
7 | */ | ||
8 | |||
9 | #ifndef __DESIGNWARE_LOCAL_H | ||
10 | #define __DESIGNWARE_LOCAL_H | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/device.h> | ||
14 | #include <linux/types.h> | ||
15 | #include <sound/dmaengine_pcm.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/designware_i2s.h> | ||
18 | |||
19 | /* common register for all channel */ | ||
20 | #define IER 0x000 | ||
21 | #define IRER 0x004 | ||
22 | #define ITER 0x008 | ||
23 | #define CER 0x00C | ||
24 | #define CCR 0x010 | ||
25 | #define RXFFR 0x014 | ||
26 | #define TXFFR 0x018 | ||
27 | |||
28 | /* Interrupt status register fields */ | ||
29 | #define ISR_TXFO BIT(5) | ||
30 | #define ISR_TXFE BIT(4) | ||
31 | #define ISR_RXFO BIT(1) | ||
32 | #define ISR_RXDA BIT(0) | ||
33 | |||
34 | /* I2STxRxRegisters for all channels */ | ||
35 | #define LRBR_LTHR(x) (0x40 * x + 0x020) | ||
36 | #define RRBR_RTHR(x) (0x40 * x + 0x024) | ||
37 | #define RER(x) (0x40 * x + 0x028) | ||
38 | #define TER(x) (0x40 * x + 0x02C) | ||
39 | #define RCR(x) (0x40 * x + 0x030) | ||
40 | #define TCR(x) (0x40 * x + 0x034) | ||
41 | #define ISR(x) (0x40 * x + 0x038) | ||
42 | #define IMR(x) (0x40 * x + 0x03C) | ||
43 | #define ROR(x) (0x40 * x + 0x040) | ||
44 | #define TOR(x) (0x40 * x + 0x044) | ||
45 | #define RFCR(x) (0x40 * x + 0x048) | ||
46 | #define TFCR(x) (0x40 * x + 0x04C) | ||
47 | #define RFF(x) (0x40 * x + 0x050) | ||
48 | #define TFF(x) (0x40 * x + 0x054) | ||
49 | |||
50 | /* I2SCOMPRegisters */ | ||
51 | #define I2S_COMP_PARAM_2 0x01F0 | ||
52 | #define I2S_COMP_PARAM_1 0x01F4 | ||
53 | #define I2S_COMP_VERSION 0x01F8 | ||
54 | #define I2S_COMP_TYPE 0x01FC | ||
55 | |||
56 | /* | ||
57 | * Component parameter register fields - define the I2S block's | ||
58 | * configuration. | ||
59 | */ | ||
60 | #define COMP1_TX_WORDSIZE_3(r) (((r) & GENMASK(27, 25)) >> 25) | ||
61 | #define COMP1_TX_WORDSIZE_2(r) (((r) & GENMASK(24, 22)) >> 22) | ||
62 | #define COMP1_TX_WORDSIZE_1(r) (((r) & GENMASK(21, 19)) >> 19) | ||
63 | #define COMP1_TX_WORDSIZE_0(r) (((r) & GENMASK(18, 16)) >> 16) | ||
64 | #define COMP1_TX_CHANNELS(r) (((r) & GENMASK(10, 9)) >> 9) | ||
65 | #define COMP1_RX_CHANNELS(r) (((r) & GENMASK(8, 7)) >> 7) | ||
66 | #define COMP1_RX_ENABLED(r) (((r) & BIT(6)) >> 6) | ||
67 | #define COMP1_TX_ENABLED(r) (((r) & BIT(5)) >> 5) | ||
68 | #define COMP1_MODE_EN(r) (((r) & BIT(4)) >> 4) | ||
69 | #define COMP1_FIFO_DEPTH_GLOBAL(r) (((r) & GENMASK(3, 2)) >> 2) | ||
70 | #define COMP1_APB_DATA_WIDTH(r) (((r) & GENMASK(1, 0)) >> 0) | ||
71 | |||
72 | #define COMP2_RX_WORDSIZE_3(r) (((r) & GENMASK(12, 10)) >> 10) | ||
73 | #define COMP2_RX_WORDSIZE_2(r) (((r) & GENMASK(9, 7)) >> 7) | ||
74 | #define COMP2_RX_WORDSIZE_1(r) (((r) & GENMASK(5, 3)) >> 3) | ||
75 | #define COMP2_RX_WORDSIZE_0(r) (((r) & GENMASK(2, 0)) >> 0) | ||
76 | |||
77 | /* Number of entries in WORDSIZE and DATA_WIDTH parameter registers */ | ||
78 | #define COMP_MAX_WORDSIZE (1 << 3) | ||
79 | #define COMP_MAX_DATA_WIDTH (1 << 2) | ||
80 | |||
81 | #define MAX_CHANNEL_NUM 8 | ||
82 | #define MIN_CHANNEL_NUM 2 | ||
83 | |||
84 | union dw_i2s_snd_dma_data { | ||
85 | struct i2s_dma_data pd; | ||
86 | struct snd_dmaengine_dai_dma_data dt; | ||
87 | }; | ||
88 | |||
89 | struct dw_i2s_dev { | ||
90 | void __iomem *i2s_base; | ||
91 | struct clk *clk; | ||
92 | int active; | ||
93 | unsigned int capability; | ||
94 | unsigned int quirks; | ||
95 | unsigned int i2s_reg_comp1; | ||
96 | unsigned int i2s_reg_comp2; | ||
97 | struct device *dev; | ||
98 | u32 ccr; | ||
99 | u32 xfer_resolution; | ||
100 | u32 fifo_th; | ||
101 | |||
102 | /* data related to DMA transfers b/w i2s and DMAC */ | ||
103 | union dw_i2s_snd_dma_data play_dma_data; | ||
104 | union dw_i2s_snd_dma_data capture_dma_data; | ||
105 | struct i2s_clk_config_data config; | ||
106 | int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); | ||
107 | |||
108 | /* data related to PIO transfers (TX) */ | ||
109 | bool use_pio; | ||
110 | struct snd_pcm_substream __rcu *tx_substream; | ||
111 | unsigned int (*tx_fn)(struct dw_i2s_dev *dev, | ||
112 | struct snd_pcm_runtime *runtime, unsigned int tx_ptr, | ||
113 | bool *period_elapsed); | ||
114 | unsigned int tx_ptr; | ||
115 | }; | ||
116 | |||
117 | #if IS_ENABLED(CONFIG_SND_DESIGNWARE_PCM) | ||
118 | void dw_pcm_push_tx(struct dw_i2s_dev *dev); | ||
119 | int dw_pcm_register(struct platform_device *pdev); | ||
120 | #else | ||
121 | void dw_pcm_push_tx(struct dw_i2s_dev *dev) { } | ||
122 | int dw_pcm_register(struct platform_device *pdev) | ||
123 | { | ||
124 | return -EINVAL; | ||
125 | } | ||
126 | #endif | ||
127 | |||
128 | #endif | ||
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 35aabf9dc503..19bdcac71775 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -4,6 +4,7 @@ comment "Common SoC Audio options for Freescale CPUs:" | |||
4 | 4 | ||
5 | config SND_SOC_FSL_ASRC | 5 | config SND_SOC_FSL_ASRC |
6 | tristate "Asynchronous Sample Rate Converter (ASRC) module support" | 6 | tristate "Asynchronous Sample Rate Converter (ASRC) module support" |
7 | depends on HAS_DMA | ||
7 | select REGMAP_MMIO | 8 | select REGMAP_MMIO |
8 | select SND_SOC_GENERIC_DMAENGINE_PCM | 9 | select SND_SOC_GENERIC_DMAENGINE_PCM |
9 | help | 10 | help |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 151849f79863..beec7934a265 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -172,7 +172,7 @@ static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name) | |||
172 | if (*pos >= size * 2) { | 172 | if (*pos >= size * 2) { |
173 | *pos = 0; | 173 | *pos = 0; |
174 | } else if (unlikely((*pos % size) + 3 > size)) { | 174 | } else if (unlikely((*pos % size) + 3 > size)) { |
175 | dev_err(&pdev->dev, "User bit receivce buffer overflow\n"); | 175 | dev_err(&pdev->dev, "User bit receive buffer overflow\n"); |
176 | return; | 176 | return; |
177 | } | 177 | } |
178 | 178 | ||
diff --git a/sound/soc/generic/Kconfig b/sound/soc/generic/Kconfig index 610f61251640..c01c5dd68601 100644 --- a/sound/soc/generic/Kconfig +++ b/sound/soc/generic/Kconfig | |||
@@ -1,4 +1,8 @@ | |||
1 | config SND_SIMPLE_CARD_UTILS | ||
2 | tristate | ||
3 | |||
1 | config SND_SIMPLE_CARD | 4 | config SND_SIMPLE_CARD |
2 | tristate "ASoC Simple sound card support" | 5 | tristate "ASoC Simple sound card support" |
6 | select SND_SIMPLE_CARD_UTILS | ||
3 | help | 7 | help |
4 | This option enables generic simple sound card support | 8 | This option enables generic simple sound card support |
diff --git a/sound/soc/generic/Makefile b/sound/soc/generic/Makefile index 9c3b246792bf..45602ca8536e 100644 --- a/sound/soc/generic/Makefile +++ b/sound/soc/generic/Makefile | |||
@@ -1,3 +1,5 @@ | |||
1 | obj-$(CONFIG_SND_SIMPLE_CARD_UTILS) := simple-card-utils.o | ||
2 | |||
1 | snd-soc-simple-card-objs := simple-card.o | 3 | snd-soc-simple-card-objs := simple-card.o |
2 | 4 | ||
3 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o | 5 | obj-$(CONFIG_SND_SIMPLE_CARD) += snd-soc-simple-card.o |
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c new file mode 100644 index 000000000000..d89a9a1b2471 --- /dev/null +++ b/sound/soc/generic/simple-card-utils.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * simple-card-core.c | ||
3 | * | ||
4 | * Copyright (c) 2016 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
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 | #include <linux/of.h> | ||
11 | #include <sound/simple_card_utils.h> | ||
12 | |||
13 | int asoc_simple_card_parse_daifmt(struct device *dev, | ||
14 | struct device_node *node, | ||
15 | struct device_node *codec, | ||
16 | char *prefix, | ||
17 | unsigned int *retfmt) | ||
18 | { | ||
19 | struct device_node *bitclkmaster = NULL; | ||
20 | struct device_node *framemaster = NULL; | ||
21 | int prefix_len = prefix ? strlen(prefix) : 0; | ||
22 | unsigned int daifmt; | ||
23 | |||
24 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
25 | &bitclkmaster, &framemaster); | ||
26 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
27 | |||
28 | if (prefix_len && !bitclkmaster && !framemaster) { | ||
29 | /* | ||
30 | * No dai-link level and master setting was not found from | ||
31 | * sound node level, revert back to legacy DT parsing and | ||
32 | * take the settings from codec node. | ||
33 | */ | ||
34 | dev_dbg(dev, "Revert to legacy daifmt parsing\n"); | ||
35 | |||
36 | daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | | ||
37 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
38 | } else { | ||
39 | if (codec == bitclkmaster) | ||
40 | daifmt |= (codec == framemaster) ? | ||
41 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
42 | else | ||
43 | daifmt |= (codec == framemaster) ? | ||
44 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
45 | } | ||
46 | |||
47 | of_node_put(bitclkmaster); | ||
48 | of_node_put(framemaster); | ||
49 | |||
50 | *retfmt = daifmt; | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_daifmt); | ||
55 | |||
56 | int asoc_simple_card_set_dailink_name(struct device *dev, | ||
57 | struct snd_soc_dai_link *dai_link, | ||
58 | const char *fmt, ...) | ||
59 | { | ||
60 | va_list ap; | ||
61 | char *name = NULL; | ||
62 | int ret = -ENOMEM; | ||
63 | |||
64 | va_start(ap, fmt); | ||
65 | name = devm_kvasprintf(dev, GFP_KERNEL, fmt, ap); | ||
66 | va_end(ap); | ||
67 | |||
68 | if (name) { | ||
69 | ret = 0; | ||
70 | |||
71 | dai_link->name = name; | ||
72 | dai_link->stream_name = name; | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | EXPORT_SYMBOL_GPL(asoc_simple_card_set_dailink_name); | ||
78 | |||
79 | int asoc_simple_card_parse_card_name(struct snd_soc_card *card, | ||
80 | char *prefix) | ||
81 | { | ||
82 | char prop[128]; | ||
83 | int ret; | ||
84 | |||
85 | snprintf(prop, sizeof(prop), "%sname", prefix); | ||
86 | |||
87 | /* Parse the card name from DT */ | ||
88 | ret = snd_soc_of_parse_card_name(card, prop); | ||
89 | if (ret < 0) | ||
90 | return ret; | ||
91 | |||
92 | if (!card->name && card->dai_link) | ||
93 | card->name = card->dai_link->name; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | EXPORT_SYMBOL_GPL(asoc_simple_card_parse_card_name); | ||
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 466492b7d4f5..43295f024982 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -21,6 +21,12 @@ | |||
21 | #include <sound/soc-dai.h> | 21 | #include <sound/soc-dai.h> |
22 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
23 | 23 | ||
24 | struct asoc_simple_jack { | ||
25 | struct snd_soc_jack jack; | ||
26 | struct snd_soc_jack_pin pin; | ||
27 | struct snd_soc_jack_gpio gpio; | ||
28 | }; | ||
29 | |||
24 | struct simple_card_data { | 30 | struct simple_card_data { |
25 | struct snd_soc_card snd_card; | 31 | struct snd_soc_card snd_card; |
26 | struct simple_dai_props { | 32 | struct simple_dai_props { |
@@ -29,10 +35,8 @@ struct simple_card_data { | |||
29 | unsigned int mclk_fs; | 35 | unsigned int mclk_fs; |
30 | } *dai_props; | 36 | } *dai_props; |
31 | unsigned int mclk_fs; | 37 | unsigned int mclk_fs; |
32 | int gpio_hp_det; | 38 | struct asoc_simple_jack hp_jack; |
33 | int gpio_hp_det_invert; | 39 | struct asoc_simple_jack mic_jack; |
34 | int gpio_mic_det; | ||
35 | int gpio_mic_det_invert; | ||
36 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ | 40 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ |
37 | }; | 41 | }; |
38 | 42 | ||
@@ -40,6 +44,69 @@ struct simple_card_data { | |||
40 | #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) | 44 | #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) |
41 | #define simple_priv_to_props(priv, i) ((priv)->dai_props + i) | 45 | #define simple_priv_to_props(priv, i) ((priv)->dai_props + i) |
42 | 46 | ||
47 | #define PREFIX "simple-audio-card," | ||
48 | |||
49 | #define asoc_simple_card_init_hp(card, sjack, prefix)\ | ||
50 | asoc_simple_card_init_jack(card, sjack, 1, prefix) | ||
51 | #define asoc_simple_card_init_mic(card, sjack, prefix)\ | ||
52 | asoc_simple_card_init_jack(card, sjack, 0, prefix) | ||
53 | static int asoc_simple_card_init_jack(struct snd_soc_card *card, | ||
54 | struct asoc_simple_jack *sjack, | ||
55 | int is_hp, char *prefix) | ||
56 | { | ||
57 | struct device *dev = card->dev; | ||
58 | enum of_gpio_flags flags; | ||
59 | char prop[128]; | ||
60 | char *pin_name; | ||
61 | char *gpio_name; | ||
62 | int mask; | ||
63 | int det; | ||
64 | |||
65 | sjack->gpio.gpio = -ENOENT; | ||
66 | |||
67 | if (is_hp) { | ||
68 | snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix); | ||
69 | pin_name = "Headphones"; | ||
70 | gpio_name = "Headphone detection"; | ||
71 | mask = SND_JACK_HEADPHONE; | ||
72 | } else { | ||
73 | snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix); | ||
74 | pin_name = "Mic Jack"; | ||
75 | gpio_name = "Mic detection"; | ||
76 | mask = SND_JACK_MICROPHONE; | ||
77 | } | ||
78 | |||
79 | det = of_get_named_gpio_flags(dev->of_node, prop, 0, &flags); | ||
80 | if (det == -EPROBE_DEFER) | ||
81 | return -EPROBE_DEFER; | ||
82 | |||
83 | if (gpio_is_valid(det)) { | ||
84 | sjack->pin.pin = pin_name; | ||
85 | sjack->pin.mask = mask; | ||
86 | |||
87 | sjack->gpio.name = gpio_name; | ||
88 | sjack->gpio.report = mask; | ||
89 | sjack->gpio.gpio = det; | ||
90 | sjack->gpio.invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
91 | sjack->gpio.debounce_time = 150; | ||
92 | |||
93 | snd_soc_card_jack_new(card, pin_name, mask, | ||
94 | &sjack->jack, | ||
95 | &sjack->pin, 1); | ||
96 | |||
97 | snd_soc_jack_add_gpios(&sjack->jack, 1, | ||
98 | &sjack->gpio); | ||
99 | } | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static void asoc_simple_card_remove_jack(struct asoc_simple_jack *sjack) | ||
105 | { | ||
106 | if (gpio_is_valid(sjack->gpio.gpio)) | ||
107 | snd_soc_jack_free_gpios(&sjack->jack, 1, &sjack->gpio); | ||
108 | } | ||
109 | |||
43 | static int asoc_simple_card_startup(struct snd_pcm_substream *substream) | 110 | static int asoc_simple_card_startup(struct snd_pcm_substream *substream) |
44 | { | 111 | { |
45 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 112 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
@@ -110,32 +177,6 @@ static struct snd_soc_ops asoc_simple_card_ops = { | |||
110 | .hw_params = asoc_simple_card_hw_params, | 177 | .hw_params = asoc_simple_card_hw_params, |
111 | }; | 178 | }; |
112 | 179 | ||
113 | static struct snd_soc_jack simple_card_hp_jack; | ||
114 | static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = { | ||
115 | { | ||
116 | .pin = "Headphones", | ||
117 | .mask = SND_JACK_HEADPHONE, | ||
118 | }, | ||
119 | }; | ||
120 | static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = { | ||
121 | .name = "Headphone detection", | ||
122 | .report = SND_JACK_HEADPHONE, | ||
123 | .debounce_time = 150, | ||
124 | }; | ||
125 | |||
126 | static struct snd_soc_jack simple_card_mic_jack; | ||
127 | static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = { | ||
128 | { | ||
129 | .pin = "Mic Jack", | ||
130 | .mask = SND_JACK_MICROPHONE, | ||
131 | }, | ||
132 | }; | ||
133 | static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = { | ||
134 | .name = "Mic detection", | ||
135 | .report = SND_JACK_MICROPHONE, | ||
136 | .debounce_time = 150, | ||
137 | }; | ||
138 | |||
139 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, | 180 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, |
140 | struct asoc_simple_dai *set) | 181 | struct asoc_simple_dai *set) |
141 | { | 182 | { |
@@ -184,30 +225,14 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
184 | if (ret < 0) | 225 | if (ret < 0) |
185 | return ret; | 226 | return ret; |
186 | 227 | ||
187 | if (gpio_is_valid(priv->gpio_hp_det)) { | 228 | ret = asoc_simple_card_init_hp(rtd->card, &priv->hp_jack, PREFIX); |
188 | snd_soc_card_jack_new(rtd->card, "Headphones", | 229 | if (ret < 0) |
189 | SND_JACK_HEADPHONE, | 230 | return ret; |
190 | &simple_card_hp_jack, | 231 | |
191 | simple_card_hp_jack_pins, | 232 | ret = asoc_simple_card_init_mic(rtd->card, &priv->hp_jack, PREFIX); |
192 | ARRAY_SIZE(simple_card_hp_jack_pins)); | 233 | if (ret < 0) |
193 | 234 | return ret; | |
194 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; | ||
195 | simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert; | ||
196 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, | ||
197 | &simple_card_hp_jack_gpio); | ||
198 | } | ||
199 | 235 | ||
200 | if (gpio_is_valid(priv->gpio_mic_det)) { | ||
201 | snd_soc_card_jack_new(rtd->card, "Mic Jack", | ||
202 | SND_JACK_MICROPHONE, | ||
203 | &simple_card_mic_jack, | ||
204 | simple_card_mic_jack_pins, | ||
205 | ARRAY_SIZE(simple_card_mic_jack_pins)); | ||
206 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; | ||
207 | simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert; | ||
208 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, | ||
209 | &simple_card_mic_jack_gpio); | ||
210 | } | ||
211 | return 0; | 236 | return 0; |
212 | } | 237 | } |
213 | 238 | ||
@@ -223,6 +248,9 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
223 | u32 val; | 248 | u32 val; |
224 | int ret; | 249 | int ret; |
225 | 250 | ||
251 | if (!np) | ||
252 | return 0; | ||
253 | |||
226 | /* | 254 | /* |
227 | * Get node via "sound-dai = <&phandle port>" | 255 | * Get node via "sound-dai = <&phandle port>" |
228 | * it will be used as xxx_of_node on soc_bind_dai_link() | 256 | * it will be used as xxx_of_node on soc_bind_dai_link() |
@@ -238,9 +266,14 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
238 | *args_count = args.args_count; | 266 | *args_count = args.args_count; |
239 | 267 | ||
240 | /* Get dai->name */ | 268 | /* Get dai->name */ |
241 | ret = snd_soc_of_get_dai_name(np, name); | 269 | if (name) { |
242 | if (ret < 0) | 270 | ret = snd_soc_of_get_dai_name(np, name); |
243 | return ret; | 271 | if (ret < 0) |
272 | return ret; | ||
273 | } | ||
274 | |||
275 | if (!dai) | ||
276 | return 0; | ||
244 | 277 | ||
245 | /* Parse TDM slot */ | 278 | /* Parse TDM slot */ |
246 | ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask, | 279 | ret = snd_soc_of_parse_tdm_slot(np, &dai->tx_slot_mask, |
@@ -275,48 +308,6 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
275 | return 0; | 308 | return 0; |
276 | } | 309 | } |
277 | 310 | ||
278 | static int asoc_simple_card_parse_daifmt(struct device_node *node, | ||
279 | struct simple_card_data *priv, | ||
280 | struct device_node *codec, | ||
281 | char *prefix, int idx) | ||
282 | { | ||
283 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | ||
284 | struct device *dev = simple_priv_to_dev(priv); | ||
285 | struct device_node *bitclkmaster = NULL; | ||
286 | struct device_node *framemaster = NULL; | ||
287 | unsigned int daifmt; | ||
288 | |||
289 | daifmt = snd_soc_of_parse_daifmt(node, prefix, | ||
290 | &bitclkmaster, &framemaster); | ||
291 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
292 | |||
293 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | ||
294 | /* | ||
295 | * No dai-link level and master setting was not found from | ||
296 | * sound node level, revert back to legacy DT parsing and | ||
297 | * take the settings from codec node. | ||
298 | */ | ||
299 | dev_dbg(dev, "Revert to legacy daifmt parsing\n"); | ||
300 | |||
301 | daifmt = snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) | | ||
302 | (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK); | ||
303 | } else { | ||
304 | if (codec == bitclkmaster) | ||
305 | daifmt |= (codec == framemaster) ? | ||
306 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
307 | else | ||
308 | daifmt |= (codec == framemaster) ? | ||
309 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
310 | } | ||
311 | |||
312 | dai_link->dai_fmt = daifmt; | ||
313 | |||
314 | of_node_put(bitclkmaster); | ||
315 | of_node_put(framemaster); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int asoc_simple_card_dai_link_of(struct device_node *node, | 311 | static int asoc_simple_card_dai_link_of(struct device_node *node, |
321 | struct simple_card_data *priv, | 312 | struct simple_card_data *priv, |
322 | int idx, | 313 | int idx, |
@@ -328,7 +319,6 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
328 | struct device_node *cpu = NULL; | 319 | struct device_node *cpu = NULL; |
329 | struct device_node *plat = NULL; | 320 | struct device_node *plat = NULL; |
330 | struct device_node *codec = NULL; | 321 | struct device_node *codec = NULL; |
331 | char *name; | ||
332 | char prop[128]; | 322 | char prop[128]; |
333 | char *prefix = ""; | 323 | char *prefix = ""; |
334 | int ret, cpu_args; | 324 | int ret, cpu_args; |
@@ -336,7 +326,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
336 | 326 | ||
337 | /* For single DAI link & old style of DT node */ | 327 | /* For single DAI link & old style of DT node */ |
338 | if (is_top_level_node) | 328 | if (is_top_level_node) |
339 | prefix = "simple-audio-card,"; | 329 | prefix = PREFIX; |
340 | 330 | ||
341 | snprintf(prop, sizeof(prop), "%scpu", prefix); | 331 | snprintf(prop, sizeof(prop), "%scpu", prefix); |
342 | cpu = of_get_child_by_name(node, prop); | 332 | cpu = of_get_child_by_name(node, prop); |
@@ -353,8 +343,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
353 | goto dai_link_of_err; | 343 | goto dai_link_of_err; |
354 | } | 344 | } |
355 | 345 | ||
356 | ret = asoc_simple_card_parse_daifmt(node, priv, | 346 | ret = asoc_simple_card_parse_daifmt(dev, node, codec, |
357 | codec, prefix, idx); | 347 | prefix, &dai_link->dai_fmt); |
358 | if (ret < 0) | 348 | if (ret < 0) |
359 | goto dai_link_of_err; | 349 | goto dai_link_of_err; |
360 | 350 | ||
@@ -374,35 +364,28 @@ static int asoc_simple_card_dai_link_of(struct device_node *node, | |||
374 | if (ret < 0) | 364 | if (ret < 0) |
375 | goto dai_link_of_err; | 365 | goto dai_link_of_err; |
376 | 366 | ||
367 | ret = asoc_simple_card_sub_parse_of(plat, NULL, | ||
368 | &dai_link->platform_of_node, | ||
369 | NULL, NULL); | ||
370 | if (ret < 0) | ||
371 | goto dai_link_of_err; | ||
372 | |||
377 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { | 373 | if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) { |
378 | ret = -EINVAL; | 374 | ret = -EINVAL; |
379 | goto dai_link_of_err; | 375 | goto dai_link_of_err; |
380 | } | 376 | } |
381 | 377 | ||
382 | if (plat) { | 378 | /* Assumes platform == cpu */ |
383 | struct of_phandle_args args; | 379 | if (!dai_link->platform_of_node) |
384 | |||
385 | ret = of_parse_phandle_with_args(plat, "sound-dai", | ||
386 | "#sound-dai-cells", 0, &args); | ||
387 | dai_link->platform_of_node = args.np; | ||
388 | } else { | ||
389 | /* Assumes platform == cpu */ | ||
390 | dai_link->platform_of_node = dai_link->cpu_of_node; | 380 | dai_link->platform_of_node = dai_link->cpu_of_node; |
391 | } | ||
392 | 381 | ||
393 | /* DAI link name is created from CPU/CODEC dai name */ | 382 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, |
394 | name = devm_kzalloc(dev, | 383 | "%s-%s", |
395 | strlen(dai_link->cpu_dai_name) + | 384 | dai_link->cpu_dai_name, |
396 | strlen(dai_link->codec_dai_name) + 2, | 385 | dai_link->codec_dai_name); |
397 | GFP_KERNEL); | 386 | if (ret < 0) |
398 | if (!name) { | ||
399 | ret = -ENOMEM; | ||
400 | goto dai_link_of_err; | 387 | goto dai_link_of_err; |
401 | } | ||
402 | 388 | ||
403 | sprintf(name, "%s-%s", dai_link->cpu_dai_name, | ||
404 | dai_link->codec_dai_name); | ||
405 | dai_link->name = dai_link->stream_name = name; | ||
406 | dai_link->ops = &asoc_simple_card_ops; | 389 | dai_link->ops = &asoc_simple_card_ops; |
407 | dai_link->init = asoc_simple_card_dai_init; | 390 | dai_link->init = asoc_simple_card_dai_init; |
408 | 391 | ||
@@ -438,42 +421,35 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
438 | struct simple_card_data *priv) | 421 | struct simple_card_data *priv) |
439 | { | 422 | { |
440 | struct device *dev = simple_priv_to_dev(priv); | 423 | struct device *dev = simple_priv_to_dev(priv); |
441 | enum of_gpio_flags flags; | ||
442 | u32 val; | 424 | u32 val; |
443 | int ret; | 425 | int ret; |
444 | 426 | ||
445 | if (!node) | 427 | if (!node) |
446 | return -EINVAL; | 428 | return -EINVAL; |
447 | 429 | ||
448 | /* Parse the card name from DT */ | ||
449 | snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); | ||
450 | |||
451 | /* The off-codec widgets */ | 430 | /* The off-codec widgets */ |
452 | if (of_property_read_bool(node, "simple-audio-card,widgets")) { | 431 | if (of_property_read_bool(node, PREFIX "widgets")) { |
453 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, | 432 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, |
454 | "simple-audio-card,widgets"); | 433 | PREFIX "widgets"); |
455 | if (ret) | 434 | if (ret) |
456 | return ret; | 435 | return ret; |
457 | } | 436 | } |
458 | 437 | ||
459 | /* DAPM routes */ | 438 | /* DAPM routes */ |
460 | if (of_property_read_bool(node, "simple-audio-card,routing")) { | 439 | if (of_property_read_bool(node, PREFIX "routing")) { |
461 | ret = snd_soc_of_parse_audio_routing(&priv->snd_card, | 440 | ret = snd_soc_of_parse_audio_routing(&priv->snd_card, |
462 | "simple-audio-card,routing"); | 441 | PREFIX "routing"); |
463 | if (ret) | 442 | if (ret) |
464 | return ret; | 443 | return ret; |
465 | } | 444 | } |
466 | 445 | ||
467 | /* Factor to mclk, used in hw_params() */ | 446 | /* Factor to mclk, used in hw_params() */ |
468 | ret = of_property_read_u32(node, "simple-audio-card,mclk-fs", &val); | 447 | ret = of_property_read_u32(node, PREFIX "mclk-fs", &val); |
469 | if (ret == 0) | 448 | if (ret == 0) |
470 | priv->mclk_fs = val; | 449 | priv->mclk_fs = val; |
471 | 450 | ||
472 | dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? | ||
473 | priv->snd_card.name : ""); | ||
474 | |||
475 | /* Single/Muti DAI link(s) & New style of DT node */ | 451 | /* Single/Muti DAI link(s) & New style of DT node */ |
476 | if (of_get_child_by_name(node, "simple-audio-card,dai-link")) { | 452 | if (of_get_child_by_name(node, PREFIX "dai-link")) { |
477 | struct device_node *np = NULL; | 453 | struct device_node *np = NULL; |
478 | int i = 0; | 454 | int i = 0; |
479 | 455 | ||
@@ -494,20 +470,9 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
494 | return ret; | 470 | return ret; |
495 | } | 471 | } |
496 | 472 | ||
497 | priv->gpio_hp_det = of_get_named_gpio_flags(node, | 473 | ret = asoc_simple_card_parse_card_name(&priv->snd_card, PREFIX); |
498 | "simple-audio-card,hp-det-gpio", 0, &flags); | 474 | if (ret) |
499 | priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | 475 | return ret; |
500 | if (priv->gpio_hp_det == -EPROBE_DEFER) | ||
501 | return -EPROBE_DEFER; | ||
502 | |||
503 | priv->gpio_mic_det = of_get_named_gpio_flags(node, | ||
504 | "simple-audio-card,mic-det-gpio", 0, &flags); | ||
505 | priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW); | ||
506 | if (priv->gpio_mic_det == -EPROBE_DEFER) | ||
507 | return -EPROBE_DEFER; | ||
508 | |||
509 | if (!priv->snd_card.name) | ||
510 | priv->snd_card.name = priv->snd_card.dai_link->name; | ||
511 | 476 | ||
512 | return 0; | 477 | return 0; |
513 | } | 478 | } |
@@ -536,7 +501,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
536 | int num_links, ret; | 501 | int num_links, ret; |
537 | 502 | ||
538 | /* Get the number of DAI links */ | 503 | /* Get the number of DAI links */ |
539 | if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) | 504 | if (np && of_get_child_by_name(np, PREFIX "dai-link")) |
540 | num_links = of_get_child_count(np); | 505 | num_links = of_get_child_count(np); |
541 | else | 506 | else |
542 | num_links = 1; | 507 | num_links = 1; |
@@ -555,9 +520,6 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
555 | priv->snd_card.dai_link = dai_link; | 520 | priv->snd_card.dai_link = dai_link; |
556 | priv->snd_card.num_links = num_links; | 521 | priv->snd_card.num_links = num_links; |
557 | 522 | ||
558 | priv->gpio_hp_det = -ENOENT; | ||
559 | priv->gpio_mic_det = -ENOENT; | ||
560 | |||
561 | /* Get room for the other properties */ | 523 | /* Get room for the other properties */ |
562 | priv->dai_props = devm_kzalloc(dev, | 524 | priv->dai_props = devm_kzalloc(dev, |
563 | sizeof(*priv->dai_props) * num_links, | 525 | sizeof(*priv->dai_props) * num_links, |
@@ -624,12 +586,8 @@ static int asoc_simple_card_remove(struct platform_device *pdev) | |||
624 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 586 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
625 | struct simple_card_data *priv = snd_soc_card_get_drvdata(card); | 587 | struct simple_card_data *priv = snd_soc_card_get_drvdata(card); |
626 | 588 | ||
627 | if (gpio_is_valid(priv->gpio_hp_det)) | 589 | asoc_simple_card_remove_jack(&priv->hp_jack); |
628 | snd_soc_jack_free_gpios(&simple_card_hp_jack, 1, | 590 | asoc_simple_card_remove_jack(&priv->mic_jack); |
629 | &simple_card_hp_jack_gpio); | ||
630 | if (gpio_is_valid(priv->gpio_mic_det)) | ||
631 | snd_soc_jack_free_gpios(&simple_card_mic_jack, 1, | ||
632 | &simple_card_mic_jack_gpio); | ||
633 | 591 | ||
634 | return asoc_simple_card_unref(card); | 592 | return asoc_simple_card_unref(card); |
635 | } | 593 | } |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 91c15abb625e..a20c3dfbcb5d 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -7,7 +7,7 @@ config SND_MFLD_MACHINE | |||
7 | help | 7 | help |
8 | 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 |
9 | 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 |
10 | Say Y if you have such a device | 10 | Say Y if you have such a device. |
11 | If unsure select "N". | 11 | If unsure select "N". |
12 | 12 | ||
13 | config SND_SST_MFLD_PLATFORM | 13 | config SND_SST_MFLD_PLATFORM |
@@ -25,7 +25,6 @@ config SND_SST_IPC_ACPI | |||
25 | tristate | 25 | tristate |
26 | select SND_SST_IPC | 26 | select SND_SST_IPC |
27 | select SND_SOC_INTEL_SST | 27 | select SND_SOC_INTEL_SST |
28 | depends on ACPI | ||
29 | 28 | ||
30 | config SND_SOC_INTEL_SST | 29 | config SND_SOC_INTEL_SST |
31 | tristate | 30 | tristate |
@@ -33,6 +32,12 @@ config SND_SOC_INTEL_SST | |||
33 | select SND_SOC_INTEL_SST_MATCH if ACPI | 32 | select SND_SOC_INTEL_SST_MATCH if ACPI |
34 | depends on (X86 || COMPILE_TEST) | 33 | depends on (X86 || COMPILE_TEST) |
35 | 34 | ||
35 | # firmware stuff depends DW_DMAC_CORE; since there is no depends-on from | ||
36 | # the reverse selection, each machine driver needs to select | ||
37 | # SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE | ||
38 | config SND_SOC_INTEL_SST_FIRMWARE | ||
39 | tristate | ||
40 | |||
36 | config SND_SOC_INTEL_SST_ACPI | 41 | config SND_SOC_INTEL_SST_ACPI |
37 | tristate | 42 | tristate |
38 | 43 | ||
@@ -48,16 +53,33 @@ config SND_SOC_INTEL_BAYTRAIL | |||
48 | config SND_SOC_INTEL_HASWELL_MACH | 53 | config SND_SOC_INTEL_HASWELL_MACH |
49 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | 54 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" |
50 | depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM | 55 | depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM |
51 | depends on DW_DMAC_CORE=y | 56 | depends on DW_DMAC_CORE |
52 | select SND_SOC_INTEL_SST | 57 | select SND_SOC_INTEL_SST |
58 | select SND_SOC_INTEL_SST_FIRMWARE | ||
53 | select SND_SOC_INTEL_HASWELL | 59 | select SND_SOC_INTEL_HASWELL |
54 | select SND_SOC_RT5640 | 60 | select SND_SOC_RT5640 |
55 | help | 61 | help |
56 | This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell | 62 | This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell |
57 | Ultrabook platforms. | 63 | Ultrabook platforms. |
58 | Say Y if you have such a device | 64 | Say Y if you have such a device. |
59 | If unsure select "N". | 65 | If unsure select "N". |
60 | 66 | ||
67 | config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH | ||
68 | tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" | ||
69 | depends on X86 && ACPI && I2C | ||
70 | select SND_SOC_INTEL_SST | ||
71 | select SND_SOC_INTEL_SKYLAKE | ||
72 | select SND_SOC_DA7219 | ||
73 | select SND_SOC_MAX98357A | ||
74 | select SND_SOC_DMIC | ||
75 | select SND_SOC_HDAC_HDMI | ||
76 | select SND_HDA_DSP_LOADER | ||
77 | help | ||
78 | This adds support for ASoC machine driver for Broxton-P platforms | ||
79 | with DA7219 + MAX98357A I2S audio codec. | ||
80 | Say Y if you have such a device. | ||
81 | If unsure select "N". | ||
82 | |||
61 | config SND_SOC_INTEL_BXT_RT298_MACH | 83 | config SND_SOC_INTEL_BXT_RT298_MACH |
62 | tristate "ASoC Audio driver for Broxton with RT298 I2S mode" | 84 | tristate "ASoC Audio driver for Broxton with RT298 I2S mode" |
63 | depends on X86 && ACPI && I2C | 85 | depends on X86 && ACPI && I2C |
@@ -70,26 +92,28 @@ config SND_SOC_INTEL_BXT_RT298_MACH | |||
70 | help | 92 | help |
71 | This adds support for ASoC machine driver for Broxton platforms | 93 | This adds support for ASoC machine driver for Broxton platforms |
72 | with RT286 I2S audio codec. | 94 | with RT286 I2S audio codec. |
73 | Say Y if you have such a device | 95 | Say Y if you have such a device. |
74 | If unsure select "N". | 96 | If unsure select "N". |
75 | 97 | ||
76 | config SND_SOC_INTEL_BYT_RT5640_MACH | 98 | config SND_SOC_INTEL_BYT_RT5640_MACH |
77 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" | 99 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" |
78 | depends on X86_INTEL_LPSS && I2C | 100 | depends on X86_INTEL_LPSS && I2C |
79 | depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) | 101 | depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) |
80 | select SND_SOC_INTEL_SST | 102 | select SND_SOC_INTEL_SST |
103 | select SND_SOC_INTEL_SST_FIRMWARE | ||
81 | select SND_SOC_INTEL_BAYTRAIL | 104 | select SND_SOC_INTEL_BAYTRAIL |
82 | select SND_SOC_RT5640 | 105 | select SND_SOC_RT5640 |
83 | help | 106 | help |
84 | This adds audio driver for Intel Baytrail platform based boards | 107 | This adds audio driver for Intel Baytrail platform based boards |
85 | with the RT5640 audio codec. This driver is deprecated, use | 108 | with the RT5640 audio codec. This driver is deprecated, use |
86 | SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality | 109 | SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. |
87 | 110 | ||
88 | config SND_SOC_INTEL_BYT_MAX98090_MACH | 111 | config SND_SOC_INTEL_BYT_MAX98090_MACH |
89 | tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" | 112 | tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" |
90 | depends on X86_INTEL_LPSS && I2C | 113 | depends on X86_INTEL_LPSS && I2C |
91 | depends on DW_DMAC_CORE=y && (SND_SST_IPC_ACPI = n) | 114 | depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) |
92 | select SND_SOC_INTEL_SST | 115 | select SND_SOC_INTEL_SST |
116 | select SND_SOC_INTEL_SST_FIRMWARE | ||
93 | select SND_SOC_INTEL_BAYTRAIL | 117 | select SND_SOC_INTEL_BAYTRAIL |
94 | select SND_SOC_MAX98090 | 118 | select SND_SOC_MAX98090 |
95 | help | 119 | help |
@@ -100,19 +124,20 @@ config SND_SOC_INTEL_BROADWELL_MACH | |||
100 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" | 124 | tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" |
101 | depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ | 125 | depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ |
102 | I2C_DESIGNWARE_PLATFORM | 126 | I2C_DESIGNWARE_PLATFORM |
103 | depends on DW_DMAC_CORE=y | 127 | depends on DW_DMAC_CORE |
104 | select SND_SOC_INTEL_SST | 128 | select SND_SOC_INTEL_SST |
129 | select SND_SOC_INTEL_SST_FIRMWARE | ||
105 | select SND_SOC_INTEL_HASWELL | 130 | select SND_SOC_INTEL_HASWELL |
106 | select SND_SOC_RT286 | 131 | select SND_SOC_RT286 |
107 | help | 132 | help |
108 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell | 133 | This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell |
109 | Ultrabook platforms. | 134 | Ultrabook platforms. |
110 | Say Y if you have such a device | 135 | Say Y if you have such a device. |
111 | If unsure select "N". | 136 | If unsure select "N". |
112 | 137 | ||
113 | config SND_SOC_INTEL_BYTCR_RT5640_MACH | 138 | config SND_SOC_INTEL_BYTCR_RT5640_MACH |
114 | tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" | 139 | tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" |
115 | depends on X86 && I2C | 140 | depends on X86 && I2C && ACPI |
116 | select SND_SOC_RT5640 | 141 | select SND_SOC_RT5640 |
117 | select SND_SST_MFLD_PLATFORM | 142 | select SND_SST_MFLD_PLATFORM |
118 | select SND_SST_IPC_ACPI | 143 | select SND_SST_IPC_ACPI |
@@ -120,12 +145,12 @@ config SND_SOC_INTEL_BYTCR_RT5640_MACH | |||
120 | help | 145 | help |
121 | This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR | 146 | This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR |
122 | platforms with RT5640 audio codec. | 147 | platforms with RT5640 audio codec. |
123 | Say Y if you have such a device | 148 | Say Y if you have such a device. |
124 | If unsure select "N". | 149 | If unsure select "N". |
125 | 150 | ||
126 | config SND_SOC_INTEL_BYTCR_RT5651_MACH | 151 | config SND_SOC_INTEL_BYTCR_RT5651_MACH |
127 | tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" | 152 | tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" |
128 | depends on X86 && I2C | 153 | depends on X86 && I2C && ACPI |
129 | select SND_SOC_RT5651 | 154 | select SND_SOC_RT5651 |
130 | select SND_SST_MFLD_PLATFORM | 155 | select SND_SST_MFLD_PLATFORM |
131 | select SND_SST_IPC_ACPI | 156 | select SND_SST_IPC_ACPI |
@@ -133,12 +158,12 @@ config SND_SOC_INTEL_BYTCR_RT5651_MACH | |||
133 | help | 158 | help |
134 | This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR | 159 | This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR |
135 | platforms with RT5651 audio codec. | 160 | platforms with RT5651 audio codec. |
136 | Say Y if you have such a device | 161 | Say Y if you have such a device. |
137 | If unsure select "N". | 162 | If unsure select "N". |
138 | 163 | ||
139 | config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | 164 | config SND_SOC_INTEL_CHT_BSW_RT5672_MACH |
140 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" | 165 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" |
141 | depends on X86_INTEL_LPSS && I2C | 166 | depends on X86_INTEL_LPSS && I2C && ACPI |
142 | select SND_SOC_RT5670 | 167 | select SND_SOC_RT5670 |
143 | select SND_SST_MFLD_PLATFORM | 168 | select SND_SST_MFLD_PLATFORM |
144 | select SND_SST_IPC_ACPI | 169 | select SND_SST_IPC_ACPI |
@@ -146,12 +171,12 @@ config SND_SOC_INTEL_CHT_BSW_RT5672_MACH | |||
146 | help | 171 | help |
147 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | 172 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell |
148 | platforms with RT5672 audio codec. | 173 | platforms with RT5672 audio codec. |
149 | Say Y if you have such a device | 174 | Say Y if you have such a device. |
150 | If unsure select "N". | 175 | If unsure select "N". |
151 | 176 | ||
152 | config SND_SOC_INTEL_CHT_BSW_RT5645_MACH | 177 | config SND_SOC_INTEL_CHT_BSW_RT5645_MACH |
153 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" | 178 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" |
154 | depends on X86_INTEL_LPSS && I2C | 179 | depends on X86_INTEL_LPSS && I2C && ACPI |
155 | select SND_SOC_RT5645 | 180 | select SND_SOC_RT5645 |
156 | select SND_SST_MFLD_PLATFORM | 181 | select SND_SST_MFLD_PLATFORM |
157 | select SND_SST_IPC_ACPI | 182 | select SND_SST_IPC_ACPI |
@@ -163,16 +188,16 @@ config SND_SOC_INTEL_CHT_BSW_RT5645_MACH | |||
163 | 188 | ||
164 | config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH | 189 | config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH |
165 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" | 190 | tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" |
166 | depends on X86_INTEL_LPSS && I2C | 191 | depends on X86_INTEL_LPSS && I2C && ACPI |
167 | select SND_SOC_MAX98090 | 192 | select SND_SOC_MAX98090 |
168 | select SND_SOC_TS3A227E | 193 | select SND_SOC_TS3A227E |
169 | select SND_SST_MFLD_PLATFORM | 194 | select SND_SST_MFLD_PLATFORM |
170 | select SND_SST_IPC_ACPI | 195 | select SND_SST_IPC_ACPI |
171 | select SND_SOC_INTEL_SST_MATCH if ACPI | 196 | select SND_SOC_INTEL_SST_MATCH if ACPI |
172 | help | 197 | help |
173 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell | 198 | This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell |
174 | platforms with MAX98090 audio codec it also can support TI jack chip as aux device. | 199 | platforms with MAX98090 audio codec it also can support TI jack chip as aux device. |
175 | If unsure select "N". | 200 | If unsure select "N". |
176 | 201 | ||
177 | config SND_SOC_INTEL_SKYLAKE | 202 | config SND_SOC_INTEL_SKYLAKE |
178 | tristate | 203 | tristate |
@@ -192,7 +217,7 @@ config SND_SOC_INTEL_SKL_RT286_MACH | |||
192 | help | 217 | help |
193 | This adds support for ASoC machine driver for Skylake platforms | 218 | This adds support for ASoC machine driver for Skylake platforms |
194 | with RT286 I2S audio codec. | 219 | with RT286 I2S audio codec. |
195 | Say Y if you have such a device | 220 | Say Y if you have such a device. |
196 | If unsure select "N". | 221 | If unsure select "N". |
197 | 222 | ||
198 | config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH | 223 | config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH |
@@ -207,7 +232,7 @@ config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH | |||
207 | help | 232 | help |
208 | This adds support for ASoC Onboard Codec I2S machine driver. This will | 233 | This adds support for ASoC Onboard Codec I2S machine driver. This will |
209 | create an alsa sound card for NAU88L25 + SSM4567. | 234 | create an alsa sound card for NAU88L25 + SSM4567. |
210 | Say Y if you have such a device | 235 | Say Y if you have such a device. |
211 | If unsure select "N". | 236 | If unsure select "N". |
212 | 237 | ||
213 | config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH | 238 | config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH |
@@ -222,5 +247,5 @@ config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH | |||
222 | help | 247 | help |
223 | This adds support for ASoC Onboard Codec I2S machine driver. This will | 248 | This adds support for ASoC Onboard Codec I2S machine driver. This will |
224 | create an alsa sound card for NAU88L25 + MAX98357A. | 249 | create an alsa sound card for NAU88L25 + MAX98357A. |
225 | Say Y if you have such a device | 250 | Say Y if you have such a device. |
226 | If unsure select "N". | 251 | If unsure select "N". |
diff --git a/sound/soc/intel/atom/sst/sst_acpi.c b/sound/soc/intel/atom/sst/sst_acpi.c index 3bc4b63b2f9d..4d3184971227 100644 --- a/sound/soc/intel/atom/sst/sst_acpi.c +++ b/sound/soc/intel/atom/sst/sst_acpi.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/firmware.h> | 28 | #include <linux/firmware.h> |
29 | #include <linux/pm_runtime.h> | 29 | #include <linux/pm_runtime.h> |
30 | #include <linux/pm_qos.h> | 30 | #include <linux/pm_qos.h> |
31 | #include <linux/dmi.h> | ||
31 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
32 | #include <asm/platform_sst_audio.h> | 33 | #include <asm/platform_sst_audio.h> |
33 | #include <sound/core.h> | 34 | #include <sound/core.h> |
@@ -237,6 +238,9 @@ static int sst_acpi_probe(struct platform_device *pdev) | |||
237 | dev_err(dev, "No matching machine driver found\n"); | 238 | dev_err(dev, "No matching machine driver found\n"); |
238 | return -ENODEV; | 239 | return -ENODEV; |
239 | } | 240 | } |
241 | if (mach->machine_quirk) | ||
242 | mach = mach->machine_quirk(mach); | ||
243 | |||
240 | pdata = mach->pdata; | 244 | pdata = mach->pdata; |
241 | 245 | ||
242 | ret = kstrtouint(id->id, 16, &dev_id); | 246 | ret = kstrtouint(id->id, 16, &dev_id); |
@@ -320,6 +324,44 @@ static int sst_acpi_remove(struct platform_device *pdev) | |||
320 | return 0; | 324 | return 0; |
321 | } | 325 | } |
322 | 326 | ||
327 | static unsigned long cht_machine_id; | ||
328 | |||
329 | #define CHT_SURFACE_MACH 1 | ||
330 | |||
331 | static int cht_surface_quirk_cb(const struct dmi_system_id *id) | ||
332 | { | ||
333 | cht_machine_id = CHT_SURFACE_MACH; | ||
334 | return 1; | ||
335 | } | ||
336 | |||
337 | |||
338 | static const struct dmi_system_id cht_table[] = { | ||
339 | { | ||
340 | .callback = cht_surface_quirk_cb, | ||
341 | .matches = { | ||
342 | DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), | ||
343 | DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), | ||
344 | }, | ||
345 | }, | ||
346 | }; | ||
347 | |||
348 | |||
349 | static struct sst_acpi_mach cht_surface_mach = { | ||
350 | "10EC5640", "cht-bsw-rt5645", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, | ||
351 | &chv_platform_data }; | ||
352 | |||
353 | static struct sst_acpi_mach *cht_quirk(void *arg) | ||
354 | { | ||
355 | struct sst_acpi_mach *mach = arg; | ||
356 | |||
357 | dmi_check_system(cht_table); | ||
358 | |||
359 | if (cht_machine_id == CHT_SURFACE_MACH) | ||
360 | return &cht_surface_mach; | ||
361 | else | ||
362 | return mach; | ||
363 | } | ||
364 | |||
323 | static struct sst_acpi_mach sst_acpi_bytcr[] = { | 365 | static struct sst_acpi_mach sst_acpi_bytcr[] = { |
324 | {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, | 366 | {"10EC5640", "bytcr_rt5640", "intel/fw_sst_0f28.bin", "bytcr_rt5640", NULL, |
325 | &byt_rvp_platform_data }, | 367 | &byt_rvp_platform_data }, |
@@ -343,7 +385,7 @@ static struct sst_acpi_mach sst_acpi_chv[] = { | |||
343 | {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, | 385 | {"193C9890", "cht-bsw-max98090", "intel/fw_sst_22a8.bin", "cht-bsw", NULL, |
344 | &chv_platform_data }, | 386 | &chv_platform_data }, |
345 | /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ | 387 | /* some CHT-T platforms rely on RT5640, use Baytrail machine driver */ |
346 | {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", NULL, | 388 | {"10EC5640", "bytcr_rt5640", "intel/fw_sst_22a8.bin", "bytcr_rt5640", cht_quirk, |
347 | &chv_platform_data }, | 389 | &chv_platform_data }, |
348 | 390 | ||
349 | {}, | 391 | {}, |
diff --git a/sound/soc/intel/boards/Makefile b/sound/soc/intel/boards/Makefile index a8506774f510..dac03a06bfd8 100644 --- a/sound/soc/intel/boards/Makefile +++ b/sound/soc/intel/boards/Makefile | |||
@@ -2,6 +2,7 @@ snd-soc-sst-haswell-objs := haswell.o | |||
2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | 2 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o |
3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o | 3 | snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o |
4 | snd-soc-sst-broadwell-objs := broadwell.o | 4 | snd-soc-sst-broadwell-objs := broadwell.o |
5 | snd-soc-sst-bxt-da7219_max98357a-objs := bxt_da7219_max98357a.o | ||
5 | snd-soc-sst-bxt-rt298-objs := bxt_rt298.o | 6 | snd-soc-sst-bxt-rt298-objs := bxt_rt298.o |
6 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o | 7 | snd-soc-sst-bytcr-rt5640-objs := bytcr_rt5640.o |
7 | snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o | 8 | snd-soc-sst-bytcr-rt5651-objs := bytcr_rt5651.o |
@@ -15,6 +16,7 @@ snd-soc-skl_nau88l25_ssm4567-objs := skl_nau88l25_ssm4567.o | |||
15 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | 16 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o |
16 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | 17 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o |
17 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o | 18 | obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o |
19 | obj-$(CONFIG_SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH) += snd-soc-sst-bxt-da7219_max98357a.o | ||
18 | obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o | 20 | obj-$(CONFIG_SND_SOC_INTEL_BXT_RT298_MACH) += snd-soc-sst-bxt-rt298.o |
19 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o | 21 | obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o |
20 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o | 22 | obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-rt5640.o |
diff --git a/sound/soc/intel/boards/bxt_da7219_max98357a.c b/sound/soc/intel/boards/bxt_da7219_max98357a.c new file mode 100644 index 000000000000..3774b117d365 --- /dev/null +++ b/sound/soc/intel/boards/bxt_da7219_max98357a.c | |||
@@ -0,0 +1,460 @@ | |||
1 | /* | ||
2 | * Intel Broxton-P I2S Machine Driver | ||
3 | * | ||
4 | * Copyright (C) 2016, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * Modified from: | ||
7 | * Intel Skylake I2S Machine driver | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License version | ||
11 | * 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/jack.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include "../../codecs/hdac_hdmi.h" | ||
27 | #include "../../codecs/da7219.h" | ||
28 | #include "../../codecs/da7219-aad.h" | ||
29 | |||
30 | #define BXT_DIALOG_CODEC_DAI "da7219-hifi" | ||
31 | #define BXT_MAXIM_CODEC_DAI "HiFi" | ||
32 | #define DUAL_CHANNEL 2 | ||
33 | |||
34 | static struct snd_soc_jack broxton_headset; | ||
35 | |||
36 | enum { | ||
37 | BXT_DPCM_AUDIO_PB = 0, | ||
38 | BXT_DPCM_AUDIO_CP, | ||
39 | BXT_DPCM_AUDIO_REF_CP, | ||
40 | BXT_DPCM_AUDIO_HDMI1_PB, | ||
41 | BXT_DPCM_AUDIO_HDMI2_PB, | ||
42 | BXT_DPCM_AUDIO_HDMI3_PB, | ||
43 | }; | ||
44 | |||
45 | static const struct snd_kcontrol_new broxton_controls[] = { | ||
46 | SOC_DAPM_PIN_SWITCH("Headphone Jack"), | ||
47 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
48 | SOC_DAPM_PIN_SWITCH("Spk"), | ||
49 | }; | ||
50 | |||
51 | static const struct snd_soc_dapm_widget broxton_widgets[] = { | ||
52 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
53 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
54 | SND_SOC_DAPM_SPK("Spk", NULL), | ||
55 | SND_SOC_DAPM_MIC("SoC DMIC", NULL), | ||
56 | SND_SOC_DAPM_SPK("HDMI1", NULL), | ||
57 | SND_SOC_DAPM_SPK("HDMI2", NULL), | ||
58 | SND_SOC_DAPM_SPK("HDMI3", NULL), | ||
59 | }; | ||
60 | |||
61 | static const struct snd_soc_dapm_route broxton_map[] = { | ||
62 | /* HP jack connectors - unknown if we have jack detection */ | ||
63 | {"Headphone Jack", NULL, "HPL"}, | ||
64 | {"Headphone Jack", NULL, "HPR"}, | ||
65 | |||
66 | /* speaker */ | ||
67 | {"Spk", NULL, "Speaker"}, | ||
68 | |||
69 | /* other jacks */ | ||
70 | {"MIC", NULL, "Headset Mic"}, | ||
71 | |||
72 | /* digital mics */ | ||
73 | {"DMic", NULL, "SoC DMIC"}, | ||
74 | |||
75 | /* CODEC BE connections */ | ||
76 | {"HiFi Playback", NULL, "ssp5 Tx"}, | ||
77 | {"ssp5 Tx", NULL, "codec0_out"}, | ||
78 | |||
79 | {"Playback", NULL, "ssp1 Tx"}, | ||
80 | {"ssp1 Tx", NULL, "codec1_out"}, | ||
81 | |||
82 | {"codec0_in", NULL, "ssp1 Rx"}, | ||
83 | {"ssp1 Rx", NULL, "Capture"}, | ||
84 | |||
85 | {"HDMI1", NULL, "hif5 Output"}, | ||
86 | {"HDMI2", NULL, "hif6 Output"}, | ||
87 | {"HDMI3", NULL, "hif7 Output"}, | ||
88 | |||
89 | {"hifi3", NULL, "iDisp3 Tx"}, | ||
90 | {"iDisp3 Tx", NULL, "iDisp3_out"}, | ||
91 | {"hifi2", NULL, "iDisp2 Tx"}, | ||
92 | {"iDisp2 Tx", NULL, "iDisp2_out"}, | ||
93 | {"hifi1", NULL, "iDisp1 Tx"}, | ||
94 | {"iDisp1 Tx", NULL, "iDisp1_out"}, | ||
95 | |||
96 | /* DMIC */ | ||
97 | {"dmic01_hifi", NULL, "DMIC01 Rx"}, | ||
98 | {"DMIC01 Rx", NULL, "DMIC AIF"}, | ||
99 | }; | ||
100 | |||
101 | static int broxton_ssp_fixup(struct snd_soc_pcm_runtime *rtd, | ||
102 | struct snd_pcm_hw_params *params) | ||
103 | { | ||
104 | struct snd_interval *rate = hw_param_interval(params, | ||
105 | SNDRV_PCM_HW_PARAM_RATE); | ||
106 | struct snd_interval *channels = hw_param_interval(params, | ||
107 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
108 | struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
109 | |||
110 | /* The ADSP will convert the FE rate to 48k, stereo */ | ||
111 | rate->min = rate->max = 48000; | ||
112 | channels->min = channels->max = DUAL_CHANNEL; | ||
113 | |||
114 | /* set SSP to 24 bit */ | ||
115 | snd_mask_none(fmt); | ||
116 | snd_mask_set(fmt, SNDRV_PCM_FORMAT_S24_LE); | ||
117 | |||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | static int broxton_da7219_codec_init(struct snd_soc_pcm_runtime *rtd) | ||
122 | { | ||
123 | int ret; | ||
124 | struct snd_soc_codec *codec = rtd->codec; | ||
125 | |||
126 | /* | ||
127 | * Headset buttons map to the google Reference headset. | ||
128 | * These can be configured by userspace. | ||
129 | */ | ||
130 | ret = snd_soc_card_jack_new(rtd->card, "Headset Jack", | ||
131 | SND_JACK_HEADSET | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
132 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &broxton_headset, | ||
133 | NULL, 0); | ||
134 | if (ret) { | ||
135 | dev_err(rtd->dev, "Headset Jack creation failed: %d\n", ret); | ||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | da7219_aad_jack_det(codec, &broxton_headset); | ||
140 | |||
141 | snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | |||
146 | static int broxton_hdmi_init(struct snd_soc_pcm_runtime *rtd) | ||
147 | { | ||
148 | struct snd_soc_dai *dai = rtd->codec_dai; | ||
149 | |||
150 | return hdac_hdmi_jack_init(dai, BXT_DPCM_AUDIO_HDMI1_PB + dai->id); | ||
151 | } | ||
152 | |||
153 | static int broxton_da7219_fe_init(struct snd_soc_pcm_runtime *rtd) | ||
154 | { | ||
155 | struct snd_soc_dapm_context *dapm; | ||
156 | struct snd_soc_component *component = rtd->cpu_dai->component; | ||
157 | |||
158 | dapm = snd_soc_component_get_dapm(component); | ||
159 | snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static unsigned int rates[] = { | ||
165 | 48000, | ||
166 | }; | ||
167 | |||
168 | static struct snd_pcm_hw_constraint_list constraints_rates = { | ||
169 | .count = ARRAY_SIZE(rates), | ||
170 | .list = rates, | ||
171 | .mask = 0, | ||
172 | }; | ||
173 | |||
174 | static unsigned int channels[] = { | ||
175 | DUAL_CHANNEL, | ||
176 | }; | ||
177 | |||
178 | static struct snd_pcm_hw_constraint_list constraints_channels = { | ||
179 | .count = ARRAY_SIZE(channels), | ||
180 | .list = channels, | ||
181 | .mask = 0, | ||
182 | }; | ||
183 | |||
184 | static int bxt_fe_startup(struct snd_pcm_substream *substream) | ||
185 | { | ||
186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
187 | |||
188 | /* | ||
189 | * On this platform for PCM device we support, | ||
190 | * 48Khz | ||
191 | * stereo | ||
192 | * 16 bit audio | ||
193 | */ | ||
194 | |||
195 | runtime->hw.channels_max = DUAL_CHANNEL; | ||
196 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
197 | &constraints_channels); | ||
198 | |||
199 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
200 | snd_pcm_hw_constraint_msbits(runtime, 0, 16, 16); | ||
201 | |||
202 | snd_pcm_hw_constraint_list(runtime, 0, | ||
203 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static const struct snd_soc_ops broxton_da7219_fe_ops = { | ||
209 | .startup = bxt_fe_startup, | ||
210 | }; | ||
211 | |||
212 | static int broxton_da7219_hw_params(struct snd_pcm_substream *substream, | ||
213 | struct snd_pcm_hw_params *params) | ||
214 | { | ||
215 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
216 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
217 | int ret; | ||
218 | |||
219 | ret = snd_soc_dai_set_sysclk(codec_dai, | ||
220 | DA7219_CLKSRC_MCLK, 19200000, SND_SOC_CLOCK_IN); | ||
221 | if (ret < 0) | ||
222 | dev_err(codec_dai->dev, "can't set codec sysclk configuration\n"); | ||
223 | |||
224 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
225 | DA7219_SYSCLK_PLL_SRM, 0, DA7219_PLL_FREQ_OUT_98304); | ||
226 | if (ret < 0) { | ||
227 | dev_err(codec_dai->dev, "failed to start PLL: %d\n", ret); | ||
228 | return -EIO; | ||
229 | } | ||
230 | |||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int broxton_da7219_hw_free(struct snd_pcm_substream *substream) | ||
235 | { | ||
236 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
237 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
238 | int ret; | ||
239 | |||
240 | ret = snd_soc_dai_set_pll(codec_dai, 0, | ||
241 | DA7219_SYSCLK_MCLK, 0, 0); | ||
242 | if (ret < 0) { | ||
243 | dev_err(codec_dai->dev, "failed to stop PLL: %d\n", ret); | ||
244 | return -EIO; | ||
245 | } | ||
246 | |||
247 | return ret; | ||
248 | } | ||
249 | |||
250 | static struct snd_soc_ops broxton_da7219_ops = { | ||
251 | .hw_params = broxton_da7219_hw_params, | ||
252 | .hw_free = broxton_da7219_hw_free, | ||
253 | }; | ||
254 | |||
255 | /* broxton digital audio interface glue - connects codec <--> CPU */ | ||
256 | static struct snd_soc_dai_link broxton_dais[] = { | ||
257 | /* Front End DAI links */ | ||
258 | [BXT_DPCM_AUDIO_PB] | ||
259 | { | ||
260 | .name = "Bxt Audio Port", | ||
261 | .stream_name = "Audio", | ||
262 | .cpu_dai_name = "System Pin", | ||
263 | .platform_name = "0000:00:0e.0", | ||
264 | .dynamic = 1, | ||
265 | .codec_name = "snd-soc-dummy", | ||
266 | .codec_dai_name = "snd-soc-dummy-dai", | ||
267 | .nonatomic = 1, | ||
268 | .init = broxton_da7219_fe_init, | ||
269 | .trigger = { | ||
270 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
271 | .dpcm_playback = 1, | ||
272 | .ops = &broxton_da7219_fe_ops, | ||
273 | }, | ||
274 | [BXT_DPCM_AUDIO_CP] | ||
275 | { | ||
276 | .name = "Bxt Audio Capture Port", | ||
277 | .stream_name = "Audio Record", | ||
278 | .cpu_dai_name = "System Pin", | ||
279 | .platform_name = "0000:00:0e.0", | ||
280 | .dynamic = 1, | ||
281 | .codec_name = "snd-soc-dummy", | ||
282 | .codec_dai_name = "snd-soc-dummy-dai", | ||
283 | .nonatomic = 1, | ||
284 | .trigger = { | ||
285 | SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
286 | .dpcm_capture = 1, | ||
287 | .ops = &broxton_da7219_fe_ops, | ||
288 | }, | ||
289 | [BXT_DPCM_AUDIO_REF_CP] | ||
290 | { | ||
291 | .name = "Bxt Audio Reference cap", | ||
292 | .stream_name = "Refcap", | ||
293 | .cpu_dai_name = "Reference Pin", | ||
294 | .codec_name = "snd-soc-dummy", | ||
295 | .codec_dai_name = "snd-soc-dummy-dai", | ||
296 | .platform_name = "0000:00:0e.0", | ||
297 | .init = NULL, | ||
298 | .dpcm_capture = 1, | ||
299 | .ignore_suspend = 1, | ||
300 | .nonatomic = 1, | ||
301 | .dynamic = 1, | ||
302 | }, | ||
303 | [BXT_DPCM_AUDIO_HDMI1_PB] | ||
304 | { | ||
305 | .name = "Bxt HDMI Port1", | ||
306 | .stream_name = "Hdmi1", | ||
307 | .cpu_dai_name = "HDMI1 Pin", | ||
308 | .codec_name = "snd-soc-dummy", | ||
309 | .codec_dai_name = "snd-soc-dummy-dai", | ||
310 | .platform_name = "0000:00:0e.0", | ||
311 | .dpcm_playback = 1, | ||
312 | .init = NULL, | ||
313 | .nonatomic = 1, | ||
314 | .dynamic = 1, | ||
315 | }, | ||
316 | [BXT_DPCM_AUDIO_HDMI2_PB] | ||
317 | { | ||
318 | .name = "Bxt HDMI Port2", | ||
319 | .stream_name = "Hdmi2", | ||
320 | .cpu_dai_name = "HDMI2 Pin", | ||
321 | .codec_name = "snd-soc-dummy", | ||
322 | .codec_dai_name = "snd-soc-dummy-dai", | ||
323 | .platform_name = "0000:00:0e.0", | ||
324 | .dpcm_playback = 1, | ||
325 | .init = NULL, | ||
326 | .nonatomic = 1, | ||
327 | .dynamic = 1, | ||
328 | }, | ||
329 | [BXT_DPCM_AUDIO_HDMI3_PB] | ||
330 | { | ||
331 | .name = "Bxt HDMI Port3", | ||
332 | .stream_name = "Hdmi3", | ||
333 | .cpu_dai_name = "HDMI3 Pin", | ||
334 | .codec_name = "snd-soc-dummy", | ||
335 | .codec_dai_name = "snd-soc-dummy-dai", | ||
336 | .platform_name = "0000:00:0e.0", | ||
337 | .dpcm_playback = 1, | ||
338 | .init = NULL, | ||
339 | .nonatomic = 1, | ||
340 | .dynamic = 1, | ||
341 | }, | ||
342 | /* Back End DAI links */ | ||
343 | { | ||
344 | /* SSP5 - Codec */ | ||
345 | .name = "SSP5-Codec", | ||
346 | .id = 0, | ||
347 | .cpu_dai_name = "SSP5 Pin", | ||
348 | .platform_name = "0000:00:0e.0", | ||
349 | .no_pcm = 1, | ||
350 | .codec_name = "MX98357A:00", | ||
351 | .codec_dai_name = BXT_MAXIM_CODEC_DAI, | ||
352 | .dai_fmt = SND_SOC_DAIFMT_I2S | | ||
353 | SND_SOC_DAIFMT_NB_NF | | ||
354 | SND_SOC_DAIFMT_CBS_CFS, | ||
355 | .ignore_pmdown_time = 1, | ||
356 | .be_hw_params_fixup = broxton_ssp_fixup, | ||
357 | .dpcm_playback = 1, | ||
358 | }, | ||
359 | { | ||
360 | /* SSP1 - Codec */ | ||
361 | .name = "SSP1-Codec", | ||
362 | .id = 1, | ||
363 | .cpu_dai_name = "SSP1 Pin", | ||
364 | .platform_name = "0000:00:0e.0", | ||
365 | .no_pcm = 1, | ||
366 | .codec_name = "i2c-DLGS7219:00", | ||
367 | .codec_dai_name = BXT_DIALOG_CODEC_DAI, | ||
368 | .init = broxton_da7219_codec_init, | ||
369 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
370 | SND_SOC_DAIFMT_CBS_CFS, | ||
371 | .ignore_pmdown_time = 1, | ||
372 | .be_hw_params_fixup = broxton_ssp_fixup, | ||
373 | .ops = &broxton_da7219_ops, | ||
374 | .dpcm_playback = 1, | ||
375 | .dpcm_capture = 1, | ||
376 | }, | ||
377 | { | ||
378 | .name = "dmic01", | ||
379 | .id = 2, | ||
380 | .cpu_dai_name = "DMIC01 Pin", | ||
381 | .codec_name = "dmic-codec", | ||
382 | .codec_dai_name = "dmic-hifi", | ||
383 | .platform_name = "0000:00:0e.0", | ||
384 | .ignore_suspend = 1, | ||
385 | .dpcm_capture = 1, | ||
386 | .no_pcm = 1, | ||
387 | }, | ||
388 | { | ||
389 | .name = "iDisp1", | ||
390 | .id = 3, | ||
391 | .cpu_dai_name = "iDisp1 Pin", | ||
392 | .codec_name = "ehdaudio0D2", | ||
393 | .codec_dai_name = "intel-hdmi-hifi1", | ||
394 | .platform_name = "0000:00:0e.0", | ||
395 | .init = broxton_hdmi_init, | ||
396 | .dpcm_playback = 1, | ||
397 | .no_pcm = 1, | ||
398 | }, | ||
399 | { | ||
400 | .name = "iDisp2", | ||
401 | .id = 4, | ||
402 | .cpu_dai_name = "iDisp2 Pin", | ||
403 | .codec_name = "ehdaudio0D2", | ||
404 | .codec_dai_name = "intel-hdmi-hifi2", | ||
405 | .platform_name = "0000:00:0e.0", | ||
406 | .init = broxton_hdmi_init, | ||
407 | .dpcm_playback = 1, | ||
408 | .no_pcm = 1, | ||
409 | }, | ||
410 | { | ||
411 | .name = "iDisp3", | ||
412 | .id = 5, | ||
413 | .cpu_dai_name = "iDisp3 Pin", | ||
414 | .codec_name = "ehdaudio0D2", | ||
415 | .codec_dai_name = "intel-hdmi-hifi3", | ||
416 | .platform_name = "0000:00:0e.0", | ||
417 | .init = broxton_hdmi_init, | ||
418 | .dpcm_playback = 1, | ||
419 | .no_pcm = 1, | ||
420 | }, | ||
421 | }; | ||
422 | |||
423 | /* broxton audio machine driver for SPT + da7219 */ | ||
424 | static struct snd_soc_card broxton_audio_card = { | ||
425 | .name = "bxtda7219max", | ||
426 | .owner = THIS_MODULE, | ||
427 | .dai_link = broxton_dais, | ||
428 | .num_links = ARRAY_SIZE(broxton_dais), | ||
429 | .controls = broxton_controls, | ||
430 | .num_controls = ARRAY_SIZE(broxton_controls), | ||
431 | .dapm_widgets = broxton_widgets, | ||
432 | .num_dapm_widgets = ARRAY_SIZE(broxton_widgets), | ||
433 | .dapm_routes = broxton_map, | ||
434 | .num_dapm_routes = ARRAY_SIZE(broxton_map), | ||
435 | .fully_routed = true, | ||
436 | }; | ||
437 | |||
438 | static int broxton_audio_probe(struct platform_device *pdev) | ||
439 | { | ||
440 | broxton_audio_card.dev = &pdev->dev; | ||
441 | return devm_snd_soc_register_card(&pdev->dev, &broxton_audio_card); | ||
442 | } | ||
443 | |||
444 | static struct platform_driver broxton_audio = { | ||
445 | .probe = broxton_audio_probe, | ||
446 | .driver = { | ||
447 | .name = "bxt_da7219_max98357a_i2s", | ||
448 | .pm = &snd_soc_pm_ops, | ||
449 | }, | ||
450 | }; | ||
451 | module_platform_driver(broxton_audio) | ||
452 | |||
453 | /* Module information */ | ||
454 | MODULE_DESCRIPTION("Audio Machine driver-DA7219 & MAX98357A in I2S mode"); | ||
455 | MODULE_AUTHOR("Sathyanarayana Nujella <sathyanarayana.nujella@intel.com>"); | ||
456 | MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com>"); | ||
457 | MODULE_AUTHOR("Harsha Priya <harshapriya.n@intel.com>"); | ||
458 | MODULE_AUTHOR("Conrad Cooke <conrad.cooke@intel.com>"); | ||
459 | MODULE_LICENSE("GPL v2"); | ||
460 | MODULE_ALIAS("platform:bxt_da7219_max98357a_i2s"); | ||
diff --git a/sound/soc/intel/boards/bxt_rt298.c b/sound/soc/intel/boards/bxt_rt298.c index f4787515c0ed..253d7bfbf511 100644 --- a/sound/soc/intel/boards/bxt_rt298.c +++ b/sound/soc/intel/boards/bxt_rt298.c | |||
@@ -33,6 +33,7 @@ enum { | |||
33 | BXT_DPCM_AUDIO_PB = 0, | 33 | BXT_DPCM_AUDIO_PB = 0, |
34 | BXT_DPCM_AUDIO_CP, | 34 | BXT_DPCM_AUDIO_CP, |
35 | BXT_DPCM_AUDIO_REF_CP, | 35 | BXT_DPCM_AUDIO_REF_CP, |
36 | BXT_DPCM_AUDIO_DMIC_CP, | ||
36 | BXT_DPCM_AUDIO_HDMI1_PB, | 37 | BXT_DPCM_AUDIO_HDMI1_PB, |
37 | BXT_DPCM_AUDIO_HDMI2_PB, | 38 | BXT_DPCM_AUDIO_HDMI2_PB, |
38 | BXT_DPCM_AUDIO_HDMI3_PB, | 39 | BXT_DPCM_AUDIO_HDMI3_PB, |
@@ -88,6 +89,7 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { | |||
88 | /* CODEC BE connections */ | 89 | /* CODEC BE connections */ |
89 | { "AIF1 Playback", NULL, "ssp5 Tx"}, | 90 | { "AIF1 Playback", NULL, "ssp5 Tx"}, |
90 | { "ssp5 Tx", NULL, "codec0_out"}, | 91 | { "ssp5 Tx", NULL, "codec0_out"}, |
92 | { "ssp5 Tx", NULL, "codec1_out"}, | ||
91 | 93 | ||
92 | { "codec0_in", NULL, "ssp5 Rx" }, | 94 | { "codec0_in", NULL, "ssp5 Rx" }, |
93 | { "ssp5 Rx", NULL, "AIF1 Capture" }, | 95 | { "ssp5 Rx", NULL, "AIF1 Capture" }, |
@@ -104,6 +106,17 @@ static const struct snd_soc_dapm_route broxton_rt298_map[] = { | |||
104 | 106 | ||
105 | }; | 107 | }; |
106 | 108 | ||
109 | static int broxton_rt298_fe_init(struct snd_soc_pcm_runtime *rtd) | ||
110 | { | ||
111 | struct snd_soc_dapm_context *dapm; | ||
112 | struct snd_soc_component *component = rtd->cpu_dai->component; | ||
113 | |||
114 | dapm = snd_soc_component_get_dapm(component); | ||
115 | snd_soc_dapm_ignore_suspend(dapm, "Reference Capture"); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
107 | static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) | 120 | static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) |
108 | { | 121 | { |
109 | struct snd_soc_codec *codec = rtd->codec; | 122 | struct snd_soc_codec *codec = rtd->codec; |
@@ -118,6 +131,9 @@ static int broxton_rt298_codec_init(struct snd_soc_pcm_runtime *rtd) | |||
118 | return ret; | 131 | return ret; |
119 | 132 | ||
120 | rt298_mic_detect(codec, &broxton_headset); | 133 | rt298_mic_detect(codec, &broxton_headset); |
134 | |||
135 | snd_soc_dapm_ignore_suspend(&rtd->card->dapm, "SoC DMIC"); | ||
136 | |||
121 | return 0; | 137 | return 0; |
122 | } | 138 | } |
123 | 139 | ||
@@ -169,6 +185,89 @@ static struct snd_soc_ops broxton_rt298_ops = { | |||
169 | .hw_params = broxton_rt298_hw_params, | 185 | .hw_params = broxton_rt298_hw_params, |
170 | }; | 186 | }; |
171 | 187 | ||
188 | static unsigned int rates[] = { | ||
189 | 48000, | ||
190 | }; | ||
191 | |||
192 | static struct snd_pcm_hw_constraint_list constraints_rates = { | ||
193 | .count = ARRAY_SIZE(rates), | ||
194 | .list = rates, | ||
195 | .mask = 0, | ||
196 | }; | ||
197 | |||
198 | static int broxton_dmic_fixup(struct snd_soc_pcm_runtime *rtd, | ||
199 | struct snd_pcm_hw_params *params) | ||
200 | { | ||
201 | struct snd_interval *channels = hw_param_interval(params, | ||
202 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
203 | if (params_channels(params) == 2) | ||
204 | channels->min = channels->max = 2; | ||
205 | else | ||
206 | channels->min = channels->max = 4; | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static unsigned int channels_dmic[] = { | ||
212 | 2, 4, | ||
213 | }; | ||
214 | |||
215 | static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { | ||
216 | .count = ARRAY_SIZE(channels_dmic), | ||
217 | .list = channels_dmic, | ||
218 | .mask = 0, | ||
219 | }; | ||
220 | |||
221 | static int broxton_dmic_startup(struct snd_pcm_substream *substream) | ||
222 | { | ||
223 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
224 | |||
225 | runtime->hw.channels_max = 4; | ||
226 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
227 | &constraints_dmic_channels); | ||
228 | |||
229 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
230 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | ||
231 | } | ||
232 | |||
233 | static struct snd_soc_ops broxton_dmic_ops = { | ||
234 | .startup = broxton_dmic_startup, | ||
235 | }; | ||
236 | |||
237 | static unsigned int channels[] = { | ||
238 | 2, | ||
239 | }; | ||
240 | |||
241 | static struct snd_pcm_hw_constraint_list constraints_channels = { | ||
242 | .count = ARRAY_SIZE(channels), | ||
243 | .list = channels, | ||
244 | .mask = 0, | ||
245 | }; | ||
246 | |||
247 | static int bxt_fe_startup(struct snd_pcm_substream *substream) | ||
248 | { | ||
249 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
250 | |||
251 | /* | ||
252 | * on this platform for PCM device we support: | ||
253 | * 48Khz | ||
254 | * stereo | ||
255 | */ | ||
256 | |||
257 | runtime->hw.channels_max = 2; | ||
258 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
259 | &constraints_channels); | ||
260 | |||
261 | snd_pcm_hw_constraint_list(runtime, 0, | ||
262 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static const struct snd_soc_ops broxton_rt286_fe_ops = { | ||
268 | .startup = bxt_fe_startup, | ||
269 | }; | ||
270 | |||
172 | /* broxton digital audio interface glue - connects codec <--> CPU */ | 271 | /* broxton digital audio interface glue - connects codec <--> CPU */ |
173 | static struct snd_soc_dai_link broxton_rt298_dais[] = { | 272 | static struct snd_soc_dai_link broxton_rt298_dais[] = { |
174 | /* Front End DAI links */ | 273 | /* Front End DAI links */ |
@@ -182,8 +281,10 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
182 | .dynamic = 1, | 281 | .dynamic = 1, |
183 | .codec_name = "snd-soc-dummy", | 282 | .codec_name = "snd-soc-dummy", |
184 | .codec_dai_name = "snd-soc-dummy-dai", | 283 | .codec_dai_name = "snd-soc-dummy-dai", |
284 | .init = broxton_rt298_fe_init, | ||
185 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 285 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
186 | .dpcm_playback = 1, | 286 | .dpcm_playback = 1, |
287 | .ops = &broxton_rt286_fe_ops, | ||
187 | }, | 288 | }, |
188 | [BXT_DPCM_AUDIO_CP] | 289 | [BXT_DPCM_AUDIO_CP] |
189 | { | 290 | { |
@@ -197,6 +298,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
197 | .codec_dai_name = "snd-soc-dummy-dai", | 298 | .codec_dai_name = "snd-soc-dummy-dai", |
198 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | 299 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, |
199 | .dpcm_capture = 1, | 300 | .dpcm_capture = 1, |
301 | .ops = &broxton_rt286_fe_ops, | ||
200 | }, | 302 | }, |
201 | [BXT_DPCM_AUDIO_REF_CP] | 303 | [BXT_DPCM_AUDIO_REF_CP] |
202 | { | 304 | { |
@@ -211,6 +313,20 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
211 | .nonatomic = 1, | 313 | .nonatomic = 1, |
212 | .dynamic = 1, | 314 | .dynamic = 1, |
213 | }, | 315 | }, |
316 | [BXT_DPCM_AUDIO_DMIC_CP] | ||
317 | { | ||
318 | .name = "Bxt Audio DMIC cap", | ||
319 | .stream_name = "dmiccap", | ||
320 | .cpu_dai_name = "DMIC Pin", | ||
321 | .codec_name = "snd-soc-dummy", | ||
322 | .codec_dai_name = "snd-soc-dummy-dai", | ||
323 | .platform_name = "0000:00:0e.0", | ||
324 | .init = NULL, | ||
325 | .dpcm_capture = 1, | ||
326 | .nonatomic = 1, | ||
327 | .dynamic = 1, | ||
328 | .ops = &broxton_dmic_ops, | ||
329 | }, | ||
214 | [BXT_DPCM_AUDIO_HDMI1_PB] | 330 | [BXT_DPCM_AUDIO_HDMI1_PB] |
215 | { | 331 | { |
216 | .name = "Bxt HDMI Port1", | 332 | .name = "Bxt HDMI Port1", |
@@ -276,6 +392,7 @@ static struct snd_soc_dai_link broxton_rt298_dais[] = { | |||
276 | .codec_name = "dmic-codec", | 392 | .codec_name = "dmic-codec", |
277 | .codec_dai_name = "dmic-hifi", | 393 | .codec_dai_name = "dmic-hifi", |
278 | .platform_name = "0000:00:0e.0", | 394 | .platform_name = "0000:00:0e.0", |
395 | .be_hw_params_fixup = broxton_dmic_fixup, | ||
279 | .ignore_suspend = 1, | 396 | .ignore_suspend = 1, |
280 | .dpcm_capture = 1, | 397 | .dpcm_capture = 1, |
281 | .no_pcm = 1, | 398 | .no_pcm = 1, |
@@ -341,6 +458,7 @@ static struct platform_driver broxton_audio = { | |||
341 | .probe = broxton_audio_probe, | 458 | .probe = broxton_audio_probe, |
342 | .driver = { | 459 | .driver = { |
343 | .name = "bxt_alc298s_i2s", | 460 | .name = "bxt_alc298s_i2s", |
461 | .pm = &snd_soc_pm_ops, | ||
344 | }, | 462 | }, |
345 | }; | 463 | }; |
346 | module_platform_driver(broxton_audio) | 464 | module_platform_driver(broxton_audio) |
diff --git a/sound/soc/intel/boards/cht_bsw_rt5645.c b/sound/soc/intel/boards/cht_bsw_rt5645.c index d7ef292c402d..56056ed7fcfd 100644 --- a/sound/soc/intel/boards/cht_bsw_rt5645.c +++ b/sound/soc/intel/boards/cht_bsw_rt5645.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/jack.h> | 30 | #include <sound/jack.h> |
31 | #include "../../codecs/rt5645.h" | 31 | #include "../../codecs/rt5645.h" |
32 | #include "../atom/sst-atom-controls.h" | 32 | #include "../atom/sst-atom-controls.h" |
33 | #include "../common/sst-acpi.h" | ||
33 | 34 | ||
34 | #define CHT_PLAT_CLK_3_HZ 19200000 | 35 | #define CHT_PLAT_CLK_3_HZ 19200000 |
35 | #define CHT_CODEC_DAI "rt5645-aif1" | 36 | #define CHT_CODEC_DAI "rt5645-aif1" |
@@ -340,10 +341,13 @@ static struct snd_soc_card snd_soc_card_chtrt5650 = { | |||
340 | }; | 341 | }; |
341 | 342 | ||
342 | static struct cht_acpi_card snd_soc_cards[] = { | 343 | static struct cht_acpi_card snd_soc_cards[] = { |
344 | {"10EC5640", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, | ||
343 | {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, | 345 | {"10EC5645", CODEC_TYPE_RT5645, &snd_soc_card_chtrt5645}, |
344 | {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, | 346 | {"10EC5650", CODEC_TYPE_RT5650, &snd_soc_card_chtrt5650}, |
345 | }; | 347 | }; |
346 | 348 | ||
349 | static char cht_rt5640_codec_name[16]; /* i2c-<HID>:00 with HID being 8 chars */ | ||
350 | |||
347 | static int snd_cht_mc_probe(struct platform_device *pdev) | 351 | static int snd_cht_mc_probe(struct platform_device *pdev) |
348 | { | 352 | { |
349 | int ret_val = 0; | 353 | int ret_val = 0; |
@@ -351,6 +355,9 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
351 | struct cht_mc_private *drv; | 355 | struct cht_mc_private *drv; |
352 | struct snd_soc_card *card = snd_soc_cards[0].soc_card; | 356 | struct snd_soc_card *card = snd_soc_cards[0].soc_card; |
353 | char codec_name[16]; | 357 | char codec_name[16]; |
358 | struct sst_acpi_mach *mach; | ||
359 | const char *i2c_name = NULL; | ||
360 | int dai_index = 0; | ||
354 | 361 | ||
355 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); | 362 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_ATOMIC); |
356 | if (!drv) | 363 | if (!drv) |
@@ -366,12 +373,23 @@ static int snd_cht_mc_probe(struct platform_device *pdev) | |||
366 | } | 373 | } |
367 | } | 374 | } |
368 | card->dev = &pdev->dev; | 375 | card->dev = &pdev->dev; |
376 | mach = card->dev->platform_data; | ||
369 | sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); | 377 | sprintf(codec_name, "i2c-%s:00", drv->acpi_card->codec_id); |
370 | 378 | ||
371 | /* set correct codec name */ | 379 | /* set correct codec name */ |
372 | for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) | 380 | for (i = 0; i < ARRAY_SIZE(cht_dailink); i++) |
373 | if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) | 381 | if (!strcmp(card->dai_link[i].codec_name, "i2c-10EC5645:00")) { |
374 | card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); | 382 | card->dai_link[i].codec_name = kstrdup(codec_name, GFP_KERNEL); |
383 | dai_index = i; | ||
384 | } | ||
385 | |||
386 | /* fixup codec name based on HID */ | ||
387 | i2c_name = sst_acpi_find_name_from_hid(mach->id); | ||
388 | if (i2c_name != NULL) { | ||
389 | snprintf(cht_rt5640_codec_name, sizeof(cht_rt5640_codec_name), | ||
390 | "%s%s", "i2c-", i2c_name); | ||
391 | cht_dailink[dai_index].codec_name = cht_rt5640_codec_name; | ||
392 | } | ||
375 | 393 | ||
376 | snd_soc_card_set_drvdata(card, drv); | 394 | snd_soc_card_set_drvdata(card, drv); |
377 | ret_val = devm_snd_soc_register_card(&pdev->dev, card); | 395 | ret_val = devm_snd_soc_register_card(&pdev->dev, card); |
diff --git a/sound/soc/intel/boards/skl_nau88l25_max98357a.c b/sound/soc/intel/boards/skl_nau88l25_max98357a.c index d2808652b974..25db5be7fdfa 100644 --- a/sound/soc/intel/boards/skl_nau88l25_max98357a.c +++ b/sound/soc/intel/boards/skl_nau88l25_max98357a.c | |||
@@ -23,12 +23,15 @@ | |||
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include "../../codecs/nau8825.h" | 24 | #include "../../codecs/nau8825.h" |
25 | #include "../../codecs/hdac_hdmi.h" | 25 | #include "../../codecs/hdac_hdmi.h" |
26 | #include "../skylake/skl.h" | ||
26 | 27 | ||
27 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" | 28 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" |
28 | #define SKL_MAXIM_CODEC_DAI "HiFi" | 29 | #define SKL_MAXIM_CODEC_DAI "HiFi" |
30 | #define DMIC_CH(p) p->list[p->count-1] | ||
29 | 31 | ||
30 | static struct snd_soc_jack skylake_headset; | 32 | static struct snd_soc_jack skylake_headset; |
31 | static struct snd_soc_card skylake_audio_card; | 33 | static struct snd_soc_card skylake_audio_card; |
34 | static const struct snd_pcm_hw_constraint_list *dmic_constraints; | ||
32 | 35 | ||
33 | struct skl_hdmi_pcm { | 36 | struct skl_hdmi_pcm { |
34 | struct list_head head; | 37 | struct list_head head; |
@@ -339,7 +342,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, | |||
339 | struct snd_interval *channels = hw_param_interval(params, | 342 | struct snd_interval *channels = hw_param_interval(params, |
340 | SNDRV_PCM_HW_PARAM_CHANNELS); | 343 | SNDRV_PCM_HW_PARAM_CHANNELS); |
341 | 344 | ||
342 | if (params_channels(params) == 2) | 345 | if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) |
343 | channels->min = channels->max = 2; | 346 | channels->min = channels->max = 2; |
344 | else | 347 | else |
345 | channels->min = channels->max = 4; | 348 | channels->min = channels->max = 4; |
@@ -357,13 +360,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { | |||
357 | .mask = 0, | 360 | .mask = 0, |
358 | }; | 361 | }; |
359 | 362 | ||
363 | static const unsigned int dmic_2ch[] = { | ||
364 | 2, | ||
365 | }; | ||
366 | |||
367 | static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { | ||
368 | .count = ARRAY_SIZE(dmic_2ch), | ||
369 | .list = dmic_2ch, | ||
370 | .mask = 0, | ||
371 | }; | ||
372 | |||
360 | static int skylake_dmic_startup(struct snd_pcm_substream *substream) | 373 | static int skylake_dmic_startup(struct snd_pcm_substream *substream) |
361 | { | 374 | { |
362 | struct snd_pcm_runtime *runtime = substream->runtime; | 375 | struct snd_pcm_runtime *runtime = substream->runtime; |
363 | 376 | ||
364 | runtime->hw.channels_max = 4; | 377 | runtime->hw.channels_max = DMIC_CH(dmic_constraints); |
365 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 378 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
366 | &constraints_dmic_channels); | 379 | dmic_constraints); |
367 | 380 | ||
368 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | 381 | return snd_pcm_hw_constraint_list(substream->runtime, 0, |
369 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | 382 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); |
@@ -382,8 +395,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = { | |||
382 | .list = rates_16000, | 395 | .list = rates_16000, |
383 | }; | 396 | }; |
384 | 397 | ||
398 | static const unsigned int ch_mono[] = { | ||
399 | 1, | ||
400 | }; | ||
401 | |||
402 | static const struct snd_pcm_hw_constraint_list constraints_refcap = { | ||
403 | .count = ARRAY_SIZE(ch_mono), | ||
404 | .list = ch_mono, | ||
405 | }; | ||
406 | |||
385 | static int skylake_refcap_startup(struct snd_pcm_substream *substream) | 407 | static int skylake_refcap_startup(struct snd_pcm_substream *substream) |
386 | { | 408 | { |
409 | substream->runtime->hw.channels_max = 1; | ||
410 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
411 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
412 | &constraints_refcap); | ||
413 | |||
387 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | 414 | return snd_pcm_hw_constraint_list(substream->runtime, 0, |
388 | SNDRV_PCM_HW_PARAM_RATE, | 415 | SNDRV_PCM_HW_PARAM_RATE, |
389 | &constraints_16000); | 416 | &constraints_16000); |
@@ -610,6 +637,7 @@ static struct snd_soc_card skylake_audio_card = { | |||
610 | static int skylake_audio_probe(struct platform_device *pdev) | 637 | static int skylake_audio_probe(struct platform_device *pdev) |
611 | { | 638 | { |
612 | struct skl_nau8825_private *ctx; | 639 | struct skl_nau8825_private *ctx; |
640 | struct skl_machine_pdata *pdata; | ||
613 | 641 | ||
614 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | 642 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); |
615 | if (!ctx) | 643 | if (!ctx) |
@@ -620,15 +648,27 @@ static int skylake_audio_probe(struct platform_device *pdev) | |||
620 | skylake_audio_card.dev = &pdev->dev; | 648 | skylake_audio_card.dev = &pdev->dev; |
621 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | 649 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); |
622 | 650 | ||
651 | pdata = dev_get_drvdata(&pdev->dev); | ||
652 | if (pdata) | ||
653 | dmic_constraints = pdata->dmic_num == 2 ? | ||
654 | &constraints_dmic_2ch : &constraints_dmic_channels; | ||
655 | |||
623 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 656 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
624 | } | 657 | } |
625 | 658 | ||
659 | static const struct platform_device_id skl_board_ids[] = { | ||
660 | { .name = "skl_n88l25_m98357a" }, | ||
661 | { .name = "kbl_n88l25_m98357a" }, | ||
662 | { } | ||
663 | }; | ||
664 | |||
626 | static struct platform_driver skylake_audio = { | 665 | static struct platform_driver skylake_audio = { |
627 | .probe = skylake_audio_probe, | 666 | .probe = skylake_audio_probe, |
628 | .driver = { | 667 | .driver = { |
629 | .name = "skl_nau88l25_max98357a_i2s", | 668 | .name = "skl_n88l25_m98357a", |
630 | .pm = &snd_soc_pm_ops, | 669 | .pm = &snd_soc_pm_ops, |
631 | }, | 670 | }, |
671 | .id_table = skl_board_ids, | ||
632 | }; | 672 | }; |
633 | 673 | ||
634 | module_platform_driver(skylake_audio) | 674 | module_platform_driver(skylake_audio) |
@@ -637,4 +677,5 @@ module_platform_driver(skylake_audio) | |||
637 | MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); | 677 | MODULE_DESCRIPTION("Audio Machine driver-NAU88L25 & MAX98357A in I2S mode"); |
638 | MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); | 678 | MODULE_AUTHOR("Rohit Ainapure <rohit.m.ainapure@intel.com"); |
639 | MODULE_LICENSE("GPL v2"); | 679 | MODULE_LICENSE("GPL v2"); |
640 | MODULE_ALIAS("platform:skl_nau88l25_max98357a_i2s"); | 680 | MODULE_ALIAS("platform:skl_n88l25_m98357a"); |
681 | MODULE_ALIAS("platform:kbl_n88l25_m98357a"); | ||
diff --git a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c index e19aa99c4f72..69c5d5da4e86 100644 --- a/sound/soc/intel/boards/skl_nau88l25_ssm4567.c +++ b/sound/soc/intel/boards/skl_nau88l25_ssm4567.c | |||
@@ -27,12 +27,15 @@ | |||
27 | #include <sound/pcm_params.h> | 27 | #include <sound/pcm_params.h> |
28 | #include "../../codecs/nau8825.h" | 28 | #include "../../codecs/nau8825.h" |
29 | #include "../../codecs/hdac_hdmi.h" | 29 | #include "../../codecs/hdac_hdmi.h" |
30 | #include "../skylake/skl.h" | ||
30 | 31 | ||
31 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" | 32 | #define SKL_NUVOTON_CODEC_DAI "nau8825-hifi" |
32 | #define SKL_SSM_CODEC_DAI "ssm4567-hifi" | 33 | #define SKL_SSM_CODEC_DAI "ssm4567-hifi" |
34 | #define DMIC_CH(p) p->list[p->count-1] | ||
33 | 35 | ||
34 | static struct snd_soc_jack skylake_headset; | 36 | static struct snd_soc_jack skylake_headset; |
35 | static struct snd_soc_card skylake_audio_card; | 37 | static struct snd_soc_card skylake_audio_card; |
38 | static const struct snd_pcm_hw_constraint_list *dmic_constraints; | ||
36 | 39 | ||
37 | struct skl_hdmi_pcm { | 40 | struct skl_hdmi_pcm { |
38 | struct list_head head; | 41 | struct list_head head; |
@@ -367,7 +370,7 @@ static int skylake_dmic_fixup(struct snd_soc_pcm_runtime *rtd, | |||
367 | { | 370 | { |
368 | struct snd_interval *channels = hw_param_interval(params, | 371 | struct snd_interval *channels = hw_param_interval(params, |
369 | SNDRV_PCM_HW_PARAM_CHANNELS); | 372 | SNDRV_PCM_HW_PARAM_CHANNELS); |
370 | if (params_channels(params) == 2) | 373 | if (params_channels(params) == 2 || DMIC_CH(dmic_constraints) == 2) |
371 | channels->min = channels->max = 2; | 374 | channels->min = channels->max = 2; |
372 | else | 375 | else |
373 | channels->min = channels->max = 4; | 376 | channels->min = channels->max = 4; |
@@ -405,13 +408,23 @@ static struct snd_pcm_hw_constraint_list constraints_dmic_channels = { | |||
405 | .mask = 0, | 408 | .mask = 0, |
406 | }; | 409 | }; |
407 | 410 | ||
411 | static const unsigned int dmic_2ch[] = { | ||
412 | 2, | ||
413 | }; | ||
414 | |||
415 | static const struct snd_pcm_hw_constraint_list constraints_dmic_2ch = { | ||
416 | .count = ARRAY_SIZE(dmic_2ch), | ||
417 | .list = dmic_2ch, | ||
418 | .mask = 0, | ||
419 | }; | ||
420 | |||
408 | static int skylake_dmic_startup(struct snd_pcm_substream *substream) | 421 | static int skylake_dmic_startup(struct snd_pcm_substream *substream) |
409 | { | 422 | { |
410 | struct snd_pcm_runtime *runtime = substream->runtime; | 423 | struct snd_pcm_runtime *runtime = substream->runtime; |
411 | 424 | ||
412 | runtime->hw.channels_max = 4; | 425 | runtime->hw.channels_max = DMIC_CH(dmic_constraints); |
413 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 426 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
414 | &constraints_dmic_channels); | 427 | dmic_constraints); |
415 | 428 | ||
416 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | 429 | return snd_pcm_hw_constraint_list(substream->runtime, 0, |
417 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); | 430 | SNDRV_PCM_HW_PARAM_RATE, &constraints_rates); |
@@ -430,8 +443,22 @@ static struct snd_pcm_hw_constraint_list constraints_16000 = { | |||
430 | .list = rates_16000, | 443 | .list = rates_16000, |
431 | }; | 444 | }; |
432 | 445 | ||
446 | static const unsigned int ch_mono[] = { | ||
447 | 1, | ||
448 | }; | ||
449 | |||
450 | static const struct snd_pcm_hw_constraint_list constraints_refcap = { | ||
451 | .count = ARRAY_SIZE(ch_mono), | ||
452 | .list = ch_mono, | ||
453 | }; | ||
454 | |||
433 | static int skylake_refcap_startup(struct snd_pcm_substream *substream) | 455 | static int skylake_refcap_startup(struct snd_pcm_substream *substream) |
434 | { | 456 | { |
457 | substream->runtime->hw.channels_max = 1; | ||
458 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
459 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
460 | &constraints_refcap); | ||
461 | |||
435 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | 462 | return snd_pcm_hw_constraint_list(substream->runtime, 0, |
436 | SNDRV_PCM_HW_PARAM_RATE, | 463 | SNDRV_PCM_HW_PARAM_RATE, |
437 | &constraints_16000); | 464 | &constraints_16000); |
@@ -662,6 +689,7 @@ static struct snd_soc_card skylake_audio_card = { | |||
662 | static int skylake_audio_probe(struct platform_device *pdev) | 689 | static int skylake_audio_probe(struct platform_device *pdev) |
663 | { | 690 | { |
664 | struct skl_nau88125_private *ctx; | 691 | struct skl_nau88125_private *ctx; |
692 | struct skl_machine_pdata *pdata; | ||
665 | 693 | ||
666 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); | 694 | ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_ATOMIC); |
667 | if (!ctx) | 695 | if (!ctx) |
@@ -672,15 +700,27 @@ static int skylake_audio_probe(struct platform_device *pdev) | |||
672 | skylake_audio_card.dev = &pdev->dev; | 700 | skylake_audio_card.dev = &pdev->dev; |
673 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); | 701 | snd_soc_card_set_drvdata(&skylake_audio_card, ctx); |
674 | 702 | ||
703 | pdata = dev_get_drvdata(&pdev->dev); | ||
704 | if (pdata) | ||
705 | dmic_constraints = pdata->dmic_num == 2 ? | ||
706 | &constraints_dmic_2ch : &constraints_dmic_channels; | ||
707 | |||
675 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); | 708 | return devm_snd_soc_register_card(&pdev->dev, &skylake_audio_card); |
676 | } | 709 | } |
677 | 710 | ||
711 | static const struct platform_device_id skl_board_ids[] = { | ||
712 | { .name = "skl_n88l25_s4567" }, | ||
713 | { .name = "kbl_n88l25_s4567" }, | ||
714 | { } | ||
715 | }; | ||
716 | |||
678 | static struct platform_driver skylake_audio = { | 717 | static struct platform_driver skylake_audio = { |
679 | .probe = skylake_audio_probe, | 718 | .probe = skylake_audio_probe, |
680 | .driver = { | 719 | .driver = { |
681 | .name = "skl_nau88l25_ssm4567_i2s", | 720 | .name = "skl_n88l25_s4567", |
682 | .pm = &snd_soc_pm_ops, | 721 | .pm = &snd_soc_pm_ops, |
683 | }, | 722 | }, |
723 | .id_table = skl_board_ids, | ||
684 | }; | 724 | }; |
685 | 725 | ||
686 | module_platform_driver(skylake_audio) | 726 | module_platform_driver(skylake_audio) |
@@ -693,4 +733,5 @@ MODULE_AUTHOR("Sathya Prakash M R <sathya.prakash.m.r@intel.com>"); | |||
693 | MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); | 733 | MODULE_AUTHOR("Yong Zhi <yong.zhi@intel.com>"); |
694 | MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); | 734 | MODULE_DESCRIPTION("Intel Audio Machine driver for SKL with NAU88L25 and SSM4567 in I2S Mode"); |
695 | MODULE_LICENSE("GPL v2"); | 735 | MODULE_LICENSE("GPL v2"); |
696 | MODULE_ALIAS("platform:skl_nau88l25_ssm4567_i2s"); | 736 | MODULE_ALIAS("platform:skl_n88l25_s4567"); |
737 | MODULE_ALIAS("platform:kbl_n88l25_s4567"); | ||
diff --git a/sound/soc/intel/boards/skl_rt286.c b/sound/soc/intel/boards/skl_rt286.c index 426b48233fdb..88c61e8cb87f 100644 --- a/sound/soc/intel/boards/skl_rt286.c +++ b/sound/soc/intel/boards/skl_rt286.c | |||
@@ -505,12 +505,20 @@ static int skylake_audio_probe(struct platform_device *pdev) | |||
505 | return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); | 505 | return devm_snd_soc_register_card(&pdev->dev, &skylake_rt286); |
506 | } | 506 | } |
507 | 507 | ||
508 | static const struct platform_device_id skl_board_ids[] = { | ||
509 | { .name = "skl_alc286s_i2s" }, | ||
510 | { .name = "kbl_alc286s_i2s" }, | ||
511 | { } | ||
512 | }; | ||
513 | |||
508 | static struct platform_driver skylake_audio = { | 514 | static struct platform_driver skylake_audio = { |
509 | .probe = skylake_audio_probe, | 515 | .probe = skylake_audio_probe, |
510 | .driver = { | 516 | .driver = { |
511 | .name = "skl_alc286s_i2s", | 517 | .name = "skl_alc286s_i2s", |
512 | .pm = &snd_soc_pm_ops, | 518 | .pm = &snd_soc_pm_ops, |
513 | }, | 519 | }, |
520 | .id_table = skl_board_ids, | ||
521 | |||
514 | }; | 522 | }; |
515 | 523 | ||
516 | module_platform_driver(skylake_audio) | 524 | module_platform_driver(skylake_audio) |
@@ -520,3 +528,4 @@ MODULE_AUTHOR("Omair Mohammed Abdullah <omair.m.abdullah@intel.com>"); | |||
520 | MODULE_DESCRIPTION("Intel SST Audio for Skylake"); | 528 | MODULE_DESCRIPTION("Intel SST Audio for Skylake"); |
521 | MODULE_LICENSE("GPL v2"); | 529 | MODULE_LICENSE("GPL v2"); |
522 | MODULE_ALIAS("platform:skl_alc286s_i2s"); | 530 | MODULE_ALIAS("platform:skl_alc286s_i2s"); |
531 | MODULE_ALIAS("platform:kbl_alc286s_i2s"); | ||
diff --git a/sound/soc/intel/common/Makefile b/sound/soc/intel/common/Makefile index fbbb25c2ceed..1a35149bcad7 100644 --- a/sound/soc/intel/common/Makefile +++ b/sound/soc/intel/common/Makefile | |||
@@ -2,9 +2,9 @@ snd-soc-sst-dsp-objs := sst-dsp.o | |||
2 | snd-soc-sst-acpi-objs := sst-acpi.o | 2 | snd-soc-sst-acpi-objs := sst-acpi.o |
3 | snd-soc-sst-match-objs := sst-match-acpi.o | 3 | snd-soc-sst-match-objs := sst-match-acpi.o |
4 | snd-soc-sst-ipc-objs := sst-ipc.o | 4 | snd-soc-sst-ipc-objs := sst-ipc.o |
5 | 5 | snd-soc-sst-firmware-objs := sst-firmware.o | |
6 | snd-soc-sst-dsp-$(CONFIG_DW_DMAC_CORE) += sst-firmware.o | ||
7 | 6 | ||
8 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o | 7 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o snd-soc-sst-ipc.o |
9 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o | 8 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o |
10 | obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o | 9 | obj-$(CONFIG_SND_SOC_INTEL_SST_MATCH) += snd-soc-sst-match.o |
10 | obj-$(CONFIG_SND_SOC_INTEL_SST_FIRMWARE) += snd-soc-sst-firmware.o | ||
diff --git a/sound/soc/intel/common/sst-acpi.h b/sound/soc/intel/common/sst-acpi.h index 8398cb227ba9..5d2949324d0e 100644 --- a/sound/soc/intel/common/sst-acpi.h +++ b/sound/soc/intel/common/sst-acpi.h | |||
@@ -20,7 +20,7 @@ | |||
20 | #if IS_ENABLED(CONFIG_ACPI) | 20 | #if IS_ENABLED(CONFIG_ACPI) |
21 | const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); | 21 | const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]); |
22 | #else | 22 | #else |
23 | inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) | 23 | static inline const char *sst_acpi_find_name_from_hid(const u8 hid[ACPI_ID_LEN]) |
24 | { | 24 | { |
25 | return NULL; | 25 | return NULL; |
26 | } | 26 | } |
@@ -40,6 +40,6 @@ struct sst_acpi_mach { | |||
40 | 40 | ||
41 | /* board name */ | 41 | /* board name */ |
42 | const char *board; | 42 | const char *board; |
43 | void (*machine_quirk)(void); | 43 | struct sst_acpi_mach * (*machine_quirk)(void *arg); |
44 | void *pdata; | 44 | void *pdata; |
45 | }; | 45 | }; |
diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 97dc1ae05e69..d13c84364c3c 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h | |||
@@ -383,10 +383,6 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | |||
383 | u32 index, void *private); | 383 | u32 index, void *private); |
384 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); | 384 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); |
385 | 385 | ||
386 | /* Create/Free DMA resources */ | ||
387 | int sst_dma_new(struct sst_dsp *sst); | ||
388 | void sst_dma_free(struct sst_dma *dma); | ||
389 | |||
390 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | 386 | u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, |
391 | enum sst_mem_type type); | 387 | enum sst_mem_type type); |
392 | #endif | 388 | #endif |
diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index b5bbdf4fe93a..c00ede4ea4d7 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c | |||
@@ -285,7 +285,7 @@ int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, | |||
285 | } | 285 | } |
286 | 286 | ||
287 | reg = sst_dsp_shim_read_unlocked(ctx, offset); | 287 | reg = sst_dsp_shim_read_unlocked(ctx, offset); |
288 | dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, | 288 | dev_dbg(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, |
289 | (time < timeout) ? "successful" : "timedout"); | 289 | (time < timeout) ? "successful" : "timedout"); |
290 | ret = time < timeout ? 0 : -ETIME; | 290 | ret = time < timeout ? 0 : -ETIME; |
291 | 291 | ||
@@ -420,73 +420,6 @@ void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) | |||
420 | } | 420 | } |
421 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); | 421 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); |
422 | 422 | ||
423 | #ifdef CONFIG_DW_DMAC_CORE | ||
424 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
425 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) | ||
426 | { | ||
427 | struct sst_dsp *sst; | ||
428 | int err; | ||
429 | |||
430 | dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id); | ||
431 | |||
432 | sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); | ||
433 | if (sst == NULL) | ||
434 | return NULL; | ||
435 | |||
436 | spin_lock_init(&sst->spinlock); | ||
437 | mutex_init(&sst->mutex); | ||
438 | sst->dev = dev; | ||
439 | sst->dma_dev = pdata->dma_dev; | ||
440 | sst->thread_context = sst_dev->thread_context; | ||
441 | sst->sst_dev = sst_dev; | ||
442 | sst->id = pdata->id; | ||
443 | sst->irq = pdata->irq; | ||
444 | sst->ops = sst_dev->ops; | ||
445 | sst->pdata = pdata; | ||
446 | INIT_LIST_HEAD(&sst->used_block_list); | ||
447 | INIT_LIST_HEAD(&sst->free_block_list); | ||
448 | INIT_LIST_HEAD(&sst->module_list); | ||
449 | INIT_LIST_HEAD(&sst->fw_list); | ||
450 | INIT_LIST_HEAD(&sst->scratch_block_list); | ||
451 | |||
452 | /* Initialise SST Audio DSP */ | ||
453 | if (sst->ops->init) { | ||
454 | err = sst->ops->init(sst, pdata); | ||
455 | if (err < 0) | ||
456 | return NULL; | ||
457 | } | ||
458 | |||
459 | /* Register the ISR */ | ||
460 | err = request_threaded_irq(sst->irq, sst->ops->irq_handler, | ||
461 | sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); | ||
462 | if (err) | ||
463 | goto irq_err; | ||
464 | |||
465 | err = sst_dma_new(sst); | ||
466 | if (err) | ||
467 | dev_warn(dev, "sst_dma_new failed %d\n", err); | ||
468 | |||
469 | return sst; | ||
470 | |||
471 | irq_err: | ||
472 | if (sst->ops->free) | ||
473 | sst->ops->free(sst); | ||
474 | |||
475 | return NULL; | ||
476 | } | ||
477 | EXPORT_SYMBOL_GPL(sst_dsp_new); | ||
478 | |||
479 | void sst_dsp_free(struct sst_dsp *sst) | ||
480 | { | ||
481 | free_irq(sst->irq, sst); | ||
482 | if (sst->ops->free) | ||
483 | sst->ops->free(sst); | ||
484 | |||
485 | sst_dma_free(sst->dma); | ||
486 | } | ||
487 | EXPORT_SYMBOL_GPL(sst_dsp_free); | ||
488 | #endif | ||
489 | |||
490 | /* Module information */ | 423 | /* Module information */ |
491 | MODULE_AUTHOR("Liam Girdwood"); | 424 | MODULE_AUTHOR("Liam Girdwood"); |
492 | MODULE_DESCRIPTION("Intel SST Core"); | 425 | MODULE_DESCRIPTION("Intel SST Core"); |
diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 0b84c719ec48..859f0de00339 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h | |||
@@ -216,7 +216,7 @@ struct sst_pdata { | |||
216 | void *dsp; | 216 | void *dsp; |
217 | }; | 217 | }; |
218 | 218 | ||
219 | #ifdef CONFIG_DW_DMAC_CORE | 219 | #if IS_ENABLED(CONFIG_DW_DMAC_CORE) |
220 | /* Initialization */ | 220 | /* Initialization */ |
221 | struct sst_dsp *sst_dsp_new(struct device *dev, | 221 | struct sst_dsp *sst_dsp_new(struct device *dev, |
222 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); | 222 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); |
diff --git a/sound/soc/intel/common/sst-firmware.c b/sound/soc/intel/common/sst-firmware.c index 25993527370b..a086c35f91bb 100644 --- a/sound/soc/intel/common/sst-firmware.c +++ b/sound/soc/intel/common/sst-firmware.c | |||
@@ -1211,3 +1211,71 @@ u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset, | |||
1211 | } | 1211 | } |
1212 | } | 1212 | } |
1213 | EXPORT_SYMBOL_GPL(sst_dsp_get_offset); | 1213 | EXPORT_SYMBOL_GPL(sst_dsp_get_offset); |
1214 | |||
1215 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
1216 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) | ||
1217 | { | ||
1218 | struct sst_dsp *sst; | ||
1219 | int err; | ||
1220 | |||
1221 | dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id); | ||
1222 | |||
1223 | sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); | ||
1224 | if (sst == NULL) | ||
1225 | return NULL; | ||
1226 | |||
1227 | spin_lock_init(&sst->spinlock); | ||
1228 | mutex_init(&sst->mutex); | ||
1229 | sst->dev = dev; | ||
1230 | sst->dma_dev = pdata->dma_dev; | ||
1231 | sst->thread_context = sst_dev->thread_context; | ||
1232 | sst->sst_dev = sst_dev; | ||
1233 | sst->id = pdata->id; | ||
1234 | sst->irq = pdata->irq; | ||
1235 | sst->ops = sst_dev->ops; | ||
1236 | sst->pdata = pdata; | ||
1237 | INIT_LIST_HEAD(&sst->used_block_list); | ||
1238 | INIT_LIST_HEAD(&sst->free_block_list); | ||
1239 | INIT_LIST_HEAD(&sst->module_list); | ||
1240 | INIT_LIST_HEAD(&sst->fw_list); | ||
1241 | INIT_LIST_HEAD(&sst->scratch_block_list); | ||
1242 | |||
1243 | /* Initialise SST Audio DSP */ | ||
1244 | if (sst->ops->init) { | ||
1245 | err = sst->ops->init(sst, pdata); | ||
1246 | if (err < 0) | ||
1247 | return NULL; | ||
1248 | } | ||
1249 | |||
1250 | /* Register the ISR */ | ||
1251 | err = request_threaded_irq(sst->irq, sst->ops->irq_handler, | ||
1252 | sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); | ||
1253 | if (err) | ||
1254 | goto irq_err; | ||
1255 | |||
1256 | err = sst_dma_new(sst); | ||
1257 | if (err) | ||
1258 | dev_warn(dev, "sst_dma_new failed %d\n", err); | ||
1259 | |||
1260 | return sst; | ||
1261 | |||
1262 | irq_err: | ||
1263 | if (sst->ops->free) | ||
1264 | sst->ops->free(sst); | ||
1265 | |||
1266 | return NULL; | ||
1267 | } | ||
1268 | EXPORT_SYMBOL_GPL(sst_dsp_new); | ||
1269 | |||
1270 | void sst_dsp_free(struct sst_dsp *sst) | ||
1271 | { | ||
1272 | free_irq(sst->irq, sst); | ||
1273 | if (sst->ops->free) | ||
1274 | sst->ops->free(sst); | ||
1275 | |||
1276 | sst_dma_free(sst->dma); | ||
1277 | } | ||
1278 | EXPORT_SYMBOL_GPL(sst_dsp_free); | ||
1279 | |||
1280 | MODULE_DESCRIPTION("Intel SST Firmware Loader"); | ||
1281 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/haswell/sst-haswell-pcm.c b/sound/soc/intel/haswell/sst-haswell-pcm.c index 994256b39b9c..3154525c2b83 100644 --- a/sound/soc/intel/haswell/sst-haswell-pcm.c +++ b/sound/soc/intel/haswell/sst-haswell-pcm.c | |||
@@ -819,7 +819,6 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream) | |||
819 | mutex_lock(&pcm_data->mutex); | 819 | mutex_lock(&pcm_data->mutex); |
820 | pm_runtime_get_sync(pdata->dev); | 820 | pm_runtime_get_sync(pdata->dev); |
821 | 821 | ||
822 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | ||
823 | pcm_data->substream = substream; | 822 | pcm_data->substream = substream; |
824 | 823 | ||
825 | snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware); | 824 | snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware); |
diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index c28f5d0e1d99..60fbc9bbe473 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile | |||
@@ -5,6 +5,6 @@ obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o | |||
5 | 5 | ||
6 | # Skylake IPC Support | 6 | # Skylake IPC Support |
7 | snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ | 7 | snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ |
8 | skl-sst.o bxt-sst.o | 8 | skl-sst.o bxt-sst.o skl-sst-utils.o |
9 | 9 | ||
10 | obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o | 10 | obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o |
diff --git a/sound/soc/intel/skylake/bxt-sst.c b/sound/soc/intel/skylake/bxt-sst.c index 8b95e09e23e8..2663781278aa 100644 --- a/sound/soc/intel/skylake/bxt-sst.c +++ b/sound/soc/intel/skylake/bxt-sst.c | |||
@@ -37,11 +37,19 @@ | |||
37 | 37 | ||
38 | #define BXT_ADSP_SRAM1_BASE 0xA0000 | 38 | #define BXT_ADSP_SRAM1_BASE 0xA0000 |
39 | 39 | ||
40 | #define BXT_INSTANCE_ID 0 | ||
41 | #define BXT_BASE_FW_MODULE_ID 0 | ||
42 | |||
40 | static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) | 43 | static unsigned int bxt_get_errorcode(struct sst_dsp *ctx) |
41 | { | 44 | { |
42 | return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); | 45 | return sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE); |
43 | } | 46 | } |
44 | 47 | ||
48 | /* | ||
49 | * First boot sequence has some extra steps. Core 0 waits for power | ||
50 | * status on core 1, so power up core 1 also momentarily, keep it in | ||
51 | * reset/stall and then turn it off | ||
52 | */ | ||
45 | static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | 53 | static int sst_bxt_prepare_fw(struct sst_dsp *ctx, |
46 | const void *fwdata, u32 fwsize) | 54 | const void *fwdata, u32 fwsize) |
47 | { | 55 | { |
@@ -49,7 +57,7 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | |||
49 | u32 reg; | 57 | u32 reg; |
50 | 58 | ||
51 | stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); | 59 | stream_tag = ctx->dsp_ops.prepare(ctx->dev, 0x40, fwsize, &ctx->dmab); |
52 | if (stream_tag < 0) { | 60 | if (stream_tag <= 0) { |
53 | dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", | 61 | dev_err(ctx->dev, "Failed to prepare DMA FW loading err: %x\n", |
54 | stream_tag); | 62 | stream_tag); |
55 | return stream_tag; | 63 | return stream_tag; |
@@ -58,17 +66,27 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | |||
58 | ctx->dsp_ops.stream_tag = stream_tag; | 66 | ctx->dsp_ops.stream_tag = stream_tag; |
59 | memcpy(ctx->dmab.area, fwdata, fwsize); | 67 | memcpy(ctx->dmab.area, fwdata, fwsize); |
60 | 68 | ||
61 | /* Purge FW request */ | 69 | /* Step 1: Power up core 0 and core1 */ |
70 | ret = skl_dsp_core_power_up(ctx, SKL_DSP_CORE0_MASK | | ||
71 | SKL_DSP_CORE_MASK(1)); | ||
72 | if (ret < 0) { | ||
73 | dev_err(ctx->dev, "dsp core0/1 power up failed\n"); | ||
74 | goto base_fw_load_failed; | ||
75 | } | ||
76 | |||
77 | /* Step 2: Purge FW request */ | ||
62 | sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | | 78 | sst_dsp_shim_write(ctx, SKL_ADSP_REG_HIPCI, SKL_ADSP_REG_HIPCI_BUSY | |
63 | BXT_IPC_PURGE_FW | (stream_tag - 1)); | 79 | (BXT_IPC_PURGE_FW | ((stream_tag - 1) << 9))); |
64 | 80 | ||
65 | ret = skl_dsp_enable_core(ctx); | 81 | /* Step 3: Unset core0 reset state & unstall/run core0 */ |
82 | ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); | ||
66 | if (ret < 0) { | 83 | if (ret < 0) { |
67 | dev_err(ctx->dev, "Boot dsp core failed ret: %d\n", ret); | 84 | dev_err(ctx->dev, "Start dsp core failed ret: %d\n", ret); |
68 | ret = -EIO; | 85 | ret = -EIO; |
69 | goto base_fw_load_failed; | 86 | goto base_fw_load_failed; |
70 | } | 87 | } |
71 | 88 | ||
89 | /* Step 4: Wait for DONE Bit */ | ||
72 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { | 90 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { |
73 | reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); | 91 | reg = sst_dsp_shim_read(ctx, SKL_ADSP_REG_HIPCIE); |
74 | 92 | ||
@@ -88,10 +106,18 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | |||
88 | SKL_ADSP_REG_HIPCIE_DONE); | 106 | SKL_ADSP_REG_HIPCIE_DONE); |
89 | } | 107 | } |
90 | 108 | ||
91 | /* enable Interrupt */ | 109 | /* Step 5: power down core1 */ |
110 | ret = skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); | ||
111 | if (ret < 0) { | ||
112 | dev_err(ctx->dev, "dsp core1 power down failed\n"); | ||
113 | goto base_fw_load_failed; | ||
114 | } | ||
115 | |||
116 | /* Step 6: Enable Interrupt */ | ||
92 | skl_ipc_int_enable(ctx); | 117 | skl_ipc_int_enable(ctx); |
93 | skl_ipc_op_int_enable(ctx); | 118 | skl_ipc_op_int_enable(ctx); |
94 | 119 | ||
120 | /* Step 7: Wait for ROM init */ | ||
95 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { | 121 | for (i = BXT_INIT_TIMEOUT; i > 0; --i) { |
96 | if (SKL_FW_INIT == | 122 | if (SKL_FW_INIT == |
97 | (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & | 123 | (sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS) & |
@@ -112,7 +138,8 @@ static int sst_bxt_prepare_fw(struct sst_dsp *ctx, | |||
112 | 138 | ||
113 | base_fw_load_failed: | 139 | base_fw_load_failed: |
114 | ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); | 140 | ctx->dsp_ops.cleanup(ctx->dev, &ctx->dmab, stream_tag); |
115 | skl_dsp_disable_core(ctx); | 141 | skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); |
142 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); | ||
116 | return ret; | 143 | return ret; |
117 | } | 144 | } |
118 | 145 | ||
@@ -130,23 +157,41 @@ static int sst_transfer_fw_host_dma(struct sst_dsp *ctx) | |||
130 | return ret; | 157 | return ret; |
131 | } | 158 | } |
132 | 159 | ||
160 | #define BXT_ADSP_FW_BIN_HDR_OFFSET 0x2000 | ||
161 | |||
133 | static int bxt_load_base_firmware(struct sst_dsp *ctx) | 162 | static int bxt_load_base_firmware(struct sst_dsp *ctx) |
134 | { | 163 | { |
135 | const struct firmware *fw = NULL; | 164 | struct firmware stripped_fw; |
136 | struct skl_sst *skl = ctx->thread_context; | 165 | struct skl_sst *skl = ctx->thread_context; |
137 | int ret; | 166 | int ret; |
138 | 167 | ||
139 | ret = request_firmware(&fw, ctx->fw_name, ctx->dev); | 168 | ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); |
140 | if (ret < 0) { | 169 | if (ret < 0) { |
141 | dev_err(ctx->dev, "Request firmware failed %d\n", ret); | 170 | dev_err(ctx->dev, "Request firmware failed %d\n", ret); |
142 | goto sst_load_base_firmware_failed; | 171 | goto sst_load_base_firmware_failed; |
143 | } | 172 | } |
144 | 173 | ||
145 | ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); | 174 | /* check for extended manifest */ |
175 | if (ctx->fw == NULL) | ||
176 | goto sst_load_base_firmware_failed; | ||
177 | |||
178 | ret = snd_skl_parse_uuids(ctx, BXT_ADSP_FW_BIN_HDR_OFFSET); | ||
179 | if (ret < 0) | ||
180 | goto sst_load_base_firmware_failed; | ||
181 | |||
182 | stripped_fw.data = ctx->fw->data; | ||
183 | stripped_fw.size = ctx->fw->size; | ||
184 | skl_dsp_strip_extended_manifest(&stripped_fw); | ||
185 | |||
186 | ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); | ||
146 | /* Retry Enabling core and ROM load. Retry seemed to help */ | 187 | /* Retry Enabling core and ROM load. Retry seemed to help */ |
147 | if (ret < 0) { | 188 | if (ret < 0) { |
148 | ret = sst_bxt_prepare_fw(ctx, fw->data, fw->size); | 189 | ret = sst_bxt_prepare_fw(ctx, stripped_fw.data, stripped_fw.size); |
149 | if (ret < 0) { | 190 | if (ret < 0) { |
191 | dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", | ||
192 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | ||
193 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | ||
194 | |||
150 | dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); | 195 | dev_err(ctx->dev, "Core En/ROM load fail:%d\n", ret); |
151 | goto sst_load_base_firmware_failed; | 196 | goto sst_load_base_firmware_failed; |
152 | } | 197 | } |
@@ -159,83 +204,135 @@ static int bxt_load_base_firmware(struct sst_dsp *ctx) | |||
159 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | 204 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), |
160 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | 205 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); |
161 | 206 | ||
162 | skl_dsp_disable_core(ctx); | 207 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); |
163 | } else { | 208 | } else { |
164 | dev_dbg(ctx->dev, "Firmware download successful\n"); | 209 | dev_dbg(ctx->dev, "Firmware download successful\n"); |
165 | ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, | 210 | ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, |
166 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); | 211 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); |
167 | if (ret == 0) { | 212 | if (ret == 0) { |
168 | dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); | 213 | dev_err(ctx->dev, "DSP boot fail, FW Ready timeout\n"); |
169 | skl_dsp_disable_core(ctx); | 214 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); |
170 | ret = -EIO; | 215 | ret = -EIO; |
171 | } else { | 216 | } else { |
172 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | ||
173 | ret = 0; | 217 | ret = 0; |
218 | skl->fw_loaded = true; | ||
174 | } | 219 | } |
175 | } | 220 | } |
176 | 221 | ||
177 | sst_load_base_firmware_failed: | 222 | sst_load_base_firmware_failed: |
178 | release_firmware(fw); | 223 | release_firmware(ctx->fw); |
179 | return ret; | 224 | return ret; |
180 | } | 225 | } |
181 | 226 | ||
182 | static int bxt_set_dsp_D0(struct sst_dsp *ctx) | 227 | static int bxt_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) |
183 | { | 228 | { |
184 | struct skl_sst *skl = ctx->thread_context; | 229 | struct skl_sst *skl = ctx->thread_context; |
185 | int ret; | 230 | int ret; |
231 | struct skl_ipc_dxstate_info dx; | ||
232 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); | ||
186 | 233 | ||
187 | skl->boot_complete = false; | 234 | if (skl->fw_loaded == false) { |
188 | 235 | skl->boot_complete = false; | |
189 | ret = skl_dsp_enable_core(ctx); | 236 | ret = bxt_load_base_firmware(ctx); |
190 | if (ret < 0) { | 237 | if (ret < 0) |
191 | dev_err(ctx->dev, "enable dsp core failed ret: %d\n", ret); | 238 | dev_err(ctx->dev, "reload fw failed: %d\n", ret); |
192 | return ret; | 239 | return ret; |
193 | } | 240 | } |
194 | 241 | ||
195 | /* enable interrupt */ | 242 | /* If core 0 is being turned on, turn on core 1 as well */ |
196 | skl_ipc_int_enable(ctx); | 243 | if (core_id == SKL_DSP_CORE0_ID) |
197 | skl_ipc_op_int_enable(ctx); | 244 | ret = skl_dsp_core_power_up(ctx, core_mask | |
245 | SKL_DSP_CORE_MASK(1)); | ||
246 | else | ||
247 | ret = skl_dsp_core_power_up(ctx, core_mask); | ||
248 | |||
249 | if (ret < 0) | ||
250 | goto err; | ||
251 | |||
252 | if (core_id == SKL_DSP_CORE0_ID) { | ||
253 | |||
254 | /* | ||
255 | * Enable interrupt after SPA is set and before | ||
256 | * DSP is unstalled | ||
257 | */ | ||
258 | skl_ipc_int_enable(ctx); | ||
259 | skl_ipc_op_int_enable(ctx); | ||
260 | skl->boot_complete = false; | ||
261 | } | ||
198 | 262 | ||
199 | ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, | 263 | ret = skl_dsp_start_core(ctx, core_mask); |
200 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); | 264 | if (ret < 0) |
201 | if (ret == 0) { | 265 | goto err; |
202 | dev_err(ctx->dev, "ipc: error DSP boot timeout\n"); | 266 | |
203 | dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", | 267 | if (core_id == SKL_DSP_CORE0_ID) { |
204 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | 268 | ret = wait_event_timeout(skl->boot_wait, |
205 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | 269 | skl->boot_complete, |
206 | return -EIO; | 270 | msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); |
271 | |||
272 | /* If core 1 was turned on for booting core 0, turn it off */ | ||
273 | skl_dsp_core_power_down(ctx, SKL_DSP_CORE_MASK(1)); | ||
274 | if (ret == 0) { | ||
275 | dev_err(ctx->dev, "%s: DSP boot timeout\n", __func__); | ||
276 | dev_err(ctx->dev, "Error code=0x%x: FW status=0x%x\n", | ||
277 | sst_dsp_shim_read(ctx, BXT_ADSP_ERROR_CODE), | ||
278 | sst_dsp_shim_read(ctx, BXT_ADSP_FW_STATUS)); | ||
279 | dev_err(ctx->dev, "Failed to set core0 to D0 state\n"); | ||
280 | ret = -EIO; | ||
281 | goto err; | ||
282 | } | ||
283 | } | ||
284 | |||
285 | /* Tell FW if additional core in now On */ | ||
286 | |||
287 | if (core_id != SKL_DSP_CORE0_ID) { | ||
288 | dx.core_mask = core_mask; | ||
289 | dx.dx_mask = core_mask; | ||
290 | |||
291 | ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, | ||
292 | BXT_BASE_FW_MODULE_ID, &dx); | ||
293 | if (ret < 0) { | ||
294 | dev_err(ctx->dev, "IPC set_dx for core %d fail: %d\n", | ||
295 | core_id, ret); | ||
296 | goto err; | ||
297 | } | ||
207 | } | 298 | } |
208 | 299 | ||
209 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | 300 | skl->cores.state[core_id] = SKL_DSP_RUNNING; |
210 | return 0; | 301 | return 0; |
302 | err: | ||
303 | if (core_id == SKL_DSP_CORE0_ID) | ||
304 | core_mask |= SKL_DSP_CORE_MASK(1); | ||
305 | skl_dsp_disable_core(ctx, core_mask); | ||
306 | |||
307 | return ret; | ||
211 | } | 308 | } |
212 | 309 | ||
213 | static int bxt_set_dsp_D3(struct sst_dsp *ctx) | 310 | static int bxt_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) |
214 | { | 311 | { |
312 | int ret; | ||
215 | struct skl_ipc_dxstate_info dx; | 313 | struct skl_ipc_dxstate_info dx; |
216 | struct skl_sst *skl = ctx->thread_context; | 314 | struct skl_sst *skl = ctx->thread_context; |
217 | int ret = 0; | 315 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); |
218 | 316 | ||
219 | if (!is_skl_dsp_running(ctx)) | 317 | dx.core_mask = core_mask; |
220 | return ret; | ||
221 | |||
222 | dx.core_mask = SKL_DSP_CORE0_MASK; | ||
223 | dx.dx_mask = SKL_IPC_D3_MASK; | 318 | dx.dx_mask = SKL_IPC_D3_MASK; |
224 | 319 | ||
225 | ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, | 320 | dev_dbg(ctx->dev, "core mask=%x dx_mask=%x\n", |
226 | SKL_BASE_FW_MODULE_ID, &dx); | 321 | dx.core_mask, dx.dx_mask); |
227 | if (ret < 0) { | 322 | |
228 | dev_err(ctx->dev, "Failed to set DSP to D3 state: %d\n", ret); | 323 | ret = skl_ipc_set_dx(&skl->ipc, BXT_INSTANCE_ID, |
229 | return ret; | 324 | BXT_BASE_FW_MODULE_ID, &dx); |
230 | } | 325 | if (ret < 0) |
326 | dev_err(ctx->dev, | ||
327 | "Failed to set DSP to D3:core id = %d;Continue reset\n", | ||
328 | core_id); | ||
231 | 329 | ||
232 | ret = skl_dsp_disable_core(ctx); | 330 | ret = skl_dsp_disable_core(ctx, core_mask); |
233 | if (ret < 0) { | 331 | if (ret < 0) { |
234 | dev_err(ctx->dev, "disbale dsp core failed: %d\n", ret); | 332 | dev_err(ctx->dev, "Failed to disable core %d", ret); |
235 | ret = -EIO; | 333 | return ret; |
236 | } | 334 | } |
237 | 335 | skl->cores.state[core_id] = SKL_DSP_RESET; | |
238 | skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); | ||
239 | return 0; | 336 | return 0; |
240 | } | 337 | } |
241 | 338 | ||
@@ -274,6 +371,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
274 | 371 | ||
275 | skl->dev = dev; | 372 | skl->dev = dev; |
276 | skl_dev.thread_context = skl; | 373 | skl_dev.thread_context = skl; |
374 | INIT_LIST_HEAD(&skl->uuid_list); | ||
277 | 375 | ||
278 | skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); | 376 | skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); |
279 | if (!skl->dsp) { | 377 | if (!skl->dsp) { |
@@ -296,6 +394,7 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
296 | if (ret) | 394 | if (ret) |
297 | return ret; | 395 | return ret; |
298 | 396 | ||
397 | skl->cores.count = 2; | ||
299 | skl->boot_complete = false; | 398 | skl->boot_complete = false; |
300 | init_waitqueue_head(&skl->boot_wait); | 399 | init_waitqueue_head(&skl->boot_wait); |
301 | 400 | ||
@@ -305,6 +404,8 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
305 | return ret; | 404 | return ret; |
306 | } | 405 | } |
307 | 406 | ||
407 | skl_dsp_init_core_state(sst); | ||
408 | |||
308 | if (dsp) | 409 | if (dsp) |
309 | *dsp = skl; | 410 | *dsp = skl; |
310 | 411 | ||
@@ -315,6 +416,7 @@ EXPORT_SYMBOL_GPL(bxt_sst_dsp_init); | |||
315 | 416 | ||
316 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | 417 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) |
317 | { | 418 | { |
419 | skl_freeup_uuid_list(ctx); | ||
318 | skl_ipc_free(&ctx->ipc); | 420 | skl_ipc_free(&ctx->ipc); |
319 | ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); | 421 | ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); |
320 | 422 | ||
diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c index 226db84ba20f..44ab595ce21a 100644 --- a/sound/soc/intel/skylake/skl-messages.c +++ b/sound/soc/intel/skylake/skl-messages.c | |||
@@ -206,6 +206,12 @@ static const struct skl_dsp_ops dsp_ops[] = { | |||
206 | .cleanup = skl_sst_dsp_cleanup | 206 | .cleanup = skl_sst_dsp_cleanup |
207 | }, | 207 | }, |
208 | { | 208 | { |
209 | .id = 0x9d71, | ||
210 | .loader_ops = skl_get_loader_ops, | ||
211 | .init = skl_sst_dsp_init, | ||
212 | .cleanup = skl_sst_dsp_cleanup | ||
213 | }, | ||
214 | { | ||
209 | .id = 0x5a98, | 215 | .id = 0x5a98, |
210 | .loader_ops = bxt_get_loader_ops, | 216 | .loader_ops = bxt_get_loader_ops, |
211 | .init = bxt_sst_dsp_init, | 217 | .init = bxt_sst_dsp_init, |
@@ -730,7 +736,7 @@ static int skl_set_module_format(struct skl_sst *ctx, | |||
730 | 736 | ||
731 | dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", | 737 | dev_dbg(ctx->dev, "Module type=%d config size: %d bytes\n", |
732 | module_config->id.module_id, param_size); | 738 | module_config->id.module_id, param_size); |
733 | print_hex_dump(KERN_DEBUG, "Module params:", DUMP_PREFIX_OFFSET, 8, 4, | 739 | print_hex_dump_debug("Module params:", DUMP_PREFIX_OFFSET, 8, 4, |
734 | *param_data, param_size, false); | 740 | *param_data, param_size, false); |
735 | return 0; | 741 | return 0; |
736 | } | 742 | } |
@@ -1046,7 +1052,7 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) | |||
1046 | 1052 | ||
1047 | dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); | 1053 | dev_dbg(ctx->dev, "%s: pipe = %d\n", __func__, pipe->ppl_id); |
1048 | 1054 | ||
1049 | /* If pipe is not started, do not try to stop the pipe in FW. */ | 1055 | /* If pipe is started, do stop the pipe in FW. */ |
1050 | if (pipe->state > SKL_PIPE_STARTED) { | 1056 | if (pipe->state > SKL_PIPE_STARTED) { |
1051 | ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); | 1057 | ret = skl_set_pipe_state(ctx, pipe, PPL_PAUSED); |
1052 | if (ret < 0) { | 1058 | if (ret < 0) { |
@@ -1055,18 +1061,20 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) | |||
1055 | } | 1061 | } |
1056 | 1062 | ||
1057 | pipe->state = SKL_PIPE_PAUSED; | 1063 | pipe->state = SKL_PIPE_PAUSED; |
1058 | } else { | 1064 | } |
1059 | /* If pipe was not created in FW, do not try to delete it */ | ||
1060 | if (pipe->state < SKL_PIPE_CREATED) | ||
1061 | return 0; | ||
1062 | 1065 | ||
1063 | ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); | 1066 | /* If pipe was not created in FW, do not try to delete it */ |
1064 | if (ret < 0) | 1067 | if (pipe->state < SKL_PIPE_CREATED) |
1065 | dev_err(ctx->dev, "Failed to delete pipeline\n"); | 1068 | return 0; |
1066 | 1069 | ||
1067 | pipe->state = SKL_PIPE_INVALID; | 1070 | ret = skl_ipc_delete_pipeline(&ctx->ipc, pipe->ppl_id); |
1071 | if (ret < 0) { | ||
1072 | dev_err(ctx->dev, "Failed to delete pipeline\n"); | ||
1073 | return ret; | ||
1068 | } | 1074 | } |
1069 | 1075 | ||
1076 | pipe->state = SKL_PIPE_INVALID; | ||
1077 | |||
1070 | return ret; | 1078 | return ret; |
1071 | } | 1079 | } |
1072 | 1080 | ||
@@ -1125,7 +1133,30 @@ int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) | |||
1125 | return ret; | 1133 | return ret; |
1126 | } | 1134 | } |
1127 | 1135 | ||
1128 | pipe->state = SKL_PIPE_CREATED; | 1136 | pipe->state = SKL_PIPE_PAUSED; |
1137 | |||
1138 | return 0; | ||
1139 | } | ||
1140 | |||
1141 | /* | ||
1142 | * Reset the pipeline by sending set pipe state IPC this will reset the DMA | ||
1143 | * from the DSP side | ||
1144 | */ | ||
1145 | int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe) | ||
1146 | { | ||
1147 | int ret; | ||
1148 | |||
1149 | /* If pipe was not created in FW, do not try to pause or delete */ | ||
1150 | if (pipe->state < SKL_PIPE_PAUSED) | ||
1151 | return 0; | ||
1152 | |||
1153 | ret = skl_set_pipe_state(ctx, pipe, PPL_RESET); | ||
1154 | if (ret < 0) { | ||
1155 | dev_dbg(ctx->dev, "Failed to reset pipe ret=%d\n", ret); | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | pipe->state = SKL_PIPE_RESET; | ||
1129 | 1160 | ||
1130 | return 0; | 1161 | return 0; |
1131 | } | 1162 | } |
diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c index 7d73648e5f9a..3f8e6f0b7eb5 100644 --- a/sound/soc/intel/skylake/skl-nhlt.c +++ b/sound/soc/intel/skylake/skl-nhlt.c | |||
@@ -17,6 +17,7 @@ | |||
17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 17 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | #include <linux/pci.h> | ||
20 | #include "skl.h" | 21 | #include "skl.h" |
21 | 22 | ||
22 | /* Unique identification for getting NHLT blobs */ | 23 | /* Unique identification for getting NHLT blobs */ |
@@ -149,6 +150,45 @@ struct nhlt_specific_cfg | |||
149 | return NULL; | 150 | return NULL; |
150 | } | 151 | } |
151 | 152 | ||
153 | int skl_get_dmic_geo(struct skl *skl) | ||
154 | { | ||
155 | struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; | ||
156 | struct nhlt_endpoint *epnt; | ||
157 | struct nhlt_dmic_array_config *cfg; | ||
158 | struct device *dev = &skl->pci->dev; | ||
159 | unsigned int dmic_geo = 0; | ||
160 | u8 j; | ||
161 | |||
162 | epnt = (struct nhlt_endpoint *)nhlt->desc; | ||
163 | |||
164 | for (j = 0; j < nhlt->endpoint_count; j++) { | ||
165 | if (epnt->linktype == NHLT_LINK_DMIC) { | ||
166 | cfg = (struct nhlt_dmic_array_config *) | ||
167 | (epnt->config.caps); | ||
168 | switch (cfg->array_type) { | ||
169 | case NHLT_MIC_ARRAY_2CH_SMALL: | ||
170 | case NHLT_MIC_ARRAY_2CH_BIG: | ||
171 | dmic_geo |= MIC_ARRAY_2CH; | ||
172 | break; | ||
173 | |||
174 | case NHLT_MIC_ARRAY_4CH_1ST_GEOM: | ||
175 | case NHLT_MIC_ARRAY_4CH_L_SHAPED: | ||
176 | case NHLT_MIC_ARRAY_4CH_2ND_GEOM: | ||
177 | dmic_geo |= MIC_ARRAY_4CH; | ||
178 | break; | ||
179 | |||
180 | default: | ||
181 | dev_warn(dev, "undefined DMIC array_type 0x%0x\n", | ||
182 | cfg->array_type); | ||
183 | |||
184 | } | ||
185 | } | ||
186 | epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); | ||
187 | } | ||
188 | |||
189 | return dmic_geo; | ||
190 | } | ||
191 | |||
152 | static void skl_nhlt_trim_space(struct skl *skl) | 192 | static void skl_nhlt_trim_space(struct skl *skl) |
153 | { | 193 | { |
154 | char *s = skl->tplg_name; | 194 | char *s = skl->tplg_name; |
diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h index 3769f9fefe2b..116534e7b3c5 100644 --- a/sound/soc/intel/skylake/skl-nhlt.h +++ b/sound/soc/intel/skylake/skl-nhlt.h | |||
@@ -103,4 +103,26 @@ struct nhlt_resource_desc { | |||
103 | u64 length; | 103 | u64 length; |
104 | } __packed; | 104 | } __packed; |
105 | 105 | ||
106 | #define MIC_ARRAY_2CH 2 | ||
107 | #define MIC_ARRAY_4CH 4 | ||
108 | |||
109 | struct nhlt_tdm_config { | ||
110 | u8 virtual_slot; | ||
111 | u8 config_type; | ||
112 | } __packed; | ||
113 | |||
114 | struct nhlt_dmic_array_config { | ||
115 | struct nhlt_tdm_config tdm_config; | ||
116 | u8 array_type; | ||
117 | } __packed; | ||
118 | |||
119 | enum { | ||
120 | NHLT_MIC_ARRAY_2CH_SMALL = 0xa, | ||
121 | NHLT_MIC_ARRAY_2CH_BIG = 0xb, | ||
122 | NHLT_MIC_ARRAY_4CH_1ST_GEOM = 0xc, | ||
123 | NHLT_MIC_ARRAY_4CH_L_SHAPED = 0xd, | ||
124 | NHLT_MIC_ARRAY_4CH_2ND_GEOM = 0xe, | ||
125 | NHLT_MIC_ARRAY_VENDOR_DEFINED = 0xf, | ||
126 | }; | ||
127 | |||
106 | #endif | 128 | #endif |
diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index 7c81b31748ff..6e05bf8622f7 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c | |||
@@ -227,16 +227,25 @@ static int skl_pcm_prepare(struct snd_pcm_substream *substream, | |||
227 | struct snd_soc_dai *dai) | 227 | struct snd_soc_dai *dai) |
228 | { | 228 | { |
229 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); | 229 | struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); |
230 | struct skl *skl = get_skl_ctx(dai->dev); | ||
230 | unsigned int format_val; | 231 | unsigned int format_val; |
231 | int err; | 232 | int err; |
233 | struct skl_module_cfg *mconfig; | ||
232 | 234 | ||
233 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); | 235 | dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); |
234 | 236 | ||
237 | mconfig = skl_tplg_fe_get_cpr_module(dai, substream->stream); | ||
238 | |||
235 | format_val = skl_get_format(substream, dai); | 239 | format_val = skl_get_format(substream, dai); |
236 | dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", | 240 | dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", |
237 | hdac_stream(stream)->stream_tag, format_val); | 241 | hdac_stream(stream)->stream_tag, format_val); |
238 | snd_hdac_stream_reset(hdac_stream(stream)); | 242 | snd_hdac_stream_reset(hdac_stream(stream)); |
239 | 243 | ||
244 | /* In case of XRUN recovery, reset the FW pipe to clean state */ | ||
245 | if (mconfig && (substream->runtime->status->state == | ||
246 | SNDRV_PCM_STATE_XRUN)) | ||
247 | skl_reset_pipe(skl->skl_sst, mconfig->pipe); | ||
248 | |||
240 | err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); | 249 | err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); |
241 | if (err < 0) | 250 | if (err < 0) |
242 | return err; | 251 | return err; |
@@ -521,6 +530,8 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, | |||
521 | struct skl_dma_params *dma_params; | 530 | struct skl_dma_params *dma_params; |
522 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 531 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
523 | struct hdac_ext_link *link; | 532 | struct hdac_ext_link *link; |
533 | struct skl *skl = get_skl_ctx(dai->dev); | ||
534 | struct skl_module_cfg *mconfig = NULL; | ||
524 | 535 | ||
525 | dma_params = (struct skl_dma_params *) | 536 | dma_params = (struct skl_dma_params *) |
526 | snd_soc_dai_get_dma_data(codec_dai, substream); | 537 | snd_soc_dai_get_dma_data(codec_dai, substream); |
@@ -535,6 +546,12 @@ static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, | |||
535 | 546 | ||
536 | snd_hdac_ext_link_stream_reset(link_dev); | 547 | snd_hdac_ext_link_stream_reset(link_dev); |
537 | 548 | ||
549 | /* In case of XRUN recovery, reset the FW pipe to clean state */ | ||
550 | mconfig = skl_tplg_be_get_cpr_module(dai, substream->stream); | ||
551 | if (mconfig && (substream->runtime->status->state == | ||
552 | SNDRV_PCM_STATE_XRUN)) | ||
553 | skl_reset_pipe(skl->skl_sst, mconfig->pipe); | ||
554 | |||
538 | snd_hdac_ext_link_stream_setup(link_dev, format_val); | 555 | snd_hdac_ext_link_stream_setup(link_dev, format_val); |
539 | 556 | ||
540 | snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); | 557 | snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); |
@@ -1009,51 +1026,11 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
1009 | return 0; | 1026 | return 0; |
1010 | } | 1027 | } |
1011 | 1028 | ||
1012 | /* calculate runtime delay from LPIB */ | 1029 | static snd_pcm_uframes_t skl_platform_pcm_pointer |
1013 | static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, | 1030 | (struct snd_pcm_substream *substream) |
1014 | struct hdac_ext_stream *sstream, | ||
1015 | unsigned int pos) | ||
1016 | { | ||
1017 | struct hdac_bus *bus = ebus_to_hbus(ebus); | ||
1018 | struct hdac_stream *hstream = hdac_stream(sstream); | ||
1019 | struct snd_pcm_substream *substream = hstream->substream; | ||
1020 | int stream = substream->stream; | ||
1021 | unsigned int lpib_pos = snd_hdac_stream_get_pos_lpib(hstream); | ||
1022 | int delay; | ||
1023 | |||
1024 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
1025 | delay = pos - lpib_pos; | ||
1026 | else | ||
1027 | delay = lpib_pos - pos; | ||
1028 | |||
1029 | if (delay < 0) { | ||
1030 | if (delay >= hstream->delay_negative_threshold) | ||
1031 | delay = 0; | ||
1032 | else | ||
1033 | delay += hstream->bufsize; | ||
1034 | } | ||
1035 | |||
1036 | if (hstream->bufsize == delay) | ||
1037 | delay = 0; | ||
1038 | |||
1039 | if (delay >= hstream->period_bytes) { | ||
1040 | dev_info(bus->dev, | ||
1041 | "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", | ||
1042 | delay, hstream->period_bytes); | ||
1043 | delay = 0; | ||
1044 | } | ||
1045 | |||
1046 | return bytes_to_frames(substream->runtime, delay); | ||
1047 | } | ||
1048 | |||
1049 | static unsigned int skl_get_position(struct hdac_ext_stream *hstream, | ||
1050 | int codec_delay) | ||
1051 | { | 1031 | { |
1052 | struct hdac_stream *hstr = hdac_stream(hstream); | 1032 | struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); |
1053 | struct snd_pcm_substream *substream = hstr->substream; | ||
1054 | struct hdac_ext_bus *ebus; | ||
1055 | unsigned int pos; | 1033 | unsigned int pos; |
1056 | int delay; | ||
1057 | 1034 | ||
1058 | /* use the position buffer as default */ | 1035 | /* use the position buffer as default */ |
1059 | pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); | 1036 | pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); |
@@ -1061,23 +1038,7 @@ static unsigned int skl_get_position(struct hdac_ext_stream *hstream, | |||
1061 | if (pos >= hdac_stream(hstream)->bufsize) | 1038 | if (pos >= hdac_stream(hstream)->bufsize) |
1062 | pos = 0; | 1039 | pos = 0; |
1063 | 1040 | ||
1064 | if (substream->runtime) { | 1041 | return bytes_to_frames(substream->runtime, pos); |
1065 | ebus = get_bus_ctx(substream); | ||
1066 | delay = skl_get_delay_from_lpib(ebus, hstream, pos) | ||
1067 | + codec_delay; | ||
1068 | substream->runtime->delay += delay; | ||
1069 | } | ||
1070 | |||
1071 | return pos; | ||
1072 | } | ||
1073 | |||
1074 | static snd_pcm_uframes_t skl_platform_pcm_pointer | ||
1075 | (struct snd_pcm_substream *substream) | ||
1076 | { | ||
1077 | struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); | ||
1078 | |||
1079 | return bytes_to_frames(substream->runtime, | ||
1080 | skl_get_position(hstream, 0)); | ||
1081 | } | 1042 | } |
1082 | 1043 | ||
1083 | static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, | 1044 | static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, |
@@ -1180,9 +1141,17 @@ static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
1180 | static int skl_platform_soc_probe(struct snd_soc_platform *platform) | 1141 | static int skl_platform_soc_probe(struct snd_soc_platform *platform) |
1181 | { | 1142 | { |
1182 | struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); | 1143 | struct hdac_ext_bus *ebus = dev_get_drvdata(platform->dev); |
1144 | struct skl *skl = ebus_to_skl(ebus); | ||
1145 | int ret; | ||
1183 | 1146 | ||
1184 | if (ebus->ppcap) | 1147 | if (ebus->ppcap) { |
1185 | return skl_tplg_init(platform, ebus); | 1148 | ret = skl_tplg_init(platform, ebus); |
1149 | if (ret < 0) { | ||
1150 | dev_err(platform->dev, "Failed to init topology!\n"); | ||
1151 | return ret; | ||
1152 | } | ||
1153 | skl->platform = platform; | ||
1154 | } | ||
1186 | 1155 | ||
1187 | return 0; | 1156 | return 0; |
1188 | } | 1157 | } |
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 13c19855ee1a..c3deefab65d6 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c | |||
@@ -34,33 +34,84 @@ void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) | |||
34 | mutex_unlock(&ctx->mutex); | 34 | mutex_unlock(&ctx->mutex); |
35 | } | 35 | } |
36 | 36 | ||
37 | static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) | 37 | /* |
38 | * Initialize core power state and usage count. To be called after | ||
39 | * successful first boot. Hence core 0 will be running and other cores | ||
40 | * will be reset | ||
41 | */ | ||
42 | void skl_dsp_init_core_state(struct sst_dsp *ctx) | ||
43 | { | ||
44 | struct skl_sst *skl = ctx->thread_context; | ||
45 | int i; | ||
46 | |||
47 | skl->cores.state[SKL_DSP_CORE0_ID] = SKL_DSP_RUNNING; | ||
48 | skl->cores.usage_count[SKL_DSP_CORE0_ID] = 1; | ||
49 | |||
50 | for (i = SKL_DSP_CORE0_ID + 1; i < SKL_DSP_CORES_MAX; i++) { | ||
51 | skl->cores.state[i] = SKL_DSP_RESET; | ||
52 | skl->cores.usage_count[i] = 0; | ||
53 | } | ||
54 | } | ||
55 | |||
56 | /* Get the mask for all enabled cores */ | ||
57 | unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx) | ||
58 | { | ||
59 | struct skl_sst *skl = ctx->thread_context; | ||
60 | unsigned int core_mask, en_cores_mask; | ||
61 | u32 val; | ||
62 | |||
63 | core_mask = SKL_DSP_CORES_MASK(skl->cores.count); | ||
64 | |||
65 | val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); | ||
66 | |||
67 | /* Cores having CPA bit set */ | ||
68 | en_cores_mask = (val & SKL_ADSPCS_CPA_MASK(core_mask)) >> | ||
69 | SKL_ADSPCS_CPA_SHIFT; | ||
70 | |||
71 | /* And cores having CRST bit cleared */ | ||
72 | en_cores_mask &= (~val & SKL_ADSPCS_CRST_MASK(core_mask)) >> | ||
73 | SKL_ADSPCS_CRST_SHIFT; | ||
74 | |||
75 | /* And cores having CSTALL bit cleared */ | ||
76 | en_cores_mask &= (~val & SKL_ADSPCS_CSTALL_MASK(core_mask)) >> | ||
77 | SKL_ADSPCS_CSTALL_SHIFT; | ||
78 | en_cores_mask &= core_mask; | ||
79 | |||
80 | dev_dbg(ctx->dev, "DSP enabled cores mask = %x\n", en_cores_mask); | ||
81 | |||
82 | return en_cores_mask; | ||
83 | } | ||
84 | |||
85 | static int | ||
86 | skl_dsp_core_set_reset_state(struct sst_dsp *ctx, unsigned int core_mask) | ||
38 | { | 87 | { |
39 | int ret; | 88 | int ret; |
40 | 89 | ||
41 | /* update bits */ | 90 | /* update bits */ |
42 | sst_dsp_shim_update_bits_unlocked(ctx, | 91 | sst_dsp_shim_update_bits_unlocked(ctx, |
43 | SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, | 92 | SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK(core_mask), |
44 | SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); | 93 | SKL_ADSPCS_CRST_MASK(core_mask)); |
45 | 94 | ||
46 | /* poll with timeout to check if operation successful */ | 95 | /* poll with timeout to check if operation successful */ |
47 | ret = sst_dsp_register_poll(ctx, | 96 | ret = sst_dsp_register_poll(ctx, |
48 | SKL_ADSP_REG_ADSPCS, | 97 | SKL_ADSP_REG_ADSPCS, |
49 | SKL_ADSPCS_CRST_MASK, | 98 | SKL_ADSPCS_CRST_MASK(core_mask), |
50 | SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), | 99 | SKL_ADSPCS_CRST_MASK(core_mask), |
51 | SKL_DSP_RESET_TO, | 100 | SKL_DSP_RESET_TO, |
52 | "Set reset"); | 101 | "Set reset"); |
53 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & | 102 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & |
54 | SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != | 103 | SKL_ADSPCS_CRST_MASK(core_mask)) != |
55 | SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { | 104 | SKL_ADSPCS_CRST_MASK(core_mask)) { |
56 | dev_err(ctx->dev, "Set reset state failed\n"); | 105 | dev_err(ctx->dev, "Set reset state failed: core_mask %x\n", |
106 | core_mask); | ||
57 | ret = -EIO; | 107 | ret = -EIO; |
58 | } | 108 | } |
59 | 109 | ||
60 | return ret; | 110 | return ret; |
61 | } | 111 | } |
62 | 112 | ||
63 | static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) | 113 | int skl_dsp_core_unset_reset_state( |
114 | struct sst_dsp *ctx, unsigned int core_mask) | ||
64 | { | 115 | { |
65 | int ret; | 116 | int ret; |
66 | 117 | ||
@@ -68,152 +119,160 @@ static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) | |||
68 | 119 | ||
69 | /* update bits */ | 120 | /* update bits */ |
70 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, | 121 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, |
71 | SKL_ADSPCS_CRST_MASK, 0); | 122 | SKL_ADSPCS_CRST_MASK(core_mask), 0); |
72 | 123 | ||
73 | /* poll with timeout to check if operation successful */ | 124 | /* poll with timeout to check if operation successful */ |
74 | ret = sst_dsp_register_poll(ctx, | 125 | ret = sst_dsp_register_poll(ctx, |
75 | SKL_ADSP_REG_ADSPCS, | 126 | SKL_ADSP_REG_ADSPCS, |
76 | SKL_ADSPCS_CRST_MASK, | 127 | SKL_ADSPCS_CRST_MASK(core_mask), |
77 | 0, | 128 | 0, |
78 | SKL_DSP_RESET_TO, | 129 | SKL_DSP_RESET_TO, |
79 | "Unset reset"); | 130 | "Unset reset"); |
80 | 131 | ||
81 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & | 132 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & |
82 | SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { | 133 | SKL_ADSPCS_CRST_MASK(core_mask)) != 0) { |
83 | dev_err(ctx->dev, "Unset reset state failed\n"); | 134 | dev_err(ctx->dev, "Unset reset state failed: core_mask %x\n", |
135 | core_mask); | ||
84 | ret = -EIO; | 136 | ret = -EIO; |
85 | } | 137 | } |
86 | 138 | ||
87 | return ret; | 139 | return ret; |
88 | } | 140 | } |
89 | 141 | ||
90 | static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) | 142 | static bool |
143 | is_skl_dsp_core_enable(struct sst_dsp *ctx, unsigned int core_mask) | ||
91 | { | 144 | { |
92 | int val; | 145 | int val; |
93 | bool is_enable; | 146 | bool is_enable; |
94 | 147 | ||
95 | val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); | 148 | val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); |
96 | 149 | ||
97 | is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && | 150 | is_enable = ((val & SKL_ADSPCS_CPA_MASK(core_mask)) && |
98 | (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && | 151 | (val & SKL_ADSPCS_SPA_MASK(core_mask)) && |
99 | !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && | 152 | !(val & SKL_ADSPCS_CRST_MASK(core_mask)) && |
100 | !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); | 153 | !(val & SKL_ADSPCS_CSTALL_MASK(core_mask))); |
154 | |||
155 | dev_dbg(ctx->dev, "DSP core(s) enabled? %d : core_mask %x\n", | ||
156 | is_enable, core_mask); | ||
101 | 157 | ||
102 | dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); | ||
103 | return is_enable; | 158 | return is_enable; |
104 | } | 159 | } |
105 | 160 | ||
106 | static int skl_dsp_reset_core(struct sst_dsp *ctx) | 161 | static int skl_dsp_reset_core(struct sst_dsp *ctx, unsigned int core_mask) |
107 | { | 162 | { |
108 | /* stall core */ | 163 | /* stall core */ |
109 | sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, | 164 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, |
110 | sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & | 165 | SKL_ADSPCS_CSTALL_MASK(core_mask), |
111 | SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); | 166 | SKL_ADSPCS_CSTALL_MASK(core_mask)); |
112 | 167 | ||
113 | /* set reset state */ | 168 | /* set reset state */ |
114 | return skl_dsp_core_set_reset_state(ctx); | 169 | return skl_dsp_core_set_reset_state(ctx, core_mask); |
115 | } | 170 | } |
116 | 171 | ||
117 | static int skl_dsp_start_core(struct sst_dsp *ctx) | 172 | int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask) |
118 | { | 173 | { |
119 | int ret; | 174 | int ret; |
120 | 175 | ||
121 | /* unset reset state */ | 176 | /* unset reset state */ |
122 | ret = skl_dsp_core_unset_reset_state(ctx); | 177 | ret = skl_dsp_core_unset_reset_state(ctx, core_mask); |
123 | if (ret < 0) { | 178 | if (ret < 0) |
124 | dev_dbg(ctx->dev, "dsp unset reset fails\n"); | ||
125 | return ret; | 179 | return ret; |
126 | } | ||
127 | 180 | ||
128 | /* run core */ | 181 | /* run core */ |
129 | dev_dbg(ctx->dev, "run core...\n"); | 182 | dev_dbg(ctx->dev, "unstall/run core: core_mask = %x\n", core_mask); |
130 | sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, | 183 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, |
131 | sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & | 184 | SKL_ADSPCS_CSTALL_MASK(core_mask), 0); |
132 | ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); | 185 | |
133 | 186 | if (!is_skl_dsp_core_enable(ctx, core_mask)) { | |
134 | if (!is_skl_dsp_core_enable(ctx)) { | 187 | skl_dsp_reset_core(ctx, core_mask); |
135 | skl_dsp_reset_core(ctx); | 188 | dev_err(ctx->dev, "DSP start core failed: core_mask %x\n", |
136 | dev_err(ctx->dev, "DSP core enable failed\n"); | 189 | core_mask); |
137 | ret = -EIO; | 190 | ret = -EIO; |
138 | } | 191 | } |
139 | 192 | ||
140 | return ret; | 193 | return ret; |
141 | } | 194 | } |
142 | 195 | ||
143 | static int skl_dsp_core_power_up(struct sst_dsp *ctx) | 196 | int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask) |
144 | { | 197 | { |
145 | int ret; | 198 | int ret; |
146 | 199 | ||
147 | /* update bits */ | 200 | /* update bits */ |
148 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, | 201 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, |
149 | SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); | 202 | SKL_ADSPCS_SPA_MASK(core_mask), |
203 | SKL_ADSPCS_SPA_MASK(core_mask)); | ||
150 | 204 | ||
151 | /* poll with timeout to check if operation successful */ | 205 | /* poll with timeout to check if operation successful */ |
152 | ret = sst_dsp_register_poll(ctx, | 206 | ret = sst_dsp_register_poll(ctx, |
153 | SKL_ADSP_REG_ADSPCS, | 207 | SKL_ADSP_REG_ADSPCS, |
154 | SKL_ADSPCS_CPA_MASK, | 208 | SKL_ADSPCS_CPA_MASK(core_mask), |
155 | SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), | 209 | SKL_ADSPCS_CPA_MASK(core_mask), |
156 | SKL_DSP_PU_TO, | 210 | SKL_DSP_PU_TO, |
157 | "Power up"); | 211 | "Power up"); |
158 | 212 | ||
159 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & | 213 | if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & |
160 | SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) != | 214 | SKL_ADSPCS_CPA_MASK(core_mask)) != |
161 | SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { | 215 | SKL_ADSPCS_CPA_MASK(core_mask)) { |
162 | dev_err(ctx->dev, "DSP core power up failed\n"); | 216 | dev_err(ctx->dev, "DSP core power up failed: core_mask %x\n", |
217 | core_mask); | ||
163 | ret = -EIO; | 218 | ret = -EIO; |
164 | } | 219 | } |
165 | 220 | ||
166 | return ret; | 221 | return ret; |
167 | } | 222 | } |
168 | 223 | ||
169 | static int skl_dsp_core_power_down(struct sst_dsp *ctx) | 224 | int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask) |
170 | { | 225 | { |
171 | /* update bits */ | 226 | /* update bits */ |
172 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, | 227 | sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, |
173 | SKL_ADSPCS_SPA_MASK, 0); | 228 | SKL_ADSPCS_SPA_MASK(core_mask), 0); |
174 | 229 | ||
175 | /* poll with timeout to check if operation successful */ | 230 | /* poll with timeout to check if operation successful */ |
176 | return sst_dsp_register_poll(ctx, | 231 | return sst_dsp_register_poll(ctx, |
177 | SKL_ADSP_REG_ADSPCS, | 232 | SKL_ADSP_REG_ADSPCS, |
178 | SKL_ADSPCS_CPA_MASK, | 233 | SKL_ADSPCS_CPA_MASK(core_mask), |
179 | 0, | 234 | 0, |
180 | SKL_DSP_PD_TO, | 235 | SKL_DSP_PD_TO, |
181 | "Power down"); | 236 | "Power down"); |
182 | } | 237 | } |
183 | 238 | ||
184 | int skl_dsp_enable_core(struct sst_dsp *ctx) | 239 | int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask) |
185 | { | 240 | { |
186 | int ret; | 241 | int ret; |
187 | 242 | ||
188 | /* power up */ | 243 | /* power up */ |
189 | ret = skl_dsp_core_power_up(ctx); | 244 | ret = skl_dsp_core_power_up(ctx, core_mask); |
190 | if (ret < 0) { | 245 | if (ret < 0) { |
191 | dev_dbg(ctx->dev, "dsp core power up failed\n"); | 246 | dev_err(ctx->dev, "dsp core power up failed: core_mask %x\n", |
247 | core_mask); | ||
192 | return ret; | 248 | return ret; |
193 | } | 249 | } |
194 | 250 | ||
195 | return skl_dsp_start_core(ctx); | 251 | return skl_dsp_start_core(ctx, core_mask); |
196 | } | 252 | } |
197 | 253 | ||
198 | int skl_dsp_disable_core(struct sst_dsp *ctx) | 254 | int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask) |
199 | { | 255 | { |
200 | int ret; | 256 | int ret; |
201 | 257 | ||
202 | ret = skl_dsp_reset_core(ctx); | 258 | ret = skl_dsp_reset_core(ctx, core_mask); |
203 | if (ret < 0) { | 259 | if (ret < 0) { |
204 | dev_err(ctx->dev, "dsp core reset failed\n"); | 260 | dev_err(ctx->dev, "dsp core reset failed: core_mask %x\n", |
261 | core_mask); | ||
205 | return ret; | 262 | return ret; |
206 | } | 263 | } |
207 | 264 | ||
208 | /* power down core*/ | 265 | /* power down core*/ |
209 | ret = skl_dsp_core_power_down(ctx); | 266 | ret = skl_dsp_core_power_down(ctx, core_mask); |
210 | if (ret < 0) { | 267 | if (ret < 0) { |
211 | dev_err(ctx->dev, "dsp core power down failed\n"); | 268 | dev_err(ctx->dev, "dsp core power down fail mask %x: %d\n", |
269 | core_mask, ret); | ||
212 | return ret; | 270 | return ret; |
213 | } | 271 | } |
214 | 272 | ||
215 | if (is_skl_dsp_core_enable(ctx)) { | 273 | if (is_skl_dsp_core_enable(ctx, core_mask)) { |
216 | dev_err(ctx->dev, "DSP core disable failed\n"); | 274 | dev_err(ctx->dev, "dsp core disable fail mask %x: %d\n", |
275 | core_mask, ret); | ||
217 | ret = -EIO; | 276 | ret = -EIO; |
218 | } | 277 | } |
219 | 278 | ||
@@ -224,28 +283,25 @@ int skl_dsp_boot(struct sst_dsp *ctx) | |||
224 | { | 283 | { |
225 | int ret; | 284 | int ret; |
226 | 285 | ||
227 | if (is_skl_dsp_core_enable(ctx)) { | 286 | if (is_skl_dsp_core_enable(ctx, SKL_DSP_CORE0_MASK)) { |
228 | dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); | 287 | ret = skl_dsp_reset_core(ctx, SKL_DSP_CORE0_MASK); |
229 | ret = skl_dsp_reset_core(ctx); | ||
230 | if (ret < 0) { | 288 | if (ret < 0) { |
231 | dev_err(ctx->dev, "dsp reset failed\n"); | 289 | dev_err(ctx->dev, "dsp core0 reset fail: %d\n", ret); |
232 | return ret; | 290 | return ret; |
233 | } | 291 | } |
234 | 292 | ||
235 | ret = skl_dsp_start_core(ctx); | 293 | ret = skl_dsp_start_core(ctx, SKL_DSP_CORE0_MASK); |
236 | if (ret < 0) { | 294 | if (ret < 0) { |
237 | dev_err(ctx->dev, "dsp start failed\n"); | 295 | dev_err(ctx->dev, "dsp core0 start fail: %d\n", ret); |
238 | return ret; | 296 | return ret; |
239 | } | 297 | } |
240 | } else { | 298 | } else { |
241 | dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); | 299 | ret = skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); |
242 | ret = skl_dsp_disable_core(ctx); | ||
243 | |||
244 | if (ret < 0) { | 300 | if (ret < 0) { |
245 | dev_err(ctx->dev, "dsp disable core failes\n"); | 301 | dev_err(ctx->dev, "dsp core0 disable fail: %d\n", ret); |
246 | return ret; | 302 | return ret; |
247 | } | 303 | } |
248 | ret = skl_dsp_enable_core(ctx); | 304 | ret = skl_dsp_enable_core(ctx, SKL_DSP_CORE0_MASK); |
249 | } | 305 | } |
250 | 306 | ||
251 | return ret; | 307 | return ret; |
@@ -281,16 +337,74 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) | |||
281 | 337 | ||
282 | return result; | 338 | return result; |
283 | } | 339 | } |
340 | /* | ||
341 | * skl_dsp_get_core/skl_dsp_put_core will be called inside DAPM context | ||
342 | * within the dapm mutex. Hence no separate lock is used. | ||
343 | */ | ||
344 | int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id) | ||
345 | { | ||
346 | struct skl_sst *skl = ctx->thread_context; | ||
347 | int ret = 0; | ||
348 | |||
349 | if (core_id >= skl->cores.count) { | ||
350 | dev_err(ctx->dev, "invalid core id: %d\n", core_id); | ||
351 | return -EINVAL; | ||
352 | } | ||
353 | |||
354 | if (skl->cores.state[core_id] == SKL_DSP_RESET) { | ||
355 | ret = ctx->fw_ops.set_state_D0(ctx, core_id); | ||
356 | if (ret < 0) { | ||
357 | dev_err(ctx->dev, "unable to get core%d\n", core_id); | ||
358 | return ret; | ||
359 | } | ||
360 | } | ||
361 | |||
362 | skl->cores.usage_count[core_id]++; | ||
363 | |||
364 | dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", | ||
365 | core_id, skl->cores.state[core_id], | ||
366 | skl->cores.usage_count[core_id]); | ||
367 | |||
368 | return ret; | ||
369 | } | ||
370 | EXPORT_SYMBOL_GPL(skl_dsp_get_core); | ||
371 | |||
372 | int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id) | ||
373 | { | ||
374 | struct skl_sst *skl = ctx->thread_context; | ||
375 | int ret = 0; | ||
376 | |||
377 | if (core_id >= skl->cores.count) { | ||
378 | dev_err(ctx->dev, "invalid core id: %d\n", core_id); | ||
379 | return -EINVAL; | ||
380 | } | ||
381 | |||
382 | if (--skl->cores.usage_count[core_id] == 0) { | ||
383 | ret = ctx->fw_ops.set_state_D3(ctx, core_id); | ||
384 | if (ret < 0) { | ||
385 | dev_err(ctx->dev, "unable to put core %d: %d\n", | ||
386 | core_id, ret); | ||
387 | skl->cores.usage_count[core_id]++; | ||
388 | } | ||
389 | } | ||
390 | |||
391 | dev_dbg(ctx->dev, "core id %d state %d usage_count %d\n", | ||
392 | core_id, skl->cores.state[core_id], | ||
393 | skl->cores.usage_count[core_id]); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | EXPORT_SYMBOL_GPL(skl_dsp_put_core); | ||
284 | 398 | ||
285 | int skl_dsp_wake(struct sst_dsp *ctx) | 399 | int skl_dsp_wake(struct sst_dsp *ctx) |
286 | { | 400 | { |
287 | return ctx->fw_ops.set_state_D0(ctx); | 401 | return skl_dsp_get_core(ctx, SKL_DSP_CORE0_ID); |
288 | } | 402 | } |
289 | EXPORT_SYMBOL_GPL(skl_dsp_wake); | 403 | EXPORT_SYMBOL_GPL(skl_dsp_wake); |
290 | 404 | ||
291 | int skl_dsp_sleep(struct sst_dsp *ctx) | 405 | int skl_dsp_sleep(struct sst_dsp *ctx) |
292 | { | 406 | { |
293 | return ctx->fw_ops.set_state_D3(ctx); | 407 | return skl_dsp_put_core(ctx, SKL_DSP_CORE0_ID); |
294 | } | 408 | } |
295 | EXPORT_SYMBOL_GPL(skl_dsp_sleep); | 409 | EXPORT_SYMBOL_GPL(skl_dsp_sleep); |
296 | 410 | ||
@@ -337,9 +451,7 @@ void skl_dsp_free(struct sst_dsp *dsp) | |||
337 | 451 | ||
338 | free_irq(dsp->irq, dsp); | 452 | free_irq(dsp->irq, dsp); |
339 | skl_ipc_op_int_disable(dsp); | 453 | skl_ipc_op_int_disable(dsp); |
340 | skl_ipc_int_disable(dsp); | 454 | skl_dsp_disable_core(dsp, SKL_DSP_CORE0_MASK); |
341 | |||
342 | skl_dsp_disable_core(dsp); | ||
343 | } | 455 | } |
344 | EXPORT_SYMBOL_GPL(skl_dsp_free); | 456 | EXPORT_SYMBOL_GPL(skl_dsp_free); |
345 | 457 | ||
diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index deabe7308d3b..0f8629ef79ac 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
20 | #include <sound/memalloc.h> | 20 | #include <sound/memalloc.h> |
21 | #include "skl-sst-cldma.h" | 21 | #include "skl-sst-cldma.h" |
22 | #include "skl-tplg-interface.h" | ||
22 | 23 | ||
23 | struct sst_dsp; | 24 | struct sst_dsp; |
24 | struct skl_sst; | 25 | struct skl_sst; |
@@ -76,35 +77,53 @@ struct sst_dsp_device; | |||
76 | #define SKL_ADSPIC_IPC 1 | 77 | #define SKL_ADSPIC_IPC 1 |
77 | #define SKL_ADSPIS_IPC 1 | 78 | #define SKL_ADSPIS_IPC 1 |
78 | 79 | ||
80 | /* Core ID of core0 */ | ||
81 | #define SKL_DSP_CORE0_ID 0 | ||
82 | |||
83 | /* Mask for a given core index, c = 0.. number of supported cores - 1 */ | ||
84 | #define SKL_DSP_CORE_MASK(c) BIT(c) | ||
85 | |||
86 | /* | ||
87 | * Core 0 mask = SKL_DSP_CORE_MASK(0); Defined separately | ||
88 | * since Core0 is primary core and it is used often | ||
89 | */ | ||
90 | #define SKL_DSP_CORE0_MASK BIT(0) | ||
91 | |||
92 | /* | ||
93 | * Mask for a given number of cores | ||
94 | * nc = number of supported cores | ||
95 | */ | ||
96 | #define SKL_DSP_CORES_MASK(nc) GENMASK((nc - 1), 0) | ||
97 | |||
79 | /* ADSPCS - Audio DSP Control & Status */ | 98 | /* ADSPCS - Audio DSP Control & Status */ |
80 | #define SKL_DSP_CORES 1 | 99 | |
81 | #define SKL_DSP_CORE0_MASK 1 | 100 | /* |
82 | #define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1) | 101 | * Core Reset - asserted high |
83 | 102 | * CRST Mask for a given core mask pattern, cm | |
84 | /* Core Reset - asserted high */ | 103 | */ |
85 | #define SKL_ADSPCS_CRST_SHIFT 0 | 104 | #define SKL_ADSPCS_CRST_SHIFT 0 |
86 | #define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT) | 105 | #define SKL_ADSPCS_CRST_MASK(cm) ((cm) << SKL_ADSPCS_CRST_SHIFT) |
87 | #define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK) | 106 | |
88 | 107 | /* | |
89 | /* Core run/stall - when set to '1' core is stalled */ | 108 | * Core run/stall - when set to '1' core is stalled |
90 | #define SKL_ADSPCS_CSTALL_SHIFT 8 | 109 | * CSTALL Mask for a given core mask pattern, cm |
91 | #define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \ | 110 | */ |
92 | SKL_ADSPCS_CSTALL_SHIFT) | 111 | #define SKL_ADSPCS_CSTALL_SHIFT 8 |
93 | #define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \ | 112 | #define SKL_ADSPCS_CSTALL_MASK(cm) ((cm) << SKL_ADSPCS_CSTALL_SHIFT) |
94 | SKL_ADSPCS_CSTALL_MASK) | 113 | |
95 | 114 | /* | |
96 | /* Set Power Active - when set to '1' turn cores on */ | 115 | * Set Power Active - when set to '1' turn cores on |
97 | #define SKL_ADSPCS_SPA_SHIFT 16 | 116 | * SPA Mask for a given core mask pattern, cm |
98 | #define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT) | 117 | */ |
99 | #define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK) | 118 | #define SKL_ADSPCS_SPA_SHIFT 16 |
100 | 119 | #define SKL_ADSPCS_SPA_MASK(cm) ((cm) << SKL_ADSPCS_SPA_SHIFT) | |
101 | /* Current Power Active - power status of cores, set by hardware */ | 120 | |
102 | #define SKL_ADSPCS_CPA_SHIFT 24 | 121 | /* |
103 | #define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT) | 122 | * Current Power Active - power status of cores, set by hardware |
104 | #define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK) | 123 | * CPA Mask for a given core mask pattern, cm |
105 | 124 | */ | |
106 | #define SST_DSP_POWER_D0 0x0 /* full On */ | 125 | #define SKL_ADSPCS_CPA_SHIFT 24 |
107 | #define SST_DSP_POWER_D3 0x3 /* Off */ | 126 | #define SKL_ADSPCS_CPA_MASK(cm) ((cm) << SKL_ADSPCS_CPA_SHIFT) |
108 | 127 | ||
109 | enum skl_dsp_states { | 128 | enum skl_dsp_states { |
110 | SKL_DSP_RUNNING = 1, | 129 | SKL_DSP_RUNNING = 1, |
@@ -115,8 +134,8 @@ struct skl_dsp_fw_ops { | |||
115 | int (*load_fw)(struct sst_dsp *ctx); | 134 | int (*load_fw)(struct sst_dsp *ctx); |
116 | /* FW module parser/loader */ | 135 | /* FW module parser/loader */ |
117 | int (*parse_fw)(struct sst_dsp *ctx); | 136 | int (*parse_fw)(struct sst_dsp *ctx); |
118 | int (*set_state_D0)(struct sst_dsp *ctx); | 137 | int (*set_state_D0)(struct sst_dsp *ctx, unsigned int core_id); |
119 | int (*set_state_D3)(struct sst_dsp *ctx); | 138 | int (*set_state_D3)(struct sst_dsp *ctx, unsigned int core_id); |
120 | unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); | 139 | unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); |
121 | int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); | 140 | int (*load_mod)(struct sst_dsp *ctx, u16 mod_id, u8 *mod_name); |
122 | int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); | 141 | int (*unload_mod)(struct sst_dsp *ctx, u16 mod_id); |
@@ -157,14 +176,26 @@ int skl_cldma_prepare(struct sst_dsp *ctx); | |||
157 | void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); | 176 | void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); |
158 | struct sst_dsp *skl_dsp_ctx_init(struct device *dev, | 177 | struct sst_dsp *skl_dsp_ctx_init(struct device *dev, |
159 | struct sst_dsp_device *sst_dev, int irq); | 178 | struct sst_dsp_device *sst_dev, int irq); |
160 | int skl_dsp_enable_core(struct sst_dsp *ctx); | ||
161 | int skl_dsp_disable_core(struct sst_dsp *ctx); | ||
162 | bool is_skl_dsp_running(struct sst_dsp *ctx); | 179 | bool is_skl_dsp_running(struct sst_dsp *ctx); |
180 | |||
181 | unsigned int skl_dsp_get_enabled_cores(struct sst_dsp *ctx); | ||
182 | void skl_dsp_init_core_state(struct sst_dsp *ctx); | ||
183 | int skl_dsp_enable_core(struct sst_dsp *ctx, unsigned int core_mask); | ||
184 | int skl_dsp_disable_core(struct sst_dsp *ctx, unsigned int core_mask); | ||
185 | int skl_dsp_core_power_up(struct sst_dsp *ctx, unsigned int core_mask); | ||
186 | int skl_dsp_core_power_down(struct sst_dsp *ctx, unsigned int core_mask); | ||
187 | int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx, | ||
188 | unsigned int core_mask); | ||
189 | int skl_dsp_start_core(struct sst_dsp *ctx, unsigned int core_mask); | ||
190 | |||
163 | irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); | 191 | irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); |
164 | int skl_dsp_wake(struct sst_dsp *ctx); | 192 | int skl_dsp_wake(struct sst_dsp *ctx); |
165 | int skl_dsp_sleep(struct sst_dsp *ctx); | 193 | int skl_dsp_sleep(struct sst_dsp *ctx); |
166 | void skl_dsp_free(struct sst_dsp *dsp); | 194 | void skl_dsp_free(struct sst_dsp *dsp); |
167 | 195 | ||
196 | int skl_dsp_get_core(struct sst_dsp *ctx, unsigned int core_id); | ||
197 | int skl_dsp_put_core(struct sst_dsp *ctx, unsigned int core_id); | ||
198 | |||
168 | int skl_dsp_boot(struct sst_dsp *ctx); | 199 | int skl_dsp_boot(struct sst_dsp *ctx); |
169 | int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | 200 | int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, |
170 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, | 201 | const char *fw_name, struct skl_dsp_loader_ops dsp_ops, |
@@ -175,4 +206,11 @@ int bxt_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
175 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | 206 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); |
176 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); | 207 | void bxt_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); |
177 | 208 | ||
209 | int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | ||
210 | struct skl_dfw_module *dfw_config); | ||
211 | int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset); | ||
212 | void skl_freeup_uuid_list(struct skl_sst *ctx); | ||
213 | |||
214 | int skl_dsp_strip_extended_manifest(struct firmware *fw); | ||
215 | |||
178 | #endif /*__SKL_SST_DSP_H__*/ | 216 | #endif /*__SKL_SST_DSP_H__*/ |
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 543460293b00..96f2f6889b18 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c | |||
@@ -363,7 +363,7 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, | |||
363 | /* first process the header */ | 363 | /* first process the header */ |
364 | switch (reply) { | 364 | switch (reply) { |
365 | case IPC_GLB_REPLY_SUCCESS: | 365 | case IPC_GLB_REPLY_SUCCESS: |
366 | dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); | 366 | dev_dbg(ipc->dev, "ipc FW reply %x: success\n", header.primary); |
367 | /* copy the rx data from the mailbox */ | 367 | /* copy the rx data from the mailbox */ |
368 | sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); | 368 | sst_dsp_inbox_read(ipc->dsp, msg->rx_data, msg->rx_size); |
369 | break; | 369 | break; |
@@ -692,7 +692,7 @@ int skl_ipc_init_instance(struct sst_generic_ipc *ipc, | |||
692 | /* param_block_size must be in dwords */ | 692 | /* param_block_size must be in dwords */ |
693 | u16 param_block_size = msg->param_data_size / sizeof(u32); | 693 | u16 param_block_size = msg->param_data_size / sizeof(u32); |
694 | 694 | ||
695 | print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, | 695 | print_hex_dump_debug("Param data:", DUMP_PREFIX_NONE, |
696 | 16, 4, buffer, param_block_size, false); | 696 | 16, 4, buffer, param_block_size, false); |
697 | 697 | ||
698 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); | 698 | header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); |
diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index d59d1ba62a43..2e3d4e80ef97 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h | |||
@@ -45,6 +45,14 @@ struct skl_ipc_header { | |||
45 | u32 extension; | 45 | u32 extension; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | #define SKL_DSP_CORES_MAX 2 | ||
49 | |||
50 | struct skl_dsp_cores { | ||
51 | unsigned int count; | ||
52 | enum skl_dsp_states state[SKL_DSP_CORES_MAX]; | ||
53 | int usage_count[SKL_DSP_CORES_MAX]; | ||
54 | }; | ||
55 | |||
48 | struct skl_sst { | 56 | struct skl_sst { |
49 | struct device *dev; | 57 | struct device *dev; |
50 | struct sst_dsp *dsp; | 58 | struct sst_dsp *dsp; |
@@ -60,6 +68,15 @@ struct skl_sst { | |||
60 | void (*enable_miscbdcge)(struct device *dev, bool enable); | 68 | void (*enable_miscbdcge)(struct device *dev, bool enable); |
61 | /*Is CGCTL.MISCBDCGE disabled*/ | 69 | /*Is CGCTL.MISCBDCGE disabled*/ |
62 | bool miscbdcg_disabled; | 70 | bool miscbdcg_disabled; |
71 | |||
72 | /* Populate module information */ | ||
73 | struct list_head uuid_list; | ||
74 | |||
75 | /* Is firmware loaded */ | ||
76 | bool fw_loaded; | ||
77 | |||
78 | /* multi-core */ | ||
79 | struct skl_dsp_cores cores; | ||
63 | }; | 80 | }; |
64 | 81 | ||
65 | struct skl_ipc_init_instance_msg { | 82 | struct skl_ipc_init_instance_msg { |
@@ -136,5 +153,6 @@ void skl_ipc_int_disable(struct sst_dsp *dsp); | |||
136 | bool skl_ipc_int_status(struct sst_dsp *dsp); | 153 | bool skl_ipc_int_status(struct sst_dsp *dsp); |
137 | void skl_ipc_free(struct sst_generic_ipc *ipc); | 154 | void skl_ipc_free(struct sst_generic_ipc *ipc); |
138 | int skl_ipc_init(struct device *dev, struct skl_sst *skl); | 155 | int skl_ipc_init(struct device *dev, struct skl_sst *skl); |
156 | void skl_clear_module_cnt(struct sst_dsp *ctx); | ||
139 | 157 | ||
140 | #endif /* __SKL_IPC_H */ | 158 | #endif /* __SKL_IPC_H */ |
diff --git a/sound/soc/intel/skylake/skl-sst-utils.c b/sound/soc/intel/skylake/skl-sst-utils.c new file mode 100644 index 000000000000..25fcb796bd86 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-utils.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * skl-sst-utils.c - SKL sst utils functions | ||
3 | * | ||
4 | * Copyright (C) 2016 Intel Corp | ||
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 as version 2, as | ||
8 | * 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 | |||
16 | #include <linux/device.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/uuid.h> | ||
19 | #include "skl-sst-dsp.h" | ||
20 | #include "../common/sst-dsp.h" | ||
21 | #include "../common/sst-dsp-priv.h" | ||
22 | #include "skl-sst-ipc.h" | ||
23 | |||
24 | |||
25 | #define UUID_STR_SIZE 37 | ||
26 | #define DEFAULT_HASH_SHA256_LEN 32 | ||
27 | |||
28 | /* FW Extended Manifest Header id = $AE1 */ | ||
29 | #define SKL_EXT_MANIFEST_HEADER_MAGIC 0x31454124 | ||
30 | |||
31 | struct skl_dfw_module_mod { | ||
32 | char name[100]; | ||
33 | struct skl_dfw_module skl_dfw_mod; | ||
34 | }; | ||
35 | |||
36 | struct UUID { | ||
37 | u8 id[16]; | ||
38 | }; | ||
39 | |||
40 | union seg_flags { | ||
41 | u32 ul; | ||
42 | struct { | ||
43 | u32 contents : 1; | ||
44 | u32 alloc : 1; | ||
45 | u32 load : 1; | ||
46 | u32 read_only : 1; | ||
47 | u32 code : 1; | ||
48 | u32 data : 1; | ||
49 | u32 _rsvd0 : 2; | ||
50 | u32 type : 4; | ||
51 | u32 _rsvd1 : 4; | ||
52 | u32 length : 16; | ||
53 | } r; | ||
54 | } __packed; | ||
55 | |||
56 | struct segment_desc { | ||
57 | union seg_flags flags; | ||
58 | u32 v_base_addr; | ||
59 | u32 file_offset; | ||
60 | }; | ||
61 | |||
62 | struct module_type { | ||
63 | u32 load_type : 4; | ||
64 | u32 auto_start : 1; | ||
65 | u32 domain_ll : 1; | ||
66 | u32 domain_dp : 1; | ||
67 | u32 rsvd : 25; | ||
68 | } __packed; | ||
69 | |||
70 | struct adsp_module_entry { | ||
71 | u32 struct_id; | ||
72 | u8 name[8]; | ||
73 | struct UUID uuid; | ||
74 | struct module_type type; | ||
75 | u8 hash1[DEFAULT_HASH_SHA256_LEN]; | ||
76 | u32 entry_point; | ||
77 | u16 cfg_offset; | ||
78 | u16 cfg_count; | ||
79 | u32 affinity_mask; | ||
80 | u16 instance_max_count; | ||
81 | u16 instance_bss_size; | ||
82 | struct segment_desc segments[3]; | ||
83 | } __packed; | ||
84 | |||
85 | struct adsp_fw_hdr { | ||
86 | u32 id; | ||
87 | u32 len; | ||
88 | u8 name[8]; | ||
89 | u32 preload_page_count; | ||
90 | u32 fw_image_flags; | ||
91 | u32 feature_mask; | ||
92 | u16 major; | ||
93 | u16 minor; | ||
94 | u16 hotfix; | ||
95 | u16 build; | ||
96 | u32 num_modules; | ||
97 | u32 hw_buf_base; | ||
98 | u32 hw_buf_length; | ||
99 | u32 load_offset; | ||
100 | } __packed; | ||
101 | |||
102 | struct uuid_module { | ||
103 | uuid_le uuid; | ||
104 | int id; | ||
105 | int is_loadable; | ||
106 | |||
107 | struct list_head list; | ||
108 | }; | ||
109 | |||
110 | struct skl_ext_manifest_hdr { | ||
111 | u32 id; | ||
112 | u32 len; | ||
113 | u16 version_major; | ||
114 | u16 version_minor; | ||
115 | u32 entries; | ||
116 | }; | ||
117 | |||
118 | int snd_skl_get_module_info(struct skl_sst *ctx, u8 *uuid, | ||
119 | struct skl_dfw_module *dfw_config) | ||
120 | { | ||
121 | struct uuid_module *module; | ||
122 | uuid_le *uuid_mod; | ||
123 | |||
124 | uuid_mod = (uuid_le *)uuid; | ||
125 | |||
126 | list_for_each_entry(module, &ctx->uuid_list, list) { | ||
127 | if (uuid_le_cmp(*uuid_mod, module->uuid) == 0) { | ||
128 | dfw_config->module_id = module->id; | ||
129 | dfw_config->is_loadable = module->is_loadable; | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | return -EINVAL; | ||
136 | } | ||
137 | EXPORT_SYMBOL_GPL(snd_skl_get_module_info); | ||
138 | |||
139 | /* | ||
140 | * Parse the firmware binary to get the UUID, module id | ||
141 | * and loadable flags | ||
142 | */ | ||
143 | int snd_skl_parse_uuids(struct sst_dsp *ctx, unsigned int offset) | ||
144 | { | ||
145 | struct adsp_fw_hdr *adsp_hdr; | ||
146 | struct adsp_module_entry *mod_entry; | ||
147 | int i, num_entry; | ||
148 | uuid_le *uuid_bin; | ||
149 | const char *buf; | ||
150 | struct skl_sst *skl = ctx->thread_context; | ||
151 | struct uuid_module *module; | ||
152 | struct firmware stripped_fw; | ||
153 | unsigned int safe_file; | ||
154 | |||
155 | /* Get the FW pointer to derive ADSP header */ | ||
156 | stripped_fw.data = ctx->fw->data; | ||
157 | stripped_fw.size = ctx->fw->size; | ||
158 | |||
159 | skl_dsp_strip_extended_manifest(&stripped_fw); | ||
160 | |||
161 | buf = stripped_fw.data; | ||
162 | |||
163 | /* check if we have enough space in file to move to header */ | ||
164 | safe_file = sizeof(*adsp_hdr) + offset; | ||
165 | if (stripped_fw.size <= safe_file) { | ||
166 | dev_err(ctx->dev, "Small fw file size, No space for hdr\n"); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | adsp_hdr = (struct adsp_fw_hdr *)(buf + offset); | ||
171 | |||
172 | /* check 1st module entry is in file */ | ||
173 | safe_file += adsp_hdr->len + sizeof(*mod_entry); | ||
174 | if (stripped_fw.size <= safe_file) { | ||
175 | dev_err(ctx->dev, "Small fw file size, No module entry\n"); | ||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | mod_entry = (struct adsp_module_entry *) | ||
180 | (buf + offset + adsp_hdr->len); | ||
181 | |||
182 | num_entry = adsp_hdr->num_modules; | ||
183 | |||
184 | /* check all entries are in file */ | ||
185 | safe_file += num_entry * sizeof(*mod_entry); | ||
186 | if (stripped_fw.size <= safe_file) { | ||
187 | dev_err(ctx->dev, "Small fw file size, No modules\n"); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* | ||
193 | * Read the UUID(GUID) from FW Manifest. | ||
194 | * | ||
195 | * The 16 byte UUID format is: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXX | ||
196 | * Populate the UUID table to store module_id and loadable flags | ||
197 | * for the module. | ||
198 | */ | ||
199 | |||
200 | for (i = 0; i < num_entry; i++, mod_entry++) { | ||
201 | module = kzalloc(sizeof(*module), GFP_KERNEL); | ||
202 | if (!module) | ||
203 | return -ENOMEM; | ||
204 | |||
205 | uuid_bin = (uuid_le *)mod_entry->uuid.id; | ||
206 | memcpy(&module->uuid, uuid_bin, sizeof(module->uuid)); | ||
207 | |||
208 | module->id = i; | ||
209 | module->is_loadable = mod_entry->type.load_type; | ||
210 | |||
211 | list_add_tail(&module->list, &skl->uuid_list); | ||
212 | |||
213 | dev_dbg(ctx->dev, | ||
214 | "Adding uuid :%pUL mod id: %d Loadable: %d\n", | ||
215 | &module->uuid, module->id, module->is_loadable); | ||
216 | } | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | void skl_freeup_uuid_list(struct skl_sst *ctx) | ||
222 | { | ||
223 | struct uuid_module *uuid, *_uuid; | ||
224 | |||
225 | list_for_each_entry_safe(uuid, _uuid, &ctx->uuid_list, list) { | ||
226 | list_del(&uuid->list); | ||
227 | kfree(uuid); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | /* | ||
232 | * some firmware binary contains some extended manifest. This needs | ||
233 | * to be stripped in that case before we load and use that image. | ||
234 | * | ||
235 | * Get the module id for the module by checking | ||
236 | * the table for the UUID for the module | ||
237 | */ | ||
238 | int skl_dsp_strip_extended_manifest(struct firmware *fw) | ||
239 | { | ||
240 | struct skl_ext_manifest_hdr *hdr; | ||
241 | |||
242 | /* check if fw file is greater than header we are looking */ | ||
243 | if (fw->size < sizeof(hdr)) { | ||
244 | pr_err("%s: Firmware file small, no hdr\n", __func__); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | hdr = (struct skl_ext_manifest_hdr *)fw->data; | ||
249 | |||
250 | if (hdr->id == SKL_EXT_MANIFEST_HEADER_MAGIC) { | ||
251 | fw->size -= hdr->len; | ||
252 | fw->data += hdr->len; | ||
253 | } | ||
254 | |||
255 | return 0; | ||
256 | } | ||
diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c index 13ec8d53b526..588f899ceb65 100644 --- a/sound/soc/intel/skylake/skl-sst.c +++ b/sound/soc/intel/skylake/skl-sst.c | |||
@@ -68,10 +68,13 @@ static int skl_transfer_firmware(struct sst_dsp *ctx, | |||
68 | return ret; | 68 | return ret; |
69 | } | 69 | } |
70 | 70 | ||
71 | #define SKL_ADSP_FW_BIN_HDR_OFFSET 0x284 | ||
72 | |||
71 | static int skl_load_base_firmware(struct sst_dsp *ctx) | 73 | static int skl_load_base_firmware(struct sst_dsp *ctx) |
72 | { | 74 | { |
73 | int ret = 0, i; | 75 | int ret = 0, i; |
74 | struct skl_sst *skl = ctx->thread_context; | 76 | struct skl_sst *skl = ctx->thread_context; |
77 | struct firmware stripped_fw; | ||
75 | u32 reg; | 78 | u32 reg; |
76 | 79 | ||
77 | skl->boot_complete = false; | 80 | skl->boot_complete = false; |
@@ -81,11 +84,25 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) | |||
81 | ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); | 84 | ret = request_firmware(&ctx->fw, ctx->fw_name, ctx->dev); |
82 | if (ret < 0) { | 85 | if (ret < 0) { |
83 | dev_err(ctx->dev, "Request firmware failed %d\n", ret); | 86 | dev_err(ctx->dev, "Request firmware failed %d\n", ret); |
84 | skl_dsp_disable_core(ctx); | ||
85 | return -EIO; | 87 | return -EIO; |
86 | } | 88 | } |
87 | } | 89 | } |
88 | 90 | ||
91 | ret = snd_skl_parse_uuids(ctx, SKL_ADSP_FW_BIN_HDR_OFFSET); | ||
92 | if (ret < 0) { | ||
93 | dev_err(ctx->dev, | ||
94 | "UUID parsing err: %d\n", ret); | ||
95 | release_firmware(ctx->fw); | ||
96 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); | ||
97 | return ret; | ||
98 | } | ||
99 | |||
100 | /* check for extended manifest */ | ||
101 | stripped_fw.data = ctx->fw->data; | ||
102 | stripped_fw.size = ctx->fw->size; | ||
103 | |||
104 | skl_dsp_strip_extended_manifest(&stripped_fw); | ||
105 | |||
89 | ret = skl_dsp_boot(ctx); | 106 | ret = skl_dsp_boot(ctx); |
90 | if (ret < 0) { | 107 | if (ret < 0) { |
91 | dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret); | 108 | dev_err(ctx->dev, "Boot dsp core failed ret: %d", ret); |
@@ -119,7 +136,7 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) | |||
119 | goto transfer_firmware_failed; | 136 | goto transfer_firmware_failed; |
120 | } | 137 | } |
121 | 138 | ||
122 | ret = skl_transfer_firmware(ctx, ctx->fw->data, ctx->fw->size); | 139 | ret = skl_transfer_firmware(ctx, stripped_fw.data, stripped_fw.size); |
123 | if (ret < 0) { | 140 | if (ret < 0) { |
124 | dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); | 141 | dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); |
125 | goto transfer_firmware_failed; | 142 | goto transfer_firmware_failed; |
@@ -133,67 +150,87 @@ static int skl_load_base_firmware(struct sst_dsp *ctx) | |||
133 | } | 150 | } |
134 | 151 | ||
135 | dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); | 152 | dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); |
136 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | 153 | skl->fw_loaded = true; |
137 | } | 154 | } |
138 | return 0; | 155 | return 0; |
139 | transfer_firmware_failed: | 156 | transfer_firmware_failed: |
140 | ctx->cl_dev.ops.cl_cleanup_controller(ctx); | 157 | ctx->cl_dev.ops.cl_cleanup_controller(ctx); |
141 | skl_load_base_firmware_failed: | 158 | skl_load_base_firmware_failed: |
142 | skl_dsp_disable_core(ctx); | 159 | skl_dsp_disable_core(ctx, SKL_DSP_CORE0_MASK); |
143 | release_firmware(ctx->fw); | 160 | release_firmware(ctx->fw); |
144 | ctx->fw = NULL; | 161 | ctx->fw = NULL; |
145 | return ret; | 162 | return ret; |
146 | } | 163 | } |
147 | 164 | ||
148 | static int skl_set_dsp_D0(struct sst_dsp *ctx) | 165 | static int skl_set_dsp_D0(struct sst_dsp *ctx, unsigned int core_id) |
149 | { | 166 | { |
150 | int ret; | 167 | int ret; |
168 | struct skl_ipc_dxstate_info dx; | ||
169 | struct skl_sst *skl = ctx->thread_context; | ||
170 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); | ||
151 | 171 | ||
152 | ret = skl_load_base_firmware(ctx); | 172 | /* If core0 is being turned on, we need to load the FW */ |
153 | if (ret < 0) { | 173 | if (core_id == SKL_DSP_CORE0_ID) { |
154 | dev_err(ctx->dev, "unable to load firmware\n"); | 174 | ret = skl_load_base_firmware(ctx); |
155 | return ret; | 175 | if (ret < 0) { |
176 | dev_err(ctx->dev, "unable to load firmware\n"); | ||
177 | return ret; | ||
178 | } | ||
156 | } | 179 | } |
157 | 180 | ||
158 | skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); | 181 | /* |
182 | * If any core other than core 0 is being moved to D0, enable the | ||
183 | * core and send the set dx IPC for the core. | ||
184 | */ | ||
185 | if (core_id != SKL_DSP_CORE0_ID) { | ||
186 | ret = skl_dsp_enable_core(ctx, core_mask); | ||
187 | if (ret < 0) | ||
188 | return ret; | ||
189 | |||
190 | dx.core_mask = core_mask; | ||
191 | dx.dx_mask = core_mask; | ||
192 | |||
193 | ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, | ||
194 | SKL_BASE_FW_MODULE_ID, &dx); | ||
195 | if (ret < 0) { | ||
196 | dev_err(ctx->dev, "Failed to set dsp to D0:core id= %d\n", | ||
197 | core_id); | ||
198 | skl_dsp_disable_core(ctx, core_mask); | ||
199 | } | ||
200 | } | ||
201 | |||
202 | skl->cores.state[core_id] = SKL_DSP_RUNNING; | ||
159 | 203 | ||
160 | return ret; | 204 | return ret; |
161 | } | 205 | } |
162 | 206 | ||
163 | static int skl_set_dsp_D3(struct sst_dsp *ctx) | 207 | static int skl_set_dsp_D3(struct sst_dsp *ctx, unsigned int core_id) |
164 | { | 208 | { |
165 | int ret; | 209 | int ret; |
166 | struct skl_ipc_dxstate_info dx; | 210 | struct skl_ipc_dxstate_info dx; |
167 | struct skl_sst *skl = ctx->thread_context; | 211 | struct skl_sst *skl = ctx->thread_context; |
212 | unsigned int core_mask = SKL_DSP_CORE_MASK(core_id); | ||
168 | 213 | ||
169 | dev_dbg(ctx->dev, "In %s:\n", __func__); | 214 | dx.core_mask = core_mask; |
170 | mutex_lock(&ctx->mutex); | ||
171 | if (!is_skl_dsp_running(ctx)) { | ||
172 | mutex_unlock(&ctx->mutex); | ||
173 | return 0; | ||
174 | } | ||
175 | mutex_unlock(&ctx->mutex); | ||
176 | |||
177 | dx.core_mask = SKL_DSP_CORE0_MASK; | ||
178 | dx.dx_mask = SKL_IPC_D3_MASK; | 215 | dx.dx_mask = SKL_IPC_D3_MASK; |
216 | |||
179 | ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); | 217 | ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); |
180 | if (ret < 0) | 218 | if (ret < 0) |
181 | dev_err(ctx->dev, | 219 | dev_err(ctx->dev, "set Dx core %d fail: %d\n", core_id, ret); |
182 | "D3 request to FW failed, continuing reset: %d", ret); | 220 | |
183 | 221 | if (core_id == SKL_DSP_CORE0_ID) { | |
184 | /* disable Interrupt */ | 222 | /* disable Interrupt */ |
185 | ctx->cl_dev.ops.cl_cleanup_controller(ctx); | 223 | ctx->cl_dev.ops.cl_cleanup_controller(ctx); |
186 | skl_cldma_int_disable(ctx); | 224 | skl_cldma_int_disable(ctx); |
187 | skl_ipc_op_int_disable(ctx); | 225 | skl_ipc_op_int_disable(ctx); |
188 | skl_ipc_int_disable(ctx); | 226 | skl_ipc_int_disable(ctx); |
189 | |||
190 | ret = skl_dsp_disable_core(ctx); | ||
191 | if (ret < 0) { | ||
192 | dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); | ||
193 | ret = -EIO; | ||
194 | } | 227 | } |
195 | skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); | ||
196 | 228 | ||
229 | ret = skl_dsp_disable_core(ctx, core_mask); | ||
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
233 | skl->cores.state[core_id] = SKL_DSP_RESET; | ||
197 | return ret; | 234 | return ret; |
198 | } | 235 | } |
199 | 236 | ||
@@ -360,6 +397,19 @@ static int skl_unload_module(struct sst_dsp *ctx, u16 mod_id) | |||
360 | return ret; | 397 | return ret; |
361 | } | 398 | } |
362 | 399 | ||
400 | void skl_clear_module_cnt(struct sst_dsp *ctx) | ||
401 | { | ||
402 | struct skl_module_table *module; | ||
403 | |||
404 | if (list_empty(&ctx->module_list)) | ||
405 | return; | ||
406 | |||
407 | list_for_each_entry(module, &ctx->module_list, list) { | ||
408 | module->usage_cnt = 0; | ||
409 | } | ||
410 | } | ||
411 | EXPORT_SYMBOL_GPL(skl_clear_module_cnt); | ||
412 | |||
363 | static void skl_clear_module_table(struct sst_dsp *ctx) | 413 | static void skl_clear_module_table(struct sst_dsp *ctx) |
364 | { | 414 | { |
365 | struct skl_module_table *module, *tmp; | 415 | struct skl_module_table *module, *tmp; |
@@ -409,6 +459,7 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
409 | 459 | ||
410 | skl->dev = dev; | 460 | skl->dev = dev; |
411 | skl_dev.thread_context = skl; | 461 | skl_dev.thread_context = skl; |
462 | INIT_LIST_HEAD(&skl->uuid_list); | ||
412 | 463 | ||
413 | skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); | 464 | skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); |
414 | if (!skl->dsp) { | 465 | if (!skl->dsp) { |
@@ -432,12 +483,16 @@ int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, | |||
432 | if (ret) | 483 | if (ret) |
433 | return ret; | 484 | return ret; |
434 | 485 | ||
486 | skl->cores.count = 2; | ||
487 | |||
435 | ret = sst->fw_ops.load_fw(sst); | 488 | ret = sst->fw_ops.load_fw(sst); |
436 | if (ret < 0) { | 489 | if (ret < 0) { |
437 | dev_err(dev, "Load base fw failed : %d", ret); | 490 | dev_err(dev, "Load base fw failed : %d", ret); |
438 | goto cleanup; | 491 | goto cleanup; |
439 | } | 492 | } |
440 | 493 | ||
494 | skl_dsp_init_core_state(sst); | ||
495 | |||
441 | if (dsp) | 496 | if (dsp) |
442 | *dsp = skl; | 497 | *dsp = skl; |
443 | 498 | ||
@@ -452,6 +507,7 @@ EXPORT_SYMBOL_GPL(skl_sst_dsp_init); | |||
452 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) | 507 | void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) |
453 | { | 508 | { |
454 | skl_clear_module_table(ctx->dsp); | 509 | skl_clear_module_table(ctx->dsp); |
510 | skl_freeup_uuid_list(ctx); | ||
455 | skl_ipc_free(&ctx->ipc); | 511 | skl_ipc_free(&ctx->ipc); |
456 | ctx->dsp->ops->free(ctx->dsp); | 512 | ctx->dsp->ops->free(ctx->dsp); |
457 | if (ctx->boot_complete) { | 513 | if (ctx->boot_complete) { |
diff --git a/sound/soc/intel/skylake/skl-topology.c b/sound/soc/intel/skylake/skl-topology.c index 3e036b0349b9..cc0150fc2601 100644 --- a/sound/soc/intel/skylake/skl-topology.c +++ b/sound/soc/intel/skylake/skl-topology.c | |||
@@ -379,43 +379,6 @@ static void skl_tplg_update_module_params(struct snd_soc_dapm_widget *w, | |||
379 | } | 379 | } |
380 | 380 | ||
381 | /* | 381 | /* |
382 | * A pipe can have multiple modules, each of them will be a DAPM widget as | ||
383 | * well. While managing a pipeline we need to get the list of all the | ||
384 | * widgets in a pipelines, so this helper - skl_tplg_get_pipe_widget() helps | ||
385 | * to get the SKL type widgets in that pipeline | ||
386 | */ | ||
387 | static int skl_tplg_alloc_pipe_widget(struct device *dev, | ||
388 | struct snd_soc_dapm_widget *w, struct skl_pipe *pipe) | ||
389 | { | ||
390 | struct skl_module_cfg *src_module = NULL; | ||
391 | struct snd_soc_dapm_path *p = NULL; | ||
392 | struct skl_pipe_module *p_module = NULL; | ||
393 | |||
394 | p_module = devm_kzalloc(dev, sizeof(*p_module), GFP_KERNEL); | ||
395 | if (!p_module) | ||
396 | return -ENOMEM; | ||
397 | |||
398 | p_module->w = w; | ||
399 | list_add_tail(&p_module->node, &pipe->w_list); | ||
400 | |||
401 | snd_soc_dapm_widget_for_each_sink_path(w, p) { | ||
402 | if ((p->sink->priv == NULL) | ||
403 | && (!is_skl_dsp_widget_type(w))) | ||
404 | continue; | ||
405 | |||
406 | if ((p->sink->priv != NULL) && p->connect | ||
407 | && is_skl_dsp_widget_type(p->sink)) { | ||
408 | |||
409 | src_module = p->sink->priv; | ||
410 | if (pipe->ppl_id == src_module->pipe->ppl_id) | ||
411 | skl_tplg_alloc_pipe_widget(dev, | ||
412 | p->sink, pipe); | ||
413 | } | ||
414 | } | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | /* | ||
419 | * some modules can have multiple params set from user control and | 382 | * some modules can have multiple params set from user control and |
420 | * need to be set after module is initialized. If set_param flag is | 383 | * need to be set after module is initialized. If set_param flag is |
421 | * set module params will be done after module is initialised. | 384 | * set module params will be done after module is initialised. |
@@ -448,7 +411,7 @@ static int skl_tplg_set_module_params(struct snd_soc_dapm_widget *w, | |||
448 | 411 | ||
449 | if (bc->set_params == SKL_PARAM_SET) { | 412 | if (bc->set_params == SKL_PARAM_SET) { |
450 | ret = skl_set_module_params(ctx, | 413 | ret = skl_set_module_params(ctx, |
451 | (u32 *)bc->params, bc->max, | 414 | (u32 *)bc->params, bc->size, |
452 | bc->param_id, mconfig); | 415 | bc->param_id, mconfig); |
453 | if (ret < 0) | 416 | if (ret < 0) |
454 | return ret; | 417 | return ret; |
@@ -483,7 +446,7 @@ static int skl_tplg_set_module_init_data(struct snd_soc_dapm_widget *w) | |||
483 | continue; | 446 | continue; |
484 | 447 | ||
485 | mconfig->formats_config.caps = (u32 *)&bc->params; | 448 | mconfig->formats_config.caps = (u32 *)&bc->params; |
486 | mconfig->formats_config.caps_size = bc->max; | 449 | mconfig->formats_config.caps_size = bc->size; |
487 | 450 | ||
488 | break; | 451 | break; |
489 | } | 452 | } |
@@ -514,8 +477,6 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
514 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) | 477 | if (!skl_is_pipe_mcps_avail(skl, mconfig)) |
515 | return -ENOMEM; | 478 | return -ENOMEM; |
516 | 479 | ||
517 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
518 | |||
519 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { | 480 | if (mconfig->is_loadable && ctx->dsp->fw_ops.load_mod) { |
520 | ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, | 481 | ret = ctx->dsp->fw_ops.load_mod(ctx->dsp, |
521 | mconfig->id.module_id, mconfig->guid); | 482 | mconfig->id.module_id, mconfig->guid); |
@@ -539,6 +500,7 @@ skl_tplg_init_pipe_modules(struct skl *skl, struct skl_pipe *pipe) | |||
539 | if (ret < 0) | 500 | if (ret < 0) |
540 | return ret; | 501 | return ret; |
541 | 502 | ||
503 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
542 | ret = skl_tplg_set_module_params(w, ctx); | 504 | ret = skl_tplg_set_module_params(w, ctx); |
543 | if (ret < 0) | 505 | if (ret < 0) |
544 | return ret; | 506 | return ret; |
@@ -591,9 +553,6 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
591 | if (!skl_is_pipe_mem_avail(skl, mconfig)) | 553 | if (!skl_is_pipe_mem_avail(skl, mconfig)) |
592 | return -ENOMEM; | 554 | return -ENOMEM; |
593 | 555 | ||
594 | skl_tplg_alloc_pipe_mem(skl, mconfig); | ||
595 | skl_tplg_alloc_pipe_mcps(skl, mconfig); | ||
596 | |||
597 | /* | 556 | /* |
598 | * Create a list of modules for pipe. | 557 | * Create a list of modules for pipe. |
599 | * This list contains modules from source to sink | 558 | * This list contains modules from source to sink |
@@ -602,19 +561,8 @@ static int skl_tplg_mixer_dapm_pre_pmu_event(struct snd_soc_dapm_widget *w, | |||
602 | if (ret < 0) | 561 | if (ret < 0) |
603 | return ret; | 562 | return ret; |
604 | 563 | ||
605 | /* | 564 | skl_tplg_alloc_pipe_mem(skl, mconfig); |
606 | * we create a w_list of all widgets in that pipe. This list is not | 565 | skl_tplg_alloc_pipe_mcps(skl, mconfig); |
607 | * freed on PMD event as widgets within a pipe are static. This | ||
608 | * saves us cycles to get widgets in pipe every time. | ||
609 | * | ||
610 | * So if we have already initialized all the widgets of a pipeline | ||
611 | * we skip, so check for list_empty and create the list if empty | ||
612 | */ | ||
613 | if (list_empty(&s_pipe->w_list)) { | ||
614 | ret = skl_tplg_alloc_pipe_widget(ctx->dev, w, s_pipe); | ||
615 | if (ret < 0) | ||
616 | return ret; | ||
617 | } | ||
618 | 566 | ||
619 | /* Init all pipe modules from source to sink */ | 567 | /* Init all pipe modules from source to sink */ |
620 | ret = skl_tplg_init_pipe_modules(skl, s_pipe); | 568 | ret = skl_tplg_init_pipe_modules(skl, s_pipe); |
@@ -949,13 +897,17 @@ static int skl_tplg_mixer_dapm_post_pmd_event(struct snd_soc_dapm_widget *w, | |||
949 | struct skl_pipe *s_pipe = mconfig->pipe; | 897 | struct skl_pipe *s_pipe = mconfig->pipe; |
950 | int ret = 0; | 898 | int ret = 0; |
951 | 899 | ||
900 | if (s_pipe->state == SKL_PIPE_INVALID) | ||
901 | return -EINVAL; | ||
902 | |||
952 | skl_tplg_free_pipe_mcps(skl, mconfig); | 903 | skl_tplg_free_pipe_mcps(skl, mconfig); |
953 | skl_tplg_free_pipe_mem(skl, mconfig); | 904 | skl_tplg_free_pipe_mem(skl, mconfig); |
954 | 905 | ||
955 | list_for_each_entry(w_module, &s_pipe->w_list, node) { | 906 | list_for_each_entry(w_module, &s_pipe->w_list, node) { |
956 | dst_module = w_module->w->priv; | 907 | dst_module = w_module->w->priv; |
957 | 908 | ||
958 | skl_tplg_free_pipe_mcps(skl, dst_module); | 909 | if (mconfig->m_state >= SKL_MODULE_INIT_DONE) |
910 | skl_tplg_free_pipe_mcps(skl, dst_module); | ||
959 | if (src_module == NULL) { | 911 | if (src_module == NULL) { |
960 | src_module = dst_module; | 912 | src_module = dst_module; |
961 | continue; | 913 | continue; |
@@ -1102,7 +1054,7 @@ static int skl_tplg_tlv_control_get(struct snd_kcontrol *kcontrol, | |||
1102 | 1054 | ||
1103 | if (w->power) | 1055 | if (w->power) |
1104 | skl_get_module_params(skl->skl_sst, (u32 *)bc->params, | 1056 | skl_get_module_params(skl->skl_sst, (u32 *)bc->params, |
1105 | bc->max, bc->param_id, mconfig); | 1057 | bc->size, bc->param_id, mconfig); |
1106 | 1058 | ||
1107 | /* decrement size for TLV header */ | 1059 | /* decrement size for TLV header */ |
1108 | size -= 2 * sizeof(u32); | 1060 | size -= 2 * sizeof(u32); |
@@ -1136,6 +1088,10 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, | |||
1136 | struct skl *skl = get_skl_ctx(w->dapm->dev); | 1088 | struct skl *skl = get_skl_ctx(w->dapm->dev); |
1137 | 1089 | ||
1138 | if (ac->params) { | 1090 | if (ac->params) { |
1091 | if (size > ac->max) | ||
1092 | return -EINVAL; | ||
1093 | |||
1094 | ac->size = size; | ||
1139 | /* | 1095 | /* |
1140 | * if the param_is is of type Vendor, firmware expects actual | 1096 | * if the param_is is of type Vendor, firmware expects actual |
1141 | * parameter id and size from the control. | 1097 | * parameter id and size from the control. |
@@ -1151,7 +1107,7 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, | |||
1151 | 1107 | ||
1152 | if (w->power) | 1108 | if (w->power) |
1153 | return skl_set_module_params(skl->skl_sst, | 1109 | return skl_set_module_params(skl->skl_sst, |
1154 | (u32 *)ac->params, ac->max, | 1110 | (u32 *)ac->params, ac->size, |
1155 | ac->param_id, mconfig); | 1111 | ac->param_id, mconfig); |
1156 | } | 1112 | } |
1157 | 1113 | ||
@@ -1159,6 +1115,39 @@ static int skl_tplg_tlv_control_set(struct snd_kcontrol *kcontrol, | |||
1159 | } | 1115 | } |
1160 | 1116 | ||
1161 | /* | 1117 | /* |
1118 | * Fill the dma id for host and link. In case of passthrough | ||
1119 | * pipeline, this will both host and link in the same | ||
1120 | * pipeline, so need to copy the link and host based on dev_type | ||
1121 | */ | ||
1122 | static void skl_tplg_fill_dma_id(struct skl_module_cfg *mcfg, | ||
1123 | struct skl_pipe_params *params) | ||
1124 | { | ||
1125 | struct skl_pipe *pipe = mcfg->pipe; | ||
1126 | |||
1127 | if (pipe->passthru) { | ||
1128 | switch (mcfg->dev_type) { | ||
1129 | case SKL_DEVICE_HDALINK: | ||
1130 | pipe->p_params->link_dma_id = params->link_dma_id; | ||
1131 | break; | ||
1132 | |||
1133 | case SKL_DEVICE_HDAHOST: | ||
1134 | pipe->p_params->host_dma_id = params->host_dma_id; | ||
1135 | break; | ||
1136 | |||
1137 | default: | ||
1138 | break; | ||
1139 | } | ||
1140 | pipe->p_params->s_fmt = params->s_fmt; | ||
1141 | pipe->p_params->ch = params->ch; | ||
1142 | pipe->p_params->s_freq = params->s_freq; | ||
1143 | pipe->p_params->stream = params->stream; | ||
1144 | |||
1145 | } else { | ||
1146 | memcpy(pipe->p_params, params, sizeof(*params)); | ||
1147 | } | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1162 | * The FE params are passed by hw_params of the DAI. | 1151 | * The FE params are passed by hw_params of the DAI. |
1163 | * On hw_params, the params are stored in Gateway module of the FE and we | 1152 | * On hw_params, the params are stored in Gateway module of the FE and we |
1164 | * need to calculate the format in DSP module configuration, that | 1153 | * need to calculate the format in DSP module configuration, that |
@@ -1168,10 +1157,9 @@ int skl_tplg_update_pipe_params(struct device *dev, | |||
1168 | struct skl_module_cfg *mconfig, | 1157 | struct skl_module_cfg *mconfig, |
1169 | struct skl_pipe_params *params) | 1158 | struct skl_pipe_params *params) |
1170 | { | 1159 | { |
1171 | struct skl_pipe *pipe = mconfig->pipe; | ||
1172 | struct skl_module_fmt *format = NULL; | 1160 | struct skl_module_fmt *format = NULL; |
1173 | 1161 | ||
1174 | memcpy(pipe->p_params, params, sizeof(*params)); | 1162 | skl_tplg_fill_dma_id(mconfig, params); |
1175 | 1163 | ||
1176 | if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) | 1164 | if (params->stream == SNDRV_PCM_STREAM_PLAYBACK) |
1177 | format = &mconfig->in_fmt[0]; | 1165 | format = &mconfig->in_fmt[0]; |
@@ -1358,12 +1346,11 @@ static int skl_tplg_be_fill_pipe_params(struct snd_soc_dai *dai, | |||
1358 | struct skl_module_cfg *mconfig, | 1346 | struct skl_module_cfg *mconfig, |
1359 | struct skl_pipe_params *params) | 1347 | struct skl_pipe_params *params) |
1360 | { | 1348 | { |
1361 | struct skl_pipe *pipe = mconfig->pipe; | ||
1362 | struct nhlt_specific_cfg *cfg; | 1349 | struct nhlt_specific_cfg *cfg; |
1363 | struct skl *skl = get_skl_ctx(dai->dev); | 1350 | struct skl *skl = get_skl_ctx(dai->dev); |
1364 | int link_type = skl_tplg_be_link_type(mconfig->dev_type); | 1351 | int link_type = skl_tplg_be_link_type(mconfig->dev_type); |
1365 | 1352 | ||
1366 | memcpy(pipe->p_params, params, sizeof(*params)); | 1353 | skl_tplg_fill_dma_id(mconfig, params); |
1367 | 1354 | ||
1368 | if (link_type == NHLT_LINK_HDA) | 1355 | if (link_type == NHLT_LINK_HDA) |
1369 | return 0; | 1356 | return 0; |
@@ -1554,6 +1541,55 @@ static void skl_tplg_fill_fmt(struct skl_module_fmt *dst_fmt, | |||
1554 | } | 1541 | } |
1555 | } | 1542 | } |
1556 | 1543 | ||
1544 | static void skl_clear_pin_config(struct snd_soc_platform *platform, | ||
1545 | struct snd_soc_dapm_widget *w) | ||
1546 | { | ||
1547 | int i; | ||
1548 | struct skl_module_cfg *mconfig; | ||
1549 | struct skl_pipe *pipe; | ||
1550 | |||
1551 | if (!strncmp(w->dapm->component->name, platform->component.name, | ||
1552 | strlen(platform->component.name))) { | ||
1553 | mconfig = w->priv; | ||
1554 | pipe = mconfig->pipe; | ||
1555 | for (i = 0; i < mconfig->max_in_queue; i++) { | ||
1556 | mconfig->m_in_pin[i].in_use = false; | ||
1557 | mconfig->m_in_pin[i].pin_state = SKL_PIN_UNBIND; | ||
1558 | } | ||
1559 | for (i = 0; i < mconfig->max_out_queue; i++) { | ||
1560 | mconfig->m_out_pin[i].in_use = false; | ||
1561 | mconfig->m_out_pin[i].pin_state = SKL_PIN_UNBIND; | ||
1562 | } | ||
1563 | pipe->state = SKL_PIPE_INVALID; | ||
1564 | mconfig->m_state = SKL_MODULE_UNINIT; | ||
1565 | } | ||
1566 | } | ||
1567 | |||
1568 | void skl_cleanup_resources(struct skl *skl) | ||
1569 | { | ||
1570 | struct skl_sst *ctx = skl->skl_sst; | ||
1571 | struct snd_soc_platform *soc_platform = skl->platform; | ||
1572 | struct snd_soc_dapm_widget *w; | ||
1573 | struct snd_soc_card *card; | ||
1574 | |||
1575 | if (soc_platform == NULL) | ||
1576 | return; | ||
1577 | |||
1578 | card = soc_platform->component.card; | ||
1579 | if (!card || !card->instantiated) | ||
1580 | return; | ||
1581 | |||
1582 | skl->resource.mem = 0; | ||
1583 | skl->resource.mcps = 0; | ||
1584 | |||
1585 | list_for_each_entry(w, &card->widgets, list) { | ||
1586 | if (is_skl_dsp_widget_type(w) && (w->priv != NULL)) | ||
1587 | skl_clear_pin_config(soc_platform, w); | ||
1588 | } | ||
1589 | |||
1590 | skl_clear_module_cnt(ctx->dsp); | ||
1591 | } | ||
1592 | |||
1557 | /* | 1593 | /* |
1558 | * Topology core widget load callback | 1594 | * Topology core widget load callback |
1559 | * | 1595 | * |
@@ -1585,6 +1621,10 @@ static int skl_tplg_widget_load(struct snd_soc_component *cmpnt, | |||
1585 | w->priv = mconfig; | 1621 | w->priv = mconfig; |
1586 | memcpy(&mconfig->guid, &dfw_config->uuid, 16); | 1622 | memcpy(&mconfig->guid, &dfw_config->uuid, 16); |
1587 | 1623 | ||
1624 | ret = snd_skl_get_module_info(skl->skl_sst, mconfig->guid, dfw_config); | ||
1625 | if (ret < 0) | ||
1626 | return ret; | ||
1627 | |||
1588 | mconfig->id.module_id = dfw_config->module_id; | 1628 | mconfig->id.module_id = dfw_config->module_id; |
1589 | mconfig->id.instance_id = dfw_config->instance_id; | 1629 | mconfig->id.instance_id = dfw_config->instance_id; |
1590 | mconfig->mcps = dfw_config->max_mcps; | 1630 | mconfig->mcps = dfw_config->max_mcps; |
@@ -1683,6 +1723,7 @@ static int skl_init_algo_data(struct device *dev, struct soc_bytes_ext *be, | |||
1683 | ac->max = dfw_ac->max; | 1723 | ac->max = dfw_ac->max; |
1684 | ac->param_id = dfw_ac->param_id; | 1724 | ac->param_id = dfw_ac->param_id; |
1685 | ac->set_params = dfw_ac->set_params; | 1725 | ac->set_params = dfw_ac->set_params; |
1726 | ac->size = dfw_ac->max; | ||
1686 | 1727 | ||
1687 | if (ac->max) { | 1728 | if (ac->max) { |
1688 | ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); | 1729 | ac->params = (char *) devm_kzalloc(dev, ac->max, GFP_KERNEL); |
@@ -1733,6 +1774,60 @@ static struct snd_soc_tplg_ops skl_tplg_ops = { | |||
1733 | .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), | 1774 | .bytes_ext_ops_count = ARRAY_SIZE(skl_tlv_ops), |
1734 | }; | 1775 | }; |
1735 | 1776 | ||
1777 | /* | ||
1778 | * A pipe can have multiple modules, each of them will be a DAPM widget as | ||
1779 | * well. While managing a pipeline we need to get the list of all the | ||
1780 | * widgets in a pipelines, so this helper - skl_tplg_create_pipe_widget_list() | ||
1781 | * helps to get the SKL type widgets in that pipeline | ||
1782 | */ | ||
1783 | static int skl_tplg_create_pipe_widget_list(struct snd_soc_platform *platform) | ||
1784 | { | ||
1785 | struct snd_soc_dapm_widget *w; | ||
1786 | struct skl_module_cfg *mcfg = NULL; | ||
1787 | struct skl_pipe_module *p_module = NULL; | ||
1788 | struct skl_pipe *pipe; | ||
1789 | |||
1790 | list_for_each_entry(w, &platform->component.card->widgets, list) { | ||
1791 | if (is_skl_dsp_widget_type(w) && w->priv != NULL) { | ||
1792 | mcfg = w->priv; | ||
1793 | pipe = mcfg->pipe; | ||
1794 | |||
1795 | p_module = devm_kzalloc(platform->dev, | ||
1796 | sizeof(*p_module), GFP_KERNEL); | ||
1797 | if (!p_module) | ||
1798 | return -ENOMEM; | ||
1799 | |||
1800 | p_module->w = w; | ||
1801 | list_add_tail(&p_module->node, &pipe->w_list); | ||
1802 | } | ||
1803 | } | ||
1804 | |||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | static void skl_tplg_set_pipe_type(struct skl *skl, struct skl_pipe *pipe) | ||
1809 | { | ||
1810 | struct skl_pipe_module *w_module; | ||
1811 | struct snd_soc_dapm_widget *w; | ||
1812 | struct skl_module_cfg *mconfig; | ||
1813 | bool host_found = false, link_found = false; | ||
1814 | |||
1815 | list_for_each_entry(w_module, &pipe->w_list, node) { | ||
1816 | w = w_module->w; | ||
1817 | mconfig = w->priv; | ||
1818 | |||
1819 | if (mconfig->dev_type == SKL_DEVICE_HDAHOST) | ||
1820 | host_found = true; | ||
1821 | else if (mconfig->dev_type != SKL_DEVICE_NONE) | ||
1822 | link_found = true; | ||
1823 | } | ||
1824 | |||
1825 | if (host_found && link_found) | ||
1826 | pipe->passthru = true; | ||
1827 | else | ||
1828 | pipe->passthru = false; | ||
1829 | } | ||
1830 | |||
1736 | /* This will be read from topology manifest, currently defined here */ | 1831 | /* This will be read from topology manifest, currently defined here */ |
1737 | #define SKL_MAX_MCPS 30000000 | 1832 | #define SKL_MAX_MCPS 30000000 |
1738 | #define SKL_FW_MAX_MEM 1000000 | 1833 | #define SKL_FW_MAX_MEM 1000000 |
@@ -1746,6 +1841,7 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) | |||
1746 | const struct firmware *fw; | 1841 | const struct firmware *fw; |
1747 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 1842 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
1748 | struct skl *skl = ebus_to_skl(ebus); | 1843 | struct skl *skl = ebus_to_skl(ebus); |
1844 | struct skl_pipeline *ppl; | ||
1749 | 1845 | ||
1750 | ret = request_firmware(&fw, skl->tplg_name, bus->dev); | 1846 | ret = request_firmware(&fw, skl->tplg_name, bus->dev); |
1751 | if (ret < 0) { | 1847 | if (ret < 0) { |
@@ -1775,6 +1871,12 @@ int skl_tplg_init(struct snd_soc_platform *platform, struct hdac_ext_bus *ebus) | |||
1775 | skl->resource.max_mem = SKL_FW_MAX_MEM; | 1871 | skl->resource.max_mem = SKL_FW_MAX_MEM; |
1776 | 1872 | ||
1777 | skl->tplg = fw; | 1873 | skl->tplg = fw; |
1874 | ret = skl_tplg_create_pipe_widget_list(platform); | ||
1875 | if (ret < 0) | ||
1876 | return ret; | ||
1877 | |||
1878 | list_for_each_entry(ppl, &skl->ppl_list, node) | ||
1879 | skl_tplg_set_pipe_type(skl, ppl->pipe); | ||
1778 | 1880 | ||
1779 | return 0; | 1881 | return 0; |
1780 | } | 1882 | } |
diff --git a/sound/soc/intel/skylake/skl-topology.h b/sound/soc/intel/skylake/skl-topology.h index e4b399cd7868..22d3ef83817d 100644 --- a/sound/soc/intel/skylake/skl-topology.h +++ b/sound/soc/intel/skylake/skl-topology.h | |||
@@ -244,7 +244,8 @@ enum skl_pipe_state { | |||
244 | SKL_PIPE_INVALID = 0, | 244 | SKL_PIPE_INVALID = 0, |
245 | SKL_PIPE_CREATED = 1, | 245 | SKL_PIPE_CREATED = 1, |
246 | SKL_PIPE_PAUSED = 2, | 246 | SKL_PIPE_PAUSED = 2, |
247 | SKL_PIPE_STARTED = 3 | 247 | SKL_PIPE_STARTED = 3, |
248 | SKL_PIPE_RESET = 4 | ||
248 | }; | 249 | }; |
249 | 250 | ||
250 | struct skl_pipe_module { | 251 | struct skl_pipe_module { |
@@ -270,6 +271,7 @@ struct skl_pipe { | |||
270 | struct skl_pipe_params *p_params; | 271 | struct skl_pipe_params *p_params; |
271 | enum skl_pipe_state state; | 272 | enum skl_pipe_state state; |
272 | struct list_head w_list; | 273 | struct list_head w_list; |
274 | bool passthru; | ||
273 | }; | 275 | }; |
274 | 276 | ||
275 | enum skl_module_state { | 277 | enum skl_module_state { |
@@ -319,6 +321,7 @@ struct skl_algo_data { | |||
319 | u32 param_id; | 321 | u32 param_id; |
320 | u32 set_params; | 322 | u32 set_params; |
321 | u32 max; | 323 | u32 max; |
324 | u32 size; | ||
322 | char *params; | 325 | char *params; |
323 | }; | 326 | }; |
324 | 327 | ||
@@ -357,6 +360,8 @@ int skl_delete_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); | |||
357 | 360 | ||
358 | int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); | 361 | int skl_stop_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); |
359 | 362 | ||
363 | int skl_reset_pipe(struct skl_sst *ctx, struct skl_pipe *pipe); | ||
364 | |||
360 | int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); | 365 | int skl_init_module(struct skl_sst *ctx, struct skl_module_cfg *module_config); |
361 | 366 | ||
362 | int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg | 367 | int skl_bind_modules(struct skl_sst *ctx, struct skl_module_cfg |
diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 06d8c263c68f..cd59536a761d 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c | |||
@@ -35,6 +35,8 @@ | |||
35 | #include "skl-sst-dsp.h" | 35 | #include "skl-sst-dsp.h" |
36 | #include "skl-sst-ipc.h" | 36 | #include "skl-sst-ipc.h" |
37 | 37 | ||
38 | static struct skl_machine_pdata skl_dmic_data; | ||
39 | |||
38 | /* | 40 | /* |
39 | * initialize the PCI registers | 41 | * initialize the PCI registers |
40 | */ | 42 | */ |
@@ -184,6 +186,7 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) | |||
184 | { | 186 | { |
185 | struct skl *skl = ebus_to_skl(ebus); | 187 | struct skl *skl = ebus_to_skl(ebus); |
186 | struct hdac_bus *bus = ebus_to_hbus(ebus); | 188 | struct hdac_bus *bus = ebus_to_hbus(ebus); |
189 | struct pci_dev *pci = to_pci_dev(bus->dev); | ||
187 | int ret; | 190 | int ret; |
188 | 191 | ||
189 | snd_hdac_ext_bus_link_power_down_all(ebus); | 192 | snd_hdac_ext_bus_link_power_down_all(ebus); |
@@ -193,9 +196,12 @@ static int _skl_suspend(struct hdac_ext_bus *ebus) | |||
193 | return ret; | 196 | return ret; |
194 | 197 | ||
195 | snd_hdac_bus_stop_chip(bus); | 198 | snd_hdac_bus_stop_chip(bus); |
199 | update_pci_dword(pci, AZX_PCIREG_PGCTL, | ||
200 | AZX_PGCTL_LSRMD_MASK, AZX_PGCTL_LSRMD_MASK); | ||
196 | skl_enable_miscbdcge(bus->dev, false); | 201 | skl_enable_miscbdcge(bus->dev, false); |
197 | snd_hdac_bus_enter_link_reset(bus); | 202 | snd_hdac_bus_enter_link_reset(bus); |
198 | skl_enable_miscbdcge(bus->dev, true); | 203 | skl_enable_miscbdcge(bus->dev, true); |
204 | skl_cleanup_resources(skl); | ||
199 | 205 | ||
200 | return 0; | 206 | return 0; |
201 | } | 207 | } |
@@ -242,6 +248,7 @@ static int skl_suspend(struct device *dev) | |||
242 | ret = _skl_suspend(ebus); | 248 | ret = _skl_suspend(ebus); |
243 | if (ret < 0) | 249 | if (ret < 0) |
244 | return ret; | 250 | return ret; |
251 | skl->skl_sst->fw_loaded = false; | ||
245 | } | 252 | } |
246 | 253 | ||
247 | if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { | 254 | if (IS_ENABLED(CONFIG_SND_SOC_HDAC_HDMI)) { |
@@ -397,6 +404,10 @@ static int skl_machine_device_register(struct skl *skl, void *driver_data) | |||
397 | platform_device_put(pdev); | 404 | platform_device_put(pdev); |
398 | return -EIO; | 405 | return -EIO; |
399 | } | 406 | } |
407 | |||
408 | if (mach->pdata) | ||
409 | dev_set_drvdata(&pdev->dev, mach->pdata); | ||
410 | |||
400 | skl->i2s_dev = pdev; | 411 | skl->i2s_dev = pdev; |
401 | 412 | ||
402 | return 0; | 413 | return 0; |
@@ -657,6 +668,8 @@ static int skl_probe(struct pci_dev *pci, | |||
657 | 668 | ||
658 | skl->pci_id = pci->device; | 669 | skl->pci_id = pci->device; |
659 | 670 | ||
671 | device_disable_async_suspend(bus->dev); | ||
672 | |||
660 | skl->nhlt = skl_nhlt_init(bus->dev); | 673 | skl->nhlt = skl_nhlt_init(bus->dev); |
661 | 674 | ||
662 | if (skl->nhlt == NULL) | 675 | if (skl->nhlt == NULL) |
@@ -666,6 +679,8 @@ static int skl_probe(struct pci_dev *pci, | |||
666 | 679 | ||
667 | pci_set_drvdata(skl->pci, ebus); | 680 | pci_set_drvdata(skl->pci, ebus); |
668 | 681 | ||
682 | skl_dmic_data.dmic_num = skl_get_dmic_geo(skl); | ||
683 | |||
669 | /* check if dsp is there */ | 684 | /* check if dsp is there */ |
670 | if (ebus->ppcap) { | 685 | if (ebus->ppcap) { |
671 | err = skl_machine_device_register(skl, | 686 | err = skl_machine_device_register(skl, |
@@ -713,7 +728,7 @@ static int skl_probe(struct pci_dev *pci, | |||
713 | list_for_each_entry(hlink, &ebus->hlink_list, list) | 728 | list_for_each_entry(hlink, &ebus->hlink_list, list) |
714 | snd_hdac_ext_bus_link_put(ebus, hlink); | 729 | snd_hdac_ext_bus_link_put(ebus, hlink); |
715 | 730 | ||
716 | /*configure PM */ | 731 | /* configure PM */ |
717 | pm_runtime_put_noidle(bus->dev); | 732 | pm_runtime_put_noidle(bus->dev); |
718 | pm_runtime_allow(bus->dev); | 733 | pm_runtime_allow(bus->dev); |
719 | 734 | ||
@@ -766,8 +781,7 @@ static void skl_remove(struct pci_dev *pci) | |||
766 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); | 781 | struct hdac_ext_bus *ebus = pci_get_drvdata(pci); |
767 | struct skl *skl = ebus_to_skl(ebus); | 782 | struct skl *skl = ebus_to_skl(ebus); |
768 | 783 | ||
769 | if (skl->tplg) | 784 | release_firmware(skl->tplg); |
770 | release_firmware(skl->tplg); | ||
771 | 785 | ||
772 | if (pci_dev_run_wake(pci)) | 786 | if (pci_dev_run_wake(pci)) |
773 | pm_runtime_get_noresume(&pci->dev); | 787 | pm_runtime_get_noresume(&pci->dev); |
@@ -786,15 +800,23 @@ static void skl_remove(struct pci_dev *pci) | |||
786 | 800 | ||
787 | static struct sst_acpi_mach sst_skl_devdata[] = { | 801 | static struct sst_acpi_mach sst_skl_devdata[] = { |
788 | { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, | 802 | { "INT343A", "skl_alc286s_i2s", "intel/dsp_fw_release.bin", NULL, NULL, NULL }, |
789 | { "INT343B", "skl_nau88l25_ssm4567_i2s", "intel/dsp_fw_release.bin", | 803 | { "INT343B", "skl_n88l25_s4567", "intel/dsp_fw_release.bin", |
790 | NULL, NULL, NULL }, | 804 | NULL, NULL, &skl_dmic_data }, |
791 | { "MX98357A", "skl_nau88l25_max98357a_i2s", "intel/dsp_fw_release.bin", | 805 | { "MX98357A", "skl_n88l25_m98357a", "intel/dsp_fw_release.bin", |
792 | NULL, NULL, NULL }, | 806 | NULL, NULL, &skl_dmic_data }, |
793 | {} | 807 | {} |
794 | }; | 808 | }; |
795 | 809 | ||
796 | static struct sst_acpi_mach sst_bxtp_devdata[] = { | 810 | static struct sst_acpi_mach sst_bxtp_devdata[] = { |
797 | { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, | 811 | { "INT343A", "bxt_alc298s_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, |
812 | { "DLGS7219", "bxt_da7219_max98357a_i2s", "intel/dsp_fw_bxtn.bin", NULL, NULL, NULL }, | ||
813 | }; | ||
814 | |||
815 | static struct sst_acpi_mach sst_kbl_devdata[] = { | ||
816 | { "INT343A", "kbl_alc286s_i2s", "intel/dsp_fw_kbl.bin", NULL, NULL, NULL }, | ||
817 | { "INT343B", "kbl_n88l25_s4567", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, | ||
818 | { "MX98357A", "kbl_n88l25_m98357a", "intel/dsp_fw_kbl.bin", NULL, NULL, &skl_dmic_data }, | ||
819 | {} | ||
798 | }; | 820 | }; |
799 | 821 | ||
800 | /* PCI IDs */ | 822 | /* PCI IDs */ |
@@ -805,6 +827,9 @@ static const struct pci_device_id skl_ids[] = { | |||
805 | /* BXT-P */ | 827 | /* BXT-P */ |
806 | { PCI_DEVICE(0x8086, 0x5a98), | 828 | { PCI_DEVICE(0x8086, 0x5a98), |
807 | .driver_data = (unsigned long)&sst_bxtp_devdata}, | 829 | .driver_data = (unsigned long)&sst_bxtp_devdata}, |
830 | /* KBL */ | ||
831 | { PCI_DEVICE(0x8086, 0x9D71), | ||
832 | .driver_data = (unsigned long)&sst_kbl_devdata}, | ||
808 | { 0, } | 833 | { 0, } |
809 | }; | 834 | }; |
810 | MODULE_DEVICE_TABLE(pci, skl_ids); | 835 | MODULE_DEVICE_TABLE(pci, skl_ids); |
diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 4b4b3876aea9..9064e5b0d676 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h | |||
@@ -48,6 +48,8 @@ | |||
48 | #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 | 48 | #define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 |
49 | #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 | 49 | #define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 |
50 | 50 | ||
51 | #define AZX_PCIREG_PGCTL 0x44 | ||
52 | #define AZX_PGCTL_LSRMD_MASK (1 << 4) | ||
51 | #define AZX_PCIREG_CGCTL 0x48 | 53 | #define AZX_PCIREG_CGCTL 0x48 |
52 | #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) | 54 | #define AZX_CGCTL_MISCBDCGE_MASK (1 << 6) |
53 | 55 | ||
@@ -65,6 +67,7 @@ struct skl { | |||
65 | unsigned int init_failed:1; /* delayed init failed */ | 67 | unsigned int init_failed:1; /* delayed init failed */ |
66 | struct platform_device *dmic_dev; | 68 | struct platform_device *dmic_dev; |
67 | struct platform_device *i2s_dev; | 69 | struct platform_device *i2s_dev; |
70 | struct snd_soc_platform *platform; | ||
68 | 71 | ||
69 | struct nhlt_acpi_table *nhlt; /* nhlt ptr */ | 72 | struct nhlt_acpi_table *nhlt; /* nhlt ptr */ |
70 | struct skl_sst *skl_sst; /* sst skl ctx */ | 73 | struct skl_sst *skl_sst; /* sst skl ctx */ |
@@ -90,6 +93,11 @@ struct skl_dma_params { | |||
90 | u8 stream_tag; | 93 | u8 stream_tag; |
91 | }; | 94 | }; |
92 | 95 | ||
96 | /* to pass dmic data */ | ||
97 | struct skl_machine_pdata { | ||
98 | u32 dmic_num; | ||
99 | }; | ||
100 | |||
93 | struct skl_dsp_ops { | 101 | struct skl_dsp_ops { |
94 | int id; | 102 | int id; |
95 | struct skl_dsp_loader_ops (*loader_ops)(void); | 103 | struct skl_dsp_loader_ops (*loader_ops)(void); |
@@ -108,9 +116,11 @@ void skl_nhlt_free(struct nhlt_acpi_table *addr); | |||
108 | struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, | 116 | struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, |
109 | u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); | 117 | u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); |
110 | 118 | ||
119 | int skl_get_dmic_geo(struct skl *skl); | ||
111 | int skl_nhlt_update_topology_bin(struct skl *skl); | 120 | int skl_nhlt_update_topology_bin(struct skl *skl); |
112 | int skl_init_dsp(struct skl *skl); | 121 | int skl_init_dsp(struct skl *skl); |
113 | int skl_free_dsp(struct skl *skl); | 122 | int skl_free_dsp(struct skl *skl); |
114 | int skl_suspend_dsp(struct skl *skl); | 123 | int skl_suspend_dsp(struct skl *skl); |
115 | int skl_resume_dsp(struct skl *skl); | 124 | int skl_resume_dsp(struct skl *skl); |
125 | void skl_cleanup_resources(struct skl *skl); | ||
116 | #endif /* __SOUND_SOC_SKL_H */ | 126 | #endif /* __SOUND_SOC_SKL_H */ |
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index 3abf51c07851..05cf809cf9e1 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig | |||
@@ -1,15 +1,40 @@ | |||
1 | config SND_SOC_MEDIATEK | 1 | config SND_SOC_MEDIATEK |
2 | tristate "ASoC support for Mediatek chip" | 2 | tristate |
3 | |||
4 | config SND_SOC_MT2701 | ||
5 | tristate "ASoC support for Mediatek MT2701 chip" | ||
6 | depends on ARCH_MEDIATEK | ||
7 | select SND_SOC_MEDIATEK | ||
8 | help | ||
9 | This adds ASoC driver for Mediatek MT2701 boards | ||
10 | that can be used with other codecs. | ||
11 | Select Y if you have such device. | ||
12 | If unsure select "N". | ||
13 | |||
14 | config SND_SOC_MT2701_CS42448 | ||
15 | tristate "ASoc Audio driver for MT2701 with CS42448 codec" | ||
16 | depends on SND_SOC_MT2701 | ||
17 | select SND_SOC_CS42XX8_I2C | ||
18 | select SND_SOC_BT_SCO | ||
19 | help | ||
20 | This adds ASoC driver for Mediatek MT2701 boards | ||
21 | with the CS42448 codecs. | ||
22 | Select Y if you have such device. | ||
23 | If unsure select "N". | ||
24 | |||
25 | config SND_SOC_MT8173 | ||
26 | tristate "ASoC support for Mediatek MT8173 chip" | ||
3 | depends on ARCH_MEDIATEK | 27 | depends on ARCH_MEDIATEK |
28 | select SND_SOC_MEDIATEK | ||
4 | help | 29 | help |
5 | This adds ASoC platform driver support for Mediatek chip | 30 | This adds ASoC platform driver support for Mediatek MT8173 chip |
6 | that can be used with other codecs. | 31 | that can be used with other codecs. |
7 | Select Y if you have such device. | 32 | Select Y if you have such device. |
8 | Ex: MT8173 | 33 | Ex: MT8173 |
9 | 34 | ||
10 | config SND_SOC_MT8173_MAX98090 | 35 | config SND_SOC_MT8173_MAX98090 |
11 | tristate "ASoC Audio driver for MT8173 with MAX98090 codec" | 36 | tristate "ASoC Audio driver for MT8173 with MAX98090 codec" |
12 | depends on SND_SOC_MEDIATEK && I2C | 37 | depends on SND_SOC_MT8173 && I2C |
13 | select SND_SOC_MAX98090 | 38 | select SND_SOC_MAX98090 |
14 | help | 39 | help |
15 | This adds ASoC driver for Mediatek MT8173 boards | 40 | This adds ASoC driver for Mediatek MT8173 boards |
@@ -19,8 +44,9 @@ config SND_SOC_MT8173_MAX98090 | |||
19 | 44 | ||
20 | config SND_SOC_MT8173_RT5650 | 45 | config SND_SOC_MT8173_RT5650 |
21 | tristate "ASoC Audio driver for MT8173 with RT5650 codec" | 46 | tristate "ASoC Audio driver for MT8173 with RT5650 codec" |
22 | depends on SND_SOC_MEDIATEK && I2C | 47 | depends on SND_SOC_MT8173 && I2C |
23 | select SND_SOC_RT5645 | 48 | select SND_SOC_RT5645 |
49 | select SND_SOC_HDMI_CODEC | ||
24 | help | 50 | help |
25 | This adds ASoC driver for Mediatek MT8173 boards | 51 | This adds ASoC driver for Mediatek MT8173 boards |
26 | with the RT5650 audio codec. | 52 | with the RT5650 audio codec. |
@@ -29,7 +55,7 @@ config SND_SOC_MT8173_RT5650 | |||
29 | 55 | ||
30 | config SND_SOC_MT8173_RT5650_RT5514 | 56 | config SND_SOC_MT8173_RT5650_RT5514 |
31 | tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" | 57 | tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" |
32 | depends on SND_SOC_MEDIATEK && I2C | 58 | depends on SND_SOC_MT8173 && I2C |
33 | select SND_SOC_RT5645 | 59 | select SND_SOC_RT5645 |
34 | select SND_SOC_RT5514 | 60 | select SND_SOC_RT5514 |
35 | help | 61 | help |
@@ -40,7 +66,7 @@ config SND_SOC_MT8173_RT5650_RT5514 | |||
40 | 66 | ||
41 | config SND_SOC_MT8173_RT5650_RT5676 | 67 | config SND_SOC_MT8173_RT5650_RT5676 |
42 | tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" | 68 | tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" |
43 | depends on SND_SOC_MEDIATEK && I2C | 69 | depends on SND_SOC_MT8173 && I2C |
44 | select SND_SOC_RT5645 | 70 | select SND_SOC_RT5645 |
45 | select SND_SOC_RT5677 | 71 | select SND_SOC_RT5677 |
46 | select SND_SOC_HDMI_CODEC | 72 | select SND_SOC_HDMI_CODEC |
diff --git a/sound/soc/mediatek/Makefile b/sound/soc/mediatek/Makefile index d486860c0a88..6bcab35dc828 100644 --- a/sound/soc/mediatek/Makefile +++ b/sound/soc/mediatek/Makefile | |||
@@ -1,7 +1,3 @@ | |||
1 | # MTK Platform Support | 1 | obj-$(CONFIG_SND_SOC_MEDIATEK) += common/ |
2 | obj-$(CONFIG_SND_SOC_MEDIATEK) += mtk-afe-pcm.o | 2 | obj-$(CONFIG_SND_SOC_MT2701) += mt2701/ |
3 | # Machine support | 3 | obj-$(CONFIG_SND_SOC_MT8173) += mt8173/ |
4 | obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o | ||
5 | obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o | ||
6 | obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o | ||
7 | obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o | ||
diff --git a/sound/soc/mediatek/common/Makefile b/sound/soc/mediatek/common/Makefile new file mode 100644 index 000000000000..a55d33bc7b01 --- /dev/null +++ b/sound/soc/mediatek/common/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | # | ||
2 | # Copyright (C) 2015 MediaTek Inc. | ||
3 | # | ||
4 | # This program is free software: you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License version 2 as | ||
6 | # published by the Free Software Foundation. | ||
7 | # | ||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | # | ||
13 | |||
14 | # platform driver | ||
15 | snd-soc-mtk-common-objs := mtk-afe-platform-driver.o mtk-afe-fe-dai.o | ||
16 | obj-$(CONFIG_SND_SOC_MEDIATEK) += snd-soc-mtk-common.o | ||
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c new file mode 100644 index 000000000000..b788791b0a35 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c | |||
@@ -0,0 +1,379 @@ | |||
1 | /* | ||
2 | * mtk-afe-fe-dais.c -- Mediatek afe fe dai operator | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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/pm_runtime.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include "mtk-afe-fe-dai.h" | ||
22 | #include "mtk-base-afe.h" | ||
23 | |||
24 | #define AFE_BASE_END_OFFSET 8 | ||
25 | |||
26 | int mtk_regmap_update_bits(struct regmap *map, int reg, unsigned int mask, | ||
27 | unsigned int val) | ||
28 | { | ||
29 | if (reg < 0) | ||
30 | return 0; | ||
31 | return regmap_update_bits(map, reg, mask, val); | ||
32 | } | ||
33 | |||
34 | int mtk_regmap_write(struct regmap *map, int reg, unsigned int val) | ||
35 | { | ||
36 | if (reg < 0) | ||
37 | return 0; | ||
38 | return regmap_write(map, reg, val); | ||
39 | } | ||
40 | |||
41 | int mtk_afe_fe_startup(struct snd_pcm_substream *substream, | ||
42 | struct snd_soc_dai *dai) | ||
43 | { | ||
44 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
45 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
46 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
47 | int memif_num = rtd->cpu_dai->id; | ||
48 | struct mtk_base_afe_memif *memif = &afe->memif[memif_num]; | ||
49 | const struct snd_pcm_hardware *mtk_afe_hardware = afe->mtk_afe_hardware; | ||
50 | int ret; | ||
51 | |||
52 | memif->substream = substream; | ||
53 | |||
54 | snd_pcm_hw_constraint_step(substream->runtime, 0, | ||
55 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 16); | ||
56 | /* enable agent */ | ||
57 | mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, | ||
58 | 1 << memif->data->agent_disable_shift, | ||
59 | 0 << memif->data->agent_disable_shift); | ||
60 | |||
61 | snd_soc_set_runtime_hwparams(substream, mtk_afe_hardware); | ||
62 | |||
63 | /* | ||
64 | * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be | ||
65 | * smaller than period_size due to AFE's internal buffer. | ||
66 | * This easily leads to overrun when avail_min is period_size. | ||
67 | * One more period can hold the possible unread buffer. | ||
68 | */ | ||
69 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
70 | int periods_max = mtk_afe_hardware->periods_max; | ||
71 | |||
72 | ret = snd_pcm_hw_constraint_minmax(runtime, | ||
73 | SNDRV_PCM_HW_PARAM_PERIODS, | ||
74 | 3, periods_max); | ||
75 | if (ret < 0) { | ||
76 | dev_err(afe->dev, "hw_constraint_minmax failed\n"); | ||
77 | return ret; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
82 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
83 | if (ret < 0) | ||
84 | dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); | ||
85 | |||
86 | /* dynamic allocate irq to memif */ | ||
87 | if (memif->irq_usage < 0) { | ||
88 | int irq_id = mtk_dynamic_irq_acquire(afe); | ||
89 | |||
90 | if (irq_id != afe->irqs_size) { | ||
91 | /* link */ | ||
92 | memif->irq_usage = irq_id; | ||
93 | } else { | ||
94 | dev_err(afe->dev, "%s() error: no more asys irq\n", | ||
95 | __func__); | ||
96 | ret = -EBUSY; | ||
97 | } | ||
98 | } | ||
99 | return ret; | ||
100 | } | ||
101 | EXPORT_SYMBOL_GPL(mtk_afe_fe_startup); | ||
102 | |||
103 | void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, | ||
104 | struct snd_soc_dai *dai) | ||
105 | { | ||
106 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
107 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
108 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
109 | int irq_id; | ||
110 | |||
111 | irq_id = memif->irq_usage; | ||
112 | |||
113 | mtk_regmap_update_bits(afe->regmap, memif->data->agent_disable_reg, | ||
114 | 1 << memif->data->agent_disable_shift, | ||
115 | 1 << memif->data->agent_disable_shift); | ||
116 | |||
117 | if (!memif->const_irq) { | ||
118 | mtk_dynamic_irq_release(afe, irq_id); | ||
119 | memif->irq_usage = -1; | ||
120 | memif->substream = NULL; | ||
121 | } | ||
122 | } | ||
123 | EXPORT_SYMBOL_GPL(mtk_afe_fe_shutdown); | ||
124 | |||
125 | int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, | ||
126 | struct snd_pcm_hw_params *params, | ||
127 | struct snd_soc_dai *dai) | ||
128 | { | ||
129 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
130 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
131 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
132 | int msb_at_bit33 = 0; | ||
133 | int ret, fs = 0; | ||
134 | |||
135 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
136 | if (ret < 0) | ||
137 | return ret; | ||
138 | |||
139 | msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; | ||
140 | memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); | ||
141 | memif->buffer_size = substream->runtime->dma_bytes; | ||
142 | |||
143 | /* start */ | ||
144 | mtk_regmap_write(afe->regmap, memif->data->reg_ofs_base, | ||
145 | memif->phys_buf_addr); | ||
146 | /* end */ | ||
147 | mtk_regmap_write(afe->regmap, | ||
148 | memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, | ||
149 | memif->phys_buf_addr + memif->buffer_size - 1); | ||
150 | |||
151 | /* set MSB to 33-bit */ | ||
152 | mtk_regmap_update_bits(afe->regmap, memif->data->msb_reg, | ||
153 | 1 << memif->data->msb_shift, | ||
154 | msb_at_bit33 << memif->data->msb_shift); | ||
155 | |||
156 | /* set channel */ | ||
157 | if (memif->data->mono_shift >= 0) { | ||
158 | unsigned int mono = (params_channels(params) == 1) ? 1 : 0; | ||
159 | |||
160 | mtk_regmap_update_bits(afe->regmap, memif->data->mono_reg, | ||
161 | 1 << memif->data->mono_shift, | ||
162 | mono << memif->data->mono_shift); | ||
163 | } | ||
164 | |||
165 | /* set rate */ | ||
166 | if (memif->data->fs_shift < 0) | ||
167 | return 0; | ||
168 | |||
169 | fs = afe->memif_fs(substream, params_rate(params)); | ||
170 | |||
171 | if (fs < 0) | ||
172 | return -EINVAL; | ||
173 | |||
174 | mtk_regmap_update_bits(afe->regmap, memif->data->fs_reg, | ||
175 | memif->data->fs_maskbit << memif->data->fs_shift, | ||
176 | fs << memif->data->fs_shift); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_params); | ||
181 | |||
182 | int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, | ||
183 | struct snd_soc_dai *dai) | ||
184 | { | ||
185 | return snd_pcm_lib_free_pages(substream); | ||
186 | } | ||
187 | EXPORT_SYMBOL_GPL(mtk_afe_fe_hw_free); | ||
188 | |||
189 | int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, | ||
190 | struct snd_soc_dai *dai) | ||
191 | { | ||
192 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
193 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
194 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
195 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
196 | struct mtk_base_afe_irq *irqs = &afe->irqs[memif->irq_usage]; | ||
197 | const struct mtk_base_irq_data *irq_data = irqs->irq_data; | ||
198 | unsigned int counter = runtime->period_size; | ||
199 | int fs; | ||
200 | |||
201 | dev_dbg(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); | ||
202 | |||
203 | switch (cmd) { | ||
204 | case SNDRV_PCM_TRIGGER_START: | ||
205 | case SNDRV_PCM_TRIGGER_RESUME: | ||
206 | if (memif->data->enable_shift >= 0) | ||
207 | mtk_regmap_update_bits(afe->regmap, | ||
208 | memif->data->enable_reg, | ||
209 | 1 << memif->data->enable_shift, | ||
210 | 1 << memif->data->enable_shift); | ||
211 | |||
212 | /* set irq counter */ | ||
213 | mtk_regmap_update_bits(afe->regmap, irq_data->irq_cnt_reg, | ||
214 | irq_data->irq_cnt_maskbit | ||
215 | << irq_data->irq_cnt_shift, | ||
216 | counter << irq_data->irq_cnt_shift); | ||
217 | |||
218 | /* set irq fs */ | ||
219 | fs = afe->irq_fs(substream, runtime->rate); | ||
220 | |||
221 | if (fs < 0) | ||
222 | return -EINVAL; | ||
223 | |||
224 | mtk_regmap_update_bits(afe->regmap, irq_data->irq_fs_reg, | ||
225 | irq_data->irq_fs_maskbit | ||
226 | << irq_data->irq_fs_shift, | ||
227 | fs << irq_data->irq_fs_shift); | ||
228 | |||
229 | /* enable interrupt */ | ||
230 | mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, | ||
231 | 1 << irq_data->irq_en_shift, | ||
232 | 1 << irq_data->irq_en_shift); | ||
233 | |||
234 | return 0; | ||
235 | case SNDRV_PCM_TRIGGER_STOP: | ||
236 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
237 | mtk_regmap_update_bits(afe->regmap, memif->data->enable_reg, | ||
238 | 1 << memif->data->enable_shift, 0); | ||
239 | /* disable interrupt */ | ||
240 | mtk_regmap_update_bits(afe->regmap, irq_data->irq_en_reg, | ||
241 | 1 << irq_data->irq_en_shift, | ||
242 | 0 << irq_data->irq_en_shift); | ||
243 | /* and clear pending IRQ */ | ||
244 | mtk_regmap_write(afe->regmap, irq_data->irq_clr_reg, | ||
245 | 1 << irq_data->irq_clr_shift); | ||
246 | return 0; | ||
247 | default: | ||
248 | return -EINVAL; | ||
249 | } | ||
250 | } | ||
251 | EXPORT_SYMBOL_GPL(mtk_afe_fe_trigger); | ||
252 | |||
253 | int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, | ||
254 | struct snd_soc_dai *dai) | ||
255 | { | ||
256 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
257 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
258 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
259 | int hd_audio = 0; | ||
260 | |||
261 | /* set hd mode */ | ||
262 | switch (substream->runtime->format) { | ||
263 | case SNDRV_PCM_FORMAT_S16_LE: | ||
264 | hd_audio = 0; | ||
265 | break; | ||
266 | case SNDRV_PCM_FORMAT_S32_LE: | ||
267 | hd_audio = 1; | ||
268 | break; | ||
269 | case SNDRV_PCM_FORMAT_S24_LE: | ||
270 | hd_audio = 1; | ||
271 | break; | ||
272 | default: | ||
273 | dev_err(afe->dev, "%s() error: unsupported format %d\n", | ||
274 | __func__, substream->runtime->format); | ||
275 | break; | ||
276 | } | ||
277 | |||
278 | mtk_regmap_update_bits(afe->regmap, memif->data->hd_reg, | ||
279 | 1 << memif->data->hd_shift, | ||
280 | hd_audio << memif->data->hd_shift); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(mtk_afe_fe_prepare); | ||
285 | |||
286 | const struct snd_soc_dai_ops mtk_afe_fe_ops = { | ||
287 | .startup = mtk_afe_fe_startup, | ||
288 | .shutdown = mtk_afe_fe_shutdown, | ||
289 | .hw_params = mtk_afe_fe_hw_params, | ||
290 | .hw_free = mtk_afe_fe_hw_free, | ||
291 | .prepare = mtk_afe_fe_prepare, | ||
292 | .trigger = mtk_afe_fe_trigger, | ||
293 | }; | ||
294 | EXPORT_SYMBOL_GPL(mtk_afe_fe_ops); | ||
295 | |||
296 | static DEFINE_MUTEX(irqs_lock); | ||
297 | int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe) | ||
298 | { | ||
299 | int i; | ||
300 | |||
301 | mutex_lock(&afe->irq_alloc_lock); | ||
302 | for (i = 0; i < afe->irqs_size; ++i) { | ||
303 | if (afe->irqs[i].irq_occupyed == 0) { | ||
304 | afe->irqs[i].irq_occupyed = 1; | ||
305 | mutex_unlock(&afe->irq_alloc_lock); | ||
306 | return i; | ||
307 | } | ||
308 | } | ||
309 | mutex_unlock(&afe->irq_alloc_lock); | ||
310 | return afe->irqs_size; | ||
311 | } | ||
312 | EXPORT_SYMBOL_GPL(mtk_dynamic_irq_acquire); | ||
313 | |||
314 | int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id) | ||
315 | { | ||
316 | mutex_lock(&afe->irq_alloc_lock); | ||
317 | if (irq_id >= 0 && irq_id < afe->irqs_size) { | ||
318 | afe->irqs[irq_id].irq_occupyed = 0; | ||
319 | mutex_unlock(&afe->irq_alloc_lock); | ||
320 | return 0; | ||
321 | } | ||
322 | mutex_unlock(&afe->irq_alloc_lock); | ||
323 | return -EINVAL; | ||
324 | } | ||
325 | EXPORT_SYMBOL_GPL(mtk_dynamic_irq_release); | ||
326 | |||
327 | int mtk_afe_dai_suspend(struct snd_soc_dai *dai) | ||
328 | { | ||
329 | struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); | ||
330 | struct device *dev = afe->dev; | ||
331 | struct regmap *regmap = afe->regmap; | ||
332 | int i; | ||
333 | |||
334 | if (pm_runtime_status_suspended(dev) || afe->suspended) | ||
335 | return 0; | ||
336 | |||
337 | if (!afe->reg_back_up) | ||
338 | afe->reg_back_up = | ||
339 | devm_kcalloc(dev, afe->reg_back_up_list_num, | ||
340 | sizeof(unsigned int), GFP_KERNEL); | ||
341 | |||
342 | for (i = 0; i < afe->reg_back_up_list_num; i++) | ||
343 | regmap_read(regmap, afe->reg_back_up_list[i], | ||
344 | &afe->reg_back_up[i]); | ||
345 | |||
346 | afe->suspended = true; | ||
347 | afe->runtime_suspend(dev); | ||
348 | return 0; | ||
349 | } | ||
350 | EXPORT_SYMBOL_GPL(mtk_afe_dai_suspend); | ||
351 | |||
352 | int mtk_afe_dai_resume(struct snd_soc_dai *dai) | ||
353 | { | ||
354 | struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); | ||
355 | struct device *dev = afe->dev; | ||
356 | struct regmap *regmap = afe->regmap; | ||
357 | int i = 0; | ||
358 | |||
359 | if (pm_runtime_status_suspended(dev) || !afe->suspended) | ||
360 | return 0; | ||
361 | |||
362 | afe->runtime_resume(dev); | ||
363 | |||
364 | if (!afe->reg_back_up) | ||
365 | dev_dbg(dev, "%s no reg_backup\n", __func__); | ||
366 | |||
367 | for (i = 0; i < afe->reg_back_up_list_num; i++) | ||
368 | mtk_regmap_write(regmap, afe->reg_back_up_list[i], | ||
369 | afe->reg_back_up[i]); | ||
370 | |||
371 | afe->suspended = false; | ||
372 | return 0; | ||
373 | } | ||
374 | EXPORT_SYMBOL_GPL(mtk_afe_dai_resume); | ||
375 | |||
376 | MODULE_DESCRIPTION("Mediatek simple fe dai operator"); | ||
377 | MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); | ||
378 | MODULE_LICENSE("GPL v2"); | ||
379 | |||
diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h new file mode 100644 index 000000000000..28cb17854da1 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * mtk-afe-fe-dais.h -- Mediatek afe fe dai operator definition | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MTK_AFE_FE_DAI_H_ | ||
18 | #define _MTK_AFE_FE_DAI_H_ | ||
19 | |||
20 | struct snd_soc_dai_ops; | ||
21 | struct mtk_base_afe; | ||
22 | struct mtk_base_afe_memif; | ||
23 | |||
24 | int mtk_afe_fe_startup(struct snd_pcm_substream *substream, | ||
25 | struct snd_soc_dai *dai); | ||
26 | void mtk_afe_fe_shutdown(struct snd_pcm_substream *substream, | ||
27 | struct snd_soc_dai *dai); | ||
28 | int mtk_afe_fe_hw_params(struct snd_pcm_substream *substream, | ||
29 | struct snd_pcm_hw_params *params, | ||
30 | struct snd_soc_dai *dai); | ||
31 | int mtk_afe_fe_hw_free(struct snd_pcm_substream *substream, | ||
32 | struct snd_soc_dai *dai); | ||
33 | int mtk_afe_fe_prepare(struct snd_pcm_substream *substream, | ||
34 | struct snd_soc_dai *dai); | ||
35 | int mtk_afe_fe_trigger(struct snd_pcm_substream *substream, int cmd, | ||
36 | struct snd_soc_dai *dai); | ||
37 | |||
38 | extern const struct snd_soc_dai_ops mtk_afe_fe_ops; | ||
39 | |||
40 | int mtk_dynamic_irq_acquire(struct mtk_base_afe *afe); | ||
41 | int mtk_dynamic_irq_release(struct mtk_base_afe *afe, int irq_id); | ||
42 | int mtk_afe_dai_suspend(struct snd_soc_dai *dai); | ||
43 | int mtk_afe_dai_resume(struct snd_soc_dai *dai); | ||
44 | |||
45 | #endif | ||
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.c b/sound/soc/mediatek/common/mtk-afe-platform-driver.c new file mode 100644 index 000000000000..82d439c15f4e --- /dev/null +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.c | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * mtk-afe-platform-driver.c -- Mediatek afe platform driver | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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/dma-mapping.h> | ||
19 | #include <sound/soc.h> | ||
20 | |||
21 | #include "mtk-afe-platform-driver.h" | ||
22 | #include "mtk-base-afe.h" | ||
23 | |||
24 | static snd_pcm_uframes_t mtk_afe_pcm_pointer | ||
25 | (struct snd_pcm_substream *substream) | ||
26 | { | ||
27 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
28 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
29 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
30 | const struct mtk_base_memif_data *memif_data = memif->data; | ||
31 | struct regmap *regmap = afe->regmap; | ||
32 | struct device *dev = afe->dev; | ||
33 | int reg_ofs_base = memif_data->reg_ofs_base; | ||
34 | int reg_ofs_cur = memif_data->reg_ofs_cur; | ||
35 | unsigned int hw_ptr = 0, hw_base = 0; | ||
36 | int ret, pcm_ptr_bytes; | ||
37 | |||
38 | ret = regmap_read(regmap, reg_ofs_cur, &hw_ptr); | ||
39 | if (ret || hw_ptr == 0) { | ||
40 | dev_err(dev, "%s hw_ptr err\n", __func__); | ||
41 | pcm_ptr_bytes = 0; | ||
42 | goto POINTER_RETURN_FRAMES; | ||
43 | } | ||
44 | |||
45 | ret = regmap_read(regmap, reg_ofs_base, &hw_base); | ||
46 | if (ret || hw_base == 0) { | ||
47 | dev_err(dev, "%s hw_ptr err\n", __func__); | ||
48 | pcm_ptr_bytes = 0; | ||
49 | goto POINTER_RETURN_FRAMES; | ||
50 | } | ||
51 | |||
52 | pcm_ptr_bytes = hw_ptr - hw_base; | ||
53 | |||
54 | POINTER_RETURN_FRAMES: | ||
55 | return bytes_to_frames(substream->runtime, pcm_ptr_bytes); | ||
56 | } | ||
57 | |||
58 | static const struct snd_pcm_ops mtk_afe_pcm_ops = { | ||
59 | .ioctl = snd_pcm_lib_ioctl, | ||
60 | .pointer = mtk_afe_pcm_pointer, | ||
61 | }; | ||
62 | |||
63 | static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
64 | { | ||
65 | size_t size; | ||
66 | struct snd_card *card = rtd->card->snd_card; | ||
67 | struct snd_pcm *pcm = rtd->pcm; | ||
68 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
69 | |||
70 | size = afe->mtk_afe_hardware->buffer_bytes_max; | ||
71 | return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
72 | card->dev, size, size); | ||
73 | } | ||
74 | |||
75 | static void mtk_afe_pcm_free(struct snd_pcm *pcm) | ||
76 | { | ||
77 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
78 | } | ||
79 | |||
80 | const struct snd_soc_platform_driver mtk_afe_pcm_platform = { | ||
81 | .ops = &mtk_afe_pcm_ops, | ||
82 | .pcm_new = mtk_afe_pcm_new, | ||
83 | .pcm_free = mtk_afe_pcm_free, | ||
84 | }; | ||
85 | EXPORT_SYMBOL_GPL(mtk_afe_pcm_platform); | ||
86 | |||
87 | MODULE_DESCRIPTION("Mediatek simple platform driver"); | ||
88 | MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); | ||
89 | MODULE_LICENSE("GPL v2"); | ||
90 | |||
diff --git a/sound/soc/mediatek/common/mtk-afe-platform-driver.h b/sound/soc/mediatek/common/mtk-afe-platform-driver.h new file mode 100644 index 000000000000..a973fc9253b4 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-afe-platform-driver.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * mtk-afe-platform-driver.h -- Mediatek afe platform driver definition | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MTK_AFE_PLATFORM_DRIVER_H_ | ||
18 | #define _MTK_AFE_PLATFORM_DRIVER_H_ | ||
19 | |||
20 | extern const struct snd_soc_platform_driver mtk_afe_pcm_platform; | ||
21 | |||
22 | #endif | ||
23 | |||
diff --git a/sound/soc/mediatek/common/mtk-base-afe.h b/sound/soc/mediatek/common/mtk-base-afe.h new file mode 100644 index 000000000000..3a78f6f17195 --- /dev/null +++ b/sound/soc/mediatek/common/mtk-base-afe.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * mtk-base-afe.h -- Mediatek base afe structure | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MTK_BASE_AFE_H_ | ||
18 | #define _MTK_BASE_AFE_H_ | ||
19 | |||
20 | struct mtk_base_memif_data { | ||
21 | int id; | ||
22 | const char *name; | ||
23 | int reg_ofs_base; | ||
24 | int reg_ofs_cur; | ||
25 | int fs_reg; | ||
26 | int fs_shift; | ||
27 | int fs_maskbit; | ||
28 | int mono_reg; | ||
29 | int mono_shift; | ||
30 | int enable_reg; | ||
31 | int enable_shift; | ||
32 | int hd_reg; | ||
33 | int hd_shift; | ||
34 | int msb_reg; | ||
35 | int msb_shift; | ||
36 | int agent_disable_reg; | ||
37 | int agent_disable_shift; | ||
38 | }; | ||
39 | |||
40 | struct mtk_base_irq_data { | ||
41 | int id; | ||
42 | int irq_cnt_reg; | ||
43 | int irq_cnt_shift; | ||
44 | int irq_cnt_maskbit; | ||
45 | int irq_fs_reg; | ||
46 | int irq_fs_shift; | ||
47 | int irq_fs_maskbit; | ||
48 | int irq_en_reg; | ||
49 | int irq_en_shift; | ||
50 | int irq_clr_reg; | ||
51 | int irq_clr_shift; | ||
52 | }; | ||
53 | |||
54 | struct device; | ||
55 | struct mtk_base_afe_memif; | ||
56 | struct mtk_base_afe_irq; | ||
57 | struct regmap; | ||
58 | struct snd_pcm_substream; | ||
59 | struct snd_soc_dai; | ||
60 | |||
61 | struct mtk_base_afe { | ||
62 | void __iomem *base_addr; | ||
63 | struct device *dev; | ||
64 | struct regmap *regmap; | ||
65 | struct mutex irq_alloc_lock; /* dynamic alloc irq lock */ | ||
66 | |||
67 | unsigned int const *reg_back_up_list; | ||
68 | unsigned int *reg_back_up; | ||
69 | unsigned int reg_back_up_list_num; | ||
70 | |||
71 | int (*runtime_suspend)(struct device *dev); | ||
72 | int (*runtime_resume)(struct device *dev); | ||
73 | bool suspended; | ||
74 | |||
75 | struct mtk_base_afe_memif *memif; | ||
76 | int memif_size; | ||
77 | struct mtk_base_afe_irq *irqs; | ||
78 | int irqs_size; | ||
79 | |||
80 | const struct snd_pcm_hardware *mtk_afe_hardware; | ||
81 | int (*memif_fs)(struct snd_pcm_substream *substream, | ||
82 | unsigned int rate); | ||
83 | int (*irq_fs)(struct snd_pcm_substream *substream, | ||
84 | unsigned int rate); | ||
85 | |||
86 | void *platform_priv; | ||
87 | }; | ||
88 | |||
89 | struct mtk_base_afe_memif { | ||
90 | unsigned int phys_buf_addr; | ||
91 | int buffer_size; | ||
92 | struct snd_pcm_substream *substream; | ||
93 | const struct mtk_base_memif_data *data; | ||
94 | int irq_usage; | ||
95 | int const_irq; | ||
96 | }; | ||
97 | |||
98 | struct mtk_base_afe_irq { | ||
99 | const struct mtk_base_irq_data *irq_data; | ||
100 | int irq_occupyed; | ||
101 | }; | ||
102 | |||
103 | #endif | ||
104 | |||
diff --git a/sound/soc/mediatek/mt2701/Makefile b/sound/soc/mediatek/mt2701/Makefile new file mode 100644 index 000000000000..31c3d04d4942 --- /dev/null +++ b/sound/soc/mediatek/mt2701/Makefile | |||
@@ -0,0 +1,19 @@ | |||
1 | # | ||
2 | # Copyright (C) 2015 MediaTek Inc. | ||
3 | # | ||
4 | # This program is free software: you can redistribute it and/or modify | ||
5 | # it under the terms of the GNU General Public License version 2 as | ||
6 | # published by the Free Software Foundation. | ||
7 | # | ||
8 | # This program is distributed in the hope that it will be useful, | ||
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | # GNU General Public License for more details. | ||
12 | # | ||
13 | |||
14 | # platform driver | ||
15 | snd-soc-mt2701-afe-objs := mt2701-afe-pcm.o mt2701-afe-clock-ctrl.o | ||
16 | obj-$(CONFIG_SND_SOC_MT2701) += snd-soc-mt2701-afe.o | ||
17 | |||
18 | # machine driver | ||
19 | obj-$(CONFIG_SND_SOC_MT2701_CS42448) += mt2701-cs42448.o | ||
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c new file mode 100644 index 000000000000..b815ecc6bbf6 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.c | |||
@@ -0,0 +1,464 @@ | |||
1 | /* | ||
2 | * mt2701-afe-clock-ctrl.c -- Mediatek 2701 afe clock ctrl | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 <sound/soc.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/pm_runtime.h> | ||
20 | |||
21 | #include "mt2701-afe-common.h" | ||
22 | #include "mt2701-afe-clock-ctrl.h" | ||
23 | |||
24 | static const char *aud_clks[MT2701_CLOCK_NUM] = { | ||
25 | [MT2701_AUD_INFRA_SYS_AUDIO] = "infra_sys_audio_clk", | ||
26 | [MT2701_AUD_AUD_MUX1_SEL] = "top_audio_mux1_sel", | ||
27 | [MT2701_AUD_AUD_MUX2_SEL] = "top_audio_mux2_sel", | ||
28 | [MT2701_AUD_AUD_MUX1_DIV] = "top_audio_mux1_div", | ||
29 | [MT2701_AUD_AUD_MUX2_DIV] = "top_audio_mux2_div", | ||
30 | [MT2701_AUD_AUD_48K_TIMING] = "top_audio_48k_timing", | ||
31 | [MT2701_AUD_AUD_44K_TIMING] = "top_audio_44k_timing", | ||
32 | [MT2701_AUD_AUDPLL_MUX_SEL] = "top_audpll_mux_sel", | ||
33 | [MT2701_AUD_APLL_SEL] = "top_apll_sel", | ||
34 | [MT2701_AUD_AUD1PLL_98M] = "top_aud1_pll_98M", | ||
35 | [MT2701_AUD_AUD2PLL_90M] = "top_aud2_pll_90M", | ||
36 | [MT2701_AUD_HADDS2PLL_98M] = "top_hadds2_pll_98M", | ||
37 | [MT2701_AUD_HADDS2PLL_294M] = "top_hadds2_pll_294M", | ||
38 | [MT2701_AUD_AUDPLL] = "top_audpll", | ||
39 | [MT2701_AUD_AUDPLL_D4] = "top_audpll_d4", | ||
40 | [MT2701_AUD_AUDPLL_D8] = "top_audpll_d8", | ||
41 | [MT2701_AUD_AUDPLL_D16] = "top_audpll_d16", | ||
42 | [MT2701_AUD_AUDPLL_D24] = "top_audpll_d24", | ||
43 | [MT2701_AUD_AUDINTBUS] = "top_audintbus_sel", | ||
44 | [MT2701_AUD_CLK_26M] = "clk_26m", | ||
45 | [MT2701_AUD_SYSPLL1_D4] = "top_syspll1_d4", | ||
46 | [MT2701_AUD_AUD_K1_SRC_SEL] = "top_aud_k1_src_sel", | ||
47 | [MT2701_AUD_AUD_K2_SRC_SEL] = "top_aud_k2_src_sel", | ||
48 | [MT2701_AUD_AUD_K3_SRC_SEL] = "top_aud_k3_src_sel", | ||
49 | [MT2701_AUD_AUD_K4_SRC_SEL] = "top_aud_k4_src_sel", | ||
50 | [MT2701_AUD_AUD_K5_SRC_SEL] = "top_aud_k5_src_sel", | ||
51 | [MT2701_AUD_AUD_K6_SRC_SEL] = "top_aud_k6_src_sel", | ||
52 | [MT2701_AUD_AUD_K1_SRC_DIV] = "top_aud_k1_src_div", | ||
53 | [MT2701_AUD_AUD_K2_SRC_DIV] = "top_aud_k2_src_div", | ||
54 | [MT2701_AUD_AUD_K3_SRC_DIV] = "top_aud_k3_src_div", | ||
55 | [MT2701_AUD_AUD_K4_SRC_DIV] = "top_aud_k4_src_div", | ||
56 | [MT2701_AUD_AUD_K5_SRC_DIV] = "top_aud_k5_src_div", | ||
57 | [MT2701_AUD_AUD_K6_SRC_DIV] = "top_aud_k6_src_div", | ||
58 | [MT2701_AUD_AUD_I2S1_MCLK] = "top_aud_i2s1_mclk", | ||
59 | [MT2701_AUD_AUD_I2S2_MCLK] = "top_aud_i2s2_mclk", | ||
60 | [MT2701_AUD_AUD_I2S3_MCLK] = "top_aud_i2s3_mclk", | ||
61 | [MT2701_AUD_AUD_I2S4_MCLK] = "top_aud_i2s4_mclk", | ||
62 | [MT2701_AUD_AUD_I2S5_MCLK] = "top_aud_i2s5_mclk", | ||
63 | [MT2701_AUD_AUD_I2S6_MCLK] = "top_aud_i2s6_mclk", | ||
64 | [MT2701_AUD_ASM_M_SEL] = "top_asm_m_sel", | ||
65 | [MT2701_AUD_ASM_H_SEL] = "top_asm_h_sel", | ||
66 | [MT2701_AUD_UNIVPLL2_D4] = "top_univpll2_d4", | ||
67 | [MT2701_AUD_UNIVPLL2_D2] = "top_univpll2_d2", | ||
68 | [MT2701_AUD_SYSPLL_D5] = "top_syspll_d5", | ||
69 | }; | ||
70 | |||
71 | int mt2701_init_clock(struct mtk_base_afe *afe) | ||
72 | { | ||
73 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
74 | int i = 0; | ||
75 | |||
76 | for (i = 0; i < MT2701_CLOCK_NUM; i++) { | ||
77 | afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); | ||
78 | if (IS_ERR(aud_clks[i])) { | ||
79 | dev_warn(afe->dev, "%s devm_clk_get %s fail\n", | ||
80 | __func__, aud_clks[i]); | ||
81 | return PTR_ERR(aud_clks[i]); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | int mt2701_afe_enable_clock(struct mtk_base_afe *afe) | ||
89 | { | ||
90 | int ret = 0; | ||
91 | |||
92 | ret = mt2701_turn_on_a1sys_clock(afe); | ||
93 | if (ret) { | ||
94 | dev_err(afe->dev, "%s turn_on_a1sys_clock fail %d\n", | ||
95 | __func__, ret); | ||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | ret = mt2701_turn_on_a2sys_clock(afe); | ||
100 | if (ret) { | ||
101 | dev_err(afe->dev, "%s turn_on_a2sys_clock fail %d\n", | ||
102 | __func__, ret); | ||
103 | mt2701_turn_off_a1sys_clock(afe); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | ret = mt2701_turn_on_afe_clock(afe); | ||
108 | if (ret) { | ||
109 | dev_err(afe->dev, "%s turn_on_afe_clock fail %d\n", | ||
110 | __func__, ret); | ||
111 | mt2701_turn_off_a1sys_clock(afe); | ||
112 | mt2701_turn_off_a2sys_clock(afe); | ||
113 | return ret; | ||
114 | } | ||
115 | |||
116 | regmap_update_bits(afe->regmap, ASYS_TOP_CON, | ||
117 | AUDIO_TOP_CON0_A1SYS_A2SYS_ON, | ||
118 | AUDIO_TOP_CON0_A1SYS_A2SYS_ON); | ||
119 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
120 | AFE_DAC_CON0_AFE_ON, | ||
121 | AFE_DAC_CON0_AFE_ON); | ||
122 | regmap_write(afe->regmap, PWR2_TOP_CON, | ||
123 | PWR2_TOP_CON_INIT_VAL); | ||
124 | regmap_write(afe->regmap, PWR1_ASM_CON1, | ||
125 | PWR1_ASM_CON1_INIT_VAL); | ||
126 | regmap_write(afe->regmap, PWR2_ASM_CON1, | ||
127 | PWR2_ASM_CON1_INIT_VAL); | ||
128 | |||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | void mt2701_afe_disable_clock(struct mtk_base_afe *afe) | ||
133 | { | ||
134 | mt2701_turn_off_afe_clock(afe); | ||
135 | mt2701_turn_off_a1sys_clock(afe); | ||
136 | mt2701_turn_off_a2sys_clock(afe); | ||
137 | regmap_update_bits(afe->regmap, ASYS_TOP_CON, | ||
138 | AUDIO_TOP_CON0_A1SYS_A2SYS_ON, 0); | ||
139 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
140 | AFE_DAC_CON0_AFE_ON, 0); | ||
141 | } | ||
142 | |||
143 | int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe) | ||
144 | { | ||
145 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
146 | int ret = 0; | ||
147 | |||
148 | /* Set Mux */ | ||
149 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); | ||
150 | if (ret) { | ||
151 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
152 | __func__, aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret); | ||
153 | goto A1SYS_CLK_AUD_MUX1_SEL_ERR; | ||
154 | } | ||
155 | |||
156 | ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL], | ||
157 | afe_priv->clocks[MT2701_AUD_AUD1PLL_98M]); | ||
158 | if (ret) { | ||
159 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, | ||
160 | aud_clks[MT2701_AUD_AUD_MUX1_SEL], | ||
161 | aud_clks[MT2701_AUD_AUD1PLL_98M], ret); | ||
162 | goto A1SYS_CLK_AUD_MUX1_SEL_ERR; | ||
163 | } | ||
164 | |||
165 | /* Set Divider */ | ||
166 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); | ||
167 | if (ret) { | ||
168 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
169 | __func__, | ||
170 | aud_clks[MT2701_AUD_AUD_MUX1_DIV], | ||
171 | ret); | ||
172 | goto A1SYS_CLK_AUD_MUX1_DIV_ERR; | ||
173 | } | ||
174 | |||
175 | ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV], | ||
176 | MT2701_AUD_AUD_MUX1_DIV_RATE); | ||
177 | if (ret) { | ||
178 | dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, | ||
179 | aud_clks[MT2701_AUD_AUD_MUX1_DIV], | ||
180 | MT2701_AUD_AUD_MUX1_DIV_RATE, ret); | ||
181 | goto A1SYS_CLK_AUD_MUX1_DIV_ERR; | ||
182 | } | ||
183 | |||
184 | /* Enable clock gate */ | ||
185 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); | ||
186 | if (ret) { | ||
187 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
188 | __func__, aud_clks[MT2701_AUD_AUD_48K_TIMING], ret); | ||
189 | goto A1SYS_CLK_AUD_48K_ERR; | ||
190 | } | ||
191 | |||
192 | /* Enable infra audio */ | ||
193 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
194 | if (ret) { | ||
195 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
196 | __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); | ||
197 | goto A1SYS_CLK_INFRA_ERR; | ||
198 | } | ||
199 | |||
200 | return 0; | ||
201 | |||
202 | A1SYS_CLK_INFRA_ERR: | ||
203 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
204 | A1SYS_CLK_AUD_48K_ERR: | ||
205 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); | ||
206 | A1SYS_CLK_AUD_MUX1_DIV_ERR: | ||
207 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); | ||
208 | A1SYS_CLK_AUD_MUX1_SEL_ERR: | ||
209 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); | ||
210 | |||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe) | ||
215 | { | ||
216 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
217 | |||
218 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
219 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_48K_TIMING]); | ||
220 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_DIV]); | ||
221 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); | ||
222 | } | ||
223 | |||
224 | int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe) | ||
225 | { | ||
226 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
227 | int ret = 0; | ||
228 | |||
229 | /* Set Mux */ | ||
230 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); | ||
231 | if (ret) { | ||
232 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
233 | __func__, aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret); | ||
234 | goto A2SYS_CLK_AUD_MUX2_SEL_ERR; | ||
235 | } | ||
236 | |||
237 | ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL], | ||
238 | afe_priv->clocks[MT2701_AUD_AUD2PLL_90M]); | ||
239 | if (ret) { | ||
240 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, | ||
241 | aud_clks[MT2701_AUD_AUD_MUX2_SEL], | ||
242 | aud_clks[MT2701_AUD_AUD2PLL_90M], ret); | ||
243 | goto A2SYS_CLK_AUD_MUX2_SEL_ERR; | ||
244 | } | ||
245 | |||
246 | /* Set Divider */ | ||
247 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); | ||
248 | if (ret) { | ||
249 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
250 | __func__, aud_clks[MT2701_AUD_AUD_MUX2_DIV], ret); | ||
251 | goto A2SYS_CLK_AUD_MUX2_DIV_ERR; | ||
252 | } | ||
253 | |||
254 | ret = clk_set_rate(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV], | ||
255 | MT2701_AUD_AUD_MUX2_DIV_RATE); | ||
256 | if (ret) { | ||
257 | dev_err(afe->dev, "%s clk_set_parent %s-%d fail %d\n", __func__, | ||
258 | aud_clks[MT2701_AUD_AUD_MUX2_DIV], | ||
259 | MT2701_AUD_AUD_MUX2_DIV_RATE, ret); | ||
260 | goto A2SYS_CLK_AUD_MUX2_DIV_ERR; | ||
261 | } | ||
262 | |||
263 | /* Enable clock gate */ | ||
264 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); | ||
265 | if (ret) { | ||
266 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
267 | __func__, aud_clks[MT2701_AUD_AUD_44K_TIMING], ret); | ||
268 | goto A2SYS_CLK_AUD_44K_ERR; | ||
269 | } | ||
270 | |||
271 | /* Enable infra audio */ | ||
272 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
273 | if (ret) { | ||
274 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
275 | __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); | ||
276 | goto A2SYS_CLK_INFRA_ERR; | ||
277 | } | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | A2SYS_CLK_INFRA_ERR: | ||
282 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
283 | A2SYS_CLK_AUD_44K_ERR: | ||
284 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); | ||
285 | A2SYS_CLK_AUD_MUX2_DIV_ERR: | ||
286 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); | ||
287 | A2SYS_CLK_AUD_MUX2_SEL_ERR: | ||
288 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); | ||
289 | |||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe) | ||
294 | { | ||
295 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
296 | |||
297 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
298 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_44K_TIMING]); | ||
299 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_DIV]); | ||
300 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); | ||
301 | } | ||
302 | |||
303 | int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe) | ||
304 | { | ||
305 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
306 | int ret; | ||
307 | |||
308 | /* enable INFRA_SYS */ | ||
309 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
310 | if (ret) { | ||
311 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
312 | __func__, aud_clks[MT2701_AUD_INFRA_SYS_AUDIO], ret); | ||
313 | goto AFE_AUD_INFRA_ERR; | ||
314 | } | ||
315 | |||
316 | /* Set MT2701_AUD_AUDINTBUS to MT2701_AUD_SYSPLL1_D4 */ | ||
317 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); | ||
318 | if (ret) { | ||
319 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
320 | __func__, aud_clks[MT2701_AUD_AUDINTBUS], ret); | ||
321 | goto AFE_AUD_AUDINTBUS_ERR; | ||
322 | } | ||
323 | |||
324 | ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_AUDINTBUS], | ||
325 | afe_priv->clocks[MT2701_AUD_SYSPLL1_D4]); | ||
326 | if (ret) { | ||
327 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, | ||
328 | aud_clks[MT2701_AUD_AUDINTBUS], | ||
329 | aud_clks[MT2701_AUD_SYSPLL1_D4], ret); | ||
330 | goto AFE_AUD_AUDINTBUS_ERR; | ||
331 | } | ||
332 | |||
333 | /* Set MT2701_AUD_ASM_H_SEL to MT2701_AUD_UNIVPLL2_D2 */ | ||
334 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); | ||
335 | if (ret) { | ||
336 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
337 | __func__, aud_clks[MT2701_AUD_ASM_H_SEL], ret); | ||
338 | goto AFE_AUD_ASM_H_ERR; | ||
339 | } | ||
340 | |||
341 | ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_H_SEL], | ||
342 | afe_priv->clocks[MT2701_AUD_UNIVPLL2_D2]); | ||
343 | if (ret) { | ||
344 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, | ||
345 | aud_clks[MT2701_AUD_ASM_H_SEL], | ||
346 | aud_clks[MT2701_AUD_UNIVPLL2_D2], ret); | ||
347 | goto AFE_AUD_ASM_H_ERR; | ||
348 | } | ||
349 | |||
350 | /* Set MT2701_AUD_ASM_M_SEL to MT2701_AUD_UNIVPLL2_D4 */ | ||
351 | ret = clk_prepare_enable(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); | ||
352 | if (ret) { | ||
353 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
354 | __func__, aud_clks[MT2701_AUD_ASM_M_SEL], ret); | ||
355 | goto AFE_AUD_ASM_M_ERR; | ||
356 | } | ||
357 | |||
358 | ret = clk_set_parent(afe_priv->clocks[MT2701_AUD_ASM_M_SEL], | ||
359 | afe_priv->clocks[MT2701_AUD_UNIVPLL2_D4]); | ||
360 | if (ret) { | ||
361 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", __func__, | ||
362 | aud_clks[MT2701_AUD_ASM_M_SEL], | ||
363 | aud_clks[MT2701_AUD_UNIVPLL2_D4], ret); | ||
364 | goto AFE_AUD_ASM_M_ERR; | ||
365 | } | ||
366 | |||
367 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
368 | AUDIO_TOP_CON0_PDN_AFE, 0); | ||
369 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
370 | AUDIO_TOP_CON0_PDN_APLL_CK, 0); | ||
371 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
372 | AUDIO_TOP_CON4_PDN_A1SYS, 0); | ||
373 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
374 | AUDIO_TOP_CON4_PDN_A2SYS, 0); | ||
375 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
376 | AUDIO_TOP_CON4_PDN_AFE_CONN, 0); | ||
377 | |||
378 | return 0; | ||
379 | |||
380 | AFE_AUD_ASM_M_ERR: | ||
381 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); | ||
382 | AFE_AUD_ASM_H_ERR: | ||
383 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); | ||
384 | AFE_AUD_AUDINTBUS_ERR: | ||
385 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); | ||
386 | AFE_AUD_INFRA_ERR: | ||
387 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
388 | |||
389 | return ret; | ||
390 | } | ||
391 | |||
392 | void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe) | ||
393 | { | ||
394 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
395 | |||
396 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_INFRA_SYS_AUDIO]); | ||
397 | |||
398 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_AUDINTBUS]); | ||
399 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_H_SEL]); | ||
400 | clk_disable_unprepare(afe_priv->clocks[MT2701_AUD_ASM_M_SEL]); | ||
401 | |||
402 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
403 | AUDIO_TOP_CON0_PDN_AFE, AUDIO_TOP_CON0_PDN_AFE); | ||
404 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | ||
405 | AUDIO_TOP_CON0_PDN_APLL_CK, | ||
406 | AUDIO_TOP_CON0_PDN_APLL_CK); | ||
407 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
408 | AUDIO_TOP_CON4_PDN_A1SYS, | ||
409 | AUDIO_TOP_CON4_PDN_A1SYS); | ||
410 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
411 | AUDIO_TOP_CON4_PDN_A2SYS, | ||
412 | AUDIO_TOP_CON4_PDN_A2SYS); | ||
413 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
414 | AUDIO_TOP_CON4_PDN_AFE_CONN, | ||
415 | AUDIO_TOP_CON4_PDN_AFE_CONN); | ||
416 | } | ||
417 | |||
418 | void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain, | ||
419 | int mclk) | ||
420 | { | ||
421 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
422 | int ret; | ||
423 | int aud_src_div_id = MT2701_AUD_AUD_K1_SRC_DIV + id; | ||
424 | int aud_src_clk_id = MT2701_AUD_AUD_K1_SRC_SEL + id; | ||
425 | |||
426 | /* Set MCLK Kx_SRC_SEL(domain) */ | ||
427 | ret = clk_prepare_enable(afe_priv->clocks[aud_src_clk_id]); | ||
428 | if (ret) | ||
429 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
430 | __func__, aud_clks[aud_src_clk_id], ret); | ||
431 | |||
432 | if (domain == 0) { | ||
433 | ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id], | ||
434 | afe_priv->clocks[MT2701_AUD_AUD_MUX1_SEL]); | ||
435 | if (ret) | ||
436 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", | ||
437 | __func__, aud_clks[aud_src_clk_id], | ||
438 | aud_clks[MT2701_AUD_AUD_MUX1_SEL], ret); | ||
439 | } else { | ||
440 | ret = clk_set_parent(afe_priv->clocks[aud_src_clk_id], | ||
441 | afe_priv->clocks[MT2701_AUD_AUD_MUX2_SEL]); | ||
442 | if (ret) | ||
443 | dev_err(afe->dev, "%s clk_set_parent %s-%s fail %d\n", | ||
444 | __func__, aud_clks[aud_src_clk_id], | ||
445 | aud_clks[MT2701_AUD_AUD_MUX2_SEL], ret); | ||
446 | } | ||
447 | clk_disable_unprepare(afe_priv->clocks[aud_src_clk_id]); | ||
448 | |||
449 | /* Set MCLK Kx_SRC_DIV(divider) */ | ||
450 | ret = clk_prepare_enable(afe_priv->clocks[aud_src_div_id]); | ||
451 | if (ret) | ||
452 | dev_err(afe->dev, "%s clk_prepare_enable %s fail %d\n", | ||
453 | __func__, aud_clks[aud_src_div_id], ret); | ||
454 | |||
455 | ret = clk_set_rate(afe_priv->clocks[aud_src_div_id], mclk); | ||
456 | if (ret) | ||
457 | dev_err(afe->dev, "%s clk_set_rate %s-%d fail %d\n", __func__, | ||
458 | aud_clks[aud_src_div_id], mclk, ret); | ||
459 | clk_disable_unprepare(afe_priv->clocks[aud_src_div_id]); | ||
460 | } | ||
461 | |||
462 | MODULE_DESCRIPTION("MT2701 afe clock control"); | ||
463 | MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); | ||
464 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h new file mode 100644 index 000000000000..6497d570cf09 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-clock-ctrl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * mt2701-afe-clock-ctrl.h -- Mediatek 2701 afe clock ctrl definition | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MT2701_AFE_CLOCK_CTRL_H_ | ||
18 | #define _MT2701_AFE_CLOCK_CTRL_H_ | ||
19 | |||
20 | struct mtk_base_afe; | ||
21 | |||
22 | int mt2701_init_clock(struct mtk_base_afe *afe); | ||
23 | int mt2701_afe_enable_clock(struct mtk_base_afe *afe); | ||
24 | void mt2701_afe_disable_clock(struct mtk_base_afe *afe); | ||
25 | |||
26 | int mt2701_turn_on_a1sys_clock(struct mtk_base_afe *afe); | ||
27 | void mt2701_turn_off_a1sys_clock(struct mtk_base_afe *afe); | ||
28 | |||
29 | int mt2701_turn_on_a2sys_clock(struct mtk_base_afe *afe); | ||
30 | void mt2701_turn_off_a2sys_clock(struct mtk_base_afe *afe); | ||
31 | |||
32 | int mt2701_turn_on_afe_clock(struct mtk_base_afe *afe); | ||
33 | void mt2701_turn_off_afe_clock(struct mtk_base_afe *afe); | ||
34 | |||
35 | void mt2701_mclk_configuration(struct mtk_base_afe *afe, int id, int domain, | ||
36 | int mclk); | ||
37 | |||
38 | #endif | ||
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-common.h b/sound/soc/mediatek/mt2701/mt2701-afe-common.h new file mode 100644 index 000000000000..c19430e98adf --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-common.h | |||
@@ -0,0 +1,172 @@ | |||
1 | /* | ||
2 | * mt2701-afe-common.h -- Mediatek 2701 audio driver definitions | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MT_2701_AFE_COMMON_H_ | ||
18 | #define _MT_2701_AFE_COMMON_H_ | ||
19 | #include <sound/soc.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include "mt2701-reg.h" | ||
23 | #include "../common/mtk-base-afe.h" | ||
24 | |||
25 | #define MT2701_STREAM_DIR_NUM (SNDRV_PCM_STREAM_LAST + 1) | ||
26 | #define MT2701_PLL_DOMAIN_0_RATE 98304000 | ||
27 | #define MT2701_PLL_DOMAIN_1_RATE 90316800 | ||
28 | #define MT2701_AUD_AUD_MUX1_DIV_RATE (MT2701_PLL_DOMAIN_0_RATE / 2) | ||
29 | #define MT2701_AUD_AUD_MUX2_DIV_RATE (MT2701_PLL_DOMAIN_1_RATE / 2) | ||
30 | |||
31 | enum { | ||
32 | MT2701_I2S_1, | ||
33 | MT2701_I2S_2, | ||
34 | MT2701_I2S_3, | ||
35 | MT2701_I2S_4, | ||
36 | MT2701_I2S_NUM, | ||
37 | }; | ||
38 | |||
39 | enum { | ||
40 | MT2701_MEMIF_DL1, | ||
41 | MT2701_MEMIF_DL2, | ||
42 | MT2701_MEMIF_DL3, | ||
43 | MT2701_MEMIF_DL4, | ||
44 | MT2701_MEMIF_DL5, | ||
45 | MT2701_MEMIF_DL_SINGLE_NUM, | ||
46 | MT2701_MEMIF_DLM = MT2701_MEMIF_DL_SINGLE_NUM, | ||
47 | MT2701_MEMIF_UL1, | ||
48 | MT2701_MEMIF_UL2, | ||
49 | MT2701_MEMIF_UL3, | ||
50 | MT2701_MEMIF_UL4, | ||
51 | MT2701_MEMIF_UL5, | ||
52 | MT2701_MEMIF_DLBT, | ||
53 | MT2701_MEMIF_ULBT, | ||
54 | MT2701_MEMIF_NUM, | ||
55 | MT2701_IO_I2S = MT2701_MEMIF_NUM, | ||
56 | MT2701_IO_2ND_I2S, | ||
57 | MT2701_IO_3RD_I2S, | ||
58 | MT2701_IO_4TH_I2S, | ||
59 | MT2701_IO_5TH_I2S, | ||
60 | MT2701_IO_6TH_I2S, | ||
61 | MT2701_IO_MRG, | ||
62 | }; | ||
63 | |||
64 | enum { | ||
65 | MT2701_IRQ_ASYS_START, | ||
66 | MT2701_IRQ_ASYS_IRQ1 = MT2701_IRQ_ASYS_START, | ||
67 | MT2701_IRQ_ASYS_IRQ2, | ||
68 | MT2701_IRQ_ASYS_IRQ3, | ||
69 | MT2701_IRQ_ASYS_END, | ||
70 | }; | ||
71 | |||
72 | /* 2701 clock def */ | ||
73 | enum audio_system_clock_type { | ||
74 | MT2701_AUD_INFRA_SYS_AUDIO, | ||
75 | MT2701_AUD_AUD_MUX1_SEL, | ||
76 | MT2701_AUD_AUD_MUX2_SEL, | ||
77 | MT2701_AUD_AUD_MUX1_DIV, | ||
78 | MT2701_AUD_AUD_MUX2_DIV, | ||
79 | MT2701_AUD_AUD_48K_TIMING, | ||
80 | MT2701_AUD_AUD_44K_TIMING, | ||
81 | MT2701_AUD_AUDPLL_MUX_SEL, | ||
82 | MT2701_AUD_APLL_SEL, | ||
83 | MT2701_AUD_AUD1PLL_98M, | ||
84 | MT2701_AUD_AUD2PLL_90M, | ||
85 | MT2701_AUD_HADDS2PLL_98M, | ||
86 | MT2701_AUD_HADDS2PLL_294M, | ||
87 | MT2701_AUD_AUDPLL, | ||
88 | MT2701_AUD_AUDPLL_D4, | ||
89 | MT2701_AUD_AUDPLL_D8, | ||
90 | MT2701_AUD_AUDPLL_D16, | ||
91 | MT2701_AUD_AUDPLL_D24, | ||
92 | MT2701_AUD_AUDINTBUS, | ||
93 | MT2701_AUD_CLK_26M, | ||
94 | MT2701_AUD_SYSPLL1_D4, | ||
95 | MT2701_AUD_AUD_K1_SRC_SEL, | ||
96 | MT2701_AUD_AUD_K2_SRC_SEL, | ||
97 | MT2701_AUD_AUD_K3_SRC_SEL, | ||
98 | MT2701_AUD_AUD_K4_SRC_SEL, | ||
99 | MT2701_AUD_AUD_K5_SRC_SEL, | ||
100 | MT2701_AUD_AUD_K6_SRC_SEL, | ||
101 | MT2701_AUD_AUD_K1_SRC_DIV, | ||
102 | MT2701_AUD_AUD_K2_SRC_DIV, | ||
103 | MT2701_AUD_AUD_K3_SRC_DIV, | ||
104 | MT2701_AUD_AUD_K4_SRC_DIV, | ||
105 | MT2701_AUD_AUD_K5_SRC_DIV, | ||
106 | MT2701_AUD_AUD_K6_SRC_DIV, | ||
107 | MT2701_AUD_AUD_I2S1_MCLK, | ||
108 | MT2701_AUD_AUD_I2S2_MCLK, | ||
109 | MT2701_AUD_AUD_I2S3_MCLK, | ||
110 | MT2701_AUD_AUD_I2S4_MCLK, | ||
111 | MT2701_AUD_AUD_I2S5_MCLK, | ||
112 | MT2701_AUD_AUD_I2S6_MCLK, | ||
113 | MT2701_AUD_ASM_M_SEL, | ||
114 | MT2701_AUD_ASM_H_SEL, | ||
115 | MT2701_AUD_UNIVPLL2_D4, | ||
116 | MT2701_AUD_UNIVPLL2_D2, | ||
117 | MT2701_AUD_SYSPLL_D5, | ||
118 | MT2701_CLOCK_NUM | ||
119 | }; | ||
120 | |||
121 | static const unsigned int mt2701_afe_backup_list[] = { | ||
122 | AUDIO_TOP_CON0, | ||
123 | AUDIO_TOP_CON4, | ||
124 | AUDIO_TOP_CON5, | ||
125 | ASYS_TOP_CON, | ||
126 | AFE_CONN0, | ||
127 | AFE_CONN1, | ||
128 | AFE_CONN2, | ||
129 | AFE_CONN3, | ||
130 | AFE_CONN15, | ||
131 | AFE_CONN16, | ||
132 | AFE_CONN17, | ||
133 | AFE_CONN18, | ||
134 | AFE_CONN19, | ||
135 | AFE_CONN20, | ||
136 | AFE_CONN21, | ||
137 | AFE_CONN22, | ||
138 | AFE_DAC_CON0, | ||
139 | AFE_MEMIF_PBUF_SIZE, | ||
140 | }; | ||
141 | |||
142 | struct snd_pcm_substream; | ||
143 | struct mtk_base_irq_data; | ||
144 | |||
145 | struct mt2701_i2s_data { | ||
146 | int i2s_ctrl_reg; | ||
147 | int i2s_pwn_shift; | ||
148 | int i2s_asrc_fs_shift; | ||
149 | int i2s_asrc_fs_mask; | ||
150 | }; | ||
151 | |||
152 | enum mt2701_i2s_dir { | ||
153 | I2S_OUT, | ||
154 | I2S_IN, | ||
155 | I2S_DIR_NUM, | ||
156 | }; | ||
157 | |||
158 | struct mt2701_i2s_path { | ||
159 | int dai_id; | ||
160 | int mclk_rate; | ||
161 | int on[I2S_DIR_NUM]; | ||
162 | int occupied[I2S_DIR_NUM]; | ||
163 | const struct mt2701_i2s_data *i2s_data[2]; | ||
164 | }; | ||
165 | |||
166 | struct mt2701_afe_private { | ||
167 | struct clk *clocks[MT2701_CLOCK_NUM]; | ||
168 | struct mt2701_i2s_path i2s_path[MT2701_I2S_NUM]; | ||
169 | bool mrg_enable[MT2701_STREAM_DIR_NUM]; | ||
170 | }; | ||
171 | |||
172 | #endif | ||
diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c new file mode 100644 index 000000000000..34a6123480d3 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c | |||
@@ -0,0 +1,1656 @@ | |||
1 | /* | ||
2 | * Mediatek ALSA SoC AFE platform driver for 2701 | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.com> | ||
6 | * Ir Lian <ir.lian@mediatek.com> | ||
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 version 2 and | ||
10 | * only version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/delay.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/of.h> | ||
21 | #include <linux/of_address.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <sound/soc.h> | ||
24 | |||
25 | #include "mt2701-afe-common.h" | ||
26 | |||
27 | #include "mt2701-afe-clock-ctrl.h" | ||
28 | #include "../common/mtk-afe-platform-driver.h" | ||
29 | #include "../common/mtk-afe-fe-dai.h" | ||
30 | |||
31 | #define AFE_IRQ_STATUS_BITS 0xff | ||
32 | |||
33 | static const struct snd_pcm_hardware mt2701_afe_hardware = { | ||
34 | .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | ||
35 | | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID, | ||
36 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | ||
37 | | SNDRV_PCM_FMTBIT_S32_LE, | ||
38 | .period_bytes_min = 1024, | ||
39 | .period_bytes_max = 1024 * 256, | ||
40 | .periods_min = 4, | ||
41 | .periods_max = 1024, | ||
42 | .buffer_bytes_max = 1024 * 1024 * 16, | ||
43 | .fifo_size = 0, | ||
44 | }; | ||
45 | |||
46 | struct mt2701_afe_rate { | ||
47 | unsigned int rate; | ||
48 | unsigned int regvalue; | ||
49 | }; | ||
50 | |||
51 | static const struct mt2701_afe_rate mt2701_afe_i2s_rates[] = { | ||
52 | { .rate = 8000, .regvalue = 0 }, | ||
53 | { .rate = 12000, .regvalue = 1 }, | ||
54 | { .rate = 16000, .regvalue = 2 }, | ||
55 | { .rate = 24000, .regvalue = 3 }, | ||
56 | { .rate = 32000, .regvalue = 4 }, | ||
57 | { .rate = 48000, .regvalue = 5 }, | ||
58 | { .rate = 96000, .regvalue = 6 }, | ||
59 | { .rate = 192000, .regvalue = 7 }, | ||
60 | { .rate = 384000, .regvalue = 8 }, | ||
61 | { .rate = 7350, .regvalue = 16 }, | ||
62 | { .rate = 11025, .regvalue = 17 }, | ||
63 | { .rate = 14700, .regvalue = 18 }, | ||
64 | { .rate = 22050, .regvalue = 19 }, | ||
65 | { .rate = 29400, .regvalue = 20 }, | ||
66 | { .rate = 44100, .regvalue = 21 }, | ||
67 | { .rate = 88200, .regvalue = 22 }, | ||
68 | { .rate = 176400, .regvalue = 23 }, | ||
69 | { .rate = 352800, .regvalue = 24 }, | ||
70 | }; | ||
71 | |||
72 | static int mt2701_dai_num_to_i2s(struct mtk_base_afe *afe, int num) | ||
73 | { | ||
74 | int val = num - MT2701_IO_I2S; | ||
75 | |||
76 | if (val < 0 || val >= MT2701_I2S_NUM) { | ||
77 | dev_err(afe->dev, "%s, num not available, num %d, val %d\n", | ||
78 | __func__, num, val); | ||
79 | return -EINVAL; | ||
80 | } | ||
81 | return val; | ||
82 | } | ||
83 | |||
84 | static int mt2701_afe_i2s_fs(unsigned int sample_rate) | ||
85 | { | ||
86 | int i; | ||
87 | |||
88 | for (i = 0; i < ARRAY_SIZE(mt2701_afe_i2s_rates); i++) | ||
89 | if (mt2701_afe_i2s_rates[i].rate == sample_rate) | ||
90 | return mt2701_afe_i2s_rates[i].regvalue; | ||
91 | |||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | static int mt2701_afe_i2s_startup(struct snd_pcm_substream *substream, | ||
96 | struct snd_soc_dai *dai) | ||
97 | { | ||
98 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
99 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
100 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
101 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
102 | int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num; | ||
103 | int ret = 0; | ||
104 | |||
105 | if (i2s_num < 0) | ||
106 | return i2s_num; | ||
107 | |||
108 | /* enable mclk */ | ||
109 | ret = clk_prepare_enable(afe_priv->clocks[clk_num]); | ||
110 | if (ret) | ||
111 | dev_err(afe->dev, "Failed to enable mclk for I2S: %d\n", | ||
112 | i2s_num); | ||
113 | |||
114 | return ret; | ||
115 | } | ||
116 | |||
117 | static int mt2701_afe_i2s_path_shutdown(struct snd_pcm_substream *substream, | ||
118 | struct snd_soc_dai *dai, | ||
119 | int dir_invert) | ||
120 | { | ||
121 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
122 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
123 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
124 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
125 | struct mt2701_i2s_path *i2s_path; | ||
126 | const struct mt2701_i2s_data *i2s_data; | ||
127 | int stream_dir = substream->stream; | ||
128 | |||
129 | if (i2s_num < 0) | ||
130 | return i2s_num; | ||
131 | |||
132 | i2s_path = &afe_priv->i2s_path[i2s_num]; | ||
133 | |||
134 | if (dir_invert) { | ||
135 | if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) | ||
136 | stream_dir = SNDRV_PCM_STREAM_CAPTURE; | ||
137 | else | ||
138 | stream_dir = SNDRV_PCM_STREAM_PLAYBACK; | ||
139 | } | ||
140 | i2s_data = i2s_path->i2s_data[stream_dir]; | ||
141 | |||
142 | i2s_path->on[stream_dir]--; | ||
143 | if (i2s_path->on[stream_dir] < 0) { | ||
144 | dev_warn(afe->dev, "i2s_path->on: %d, dir: %d\n", | ||
145 | i2s_path->on[stream_dir], stream_dir); | ||
146 | i2s_path->on[stream_dir] = 0; | ||
147 | } | ||
148 | if (i2s_path->on[stream_dir]) | ||
149 | return 0; | ||
150 | |||
151 | /* disable i2s */ | ||
152 | regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, | ||
153 | ASYS_I2S_CON_I2S_EN, 0); | ||
154 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
155 | 1 << i2s_data->i2s_pwn_shift, | ||
156 | 1 << i2s_data->i2s_pwn_shift); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static void mt2701_afe_i2s_shutdown(struct snd_pcm_substream *substream, | ||
161 | struct snd_soc_dai *dai) | ||
162 | { | ||
163 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
164 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
165 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
166 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
167 | struct mt2701_i2s_path *i2s_path; | ||
168 | int clk_num = MT2701_AUD_AUD_I2S1_MCLK + i2s_num; | ||
169 | |||
170 | if (i2s_num < 0) | ||
171 | return; | ||
172 | |||
173 | i2s_path = &afe_priv->i2s_path[i2s_num]; | ||
174 | |||
175 | if (i2s_path->occupied[substream->stream]) | ||
176 | i2s_path->occupied[substream->stream] = 0; | ||
177 | else | ||
178 | goto I2S_UNSTART; | ||
179 | |||
180 | mt2701_afe_i2s_path_shutdown(substream, dai, 0); | ||
181 | |||
182 | /* need to disable i2s-out path when disable i2s-in */ | ||
183 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
184 | mt2701_afe_i2s_path_shutdown(substream, dai, 1); | ||
185 | |||
186 | I2S_UNSTART: | ||
187 | /* disable mclk */ | ||
188 | clk_disable_unprepare(afe_priv->clocks[clk_num]); | ||
189 | } | ||
190 | |||
191 | static int mt2701_i2s_path_prepare_enable(struct snd_pcm_substream *substream, | ||
192 | struct snd_soc_dai *dai, | ||
193 | int dir_invert) | ||
194 | { | ||
195 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
196 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
197 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
198 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
199 | struct mt2701_i2s_path *i2s_path; | ||
200 | const struct mt2701_i2s_data *i2s_data; | ||
201 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
202 | int reg, fs, w_len = 1; /* now we support bck 64bits only */ | ||
203 | int stream_dir = substream->stream; | ||
204 | unsigned int mask = 0, val = 0; | ||
205 | |||
206 | if (i2s_num < 0) | ||
207 | return i2s_num; | ||
208 | |||
209 | i2s_path = &afe_priv->i2s_path[i2s_num]; | ||
210 | |||
211 | if (dir_invert) { | ||
212 | if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) | ||
213 | stream_dir = SNDRV_PCM_STREAM_CAPTURE; | ||
214 | else | ||
215 | stream_dir = SNDRV_PCM_STREAM_PLAYBACK; | ||
216 | } | ||
217 | i2s_data = i2s_path->i2s_data[stream_dir]; | ||
218 | |||
219 | /* no need to enable if already done */ | ||
220 | i2s_path->on[stream_dir]++; | ||
221 | |||
222 | if (i2s_path->on[stream_dir] != 1) | ||
223 | return 0; | ||
224 | |||
225 | fs = mt2701_afe_i2s_fs(runtime->rate); | ||
226 | |||
227 | mask = ASYS_I2S_CON_FS | | ||
228 | ASYS_I2S_CON_I2S_COUPLE_MODE | /* 0 */ | ||
229 | ASYS_I2S_CON_I2S_MODE | | ||
230 | ASYS_I2S_CON_WIDE_MODE; | ||
231 | |||
232 | val = ASYS_I2S_CON_FS_SET(fs) | | ||
233 | ASYS_I2S_CON_I2S_MODE | | ||
234 | ASYS_I2S_CON_WIDE_MODE_SET(w_len); | ||
235 | |||
236 | if (stream_dir == SNDRV_PCM_STREAM_CAPTURE) { | ||
237 | mask |= ASYS_I2S_IN_PHASE_FIX; | ||
238 | val |= ASYS_I2S_IN_PHASE_FIX; | ||
239 | } | ||
240 | |||
241 | regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, mask, val); | ||
242 | |||
243 | if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) | ||
244 | reg = ASMO_TIMING_CON1; | ||
245 | else | ||
246 | reg = ASMI_TIMING_CON1; | ||
247 | |||
248 | regmap_update_bits(afe->regmap, reg, | ||
249 | i2s_data->i2s_asrc_fs_mask | ||
250 | << i2s_data->i2s_asrc_fs_shift, | ||
251 | fs << i2s_data->i2s_asrc_fs_shift); | ||
252 | |||
253 | /* enable i2s */ | ||
254 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
255 | 1 << i2s_data->i2s_pwn_shift, | ||
256 | 0 << i2s_data->i2s_pwn_shift); | ||
257 | |||
258 | /* reset i2s hw status before enable */ | ||
259 | regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, | ||
260 | ASYS_I2S_CON_RESET, ASYS_I2S_CON_RESET); | ||
261 | udelay(1); | ||
262 | regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, | ||
263 | ASYS_I2S_CON_RESET, 0); | ||
264 | udelay(1); | ||
265 | regmap_update_bits(afe->regmap, i2s_data->i2s_ctrl_reg, | ||
266 | ASYS_I2S_CON_I2S_EN, ASYS_I2S_CON_I2S_EN); | ||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int mt2701_afe_i2s_prepare(struct snd_pcm_substream *substream, | ||
271 | struct snd_soc_dai *dai) | ||
272 | { | ||
273 | int clk_domain; | ||
274 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
275 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
276 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
277 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
278 | struct mt2701_i2s_path *i2s_path; | ||
279 | int mclk_rate; | ||
280 | |||
281 | if (i2s_num < 0) | ||
282 | return i2s_num; | ||
283 | |||
284 | i2s_path = &afe_priv->i2s_path[i2s_num]; | ||
285 | mclk_rate = i2s_path->mclk_rate; | ||
286 | |||
287 | if (i2s_path->occupied[substream->stream]) | ||
288 | return -EBUSY; | ||
289 | i2s_path->occupied[substream->stream] = 1; | ||
290 | |||
291 | if (MT2701_PLL_DOMAIN_0_RATE % mclk_rate == 0) { | ||
292 | clk_domain = 0; | ||
293 | } else if (MT2701_PLL_DOMAIN_1_RATE % mclk_rate == 0) { | ||
294 | clk_domain = 1; | ||
295 | } else { | ||
296 | dev_err(dai->dev, "%s() bad mclk rate %d\n", | ||
297 | __func__, mclk_rate); | ||
298 | return -EINVAL; | ||
299 | } | ||
300 | mt2701_mclk_configuration(afe, i2s_num, clk_domain, mclk_rate); | ||
301 | |||
302 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
303 | mt2701_i2s_path_prepare_enable(substream, dai, 0); | ||
304 | } else { | ||
305 | /* need to enable i2s-out path when enable i2s-in */ | ||
306 | /* prepare for another direction "out" */ | ||
307 | mt2701_i2s_path_prepare_enable(substream, dai, 1); | ||
308 | /* prepare for "in" */ | ||
309 | mt2701_i2s_path_prepare_enable(substream, dai, 0); | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int mt2701_afe_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
316 | unsigned int freq, int dir) | ||
317 | { | ||
318 | struct mtk_base_afe *afe = dev_get_drvdata(dai->dev); | ||
319 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
320 | int i2s_num = mt2701_dai_num_to_i2s(afe, dai->id); | ||
321 | |||
322 | if (i2s_num < 0) | ||
323 | return i2s_num; | ||
324 | |||
325 | /* mclk */ | ||
326 | if (dir == SND_SOC_CLOCK_IN) { | ||
327 | dev_warn(dai->dev, | ||
328 | "%s() warning: mt2701 doesn't support mclk input\n", | ||
329 | __func__); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | afe_priv->i2s_path[i2s_num].mclk_rate = freq; | ||
333 | return 0; | ||
334 | } | ||
335 | |||
336 | static int mt2701_btmrg_startup(struct snd_pcm_substream *substream, | ||
337 | struct snd_soc_dai *dai) | ||
338 | { | ||
339 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
340 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
341 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
342 | |||
343 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
344 | AUDIO_TOP_CON4_PDN_MRGIF, 0); | ||
345 | |||
346 | afe_priv->mrg_enable[substream->stream] = 1; | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int mt2701_btmrg_hw_params(struct snd_pcm_substream *substream, | ||
351 | struct snd_pcm_hw_params *params, | ||
352 | struct snd_soc_dai *dai) | ||
353 | { | ||
354 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
355 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
356 | int stream_fs; | ||
357 | u32 val, msk; | ||
358 | |||
359 | stream_fs = params_rate(params); | ||
360 | |||
361 | if ((stream_fs != 8000) && (stream_fs != 16000)) { | ||
362 | dev_err(afe->dev, "%s() btmgr not supprt this stream_fs %d\n", | ||
363 | __func__, stream_fs); | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | regmap_update_bits(afe->regmap, AFE_MRGIF_CON, | ||
368 | AFE_MRGIF_CON_I2S_MODE_MASK, | ||
369 | AFE_MRGIF_CON_I2S_MODE_32K); | ||
370 | |||
371 | val = AFE_DAIBT_CON0_BT_FUNC_EN | AFE_DAIBT_CON0_BT_FUNC_RDY | ||
372 | | AFE_DAIBT_CON0_MRG_USE; | ||
373 | msk = val; | ||
374 | |||
375 | if (stream_fs == 16000) | ||
376 | val |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN; | ||
377 | |||
378 | msk |= AFE_DAIBT_CON0_BT_WIDE_MODE_EN; | ||
379 | |||
380 | regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, msk, val); | ||
381 | |||
382 | regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, | ||
383 | AFE_DAIBT_CON0_DAIBT_EN, | ||
384 | AFE_DAIBT_CON0_DAIBT_EN); | ||
385 | regmap_update_bits(afe->regmap, AFE_MRGIF_CON, | ||
386 | AFE_MRGIF_CON_MRG_I2S_EN, | ||
387 | AFE_MRGIF_CON_MRG_I2S_EN); | ||
388 | regmap_update_bits(afe->regmap, AFE_MRGIF_CON, | ||
389 | AFE_MRGIF_CON_MRG_EN, | ||
390 | AFE_MRGIF_CON_MRG_EN); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static void mt2701_btmrg_shutdown(struct snd_pcm_substream *substream, | ||
395 | struct snd_soc_dai *dai) | ||
396 | { | ||
397 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
398 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
399 | struct mt2701_afe_private *afe_priv = afe->platform_priv; | ||
400 | |||
401 | /* if the other direction stream is not occupied */ | ||
402 | if (!afe_priv->mrg_enable[!substream->stream]) { | ||
403 | regmap_update_bits(afe->regmap, AFE_DAIBT_CON0, | ||
404 | AFE_DAIBT_CON0_DAIBT_EN, 0); | ||
405 | regmap_update_bits(afe->regmap, AFE_MRGIF_CON, | ||
406 | AFE_MRGIF_CON_MRG_EN, 0); | ||
407 | regmap_update_bits(afe->regmap, AFE_MRGIF_CON, | ||
408 | AFE_MRGIF_CON_MRG_I2S_EN, 0); | ||
409 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON4, | ||
410 | AUDIO_TOP_CON4_PDN_MRGIF, | ||
411 | AUDIO_TOP_CON4_PDN_MRGIF); | ||
412 | } | ||
413 | afe_priv->mrg_enable[substream->stream] = 0; | ||
414 | } | ||
415 | |||
416 | static int mt2701_simple_fe_startup(struct snd_pcm_substream *substream, | ||
417 | struct snd_soc_dai *dai) | ||
418 | { | ||
419 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
420 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
421 | int stream_dir = substream->stream; | ||
422 | int memif_num = rtd->cpu_dai->id; | ||
423 | struct mtk_base_afe_memif *memif_tmp; | ||
424 | |||
425 | /* can't run single DL & DLM at the same time */ | ||
426 | if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) { | ||
427 | memif_tmp = &afe->memif[MT2701_MEMIF_DLM]; | ||
428 | if (memif_tmp->substream) { | ||
429 | dev_warn(afe->dev, "%s memif is not available, stream_dir %d, memif_num %d\n", | ||
430 | __func__, stream_dir, memif_num); | ||
431 | return -EBUSY; | ||
432 | } | ||
433 | } | ||
434 | return mtk_afe_fe_startup(substream, dai); | ||
435 | } | ||
436 | |||
437 | static int mt2701_simple_fe_hw_params(struct snd_pcm_substream *substream, | ||
438 | struct snd_pcm_hw_params *params, | ||
439 | struct snd_soc_dai *dai) | ||
440 | { | ||
441 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
442 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
443 | int stream_dir = substream->stream; | ||
444 | |||
445 | /* single DL use PAIR_INTERLEAVE */ | ||
446 | if (stream_dir == SNDRV_PCM_STREAM_PLAYBACK) { | ||
447 | regmap_update_bits(afe->regmap, | ||
448 | AFE_MEMIF_PBUF_SIZE, | ||
449 | AFE_MEMIF_PBUF_SIZE_DLM_MASK, | ||
450 | AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE); | ||
451 | } | ||
452 | return mtk_afe_fe_hw_params(substream, params, dai); | ||
453 | } | ||
454 | |||
455 | static int mt2701_dlm_fe_startup(struct snd_pcm_substream *substream, | ||
456 | struct snd_soc_dai *dai) | ||
457 | { | ||
458 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
459 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
460 | struct mtk_base_afe_memif *memif_tmp; | ||
461 | const struct mtk_base_memif_data *memif_data; | ||
462 | int i; | ||
463 | |||
464 | for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) { | ||
465 | memif_tmp = &afe->memif[i]; | ||
466 | if (memif_tmp->substream) | ||
467 | return -EBUSY; | ||
468 | } | ||
469 | |||
470 | /* enable agent for all signal DL (due to hw design) */ | ||
471 | for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) { | ||
472 | memif_data = afe->memif[i].data; | ||
473 | regmap_update_bits(afe->regmap, | ||
474 | memif_data->agent_disable_reg, | ||
475 | 1 << memif_data->agent_disable_shift, | ||
476 | 0 << memif_data->agent_disable_shift); | ||
477 | } | ||
478 | |||
479 | return mtk_afe_fe_startup(substream, dai); | ||
480 | } | ||
481 | |||
482 | static void mt2701_dlm_fe_shutdown(struct snd_pcm_substream *substream, | ||
483 | struct snd_soc_dai *dai) | ||
484 | { | ||
485 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
486 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
487 | const struct mtk_base_memif_data *memif_data; | ||
488 | int i; | ||
489 | |||
490 | for (i = MT2701_MEMIF_DL1; i < MT2701_MEMIF_DL_SINGLE_NUM; ++i) { | ||
491 | memif_data = afe->memif[i].data; | ||
492 | regmap_update_bits(afe->regmap, | ||
493 | memif_data->agent_disable_reg, | ||
494 | 1 << memif_data->agent_disable_shift, | ||
495 | 1 << memif_data->agent_disable_shift); | ||
496 | } | ||
497 | return mtk_afe_fe_shutdown(substream, dai); | ||
498 | } | ||
499 | |||
500 | static int mt2701_dlm_fe_hw_params(struct snd_pcm_substream *substream, | ||
501 | struct snd_pcm_hw_params *params, | ||
502 | struct snd_soc_dai *dai) | ||
503 | { | ||
504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
505 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
506 | int channels = params_channels(params); | ||
507 | |||
508 | regmap_update_bits(afe->regmap, | ||
509 | AFE_MEMIF_PBUF_SIZE, | ||
510 | AFE_MEMIF_PBUF_SIZE_DLM_MASK, | ||
511 | AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE); | ||
512 | regmap_update_bits(afe->regmap, | ||
513 | AFE_MEMIF_PBUF_SIZE, | ||
514 | AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK, | ||
515 | AFE_MEMIF_PBUF_SIZE_DLM_32BYTES); | ||
516 | regmap_update_bits(afe->regmap, | ||
517 | AFE_MEMIF_PBUF_SIZE, | ||
518 | AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK, | ||
519 | AFE_MEMIF_PBUF_SIZE_DLM_CH(channels)); | ||
520 | |||
521 | return mtk_afe_fe_hw_params(substream, params, dai); | ||
522 | } | ||
523 | |||
524 | static int mt2701_dlm_fe_trigger(struct snd_pcm_substream *substream, | ||
525 | int cmd, struct snd_soc_dai *dai) | ||
526 | { | ||
527 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
528 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
529 | struct mtk_base_afe_memif *memif_tmp = &afe->memif[MT2701_MEMIF_DL1]; | ||
530 | |||
531 | switch (cmd) { | ||
532 | case SNDRV_PCM_TRIGGER_START: | ||
533 | case SNDRV_PCM_TRIGGER_RESUME: | ||
534 | regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg, | ||
535 | 1 << memif_tmp->data->enable_shift, | ||
536 | 1 << memif_tmp->data->enable_shift); | ||
537 | mtk_afe_fe_trigger(substream, cmd, dai); | ||
538 | return 0; | ||
539 | case SNDRV_PCM_TRIGGER_STOP: | ||
540 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
541 | mtk_afe_fe_trigger(substream, cmd, dai); | ||
542 | regmap_update_bits(afe->regmap, memif_tmp->data->enable_reg, | ||
543 | 1 << memif_tmp->data->enable_shift, 0); | ||
544 | |||
545 | return 0; | ||
546 | default: | ||
547 | return -EINVAL; | ||
548 | } | ||
549 | } | ||
550 | |||
551 | static int mt2701_memif_fs(struct snd_pcm_substream *substream, | ||
552 | unsigned int rate) | ||
553 | { | ||
554 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
555 | int fs; | ||
556 | |||
557 | if (rtd->cpu_dai->id != MT2701_MEMIF_ULBT) | ||
558 | fs = mt2701_afe_i2s_fs(rate); | ||
559 | else | ||
560 | fs = (rate == 16000 ? 1 : 0); | ||
561 | return fs; | ||
562 | } | ||
563 | |||
564 | static int mt2701_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) | ||
565 | { | ||
566 | return mt2701_afe_i2s_fs(rate); | ||
567 | } | ||
568 | |||
569 | /* FE DAIs */ | ||
570 | static const struct snd_soc_dai_ops mt2701_single_memif_dai_ops = { | ||
571 | .startup = mt2701_simple_fe_startup, | ||
572 | .shutdown = mtk_afe_fe_shutdown, | ||
573 | .hw_params = mt2701_simple_fe_hw_params, | ||
574 | .hw_free = mtk_afe_fe_hw_free, | ||
575 | .prepare = mtk_afe_fe_prepare, | ||
576 | .trigger = mtk_afe_fe_trigger, | ||
577 | |||
578 | }; | ||
579 | |||
580 | static const struct snd_soc_dai_ops mt2701_dlm_memif_dai_ops = { | ||
581 | .startup = mt2701_dlm_fe_startup, | ||
582 | .shutdown = mt2701_dlm_fe_shutdown, | ||
583 | .hw_params = mt2701_dlm_fe_hw_params, | ||
584 | .hw_free = mtk_afe_fe_hw_free, | ||
585 | .prepare = mtk_afe_fe_prepare, | ||
586 | .trigger = mt2701_dlm_fe_trigger, | ||
587 | }; | ||
588 | |||
589 | /* I2S BE DAIs */ | ||
590 | static const struct snd_soc_dai_ops mt2701_afe_i2s_ops = { | ||
591 | .startup = mt2701_afe_i2s_startup, | ||
592 | .shutdown = mt2701_afe_i2s_shutdown, | ||
593 | .prepare = mt2701_afe_i2s_prepare, | ||
594 | .set_sysclk = mt2701_afe_i2s_set_sysclk, | ||
595 | }; | ||
596 | |||
597 | /* MRG BE DAIs */ | ||
598 | static struct snd_soc_dai_ops mt2701_btmrg_ops = { | ||
599 | .startup = mt2701_btmrg_startup, | ||
600 | .shutdown = mt2701_btmrg_shutdown, | ||
601 | .hw_params = mt2701_btmrg_hw_params, | ||
602 | }; | ||
603 | |||
604 | static struct snd_soc_dai_driver mt2701_afe_pcm_dais[] = { | ||
605 | /* FE DAIs: memory intefaces to CPU */ | ||
606 | { | ||
607 | .name = "PCM_multi", | ||
608 | .id = MT2701_MEMIF_DLM, | ||
609 | .suspend = mtk_afe_dai_suspend, | ||
610 | .resume = mtk_afe_dai_resume, | ||
611 | .playback = { | ||
612 | .stream_name = "DLM", | ||
613 | .channels_min = 1, | ||
614 | .channels_max = 8, | ||
615 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
616 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
617 | | SNDRV_PCM_FMTBIT_S24_LE | ||
618 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
619 | |||
620 | }, | ||
621 | .ops = &mt2701_dlm_memif_dai_ops, | ||
622 | }, | ||
623 | { | ||
624 | .name = "PCM0", | ||
625 | .id = MT2701_MEMIF_UL1, | ||
626 | .suspend = mtk_afe_dai_suspend, | ||
627 | .resume = mtk_afe_dai_resume, | ||
628 | .capture = { | ||
629 | .stream_name = "UL1", | ||
630 | .channels_min = 1, | ||
631 | .channels_max = 2, | ||
632 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
633 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
634 | | SNDRV_PCM_FMTBIT_S24_LE | ||
635 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
636 | }, | ||
637 | .ops = &mt2701_single_memif_dai_ops, | ||
638 | }, | ||
639 | { | ||
640 | .name = "PCM1", | ||
641 | .id = MT2701_MEMIF_UL2, | ||
642 | .suspend = mtk_afe_dai_suspend, | ||
643 | .resume = mtk_afe_dai_resume, | ||
644 | .capture = { | ||
645 | .stream_name = "UL2", | ||
646 | .channels_min = 1, | ||
647 | .channels_max = 2, | ||
648 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
649 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
650 | | SNDRV_PCM_FMTBIT_S24_LE | ||
651 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
652 | |||
653 | }, | ||
654 | .ops = &mt2701_single_memif_dai_ops, | ||
655 | }, | ||
656 | { | ||
657 | .name = "PCM_BT_DL", | ||
658 | .id = MT2701_MEMIF_DLBT, | ||
659 | .suspend = mtk_afe_dai_suspend, | ||
660 | .resume = mtk_afe_dai_resume, | ||
661 | .playback = { | ||
662 | .stream_name = "DLBT", | ||
663 | .channels_min = 1, | ||
664 | .channels_max = 1, | ||
665 | .rates = (SNDRV_PCM_RATE_8000 | ||
666 | | SNDRV_PCM_RATE_16000), | ||
667 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
668 | }, | ||
669 | .ops = &mt2701_single_memif_dai_ops, | ||
670 | }, | ||
671 | { | ||
672 | .name = "PCM_BT_UL", | ||
673 | .id = MT2701_MEMIF_ULBT, | ||
674 | .suspend = mtk_afe_dai_suspend, | ||
675 | .resume = mtk_afe_dai_resume, | ||
676 | .capture = { | ||
677 | .stream_name = "ULBT", | ||
678 | .channels_min = 1, | ||
679 | .channels_max = 1, | ||
680 | .rates = (SNDRV_PCM_RATE_8000 | ||
681 | | SNDRV_PCM_RATE_16000), | ||
682 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
683 | }, | ||
684 | .ops = &mt2701_single_memif_dai_ops, | ||
685 | }, | ||
686 | /* BE DAIs */ | ||
687 | { | ||
688 | .name = "I2S0", | ||
689 | .id = MT2701_IO_I2S, | ||
690 | .playback = { | ||
691 | .stream_name = "I2S0 Playback", | ||
692 | .channels_min = 1, | ||
693 | .channels_max = 2, | ||
694 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
695 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
696 | | SNDRV_PCM_FMTBIT_S24_LE | ||
697 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
698 | |||
699 | }, | ||
700 | .capture = { | ||
701 | .stream_name = "I2S0 Capture", | ||
702 | .channels_min = 1, | ||
703 | .channels_max = 2, | ||
704 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
705 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
706 | | SNDRV_PCM_FMTBIT_S24_LE | ||
707 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
708 | |||
709 | }, | ||
710 | .ops = &mt2701_afe_i2s_ops, | ||
711 | .symmetric_rates = 1, | ||
712 | }, | ||
713 | { | ||
714 | .name = "I2S1", | ||
715 | .id = MT2701_IO_2ND_I2S, | ||
716 | .playback = { | ||
717 | .stream_name = "I2S1 Playback", | ||
718 | .channels_min = 1, | ||
719 | .channels_max = 2, | ||
720 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
721 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
722 | | SNDRV_PCM_FMTBIT_S24_LE | ||
723 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
724 | }, | ||
725 | .capture = { | ||
726 | .stream_name = "I2S1 Capture", | ||
727 | .channels_min = 1, | ||
728 | .channels_max = 2, | ||
729 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
730 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
731 | | SNDRV_PCM_FMTBIT_S24_LE | ||
732 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
733 | }, | ||
734 | .ops = &mt2701_afe_i2s_ops, | ||
735 | .symmetric_rates = 1, | ||
736 | }, | ||
737 | { | ||
738 | .name = "I2S2", | ||
739 | .id = MT2701_IO_3RD_I2S, | ||
740 | .playback = { | ||
741 | .stream_name = "I2S2 Playback", | ||
742 | .channels_min = 1, | ||
743 | .channels_max = 2, | ||
744 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
745 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
746 | | SNDRV_PCM_FMTBIT_S24_LE | ||
747 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
748 | }, | ||
749 | .capture = { | ||
750 | .stream_name = "I2S2 Capture", | ||
751 | .channels_min = 1, | ||
752 | .channels_max = 2, | ||
753 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
754 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
755 | | SNDRV_PCM_FMTBIT_S24_LE | ||
756 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
757 | }, | ||
758 | .ops = &mt2701_afe_i2s_ops, | ||
759 | .symmetric_rates = 1, | ||
760 | }, | ||
761 | { | ||
762 | .name = "I2S3", | ||
763 | .id = MT2701_IO_4TH_I2S, | ||
764 | .playback = { | ||
765 | .stream_name = "I2S3 Playback", | ||
766 | .channels_min = 1, | ||
767 | .channels_max = 2, | ||
768 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
769 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
770 | | SNDRV_PCM_FMTBIT_S24_LE | ||
771 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
772 | }, | ||
773 | .capture = { | ||
774 | .stream_name = "I2S3 Capture", | ||
775 | .channels_min = 1, | ||
776 | .channels_max = 2, | ||
777 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
778 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | ||
779 | | SNDRV_PCM_FMTBIT_S24_LE | ||
780 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
781 | }, | ||
782 | .ops = &mt2701_afe_i2s_ops, | ||
783 | .symmetric_rates = 1, | ||
784 | }, | ||
785 | { | ||
786 | .name = "MRG BT", | ||
787 | .id = MT2701_IO_MRG, | ||
788 | .playback = { | ||
789 | .stream_name = "BT Playback", | ||
790 | .channels_min = 1, | ||
791 | .channels_max = 1, | ||
792 | .rates = (SNDRV_PCM_RATE_8000 | ||
793 | | SNDRV_PCM_RATE_16000), | ||
794 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
795 | }, | ||
796 | .capture = { | ||
797 | .stream_name = "BT Capture", | ||
798 | .channels_min = 1, | ||
799 | .channels_max = 1, | ||
800 | .rates = (SNDRV_PCM_RATE_8000 | ||
801 | | SNDRV_PCM_RATE_16000), | ||
802 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
803 | }, | ||
804 | .ops = &mt2701_btmrg_ops, | ||
805 | .symmetric_rates = 1, | ||
806 | } | ||
807 | }; | ||
808 | |||
809 | static const struct snd_kcontrol_new mt2701_afe_o00_mix[] = { | ||
810 | SOC_DAPM_SINGLE_AUTODISABLE("I00 Switch", AFE_CONN0, 0, 1, 0), | ||
811 | }; | ||
812 | |||
813 | static const struct snd_kcontrol_new mt2701_afe_o01_mix[] = { | ||
814 | SOC_DAPM_SINGLE_AUTODISABLE("I01 Switch", AFE_CONN1, 1, 1, 0), | ||
815 | }; | ||
816 | |||
817 | static const struct snd_kcontrol_new mt2701_afe_o02_mix[] = { | ||
818 | SOC_DAPM_SINGLE_AUTODISABLE("I02 Switch", AFE_CONN2, 2, 1, 0), | ||
819 | }; | ||
820 | |||
821 | static const struct snd_kcontrol_new mt2701_afe_o03_mix[] = { | ||
822 | SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 3, 1, 0), | ||
823 | }; | ||
824 | |||
825 | static const struct snd_kcontrol_new mt2701_afe_o14_mix[] = { | ||
826 | SOC_DAPM_SINGLE_AUTODISABLE("I26 Switch", AFE_CONN14, 26, 1, 0), | ||
827 | }; | ||
828 | |||
829 | static const struct snd_kcontrol_new mt2701_afe_o15_mix[] = { | ||
830 | SOC_DAPM_SINGLE_AUTODISABLE("I12 Switch", AFE_CONN15, 12, 1, 0), | ||
831 | }; | ||
832 | |||
833 | static const struct snd_kcontrol_new mt2701_afe_o16_mix[] = { | ||
834 | SOC_DAPM_SINGLE_AUTODISABLE("I13 Switch", AFE_CONN16, 13, 1, 0), | ||
835 | }; | ||
836 | |||
837 | static const struct snd_kcontrol_new mt2701_afe_o17_mix[] = { | ||
838 | SOC_DAPM_SINGLE_AUTODISABLE("I14 Switch", AFE_CONN17, 14, 1, 0), | ||
839 | }; | ||
840 | |||
841 | static const struct snd_kcontrol_new mt2701_afe_o18_mix[] = { | ||
842 | SOC_DAPM_SINGLE_AUTODISABLE("I15 Switch", AFE_CONN18, 15, 1, 0), | ||
843 | }; | ||
844 | |||
845 | static const struct snd_kcontrol_new mt2701_afe_o19_mix[] = { | ||
846 | SOC_DAPM_SINGLE_AUTODISABLE("I16 Switch", AFE_CONN19, 16, 1, 0), | ||
847 | }; | ||
848 | |||
849 | static const struct snd_kcontrol_new mt2701_afe_o20_mix[] = { | ||
850 | SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN20, 17, 1, 0), | ||
851 | }; | ||
852 | |||
853 | static const struct snd_kcontrol_new mt2701_afe_o21_mix[] = { | ||
854 | SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN21, 18, 1, 0), | ||
855 | }; | ||
856 | |||
857 | static const struct snd_kcontrol_new mt2701_afe_o22_mix[] = { | ||
858 | SOC_DAPM_SINGLE_AUTODISABLE("I19 Switch", AFE_CONN22, 19, 1, 0), | ||
859 | }; | ||
860 | |||
861 | static const struct snd_kcontrol_new mt2701_afe_o23_mix[] = { | ||
862 | SOC_DAPM_SINGLE_AUTODISABLE("I20 Switch", AFE_CONN23, 20, 1, 0), | ||
863 | }; | ||
864 | |||
865 | static const struct snd_kcontrol_new mt2701_afe_o24_mix[] = { | ||
866 | SOC_DAPM_SINGLE_AUTODISABLE("I21 Switch", AFE_CONN24, 21, 1, 0), | ||
867 | }; | ||
868 | |||
869 | static const struct snd_kcontrol_new mt2701_afe_o31_mix[] = { | ||
870 | SOC_DAPM_SINGLE_AUTODISABLE("I35 Switch", AFE_CONN41, 9, 1, 0), | ||
871 | }; | ||
872 | |||
873 | static const struct snd_kcontrol_new mt2701_afe_i02_mix[] = { | ||
874 | SOC_DAPM_SINGLE("I2S0 Switch", SND_SOC_NOPM, 0, 1, 0), | ||
875 | }; | ||
876 | |||
877 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s0[] = { | ||
878 | SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S0 Out Switch", | ||
879 | ASYS_I2SO1_CON, 26, 1, 0), | ||
880 | }; | ||
881 | |||
882 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s1[] = { | ||
883 | SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S1 Out Switch", | ||
884 | ASYS_I2SO2_CON, 26, 1, 0), | ||
885 | }; | ||
886 | |||
887 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s2[] = { | ||
888 | SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S2 Out Switch", | ||
889 | PWR2_TOP_CON, 17, 1, 0), | ||
890 | }; | ||
891 | |||
892 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s3[] = { | ||
893 | SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S3 Out Switch", | ||
894 | PWR2_TOP_CON, 18, 1, 0), | ||
895 | }; | ||
896 | |||
897 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_i2s4[] = { | ||
898 | SOC_DAPM_SINGLE_AUTODISABLE("Multich I2S4 Out Switch", | ||
899 | PWR2_TOP_CON, 19, 1, 0), | ||
900 | }; | ||
901 | |||
902 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc0[] = { | ||
903 | SOC_DAPM_SINGLE_AUTODISABLE("Asrc0 out Switch", AUDIO_TOP_CON4, 14, 1, | ||
904 | 1), | ||
905 | }; | ||
906 | |||
907 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc1[] = { | ||
908 | SOC_DAPM_SINGLE_AUTODISABLE("Asrc1 out Switch", AUDIO_TOP_CON4, 15, 1, | ||
909 | 1), | ||
910 | }; | ||
911 | |||
912 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc2[] = { | ||
913 | SOC_DAPM_SINGLE_AUTODISABLE("Asrc2 out Switch", PWR2_TOP_CON, 6, 1, | ||
914 | 1), | ||
915 | }; | ||
916 | |||
917 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc3[] = { | ||
918 | SOC_DAPM_SINGLE_AUTODISABLE("Asrc3 out Switch", PWR2_TOP_CON, 7, 1, | ||
919 | 1), | ||
920 | }; | ||
921 | |||
922 | static const struct snd_kcontrol_new mt2701_afe_multi_ch_out_asrc4[] = { | ||
923 | SOC_DAPM_SINGLE_AUTODISABLE("Asrc4 out Switch", PWR2_TOP_CON, 8, 1, | ||
924 | 1), | ||
925 | }; | ||
926 | |||
927 | static const struct snd_soc_dapm_widget mt2701_afe_pcm_widgets[] = { | ||
928 | /* inter-connections */ | ||
929 | SND_SOC_DAPM_MIXER("I00", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
930 | SND_SOC_DAPM_MIXER("I01", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
931 | SND_SOC_DAPM_MIXER("I02", SND_SOC_NOPM, 0, 0, mt2701_afe_i02_mix, | ||
932 | ARRAY_SIZE(mt2701_afe_i02_mix)), | ||
933 | SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
934 | SND_SOC_DAPM_MIXER("I12", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
935 | SND_SOC_DAPM_MIXER("I13", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
936 | SND_SOC_DAPM_MIXER("I14", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
937 | SND_SOC_DAPM_MIXER("I15", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
938 | SND_SOC_DAPM_MIXER("I16", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
939 | SND_SOC_DAPM_MIXER("I17", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
940 | SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
941 | SND_SOC_DAPM_MIXER("I19", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
942 | SND_SOC_DAPM_MIXER("I26", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
943 | SND_SOC_DAPM_MIXER("I35", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
944 | |||
945 | SND_SOC_DAPM_MIXER("O00", SND_SOC_NOPM, 0, 0, mt2701_afe_o00_mix, | ||
946 | ARRAY_SIZE(mt2701_afe_o00_mix)), | ||
947 | SND_SOC_DAPM_MIXER("O01", SND_SOC_NOPM, 0, 0, mt2701_afe_o01_mix, | ||
948 | ARRAY_SIZE(mt2701_afe_o01_mix)), | ||
949 | SND_SOC_DAPM_MIXER("O02", SND_SOC_NOPM, 0, 0, mt2701_afe_o02_mix, | ||
950 | ARRAY_SIZE(mt2701_afe_o02_mix)), | ||
951 | SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, mt2701_afe_o03_mix, | ||
952 | ARRAY_SIZE(mt2701_afe_o03_mix)), | ||
953 | SND_SOC_DAPM_MIXER("O14", SND_SOC_NOPM, 0, 0, mt2701_afe_o14_mix, | ||
954 | ARRAY_SIZE(mt2701_afe_o14_mix)), | ||
955 | SND_SOC_DAPM_MIXER("O15", SND_SOC_NOPM, 0, 0, mt2701_afe_o15_mix, | ||
956 | ARRAY_SIZE(mt2701_afe_o15_mix)), | ||
957 | SND_SOC_DAPM_MIXER("O16", SND_SOC_NOPM, 0, 0, mt2701_afe_o16_mix, | ||
958 | ARRAY_SIZE(mt2701_afe_o16_mix)), | ||
959 | SND_SOC_DAPM_MIXER("O17", SND_SOC_NOPM, 0, 0, mt2701_afe_o17_mix, | ||
960 | ARRAY_SIZE(mt2701_afe_o17_mix)), | ||
961 | SND_SOC_DAPM_MIXER("O18", SND_SOC_NOPM, 0, 0, mt2701_afe_o18_mix, | ||
962 | ARRAY_SIZE(mt2701_afe_o18_mix)), | ||
963 | SND_SOC_DAPM_MIXER("O19", SND_SOC_NOPM, 0, 0, mt2701_afe_o19_mix, | ||
964 | ARRAY_SIZE(mt2701_afe_o19_mix)), | ||
965 | SND_SOC_DAPM_MIXER("O20", SND_SOC_NOPM, 0, 0, mt2701_afe_o20_mix, | ||
966 | ARRAY_SIZE(mt2701_afe_o20_mix)), | ||
967 | SND_SOC_DAPM_MIXER("O21", SND_SOC_NOPM, 0, 0, mt2701_afe_o21_mix, | ||
968 | ARRAY_SIZE(mt2701_afe_o21_mix)), | ||
969 | SND_SOC_DAPM_MIXER("O22", SND_SOC_NOPM, 0, 0, mt2701_afe_o22_mix, | ||
970 | ARRAY_SIZE(mt2701_afe_o22_mix)), | ||
971 | SND_SOC_DAPM_MIXER("O31", SND_SOC_NOPM, 0, 0, mt2701_afe_o31_mix, | ||
972 | ARRAY_SIZE(mt2701_afe_o31_mix)), | ||
973 | |||
974 | SND_SOC_DAPM_MIXER("I12I13", SND_SOC_NOPM, 0, 0, | ||
975 | mt2701_afe_multi_ch_out_i2s0, | ||
976 | ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s0)), | ||
977 | SND_SOC_DAPM_MIXER("I14I15", SND_SOC_NOPM, 0, 0, | ||
978 | mt2701_afe_multi_ch_out_i2s1, | ||
979 | ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s1)), | ||
980 | SND_SOC_DAPM_MIXER("I16I17", SND_SOC_NOPM, 0, 0, | ||
981 | mt2701_afe_multi_ch_out_i2s2, | ||
982 | ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s2)), | ||
983 | SND_SOC_DAPM_MIXER("I18I19", SND_SOC_NOPM, 0, 0, | ||
984 | mt2701_afe_multi_ch_out_i2s3, | ||
985 | ARRAY_SIZE(mt2701_afe_multi_ch_out_i2s3)), | ||
986 | |||
987 | SND_SOC_DAPM_MIXER("ASRC_O0", SND_SOC_NOPM, 0, 0, | ||
988 | mt2701_afe_multi_ch_out_asrc0, | ||
989 | ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc0)), | ||
990 | SND_SOC_DAPM_MIXER("ASRC_O1", SND_SOC_NOPM, 0, 0, | ||
991 | mt2701_afe_multi_ch_out_asrc1, | ||
992 | ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc1)), | ||
993 | SND_SOC_DAPM_MIXER("ASRC_O2", SND_SOC_NOPM, 0, 0, | ||
994 | mt2701_afe_multi_ch_out_asrc2, | ||
995 | ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc2)), | ||
996 | SND_SOC_DAPM_MIXER("ASRC_O3", SND_SOC_NOPM, 0, 0, | ||
997 | mt2701_afe_multi_ch_out_asrc3, | ||
998 | ARRAY_SIZE(mt2701_afe_multi_ch_out_asrc3)), | ||
999 | }; | ||
1000 | |||
1001 | static const struct snd_soc_dapm_route mt2701_afe_pcm_routes[] = { | ||
1002 | {"I12", NULL, "DL1"}, | ||
1003 | {"I13", NULL, "DL1"}, | ||
1004 | {"I35", NULL, "DLBT"}, | ||
1005 | |||
1006 | {"I2S0 Playback", NULL, "O15"}, | ||
1007 | {"I2S0 Playback", NULL, "O16"}, | ||
1008 | |||
1009 | {"I2S1 Playback", NULL, "O17"}, | ||
1010 | {"I2S1 Playback", NULL, "O18"}, | ||
1011 | {"I2S2 Playback", NULL, "O19"}, | ||
1012 | {"I2S2 Playback", NULL, "O20"}, | ||
1013 | {"I2S3 Playback", NULL, "O21"}, | ||
1014 | {"I2S3 Playback", NULL, "O22"}, | ||
1015 | {"BT Playback", NULL, "O31"}, | ||
1016 | |||
1017 | {"UL1", NULL, "O00"}, | ||
1018 | {"UL1", NULL, "O01"}, | ||
1019 | {"UL2", NULL, "O02"}, | ||
1020 | {"UL2", NULL, "O03"}, | ||
1021 | {"ULBT", NULL, "O14"}, | ||
1022 | |||
1023 | {"I00", NULL, "I2S0 Capture"}, | ||
1024 | {"I01", NULL, "I2S0 Capture"}, | ||
1025 | |||
1026 | {"I02", NULL, "I2S1 Capture"}, | ||
1027 | {"I03", NULL, "I2S1 Capture"}, | ||
1028 | /* I02,03 link to UL2, also need to open I2S0 */ | ||
1029 | {"I02", "I2S0 Switch", "I2S0 Capture"}, | ||
1030 | |||
1031 | {"I26", NULL, "BT Capture"}, | ||
1032 | |||
1033 | {"ASRC_O0", "Asrc0 out Switch", "DLM"}, | ||
1034 | {"ASRC_O1", "Asrc1 out Switch", "DLM"}, | ||
1035 | {"ASRC_O2", "Asrc2 out Switch", "DLM"}, | ||
1036 | {"ASRC_O3", "Asrc3 out Switch", "DLM"}, | ||
1037 | |||
1038 | {"I12I13", "Multich I2S0 Out Switch", "ASRC_O0"}, | ||
1039 | {"I14I15", "Multich I2S1 Out Switch", "ASRC_O1"}, | ||
1040 | {"I16I17", "Multich I2S2 Out Switch", "ASRC_O2"}, | ||
1041 | {"I18I19", "Multich I2S3 Out Switch", "ASRC_O3"}, | ||
1042 | |||
1043 | { "I12", NULL, "I12I13" }, | ||
1044 | { "I13", NULL, "I12I13" }, | ||
1045 | { "I14", NULL, "I14I15" }, | ||
1046 | { "I15", NULL, "I14I15" }, | ||
1047 | { "I16", NULL, "I16I17" }, | ||
1048 | { "I17", NULL, "I16I17" }, | ||
1049 | { "I18", NULL, "I18I19" }, | ||
1050 | { "I19", NULL, "I18I19" }, | ||
1051 | |||
1052 | { "O00", "I00 Switch", "I00" }, | ||
1053 | { "O01", "I01 Switch", "I01" }, | ||
1054 | { "O02", "I02 Switch", "I02" }, | ||
1055 | { "O03", "I03 Switch", "I03" }, | ||
1056 | { "O14", "I26 Switch", "I26" }, | ||
1057 | { "O15", "I12 Switch", "I12" }, | ||
1058 | { "O16", "I13 Switch", "I13" }, | ||
1059 | { "O17", "I14 Switch", "I14" }, | ||
1060 | { "O18", "I15 Switch", "I15" }, | ||
1061 | { "O19", "I16 Switch", "I16" }, | ||
1062 | { "O20", "I17 Switch", "I17" }, | ||
1063 | { "O21", "I18 Switch", "I18" }, | ||
1064 | { "O22", "I19 Switch", "I19" }, | ||
1065 | { "O31", "I35 Switch", "I35" }, | ||
1066 | |||
1067 | }; | ||
1068 | |||
1069 | static const struct snd_soc_component_driver mt2701_afe_pcm_dai_component = { | ||
1070 | .name = "mt2701-afe-pcm-dai", | ||
1071 | .dapm_widgets = mt2701_afe_pcm_widgets, | ||
1072 | .num_dapm_widgets = ARRAY_SIZE(mt2701_afe_pcm_widgets), | ||
1073 | .dapm_routes = mt2701_afe_pcm_routes, | ||
1074 | .num_dapm_routes = ARRAY_SIZE(mt2701_afe_pcm_routes), | ||
1075 | }; | ||
1076 | |||
1077 | static const struct mtk_base_memif_data memif_data[MT2701_MEMIF_NUM] = { | ||
1078 | { | ||
1079 | .name = "DL1", | ||
1080 | .id = MT2701_MEMIF_DL1, | ||
1081 | .reg_ofs_base = AFE_DL1_BASE, | ||
1082 | .reg_ofs_cur = AFE_DL1_CUR, | ||
1083 | .fs_reg = AFE_DAC_CON1, | ||
1084 | .fs_shift = 0, | ||
1085 | .fs_maskbit = 0x1f, | ||
1086 | .mono_reg = AFE_DAC_CON3, | ||
1087 | .mono_shift = 16, | ||
1088 | .enable_reg = AFE_DAC_CON0, | ||
1089 | .enable_shift = 1, | ||
1090 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1091 | .hd_shift = 0, | ||
1092 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1093 | .agent_disable_shift = 6, | ||
1094 | .msb_reg = -1, | ||
1095 | .msb_shift = -1, | ||
1096 | }, | ||
1097 | { | ||
1098 | .name = "DL2", | ||
1099 | .id = MT2701_MEMIF_DL2, | ||
1100 | .reg_ofs_base = AFE_DL2_BASE, | ||
1101 | .reg_ofs_cur = AFE_DL2_CUR, | ||
1102 | .fs_reg = AFE_DAC_CON1, | ||
1103 | .fs_shift = 5, | ||
1104 | .fs_maskbit = 0x1f, | ||
1105 | .mono_reg = AFE_DAC_CON3, | ||
1106 | .mono_shift = 17, | ||
1107 | .enable_reg = AFE_DAC_CON0, | ||
1108 | .enable_shift = 2, | ||
1109 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1110 | .hd_shift = 2, | ||
1111 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1112 | .agent_disable_shift = 7, | ||
1113 | .msb_reg = -1, | ||
1114 | .msb_shift = -1, | ||
1115 | }, | ||
1116 | { | ||
1117 | .name = "DL3", | ||
1118 | .id = MT2701_MEMIF_DL3, | ||
1119 | .reg_ofs_base = AFE_DL3_BASE, | ||
1120 | .reg_ofs_cur = AFE_DL3_CUR, | ||
1121 | .fs_reg = AFE_DAC_CON1, | ||
1122 | .fs_shift = 10, | ||
1123 | .fs_maskbit = 0x1f, | ||
1124 | .mono_reg = AFE_DAC_CON3, | ||
1125 | .mono_shift = 18, | ||
1126 | .enable_reg = AFE_DAC_CON0, | ||
1127 | .enable_shift = 3, | ||
1128 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1129 | .hd_shift = 4, | ||
1130 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1131 | .agent_disable_shift = 8, | ||
1132 | .msb_reg = -1, | ||
1133 | .msb_shift = -1, | ||
1134 | }, | ||
1135 | { | ||
1136 | .name = "DL4", | ||
1137 | .id = MT2701_MEMIF_DL4, | ||
1138 | .reg_ofs_base = AFE_DL4_BASE, | ||
1139 | .reg_ofs_cur = AFE_DL4_CUR, | ||
1140 | .fs_reg = AFE_DAC_CON1, | ||
1141 | .fs_shift = 15, | ||
1142 | .fs_maskbit = 0x1f, | ||
1143 | .mono_reg = AFE_DAC_CON3, | ||
1144 | .mono_shift = 19, | ||
1145 | .enable_reg = AFE_DAC_CON0, | ||
1146 | .enable_shift = 4, | ||
1147 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1148 | .hd_shift = 6, | ||
1149 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1150 | .agent_disable_shift = 9, | ||
1151 | .msb_reg = -1, | ||
1152 | .msb_shift = -1, | ||
1153 | }, | ||
1154 | { | ||
1155 | .name = "DL5", | ||
1156 | .id = MT2701_MEMIF_DL5, | ||
1157 | .reg_ofs_base = AFE_DL5_BASE, | ||
1158 | .reg_ofs_cur = AFE_DL5_CUR, | ||
1159 | .fs_reg = AFE_DAC_CON1, | ||
1160 | .fs_shift = 20, | ||
1161 | .fs_maskbit = 0x1f, | ||
1162 | .mono_reg = AFE_DAC_CON3, | ||
1163 | .mono_shift = 20, | ||
1164 | .enable_reg = AFE_DAC_CON0, | ||
1165 | .enable_shift = 5, | ||
1166 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1167 | .hd_shift = 8, | ||
1168 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1169 | .agent_disable_shift = 10, | ||
1170 | .msb_reg = -1, | ||
1171 | .msb_shift = -1, | ||
1172 | }, | ||
1173 | { | ||
1174 | .name = "DLM", | ||
1175 | .id = MT2701_MEMIF_DLM, | ||
1176 | .reg_ofs_base = AFE_DLMCH_BASE, | ||
1177 | .reg_ofs_cur = AFE_DLMCH_CUR, | ||
1178 | .fs_reg = AFE_DAC_CON1, | ||
1179 | .fs_shift = 0, | ||
1180 | .fs_maskbit = 0x1f, | ||
1181 | .mono_reg = -1, | ||
1182 | .mono_shift = -1, | ||
1183 | .enable_reg = AFE_DAC_CON0, | ||
1184 | .enable_shift = 7, | ||
1185 | .hd_reg = AFE_MEMIF_PBUF_SIZE, | ||
1186 | .hd_shift = 28, | ||
1187 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1188 | .agent_disable_shift = 12, | ||
1189 | .msb_reg = -1, | ||
1190 | .msb_shift = -1, | ||
1191 | }, | ||
1192 | { | ||
1193 | .name = "UL1", | ||
1194 | .id = MT2701_MEMIF_UL1, | ||
1195 | .reg_ofs_base = AFE_VUL_BASE, | ||
1196 | .reg_ofs_cur = AFE_VUL_CUR, | ||
1197 | .fs_reg = AFE_DAC_CON2, | ||
1198 | .fs_shift = 0, | ||
1199 | .fs_maskbit = 0x1f, | ||
1200 | .mono_reg = AFE_DAC_CON4, | ||
1201 | .mono_shift = 0, | ||
1202 | .enable_reg = AFE_DAC_CON0, | ||
1203 | .enable_shift = 10, | ||
1204 | .hd_reg = AFE_MEMIF_HD_CON1, | ||
1205 | .hd_shift = 0, | ||
1206 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1207 | .agent_disable_shift = 0, | ||
1208 | .msb_reg = -1, | ||
1209 | .msb_shift = -1, | ||
1210 | }, | ||
1211 | { | ||
1212 | .name = "UL2", | ||
1213 | .id = MT2701_MEMIF_UL2, | ||
1214 | .reg_ofs_base = AFE_UL2_BASE, | ||
1215 | .reg_ofs_cur = AFE_UL2_CUR, | ||
1216 | .fs_reg = AFE_DAC_CON2, | ||
1217 | .fs_shift = 5, | ||
1218 | .fs_maskbit = 0x1f, | ||
1219 | .mono_reg = AFE_DAC_CON4, | ||
1220 | .mono_shift = 2, | ||
1221 | .enable_reg = AFE_DAC_CON0, | ||
1222 | .enable_shift = 11, | ||
1223 | .hd_reg = AFE_MEMIF_HD_CON1, | ||
1224 | .hd_shift = 2, | ||
1225 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1226 | .agent_disable_shift = 1, | ||
1227 | .msb_reg = -1, | ||
1228 | .msb_shift = -1, | ||
1229 | }, | ||
1230 | { | ||
1231 | .name = "UL3", | ||
1232 | .id = MT2701_MEMIF_UL3, | ||
1233 | .reg_ofs_base = AFE_UL3_BASE, | ||
1234 | .reg_ofs_cur = AFE_UL3_CUR, | ||
1235 | .fs_reg = AFE_DAC_CON2, | ||
1236 | .fs_shift = 10, | ||
1237 | .fs_maskbit = 0x1f, | ||
1238 | .mono_reg = AFE_DAC_CON4, | ||
1239 | .mono_shift = 4, | ||
1240 | .enable_reg = AFE_DAC_CON0, | ||
1241 | .enable_shift = 12, | ||
1242 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1243 | .hd_shift = 0, | ||
1244 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1245 | .agent_disable_shift = 2, | ||
1246 | .msb_reg = -1, | ||
1247 | .msb_shift = -1, | ||
1248 | }, | ||
1249 | { | ||
1250 | .name = "UL4", | ||
1251 | .id = MT2701_MEMIF_UL4, | ||
1252 | .reg_ofs_base = AFE_UL4_BASE, | ||
1253 | .reg_ofs_cur = AFE_UL4_CUR, | ||
1254 | .fs_reg = AFE_DAC_CON2, | ||
1255 | .fs_shift = 15, | ||
1256 | .fs_maskbit = 0x1f, | ||
1257 | .mono_reg = AFE_DAC_CON4, | ||
1258 | .mono_shift = 6, | ||
1259 | .enable_reg = AFE_DAC_CON0, | ||
1260 | .enable_shift = 13, | ||
1261 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1262 | .hd_shift = 6, | ||
1263 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1264 | .agent_disable_shift = 3, | ||
1265 | .msb_reg = -1, | ||
1266 | .msb_shift = -1, | ||
1267 | }, | ||
1268 | { | ||
1269 | .name = "UL5", | ||
1270 | .id = MT2701_MEMIF_UL5, | ||
1271 | .reg_ofs_base = AFE_UL5_BASE, | ||
1272 | .reg_ofs_cur = AFE_UL5_CUR, | ||
1273 | .fs_reg = AFE_DAC_CON2, | ||
1274 | .fs_shift = 20, | ||
1275 | .mono_reg = AFE_DAC_CON4, | ||
1276 | .mono_shift = 8, | ||
1277 | .fs_maskbit = 0x1f, | ||
1278 | .enable_reg = AFE_DAC_CON0, | ||
1279 | .enable_shift = 14, | ||
1280 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1281 | .hd_shift = 8, | ||
1282 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1283 | .agent_disable_shift = 4, | ||
1284 | .msb_reg = -1, | ||
1285 | .msb_shift = -1, | ||
1286 | }, | ||
1287 | { | ||
1288 | .name = "DLBT", | ||
1289 | .id = MT2701_MEMIF_DLBT, | ||
1290 | .reg_ofs_base = AFE_ARB1_BASE, | ||
1291 | .reg_ofs_cur = AFE_ARB1_CUR, | ||
1292 | .fs_reg = AFE_DAC_CON3, | ||
1293 | .fs_shift = 10, | ||
1294 | .fs_maskbit = 0x1f, | ||
1295 | .mono_reg = AFE_DAC_CON3, | ||
1296 | .mono_shift = 22, | ||
1297 | .enable_reg = AFE_DAC_CON0, | ||
1298 | .enable_shift = 8, | ||
1299 | .hd_reg = AFE_MEMIF_HD_CON0, | ||
1300 | .hd_shift = 14, | ||
1301 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1302 | .agent_disable_shift = 13, | ||
1303 | .msb_reg = -1, | ||
1304 | .msb_shift = -1, | ||
1305 | }, | ||
1306 | { | ||
1307 | .name = "ULBT", | ||
1308 | .id = MT2701_MEMIF_ULBT, | ||
1309 | .reg_ofs_base = AFE_DAI_BASE, | ||
1310 | .reg_ofs_cur = AFE_DAI_CUR, | ||
1311 | .fs_reg = AFE_DAC_CON2, | ||
1312 | .fs_shift = 30, | ||
1313 | .fs_maskbit = 0x1, | ||
1314 | .mono_reg = -1, | ||
1315 | .mono_shift = -1, | ||
1316 | .enable_reg = AFE_DAC_CON0, | ||
1317 | .enable_shift = 17, | ||
1318 | .hd_reg = AFE_MEMIF_HD_CON1, | ||
1319 | .hd_shift = 20, | ||
1320 | .agent_disable_reg = AUDIO_TOP_CON5, | ||
1321 | .agent_disable_shift = 16, | ||
1322 | .msb_reg = -1, | ||
1323 | .msb_shift = -1, | ||
1324 | }, | ||
1325 | }; | ||
1326 | |||
1327 | static const struct mtk_base_irq_data irq_data[MT2701_IRQ_ASYS_END] = { | ||
1328 | { | ||
1329 | .id = MT2701_IRQ_ASYS_IRQ1, | ||
1330 | .irq_cnt_reg = ASYS_IRQ1_CON, | ||
1331 | .irq_cnt_shift = 0, | ||
1332 | .irq_cnt_maskbit = 0xffffff, | ||
1333 | .irq_fs_reg = ASYS_IRQ1_CON, | ||
1334 | .irq_fs_shift = 24, | ||
1335 | .irq_fs_maskbit = 0x1f, | ||
1336 | .irq_en_reg = ASYS_IRQ1_CON, | ||
1337 | .irq_en_shift = 31, | ||
1338 | .irq_clr_reg = ASYS_IRQ_CLR, | ||
1339 | .irq_clr_shift = 0, | ||
1340 | }, | ||
1341 | { | ||
1342 | .id = MT2701_IRQ_ASYS_IRQ2, | ||
1343 | .irq_cnt_reg = ASYS_IRQ2_CON, | ||
1344 | .irq_cnt_shift = 0, | ||
1345 | .irq_cnt_maskbit = 0xffffff, | ||
1346 | .irq_fs_reg = ASYS_IRQ2_CON, | ||
1347 | .irq_fs_shift = 24, | ||
1348 | .irq_fs_maskbit = 0x1f, | ||
1349 | .irq_en_reg = ASYS_IRQ2_CON, | ||
1350 | .irq_en_shift = 31, | ||
1351 | .irq_clr_reg = ASYS_IRQ_CLR, | ||
1352 | .irq_clr_shift = 1, | ||
1353 | }, | ||
1354 | { | ||
1355 | .id = MT2701_IRQ_ASYS_IRQ3, | ||
1356 | .irq_cnt_reg = ASYS_IRQ3_CON, | ||
1357 | .irq_cnt_shift = 0, | ||
1358 | .irq_cnt_maskbit = 0xffffff, | ||
1359 | .irq_fs_reg = ASYS_IRQ3_CON, | ||
1360 | .irq_fs_shift = 24, | ||
1361 | .irq_fs_maskbit = 0x1f, | ||
1362 | .irq_en_reg = ASYS_IRQ3_CON, | ||
1363 | .irq_en_shift = 31, | ||
1364 | .irq_clr_reg = ASYS_IRQ_CLR, | ||
1365 | .irq_clr_shift = 2, | ||
1366 | } | ||
1367 | }; | ||
1368 | |||
1369 | static const struct mt2701_i2s_data mt2701_i2s_data[MT2701_I2S_NUM][2] = { | ||
1370 | { | ||
1371 | { | ||
1372 | .i2s_ctrl_reg = ASYS_I2SO1_CON, | ||
1373 | .i2s_pwn_shift = 6, | ||
1374 | .i2s_asrc_fs_shift = 0, | ||
1375 | .i2s_asrc_fs_mask = 0x1f, | ||
1376 | |||
1377 | }, | ||
1378 | { | ||
1379 | .i2s_ctrl_reg = ASYS_I2SIN1_CON, | ||
1380 | .i2s_pwn_shift = 0, | ||
1381 | .i2s_asrc_fs_shift = 0, | ||
1382 | .i2s_asrc_fs_mask = 0x1f, | ||
1383 | |||
1384 | }, | ||
1385 | }, | ||
1386 | { | ||
1387 | { | ||
1388 | .i2s_ctrl_reg = ASYS_I2SO2_CON, | ||
1389 | .i2s_pwn_shift = 7, | ||
1390 | .i2s_asrc_fs_shift = 5, | ||
1391 | .i2s_asrc_fs_mask = 0x1f, | ||
1392 | |||
1393 | }, | ||
1394 | { | ||
1395 | .i2s_ctrl_reg = ASYS_I2SIN2_CON, | ||
1396 | .i2s_pwn_shift = 1, | ||
1397 | .i2s_asrc_fs_shift = 5, | ||
1398 | .i2s_asrc_fs_mask = 0x1f, | ||
1399 | |||
1400 | }, | ||
1401 | }, | ||
1402 | { | ||
1403 | { | ||
1404 | .i2s_ctrl_reg = ASYS_I2SO3_CON, | ||
1405 | .i2s_pwn_shift = 8, | ||
1406 | .i2s_asrc_fs_shift = 10, | ||
1407 | .i2s_asrc_fs_mask = 0x1f, | ||
1408 | |||
1409 | }, | ||
1410 | { | ||
1411 | .i2s_ctrl_reg = ASYS_I2SIN3_CON, | ||
1412 | .i2s_pwn_shift = 2, | ||
1413 | .i2s_asrc_fs_shift = 10, | ||
1414 | .i2s_asrc_fs_mask = 0x1f, | ||
1415 | |||
1416 | }, | ||
1417 | }, | ||
1418 | { | ||
1419 | { | ||
1420 | .i2s_ctrl_reg = ASYS_I2SO4_CON, | ||
1421 | .i2s_pwn_shift = 9, | ||
1422 | .i2s_asrc_fs_shift = 15, | ||
1423 | .i2s_asrc_fs_mask = 0x1f, | ||
1424 | |||
1425 | }, | ||
1426 | { | ||
1427 | .i2s_ctrl_reg = ASYS_I2SIN4_CON, | ||
1428 | .i2s_pwn_shift = 3, | ||
1429 | .i2s_asrc_fs_shift = 15, | ||
1430 | .i2s_asrc_fs_mask = 0x1f, | ||
1431 | |||
1432 | }, | ||
1433 | }, | ||
1434 | }; | ||
1435 | |||
1436 | static const struct regmap_config mt2701_afe_regmap_config = { | ||
1437 | .reg_bits = 32, | ||
1438 | .reg_stride = 4, | ||
1439 | .val_bits = 32, | ||
1440 | .max_register = AFE_END_ADDR, | ||
1441 | .cache_type = REGCACHE_NONE, | ||
1442 | }; | ||
1443 | |||
1444 | static irqreturn_t mt2701_asys_isr(int irq_id, void *dev) | ||
1445 | { | ||
1446 | int id; | ||
1447 | struct mtk_base_afe *afe = dev; | ||
1448 | struct mtk_base_afe_memif *memif; | ||
1449 | struct mtk_base_afe_irq *irq; | ||
1450 | u32 status; | ||
1451 | |||
1452 | regmap_read(afe->regmap, ASYS_IRQ_STATUS, &status); | ||
1453 | regmap_write(afe->regmap, ASYS_IRQ_CLR, status); | ||
1454 | |||
1455 | for (id = 0; id < MT2701_MEMIF_NUM; ++id) { | ||
1456 | memif = &afe->memif[id]; | ||
1457 | if (memif->irq_usage < 0) | ||
1458 | continue; | ||
1459 | irq = &afe->irqs[memif->irq_usage]; | ||
1460 | if (status & 1 << (irq->irq_data->irq_clr_shift)) | ||
1461 | snd_pcm_period_elapsed(memif->substream); | ||
1462 | } | ||
1463 | return IRQ_HANDLED; | ||
1464 | } | ||
1465 | |||
1466 | static int mt2701_afe_runtime_suspend(struct device *dev) | ||
1467 | { | ||
1468 | struct mtk_base_afe *afe = dev_get_drvdata(dev); | ||
1469 | |||
1470 | mt2701_afe_disable_clock(afe); | ||
1471 | return 0; | ||
1472 | } | ||
1473 | |||
1474 | static int mt2701_afe_runtime_resume(struct device *dev) | ||
1475 | { | ||
1476 | struct mtk_base_afe *afe = dev_get_drvdata(dev); | ||
1477 | |||
1478 | return mt2701_afe_enable_clock(afe); | ||
1479 | } | ||
1480 | |||
1481 | static int mt2701_afe_pcm_dev_probe(struct platform_device *pdev) | ||
1482 | { | ||
1483 | int ret, i; | ||
1484 | unsigned int irq_id; | ||
1485 | struct mtk_base_afe *afe; | ||
1486 | struct mt2701_afe_private *afe_priv; | ||
1487 | struct resource *res; | ||
1488 | struct device *dev; | ||
1489 | |||
1490 | ret = 0; | ||
1491 | afe = devm_kzalloc(&pdev->dev, sizeof(*afe), GFP_KERNEL); | ||
1492 | if (!afe) | ||
1493 | return -ENOMEM; | ||
1494 | afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), | ||
1495 | GFP_KERNEL); | ||
1496 | if (!afe->platform_priv) | ||
1497 | return -ENOMEM; | ||
1498 | afe_priv = afe->platform_priv; | ||
1499 | |||
1500 | afe->dev = &pdev->dev; | ||
1501 | dev = afe->dev; | ||
1502 | |||
1503 | irq_id = platform_get_irq(pdev, 0); | ||
1504 | if (!irq_id) { | ||
1505 | dev_err(dev, "%s no irq found\n", dev->of_node->name); | ||
1506 | return -ENXIO; | ||
1507 | } | ||
1508 | ret = devm_request_irq(dev, irq_id, mt2701_asys_isr, | ||
1509 | IRQF_TRIGGER_NONE, "asys-isr", (void *)afe); | ||
1510 | if (ret) { | ||
1511 | dev_err(dev, "could not request_irq for asys-isr\n"); | ||
1512 | return ret; | ||
1513 | } | ||
1514 | |||
1515 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
1516 | |||
1517 | afe->base_addr = devm_ioremap_resource(&pdev->dev, res); | ||
1518 | |||
1519 | if (IS_ERR(afe->base_addr)) | ||
1520 | return PTR_ERR(afe->base_addr); | ||
1521 | |||
1522 | afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, | ||
1523 | &mt2701_afe_regmap_config); | ||
1524 | if (IS_ERR(afe->regmap)) | ||
1525 | return PTR_ERR(afe->regmap); | ||
1526 | |||
1527 | mutex_init(&afe->irq_alloc_lock); | ||
1528 | |||
1529 | /* memif initialize */ | ||
1530 | afe->memif_size = MT2701_MEMIF_NUM; | ||
1531 | afe->memif = devm_kcalloc(dev, afe->memif_size, sizeof(*afe->memif), | ||
1532 | GFP_KERNEL); | ||
1533 | |||
1534 | if (!afe->memif) | ||
1535 | return -ENOMEM; | ||
1536 | |||
1537 | for (i = 0; i < afe->memif_size; i++) { | ||
1538 | afe->memif[i].data = &memif_data[i]; | ||
1539 | afe->memif[i].irq_usage = -1; | ||
1540 | } | ||
1541 | |||
1542 | /* irq initialize */ | ||
1543 | afe->irqs_size = MT2701_IRQ_ASYS_END; | ||
1544 | afe->irqs = devm_kcalloc(dev, afe->irqs_size, sizeof(*afe->irqs), | ||
1545 | GFP_KERNEL); | ||
1546 | |||
1547 | if (!afe->irqs) | ||
1548 | return -ENOMEM; | ||
1549 | |||
1550 | for (i = 0; i < afe->irqs_size; i++) | ||
1551 | afe->irqs[i].irq_data = &irq_data[i]; | ||
1552 | |||
1553 | /* I2S initialize */ | ||
1554 | for (i = 0; i < MT2701_I2S_NUM; i++) { | ||
1555 | afe_priv->i2s_path[i].i2s_data[I2S_OUT] | ||
1556 | = &mt2701_i2s_data[i][I2S_OUT]; | ||
1557 | afe_priv->i2s_path[i].i2s_data[I2S_IN] | ||
1558 | = &mt2701_i2s_data[i][I2S_IN]; | ||
1559 | } | ||
1560 | |||
1561 | afe->mtk_afe_hardware = &mt2701_afe_hardware; | ||
1562 | afe->memif_fs = mt2701_memif_fs; | ||
1563 | afe->irq_fs = mt2701_irq_fs; | ||
1564 | |||
1565 | afe->reg_back_up_list = mt2701_afe_backup_list; | ||
1566 | afe->reg_back_up_list_num = ARRAY_SIZE(mt2701_afe_backup_list); | ||
1567 | afe->runtime_resume = mt2701_afe_runtime_resume; | ||
1568 | afe->runtime_suspend = mt2701_afe_runtime_suspend; | ||
1569 | |||
1570 | /* initial audio related clock */ | ||
1571 | ret = mt2701_init_clock(afe); | ||
1572 | if (ret) { | ||
1573 | dev_err(dev, "init clock error\n"); | ||
1574 | return ret; | ||
1575 | } | ||
1576 | |||
1577 | platform_set_drvdata(pdev, afe); | ||
1578 | pm_runtime_enable(&pdev->dev); | ||
1579 | if (!pm_runtime_enabled(&pdev->dev)) | ||
1580 | goto err_pm_disable; | ||
1581 | |||
1582 | ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); | ||
1583 | if (ret) { | ||
1584 | dev_warn(dev, "err_platform\n"); | ||
1585 | goto err_platform; | ||
1586 | } | ||
1587 | |||
1588 | ret = snd_soc_register_component(&pdev->dev, | ||
1589 | &mt2701_afe_pcm_dai_component, | ||
1590 | mt2701_afe_pcm_dais, | ||
1591 | ARRAY_SIZE(mt2701_afe_pcm_dais)); | ||
1592 | if (ret) { | ||
1593 | dev_warn(dev, "err_dai_component\n"); | ||
1594 | goto err_dai_component; | ||
1595 | } | ||
1596 | |||
1597 | mt2701_afe_runtime_resume(&pdev->dev); | ||
1598 | |||
1599 | return 0; | ||
1600 | |||
1601 | err_dai_component: | ||
1602 | snd_soc_unregister_component(&pdev->dev); | ||
1603 | |||
1604 | err_platform: | ||
1605 | snd_soc_unregister_platform(&pdev->dev); | ||
1606 | |||
1607 | err_pm_disable: | ||
1608 | pm_runtime_disable(&pdev->dev); | ||
1609 | |||
1610 | return ret; | ||
1611 | } | ||
1612 | |||
1613 | static int mt2701_afe_pcm_dev_remove(struct platform_device *pdev) | ||
1614 | { | ||
1615 | struct mtk_base_afe *afe = platform_get_drvdata(pdev); | ||
1616 | |||
1617 | pm_runtime_disable(&pdev->dev); | ||
1618 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
1619 | mt2701_afe_runtime_suspend(&pdev->dev); | ||
1620 | |||
1621 | snd_soc_unregister_component(&pdev->dev); | ||
1622 | snd_soc_unregister_platform(&pdev->dev); | ||
1623 | /* disable afe clock */ | ||
1624 | mt2701_afe_disable_clock(afe); | ||
1625 | return 0; | ||
1626 | } | ||
1627 | |||
1628 | static const struct of_device_id mt2701_afe_pcm_dt_match[] = { | ||
1629 | { .compatible = "mediatek,mt2701-audio", }, | ||
1630 | {}, | ||
1631 | }; | ||
1632 | MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match); | ||
1633 | |||
1634 | static const struct dev_pm_ops mt2701_afe_pm_ops = { | ||
1635 | SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend, | ||
1636 | mt2701_afe_runtime_resume, NULL) | ||
1637 | }; | ||
1638 | |||
1639 | static struct platform_driver mt2701_afe_pcm_driver = { | ||
1640 | .driver = { | ||
1641 | .name = "mt2701-audio", | ||
1642 | .of_match_table = mt2701_afe_pcm_dt_match, | ||
1643 | #ifdef CONFIG_PM | ||
1644 | .pm = &mt2701_afe_pm_ops, | ||
1645 | #endif | ||
1646 | }, | ||
1647 | .probe = mt2701_afe_pcm_dev_probe, | ||
1648 | .remove = mt2701_afe_pcm_dev_remove, | ||
1649 | }; | ||
1650 | |||
1651 | module_platform_driver(mt2701_afe_pcm_driver); | ||
1652 | |||
1653 | MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver for 2701"); | ||
1654 | MODULE_AUTHOR("Garlic Tseng <garlic.tseng@mediatek.com>"); | ||
1655 | MODULE_LICENSE("GPL v2"); | ||
1656 | |||
diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c new file mode 100644 index 000000000000..1e7e8d43fd8a --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c | |||
@@ -0,0 +1,412 @@ | |||
1 | /* | ||
2 | * mt2701-cs42448.c -- MT2701 CS42448 ALSA SoC machine driver | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Ir Lian <ir.lian@mediatek.com> | ||
6 | * Garlic Tseng <garlic.tseng@mediatek.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 and | ||
11 | * only version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <sound/soc.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/pinctrl/consumer.h> | ||
24 | #include <linux/of_gpio.h> | ||
25 | |||
26 | #include "mt2701-afe-common.h" | ||
27 | |||
28 | struct mt2701_cs42448_private { | ||
29 | int i2s1_in_mux; | ||
30 | int i2s1_in_mux_gpio_sel_1; | ||
31 | int i2s1_in_mux_gpio_sel_2; | ||
32 | }; | ||
33 | |||
34 | static const char * const i2sin_mux_switch_text[] = { | ||
35 | "ADC_SDOUT2", | ||
36 | "ADC_SDOUT3", | ||
37 | "I2S_IN_1", | ||
38 | "I2S_IN_2", | ||
39 | }; | ||
40 | |||
41 | static const struct soc_enum i2sin_mux_enum = | ||
42 | SOC_ENUM_SINGLE_EXT(4, i2sin_mux_switch_text); | ||
43 | |||
44 | static int mt2701_cs42448_i2sin1_mux_get(struct snd_kcontrol *kcontrol, | ||
45 | struct snd_ctl_elem_value *ucontrol) | ||
46 | { | ||
47 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | ||
48 | struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card); | ||
49 | |||
50 | ucontrol->value.integer.value[0] = priv->i2s1_in_mux; | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static int mt2701_cs42448_i2sin1_mux_set(struct snd_kcontrol *kcontrol, | ||
55 | struct snd_ctl_elem_value *ucontrol) | ||
56 | { | ||
57 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | ||
58 | struct mt2701_cs42448_private *priv = snd_soc_card_get_drvdata(card); | ||
59 | |||
60 | if (ucontrol->value.integer.value[0] == priv->i2s1_in_mux) | ||
61 | return 0; | ||
62 | |||
63 | switch (ucontrol->value.integer.value[0]) { | ||
64 | case 0: | ||
65 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0); | ||
66 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0); | ||
67 | break; | ||
68 | case 1: | ||
69 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1); | ||
70 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 0); | ||
71 | break; | ||
72 | case 2: | ||
73 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 0); | ||
74 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1); | ||
75 | break; | ||
76 | case 3: | ||
77 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_1, 1); | ||
78 | gpio_set_value(priv->i2s1_in_mux_gpio_sel_2, 1); | ||
79 | break; | ||
80 | default: | ||
81 | dev_warn(card->dev, "%s invalid setting\n", __func__); | ||
82 | } | ||
83 | |||
84 | priv->i2s1_in_mux = ucontrol->value.integer.value[0]; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static const struct snd_soc_dapm_widget | ||
89 | mt2701_cs42448_asoc_card_dapm_widgets[] = { | ||
90 | SND_SOC_DAPM_LINE("Line Out Jack", NULL), | ||
91 | SND_SOC_DAPM_MIC("AMIC", NULL), | ||
92 | SND_SOC_DAPM_LINE("Tuner In", NULL), | ||
93 | SND_SOC_DAPM_LINE("Satellite Tuner In", NULL), | ||
94 | SND_SOC_DAPM_LINE("AUX In", NULL), | ||
95 | }; | ||
96 | |||
97 | static const struct snd_kcontrol_new mt2701_cs42448_controls[] = { | ||
98 | SOC_DAPM_PIN_SWITCH("Line Out Jack"), | ||
99 | SOC_DAPM_PIN_SWITCH("AMIC"), | ||
100 | SOC_DAPM_PIN_SWITCH("Tuner In"), | ||
101 | SOC_DAPM_PIN_SWITCH("Satellite Tuner In"), | ||
102 | SOC_DAPM_PIN_SWITCH("AUX In"), | ||
103 | SOC_ENUM_EXT("I2SIN1_MUX_Switch", i2sin_mux_enum, | ||
104 | mt2701_cs42448_i2sin1_mux_get, | ||
105 | mt2701_cs42448_i2sin1_mux_set), | ||
106 | }; | ||
107 | |||
108 | static const unsigned int mt2701_cs42448_sampling_rates[] = {48000}; | ||
109 | |||
110 | static struct snd_pcm_hw_constraint_list mt2701_cs42448_constraints_rates = { | ||
111 | .count = ARRAY_SIZE(mt2701_cs42448_sampling_rates), | ||
112 | .list = mt2701_cs42448_sampling_rates, | ||
113 | .mask = 0, | ||
114 | }; | ||
115 | |||
116 | static int mt2701_cs42448_fe_ops_startup(struct snd_pcm_substream *substream) | ||
117 | { | ||
118 | int err; | ||
119 | |||
120 | err = snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
121 | SNDRV_PCM_HW_PARAM_RATE, | ||
122 | &mt2701_cs42448_constraints_rates); | ||
123 | if (err < 0) { | ||
124 | dev_err(substream->pcm->card->dev, | ||
125 | "%s snd_pcm_hw_constraint_list failed: 0x%x\n", | ||
126 | __func__, err); | ||
127 | return err; | ||
128 | } | ||
129 | return 0; | ||
130 | } | ||
131 | |||
132 | static struct snd_soc_ops mt2701_cs42448_48k_fe_ops = { | ||
133 | .startup = mt2701_cs42448_fe_ops_startup, | ||
134 | }; | ||
135 | |||
136 | static int mt2701_cs42448_be_ops_hw_params(struct snd_pcm_substream *substream, | ||
137 | struct snd_pcm_hw_params *params) | ||
138 | { | ||
139 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
140 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
141 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
142 | unsigned int mclk_rate; | ||
143 | unsigned int rate = params_rate(params); | ||
144 | unsigned int div_mclk_over_bck = rate > 192000 ? 2 : 4; | ||
145 | unsigned int div_bck_over_lrck = 64; | ||
146 | |||
147 | mclk_rate = rate * div_bck_over_lrck * div_mclk_over_bck; | ||
148 | |||
149 | /* mt2701 mclk */ | ||
150 | snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, SND_SOC_CLOCK_OUT); | ||
151 | |||
152 | /* codec mclk */ | ||
153 | snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, SND_SOC_CLOCK_IN); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static struct snd_soc_ops mt2701_cs42448_be_ops = { | ||
159 | .hw_params = mt2701_cs42448_be_ops_hw_params | ||
160 | }; | ||
161 | |||
162 | enum { | ||
163 | DAI_LINK_FE_MULTI_CH_OUT, | ||
164 | DAI_LINK_FE_PCM0_IN, | ||
165 | DAI_LINK_FE_PCM1_IN, | ||
166 | DAI_LINK_FE_BT_OUT, | ||
167 | DAI_LINK_FE_BT_IN, | ||
168 | DAI_LINK_BE_I2S0, | ||
169 | DAI_LINK_BE_I2S1, | ||
170 | DAI_LINK_BE_I2S2, | ||
171 | DAI_LINK_BE_I2S3, | ||
172 | DAI_LINK_BE_MRG_BT, | ||
173 | }; | ||
174 | |||
175 | static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { | ||
176 | /* FE */ | ||
177 | [DAI_LINK_FE_MULTI_CH_OUT] = { | ||
178 | .name = "mt2701-cs42448-multi-ch-out", | ||
179 | .stream_name = "mt2701-cs42448-multi-ch-out", | ||
180 | .cpu_dai_name = "PCM_multi", | ||
181 | .codec_name = "snd-soc-dummy", | ||
182 | .codec_dai_name = "snd-soc-dummy-dai", | ||
183 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, | ||
184 | SND_SOC_DPCM_TRIGGER_POST}, | ||
185 | .ops = &mt2701_cs42448_48k_fe_ops, | ||
186 | .dynamic = 1, | ||
187 | .dpcm_playback = 1, | ||
188 | }, | ||
189 | [DAI_LINK_FE_PCM0_IN] = { | ||
190 | .name = "mt2701-cs42448-pcm0", | ||
191 | .stream_name = "mt2701-cs42448-pcm0-data-UL", | ||
192 | .cpu_dai_name = "PCM0", | ||
193 | .codec_name = "snd-soc-dummy", | ||
194 | .codec_dai_name = "snd-soc-dummy-dai", | ||
195 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, | ||
196 | SND_SOC_DPCM_TRIGGER_POST}, | ||
197 | .ops = &mt2701_cs42448_48k_fe_ops, | ||
198 | .dynamic = 1, | ||
199 | .dpcm_capture = 1, | ||
200 | }, | ||
201 | [DAI_LINK_FE_PCM1_IN] = { | ||
202 | .name = "mt2701-cs42448-pcm1-data-UL", | ||
203 | .stream_name = "mt2701-cs42448-pcm1-data-UL", | ||
204 | .cpu_dai_name = "PCM1", | ||
205 | .codec_name = "snd-soc-dummy", | ||
206 | .codec_dai_name = "snd-soc-dummy-dai", | ||
207 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, | ||
208 | SND_SOC_DPCM_TRIGGER_POST}, | ||
209 | .ops = &mt2701_cs42448_48k_fe_ops, | ||
210 | .dynamic = 1, | ||
211 | .dpcm_capture = 1, | ||
212 | }, | ||
213 | [DAI_LINK_FE_BT_OUT] = { | ||
214 | .name = "mt2701-cs42448-pcm-BT-out", | ||
215 | .stream_name = "mt2701-cs42448-pcm-BT", | ||
216 | .cpu_dai_name = "PCM_BT_DL", | ||
217 | .codec_name = "snd-soc-dummy", | ||
218 | .codec_dai_name = "snd-soc-dummy-dai", | ||
219 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, | ||
220 | SND_SOC_DPCM_TRIGGER_POST}, | ||
221 | .dynamic = 1, | ||
222 | .dpcm_playback = 1, | ||
223 | }, | ||
224 | [DAI_LINK_FE_BT_IN] = { | ||
225 | .name = "mt2701-cs42448-pcm-BT-in", | ||
226 | .stream_name = "mt2701-cs42448-pcm-BT", | ||
227 | .cpu_dai_name = "PCM_BT_UL", | ||
228 | .codec_name = "snd-soc-dummy", | ||
229 | .codec_dai_name = "snd-soc-dummy-dai", | ||
230 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, | ||
231 | SND_SOC_DPCM_TRIGGER_POST}, | ||
232 | .dynamic = 1, | ||
233 | .dpcm_capture = 1, | ||
234 | }, | ||
235 | /* BE */ | ||
236 | [DAI_LINK_BE_I2S0] = { | ||
237 | .name = "mt2701-cs42448-I2S0", | ||
238 | .cpu_dai_name = "I2S0", | ||
239 | .no_pcm = 1, | ||
240 | .codec_dai_name = "cs42448", | ||
241 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | ||
242 | | SND_SOC_DAIFMT_GATED, | ||
243 | .ops = &mt2701_cs42448_be_ops, | ||
244 | .dpcm_playback = 1, | ||
245 | .dpcm_capture = 1, | ||
246 | }, | ||
247 | [DAI_LINK_BE_I2S1] = { | ||
248 | .name = "mt2701-cs42448-I2S1", | ||
249 | .cpu_dai_name = "I2S1", | ||
250 | .no_pcm = 1, | ||
251 | .codec_dai_name = "cs42448", | ||
252 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | ||
253 | | SND_SOC_DAIFMT_GATED, | ||
254 | .ops = &mt2701_cs42448_be_ops, | ||
255 | .dpcm_playback = 1, | ||
256 | .dpcm_capture = 1, | ||
257 | }, | ||
258 | [DAI_LINK_BE_I2S2] = { | ||
259 | .name = "mt2701-cs42448-I2S2", | ||
260 | .cpu_dai_name = "I2S2", | ||
261 | .no_pcm = 1, | ||
262 | .codec_dai_name = "cs42448", | ||
263 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | ||
264 | | SND_SOC_DAIFMT_GATED, | ||
265 | .ops = &mt2701_cs42448_be_ops, | ||
266 | .dpcm_playback = 1, | ||
267 | .dpcm_capture = 1, | ||
268 | }, | ||
269 | [DAI_LINK_BE_I2S3] = { | ||
270 | .name = "mt2701-cs42448-I2S3", | ||
271 | .cpu_dai_name = "I2S3", | ||
272 | .no_pcm = 1, | ||
273 | .codec_dai_name = "cs42448", | ||
274 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS | ||
275 | | SND_SOC_DAIFMT_GATED, | ||
276 | .ops = &mt2701_cs42448_be_ops, | ||
277 | .dpcm_playback = 1, | ||
278 | .dpcm_capture = 1, | ||
279 | }, | ||
280 | [DAI_LINK_BE_MRG_BT] = { | ||
281 | .name = "mt2701-cs42448-MRG-BT", | ||
282 | .cpu_dai_name = "MRG BT", | ||
283 | .no_pcm = 1, | ||
284 | .codec_dai_name = "bt-sco-pcm-wb", | ||
285 | .dpcm_playback = 1, | ||
286 | .dpcm_capture = 1, | ||
287 | }, | ||
288 | }; | ||
289 | |||
290 | static struct snd_soc_card mt2701_cs42448_soc_card = { | ||
291 | .name = "mt2701-cs42448", | ||
292 | .owner = THIS_MODULE, | ||
293 | .dai_link = mt2701_cs42448_dai_links, | ||
294 | .num_links = ARRAY_SIZE(mt2701_cs42448_dai_links), | ||
295 | .controls = mt2701_cs42448_controls, | ||
296 | .num_controls = ARRAY_SIZE(mt2701_cs42448_controls), | ||
297 | .dapm_widgets = mt2701_cs42448_asoc_card_dapm_widgets, | ||
298 | .num_dapm_widgets = ARRAY_SIZE(mt2701_cs42448_asoc_card_dapm_widgets), | ||
299 | }; | ||
300 | |||
301 | static int mt2701_cs42448_machine_probe(struct platform_device *pdev) | ||
302 | { | ||
303 | struct snd_soc_card *card = &mt2701_cs42448_soc_card; | ||
304 | int ret; | ||
305 | int i; | ||
306 | struct device_node *platform_node, *codec_node, *codec_node_bt_mrg; | ||
307 | struct mt2701_cs42448_private *priv = | ||
308 | devm_kzalloc(&pdev->dev, sizeof(struct mt2701_cs42448_private), | ||
309 | GFP_KERNEL); | ||
310 | struct device *dev = &pdev->dev; | ||
311 | |||
312 | if (!priv) | ||
313 | return -ENOMEM; | ||
314 | |||
315 | platform_node = of_parse_phandle(pdev->dev.of_node, | ||
316 | "mediatek,platform", 0); | ||
317 | if (!platform_node) { | ||
318 | dev_err(&pdev->dev, "Property 'platform' missing or invalid\n"); | ||
319 | return -EINVAL; | ||
320 | } | ||
321 | for (i = 0; i < card->num_links; i++) { | ||
322 | if (mt2701_cs42448_dai_links[i].platform_name) | ||
323 | continue; | ||
324 | mt2701_cs42448_dai_links[i].platform_of_node = platform_node; | ||
325 | } | ||
326 | |||
327 | card->dev = dev; | ||
328 | |||
329 | codec_node = of_parse_phandle(pdev->dev.of_node, | ||
330 | "mediatek,audio-codec", 0); | ||
331 | if (!codec_node) { | ||
332 | dev_err(&pdev->dev, | ||
333 | "Property 'audio-codec' missing or invalid\n"); | ||
334 | return -EINVAL; | ||
335 | } | ||
336 | for (i = 0; i < card->num_links; i++) { | ||
337 | if (mt2701_cs42448_dai_links[i].codec_name) | ||
338 | continue; | ||
339 | mt2701_cs42448_dai_links[i].codec_of_node = codec_node; | ||
340 | } | ||
341 | |||
342 | codec_node_bt_mrg = of_parse_phandle(pdev->dev.of_node, | ||
343 | "mediatek,audio-codec-bt-mrg", 0); | ||
344 | if (!codec_node_bt_mrg) { | ||
345 | dev_err(&pdev->dev, | ||
346 | "Property 'audio-codec-bt-mrg' missing or invalid\n"); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | mt2701_cs42448_dai_links[DAI_LINK_BE_MRG_BT].codec_of_node | ||
350 | = codec_node_bt_mrg; | ||
351 | |||
352 | ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); | ||
353 | if (ret) { | ||
354 | dev_err(&pdev->dev, "failed to parse audio-routing: %d\n", ret); | ||
355 | return ret; | ||
356 | } | ||
357 | |||
358 | priv->i2s1_in_mux_gpio_sel_1 = | ||
359 | of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio1", 0); | ||
360 | if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_1)) { | ||
361 | ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_1, | ||
362 | "i2s1_in_mux_gpio_sel_1"); | ||
363 | if (ret) | ||
364 | dev_warn(&pdev->dev, "%s devm_gpio_request fail %d\n", | ||
365 | __func__, ret); | ||
366 | gpio_direction_output(priv->i2s1_in_mux_gpio_sel_1, 0); | ||
367 | } | ||
368 | |||
369 | priv->i2s1_in_mux_gpio_sel_2 = | ||
370 | of_get_named_gpio(dev->of_node, "i2s1-in-sel-gpio2", 0); | ||
371 | if (gpio_is_valid(priv->i2s1_in_mux_gpio_sel_2)) { | ||
372 | ret = devm_gpio_request(dev, priv->i2s1_in_mux_gpio_sel_2, | ||
373 | "i2s1_in_mux_gpio_sel_2"); | ||
374 | if (ret) | ||
375 | dev_warn(&pdev->dev, "%s devm_gpio_request fail2 %d\n", | ||
376 | __func__, ret); | ||
377 | gpio_direction_output(priv->i2s1_in_mux_gpio_sel_2, 0); | ||
378 | } | ||
379 | snd_soc_card_set_drvdata(card, priv); | ||
380 | |||
381 | ret = devm_snd_soc_register_card(&pdev->dev, card); | ||
382 | |||
383 | if (ret) | ||
384 | dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n", | ||
385 | __func__, ret); | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | #ifdef CONFIG_OF | ||
390 | static const struct of_device_id mt2701_cs42448_machine_dt_match[] = { | ||
391 | {.compatible = "mediatek,mt2701-cs42448-machine",}, | ||
392 | {} | ||
393 | }; | ||
394 | #endif | ||
395 | |||
396 | static struct platform_driver mt2701_cs42448_machine = { | ||
397 | .driver = { | ||
398 | .name = "mt2701-cs42448", | ||
399 | #ifdef CONFIG_OF | ||
400 | .of_match_table = mt2701_cs42448_machine_dt_match, | ||
401 | #endif | ||
402 | }, | ||
403 | .probe = mt2701_cs42448_machine_probe, | ||
404 | }; | ||
405 | |||
406 | module_platform_driver(mt2701_cs42448_machine); | ||
407 | |||
408 | /* Module information */ | ||
409 | MODULE_DESCRIPTION("MT2701 CS42448 ALSA SoC machine driver"); | ||
410 | MODULE_AUTHOR("Ir Lian <ir.lian@mediatek.com>"); | ||
411 | MODULE_LICENSE("GPL v2"); | ||
412 | MODULE_ALIAS("mt2701 cs42448 soc card"); | ||
diff --git a/sound/soc/mediatek/mt2701/mt2701-reg.h b/sound/soc/mediatek/mt2701/mt2701-reg.h new file mode 100644 index 000000000000..bb62b1c55957 --- /dev/null +++ b/sound/soc/mediatek/mt2701/mt2701-reg.h | |||
@@ -0,0 +1,186 @@ | |||
1 | /* | ||
2 | * mt2701-reg.h -- Mediatek 2701 audio driver reg definition | ||
3 | * | ||
4 | * Copyright (c) 2016 MediaTek Inc. | ||
5 | * Author: Garlic Tseng <garlic.tseng@mediatek.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 and | ||
9 | * only version 2 as published by the Free Software Foundation. | ||
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 | #ifndef _MT2701_REG_H_ | ||
18 | #define _MT2701_REG_H_ | ||
19 | |||
20 | #include <linux/delay.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/of_address.h> | ||
24 | #include <linux/pm_runtime.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include "mt2701-afe-common.h" | ||
27 | |||
28 | /***************************************************************************** | ||
29 | * R E G I S T E R D E F I N I T I O N | ||
30 | *****************************************************************************/ | ||
31 | #define AUDIO_TOP_CON0 0x0000 | ||
32 | #define AUDIO_TOP_CON4 0x0010 | ||
33 | #define AUDIO_TOP_CON5 0x0014 | ||
34 | #define AFE_DAIBT_CON0 0x001c | ||
35 | #define AFE_MRGIF_CON 0x003c | ||
36 | #define ASMI_TIMING_CON1 0x0100 | ||
37 | #define ASMO_TIMING_CON1 0x0104 | ||
38 | #define PWR1_ASM_CON1 0x0108 | ||
39 | #define ASYS_TOP_CON 0x0600 | ||
40 | #define ASYS_I2SIN1_CON 0x0604 | ||
41 | #define ASYS_I2SIN2_CON 0x0608 | ||
42 | #define ASYS_I2SIN3_CON 0x060c | ||
43 | #define ASYS_I2SIN4_CON 0x0610 | ||
44 | #define ASYS_I2SIN5_CON 0x0614 | ||
45 | #define ASYS_I2SO1_CON 0x061C | ||
46 | #define ASYS_I2SO2_CON 0x0620 | ||
47 | #define ASYS_I2SO3_CON 0x0624 | ||
48 | #define ASYS_I2SO4_CON 0x0628 | ||
49 | #define ASYS_I2SO5_CON 0x062c | ||
50 | #define PWR2_TOP_CON 0x0634 | ||
51 | #define AFE_CONN0 0x06c0 | ||
52 | #define AFE_CONN1 0x06c4 | ||
53 | #define AFE_CONN2 0x06c8 | ||
54 | #define AFE_CONN3 0x06cc | ||
55 | #define AFE_CONN14 0x06f8 | ||
56 | #define AFE_CONN15 0x06fc | ||
57 | #define AFE_CONN16 0x0700 | ||
58 | #define AFE_CONN17 0x0704 | ||
59 | #define AFE_CONN18 0x0708 | ||
60 | #define AFE_CONN19 0x070c | ||
61 | #define AFE_CONN20 0x0710 | ||
62 | #define AFE_CONN21 0x0714 | ||
63 | #define AFE_CONN22 0x0718 | ||
64 | #define AFE_CONN23 0x071c | ||
65 | #define AFE_CONN24 0x0720 | ||
66 | #define AFE_CONN41 0x0764 | ||
67 | #define ASYS_IRQ1_CON 0x0780 | ||
68 | #define ASYS_IRQ2_CON 0x0784 | ||
69 | #define ASYS_IRQ3_CON 0x0788 | ||
70 | #define ASYS_IRQ_CLR 0x07c0 | ||
71 | #define ASYS_IRQ_STATUS 0x07c4 | ||
72 | #define PWR2_ASM_CON1 0x1070 | ||
73 | #define AFE_DAC_CON0 0x1200 | ||
74 | #define AFE_DAC_CON1 0x1204 | ||
75 | #define AFE_DAC_CON2 0x1208 | ||
76 | #define AFE_DAC_CON3 0x120c | ||
77 | #define AFE_DAC_CON4 0x1210 | ||
78 | #define AFE_MEMIF_HD_CON1 0x121c | ||
79 | #define AFE_MEMIF_PBUF_SIZE 0x1238 | ||
80 | #define AFE_MEMIF_HD_CON0 0x123c | ||
81 | #define AFE_DL1_BASE 0x1240 | ||
82 | #define AFE_DL1_CUR 0x1244 | ||
83 | #define AFE_DL2_BASE 0x1250 | ||
84 | #define AFE_DL2_CUR 0x1254 | ||
85 | #define AFE_DL3_BASE 0x1260 | ||
86 | #define AFE_DL3_CUR 0x1264 | ||
87 | #define AFE_DL4_BASE 0x1270 | ||
88 | #define AFE_DL4_CUR 0x1274 | ||
89 | #define AFE_DL5_BASE 0x1280 | ||
90 | #define AFE_DL5_CUR 0x1284 | ||
91 | #define AFE_DLMCH_BASE 0x12a0 | ||
92 | #define AFE_DLMCH_CUR 0x12a4 | ||
93 | #define AFE_ARB1_BASE 0x12b0 | ||
94 | #define AFE_ARB1_CUR 0x12b4 | ||
95 | #define AFE_VUL_BASE 0x1300 | ||
96 | #define AFE_VUL_CUR 0x130c | ||
97 | #define AFE_UL2_BASE 0x1310 | ||
98 | #define AFE_UL2_END 0x1318 | ||
99 | #define AFE_UL2_CUR 0x131c | ||
100 | #define AFE_UL3_BASE 0x1320 | ||
101 | #define AFE_UL3_END 0x1328 | ||
102 | #define AFE_UL3_CUR 0x132c | ||
103 | #define AFE_UL4_BASE 0x1330 | ||
104 | #define AFE_UL4_END 0x1338 | ||
105 | #define AFE_UL4_CUR 0x133c | ||
106 | #define AFE_UL5_BASE 0x1340 | ||
107 | #define AFE_UL5_END 0x1348 | ||
108 | #define AFE_UL5_CUR 0x134c | ||
109 | #define AFE_DAI_BASE 0x1370 | ||
110 | #define AFE_DAI_CUR 0x137c | ||
111 | |||
112 | /* AUDIO_TOP_CON0 (0x0000) */ | ||
113 | #define AUDIO_TOP_CON0_A1SYS_A2SYS_ON (0x3 << 0) | ||
114 | #define AUDIO_TOP_CON0_PDN_AFE (0x1 << 2) | ||
115 | #define AUDIO_TOP_CON0_PDN_APLL_CK (0x1 << 23) | ||
116 | |||
117 | /* AUDIO_TOP_CON4 (0x0010) */ | ||
118 | #define AUDIO_TOP_CON4_I2SO1_PWN (0x1 << 6) | ||
119 | #define AUDIO_TOP_CON4_PDN_A1SYS (0x1 << 21) | ||
120 | #define AUDIO_TOP_CON4_PDN_A2SYS (0x1 << 22) | ||
121 | #define AUDIO_TOP_CON4_PDN_AFE_CONN (0x1 << 23) | ||
122 | #define AUDIO_TOP_CON4_PDN_MRGIF (0x1 << 25) | ||
123 | |||
124 | /* AFE_DAIBT_CON0 (0x001c) */ | ||
125 | #define AFE_DAIBT_CON0_DAIBT_EN (0x1 << 0) | ||
126 | #define AFE_DAIBT_CON0_BT_FUNC_EN (0x1 << 1) | ||
127 | #define AFE_DAIBT_CON0_BT_FUNC_RDY (0x1 << 3) | ||
128 | #define AFE_DAIBT_CON0_BT_WIDE_MODE_EN (0x1 << 9) | ||
129 | #define AFE_DAIBT_CON0_MRG_USE (0x1 << 12) | ||
130 | |||
131 | /* PWR1_ASM_CON1 (0x0108) */ | ||
132 | #define PWR1_ASM_CON1_INIT_VAL (0x492) | ||
133 | |||
134 | /* AFE_MRGIF_CON (0x003c) */ | ||
135 | #define AFE_MRGIF_CON_MRG_EN (0x1 << 0) | ||
136 | #define AFE_MRGIF_CON_MRG_I2S_EN (0x1 << 16) | ||
137 | #define AFE_MRGIF_CON_I2S_MODE_MASK (0xf << 20) | ||
138 | #define AFE_MRGIF_CON_I2S_MODE_32K (0x4 << 20) | ||
139 | |||
140 | /* ASYS_I2SO1_CON (0x061c) */ | ||
141 | #define ASYS_I2SO1_CON_FS (0x1f << 8) | ||
142 | #define ASYS_I2SO1_CON_FS_SET(x) ((x) << 8) | ||
143 | #define ASYS_I2SO1_CON_MULTI_CH (0x1 << 16) | ||
144 | #define ASYS_I2SO1_CON_SIDEGEN (0x1 << 30) | ||
145 | #define ASYS_I2SO1_CON_I2S_EN (0x1 << 0) | ||
146 | /* 0:EIAJ 1:I2S */ | ||
147 | #define ASYS_I2SO1_CON_I2S_MODE (0x1 << 3) | ||
148 | #define ASYS_I2SO1_CON_WIDE_MODE (0x1 << 1) | ||
149 | #define ASYS_I2SO1_CON_WIDE_MODE_SET(x) ((x) << 1) | ||
150 | |||
151 | /* PWR2_TOP_CON (0x0634) */ | ||
152 | #define PWR2_TOP_CON_INIT_VAL (0xffe1ffff) | ||
153 | |||
154 | /* ASYS_IRQ_CLR (0x07c0) */ | ||
155 | #define ASYS_IRQ_CLR_ALL (0xffffffff) | ||
156 | |||
157 | /* PWR2_ASM_CON1 (0x1070) */ | ||
158 | #define PWR2_ASM_CON1_INIT_VAL (0x492492) | ||
159 | |||
160 | /* AFE_DAC_CON0 (0x1200) */ | ||
161 | #define AFE_DAC_CON0_AFE_ON (0x1 << 0) | ||
162 | |||
163 | /* AFE_MEMIF_PBUF_SIZE (0x1238) */ | ||
164 | #define AFE_MEMIF_PBUF_SIZE_DLM_MASK (0x1 << 29) | ||
165 | #define AFE_MEMIF_PBUF_SIZE_PAIR_INTERLEAVE (0x0 << 29) | ||
166 | #define AFE_MEMIF_PBUF_SIZE_FULL_INTERLEAVE (0x1 << 29) | ||
167 | #define DLMCH_BIT_WIDTH_MASK (0x1 << 28) | ||
168 | #define AFE_MEMIF_PBUF_SIZE_DLM_CH_MASK (0xf << 24) | ||
169 | #define AFE_MEMIF_PBUF_SIZE_DLM_CH(x) ((x) << 24) | ||
170 | #define AFE_MEMIF_PBUF_SIZE_DLM_BYTE_MASK (0x3 << 12) | ||
171 | #define AFE_MEMIF_PBUF_SIZE_DLM_32BYTES (0x1 << 12) | ||
172 | |||
173 | /* I2S in/out register bit control */ | ||
174 | #define ASYS_I2S_CON_FS (0x1f << 8) | ||
175 | #define ASYS_I2S_CON_FS_SET(x) ((x) << 8) | ||
176 | #define ASYS_I2S_CON_RESET (0x1 << 30) | ||
177 | #define ASYS_I2S_CON_I2S_EN (0x1 << 0) | ||
178 | #define ASYS_I2S_CON_I2S_COUPLE_MODE (0x1 << 17) | ||
179 | /* 0:EIAJ 1:I2S */ | ||
180 | #define ASYS_I2S_CON_I2S_MODE (0x1 << 3) | ||
181 | #define ASYS_I2S_CON_WIDE_MODE (0x1 << 1) | ||
182 | #define ASYS_I2S_CON_WIDE_MODE_SET(x) ((x) << 1) | ||
183 | #define ASYS_I2S_IN_PHASE_FIX (0x1 << 31) | ||
184 | |||
185 | #define AFE_END_ADDR 0x15e0 | ||
186 | #endif | ||
diff --git a/sound/soc/mediatek/mt8173/Makefile b/sound/soc/mediatek/mt8173/Makefile new file mode 100644 index 000000000000..0357b27d29f2 --- /dev/null +++ b/sound/soc/mediatek/mt8173/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # MTK Platform Support | ||
2 | obj-$(CONFIG_SND_SOC_MT8173) += mt8173-afe-pcm.o | ||
3 | # Machine support | ||
4 | obj-$(CONFIG_SND_SOC_MT8173_MAX98090) += mt8173-max98090.o | ||
5 | obj-$(CONFIG_SND_SOC_MT8173_RT5650) += mt8173-rt5650.o | ||
6 | obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5514) += mt8173-rt5650-rt5514.o | ||
7 | obj-$(CONFIG_SND_SOC_MT8173_RT5650_RT5676) += mt8173-rt5650-rt5676.o | ||
diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-common.h b/sound/soc/mediatek/mt8173/mt8173-afe-common.h new file mode 100644 index 000000000000..9a4837cc181a --- /dev/null +++ b/sound/soc/mediatek/mt8173/mt8173-afe-common.h | |||
@@ -0,0 +1,73 @@ | |||
1 | /* | ||
2 | * mt8173_afe_common.h -- Mediatek 8173 audio driver common definitions | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * Hidalgo Huang <hidalgo.huang@mediatek.com> | ||
8 | * Ir Lian <ir.lian@mediatek.com> | ||
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 version 2 and | ||
12 | * only version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MT8173_AFE_COMMON_H_ | ||
21 | #define _MT8173_AFE_COMMON_H_ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/regmap.h> | ||
25 | |||
26 | enum { | ||
27 | MT8173_AFE_MEMIF_DL1, | ||
28 | MT8173_AFE_MEMIF_DL2, | ||
29 | MT8173_AFE_MEMIF_VUL, | ||
30 | MT8173_AFE_MEMIF_DAI, | ||
31 | MT8173_AFE_MEMIF_AWB, | ||
32 | MT8173_AFE_MEMIF_MOD_DAI, | ||
33 | MT8173_AFE_MEMIF_HDMI, | ||
34 | MT8173_AFE_MEMIF_NUM, | ||
35 | MT8173_AFE_IO_MOD_PCM1 = MT8173_AFE_MEMIF_NUM, | ||
36 | MT8173_AFE_IO_MOD_PCM2, | ||
37 | MT8173_AFE_IO_PMIC, | ||
38 | MT8173_AFE_IO_I2S, | ||
39 | MT8173_AFE_IO_2ND_I2S, | ||
40 | MT8173_AFE_IO_HW_GAIN1, | ||
41 | MT8173_AFE_IO_HW_GAIN2, | ||
42 | MT8173_AFE_IO_MRG_O, | ||
43 | MT8173_AFE_IO_MRG_I, | ||
44 | MT8173_AFE_IO_DAIBT, | ||
45 | MT8173_AFE_IO_HDMI, | ||
46 | }; | ||
47 | |||
48 | enum { | ||
49 | MT8173_AFE_IRQ_DL1, | ||
50 | MT8173_AFE_IRQ_DL2, | ||
51 | MT8173_AFE_IRQ_VUL, | ||
52 | MT8173_AFE_IRQ_DAI, | ||
53 | MT8173_AFE_IRQ_AWB, | ||
54 | MT8173_AFE_IRQ_MOD_DAI, | ||
55 | MT8173_AFE_IRQ_HDMI, | ||
56 | MT8173_AFE_IRQ_NUM, | ||
57 | }; | ||
58 | |||
59 | enum { | ||
60 | MT8173_CLK_INFRASYS_AUD, | ||
61 | MT8173_CLK_TOP_PDN_AUD, | ||
62 | MT8173_CLK_TOP_PDN_AUD_BUS, | ||
63 | MT8173_CLK_I2S0_M, | ||
64 | MT8173_CLK_I2S1_M, | ||
65 | MT8173_CLK_I2S2_M, | ||
66 | MT8173_CLK_I2S3_M, | ||
67 | MT8173_CLK_I2S3_B, | ||
68 | MT8173_CLK_BCK0, | ||
69 | MT8173_CLK_BCK1, | ||
70 | MT8173_CLK_NUM | ||
71 | }; | ||
72 | |||
73 | #endif | ||
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 2b5df2ef51a3..8a643a35d3d4 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Mediatek ALSA SoC AFE platform driver | 2 | * Mediatek 8173 ALSA SoC AFE platform driver |
3 | * | 3 | * |
4 | * Copyright (c) 2015 MediaTek Inc. | 4 | * Copyright (c) 2015 MediaTek Inc. |
5 | * Author: Koro Chen <koro.chen@mediatek.com> | 5 | * Author: Koro Chen <koro.chen@mediatek.com> |
@@ -24,7 +24,10 @@ | |||
24 | #include <linux/dma-mapping.h> | 24 | #include <linux/dma-mapping.h> |
25 | #include <linux/pm_runtime.h> | 25 | #include <linux/pm_runtime.h> |
26 | #include <sound/soc.h> | 26 | #include <sound/soc.h> |
27 | #include "mtk-afe-common.h" | 27 | #include "mt8173-afe-common.h" |
28 | #include "../common/mtk-base-afe.h" | ||
29 | #include "../common/mtk-afe-platform-driver.h" | ||
30 | #include "../common/mtk-afe-fe-dai.h" | ||
28 | 31 | ||
29 | /***************************************************************************** | 32 | /***************************************************************************** |
30 | * R E G I S T E R D E F I N I T I O N | 33 | * R E G I S T E R D E F I N I T I O N |
@@ -81,7 +84,6 @@ | |||
81 | #define AFE_TDM_CON1 0x0548 | 84 | #define AFE_TDM_CON1 0x0548 |
82 | #define AFE_TDM_CON2 0x054c | 85 | #define AFE_TDM_CON2 0x054c |
83 | 86 | ||
84 | #define AFE_BASE_END_OFFSET 8 | ||
85 | #define AFE_IRQ_STATUS_BITS 0xff | 87 | #define AFE_IRQ_STATUS_BITS 0xff |
86 | 88 | ||
87 | /* AUDIO_TOP_CON0 (0x0000) */ | 89 | /* AUDIO_TOP_CON0 (0x0000) */ |
@@ -135,7 +137,7 @@ enum afe_tdm_ch_start { | |||
135 | AFE_TDM_CH_ZERO, | 137 | AFE_TDM_CH_ZERO, |
136 | }; | 138 | }; |
137 | 139 | ||
138 | static const unsigned int mtk_afe_backup_list[] = { | 140 | static const unsigned int mt8173_afe_backup_list[] = { |
139 | AUDIO_TOP_CON0, | 141 | AUDIO_TOP_CON0, |
140 | AFE_CONN1, | 142 | AFE_CONN1, |
141 | AFE_CONN2, | 143 | AFE_CONN2, |
@@ -152,18 +154,11 @@ static const unsigned int mtk_afe_backup_list[] = { | |||
152 | AFE_DAC_CON0, | 154 | AFE_DAC_CON0, |
153 | }; | 155 | }; |
154 | 156 | ||
155 | struct mtk_afe { | 157 | struct mt8173_afe_private { |
156 | /* address for ioremap audio hardware register */ | 158 | struct clk *clocks[MT8173_CLK_NUM]; |
157 | void __iomem *base_addr; | ||
158 | struct device *dev; | ||
159 | struct regmap *regmap; | ||
160 | struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; | ||
161 | struct clk *clocks[MTK_CLK_NUM]; | ||
162 | unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)]; | ||
163 | bool suspended; | ||
164 | }; | 159 | }; |
165 | 160 | ||
166 | static const struct snd_pcm_hardware mtk_afe_hardware = { | 161 | static const struct snd_pcm_hardware mt8173_afe_hardware = { |
167 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 162 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
168 | SNDRV_PCM_INFO_MMAP_VALID), | 163 | SNDRV_PCM_INFO_MMAP_VALID), |
169 | .buffer_bytes_max = 256 * 1024, | 164 | .buffer_bytes_max = 256 * 1024, |
@@ -174,59 +169,12 @@ static const struct snd_pcm_hardware mtk_afe_hardware = { | |||
174 | .fifo_size = 0, | 169 | .fifo_size = 0, |
175 | }; | 170 | }; |
176 | 171 | ||
177 | static snd_pcm_uframes_t mtk_afe_pcm_pointer | 172 | struct mt8173_afe_rate { |
178 | (struct snd_pcm_substream *substream) | ||
179 | { | ||
180 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
181 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
182 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
183 | unsigned int hw_ptr; | ||
184 | int ret; | ||
185 | |||
186 | ret = regmap_read(afe->regmap, memif->data->reg_ofs_cur, &hw_ptr); | ||
187 | if (ret || hw_ptr == 0) { | ||
188 | dev_err(afe->dev, "%s hw_ptr err\n", __func__); | ||
189 | hw_ptr = memif->phys_buf_addr; | ||
190 | } | ||
191 | |||
192 | return bytes_to_frames(substream->runtime, | ||
193 | hw_ptr - memif->phys_buf_addr); | ||
194 | } | ||
195 | |||
196 | static const struct snd_pcm_ops mtk_afe_pcm_ops = { | ||
197 | .ioctl = snd_pcm_lib_ioctl, | ||
198 | .pointer = mtk_afe_pcm_pointer, | ||
199 | }; | ||
200 | |||
201 | static int mtk_afe_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
202 | { | ||
203 | size_t size; | ||
204 | struct snd_card *card = rtd->card->snd_card; | ||
205 | struct snd_pcm *pcm = rtd->pcm; | ||
206 | |||
207 | size = mtk_afe_hardware.buffer_bytes_max; | ||
208 | |||
209 | return snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
210 | card->dev, size, size); | ||
211 | } | ||
212 | |||
213 | static void mtk_afe_pcm_free(struct snd_pcm *pcm) | ||
214 | { | ||
215 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
216 | } | ||
217 | |||
218 | static const struct snd_soc_platform_driver mtk_afe_pcm_platform = { | ||
219 | .ops = &mtk_afe_pcm_ops, | ||
220 | .pcm_new = mtk_afe_pcm_new, | ||
221 | .pcm_free = mtk_afe_pcm_free, | ||
222 | }; | ||
223 | |||
224 | struct mtk_afe_rate { | ||
225 | unsigned int rate; | 173 | unsigned int rate; |
226 | unsigned int regvalue; | 174 | unsigned int regvalue; |
227 | }; | 175 | }; |
228 | 176 | ||
229 | static const struct mtk_afe_rate mtk_afe_i2s_rates[] = { | 177 | static const struct mt8173_afe_rate mt8173_afe_i2s_rates[] = { |
230 | { .rate = 8000, .regvalue = 0 }, | 178 | { .rate = 8000, .regvalue = 0 }, |
231 | { .rate = 11025, .regvalue = 1 }, | 179 | { .rate = 11025, .regvalue = 1 }, |
232 | { .rate = 12000, .regvalue = 2 }, | 180 | { .rate = 12000, .regvalue = 2 }, |
@@ -242,21 +190,21 @@ static const struct mtk_afe_rate mtk_afe_i2s_rates[] = { | |||
242 | { .rate = 192000, .regvalue = 14 }, | 190 | { .rate = 192000, .regvalue = 14 }, |
243 | }; | 191 | }; |
244 | 192 | ||
245 | static int mtk_afe_i2s_fs(unsigned int sample_rate) | 193 | static int mt8173_afe_i2s_fs(unsigned int sample_rate) |
246 | { | 194 | { |
247 | int i; | 195 | int i; |
248 | 196 | ||
249 | for (i = 0; i < ARRAY_SIZE(mtk_afe_i2s_rates); i++) | 197 | for (i = 0; i < ARRAY_SIZE(mt8173_afe_i2s_rates); i++) |
250 | if (mtk_afe_i2s_rates[i].rate == sample_rate) | 198 | if (mt8173_afe_i2s_rates[i].rate == sample_rate) |
251 | return mtk_afe_i2s_rates[i].regvalue; | 199 | return mt8173_afe_i2s_rates[i].regvalue; |
252 | 200 | ||
253 | return -EINVAL; | 201 | return -EINVAL; |
254 | } | 202 | } |
255 | 203 | ||
256 | static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) | 204 | static int mt8173_afe_set_i2s(struct mtk_base_afe *afe, unsigned int rate) |
257 | { | 205 | { |
258 | unsigned int val; | 206 | unsigned int val; |
259 | int fs = mtk_afe_i2s_fs(rate); | 207 | int fs = mt8173_afe_i2s_fs(rate); |
260 | 208 | ||
261 | if (fs < 0) | 209 | if (fs < 0) |
262 | return -EINVAL; | 210 | return -EINVAL; |
@@ -281,7 +229,7 @@ static int mtk_afe_set_i2s(struct mtk_afe *afe, unsigned int rate) | |||
281 | return 0; | 229 | return 0; |
282 | } | 230 | } |
283 | 231 | ||
284 | static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) | 232 | static void mt8173_afe_set_i2s_enable(struct mtk_base_afe *afe, bool enable) |
285 | { | 233 | { |
286 | unsigned int val; | 234 | unsigned int val; |
287 | 235 | ||
@@ -296,8 +244,8 @@ static void mtk_afe_set_i2s_enable(struct mtk_afe *afe, bool enable) | |||
296 | regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); | 244 | regmap_update_bits(afe->regmap, AFE_I2S_CON1, 0x1, enable); |
297 | } | 245 | } |
298 | 246 | ||
299 | static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, | 247 | static int mt8173_afe_dais_enable_clks(struct mtk_base_afe *afe, |
300 | struct clk *m_ck, struct clk *b_ck) | 248 | struct clk *m_ck, struct clk *b_ck) |
301 | { | 249 | { |
302 | int ret; | 250 | int ret; |
303 | 251 | ||
@@ -319,9 +267,9 @@ static int mtk_afe_dais_enable_clks(struct mtk_afe *afe, | |||
319 | return 0; | 267 | return 0; |
320 | } | 268 | } |
321 | 269 | ||
322 | static int mtk_afe_dais_set_clks(struct mtk_afe *afe, | 270 | static int mt8173_afe_dais_set_clks(struct mtk_base_afe *afe, |
323 | struct clk *m_ck, unsigned int mck_rate, | 271 | struct clk *m_ck, unsigned int mck_rate, |
324 | struct clk *b_ck, unsigned int bck_rate) | 272 | struct clk *b_ck, unsigned int bck_rate) |
325 | { | 273 | { |
326 | int ret; | 274 | int ret; |
327 | 275 | ||
@@ -343,8 +291,8 @@ static int mtk_afe_dais_set_clks(struct mtk_afe *afe, | |||
343 | return 0; | 291 | return 0; |
344 | } | 292 | } |
345 | 293 | ||
346 | static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, | 294 | static void mt8173_afe_dais_disable_clks(struct mtk_base_afe *afe, |
347 | struct clk *m_ck, struct clk *b_ck) | 295 | struct clk *m_ck, struct clk *b_ck) |
348 | { | 296 | { |
349 | if (m_ck) | 297 | if (m_ck) |
350 | clk_disable_unprepare(m_ck); | 298 | clk_disable_unprepare(m_ck); |
@@ -352,102 +300,101 @@ static void mtk_afe_dais_disable_clks(struct mtk_afe *afe, | |||
352 | clk_disable_unprepare(b_ck); | 300 | clk_disable_unprepare(b_ck); |
353 | } | 301 | } |
354 | 302 | ||
355 | static int mtk_afe_i2s_startup(struct snd_pcm_substream *substream, | 303 | static int mt8173_afe_i2s_startup(struct snd_pcm_substream *substream, |
356 | struct snd_soc_dai *dai) | 304 | struct snd_soc_dai *dai) |
357 | { | 305 | { |
358 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 306 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
359 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 307 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
360 | 308 | ||
361 | if (dai->active) | 309 | if (dai->active) |
362 | return 0; | 310 | return 0; |
363 | 311 | ||
364 | mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); | ||
365 | mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); | ||
366 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | 312 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, |
367 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); | 313 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, 0); |
368 | return 0; | 314 | return 0; |
369 | } | 315 | } |
370 | 316 | ||
371 | static void mtk_afe_i2s_shutdown(struct snd_pcm_substream *substream, | 317 | static void mt8173_afe_i2s_shutdown(struct snd_pcm_substream *substream, |
372 | struct snd_soc_dai *dai) | 318 | struct snd_soc_dai *dai) |
373 | { | 319 | { |
374 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 320 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
375 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 321 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
376 | 322 | ||
377 | if (dai->active) | 323 | if (dai->active) |
378 | return; | 324 | return; |
379 | 325 | ||
380 | mtk_afe_set_i2s_enable(afe, false); | 326 | mt8173_afe_set_i2s_enable(afe, false); |
381 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | 327 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, |
382 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, | 328 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M, |
383 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); | 329 | AUD_TCON0_PDN_22M | AUD_TCON0_PDN_24M); |
384 | mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S1_M], NULL); | ||
385 | mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S2_M], NULL); | ||
386 | } | 330 | } |
387 | 331 | ||
388 | static int mtk_afe_i2s_prepare(struct snd_pcm_substream *substream, | 332 | static int mt8173_afe_i2s_prepare(struct snd_pcm_substream *substream, |
389 | struct snd_soc_dai *dai) | 333 | struct snd_soc_dai *dai) |
390 | { | 334 | { |
391 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 335 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
392 | struct snd_pcm_runtime * const runtime = substream->runtime; | 336 | struct snd_pcm_runtime * const runtime = substream->runtime; |
393 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 337 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
338 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
394 | int ret; | 339 | int ret; |
395 | 340 | ||
396 | mtk_afe_dais_set_clks(afe, | 341 | mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S1_M], |
397 | afe->clocks[MTK_CLK_I2S1_M], runtime->rate * 256, | 342 | runtime->rate * 256, NULL, 0); |
398 | NULL, 0); | 343 | mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S2_M], |
399 | mtk_afe_dais_set_clks(afe, | 344 | runtime->rate * 256, NULL, 0); |
400 | afe->clocks[MTK_CLK_I2S2_M], runtime->rate * 256, | ||
401 | NULL, 0); | ||
402 | /* config I2S */ | 345 | /* config I2S */ |
403 | ret = mtk_afe_set_i2s(afe, substream->runtime->rate); | 346 | ret = mt8173_afe_set_i2s(afe, substream->runtime->rate); |
404 | if (ret) | 347 | if (ret) |
405 | return ret; | 348 | return ret; |
406 | 349 | ||
407 | mtk_afe_set_i2s_enable(afe, true); | 350 | mt8173_afe_set_i2s_enable(afe, true); |
408 | 351 | ||
409 | return 0; | 352 | return 0; |
410 | } | 353 | } |
411 | 354 | ||
412 | static int mtk_afe_hdmi_startup(struct snd_pcm_substream *substream, | 355 | static int mt8173_afe_hdmi_startup(struct snd_pcm_substream *substream, |
413 | struct snd_soc_dai *dai) | 356 | struct snd_soc_dai *dai) |
414 | { | 357 | { |
415 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 358 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
416 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 359 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
360 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
417 | 361 | ||
418 | if (dai->active) | 362 | if (dai->active) |
419 | return 0; | 363 | return 0; |
420 | 364 | ||
421 | mtk_afe_dais_enable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], | 365 | mt8173_afe_dais_enable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M], |
422 | afe->clocks[MTK_CLK_I2S3_B]); | 366 | afe_priv->clocks[MT8173_CLK_I2S3_B]); |
423 | return 0; | 367 | return 0; |
424 | } | 368 | } |
425 | 369 | ||
426 | static void mtk_afe_hdmi_shutdown(struct snd_pcm_substream *substream, | 370 | static void mt8173_afe_hdmi_shutdown(struct snd_pcm_substream *substream, |
427 | struct snd_soc_dai *dai) | 371 | struct snd_soc_dai *dai) |
428 | { | 372 | { |
429 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 373 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
430 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 374 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
375 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
431 | 376 | ||
432 | if (dai->active) | 377 | if (dai->active) |
433 | return; | 378 | return; |
434 | 379 | ||
435 | mtk_afe_dais_disable_clks(afe, afe->clocks[MTK_CLK_I2S3_M], | 380 | mt8173_afe_dais_disable_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M], |
436 | afe->clocks[MTK_CLK_I2S3_B]); | 381 | afe_priv->clocks[MT8173_CLK_I2S3_B]); |
437 | } | 382 | } |
438 | 383 | ||
439 | static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, | 384 | static int mt8173_afe_hdmi_prepare(struct snd_pcm_substream *substream, |
440 | struct snd_soc_dai *dai) | 385 | struct snd_soc_dai *dai) |
441 | { | 386 | { |
442 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 387 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
443 | struct snd_pcm_runtime * const runtime = substream->runtime; | 388 | struct snd_pcm_runtime * const runtime = substream->runtime; |
444 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 389 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
390 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
391 | |||
445 | unsigned int val; | 392 | unsigned int val; |
446 | 393 | ||
447 | mtk_afe_dais_set_clks(afe, | 394 | mt8173_afe_dais_set_clks(afe, afe_priv->clocks[MT8173_CLK_I2S3_M], |
448 | afe->clocks[MTK_CLK_I2S3_M], runtime->rate * 128, | 395 | runtime->rate * 128, |
449 | afe->clocks[MTK_CLK_I2S3_B], | 396 | afe_priv->clocks[MT8173_CLK_I2S3_B], |
450 | runtime->rate * runtime->channels * 32); | 397 | runtime->rate * runtime->channels * 32); |
451 | 398 | ||
452 | val = AFE_TDM_CON1_BCK_INV | | 399 | val = AFE_TDM_CON1_BCK_INV | |
453 | AFE_TDM_CON1_LRCK_INV | | 400 | AFE_TDM_CON1_LRCK_INV | |
@@ -498,11 +445,11 @@ static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, | |||
498 | return 0; | 445 | return 0; |
499 | } | 446 | } |
500 | 447 | ||
501 | static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, | 448 | static int mt8173_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, |
502 | struct snd_soc_dai *dai) | 449 | struct snd_soc_dai *dai) |
503 | { | 450 | { |
504 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 451 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
505 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 452 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
506 | 453 | ||
507 | dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name); | 454 | dev_info(afe->dev, "%s cmd=%d %s\n", __func__, cmd, dai->name); |
508 | 455 | ||
@@ -514,10 +461,14 @@ static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
514 | 461 | ||
515 | /* set connections: O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */ | 462 | /* set connections: O30~O37: L/R/LS/RS/C/LFE/CH7/CH8 */ |
516 | regmap_write(afe->regmap, AFE_HDMI_CONN0, | 463 | regmap_write(afe->regmap, AFE_HDMI_CONN0, |
517 | AFE_HDMI_CONN0_O30_I30 | AFE_HDMI_CONN0_O31_I31 | | 464 | AFE_HDMI_CONN0_O30_I30 | |
518 | AFE_HDMI_CONN0_O32_I34 | AFE_HDMI_CONN0_O33_I35 | | 465 | AFE_HDMI_CONN0_O31_I31 | |
519 | AFE_HDMI_CONN0_O34_I32 | AFE_HDMI_CONN0_O35_I33 | | 466 | AFE_HDMI_CONN0_O32_I34 | |
520 | AFE_HDMI_CONN0_O36_I36 | AFE_HDMI_CONN0_O37_I37); | 467 | AFE_HDMI_CONN0_O33_I35 | |
468 | AFE_HDMI_CONN0_O34_I32 | | ||
469 | AFE_HDMI_CONN0_O35_I33 | | ||
470 | AFE_HDMI_CONN0_O36_I36 | | ||
471 | AFE_HDMI_CONN0_O37_I37); | ||
521 | 472 | ||
522 | /* enable Out control */ | 473 | /* enable Out control */ |
523 | regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1); | 474 | regmap_update_bits(afe->regmap, AFE_HDMI_OUT_CON0, 0x1, 0x1); |
@@ -537,284 +488,65 @@ static int mtk_afe_hdmi_trigger(struct snd_pcm_substream *substream, int cmd, | |||
537 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | 488 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, |
538 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, | 489 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF, |
539 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF); | 490 | AUD_TCON0_PDN_HDMI | AUD_TCON0_PDN_SPDF); |
540 | |||
541 | return 0; | 491 | return 0; |
542 | default: | 492 | default: |
543 | return -EINVAL; | 493 | return -EINVAL; |
544 | } | 494 | } |
545 | } | 495 | } |
546 | 496 | ||
547 | static int mtk_afe_dais_startup(struct snd_pcm_substream *substream, | 497 | static int mt8173_memif_fs(struct snd_pcm_substream *substream, |
548 | struct snd_soc_dai *dai) | 498 | unsigned int rate) |
549 | { | ||
550 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
551 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
552 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
553 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
554 | int ret; | ||
555 | |||
556 | memif->substream = substream; | ||
557 | |||
558 | snd_soc_set_runtime_hwparams(substream, &mtk_afe_hardware); | ||
559 | |||
560 | /* | ||
561 | * Capture cannot use ping-pong buffer since hw_ptr at IRQ may be | ||
562 | * smaller than period_size due to AFE's internal buffer. | ||
563 | * This easily leads to overrun when avail_min is period_size. | ||
564 | * One more period can hold the possible unread buffer. | ||
565 | */ | ||
566 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | ||
567 | ret = snd_pcm_hw_constraint_minmax(runtime, | ||
568 | SNDRV_PCM_HW_PARAM_PERIODS, | ||
569 | 3, | ||
570 | mtk_afe_hardware.periods_max); | ||
571 | if (ret < 0) { | ||
572 | dev_err(afe->dev, "hw_constraint_minmax failed\n"); | ||
573 | return ret; | ||
574 | } | ||
575 | } | ||
576 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
577 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
578 | if (ret < 0) | ||
579 | dev_err(afe->dev, "snd_pcm_hw_constraint_integer failed\n"); | ||
580 | return ret; | ||
581 | } | ||
582 | |||
583 | static void mtk_afe_dais_shutdown(struct snd_pcm_substream *substream, | ||
584 | struct snd_soc_dai *dai) | ||
585 | { | 499 | { |
586 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 500 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
587 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | 501 | struct mtk_base_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); |
588 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | 502 | struct mtk_base_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; |
589 | 503 | int fs; | |
590 | memif->substream = NULL; | ||
591 | } | ||
592 | |||
593 | static int mtk_afe_dais_hw_params(struct snd_pcm_substream *substream, | ||
594 | struct snd_pcm_hw_params *params, | ||
595 | struct snd_soc_dai *dai) | ||
596 | { | ||
597 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
598 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
599 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
600 | int msb_at_bit33 = 0; | ||
601 | int ret; | ||
602 | |||
603 | dev_dbg(afe->dev, | ||
604 | "%s period = %u, rate= %u, channels=%u\n", | ||
605 | __func__, params_period_size(params), params_rate(params), | ||
606 | params_channels(params)); | ||
607 | 504 | ||
608 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | 505 | if (memif->data->id == MT8173_AFE_MEMIF_DAI || |
609 | if (ret < 0) | 506 | memif->data->id == MT8173_AFE_MEMIF_MOD_DAI) { |
610 | return ret; | 507 | switch (rate) { |
611 | |||
612 | msb_at_bit33 = upper_32_bits(substream->runtime->dma_addr) ? 1 : 0; | ||
613 | memif->phys_buf_addr = lower_32_bits(substream->runtime->dma_addr); | ||
614 | memif->buffer_size = substream->runtime->dma_bytes; | ||
615 | |||
616 | /* start */ | ||
617 | regmap_write(afe->regmap, | ||
618 | memif->data->reg_ofs_base, memif->phys_buf_addr); | ||
619 | /* end */ | ||
620 | regmap_write(afe->regmap, | ||
621 | memif->data->reg_ofs_base + AFE_BASE_END_OFFSET, | ||
622 | memif->phys_buf_addr + memif->buffer_size - 1); | ||
623 | |||
624 | /* set MSB to 33-bit */ | ||
625 | regmap_update_bits(afe->regmap, AFE_MEMIF_MSB, | ||
626 | 1 << memif->data->msb_shift, | ||
627 | msb_at_bit33 << memif->data->msb_shift); | ||
628 | |||
629 | /* set channel */ | ||
630 | if (memif->data->mono_shift >= 0) { | ||
631 | unsigned int mono = (params_channels(params) == 1) ? 1 : 0; | ||
632 | |||
633 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
634 | 1 << memif->data->mono_shift, | ||
635 | mono << memif->data->mono_shift); | ||
636 | } | ||
637 | |||
638 | /* set rate */ | ||
639 | if (memif->data->fs_shift < 0) | ||
640 | return 0; | ||
641 | if (memif->data->id == MTK_AFE_MEMIF_DAI || | ||
642 | memif->data->id == MTK_AFE_MEMIF_MOD_DAI) { | ||
643 | unsigned int val; | ||
644 | |||
645 | switch (params_rate(params)) { | ||
646 | case 8000: | 508 | case 8000: |
647 | val = 0; | 509 | fs = 0; |
648 | break; | 510 | break; |
649 | case 16000: | 511 | case 16000: |
650 | val = 1; | 512 | fs = 1; |
651 | break; | 513 | break; |
652 | case 32000: | 514 | case 32000: |
653 | val = 2; | 515 | fs = 2; |
654 | break; | 516 | break; |
655 | default: | 517 | default: |
656 | return -EINVAL; | 518 | return -EINVAL; |
657 | } | 519 | } |
658 | |||
659 | if (memif->data->id == MTK_AFE_MEMIF_DAI) | ||
660 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
661 | 0x3 << memif->data->fs_shift, | ||
662 | val << memif->data->fs_shift); | ||
663 | else | ||
664 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
665 | 0x3 << memif->data->fs_shift, | ||
666 | val << memif->data->fs_shift); | ||
667 | |||
668 | } else { | 520 | } else { |
669 | int fs = mtk_afe_i2s_fs(params_rate(params)); | 521 | fs = mt8173_afe_i2s_fs(rate); |
670 | |||
671 | if (fs < 0) | ||
672 | return -EINVAL; | ||
673 | |||
674 | regmap_update_bits(afe->regmap, AFE_DAC_CON1, | ||
675 | 0xf << memif->data->fs_shift, | ||
676 | fs << memif->data->fs_shift); | ||
677 | } | 522 | } |
678 | 523 | return fs; | |
679 | return 0; | ||
680 | } | 524 | } |
681 | 525 | ||
682 | static int mtk_afe_dais_hw_free(struct snd_pcm_substream *substream, | 526 | static int mt8173_irq_fs(struct snd_pcm_substream *substream, unsigned int rate) |
683 | struct snd_soc_dai *dai) | ||
684 | { | 527 | { |
685 | return snd_pcm_lib_free_pages(substream); | 528 | return mt8173_afe_i2s_fs(rate); |
686 | } | 529 | } |
687 | 530 | ||
688 | static int mtk_afe_dais_trigger(struct snd_pcm_substream *substream, int cmd, | ||
689 | struct snd_soc_dai *dai) | ||
690 | { | ||
691 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
692 | struct snd_pcm_runtime * const runtime = substream->runtime; | ||
693 | struct mtk_afe *afe = snd_soc_platform_get_drvdata(rtd->platform); | ||
694 | struct mtk_afe_memif *memif = &afe->memif[rtd->cpu_dai->id]; | ||
695 | unsigned int counter = runtime->period_size; | ||
696 | |||
697 | dev_info(afe->dev, "%s %s cmd=%d\n", __func__, memif->data->name, cmd); | ||
698 | |||
699 | switch (cmd) { | ||
700 | case SNDRV_PCM_TRIGGER_START: | ||
701 | case SNDRV_PCM_TRIGGER_RESUME: | ||
702 | if (memif->data->enable_shift >= 0) | ||
703 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
704 | 1 << memif->data->enable_shift, | ||
705 | 1 << memif->data->enable_shift); | ||
706 | |||
707 | /* set irq counter */ | ||
708 | regmap_update_bits(afe->regmap, | ||
709 | memif->data->irq_reg_cnt, | ||
710 | 0x3ffff << memif->data->irq_cnt_shift, | ||
711 | counter << memif->data->irq_cnt_shift); | ||
712 | |||
713 | /* set irq fs */ | ||
714 | if (memif->data->irq_fs_shift >= 0) { | ||
715 | int fs = mtk_afe_i2s_fs(runtime->rate); | ||
716 | |||
717 | if (fs < 0) | ||
718 | return -EINVAL; | ||
719 | |||
720 | regmap_update_bits(afe->regmap, | ||
721 | AFE_IRQ_MCU_CON, | ||
722 | 0xf << memif->data->irq_fs_shift, | ||
723 | fs << memif->data->irq_fs_shift); | ||
724 | } | ||
725 | /* enable interrupt */ | ||
726 | regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, | ||
727 | 1 << memif->data->irq_en_shift, | ||
728 | 1 << memif->data->irq_en_shift); | ||
729 | |||
730 | return 0; | ||
731 | case SNDRV_PCM_TRIGGER_STOP: | ||
732 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
733 | if (memif->data->enable_shift >= 0) | ||
734 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, | ||
735 | 1 << memif->data->enable_shift, 0); | ||
736 | /* disable interrupt */ | ||
737 | regmap_update_bits(afe->regmap, AFE_IRQ_MCU_CON, | ||
738 | 1 << memif->data->irq_en_shift, | ||
739 | 0 << memif->data->irq_en_shift); | ||
740 | /* and clear pending IRQ */ | ||
741 | regmap_write(afe->regmap, AFE_IRQ_CLR, | ||
742 | 1 << memif->data->irq_clr_shift); | ||
743 | return 0; | ||
744 | default: | ||
745 | return -EINVAL; | ||
746 | } | ||
747 | } | ||
748 | |||
749 | /* FE DAIs */ | ||
750 | static const struct snd_soc_dai_ops mtk_afe_dai_ops = { | ||
751 | .startup = mtk_afe_dais_startup, | ||
752 | .shutdown = mtk_afe_dais_shutdown, | ||
753 | .hw_params = mtk_afe_dais_hw_params, | ||
754 | .hw_free = mtk_afe_dais_hw_free, | ||
755 | .trigger = mtk_afe_dais_trigger, | ||
756 | }; | ||
757 | |||
758 | /* BE DAIs */ | 531 | /* BE DAIs */ |
759 | static const struct snd_soc_dai_ops mtk_afe_i2s_ops = { | 532 | static const struct snd_soc_dai_ops mt8173_afe_i2s_ops = { |
760 | .startup = mtk_afe_i2s_startup, | 533 | .startup = mt8173_afe_i2s_startup, |
761 | .shutdown = mtk_afe_i2s_shutdown, | 534 | .shutdown = mt8173_afe_i2s_shutdown, |
762 | .prepare = mtk_afe_i2s_prepare, | 535 | .prepare = mt8173_afe_i2s_prepare, |
763 | }; | 536 | }; |
764 | 537 | ||
765 | static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = { | 538 | static const struct snd_soc_dai_ops mt8173_afe_hdmi_ops = { |
766 | .startup = mtk_afe_hdmi_startup, | 539 | .startup = mt8173_afe_hdmi_startup, |
767 | .shutdown = mtk_afe_hdmi_shutdown, | 540 | .shutdown = mt8173_afe_hdmi_shutdown, |
768 | .prepare = mtk_afe_hdmi_prepare, | 541 | .prepare = mt8173_afe_hdmi_prepare, |
769 | .trigger = mtk_afe_hdmi_trigger, | 542 | .trigger = mt8173_afe_hdmi_trigger, |
770 | |||
771 | }; | 543 | }; |
772 | 544 | ||
773 | static int mtk_afe_runtime_suspend(struct device *dev); | 545 | static struct snd_soc_dai_driver mt8173_afe_pcm_dais[] = { |
774 | static int mtk_afe_runtime_resume(struct device *dev); | ||
775 | |||
776 | static int mtk_afe_dai_suspend(struct snd_soc_dai *dai) | ||
777 | { | ||
778 | struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); | ||
779 | int i; | ||
780 | |||
781 | dev_dbg(afe->dev, "%s\n", __func__); | ||
782 | if (pm_runtime_status_suspended(afe->dev) || afe->suspended) | ||
783 | return 0; | ||
784 | |||
785 | for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) | ||
786 | regmap_read(afe->regmap, mtk_afe_backup_list[i], | ||
787 | &afe->backup_regs[i]); | ||
788 | |||
789 | afe->suspended = true; | ||
790 | mtk_afe_runtime_suspend(afe->dev); | ||
791 | return 0; | ||
792 | } | ||
793 | |||
794 | static int mtk_afe_dai_resume(struct snd_soc_dai *dai) | ||
795 | { | ||
796 | struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); | ||
797 | int i = 0; | ||
798 | |||
799 | dev_dbg(afe->dev, "%s\n", __func__); | ||
800 | if (pm_runtime_status_suspended(afe->dev) || !afe->suspended) | ||
801 | return 0; | ||
802 | |||
803 | mtk_afe_runtime_resume(afe->dev); | ||
804 | |||
805 | for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) | ||
806 | regmap_write(afe->regmap, mtk_afe_backup_list[i], | ||
807 | afe->backup_regs[i]); | ||
808 | |||
809 | afe->suspended = false; | ||
810 | return 0; | ||
811 | } | ||
812 | |||
813 | static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { | ||
814 | /* FE DAIs: memory intefaces to CPU */ | 546 | /* FE DAIs: memory intefaces to CPU */ |
815 | { | 547 | { |
816 | .name = "DL1", /* downlink 1 */ | 548 | .name = "DL1", /* downlink 1 */ |
817 | .id = MTK_AFE_MEMIF_DL1, | 549 | .id = MT8173_AFE_MEMIF_DL1, |
818 | .suspend = mtk_afe_dai_suspend, | 550 | .suspend = mtk_afe_dai_suspend, |
819 | .resume = mtk_afe_dai_resume, | 551 | .resume = mtk_afe_dai_resume, |
820 | .playback = { | 552 | .playback = { |
@@ -824,10 +556,10 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { | |||
824 | .rates = SNDRV_PCM_RATE_8000_48000, | 556 | .rates = SNDRV_PCM_RATE_8000_48000, |
825 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 557 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
826 | }, | 558 | }, |
827 | .ops = &mtk_afe_dai_ops, | 559 | .ops = &mtk_afe_fe_ops, |
828 | }, { | 560 | }, { |
829 | .name = "VUL", /* voice uplink */ | 561 | .name = "VUL", /* voice uplink */ |
830 | .id = MTK_AFE_MEMIF_VUL, | 562 | .id = MT8173_AFE_MEMIF_VUL, |
831 | .suspend = mtk_afe_dai_suspend, | 563 | .suspend = mtk_afe_dai_suspend, |
832 | .resume = mtk_afe_dai_resume, | 564 | .resume = mtk_afe_dai_resume, |
833 | .capture = { | 565 | .capture = { |
@@ -837,11 +569,11 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { | |||
837 | .rates = SNDRV_PCM_RATE_8000_48000, | 569 | .rates = SNDRV_PCM_RATE_8000_48000, |
838 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 570 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
839 | }, | 571 | }, |
840 | .ops = &mtk_afe_dai_ops, | 572 | .ops = &mtk_afe_fe_ops, |
841 | }, { | 573 | }, { |
842 | /* BE DAIs */ | 574 | /* BE DAIs */ |
843 | .name = "I2S", | 575 | .name = "I2S", |
844 | .id = MTK_AFE_IO_I2S, | 576 | .id = MT8173_AFE_IO_I2S, |
845 | .playback = { | 577 | .playback = { |
846 | .stream_name = "I2S Playback", | 578 | .stream_name = "I2S Playback", |
847 | .channels_min = 1, | 579 | .channels_min = 1, |
@@ -856,16 +588,16 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { | |||
856 | .rates = SNDRV_PCM_RATE_8000_48000, | 588 | .rates = SNDRV_PCM_RATE_8000_48000, |
857 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 589 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
858 | }, | 590 | }, |
859 | .ops = &mtk_afe_i2s_ops, | 591 | .ops = &mt8173_afe_i2s_ops, |
860 | .symmetric_rates = 1, | 592 | .symmetric_rates = 1, |
861 | }, | 593 | }, |
862 | }; | 594 | }; |
863 | 595 | ||
864 | static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { | 596 | static struct snd_soc_dai_driver mt8173_afe_hdmi_dais[] = { |
865 | /* FE DAIs */ | 597 | /* FE DAIs */ |
866 | { | 598 | { |
867 | .name = "HDMI", | 599 | .name = "HDMI", |
868 | .id = MTK_AFE_MEMIF_HDMI, | 600 | .id = MT8173_AFE_MEMIF_HDMI, |
869 | .suspend = mtk_afe_dai_suspend, | 601 | .suspend = mtk_afe_dai_suspend, |
870 | .resume = mtk_afe_dai_resume, | 602 | .resume = mtk_afe_dai_resume, |
871 | .playback = { | 603 | .playback = { |
@@ -878,11 +610,11 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { | |||
878 | SNDRV_PCM_RATE_192000, | 610 | SNDRV_PCM_RATE_192000, |
879 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 611 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
880 | }, | 612 | }, |
881 | .ops = &mtk_afe_dai_ops, | 613 | .ops = &mtk_afe_fe_ops, |
882 | }, { | 614 | }, { |
883 | /* BE DAIs */ | 615 | /* BE DAIs */ |
884 | .name = "HDMIO", | 616 | .name = "HDMIO", |
885 | .id = MTK_AFE_IO_HDMI, | 617 | .id = MT8173_AFE_IO_HDMI, |
886 | .playback = { | 618 | .playback = { |
887 | .stream_name = "HDMIO Playback", | 619 | .stream_name = "HDMIO Playback", |
888 | .channels_min = 2, | 620 | .channels_min = 2, |
@@ -893,29 +625,29 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { | |||
893 | SNDRV_PCM_RATE_192000, | 625 | SNDRV_PCM_RATE_192000, |
894 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 626 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
895 | }, | 627 | }, |
896 | .ops = &mtk_afe_hdmi_ops, | 628 | .ops = &mt8173_afe_hdmi_ops, |
897 | }, | 629 | }, |
898 | }; | 630 | }; |
899 | 631 | ||
900 | static const struct snd_kcontrol_new mtk_afe_o03_mix[] = { | 632 | static const struct snd_kcontrol_new mt8173_afe_o03_mix[] = { |
901 | SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0), | 633 | SOC_DAPM_SINGLE_AUTODISABLE("I05 Switch", AFE_CONN1, 21, 1, 0), |
902 | }; | 634 | }; |
903 | 635 | ||
904 | static const struct snd_kcontrol_new mtk_afe_o04_mix[] = { | 636 | static const struct snd_kcontrol_new mt8173_afe_o04_mix[] = { |
905 | SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0), | 637 | SOC_DAPM_SINGLE_AUTODISABLE("I06 Switch", AFE_CONN2, 6, 1, 0), |
906 | }; | 638 | }; |
907 | 639 | ||
908 | static const struct snd_kcontrol_new mtk_afe_o09_mix[] = { | 640 | static const struct snd_kcontrol_new mt8173_afe_o09_mix[] = { |
909 | SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), | 641 | SOC_DAPM_SINGLE_AUTODISABLE("I03 Switch", AFE_CONN3, 0, 1, 0), |
910 | SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), | 642 | SOC_DAPM_SINGLE_AUTODISABLE("I17 Switch", AFE_CONN7, 30, 1, 0), |
911 | }; | 643 | }; |
912 | 644 | ||
913 | static const struct snd_kcontrol_new mtk_afe_o10_mix[] = { | 645 | static const struct snd_kcontrol_new mt8173_afe_o10_mix[] = { |
914 | SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), | 646 | SOC_DAPM_SINGLE_AUTODISABLE("I04 Switch", AFE_CONN3, 3, 1, 0), |
915 | SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), | 647 | SOC_DAPM_SINGLE_AUTODISABLE("I18 Switch", AFE_CONN8, 0, 1, 0), |
916 | }; | 648 | }; |
917 | 649 | ||
918 | static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { | 650 | static const struct snd_soc_dapm_widget mt8173_afe_pcm_widgets[] = { |
919 | /* inter-connections */ | 651 | /* inter-connections */ |
920 | SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), | 652 | SND_SOC_DAPM_MIXER("I03", SND_SOC_NOPM, 0, 0, NULL, 0), |
921 | SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), | 653 | SND_SOC_DAPM_MIXER("I04", SND_SOC_NOPM, 0, 0, NULL, 0), |
@@ -925,16 +657,16 @@ static const struct snd_soc_dapm_widget mtk_afe_pcm_widgets[] = { | |||
925 | SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), | 657 | SND_SOC_DAPM_MIXER("I18", SND_SOC_NOPM, 0, 0, NULL, 0), |
926 | 658 | ||
927 | SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, | 659 | SND_SOC_DAPM_MIXER("O03", SND_SOC_NOPM, 0, 0, |
928 | mtk_afe_o03_mix, ARRAY_SIZE(mtk_afe_o03_mix)), | 660 | mt8173_afe_o03_mix, ARRAY_SIZE(mt8173_afe_o03_mix)), |
929 | SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, | 661 | SND_SOC_DAPM_MIXER("O04", SND_SOC_NOPM, 0, 0, |
930 | mtk_afe_o04_mix, ARRAY_SIZE(mtk_afe_o04_mix)), | 662 | mt8173_afe_o04_mix, ARRAY_SIZE(mt8173_afe_o04_mix)), |
931 | SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, | 663 | SND_SOC_DAPM_MIXER("O09", SND_SOC_NOPM, 0, 0, |
932 | mtk_afe_o09_mix, ARRAY_SIZE(mtk_afe_o09_mix)), | 664 | mt8173_afe_o09_mix, ARRAY_SIZE(mt8173_afe_o09_mix)), |
933 | SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, | 665 | SND_SOC_DAPM_MIXER("O10", SND_SOC_NOPM, 0, 0, |
934 | mtk_afe_o10_mix, ARRAY_SIZE(mtk_afe_o10_mix)), | 666 | mt8173_afe_o10_mix, ARRAY_SIZE(mt8173_afe_o10_mix)), |
935 | }; | 667 | }; |
936 | 668 | ||
937 | static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { | 669 | static const struct snd_soc_dapm_route mt8173_afe_pcm_routes[] = { |
938 | {"I05", NULL, "DL1"}, | 670 | {"I05", NULL, "DL1"}, |
939 | {"I06", NULL, "DL1"}, | 671 | {"I06", NULL, "DL1"}, |
940 | {"I2S Playback", NULL, "O03"}, | 672 | {"I2S Playback", NULL, "O03"}, |
@@ -953,140 +685,257 @@ static const struct snd_soc_dapm_route mtk_afe_pcm_routes[] = { | |||
953 | { "O10", "I04 Switch", "I04" }, | 685 | { "O10", "I04 Switch", "I04" }, |
954 | }; | 686 | }; |
955 | 687 | ||
956 | static const struct snd_soc_dapm_route mtk_afe_hdmi_routes[] = { | 688 | static const struct snd_soc_dapm_route mt8173_afe_hdmi_routes[] = { |
957 | {"HDMIO Playback", NULL, "HDMI"}, | 689 | {"HDMIO Playback", NULL, "HDMI"}, |
958 | }; | 690 | }; |
959 | 691 | ||
960 | static const struct snd_soc_component_driver mtk_afe_pcm_dai_component = { | 692 | static const struct snd_soc_component_driver mt8173_afe_pcm_dai_component = { |
961 | .name = "mtk-afe-pcm-dai", | 693 | .name = "mt8173-afe-pcm-dai", |
962 | .dapm_widgets = mtk_afe_pcm_widgets, | 694 | .dapm_widgets = mt8173_afe_pcm_widgets, |
963 | .num_dapm_widgets = ARRAY_SIZE(mtk_afe_pcm_widgets), | 695 | .num_dapm_widgets = ARRAY_SIZE(mt8173_afe_pcm_widgets), |
964 | .dapm_routes = mtk_afe_pcm_routes, | 696 | .dapm_routes = mt8173_afe_pcm_routes, |
965 | .num_dapm_routes = ARRAY_SIZE(mtk_afe_pcm_routes), | 697 | .num_dapm_routes = ARRAY_SIZE(mt8173_afe_pcm_routes), |
966 | }; | 698 | }; |
967 | 699 | ||
968 | static const struct snd_soc_component_driver mtk_afe_hdmi_dai_component = { | 700 | static const struct snd_soc_component_driver mt8173_afe_hdmi_dai_component = { |
969 | .name = "mtk-afe-hdmi-dai", | 701 | .name = "mt8173-afe-hdmi-dai", |
970 | .dapm_routes = mtk_afe_hdmi_routes, | 702 | .dapm_routes = mt8173_afe_hdmi_routes, |
971 | .num_dapm_routes = ARRAY_SIZE(mtk_afe_hdmi_routes), | 703 | .num_dapm_routes = ARRAY_SIZE(mt8173_afe_hdmi_routes), |
972 | }; | 704 | }; |
973 | 705 | ||
974 | static const char *aud_clks[MTK_CLK_NUM] = { | 706 | static const char *aud_clks[MT8173_CLK_NUM] = { |
975 | [MTK_CLK_INFRASYS_AUD] = "infra_sys_audio_clk", | 707 | [MT8173_CLK_INFRASYS_AUD] = "infra_sys_audio_clk", |
976 | [MTK_CLK_TOP_PDN_AUD] = "top_pdn_audio", | 708 | [MT8173_CLK_TOP_PDN_AUD] = "top_pdn_audio", |
977 | [MTK_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus", | 709 | [MT8173_CLK_TOP_PDN_AUD_BUS] = "top_pdn_aud_intbus", |
978 | [MTK_CLK_I2S0_M] = "i2s0_m", | 710 | [MT8173_CLK_I2S0_M] = "i2s0_m", |
979 | [MTK_CLK_I2S1_M] = "i2s1_m", | 711 | [MT8173_CLK_I2S1_M] = "i2s1_m", |
980 | [MTK_CLK_I2S2_M] = "i2s2_m", | 712 | [MT8173_CLK_I2S2_M] = "i2s2_m", |
981 | [MTK_CLK_I2S3_M] = "i2s3_m", | 713 | [MT8173_CLK_I2S3_M] = "i2s3_m", |
982 | [MTK_CLK_I2S3_B] = "i2s3_b", | 714 | [MT8173_CLK_I2S3_B] = "i2s3_b", |
983 | [MTK_CLK_BCK0] = "bck0", | 715 | [MT8173_CLK_BCK0] = "bck0", |
984 | [MTK_CLK_BCK1] = "bck1", | 716 | [MT8173_CLK_BCK1] = "bck1", |
985 | }; | 717 | }; |
986 | 718 | ||
987 | static const struct mtk_afe_memif_data memif_data[MTK_AFE_MEMIF_NUM] = { | 719 | static const struct mtk_base_memif_data memif_data[MT8173_AFE_MEMIF_NUM] = { |
988 | { | 720 | { |
989 | .name = "DL1", | 721 | .name = "DL1", |
990 | .id = MTK_AFE_MEMIF_DL1, | 722 | .id = MT8173_AFE_MEMIF_DL1, |
991 | .reg_ofs_base = AFE_DL1_BASE, | 723 | .reg_ofs_base = AFE_DL1_BASE, |
992 | .reg_ofs_cur = AFE_DL1_CUR, | 724 | .reg_ofs_cur = AFE_DL1_CUR, |
725 | .fs_reg = AFE_DAC_CON1, | ||
993 | .fs_shift = 0, | 726 | .fs_shift = 0, |
727 | .fs_maskbit = 0xf, | ||
728 | .mono_reg = AFE_DAC_CON1, | ||
994 | .mono_shift = 21, | 729 | .mono_shift = 21, |
730 | .hd_reg = -1, | ||
731 | .hd_shift = -1, | ||
732 | .enable_reg = AFE_DAC_CON0, | ||
995 | .enable_shift = 1, | 733 | .enable_shift = 1, |
996 | .irq_reg_cnt = AFE_IRQ_CNT1, | 734 | .msb_reg = AFE_MEMIF_MSB, |
997 | .irq_cnt_shift = 0, | ||
998 | .irq_en_shift = 0, | ||
999 | .irq_fs_shift = 4, | ||
1000 | .irq_clr_shift = 0, | ||
1001 | .msb_shift = 0, | 735 | .msb_shift = 0, |
736 | .agent_disable_reg = -1, | ||
737 | .agent_disable_shift = -1, | ||
1002 | }, { | 738 | }, { |
1003 | .name = "DL2", | 739 | .name = "DL2", |
1004 | .id = MTK_AFE_MEMIF_DL2, | 740 | .id = MT8173_AFE_MEMIF_DL2, |
1005 | .reg_ofs_base = AFE_DL2_BASE, | 741 | .reg_ofs_base = AFE_DL2_BASE, |
1006 | .reg_ofs_cur = AFE_DL2_CUR, | 742 | .reg_ofs_cur = AFE_DL2_CUR, |
743 | .fs_reg = AFE_DAC_CON1, | ||
1007 | .fs_shift = 4, | 744 | .fs_shift = 4, |
745 | .fs_maskbit = 0xf, | ||
746 | .mono_reg = AFE_DAC_CON1, | ||
1008 | .mono_shift = 22, | 747 | .mono_shift = 22, |
748 | .hd_reg = -1, | ||
749 | .hd_shift = -1, | ||
750 | .enable_reg = AFE_DAC_CON0, | ||
1009 | .enable_shift = 2, | 751 | .enable_shift = 2, |
1010 | .irq_reg_cnt = AFE_IRQ_CNT1, | 752 | .msb_reg = AFE_MEMIF_MSB, |
1011 | .irq_cnt_shift = 20, | ||
1012 | .irq_en_shift = 2, | ||
1013 | .irq_fs_shift = 16, | ||
1014 | .irq_clr_shift = 2, | ||
1015 | .msb_shift = 1, | 753 | .msb_shift = 1, |
754 | .agent_disable_reg = -1, | ||
755 | .agent_disable_shift = -1, | ||
1016 | }, { | 756 | }, { |
1017 | .name = "VUL", | 757 | .name = "VUL", |
1018 | .id = MTK_AFE_MEMIF_VUL, | 758 | .id = MT8173_AFE_MEMIF_VUL, |
1019 | .reg_ofs_base = AFE_VUL_BASE, | 759 | .reg_ofs_base = AFE_VUL_BASE, |
1020 | .reg_ofs_cur = AFE_VUL_CUR, | 760 | .reg_ofs_cur = AFE_VUL_CUR, |
761 | .fs_reg = AFE_DAC_CON1, | ||
1021 | .fs_shift = 16, | 762 | .fs_shift = 16, |
763 | .fs_maskbit = 0xf, | ||
764 | .mono_reg = AFE_DAC_CON1, | ||
1022 | .mono_shift = 27, | 765 | .mono_shift = 27, |
766 | .hd_reg = -1, | ||
767 | .hd_shift = -1, | ||
768 | .enable_reg = AFE_DAC_CON0, | ||
1023 | .enable_shift = 3, | 769 | .enable_shift = 3, |
1024 | .irq_reg_cnt = AFE_IRQ_CNT2, | 770 | .msb_reg = AFE_MEMIF_MSB, |
1025 | .irq_cnt_shift = 0, | ||
1026 | .irq_en_shift = 1, | ||
1027 | .irq_fs_shift = 8, | ||
1028 | .irq_clr_shift = 1, | ||
1029 | .msb_shift = 6, | 771 | .msb_shift = 6, |
772 | .agent_disable_reg = -1, | ||
773 | .agent_disable_shift = -1, | ||
1030 | }, { | 774 | }, { |
1031 | .name = "DAI", | 775 | .name = "DAI", |
1032 | .id = MTK_AFE_MEMIF_DAI, | 776 | .id = MT8173_AFE_MEMIF_DAI, |
1033 | .reg_ofs_base = AFE_DAI_BASE, | 777 | .reg_ofs_base = AFE_DAI_BASE, |
1034 | .reg_ofs_cur = AFE_DAI_CUR, | 778 | .reg_ofs_cur = AFE_DAI_CUR, |
779 | .fs_reg = AFE_DAC_CON0, | ||
1035 | .fs_shift = 24, | 780 | .fs_shift = 24, |
781 | .fs_maskbit = 0x3, | ||
782 | .mono_reg = -1, | ||
1036 | .mono_shift = -1, | 783 | .mono_shift = -1, |
784 | .hd_reg = -1, | ||
785 | .hd_shift = -1, | ||
786 | .enable_reg = AFE_DAC_CON0, | ||
1037 | .enable_shift = 4, | 787 | .enable_shift = 4, |
1038 | .irq_reg_cnt = AFE_IRQ_CNT2, | 788 | .msb_reg = AFE_MEMIF_MSB, |
1039 | .irq_cnt_shift = 20, | ||
1040 | .irq_en_shift = 3, | ||
1041 | .irq_fs_shift = 20, | ||
1042 | .irq_clr_shift = 3, | ||
1043 | .msb_shift = 5, | 789 | .msb_shift = 5, |
790 | .agent_disable_reg = -1, | ||
791 | .agent_disable_shift = -1, | ||
1044 | }, { | 792 | }, { |
1045 | .name = "AWB", | 793 | .name = "AWB", |
1046 | .id = MTK_AFE_MEMIF_AWB, | 794 | .id = MT8173_AFE_MEMIF_AWB, |
1047 | .reg_ofs_base = AFE_AWB_BASE, | 795 | .reg_ofs_base = AFE_AWB_BASE, |
1048 | .reg_ofs_cur = AFE_AWB_CUR, | 796 | .reg_ofs_cur = AFE_AWB_CUR, |
797 | .fs_reg = AFE_DAC_CON1, | ||
1049 | .fs_shift = 12, | 798 | .fs_shift = 12, |
799 | .fs_maskbit = 0xf, | ||
800 | .mono_reg = AFE_DAC_CON1, | ||
1050 | .mono_shift = 24, | 801 | .mono_shift = 24, |
802 | .hd_reg = -1, | ||
803 | .hd_shift = -1, | ||
804 | .enable_reg = AFE_DAC_CON0, | ||
1051 | .enable_shift = 6, | 805 | .enable_shift = 6, |
1052 | .irq_reg_cnt = AFE_IRQ_CNT7, | 806 | .msb_reg = AFE_MEMIF_MSB, |
1053 | .irq_cnt_shift = 0, | ||
1054 | .irq_en_shift = 14, | ||
1055 | .irq_fs_shift = 24, | ||
1056 | .irq_clr_shift = 6, | ||
1057 | .msb_shift = 3, | 807 | .msb_shift = 3, |
808 | .agent_disable_reg = -1, | ||
809 | .agent_disable_shift = -1, | ||
1058 | }, { | 810 | }, { |
1059 | .name = "MOD_DAI", | 811 | .name = "MOD_DAI", |
1060 | .id = MTK_AFE_MEMIF_MOD_DAI, | 812 | .id = MT8173_AFE_MEMIF_MOD_DAI, |
1061 | .reg_ofs_base = AFE_MOD_PCM_BASE, | 813 | .reg_ofs_base = AFE_MOD_PCM_BASE, |
1062 | .reg_ofs_cur = AFE_MOD_PCM_CUR, | 814 | .reg_ofs_cur = AFE_MOD_PCM_CUR, |
815 | .fs_reg = AFE_DAC_CON1, | ||
1063 | .fs_shift = 30, | 816 | .fs_shift = 30, |
817 | .fs_maskbit = 0x3, | ||
818 | .mono_reg = AFE_DAC_CON1, | ||
1064 | .mono_shift = 30, | 819 | .mono_shift = 30, |
820 | .hd_reg = -1, | ||
821 | .hd_shift = -1, | ||
822 | .enable_reg = AFE_DAC_CON0, | ||
1065 | .enable_shift = 7, | 823 | .enable_shift = 7, |
1066 | .irq_reg_cnt = AFE_IRQ_CNT2, | 824 | .msb_reg = AFE_MEMIF_MSB, |
1067 | .irq_cnt_shift = 20, | ||
1068 | .irq_en_shift = 3, | ||
1069 | .irq_fs_shift = 20, | ||
1070 | .irq_clr_shift = 3, | ||
1071 | .msb_shift = 4, | 825 | .msb_shift = 4, |
826 | .agent_disable_reg = -1, | ||
827 | .agent_disable_shift = -1, | ||
1072 | }, { | 828 | }, { |
1073 | .name = "HDMI", | 829 | .name = "HDMI", |
1074 | .id = MTK_AFE_MEMIF_HDMI, | 830 | .id = MT8173_AFE_MEMIF_HDMI, |
1075 | .reg_ofs_base = AFE_HDMI_OUT_BASE, | 831 | .reg_ofs_base = AFE_HDMI_OUT_BASE, |
1076 | .reg_ofs_cur = AFE_HDMI_OUT_CUR, | 832 | .reg_ofs_cur = AFE_HDMI_OUT_CUR, |
833 | .fs_reg = -1, | ||
1077 | .fs_shift = -1, | 834 | .fs_shift = -1, |
835 | .fs_maskbit = -1, | ||
836 | .mono_reg = -1, | ||
1078 | .mono_shift = -1, | 837 | .mono_shift = -1, |
838 | .hd_reg = -1, | ||
839 | .hd_shift = -1, | ||
840 | .enable_reg = -1, | ||
1079 | .enable_shift = -1, | 841 | .enable_shift = -1, |
1080 | .irq_reg_cnt = AFE_IRQ_CNT5, | 842 | .msb_reg = AFE_MEMIF_MSB, |
843 | .msb_shift = 8, | ||
844 | .agent_disable_reg = -1, | ||
845 | .agent_disable_shift = -1, | ||
846 | }, | ||
847 | }; | ||
848 | |||
849 | static const struct mtk_base_irq_data irq_data[MT8173_AFE_IRQ_NUM] = { | ||
850 | { | ||
851 | .id = MT8173_AFE_IRQ_DL1, | ||
852 | .irq_cnt_reg = AFE_IRQ_CNT1, | ||
853 | .irq_cnt_shift = 0, | ||
854 | .irq_cnt_maskbit = 0x3ffff, | ||
855 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
856 | .irq_en_shift = 0, | ||
857 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
858 | .irq_fs_shift = 4, | ||
859 | .irq_fs_maskbit = 0xf, | ||
860 | .irq_clr_reg = AFE_IRQ_CLR, | ||
861 | .irq_clr_shift = 0, | ||
862 | }, { | ||
863 | .id = MT8173_AFE_IRQ_DL2, | ||
864 | .irq_cnt_reg = AFE_IRQ_CNT1, | ||
865 | .irq_cnt_shift = 20, | ||
866 | .irq_cnt_maskbit = 0x3ffff, | ||
867 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
868 | .irq_en_shift = 2, | ||
869 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
870 | .irq_fs_shift = 16, | ||
871 | .irq_fs_maskbit = 0xf, | ||
872 | .irq_clr_reg = AFE_IRQ_CLR, | ||
873 | .irq_clr_shift = 2, | ||
874 | |||
875 | }, { | ||
876 | .id = MT8173_AFE_IRQ_VUL, | ||
877 | .irq_cnt_reg = AFE_IRQ_CNT2, | ||
878 | .irq_cnt_shift = 0, | ||
879 | .irq_cnt_maskbit = 0x3ffff, | ||
880 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
881 | .irq_en_shift = 1, | ||
882 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
883 | .irq_fs_shift = 8, | ||
884 | .irq_fs_maskbit = 0xf, | ||
885 | .irq_clr_reg = AFE_IRQ_CLR, | ||
886 | .irq_clr_shift = 1, | ||
887 | }, { | ||
888 | .id = MT8173_AFE_IRQ_DAI, | ||
889 | .irq_cnt_reg = AFE_IRQ_CNT2, | ||
890 | .irq_cnt_shift = 20, | ||
891 | .irq_cnt_maskbit = 0x3ffff, | ||
892 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
893 | .irq_en_shift = 3, | ||
894 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
895 | .irq_fs_shift = 20, | ||
896 | .irq_fs_maskbit = 0xf, | ||
897 | .irq_clr_reg = AFE_IRQ_CLR, | ||
898 | .irq_clr_shift = 3, | ||
899 | }, { | ||
900 | .id = MT8173_AFE_IRQ_AWB, | ||
901 | .irq_cnt_reg = AFE_IRQ_CNT7, | ||
1081 | .irq_cnt_shift = 0, | 902 | .irq_cnt_shift = 0, |
903 | .irq_cnt_maskbit = 0x3ffff, | ||
904 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
905 | .irq_en_shift = 14, | ||
906 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
907 | .irq_fs_shift = 24, | ||
908 | .irq_fs_maskbit = 0xf, | ||
909 | .irq_clr_reg = AFE_IRQ_CLR, | ||
910 | .irq_clr_shift = 6, | ||
911 | }, { | ||
912 | .id = MT8173_AFE_IRQ_DAI, | ||
913 | .irq_cnt_reg = AFE_IRQ_CNT2, | ||
914 | .irq_cnt_shift = 20, | ||
915 | .irq_cnt_maskbit = 0x3ffff, | ||
916 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
917 | .irq_en_shift = 3, | ||
918 | .irq_fs_reg = AFE_IRQ_MCU_CON, | ||
919 | .irq_fs_shift = 20, | ||
920 | .irq_fs_maskbit = 0xf, | ||
921 | .irq_clr_reg = AFE_IRQ_CLR, | ||
922 | .irq_clr_shift = 3, | ||
923 | }, { | ||
924 | .id = MT8173_AFE_IRQ_HDMI, | ||
925 | .irq_cnt_reg = AFE_IRQ_CNT5, | ||
926 | .irq_cnt_shift = 0, | ||
927 | .irq_cnt_maskbit = 0x3ffff, | ||
928 | .irq_en_reg = AFE_IRQ_MCU_CON, | ||
1082 | .irq_en_shift = 12, | 929 | .irq_en_shift = 12, |
930 | .irq_fs_reg = -1, | ||
1083 | .irq_fs_shift = -1, | 931 | .irq_fs_shift = -1, |
932 | .irq_fs_maskbit = -1, | ||
933 | .irq_clr_reg = AFE_IRQ_CLR, | ||
1084 | .irq_clr_shift = 4, | 934 | .irq_clr_shift = 4, |
1085 | .msb_shift = 8, | ||
1086 | }, | 935 | }, |
1087 | }; | 936 | }; |
1088 | 937 | ||
1089 | static const struct regmap_config mtk_afe_regmap_config = { | 938 | static const struct regmap_config mt8173_afe_regmap_config = { |
1090 | .reg_bits = 32, | 939 | .reg_bits = 32, |
1091 | .reg_stride = 4, | 940 | .reg_stride = 4, |
1092 | .val_bits = 32, | 941 | .val_bits = 32, |
@@ -1094,9 +943,9 @@ static const struct regmap_config mtk_afe_regmap_config = { | |||
1094 | .cache_type = REGCACHE_NONE, | 943 | .cache_type = REGCACHE_NONE, |
1095 | }; | 944 | }; |
1096 | 945 | ||
1097 | static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) | 946 | static irqreturn_t mt8173_afe_irq_handler(int irq, void *dev_id) |
1098 | { | 947 | { |
1099 | struct mtk_afe *afe = dev_id; | 948 | struct mtk_base_afe *afe = dev_id; |
1100 | unsigned int reg_value; | 949 | unsigned int reg_value; |
1101 | int i, ret; | 950 | int i, ret; |
1102 | 951 | ||
@@ -1107,10 +956,16 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) | |||
1107 | goto err_irq; | 956 | goto err_irq; |
1108 | } | 957 | } |
1109 | 958 | ||
1110 | for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) { | 959 | for (i = 0; i < MT8173_AFE_MEMIF_NUM; i++) { |
1111 | struct mtk_afe_memif *memif = &afe->memif[i]; | 960 | struct mtk_base_afe_memif *memif = &afe->memif[i]; |
961 | struct mtk_base_afe_irq *irq; | ||
1112 | 962 | ||
1113 | if (!(reg_value & (1 << memif->data->irq_clr_shift))) | 963 | if (memif->irq_usage < 0) |
964 | continue; | ||
965 | |||
966 | irq = &afe->irqs[memif->irq_usage]; | ||
967 | |||
968 | if (!(reg_value & (1 << irq->irq_data->irq_clr_shift))) | ||
1114 | continue; | 969 | continue; |
1115 | 970 | ||
1116 | snd_pcm_period_elapsed(memif->substream); | 971 | snd_pcm_period_elapsed(memif->substream); |
@@ -1118,14 +973,16 @@ static irqreturn_t mtk_afe_irq_handler(int irq, void *dev_id) | |||
1118 | 973 | ||
1119 | err_irq: | 974 | err_irq: |
1120 | /* clear irq */ | 975 | /* clear irq */ |
1121 | regmap_write(afe->regmap, AFE_IRQ_CLR, reg_value & AFE_IRQ_STATUS_BITS); | 976 | regmap_write(afe->regmap, AFE_IRQ_CLR, |
977 | reg_value & AFE_IRQ_STATUS_BITS); | ||
1122 | 978 | ||
1123 | return IRQ_HANDLED; | 979 | return IRQ_HANDLED; |
1124 | } | 980 | } |
1125 | 981 | ||
1126 | static int mtk_afe_runtime_suspend(struct device *dev) | 982 | static int mt8173_afe_runtime_suspend(struct device *dev) |
1127 | { | 983 | { |
1128 | struct mtk_afe *afe = dev_get_drvdata(dev); | 984 | struct mtk_base_afe *afe = dev_get_drvdata(dev); |
985 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
1129 | 986 | ||
1130 | /* disable AFE */ | 987 | /* disable AFE */ |
1131 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); | 988 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0); |
@@ -1134,38 +991,47 @@ static int mtk_afe_runtime_suspend(struct device *dev) | |||
1134 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, | 991 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, |
1135 | AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE); | 992 | AUD_TCON0_PDN_AFE, AUD_TCON0_PDN_AFE); |
1136 | 993 | ||
1137 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); | 994 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]); |
1138 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK1]); | 995 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]); |
1139 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | 996 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]); |
1140 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | 997 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK1]); |
1141 | clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); | 998 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]); |
999 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); | ||
1000 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]); | ||
1142 | return 0; | 1001 | return 0; |
1143 | } | 1002 | } |
1144 | 1003 | ||
1145 | static int mtk_afe_runtime_resume(struct device *dev) | 1004 | static int mt8173_afe_runtime_resume(struct device *dev) |
1146 | { | 1005 | { |
1147 | struct mtk_afe *afe = dev_get_drvdata(dev); | 1006 | struct mtk_base_afe *afe = dev_get_drvdata(dev); |
1007 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
1148 | int ret; | 1008 | int ret; |
1149 | 1009 | ||
1150 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_INFRASYS_AUD]); | 1010 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]); |
1151 | if (ret) | 1011 | if (ret) |
1152 | return ret; | 1012 | return ret; |
1153 | 1013 | ||
1154 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | 1014 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); |
1155 | if (ret) | 1015 | if (ret) |
1156 | goto err_infra; | 1016 | goto err_infra; |
1157 | 1017 | ||
1158 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | 1018 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]); |
1159 | if (ret) | 1019 | if (ret) |
1160 | goto err_top_aud_bus; | 1020 | goto err_top_aud_bus; |
1161 | 1021 | ||
1162 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK0]); | 1022 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK0]); |
1163 | if (ret) | 1023 | if (ret) |
1164 | goto err_top_aud; | 1024 | goto err_top_aud; |
1165 | 1025 | ||
1166 | ret = clk_prepare_enable(afe->clocks[MTK_CLK_BCK1]); | 1026 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_BCK1]); |
1167 | if (ret) | 1027 | if (ret) |
1168 | goto err_bck0; | 1028 | goto err_bck0; |
1029 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S1_M]); | ||
1030 | if (ret) | ||
1031 | goto err_i2s1_m; | ||
1032 | ret = clk_prepare_enable(afe_priv->clocks[MT8173_CLK_I2S2_M]); | ||
1033 | if (ret) | ||
1034 | goto err_i2s2_m; | ||
1169 | 1035 | ||
1170 | /* enable AFE clk */ | 1036 | /* enable AFE clk */ |
1171 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0); | 1037 | regmap_update_bits(afe->regmap, AUDIO_TOP_CON0, AUD_TCON0_PDN_AFE, 0); |
@@ -1181,39 +1047,45 @@ static int mtk_afe_runtime_resume(struct device *dev) | |||
1181 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); | 1047 | regmap_update_bits(afe->regmap, AFE_DAC_CON0, 0x1, 0x1); |
1182 | return 0; | 1048 | return 0; |
1183 | 1049 | ||
1050 | err_i2s1_m: | ||
1051 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S1_M]); | ||
1052 | err_i2s2_m: | ||
1053 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_I2S2_M]); | ||
1184 | err_bck0: | 1054 | err_bck0: |
1185 | clk_disable_unprepare(afe->clocks[MTK_CLK_BCK0]); | 1055 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_BCK0]); |
1186 | err_top_aud: | 1056 | err_top_aud: |
1187 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD]); | 1057 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD]); |
1188 | err_top_aud_bus: | 1058 | err_top_aud_bus: |
1189 | clk_disable_unprepare(afe->clocks[MTK_CLK_TOP_PDN_AUD_BUS]); | 1059 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_TOP_PDN_AUD_BUS]); |
1190 | err_infra: | 1060 | err_infra: |
1191 | clk_disable_unprepare(afe->clocks[MTK_CLK_INFRASYS_AUD]); | 1061 | clk_disable_unprepare(afe_priv->clocks[MT8173_CLK_INFRASYS_AUD]); |
1192 | return ret; | 1062 | return ret; |
1193 | } | 1063 | } |
1194 | 1064 | ||
1195 | static int mtk_afe_init_audio_clk(struct mtk_afe *afe) | 1065 | static int mt8173_afe_init_audio_clk(struct mtk_base_afe *afe) |
1196 | { | 1066 | { |
1197 | size_t i; | 1067 | size_t i; |
1068 | struct mt8173_afe_private *afe_priv = afe->platform_priv; | ||
1198 | 1069 | ||
1199 | for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { | 1070 | for (i = 0; i < ARRAY_SIZE(aud_clks); i++) { |
1200 | afe->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); | 1071 | afe_priv->clocks[i] = devm_clk_get(afe->dev, aud_clks[i]); |
1201 | if (IS_ERR(afe->clocks[i])) { | 1072 | if (IS_ERR(afe_priv->clocks[i])) { |
1202 | dev_err(afe->dev, "%s devm_clk_get %s fail\n", | 1073 | dev_err(afe->dev, "%s devm_clk_get %s fail\n", |
1203 | __func__, aud_clks[i]); | 1074 | __func__, aud_clks[i]); |
1204 | return PTR_ERR(afe->clocks[i]); | 1075 | return PTR_ERR(afe_priv->clocks[i]); |
1205 | } | 1076 | } |
1206 | } | 1077 | } |
1207 | clk_set_rate(afe->clocks[MTK_CLK_BCK0], 22579200); /* 22M */ | 1078 | clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK0], 22579200); /* 22M */ |
1208 | clk_set_rate(afe->clocks[MTK_CLK_BCK1], 24576000); /* 24M */ | 1079 | clk_set_rate(afe_priv->clocks[MT8173_CLK_BCK1], 24576000); /* 24M */ |
1209 | return 0; | 1080 | return 0; |
1210 | } | 1081 | } |
1211 | 1082 | ||
1212 | static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) | 1083 | static int mt8173_afe_pcm_dev_probe(struct platform_device *pdev) |
1213 | { | 1084 | { |
1214 | int ret, i; | 1085 | int ret, i; |
1215 | unsigned int irq_id; | 1086 | unsigned int irq_id; |
1216 | struct mtk_afe *afe; | 1087 | struct mtk_base_afe *afe; |
1088 | struct mt8173_afe_private *afe_priv; | ||
1217 | struct resource *res; | 1089 | struct resource *res; |
1218 | 1090 | ||
1219 | ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); | 1091 | ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(33)); |
@@ -1224,6 +1096,12 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) | |||
1224 | if (!afe) | 1096 | if (!afe) |
1225 | return -ENOMEM; | 1097 | return -ENOMEM; |
1226 | 1098 | ||
1099 | afe->platform_priv = devm_kzalloc(&pdev->dev, sizeof(*afe_priv), | ||
1100 | GFP_KERNEL); | ||
1101 | afe_priv = afe->platform_priv; | ||
1102 | if (!afe_priv) | ||
1103 | return -ENOMEM; | ||
1104 | |||
1227 | afe->dev = &pdev->dev; | 1105 | afe->dev = &pdev->dev; |
1228 | 1106 | ||
1229 | irq_id = platform_get_irq(pdev, 0); | 1107 | irq_id = platform_get_irq(pdev, 0); |
@@ -1231,7 +1109,7 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) | |||
1231 | dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); | 1109 | dev_err(afe->dev, "np %s no irq\n", afe->dev->of_node->name); |
1232 | return -ENXIO; | 1110 | return -ENXIO; |
1233 | } | 1111 | } |
1234 | ret = devm_request_irq(afe->dev, irq_id, mtk_afe_irq_handler, | 1112 | ret = devm_request_irq(afe->dev, irq_id, mt8173_afe_irq_handler, |
1235 | 0, "Afe_ISR_Handle", (void *)afe); | 1113 | 0, "Afe_ISR_Handle", (void *)afe); |
1236 | if (ret) { | 1114 | if (ret) { |
1237 | dev_err(afe->dev, "could not request_irq\n"); | 1115 | dev_err(afe->dev, "could not request_irq\n"); |
@@ -1244,48 +1122,75 @@ static int mtk_afe_pcm_dev_probe(struct platform_device *pdev) | |||
1244 | return PTR_ERR(afe->base_addr); | 1122 | return PTR_ERR(afe->base_addr); |
1245 | 1123 | ||
1246 | afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, | 1124 | afe->regmap = devm_regmap_init_mmio(&pdev->dev, afe->base_addr, |
1247 | &mtk_afe_regmap_config); | 1125 | &mt8173_afe_regmap_config); |
1248 | if (IS_ERR(afe->regmap)) | 1126 | if (IS_ERR(afe->regmap)) |
1249 | return PTR_ERR(afe->regmap); | 1127 | return PTR_ERR(afe->regmap); |
1250 | 1128 | ||
1251 | /* initial audio related clock */ | 1129 | /* initial audio related clock */ |
1252 | ret = mtk_afe_init_audio_clk(afe); | 1130 | ret = mt8173_afe_init_audio_clk(afe); |
1253 | if (ret) { | 1131 | if (ret) { |
1254 | dev_err(afe->dev, "mtk_afe_init_audio_clk fail\n"); | 1132 | dev_err(afe->dev, "mt8173_afe_init_audio_clk fail\n"); |
1255 | return ret; | 1133 | return ret; |
1256 | } | 1134 | } |
1257 | 1135 | ||
1258 | for (i = 0; i < MTK_AFE_MEMIF_NUM; i++) | 1136 | /* memif % irq initialize*/ |
1137 | afe->memif_size = MT8173_AFE_MEMIF_NUM; | ||
1138 | afe->memif = devm_kcalloc(afe->dev, afe->memif_size, | ||
1139 | sizeof(*afe->memif), GFP_KERNEL); | ||
1140 | if (!afe->memif) | ||
1141 | return -ENOMEM; | ||
1142 | |||
1143 | afe->irqs_size = MT8173_AFE_IRQ_NUM; | ||
1144 | afe->irqs = devm_kcalloc(afe->dev, afe->irqs_size, | ||
1145 | sizeof(*afe->irqs), GFP_KERNEL); | ||
1146 | if (!afe->irqs) | ||
1147 | return -ENOMEM; | ||
1148 | |||
1149 | for (i = 0; i < afe->irqs_size; i++) { | ||
1259 | afe->memif[i].data = &memif_data[i]; | 1150 | afe->memif[i].data = &memif_data[i]; |
1151 | afe->irqs[i].irq_data = &irq_data[i]; | ||
1152 | afe->irqs[i].irq_occupyed = true; | ||
1153 | afe->memif[i].irq_usage = i; | ||
1154 | afe->memif[i].const_irq = 1; | ||
1155 | } | ||
1156 | |||
1157 | afe->mtk_afe_hardware = &mt8173_afe_hardware; | ||
1158 | afe->memif_fs = mt8173_memif_fs; | ||
1159 | afe->irq_fs = mt8173_irq_fs; | ||
1260 | 1160 | ||
1261 | platform_set_drvdata(pdev, afe); | 1161 | platform_set_drvdata(pdev, afe); |
1262 | 1162 | ||
1263 | pm_runtime_enable(&pdev->dev); | 1163 | pm_runtime_enable(&pdev->dev); |
1264 | if (!pm_runtime_enabled(&pdev->dev)) { | 1164 | if (!pm_runtime_enabled(&pdev->dev)) { |
1265 | ret = mtk_afe_runtime_resume(&pdev->dev); | 1165 | ret = mt8173_afe_runtime_resume(&pdev->dev); |
1266 | if (ret) | 1166 | if (ret) |
1267 | goto err_pm_disable; | 1167 | goto err_pm_disable; |
1268 | } | 1168 | } |
1269 | 1169 | ||
1170 | afe->reg_back_up_list = mt8173_afe_backup_list; | ||
1171 | afe->reg_back_up_list_num = ARRAY_SIZE(mt8173_afe_backup_list); | ||
1172 | afe->runtime_resume = mt8173_afe_runtime_resume; | ||
1173 | afe->runtime_suspend = mt8173_afe_runtime_suspend; | ||
1174 | |||
1270 | ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); | 1175 | ret = snd_soc_register_platform(&pdev->dev, &mtk_afe_pcm_platform); |
1271 | if (ret) | 1176 | if (ret) |
1272 | goto err_pm_disable; | 1177 | goto err_pm_disable; |
1273 | 1178 | ||
1274 | ret = snd_soc_register_component(&pdev->dev, | 1179 | ret = snd_soc_register_component(&pdev->dev, |
1275 | &mtk_afe_pcm_dai_component, | 1180 | &mt8173_afe_pcm_dai_component, |
1276 | mtk_afe_pcm_dais, | 1181 | mt8173_afe_pcm_dais, |
1277 | ARRAY_SIZE(mtk_afe_pcm_dais)); | 1182 | ARRAY_SIZE(mt8173_afe_pcm_dais)); |
1278 | if (ret) | 1183 | if (ret) |
1279 | goto err_platform; | 1184 | goto err_platform; |
1280 | 1185 | ||
1281 | ret = snd_soc_register_component(&pdev->dev, | 1186 | ret = snd_soc_register_component(&pdev->dev, |
1282 | &mtk_afe_hdmi_dai_component, | 1187 | &mt8173_afe_hdmi_dai_component, |
1283 | mtk_afe_hdmi_dais, | 1188 | mt8173_afe_hdmi_dais, |
1284 | ARRAY_SIZE(mtk_afe_hdmi_dais)); | 1189 | ARRAY_SIZE(mt8173_afe_hdmi_dais)); |
1285 | if (ret) | 1190 | if (ret) |
1286 | goto err_comp; | 1191 | goto err_comp; |
1287 | 1192 | ||
1288 | dev_info(&pdev->dev, "MTK AFE driver initialized.\n"); | 1193 | dev_info(&pdev->dev, "MT8173 AFE driver initialized.\n"); |
1289 | return 0; | 1194 | return 0; |
1290 | 1195 | ||
1291 | err_comp: | 1196 | err_comp: |
@@ -1297,38 +1202,38 @@ err_pm_disable: | |||
1297 | return ret; | 1202 | return ret; |
1298 | } | 1203 | } |
1299 | 1204 | ||
1300 | static int mtk_afe_pcm_dev_remove(struct platform_device *pdev) | 1205 | static int mt8173_afe_pcm_dev_remove(struct platform_device *pdev) |
1301 | { | 1206 | { |
1302 | pm_runtime_disable(&pdev->dev); | 1207 | pm_runtime_disable(&pdev->dev); |
1303 | if (!pm_runtime_status_suspended(&pdev->dev)) | 1208 | if (!pm_runtime_status_suspended(&pdev->dev)) |
1304 | mtk_afe_runtime_suspend(&pdev->dev); | 1209 | mt8173_afe_runtime_suspend(&pdev->dev); |
1305 | snd_soc_unregister_component(&pdev->dev); | 1210 | snd_soc_unregister_component(&pdev->dev); |
1306 | snd_soc_unregister_platform(&pdev->dev); | 1211 | snd_soc_unregister_platform(&pdev->dev); |
1307 | return 0; | 1212 | return 0; |
1308 | } | 1213 | } |
1309 | 1214 | ||
1310 | static const struct of_device_id mtk_afe_pcm_dt_match[] = { | 1215 | static const struct of_device_id mt8173_afe_pcm_dt_match[] = { |
1311 | { .compatible = "mediatek,mt8173-afe-pcm", }, | 1216 | { .compatible = "mediatek,mt8173-afe-pcm", }, |
1312 | { } | 1217 | { } |
1313 | }; | 1218 | }; |
1314 | MODULE_DEVICE_TABLE(of, mtk_afe_pcm_dt_match); | 1219 | MODULE_DEVICE_TABLE(of, mt8173_afe_pcm_dt_match); |
1315 | 1220 | ||
1316 | static const struct dev_pm_ops mtk_afe_pm_ops = { | 1221 | static const struct dev_pm_ops mt8173_afe_pm_ops = { |
1317 | SET_RUNTIME_PM_OPS(mtk_afe_runtime_suspend, mtk_afe_runtime_resume, | 1222 | SET_RUNTIME_PM_OPS(mt8173_afe_runtime_suspend, |
1318 | NULL) | 1223 | mt8173_afe_runtime_resume, NULL) |
1319 | }; | 1224 | }; |
1320 | 1225 | ||
1321 | static struct platform_driver mtk_afe_pcm_driver = { | 1226 | static struct platform_driver mt8173_afe_pcm_driver = { |
1322 | .driver = { | 1227 | .driver = { |
1323 | .name = "mtk-afe-pcm", | 1228 | .name = "mt8173-afe-pcm", |
1324 | .of_match_table = mtk_afe_pcm_dt_match, | 1229 | .of_match_table = mt8173_afe_pcm_dt_match, |
1325 | .pm = &mtk_afe_pm_ops, | 1230 | .pm = &mt8173_afe_pm_ops, |
1326 | }, | 1231 | }, |
1327 | .probe = mtk_afe_pcm_dev_probe, | 1232 | .probe = mt8173_afe_pcm_dev_probe, |
1328 | .remove = mtk_afe_pcm_dev_remove, | 1233 | .remove = mt8173_afe_pcm_dev_remove, |
1329 | }; | 1234 | }; |
1330 | 1235 | ||
1331 | module_platform_driver(mtk_afe_pcm_driver); | 1236 | module_platform_driver(mt8173_afe_pcm_driver); |
1332 | 1237 | ||
1333 | MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver"); | 1238 | MODULE_DESCRIPTION("Mediatek ALSA SoC AFE platform driver"); |
1334 | MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); | 1239 | MODULE_AUTHOR("Koro Chen <koro.chen@mediatek.com>"); |
diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 71a1a35047ba..5524a2c727ec 100644 --- a/sound/soc/mediatek/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c | |||
@@ -18,7 +18,7 @@ | |||
18 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | #include <sound/jack.h> | 19 | #include <sound/jack.h> |
20 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
21 | #include "../codecs/max98090.h" | 21 | #include "../../codecs/max98090.h" |
22 | 22 | ||
23 | static struct snd_soc_jack mt8173_max98090_jack; | 23 | static struct snd_soc_jack mt8173_max98090_jack; |
24 | 24 | ||
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index 58e083642dea..467f7049a288 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c | |||
@@ -19,7 +19,7 @@ | |||
19 | #include <linux/of_gpio.h> | 19 | #include <linux/of_gpio.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/jack.h> | 21 | #include <sound/jack.h> |
22 | #include "../codecs/rt5645.h" | 22 | #include "../../codecs/rt5645.h" |
23 | 23 | ||
24 | #define MCLK_FOR_CODECS 12288000 | 24 | #define MCLK_FOR_CODECS 12288000 |
25 | 25 | ||
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index bb593926c62d..1b8b2a778845 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c | |||
@@ -19,8 +19,8 @@ | |||
19 | #include <linux/of_gpio.h> | 19 | #include <linux/of_gpio.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/jack.h> | 21 | #include <sound/jack.h> |
22 | #include "../codecs/rt5645.h" | 22 | #include "../../codecs/rt5645.h" |
23 | #include "../codecs/rt5677.h" | 23 | #include "../../codecs/rt5677.h" |
24 | 24 | ||
25 | #define MCLK_FOR_CODECS 12288000 | 25 | #define MCLK_FOR_CODECS 12288000 |
26 | 26 | ||
diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index a27a6673dbe3..ba65f4157a7e 100644 --- a/sound/soc/mediatek/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c | |||
@@ -19,10 +19,24 @@ | |||
19 | #include <linux/of_gpio.h> | 19 | #include <linux/of_gpio.h> |
20 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/jack.h> | 21 | #include <sound/jack.h> |
22 | #include "../codecs/rt5645.h" | 22 | #include "../../codecs/rt5645.h" |
23 | 23 | ||
24 | #define MCLK_FOR_CODECS 12288000 | 24 | #define MCLK_FOR_CODECS 12288000 |
25 | 25 | ||
26 | enum mt8173_rt5650_mclk { | ||
27 | MT8173_RT5650_MCLK_EXTERNAL = 0, | ||
28 | MT8173_RT5650_MCLK_INTERNAL, | ||
29 | }; | ||
30 | |||
31 | struct mt8173_rt5650_platform_data { | ||
32 | enum mt8173_rt5650_mclk pll_from; | ||
33 | /* 0 = external oscillator; 1 = internal source from mt8173 */ | ||
34 | }; | ||
35 | |||
36 | static struct mt8173_rt5650_platform_data mt8173_rt5650_priv = { | ||
37 | .pll_from = MT8173_RT5650_MCLK_EXTERNAL, | ||
38 | }; | ||
39 | |||
26 | static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = { | 40 | static const struct snd_soc_dapm_widget mt8173_rt5650_widgets[] = { |
27 | SND_SOC_DAPM_SPK("Speaker", NULL), | 41 | SND_SOC_DAPM_SPK("Speaker", NULL), |
28 | SND_SOC_DAPM_MIC("Int Mic", NULL), | 42 | SND_SOC_DAPM_MIC("Int Mic", NULL), |
@@ -54,13 +68,29 @@ static int mt8173_rt5650_hw_params(struct snd_pcm_substream *substream, | |||
54 | struct snd_pcm_hw_params *params) | 68 | struct snd_pcm_hw_params *params) |
55 | { | 69 | { |
56 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 70 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
71 | unsigned int mclk_clock; | ||
57 | int i, ret; | 72 | int i, ret; |
58 | 73 | ||
74 | switch (mt8173_rt5650_priv.pll_from) { | ||
75 | case MT8173_RT5650_MCLK_EXTERNAL: | ||
76 | /* mclk = 12.288M */ | ||
77 | mclk_clock = MCLK_FOR_CODECS; | ||
78 | break; | ||
79 | case MT8173_RT5650_MCLK_INTERNAL: | ||
80 | /* mclk = sampling rate*256 */ | ||
81 | mclk_clock = params_rate(params) * 256; | ||
82 | break; | ||
83 | default: | ||
84 | /* mclk = 12.288M */ | ||
85 | mclk_clock = MCLK_FOR_CODECS; | ||
86 | break; | ||
87 | } | ||
88 | |||
59 | for (i = 0; i < rtd->num_codecs; i++) { | 89 | for (i = 0; i < rtd->num_codecs; i++) { |
60 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; | 90 | struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; |
61 | 91 | ||
62 | /* pll from mclk 12.288M */ | 92 | /* pll from mclk */ |
63 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, MCLK_FOR_CODECS, | 93 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, mclk_clock, |
64 | params_rate(params) * 512); | 94 | params_rate(params) * 512); |
65 | if (ret) | 95 | if (ret) |
66 | return ret; | 96 | return ret; |
@@ -139,7 +169,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { | |||
139 | enum { | 169 | enum { |
140 | DAI_LINK_PLAYBACK, | 170 | DAI_LINK_PLAYBACK, |
141 | DAI_LINK_CAPTURE, | 171 | DAI_LINK_CAPTURE, |
172 | DAI_LINK_HDMI, | ||
142 | DAI_LINK_CODEC_I2S, | 173 | DAI_LINK_CODEC_I2S, |
174 | DAI_LINK_HDMI_I2S, | ||
143 | }; | 175 | }; |
144 | 176 | ||
145 | /* Digital audio interface glue - connects codec <---> CPU */ | 177 | /* Digital audio interface glue - connects codec <---> CPU */ |
@@ -165,6 +197,16 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { | |||
165 | .dynamic = 1, | 197 | .dynamic = 1, |
166 | .dpcm_capture = 1, | 198 | .dpcm_capture = 1, |
167 | }, | 199 | }, |
200 | [DAI_LINK_HDMI] = { | ||
201 | .name = "HDMI", | ||
202 | .stream_name = "HDMI PCM", | ||
203 | .cpu_dai_name = "HDMI", | ||
204 | .codec_name = "snd-soc-dummy", | ||
205 | .codec_dai_name = "snd-soc-dummy-dai", | ||
206 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
207 | .dynamic = 1, | ||
208 | .dpcm_playback = 1, | ||
209 | }, | ||
168 | /* Back End DAI links */ | 210 | /* Back End DAI links */ |
169 | [DAI_LINK_CODEC_I2S] = { | 211 | [DAI_LINK_CODEC_I2S] = { |
170 | .name = "Codec", | 212 | .name = "Codec", |
@@ -180,6 +222,13 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { | |||
180 | .dpcm_playback = 1, | 222 | .dpcm_playback = 1, |
181 | .dpcm_capture = 1, | 223 | .dpcm_capture = 1, |
182 | }, | 224 | }, |
225 | [DAI_LINK_HDMI_I2S] = { | ||
226 | .name = "HDMI BE", | ||
227 | .cpu_dai_name = "HDMIO", | ||
228 | .no_pcm = 1, | ||
229 | .codec_dai_name = "i2s-hifi", | ||
230 | .dpcm_playback = 1, | ||
231 | }, | ||
183 | }; | 232 | }; |
184 | 233 | ||
185 | static struct snd_soc_card mt8173_rt5650_card = { | 234 | static struct snd_soc_card mt8173_rt5650_card = { |
@@ -243,6 +292,24 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) | |||
243 | mt8173_rt5650_codecs[1].dai_name = codec_capture_dai; | 292 | mt8173_rt5650_codecs[1].dai_name = codec_capture_dai; |
244 | } | 293 | } |
245 | 294 | ||
295 | if (device_property_present(&pdev->dev, "mediatek,mclk")) { | ||
296 | ret = device_property_read_u32(&pdev->dev, | ||
297 | "mediatek,mclk", | ||
298 | &mt8173_rt5650_priv.pll_from); | ||
299 | if (ret) { | ||
300 | dev_err(&pdev->dev, | ||
301 | "%s snd_soc_register_card fail %d\n", | ||
302 | __func__, ret); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node = | ||
307 | of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 1); | ||
308 | if (!mt8173_rt5650_dais[DAI_LINK_HDMI_I2S].codec_of_node) { | ||
309 | dev_err(&pdev->dev, | ||
310 | "Property 'audio-codec' missing or invalid\n"); | ||
311 | return -EINVAL; | ||
312 | } | ||
246 | card->dev = &pdev->dev; | 313 | card->dev = &pdev->dev; |
247 | platform_set_drvdata(pdev, card); | 314 | platform_set_drvdata(pdev, card); |
248 | 315 | ||
diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h deleted file mode 100644 index f341f623e887..000000000000 --- a/sound/soc/mediatek/mtk-afe-common.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* | ||
2 | * mtk_afe_common.h -- Mediatek audio driver common definitions | ||
3 | * | ||
4 | * Copyright (c) 2015 MediaTek Inc. | ||
5 | * Author: Koro Chen <koro.chen@mediatek.com> | ||
6 | * Sascha Hauer <s.hauer@pengutronix.de> | ||
7 | * Hidalgo Huang <hidalgo.huang@mediatek.com> | ||
8 | * Ir Lian <ir.lian@mediatek.com> | ||
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 version 2 and | ||
12 | * only version 2 as published by the Free Software Foundation. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | */ | ||
19 | |||
20 | #ifndef _MTK_AFE_COMMON_H_ | ||
21 | #define _MTK_AFE_COMMON_H_ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/regmap.h> | ||
25 | |||
26 | enum { | ||
27 | MTK_AFE_MEMIF_DL1, | ||
28 | MTK_AFE_MEMIF_DL2, | ||
29 | MTK_AFE_MEMIF_VUL, | ||
30 | MTK_AFE_MEMIF_DAI, | ||
31 | MTK_AFE_MEMIF_AWB, | ||
32 | MTK_AFE_MEMIF_MOD_DAI, | ||
33 | MTK_AFE_MEMIF_HDMI, | ||
34 | MTK_AFE_MEMIF_NUM, | ||
35 | MTK_AFE_IO_MOD_PCM1 = MTK_AFE_MEMIF_NUM, | ||
36 | MTK_AFE_IO_MOD_PCM2, | ||
37 | MTK_AFE_IO_PMIC, | ||
38 | MTK_AFE_IO_I2S, | ||
39 | MTK_AFE_IO_2ND_I2S, | ||
40 | MTK_AFE_IO_HW_GAIN1, | ||
41 | MTK_AFE_IO_HW_GAIN2, | ||
42 | MTK_AFE_IO_MRG_O, | ||
43 | MTK_AFE_IO_MRG_I, | ||
44 | MTK_AFE_IO_DAIBT, | ||
45 | MTK_AFE_IO_HDMI, | ||
46 | }; | ||
47 | |||
48 | enum { | ||
49 | MTK_AFE_IRQ_1, | ||
50 | MTK_AFE_IRQ_2, | ||
51 | MTK_AFE_IRQ_3, | ||
52 | MTK_AFE_IRQ_4, | ||
53 | MTK_AFE_IRQ_5, | ||
54 | MTK_AFE_IRQ_6, | ||
55 | MTK_AFE_IRQ_7, | ||
56 | MTK_AFE_IRQ_8, | ||
57 | MTK_AFE_IRQ_NUM, | ||
58 | }; | ||
59 | |||
60 | enum { | ||
61 | MTK_CLK_INFRASYS_AUD, | ||
62 | MTK_CLK_TOP_PDN_AUD, | ||
63 | MTK_CLK_TOP_PDN_AUD_BUS, | ||
64 | MTK_CLK_I2S0_M, | ||
65 | MTK_CLK_I2S1_M, | ||
66 | MTK_CLK_I2S2_M, | ||
67 | MTK_CLK_I2S3_M, | ||
68 | MTK_CLK_I2S3_B, | ||
69 | MTK_CLK_BCK0, | ||
70 | MTK_CLK_BCK1, | ||
71 | MTK_CLK_NUM | ||
72 | }; | ||
73 | |||
74 | struct mtk_afe; | ||
75 | struct snd_pcm_substream; | ||
76 | |||
77 | struct mtk_afe_memif_data { | ||
78 | int id; | ||
79 | const char *name; | ||
80 | int reg_ofs_base; | ||
81 | int reg_ofs_cur; | ||
82 | int fs_shift; | ||
83 | int mono_shift; | ||
84 | int enable_shift; | ||
85 | int irq_reg_cnt; | ||
86 | int irq_cnt_shift; | ||
87 | int irq_en_shift; | ||
88 | int irq_fs_shift; | ||
89 | int irq_clr_shift; | ||
90 | int msb_shift; | ||
91 | }; | ||
92 | |||
93 | struct mtk_afe_memif { | ||
94 | unsigned int phys_buf_addr; | ||
95 | int buffer_size; | ||
96 | struct snd_pcm_substream *substream; | ||
97 | const struct mtk_afe_memif_data *data; | ||
98 | const struct mtk_afe_irq_data *irqdata; | ||
99 | }; | ||
100 | |||
101 | #endif | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 5185a3844da9..f5451c78ede5 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -100,13 +100,14 @@ config SND_OMAP_SOC_OMAP_TWL4030 | |||
100 | 100 | ||
101 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 | 101 | config SND_OMAP_SOC_OMAP_ABE_TWL6040 |
102 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" | 102 | tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" |
103 | depends on TWL6040_CORE && SND_OMAP_SOC | 103 | depends on TWL6040_CORE && SND_OMAP_SOC && COMMON_CLK |
104 | depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST | 104 | depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST |
105 | select SND_OMAP_SOC_DMIC | 105 | select SND_OMAP_SOC_DMIC |
106 | select SND_OMAP_SOC_MCPDM | 106 | select SND_OMAP_SOC_MCPDM |
107 | select SND_SOC_TWL6040 | 107 | select SND_SOC_TWL6040 |
108 | select SND_SOC_DMIC | 108 | select SND_SOC_DMIC |
109 | select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) | 109 | select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) |
110 | select CLK_TWL6040 | ||
110 | help | 111 | help |
111 | Say Y if you want to add support for SoC audio on OMAP boards using | 112 | Say Y if you want to add support for SoC audio on OMAP boards using |
112 | ABE and twl6040 codec. This driver currently supports: | 113 | ABE and twl6040 codec. This driver currently supports: |
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c index b837265ac3e9..e7cdc51fd806 100644 --- a/sound/soc/omap/omap-mcpdm.c +++ b/sound/soc/omap/omap-mcpdm.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/err.h> | 31 | #include <linux/err.h> |
32 | #include <linux/io.h> | 32 | #include <linux/io.h> |
33 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
34 | #include <linux/clk.h> | ||
34 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
35 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
36 | #include <linux/of_device.h> | 37 | #include <linux/of_device.h> |
@@ -54,6 +55,7 @@ struct omap_mcpdm { | |||
54 | unsigned long phys_base; | 55 | unsigned long phys_base; |
55 | void __iomem *io_base; | 56 | void __iomem *io_base; |
56 | int irq; | 57 | int irq; |
58 | struct clk *pdmclk; | ||
57 | 59 | ||
58 | struct mutex mutex; | 60 | struct mutex mutex; |
59 | 61 | ||
@@ -66,6 +68,9 @@ struct omap_mcpdm { | |||
66 | /* McPDM needs to be restarted due to runtime reconfiguration */ | 68 | /* McPDM needs to be restarted due to runtime reconfiguration */ |
67 | bool restart; | 69 | bool restart; |
68 | 70 | ||
71 | /* pm state for suspend/resume handling */ | ||
72 | int pm_active_count; | ||
73 | |||
69 | struct snd_dmaengine_dai_dma_data dma_data[2]; | 74 | struct snd_dmaengine_dai_dma_data dma_data[2]; |
70 | }; | 75 | }; |
71 | 76 | ||
@@ -173,6 +178,10 @@ static inline int omap_mcpdm_active(struct omap_mcpdm *mcpdm) | |||
173 | */ | 178 | */ |
174 | static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) | 179 | static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm) |
175 | { | 180 | { |
181 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); | ||
182 | |||
183 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); | ||
184 | |||
176 | omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, | 185 | omap_mcpdm_write(mcpdm, MCPDM_REG_IRQENABLE_SET, |
177 | MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | | 186 | MCPDM_DN_IRQ_EMPTY | MCPDM_DN_IRQ_FULL | |
178 | MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); | 187 | MCPDM_UP_IRQ_EMPTY | MCPDM_UP_IRQ_FULL); |
@@ -258,12 +267,9 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream, | |||
258 | 267 | ||
259 | mutex_lock(&mcpdm->mutex); | 268 | mutex_lock(&mcpdm->mutex); |
260 | 269 | ||
261 | if (!dai->active) { | 270 | if (!dai->active) |
262 | u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); | ||
263 | |||
264 | omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl | MCPDM_WD_EN); | ||
265 | omap_mcpdm_open_streams(mcpdm); | 271 | omap_mcpdm_open_streams(mcpdm); |
266 | } | 272 | |
267 | mutex_unlock(&mcpdm->mutex); | 273 | mutex_unlock(&mcpdm->mutex); |
268 | 274 | ||
269 | return 0; | 275 | return 0; |
@@ -384,6 +390,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai) | |||
384 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); | 390 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); |
385 | int ret; | 391 | int ret; |
386 | 392 | ||
393 | clk_prepare_enable(mcpdm->pdmclk); | ||
387 | pm_runtime_enable(mcpdm->dev); | 394 | pm_runtime_enable(mcpdm->dev); |
388 | 395 | ||
389 | /* Disable lines while request is ongoing */ | 396 | /* Disable lines while request is ongoing */ |
@@ -418,8 +425,54 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) | |||
418 | 425 | ||
419 | pm_runtime_disable(mcpdm->dev); | 426 | pm_runtime_disable(mcpdm->dev); |
420 | 427 | ||
428 | clk_disable_unprepare(mcpdm->pdmclk); | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | #ifdef CONFIG_PM_SLEEP | ||
433 | static int omap_mcpdm_suspend(struct snd_soc_dai *dai) | ||
434 | { | ||
435 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); | ||
436 | |||
437 | if (dai->active) { | ||
438 | omap_mcpdm_stop(mcpdm); | ||
439 | omap_mcpdm_close_streams(mcpdm); | ||
440 | } | ||
441 | |||
442 | mcpdm->pm_active_count = 0; | ||
443 | while (pm_runtime_active(mcpdm->dev)) { | ||
444 | pm_runtime_put_sync(mcpdm->dev); | ||
445 | mcpdm->pm_active_count++; | ||
446 | } | ||
447 | |||
448 | clk_disable_unprepare(mcpdm->pdmclk); | ||
449 | |||
450 | return 0; | ||
451 | } | ||
452 | |||
453 | static int omap_mcpdm_resume(struct snd_soc_dai *dai) | ||
454 | { | ||
455 | struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); | ||
456 | |||
457 | clk_prepare_enable(mcpdm->pdmclk); | ||
458 | |||
459 | if (mcpdm->pm_active_count) { | ||
460 | while (mcpdm->pm_active_count--) | ||
461 | pm_runtime_get_sync(mcpdm->dev); | ||
462 | |||
463 | if (dai->active) { | ||
464 | omap_mcpdm_open_streams(mcpdm); | ||
465 | omap_mcpdm_start(mcpdm); | ||
466 | } | ||
467 | } | ||
468 | |||
469 | |||
421 | return 0; | 470 | return 0; |
422 | } | 471 | } |
472 | #else | ||
473 | #define omap_mcpdm_suspend NULL | ||
474 | #define omap_mcpdm_resume NULL | ||
475 | #endif | ||
423 | 476 | ||
424 | #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 477 | #define OMAP_MCPDM_RATES (SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
425 | #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE | 478 | #define OMAP_MCPDM_FORMATS SNDRV_PCM_FMTBIT_S32_LE |
@@ -427,6 +480,8 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai) | |||
427 | static struct snd_soc_dai_driver omap_mcpdm_dai = { | 480 | static struct snd_soc_dai_driver omap_mcpdm_dai = { |
428 | .probe = omap_mcpdm_probe, | 481 | .probe = omap_mcpdm_probe, |
429 | .remove = omap_mcpdm_remove, | 482 | .remove = omap_mcpdm_remove, |
483 | .suspend = omap_mcpdm_suspend, | ||
484 | .resume = omap_mcpdm_resume, | ||
430 | .probe_order = SND_SOC_COMP_ORDER_LATE, | 485 | .probe_order = SND_SOC_COMP_ORDER_LATE, |
431 | .remove_order = SND_SOC_COMP_ORDER_EARLY, | 486 | .remove_order = SND_SOC_COMP_ORDER_EARLY, |
432 | .playback = { | 487 | .playback = { |
@@ -494,6 +549,15 @@ static int asoc_mcpdm_probe(struct platform_device *pdev) | |||
494 | 549 | ||
495 | mcpdm->dev = &pdev->dev; | 550 | mcpdm->dev = &pdev->dev; |
496 | 551 | ||
552 | mcpdm->pdmclk = devm_clk_get(&pdev->dev, "pdmclk"); | ||
553 | if (IS_ERR(mcpdm->pdmclk)) { | ||
554 | if (PTR_ERR(mcpdm->pdmclk) == -EPROBE_DEFER) | ||
555 | return -EPROBE_DEFER; | ||
556 | dev_warn(&pdev->dev, "Error getting pdmclk (%ld)!\n", | ||
557 | PTR_ERR(mcpdm->pdmclk)); | ||
558 | mcpdm->pdmclk = NULL; | ||
559 | } | ||
560 | |||
497 | ret = devm_snd_soc_register_component(&pdev->dev, | 561 | ret = devm_snd_soc_register_component(&pdev->dev, |
498 | &omap_mcpdm_component, | 562 | &omap_mcpdm_component, |
499 | &omap_mcpdm_dai, 1); | 563 | &omap_mcpdm_dai, 1); |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 54949242bc70..a76845748a10 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <sound/pcm.h> | 33 | #include <sound/pcm.h> |
34 | #include <sound/soc.h> | 34 | #include <sound/soc.h> |
35 | #include <linux/platform_data/asoc-ti-mcbsp.h> | 35 | #include <linux/platform_data/asoc-ti-mcbsp.h> |
36 | #include "../codecs/tpa6130a2.h" | ||
37 | 36 | ||
38 | #include <asm/mach-types.h> | 37 | #include <asm/mach-types.h> |
39 | 38 | ||
@@ -164,19 +163,6 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, | |||
164 | return 0; | 163 | return 0; |
165 | } | 164 | } |
166 | 165 | ||
167 | static int rx51_hp_event(struct snd_soc_dapm_widget *w, | ||
168 | struct snd_kcontrol *k, int event) | ||
169 | { | ||
170 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
171 | |||
172 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
173 | tpa6130a2_stereo_enable(codec, 1); | ||
174 | else | ||
175 | tpa6130a2_stereo_enable(codec, 0); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | static int rx51_get_input(struct snd_kcontrol *kcontrol, | 166 | static int rx51_get_input(struct snd_kcontrol *kcontrol, |
181 | struct snd_ctl_elem_value *ucontrol) | 167 | struct snd_ctl_elem_value *ucontrol) |
182 | { | 168 | { |
@@ -235,7 +221,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { | |||
235 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | 221 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { |
236 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | 222 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), |
237 | SND_SOC_DAPM_MIC("DMic", NULL), | 223 | SND_SOC_DAPM_MIC("DMic", NULL), |
238 | SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), | 224 | SND_SOC_DAPM_HP("Headphone Jack", NULL), |
239 | SND_SOC_DAPM_MIC("HS Mic", NULL), | 225 | SND_SOC_DAPM_MIC("HS Mic", NULL), |
240 | SND_SOC_DAPM_LINE("FM Transmitter", NULL), | 226 | SND_SOC_DAPM_LINE("FM Transmitter", NULL), |
241 | SND_SOC_DAPM_SPK("Earphone", NULL), | 227 | SND_SOC_DAPM_SPK("Earphone", NULL), |
@@ -246,11 +232,14 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
246 | {"Ext Spk", NULL, "HPROUT"}, | 232 | {"Ext Spk", NULL, "HPROUT"}, |
247 | {"Ext Spk", NULL, "HPLCOM"}, | 233 | {"Ext Spk", NULL, "HPLCOM"}, |
248 | {"Ext Spk", NULL, "HPRCOM"}, | 234 | {"Ext Spk", NULL, "HPRCOM"}, |
249 | {"Headphone Jack", NULL, "LLOUT"}, | ||
250 | {"Headphone Jack", NULL, "RLOUT"}, | ||
251 | {"FM Transmitter", NULL, "LLOUT"}, | 235 | {"FM Transmitter", NULL, "LLOUT"}, |
252 | {"FM Transmitter", NULL, "RLOUT"}, | 236 | {"FM Transmitter", NULL, "RLOUT"}, |
253 | 237 | ||
238 | {"Headphone Jack", NULL, "TPA6130A2 HPLEFT"}, | ||
239 | {"Headphone Jack", NULL, "TPA6130A2 HPRIGHT"}, | ||
240 | {"TPA6130A2 LEFTIN", NULL, "LLOUT"}, | ||
241 | {"TPA6130A2 RIGHTIN", NULL, "RLOUT"}, | ||
242 | |||
254 | {"DMic Rate 64", NULL, "DMic"}, | 243 | {"DMic Rate 64", NULL, "DMic"}, |
255 | {"DMic", NULL, "Mic Bias"}, | 244 | {"DMic", NULL, "Mic Bias"}, |
256 | 245 | ||
@@ -286,16 +275,10 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { | |||
286 | 275 | ||
287 | static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | 276 | static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) |
288 | { | 277 | { |
289 | struct snd_soc_codec *codec = rtd->codec; | ||
290 | struct snd_soc_card *card = rtd->card; | 278 | struct snd_soc_card *card = rtd->card; |
291 | struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); | 279 | struct rx51_audio_pdata *pdata = snd_soc_card_get_drvdata(card); |
292 | int err; | 280 | int err; |
293 | 281 | ||
294 | err = tpa6130a2_add_controls(codec); | ||
295 | if (err < 0) { | ||
296 | dev_err(card->dev, "Failed to add TPA6130A2 controls\n"); | ||
297 | return err; | ||
298 | } | ||
299 | snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42); | 282 | snd_soc_limit_volume(card, "TPA6130A2 Headphone Playback Volume", 42); |
300 | 283 | ||
301 | err = omap_mcbsp_st_add_controls(rtd, 2); | 284 | err = omap_mcbsp_st_add_controls(rtd, 2); |
@@ -357,6 +340,10 @@ static struct snd_soc_aux_dev rx51_aux_dev[] = { | |||
357 | .name = "TLV320AIC34b", | 340 | .name = "TLV320AIC34b", |
358 | .codec_name = "tlv320aic3x-codec.2-0019", | 341 | .codec_name = "tlv320aic3x-codec.2-0019", |
359 | }, | 342 | }, |
343 | { | ||
344 | .name = "TPA61320A2", | ||
345 | .codec_name = "tpa6130a2.2-0060", | ||
346 | }, | ||
360 | }; | 347 | }; |
361 | 348 | ||
362 | static struct snd_soc_codec_conf rx51_codec_conf[] = { | 349 | static struct snd_soc_codec_conf rx51_codec_conf[] = { |
@@ -364,6 +351,10 @@ static struct snd_soc_codec_conf rx51_codec_conf[] = { | |||
364 | .dev_name = "tlv320aic3x-codec.2-0019", | 351 | .dev_name = "tlv320aic3x-codec.2-0019", |
365 | .name_prefix = "b", | 352 | .name_prefix = "b", |
366 | }, | 353 | }, |
354 | { | ||
355 | .dev_name = "tpa6130a2.2-0060", | ||
356 | .name_prefix = "TPA6130A2", | ||
357 | }, | ||
367 | }; | 358 | }; |
368 | 359 | ||
369 | /* Audio card */ | 360 | /* Audio card */ |
@@ -435,11 +426,10 @@ static int rx51_soc_probe(struct platform_device *pdev) | |||
435 | dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); | 426 | dev_err(&pdev->dev, "Headphone amplifier node is not provided\n"); |
436 | return -EINVAL; | 427 | return -EINVAL; |
437 | } | 428 | } |
438 | 429 | rx51_aux_dev[1].codec_name = NULL; | |
439 | /* TODO: tpa6130a2a driver supports only a single instance, so | 430 | rx51_aux_dev[1].codec_of_node = dai_node; |
440 | * this driver ignores the headphone-amplifier node for now. | 431 | rx51_codec_conf[1].dev_name = NULL; |
441 | * It's already mandatory in the DT binding to be future proof. | 432 | rx51_codec_conf[1].of_node = dai_node; |
442 | */ | ||
443 | } | 433 | } |
444 | 434 | ||
445 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 435 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 574c6af28c06..652e8c5ea166 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
@@ -11,8 +11,10 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/mfd/syscon.h> | ||
14 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
15 | #include <linux/of_gpio.h> | 16 | #include <linux/of_gpio.h> |
17 | #include <linux/of_device.h> | ||
16 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
17 | #include <linux/pm_runtime.h> | 19 | #include <linux/pm_runtime.h> |
18 | #include <linux/regmap.h> | 20 | #include <linux/regmap.h> |
@@ -23,6 +25,11 @@ | |||
23 | 25 | ||
24 | #define DRV_NAME "rockchip-i2s" | 26 | #define DRV_NAME "rockchip-i2s" |
25 | 27 | ||
28 | struct rk_i2s_pins { | ||
29 | u32 reg_offset; | ||
30 | u32 shift; | ||
31 | }; | ||
32 | |||
26 | struct rk_i2s_dev { | 33 | struct rk_i2s_dev { |
27 | struct device *dev; | 34 | struct device *dev; |
28 | 35 | ||
@@ -33,6 +40,7 @@ struct rk_i2s_dev { | |||
33 | struct snd_dmaengine_dai_dma_data playback_dma_data; | 40 | struct snd_dmaengine_dai_dma_data playback_dma_data; |
34 | 41 | ||
35 | struct regmap *regmap; | 42 | struct regmap *regmap; |
43 | struct regmap *grf; | ||
36 | 44 | ||
37 | /* | 45 | /* |
38 | * Used to indicate the tx/rx status. | 46 | * Used to indicate the tx/rx status. |
@@ -42,6 +50,7 @@ struct rk_i2s_dev { | |||
42 | bool tx_start; | 50 | bool tx_start; |
43 | bool rx_start; | 51 | bool rx_start; |
44 | bool is_master_mode; | 52 | bool is_master_mode; |
53 | const struct rk_i2s_pins *pins; | ||
45 | }; | 54 | }; |
46 | 55 | ||
47 | static int i2s_runtime_suspend(struct device *dev) | 56 | static int i2s_runtime_suspend(struct device *dev) |
@@ -300,14 +309,38 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, | |||
300 | I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, | 309 | I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, |
301 | val); | 310 | val); |
302 | 311 | ||
312 | if (!IS_ERR(i2s->grf) && i2s->pins) { | ||
313 | regmap_read(i2s->regmap, I2S_TXCR, &val); | ||
314 | val &= I2S_TXCR_CSR_MASK; | ||
315 | |||
316 | switch (val) { | ||
317 | case I2S_CHN_4: | ||
318 | val = I2S_IO_4CH_OUT_6CH_IN; | ||
319 | break; | ||
320 | case I2S_CHN_6: | ||
321 | val = I2S_IO_6CH_OUT_4CH_IN; | ||
322 | break; | ||
323 | case I2S_CHN_8: | ||
324 | val = I2S_IO_8CH_OUT_2CH_IN; | ||
325 | break; | ||
326 | default: | ||
327 | val = I2S_IO_2CH_OUT_8CH_IN; | ||
328 | break; | ||
329 | } | ||
330 | |||
331 | val <<= i2s->pins->shift; | ||
332 | val |= (I2S_IO_DIRECTION_MASK << i2s->pins->shift) << 16; | ||
333 | regmap_write(i2s->grf, i2s->pins->reg_offset, val); | ||
334 | } | ||
335 | |||
303 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, | 336 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, |
304 | I2S_DMACR_TDL(16)); | 337 | I2S_DMACR_TDL(16)); |
305 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, | 338 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, |
306 | I2S_DMACR_RDL(16)); | 339 | I2S_DMACR_RDL(16)); |
307 | 340 | ||
308 | val = I2S_CKR_TRCM_TXRX; | 341 | val = I2S_CKR_TRCM_TXRX; |
309 | if (dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates) | 342 | if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates) |
310 | val = I2S_CKR_TRCM_TXSHARE; | 343 | val = I2S_CKR_TRCM_TXONLY; |
311 | 344 | ||
312 | regmap_update_bits(i2s->regmap, I2S_CKR, | 345 | regmap_update_bits(i2s->regmap, I2S_CKR, |
313 | I2S_CKR_TRCM_MASK, | 346 | I2S_CKR_TRCM_MASK, |
@@ -485,9 +518,23 @@ static const struct regmap_config rockchip_i2s_regmap_config = { | |||
485 | .cache_type = REGCACHE_FLAT, | 518 | .cache_type = REGCACHE_FLAT, |
486 | }; | 519 | }; |
487 | 520 | ||
521 | static const struct rk_i2s_pins rk3399_i2s_pins = { | ||
522 | .reg_offset = 0xe220, | ||
523 | .shift = 11, | ||
524 | }; | ||
525 | |||
526 | static const struct of_device_id rockchip_i2s_match[] = { | ||
527 | { .compatible = "rockchip,rk3066-i2s", }, | ||
528 | { .compatible = "rockchip,rk3188-i2s", }, | ||
529 | { .compatible = "rockchip,rk3288-i2s", }, | ||
530 | { .compatible = "rockchip,rk3399-i2s", .data = &rk3399_i2s_pins }, | ||
531 | {}, | ||
532 | }; | ||
533 | |||
488 | static int rockchip_i2s_probe(struct platform_device *pdev) | 534 | static int rockchip_i2s_probe(struct platform_device *pdev) |
489 | { | 535 | { |
490 | struct device_node *node = pdev->dev.of_node; | 536 | struct device_node *node = pdev->dev.of_node; |
537 | const struct of_device_id *of_id; | ||
491 | struct rk_i2s_dev *i2s; | 538 | struct rk_i2s_dev *i2s; |
492 | struct snd_soc_dai_driver *soc_dai; | 539 | struct snd_soc_dai_driver *soc_dai; |
493 | struct resource *res; | 540 | struct resource *res; |
@@ -501,6 +548,17 @@ static int rockchip_i2s_probe(struct platform_device *pdev) | |||
501 | return -ENOMEM; | 548 | return -ENOMEM; |
502 | } | 549 | } |
503 | 550 | ||
551 | i2s->dev = &pdev->dev; | ||
552 | |||
553 | i2s->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); | ||
554 | if (!IS_ERR(i2s->grf)) { | ||
555 | of_id = of_match_device(rockchip_i2s_match, &pdev->dev); | ||
556 | if (!of_id || !of_id->data) | ||
557 | return -EINVAL; | ||
558 | |||
559 | i2s->pins = of_id->data; | ||
560 | } | ||
561 | |||
504 | /* try to prepare related clocks */ | 562 | /* try to prepare related clocks */ |
505 | i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk"); | 563 | i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk"); |
506 | if (IS_ERR(i2s->hclk)) { | 564 | if (IS_ERR(i2s->hclk)) { |
@@ -540,7 +598,6 @@ static int rockchip_i2s_probe(struct platform_device *pdev) | |||
540 | i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 598 | i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
541 | i2s->capture_dma_data.maxburst = 4; | 599 | i2s->capture_dma_data.maxburst = 4; |
542 | 600 | ||
543 | i2s->dev = &pdev->dev; | ||
544 | dev_set_drvdata(&pdev->dev, i2s); | 601 | dev_set_drvdata(&pdev->dev, i2s); |
545 | 602 | ||
546 | pm_runtime_enable(&pdev->dev); | 603 | pm_runtime_enable(&pdev->dev); |
@@ -606,14 +663,6 @@ static int rockchip_i2s_remove(struct platform_device *pdev) | |||
606 | return 0; | 663 | return 0; |
607 | } | 664 | } |
608 | 665 | ||
609 | static const struct of_device_id rockchip_i2s_match[] = { | ||
610 | { .compatible = "rockchip,rk3066-i2s", }, | ||
611 | { .compatible = "rockchip,rk3188-i2s", }, | ||
612 | { .compatible = "rockchip,rk3288-i2s", }, | ||
613 | { .compatible = "rockchip,rk3399-i2s", }, | ||
614 | {}, | ||
615 | }; | ||
616 | |||
617 | static const struct dev_pm_ops rockchip_i2s_pm_ops = { | 666 | static const struct dev_pm_ops rockchip_i2s_pm_ops = { |
618 | SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, | 667 | SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, |
619 | NULL) | 668 | NULL) |
diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h index dc6e2c74d088..31f11fd25393 100644 --- a/sound/soc/rockchip/rockchip_i2s.h +++ b/sound/soc/rockchip/rockchip_i2s.h | |||
@@ -81,8 +81,8 @@ | |||
81 | #define I2S_CKR_TRCM_SHIFT 28 | 81 | #define I2S_CKR_TRCM_SHIFT 28 |
82 | #define I2S_CKR_TRCM(x) (x << I2S_CKR_TRCM_SHIFT) | 82 | #define I2S_CKR_TRCM(x) (x << I2S_CKR_TRCM_SHIFT) |
83 | #define I2S_CKR_TRCM_TXRX (0 << I2S_CKR_TRCM_SHIFT) | 83 | #define I2S_CKR_TRCM_TXRX (0 << I2S_CKR_TRCM_SHIFT) |
84 | #define I2S_CKR_TRCM_TXSHARE (1 << I2S_CKR_TRCM_SHIFT) | 84 | #define I2S_CKR_TRCM_TXONLY (1 << I2S_CKR_TRCM_SHIFT) |
85 | #define I2S_CKR_TRCM_RXSHARE (2 << I2S_CKR_TRCM_SHIFT) | 85 | #define I2S_CKR_TRCM_RXONLY (2 << I2S_CKR_TRCM_SHIFT) |
86 | #define I2S_CKR_TRCM_MASK (3 << I2S_CKR_TRCM_SHIFT) | 86 | #define I2S_CKR_TRCM_MASK (3 << I2S_CKR_TRCM_SHIFT) |
87 | #define I2S_CKR_MSS_SHIFT 27 | 87 | #define I2S_CKR_MSS_SHIFT 27 |
88 | #define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT) | 88 | #define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT) |
@@ -236,4 +236,11 @@ enum { | |||
236 | #define I2S_TXDR (0x0024) | 236 | #define I2S_TXDR (0x0024) |
237 | #define I2S_RXDR (0x0028) | 237 | #define I2S_RXDR (0x0028) |
238 | 238 | ||
239 | /* io direction cfg register */ | ||
240 | #define I2S_IO_DIRECTION_MASK (7) | ||
241 | #define I2S_IO_8CH_OUT_2CH_IN (0) | ||
242 | #define I2S_IO_6CH_OUT_4CH_IN (4) | ||
243 | #define I2S_IO_4CH_OUT_6CH_IN (6) | ||
244 | #define I2S_IO_2CH_OUT_8CH_IN (7) | ||
245 | |||
239 | #endif /* _ROCKCHIP_IIS_H */ | 246 | #endif /* _ROCKCHIP_IIS_H */ |
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 543610282cdb..e70ffad07184 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c | |||
@@ -34,13 +34,18 @@ | |||
34 | #define DRV_NAME "rockchip-snd-max98090" | 34 | #define DRV_NAME "rockchip-snd-max98090" |
35 | 35 | ||
36 | static struct snd_soc_jack headset_jack; | 36 | static struct snd_soc_jack headset_jack; |
37 | |||
38 | /* Headset jack detection DAPM pins */ | ||
37 | static struct snd_soc_jack_pin headset_jack_pins[] = { | 39 | static struct snd_soc_jack_pin headset_jack_pins[] = { |
38 | { | 40 | { |
39 | .pin = "Headset Jack", | 41 | .pin = "Headphone", |
40 | .mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | | 42 | .mask = SND_JACK_HEADPHONE, |
41 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | 43 | }, |
42 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | 44 | { |
45 | .pin = "Headset Mic", | ||
46 | .mask = SND_JACK_MICROPHONE, | ||
43 | }, | 47 | }, |
48 | |||
44 | }; | 49 | }; |
45 | 50 | ||
46 | static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { | 51 | static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { |
@@ -53,7 +58,7 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { | |||
53 | static const struct snd_soc_dapm_route rk_audio_map[] = { | 58 | static const struct snd_soc_dapm_route rk_audio_map[] = { |
54 | {"IN34", NULL, "Headset Mic"}, | 59 | {"IN34", NULL, "Headset Mic"}, |
55 | {"IN34", NULL, "MICBIAS"}, | 60 | {"IN34", NULL, "MICBIAS"}, |
56 | {"MICBIAS", NULL, "Headset Mic"}, | 61 | {"Headset Mic", NULL, "MICBIAS"}, |
57 | {"DMICL", NULL, "Int Mic"}, | 62 | {"DMICL", NULL, "Int Mic"}, |
58 | {"Headphone", NULL, "HPL"}, | 63 | {"Headphone", NULL, "HPL"}, |
59 | {"Headphone", NULL, "HPR"}, | 64 | {"Headphone", NULL, "HPR"}, |
@@ -114,43 +119,27 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, | |||
114 | return ret; | 119 | return ret; |
115 | } | 120 | } |
116 | 121 | ||
117 | static int rk_init(struct snd_soc_pcm_runtime *runtime) | ||
118 | { | ||
119 | /* Enable Headset and 4 Buttons Jack detection */ | ||
120 | return snd_soc_card_jack_new(runtime->card, "Headset Jack", | ||
121 | SND_JACK_HEADSET | | ||
122 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
123 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | ||
124 | &headset_jack, | ||
125 | headset_jack_pins, | ||
126 | ARRAY_SIZE(headset_jack_pins)); | ||
127 | } | ||
128 | |||
129 | static int rk_98090_headset_init(struct snd_soc_component *component) | ||
130 | { | ||
131 | return ts3a227e_enable_jack_detect(component, &headset_jack); | ||
132 | } | ||
133 | |||
134 | static struct snd_soc_ops rk_aif1_ops = { | 122 | static struct snd_soc_ops rk_aif1_ops = { |
135 | .hw_params = rk_aif1_hw_params, | 123 | .hw_params = rk_aif1_hw_params, |
136 | }; | 124 | }; |
137 | 125 | ||
138 | static struct snd_soc_aux_dev rk_98090_headset_dev = { | ||
139 | .name = "Headset Chip", | ||
140 | .init = rk_98090_headset_init, | ||
141 | }; | ||
142 | |||
143 | static struct snd_soc_dai_link rk_dailink = { | 126 | static struct snd_soc_dai_link rk_dailink = { |
144 | .name = "max98090", | 127 | .name = "max98090", |
145 | .stream_name = "Audio", | 128 | .stream_name = "Audio", |
146 | .codec_dai_name = "HiFi", | 129 | .codec_dai_name = "HiFi", |
147 | .init = rk_init, | ||
148 | .ops = &rk_aif1_ops, | 130 | .ops = &rk_aif1_ops, |
149 | /* set max98090 as slave */ | 131 | /* set max98090 as slave */ |
150 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 132 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
151 | SND_SOC_DAIFMT_CBS_CFS, | 133 | SND_SOC_DAIFMT_CBS_CFS, |
152 | }; | 134 | }; |
153 | 135 | ||
136 | static int rk_98090_headset_init(struct snd_soc_component *component); | ||
137 | |||
138 | static struct snd_soc_aux_dev rk_98090_headset_dev = { | ||
139 | .name = "Headset Chip", | ||
140 | .init = rk_98090_headset_init, | ||
141 | }; | ||
142 | |||
154 | static struct snd_soc_card snd_soc_card_rk = { | 143 | static struct snd_soc_card snd_soc_card_rk = { |
155 | .name = "ROCKCHIP-I2S", | 144 | .name = "ROCKCHIP-I2S", |
156 | .owner = THIS_MODULE, | 145 | .owner = THIS_MODULE, |
@@ -166,6 +155,26 @@ static struct snd_soc_card snd_soc_card_rk = { | |||
166 | .num_controls = ARRAY_SIZE(rk_mc_controls), | 155 | .num_controls = ARRAY_SIZE(rk_mc_controls), |
167 | }; | 156 | }; |
168 | 157 | ||
158 | static int rk_98090_headset_init(struct snd_soc_component *component) | ||
159 | { | ||
160 | int ret; | ||
161 | |||
162 | /* Enable Headset and 4 Buttons Jack detection */ | ||
163 | ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack", | ||
164 | SND_JACK_HEADSET | | ||
165 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | | ||
166 | SND_JACK_BTN_2 | SND_JACK_BTN_3, | ||
167 | &headset_jack, | ||
168 | headset_jack_pins, | ||
169 | ARRAY_SIZE(headset_jack_pins)); | ||
170 | if (ret) | ||
171 | return ret; | ||
172 | |||
173 | ret = ts3a227e_enable_jack_detect(component, &headset_jack); | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
169 | static int snd_rk_mc_probe(struct platform_device *pdev) | 178 | static int snd_rk_mc_probe(struct platform_device *pdev) |
170 | { | 179 | { |
171 | int ret = 0; | 180 | int ret = 0; |
diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index 100781e37848..4ca265737eda 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c | |||
@@ -101,21 +101,7 @@ static int rk_spdif_hw_params(struct snd_pcm_substream *substream, | |||
101 | int ret; | 101 | int ret; |
102 | 102 | ||
103 | srate = params_rate(params); | 103 | srate = params_rate(params); |
104 | switch (srate) { | 104 | mclk = srate * 128; |
105 | case 32000: | ||
106 | case 48000: | ||
107 | case 96000: | ||
108 | mclk = 96000 * 128; /* 12288000 hz */ | ||
109 | break; | ||
110 | case 44100: | ||
111 | mclk = 44100 * 256; /* 11289600 hz */ | ||
112 | break; | ||
113 | case 192000: | ||
114 | mclk = 192000 * 128; /* 24576000 hz */ | ||
115 | break; | ||
116 | default: | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | 105 | ||
120 | switch (params_format(params)) { | 106 | switch (params_format(params)) { |
121 | case SNDRV_PCM_FORMAT_S16_LE: | 107 | case SNDRV_PCM_FORMAT_S16_LE: |
@@ -139,7 +125,6 @@ static int rk_spdif_hw_params(struct snd_pcm_substream *substream, | |||
139 | return ret; | 125 | return ret; |
140 | } | 126 | } |
141 | 127 | ||
142 | val |= SPDIF_CFGR_CLK_DIV(mclk/(srate * 256)); | ||
143 | ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR, | 128 | ret = regmap_update_bits(spdif->regmap, SPDIF_CFGR, |
144 | SPDIF_CFGR_CLK_DIV_MASK | SPDIF_CFGR_HALFWORD_ENABLE | | 129 | SPDIF_CFGR_CLK_DIV_MASK | SPDIF_CFGR_HALFWORD_ENABLE | |
145 | SDPIF_CFGR_VDW_MASK, | 130 | SDPIF_CFGR_VDW_MASK, |
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 78baa26e938b..7b722b0094d9 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -224,14 +224,6 @@ config SND_SOC_SNOW | |||
224 | Say Y if you want to add audio support for various Snow | 224 | Say Y if you want to add audio support for various Snow |
225 | boards based on Exynos5 series of SoCs. | 225 | boards based on Exynos5 series of SoCs. |
226 | 226 | ||
227 | config SND_SOC_ODROIDX2 | ||
228 | tristate "Audio support for Odroid-X2 and Odroid-U3" | ||
229 | depends on SND_SOC_SAMSUNG && I2C | ||
230 | select SND_SOC_MAX98090 | ||
231 | select SND_SAMSUNG_I2S | ||
232 | help | ||
233 | Say Y here to enable audio support for the Odroid-X2/U3. | ||
234 | |||
235 | config SND_SOC_ARNDALE_RT5631_ALC5631 | 227 | config SND_SOC_ARNDALE_RT5631_ALC5631 |
236 | tristate "Audio support for RT5631(ALC5631) on Arndale Board" | 228 | tristate "Audio support for RT5631(ALC5631) on Arndale Board" |
237 | depends on SND_SOC_SAMSUNG && I2C | 229 | depends on SND_SOC_SAMSUNG && I2C |
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 052fe71be518..5d03f5ce6916 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile | |||
@@ -43,7 +43,6 @@ snd-soc-tobermory-objs := tobermory.o | |||
43 | snd-soc-lowland-objs := lowland.o | 43 | snd-soc-lowland-objs := lowland.o |
44 | snd-soc-littlemill-objs := littlemill.o | 44 | snd-soc-littlemill-objs := littlemill.o |
45 | snd-soc-bells-objs := bells.o | 45 | snd-soc-bells-objs := bells.o |
46 | snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o | ||
47 | snd-soc-arndale-rt5631-objs := arndale_rt5631.o | 46 | snd-soc-arndale-rt5631-objs := arndale_rt5631.o |
48 | 47 | ||
49 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o | 48 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o |
@@ -69,5 +68,4 @@ obj-$(CONFIG_SND_SOC_TOBERMORY) += snd-soc-tobermory.o | |||
69 | obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o | 68 | obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o |
70 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o | 69 | obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o |
71 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o | 70 | obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o |
72 | obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o | ||
73 | obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o | 71 | 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 4a7a503fe13c..547d31032088 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -389,7 +389,8 @@ static int s3c_ac97_probe(struct platform_device *pdev) | |||
389 | goto err5; | 389 | goto err5; |
390 | 390 | ||
391 | ret = samsung_asoc_dma_platform_register(&pdev->dev, | 391 | ret = samsung_asoc_dma_platform_register(&pdev->dev, |
392 | ac97_pdata->dma_filter); | 392 | ac97_pdata->dma_filter, |
393 | NULL, NULL); | ||
393 | if (ret) { | 394 | if (ret) { |
394 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); | 395 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); |
395 | goto err5; | 396 | goto err5; |
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index a7616cc9b39e..3830f297e0b6 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h | |||
@@ -26,7 +26,10 @@ struct s3c_dma_params { | |||
26 | void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, | 26 | void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, |
27 | struct s3c_dma_params *playback, | 27 | struct s3c_dma_params *playback, |
28 | struct s3c_dma_params *capture); | 28 | struct s3c_dma_params *capture); |
29 | int samsung_asoc_dma_platform_register(struct device *dev, | 29 | /* |
30 | dma_filter_fn fn); | 30 | * @tx, @rx arguments can be NULL if the DMA channel names are "tx", "rx", |
31 | 31 | * otherwise actual DMA channel names must be passed to this function. | |
32 | */ | ||
33 | int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, | ||
34 | const char *tx, const char *rx); | ||
32 | #endif | 35 | #endif |
diff --git a/sound/soc/samsung/dmaengine.c b/sound/soc/samsung/dmaengine.c index 063125937311..2c87f380bfc4 100644 --- a/sound/soc/samsung/dmaengine.c +++ b/sound/soc/samsung/dmaengine.c | |||
@@ -28,10 +28,6 @@ | |||
28 | 28 | ||
29 | #include "dma.h" | 29 | #include "dma.h" |
30 | 30 | ||
31 | static struct snd_dmaengine_pcm_config samsung_dmaengine_pcm_config = { | ||
32 | .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, | ||
33 | }; | ||
34 | |||
35 | void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, | 31 | void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, |
36 | struct s3c_dma_params *playback, | 32 | struct s3c_dma_params *playback, |
37 | struct s3c_dma_params *capture) | 33 | struct s3c_dma_params *capture) |
@@ -58,15 +54,28 @@ void samsung_asoc_init_dma_data(struct snd_soc_dai *dai, | |||
58 | } | 54 | } |
59 | EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); | 55 | EXPORT_SYMBOL_GPL(samsung_asoc_init_dma_data); |
60 | 56 | ||
61 | int samsung_asoc_dma_platform_register(struct device *dev, | 57 | int samsung_asoc_dma_platform_register(struct device *dev, dma_filter_fn filter, |
62 | dma_filter_fn filter) | 58 | const char *tx, const char *rx) |
63 | { | 59 | { |
64 | samsung_dmaengine_pcm_config.compat_filter_fn = filter; | 60 | unsigned int flags = SND_DMAENGINE_PCM_FLAG_COMPAT; |
61 | |||
62 | struct snd_dmaengine_pcm_config *pcm_conf; | ||
63 | |||
64 | pcm_conf = devm_kzalloc(dev, sizeof(*pcm_conf), GFP_KERNEL); | ||
65 | if (!pcm_conf) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | pcm_conf->prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config; | ||
69 | pcm_conf->compat_filter_fn = filter; | ||
70 | |||
71 | if (dev->of_node) { | ||
72 | pcm_conf->chan_names[SNDRV_PCM_STREAM_PLAYBACK] = tx; | ||
73 | pcm_conf->chan_names[SNDRV_PCM_STREAM_CAPTURE] = rx; | ||
74 | } else { | ||
75 | flags |= SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME; | ||
76 | } | ||
65 | 77 | ||
66 | return devm_snd_dmaengine_pcm_register(dev, | 78 | return devm_snd_dmaengine_pcm_register(dev, pcm_conf, flags); |
67 | &samsung_dmaengine_pcm_config, | ||
68 | SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME | | ||
69 | SND_DMAENGINE_PCM_FLAG_COMPAT); | ||
70 | } | 79 | } |
71 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); | 80 | EXPORT_SYMBOL_GPL(samsung_asoc_dma_platform_register); |
72 | 81 | ||
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 70a2559b63f9..50635ee8ff20 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/io.h> | 18 | #include <linux/io.h> |
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/of.h> | 20 | #include <linux/of.h> |
21 | #include <linux/of_device.h> | ||
21 | #include <linux/of_gpio.h> | 22 | #include <linux/of_gpio.h> |
22 | #include <linux/pm_runtime.h> | 23 | #include <linux/pm_runtime.h> |
23 | 24 | ||
@@ -1106,19 +1107,9 @@ static struct i2s_dai *i2s_alloc_dai(struct platform_device *pdev, bool sec) | |||
1106 | return i2s; | 1107 | return i2s; |
1107 | } | 1108 | } |
1108 | 1109 | ||
1109 | static const struct of_device_id exynos_i2s_match[]; | 1110 | static void i2s_free_sec_dai(struct i2s_dai *i2s) |
1110 | |||
1111 | static inline const struct samsung_i2s_dai_data *samsung_i2s_get_driver_data( | ||
1112 | struct platform_device *pdev) | ||
1113 | { | 1111 | { |
1114 | if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { | 1112 | platform_device_del(i2s->pdev); |
1115 | const struct of_device_id *match; | ||
1116 | match = of_match_node(exynos_i2s_match, pdev->dev.of_node); | ||
1117 | return match ? match->data : NULL; | ||
1118 | } else { | ||
1119 | return (struct samsung_i2s_dai_data *) | ||
1120 | platform_get_device_id(pdev)->driver_data; | ||
1121 | } | ||
1122 | } | 1113 | } |
1123 | 1114 | ||
1124 | #ifdef CONFIG_PM | 1115 | #ifdef CONFIG_PM |
@@ -1233,9 +1224,13 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1233 | const struct samsung_i2s_dai_data *i2s_dai_data; | 1224 | const struct samsung_i2s_dai_data *i2s_dai_data; |
1234 | int ret; | 1225 | int ret; |
1235 | 1226 | ||
1236 | /* Call during Seconday interface registration */ | 1227 | if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) |
1237 | i2s_dai_data = samsung_i2s_get_driver_data(pdev); | 1228 | i2s_dai_data = of_device_get_match_data(&pdev->dev); |
1229 | else | ||
1230 | i2s_dai_data = (struct samsung_i2s_dai_data *) | ||
1231 | platform_get_device_id(pdev)->driver_data; | ||
1238 | 1232 | ||
1233 | /* Call during the secondary interface registration */ | ||
1239 | if (i2s_dai_data->dai_type == TYPE_SEC) { | 1234 | if (i2s_dai_data->dai_type == TYPE_SEC) { |
1240 | sec_dai = dev_get_drvdata(&pdev->dev); | 1235 | sec_dai = dev_get_drvdata(&pdev->dev); |
1241 | if (!sec_dai) { | 1236 | if (!sec_dai) { |
@@ -1249,7 +1244,7 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1249 | return ret; | 1244 | return ret; |
1250 | 1245 | ||
1251 | return samsung_asoc_dma_platform_register(&pdev->dev, | 1246 | return samsung_asoc_dma_platform_register(&pdev->dev, |
1252 | sec_dai->filter); | 1247 | sec_dai->filter, "tx-sec", NULL); |
1253 | } | 1248 | } |
1254 | 1249 | ||
1255 | pri_dai = i2s_alloc_dai(pdev, false); | 1250 | pri_dai = i2s_alloc_dai(pdev, false); |
@@ -1350,17 +1345,28 @@ static int samsung_i2s_probe(struct platform_device *pdev) | |||
1350 | return -EINVAL; | 1345 | return -EINVAL; |
1351 | } | 1346 | } |
1352 | 1347 | ||
1353 | devm_snd_soc_register_component(&pri_dai->pdev->dev, | 1348 | ret = devm_snd_soc_register_component(&pri_dai->pdev->dev, |
1354 | &samsung_i2s_component, | 1349 | &samsung_i2s_component, |
1355 | &pri_dai->i2s_dai_drv, 1); | 1350 | &pri_dai->i2s_dai_drv, 1); |
1351 | if (ret < 0) | ||
1352 | goto err_free_dai; | ||
1353 | |||
1354 | ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter, | ||
1355 | NULL, NULL); | ||
1356 | if (ret < 0) | ||
1357 | goto err_free_dai; | ||
1356 | 1358 | ||
1357 | pm_runtime_enable(&pdev->dev); | 1359 | pm_runtime_enable(&pdev->dev); |
1358 | 1360 | ||
1359 | ret = samsung_asoc_dma_platform_register(&pdev->dev, pri_dai->filter); | 1361 | ret = i2s_register_clock_provider(pdev); |
1360 | if (ret != 0) | 1362 | if (!ret) |
1361 | return ret; | 1363 | return 0; |
1362 | 1364 | ||
1363 | return i2s_register_clock_provider(pdev); | 1365 | pm_runtime_disable(&pdev->dev); |
1366 | err_free_dai: | ||
1367 | if (sec_dai) | ||
1368 | i2s_free_sec_dai(sec_dai); | ||
1369 | return ret; | ||
1364 | } | 1370 | } |
1365 | 1371 | ||
1366 | static int samsung_i2s_remove(struct platform_device *pdev) | 1372 | static int samsung_i2s_remove(struct platform_device *pdev) |
@@ -1477,10 +1483,6 @@ static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = { | |||
1477 | .i2s_variant_regs = &i2sv5_i2s1_regs, | 1483 | .i2s_variant_regs = &i2sv5_i2s1_regs, |
1478 | }; | 1484 | }; |
1479 | 1485 | ||
1480 | static const struct samsung_i2s_dai_data samsung_dai_type_pri = { | ||
1481 | .dai_type = TYPE_PRI, | ||
1482 | }; | ||
1483 | |||
1484 | static const struct samsung_i2s_dai_data samsung_dai_type_sec = { | 1486 | static const struct samsung_i2s_dai_data samsung_dai_type_sec = { |
1485 | .dai_type = TYPE_SEC, | 1487 | .dai_type = TYPE_SEC, |
1486 | }; | 1488 | }; |
@@ -1492,9 +1494,6 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { | |||
1492 | }, { | 1494 | }, { |
1493 | .name = "samsung-i2s-sec", | 1495 | .name = "samsung-i2s-sec", |
1494 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, | 1496 | .driver_data = (kernel_ulong_t)&samsung_dai_type_sec, |
1495 | }, { | ||
1496 | .name = "samsung-i2sv4", | ||
1497 | .driver_data = (kernel_ulong_t)&i2sv5_dai_type, | ||
1498 | }, | 1497 | }, |
1499 | {}, | 1498 | {}, |
1500 | }; | 1499 | }; |
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c deleted file mode 100644 index 04217279fe25..000000000000 --- a/sound/soc/samsung/odroidx2_max98090.c +++ /dev/null | |||
@@ -1,185 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2014 Samsung Electronics Co., Ltd. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms of the GNU General Public License as published by the | ||
6 | * Free Software Foundation; either version 2 of the License, or (at your | ||
7 | * option) any later version. | ||
8 | */ | ||
9 | |||
10 | #include <linux/of.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <sound/soc.h> | ||
13 | #include <sound/pcm_params.h> | ||
14 | #include "i2s.h" | ||
15 | |||
16 | struct odroidx2_drv_data { | ||
17 | const struct snd_soc_dapm_widget *dapm_widgets; | ||
18 | unsigned int num_dapm_widgets; | ||
19 | }; | ||
20 | |||
21 | /* The I2S CDCLK output clock frequency for the MAX98090 codec */ | ||
22 | #define MAX98090_MCLK 19200000 | ||
23 | |||
24 | static struct snd_soc_dai_link odroidx2_dai[]; | ||
25 | |||
26 | static int odroidx2_late_probe(struct snd_soc_card *card) | ||
27 | { | ||
28 | struct snd_soc_pcm_runtime *rtd; | ||
29 | struct snd_soc_dai *codec_dai; | ||
30 | struct snd_soc_dai *cpu_dai; | ||
31 | int ret; | ||
32 | |||
33 | rtd = snd_soc_get_pcm_runtime(card, card->dai_link[0].name); | ||
34 | codec_dai = rtd->codec_dai; | ||
35 | cpu_dai = rtd->cpu_dai; | ||
36 | |||
37 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, MAX98090_MCLK, | ||
38 | SND_SOC_CLOCK_IN); | ||
39 | |||
40 | if (ret < 0 || of_find_property(odroidx2_dai[0].codec_of_node, | ||
41 | "clocks", NULL)) | ||
42 | return ret; | ||
43 | |||
44 | /* Set the cpu DAI configuration in order to use CDCLK */ | ||
45 | return snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK, | ||
46 | 0, SND_SOC_CLOCK_OUT); | ||
47 | } | ||
48 | |||
49 | static const struct snd_soc_dapm_widget odroidx2_dapm_widgets[] = { | ||
50 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
51 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
52 | SND_SOC_DAPM_MIC("DMIC", NULL), | ||
53 | }; | ||
54 | |||
55 | static const struct snd_soc_dapm_widget odroidu3_dapm_widgets[] = { | ||
56 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
57 | SND_SOC_DAPM_SPK("Speakers", NULL), | ||
58 | }; | ||
59 | |||
60 | static struct snd_soc_dai_link odroidx2_dai[] = { | ||
61 | { | ||
62 | .name = "MAX98090", | ||
63 | .stream_name = "MAX98090 PCM", | ||
64 | .codec_dai_name = "HiFi", | ||
65 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
66 | SND_SOC_DAIFMT_CBM_CFM, | ||
67 | } | ||
68 | }; | ||
69 | |||
70 | static struct snd_soc_card odroidx2 = { | ||
71 | .owner = THIS_MODULE, | ||
72 | .dai_link = odroidx2_dai, | ||
73 | .num_links = ARRAY_SIZE(odroidx2_dai), | ||
74 | .fully_routed = true, | ||
75 | .late_probe = odroidx2_late_probe, | ||
76 | }; | ||
77 | |||
78 | static const struct odroidx2_drv_data odroidx2_drvdata = { | ||
79 | .dapm_widgets = odroidx2_dapm_widgets, | ||
80 | .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), | ||
81 | }; | ||
82 | |||
83 | static const struct odroidx2_drv_data odroidu3_drvdata = { | ||
84 | .dapm_widgets = odroidu3_dapm_widgets, | ||
85 | .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), | ||
86 | }; | ||
87 | |||
88 | static const struct of_device_id odroidx2_audio_of_match[] = { | ||
89 | { | ||
90 | .compatible = "samsung,odroidx2-audio", | ||
91 | .data = &odroidx2_drvdata, | ||
92 | }, { | ||
93 | .compatible = "samsung,odroidu3-audio", | ||
94 | .data = &odroidu3_drvdata, | ||
95 | }, | ||
96 | { }, | ||
97 | }; | ||
98 | MODULE_DEVICE_TABLE(of, odroidx2_audio_of_match); | ||
99 | |||
100 | static int odroidx2_audio_probe(struct platform_device *pdev) | ||
101 | { | ||
102 | struct device_node *snd_node = pdev->dev.of_node; | ||
103 | struct snd_soc_card *card = &odroidx2; | ||
104 | struct device_node *i2s_node, *codec_node; | ||
105 | struct odroidx2_drv_data *dd; | ||
106 | const struct of_device_id *of_id; | ||
107 | int ret; | ||
108 | |||
109 | of_id = of_match_node(odroidx2_audio_of_match, snd_node); | ||
110 | dd = (struct odroidx2_drv_data *)of_id->data; | ||
111 | |||
112 | card->num_dapm_widgets = dd->num_dapm_widgets; | ||
113 | card->dapm_widgets = dd->dapm_widgets; | ||
114 | |||
115 | card->dev = &pdev->dev; | ||
116 | |||
117 | ret = snd_soc_of_parse_card_name(card, "samsung,model"); | ||
118 | if (ret < 0) | ||
119 | return ret; | ||
120 | |||
121 | ret = snd_soc_of_parse_audio_routing(card, "samsung,audio-routing"); | ||
122 | if (ret < 0) | ||
123 | return ret; | ||
124 | |||
125 | codec_node = of_parse_phandle(snd_node, "samsung,audio-codec", 0); | ||
126 | if (!codec_node) { | ||
127 | dev_err(&pdev->dev, | ||
128 | "Failed parsing samsung,i2s-codec property\n"); | ||
129 | return -EINVAL; | ||
130 | } | ||
131 | |||
132 | i2s_node = of_parse_phandle(snd_node, "samsung,i2s-controller", 0); | ||
133 | if (!i2s_node) { | ||
134 | dev_err(&pdev->dev, | ||
135 | "Failed parsing samsung,i2s-controller property\n"); | ||
136 | ret = -EINVAL; | ||
137 | goto err_put_codec_n; | ||
138 | } | ||
139 | |||
140 | odroidx2_dai[0].codec_of_node = codec_node; | ||
141 | odroidx2_dai[0].cpu_of_node = i2s_node; | ||
142 | odroidx2_dai[0].platform_of_node = i2s_node; | ||
143 | |||
144 | ret = snd_soc_register_card(card); | ||
145 | if (ret) { | ||
146 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
147 | ret); | ||
148 | goto err_put_i2s_n; | ||
149 | } | ||
150 | return 0; | ||
151 | |||
152 | err_put_i2s_n: | ||
153 | of_node_put(i2s_node); | ||
154 | err_put_codec_n: | ||
155 | of_node_put(codec_node); | ||
156 | return ret; | ||
157 | } | ||
158 | |||
159 | static int odroidx2_audio_remove(struct platform_device *pdev) | ||
160 | { | ||
161 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
162 | |||
163 | snd_soc_unregister_card(card); | ||
164 | |||
165 | of_node_put(odroidx2_dai[0].cpu_of_node); | ||
166 | of_node_put(odroidx2_dai[0].codec_of_node); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static struct platform_driver odroidx2_audio_driver = { | ||
172 | .driver = { | ||
173 | .name = "odroidx2-audio", | ||
174 | .of_match_table = odroidx2_audio_of_match, | ||
175 | .pm = &snd_soc_pm_ops, | ||
176 | }, | ||
177 | .probe = odroidx2_audio_probe, | ||
178 | .remove = odroidx2_audio_remove, | ||
179 | }; | ||
180 | module_platform_driver(odroidx2_audio_driver); | ||
181 | |||
182 | MODULE_AUTHOR("Chen Zhen <zhen1.chen@samsung.com>"); | ||
183 | MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>"); | ||
184 | MODULE_DESCRIPTION("ALSA SoC Odroid X2/U3 Audio Support"); | ||
185 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 498f563a4c9c..490c1a87fd66 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c | |||
@@ -576,7 +576,8 @@ static int s3c_pcm_dev_probe(struct platform_device *pdev) | |||
576 | goto err5; | 576 | goto err5; |
577 | } | 577 | } |
578 | 578 | ||
579 | ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); | 579 | ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, |
580 | NULL, NULL); | ||
580 | if (ret) { | 581 | if (ret) { |
581 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); | 582 | dev_err(&pdev->dev, "failed to get register DMA: %d\n", ret); |
582 | goto err5; | 583 | goto err5; |
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index b6ab3fc5789e..bf8ae79b0fd2 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c | |||
@@ -268,7 +268,7 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
268 | iismod &= ~S3C2412_IISMOD_SLAVE; | 268 | iismod &= ~S3C2412_IISMOD_SLAVE; |
269 | break; | 269 | break; |
270 | default: | 270 | default: |
271 | pr_err("unknwon master/slave format\n"); | 271 | pr_err("unknown master/slave format\n"); |
272 | return -EINVAL; | 272 | return -EINVAL; |
273 | } | 273 | } |
274 | 274 | ||
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 204029d12f5b..d45dffb297d8 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c | |||
@@ -177,7 +177,8 @@ static int s3c2412_iis_dev_probe(struct platform_device *pdev) | |||
177 | } | 177 | } |
178 | 178 | ||
179 | ret = samsung_asoc_dma_platform_register(&pdev->dev, | 179 | ret = samsung_asoc_dma_platform_register(&pdev->dev, |
180 | pdata->dma_filter); | 180 | pdata->dma_filter, |
181 | NULL, NULL); | ||
181 | if (ret) | 182 | if (ret) |
182 | pr_err("failed to register the DMA: %d\n", ret); | 183 | pr_err("failed to register the DMA: %d\n", ret); |
183 | 184 | ||
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index b3a475d73ba7..3e76f2a75a24 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c | |||
@@ -482,7 +482,8 @@ static int s3c24xx_iis_dev_probe(struct platform_device *pdev) | |||
482 | } | 482 | } |
483 | 483 | ||
484 | ret = samsung_asoc_dma_platform_register(&pdev->dev, | 484 | ret = samsung_asoc_dma_platform_register(&pdev->dev, |
485 | pdata->dma_filter); | 485 | pdata->dma_filter, |
486 | NULL, NULL); | ||
486 | if (ret) | 487 | if (ret) |
487 | pr_err("failed to register the dma: %d\n", ret); | 488 | pr_err("failed to register the dma: %d\n", ret); |
488 | 489 | ||
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index 4687f521197c..0cb9c8567546 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c | |||
@@ -435,7 +435,8 @@ static int spdif_probe(struct platform_device *pdev) | |||
435 | 435 | ||
436 | spdif->dma_playback = &spdif_stereo_out; | 436 | spdif->dma_playback = &spdif_stereo_out; |
437 | 437 | ||
438 | ret = samsung_asoc_dma_platform_register(&pdev->dev, filter); | 438 | ret = samsung_asoc_dma_platform_register(&pdev->dev, filter, |
439 | NULL, NULL); | ||
439 | if (ret) { | 440 | if (ret) { |
440 | dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); | 441 | dev_err(&pdev->dev, "failed to register DMA: %d\n", ret); |
441 | goto err4; | 442 | goto err4; |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index c9902a6d6fa0..9311f119feb5 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -44,6 +44,7 @@ config SND_SOC_RCAR | |||
44 | 44 | ||
45 | config SND_SOC_RSRC_CARD | 45 | config SND_SOC_RSRC_CARD |
46 | tristate "Renesas Sampling Rate Convert Sound Card" | 46 | tristate "Renesas Sampling Rate Convert Sound Card" |
47 | select SND_SIMPLE_CARD_UTILS | ||
47 | help | 48 | help |
48 | This option enables simple sound if you need sampling rate convert | 49 | This option enables simple sound if you need sampling rate convert |
49 | 50 | ||
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index c4c51a4d3c8f..2145957d0229 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -33,11 +33,15 @@ struct rsnd_adg { | |||
33 | struct clk *clkout[CLKOUTMAX]; | 33 | struct clk *clkout[CLKOUTMAX]; |
34 | struct clk_onecell_data onecell; | 34 | struct clk_onecell_data onecell; |
35 | struct rsnd_mod mod; | 35 | struct rsnd_mod mod; |
36 | u32 flags; | ||
36 | 37 | ||
37 | int rbga_rate_for_441khz; /* RBGA */ | 38 | int rbga_rate_for_441khz; /* RBGA */ |
38 | int rbgb_rate_for_48khz; /* RBGB */ | 39 | int rbgb_rate_for_48khz; /* RBGB */ |
39 | }; | 40 | }; |
40 | 41 | ||
42 | #define LRCLK_ASYNC (1 << 0) | ||
43 | #define adg_mode_flags(adg) (adg->flags) | ||
44 | |||
41 | #define for_each_rsnd_clk(pos, adg, i) \ | 45 | #define for_each_rsnd_clk(pos, adg, i) \ |
42 | for (i = 0; \ | 46 | for (i = 0; \ |
43 | (i < CLKMAX) && \ | 47 | (i < CLKMAX) && \ |
@@ -355,6 +359,16 @@ found_clock: | |||
355 | 359 | ||
356 | rsnd_adg_set_ssi_clk(ssi_mod, data); | 360 | rsnd_adg_set_ssi_clk(ssi_mod, data); |
357 | 361 | ||
362 | if (!(adg_mode_flags(adg) & LRCLK_ASYNC)) { | ||
363 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); | ||
364 | u32 ckr = 0; | ||
365 | |||
366 | if (0 == (rate % 8000)) | ||
367 | ckr = 0x80000000; | ||
368 | |||
369 | rsnd_mod_bset(adg_mod, SSICKR, 0x80000000, ckr); | ||
370 | } | ||
371 | |||
358 | dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", | 372 | dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", |
359 | rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), | 373 | rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), |
360 | data, rate); | 374 | data, rate); |
@@ -532,6 +546,7 @@ int rsnd_adg_probe(struct rsnd_priv *priv) | |||
532 | { | 546 | { |
533 | struct rsnd_adg *adg; | 547 | struct rsnd_adg *adg; |
534 | struct device *dev = rsnd_priv_to_dev(priv); | 548 | struct device *dev = rsnd_priv_to_dev(priv); |
549 | struct device_node *np = dev->of_node; | ||
535 | 550 | ||
536 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); | 551 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); |
537 | if (!adg) { | 552 | if (!adg) { |
@@ -545,6 +560,9 @@ int rsnd_adg_probe(struct rsnd_priv *priv) | |||
545 | rsnd_adg_get_clkin(priv, adg); | 560 | rsnd_adg_get_clkin(priv, adg); |
546 | rsnd_adg_get_clkout(priv, adg); | 561 | rsnd_adg_get_clkout(priv, adg); |
547 | 562 | ||
563 | if (of_get_property(np, "clkout-lr-asynchronous", NULL)) | ||
564 | adg->flags = LRCLK_ASYNC; | ||
565 | |||
548 | priv->adg = adg; | 566 | priv->adg = adg; |
549 | 567 | ||
550 | return 0; | 568 | return 0; |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 46c0ba7b6414..7d2fdf8dd188 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -206,7 +206,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
206 | */ | 206 | */ |
207 | static int rsnd_gen2_probe(struct rsnd_priv *priv) | 207 | static int rsnd_gen2_probe(struct rsnd_priv *priv) |
208 | { | 208 | { |
209 | const static struct rsnd_regmap_field_conf conf_ssiu[] = { | 209 | static const struct rsnd_regmap_field_conf conf_ssiu[] = { |
210 | RSND_GEN_S_REG(SSI_MODE0, 0x800), | 210 | RSND_GEN_S_REG(SSI_MODE0, 0x800), |
211 | RSND_GEN_S_REG(SSI_MODE1, 0x804), | 211 | RSND_GEN_S_REG(SSI_MODE1, 0x804), |
212 | RSND_GEN_S_REG(SSI_MODE2, 0x808), | 212 | RSND_GEN_S_REG(SSI_MODE2, 0x808), |
@@ -221,7 +221,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) | |||
221 | RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), | 221 | RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), |
222 | }; | 222 | }; |
223 | 223 | ||
224 | const static struct rsnd_regmap_field_conf conf_scu[] = { | 224 | static const struct rsnd_regmap_field_conf conf_scu[] = { |
225 | RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), | 225 | RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), |
226 | RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), | 226 | RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), |
227 | RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), | 227 | RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), |
@@ -308,7 +308,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) | |||
308 | RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), | 308 | RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), |
309 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), | 309 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), |
310 | }; | 310 | }; |
311 | const static struct rsnd_regmap_field_conf conf_adg[] = { | 311 | static const struct rsnd_regmap_field_conf conf_adg[] = { |
312 | RSND_GEN_S_REG(BRRA, 0x00), | 312 | RSND_GEN_S_REG(BRRA, 0x00), |
313 | RSND_GEN_S_REG(BRRB, 0x04), | 313 | RSND_GEN_S_REG(BRRB, 0x04), |
314 | RSND_GEN_S_REG(SSICKR, 0x08), | 314 | RSND_GEN_S_REG(SSICKR, 0x08), |
@@ -328,7 +328,7 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) | |||
328 | RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), | 328 | RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), |
329 | RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), | 329 | RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), |
330 | }; | 330 | }; |
331 | const static struct rsnd_regmap_field_conf conf_ssi[] = { | 331 | static const struct rsnd_regmap_field_conf conf_ssi[] = { |
332 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | 332 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), |
333 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | 333 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), |
334 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | 334 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), |
@@ -359,14 +359,14 @@ static int rsnd_gen2_probe(struct rsnd_priv *priv) | |||
359 | 359 | ||
360 | static int rsnd_gen1_probe(struct rsnd_priv *priv) | 360 | static int rsnd_gen1_probe(struct rsnd_priv *priv) |
361 | { | 361 | { |
362 | const static struct rsnd_regmap_field_conf conf_adg[] = { | 362 | static const struct rsnd_regmap_field_conf conf_adg[] = { |
363 | RSND_GEN_S_REG(BRRA, 0x00), | 363 | RSND_GEN_S_REG(BRRA, 0x00), |
364 | RSND_GEN_S_REG(BRRB, 0x04), | 364 | RSND_GEN_S_REG(BRRB, 0x04), |
365 | RSND_GEN_S_REG(SSICKR, 0x08), | 365 | RSND_GEN_S_REG(SSICKR, 0x08), |
366 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), | 366 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), |
367 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), | 367 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), |
368 | }; | 368 | }; |
369 | const static struct rsnd_regmap_field_conf conf_ssi[] = { | 369 | static const struct rsnd_regmap_field_conf conf_ssi[] = { |
370 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | 370 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), |
371 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | 371 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), |
372 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | 372 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), |
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 1bc7ecfc42a9..fa37f842b62f 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <sound/jack.h> | 20 | #include <sound/jack.h> |
21 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
22 | #include <sound/soc-dai.h> | 22 | #include <sound/soc-dai.h> |
23 | #include <sound/simple_card_utils.h> | ||
23 | 24 | ||
24 | struct rsrc_card_of_data { | 25 | struct rsrc_card_of_data { |
25 | const char *prefix; | 26 | const char *prefix; |
@@ -46,25 +47,13 @@ static const struct of_device_id rsrc_card_of_match[] = { | |||
46 | }; | 47 | }; |
47 | MODULE_DEVICE_TABLE(of, rsrc_card_of_match); | 48 | MODULE_DEVICE_TABLE(of, rsrc_card_of_match); |
48 | 49 | ||
49 | #define DAI_NAME_NUM 32 | ||
50 | struct rsrc_card_dai { | ||
51 | unsigned int sysclk; | ||
52 | unsigned int tx_slot_mask; | ||
53 | unsigned int rx_slot_mask; | ||
54 | int slots; | ||
55 | int slot_width; | ||
56 | struct clk *clk; | ||
57 | char dai_name[DAI_NAME_NUM]; | ||
58 | }; | ||
59 | |||
60 | #define IDX_CPU 0 | 50 | #define IDX_CPU 0 |
61 | #define IDX_CODEC 1 | 51 | #define IDX_CODEC 1 |
62 | struct rsrc_card_priv { | 52 | struct rsrc_card_priv { |
63 | struct snd_soc_card snd_card; | 53 | struct snd_soc_card snd_card; |
64 | struct snd_soc_codec_conf codec_conf; | 54 | struct snd_soc_codec_conf codec_conf; |
65 | struct rsrc_card_dai *dai_props; | 55 | struct asoc_simple_dai *dai_props; |
66 | struct snd_soc_dai_link *dai_link; | 56 | struct snd_soc_dai_link *dai_link; |
67 | int dai_num; | ||
68 | u32 convert_rate; | 57 | u32 convert_rate; |
69 | u32 convert_channels; | 58 | u32 convert_channels; |
70 | }; | 59 | }; |
@@ -77,7 +66,7 @@ static int rsrc_card_startup(struct snd_pcm_substream *substream) | |||
77 | { | 66 | { |
78 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 67 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
79 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | 68 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); |
80 | struct rsrc_card_dai *dai_props = | 69 | struct asoc_simple_dai *dai_props = |
81 | rsrc_priv_to_props(priv, rtd->num); | 70 | rsrc_priv_to_props(priv, rtd->num); |
82 | 71 | ||
83 | return clk_prepare_enable(dai_props->clk); | 72 | return clk_prepare_enable(dai_props->clk); |
@@ -87,7 +76,7 @@ static void rsrc_card_shutdown(struct snd_pcm_substream *substream) | |||
87 | { | 76 | { |
88 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 77 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
89 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | 78 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); |
90 | struct rsrc_card_dai *dai_props = | 79 | struct asoc_simple_dai *dai_props = |
91 | rsrc_priv_to_props(priv, rtd->num); | 80 | rsrc_priv_to_props(priv, rtd->num); |
92 | 81 | ||
93 | clk_disable_unprepare(dai_props->clk); | 82 | clk_disable_unprepare(dai_props->clk); |
@@ -103,7 +92,7 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
103 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | 92 | struct rsrc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); |
104 | struct snd_soc_dai *dai; | 93 | struct snd_soc_dai *dai; |
105 | struct snd_soc_dai_link *dai_link; | 94 | struct snd_soc_dai_link *dai_link; |
106 | struct rsrc_card_dai *dai_props; | 95 | struct asoc_simple_dai *dai_props; |
107 | int num = rtd->num; | 96 | int num = rtd->num; |
108 | int ret; | 97 | int ret; |
109 | 98 | ||
@@ -159,44 +148,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | |||
159 | return 0; | 148 | return 0; |
160 | } | 149 | } |
161 | 150 | ||
162 | static int rsrc_card_parse_daifmt(struct device_node *node, | ||
163 | struct device_node *codec, | ||
164 | struct rsrc_card_priv *priv, | ||
165 | struct snd_soc_dai_link *dai_link, | ||
166 | unsigned int *retfmt) | ||
167 | { | ||
168 | struct device_node *bitclkmaster = NULL; | ||
169 | struct device_node *framemaster = NULL; | ||
170 | unsigned int daifmt; | ||
171 | |||
172 | daifmt = snd_soc_of_parse_daifmt(node, NULL, | ||
173 | &bitclkmaster, &framemaster); | ||
174 | daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK; | ||
175 | |||
176 | if (!bitclkmaster && !framemaster) | ||
177 | return -EINVAL; | ||
178 | |||
179 | if (codec == bitclkmaster) | ||
180 | daifmt |= (codec == framemaster) ? | ||
181 | SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS; | ||
182 | else | ||
183 | daifmt |= (codec == framemaster) ? | ||
184 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | ||
185 | |||
186 | of_node_put(bitclkmaster); | ||
187 | of_node_put(framemaster); | ||
188 | |||
189 | *retfmt = daifmt; | ||
190 | |||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int rsrc_card_parse_links(struct device_node *np, | 151 | static int rsrc_card_parse_links(struct device_node *np, |
195 | struct rsrc_card_priv *priv, | 152 | struct rsrc_card_priv *priv, |
196 | int idx, bool is_fe) | 153 | int idx, bool is_fe) |
197 | { | 154 | { |
155 | struct device *dev = rsrc_priv_to_dev(priv); | ||
198 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | 156 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); |
199 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | 157 | struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); |
200 | struct of_phandle_args args; | 158 | struct of_phandle_args args; |
201 | int ret; | 159 | int ret; |
202 | 160 | ||
@@ -232,9 +190,11 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
232 | if (ret < 0) | 190 | if (ret < 0) |
233 | return ret; | 191 | return ret; |
234 | 192 | ||
235 | /* set dai_name */ | 193 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, |
236 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", | 194 | "fe.%s", |
237 | dai_link->cpu_dai_name); | 195 | dai_link->cpu_dai_name); |
196 | if (ret < 0) | ||
197 | return ret; | ||
238 | 198 | ||
239 | /* | 199 | /* |
240 | * In soc_bind_dai_link() will check cpu name after | 200 | * In soc_bind_dai_link() will check cpu name after |
@@ -248,7 +208,6 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
248 | if (!args.args_count) | 208 | if (!args.args_count) |
249 | dai_link->cpu_dai_name = NULL; | 209 | dai_link->cpu_dai_name = NULL; |
250 | } else { | 210 | } else { |
251 | struct device *dev = rsrc_priv_to_dev(priv); | ||
252 | const struct rsrc_card_of_data *of_data; | 211 | const struct rsrc_card_of_data *of_data; |
253 | 212 | ||
254 | of_data = of_device_get_match_data(dev); | 213 | of_data = of_device_get_match_data(dev); |
@@ -266,6 +225,12 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
266 | if (ret < 0) | 225 | if (ret < 0) |
267 | return ret; | 226 | return ret; |
268 | 227 | ||
228 | ret = asoc_simple_card_set_dailink_name(dev, dai_link, | ||
229 | "be.%s", | ||
230 | dai_link->codec_dai_name); | ||
231 | if (ret < 0) | ||
232 | return ret; | ||
233 | |||
269 | /* additional name prefix */ | 234 | /* additional name prefix */ |
270 | if (of_data) { | 235 | if (of_data) { |
271 | priv->codec_conf.of_node = dai_link->codec_of_node; | 236 | priv->codec_conf.of_node = dai_link->codec_of_node; |
@@ -276,18 +241,12 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
276 | dai_link->codec_of_node, | 241 | dai_link->codec_of_node, |
277 | "audio-prefix"); | 242 | "audio-prefix"); |
278 | } | 243 | } |
279 | |||
280 | /* set dai_name */ | ||
281 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s", | ||
282 | dai_link->codec_dai_name); | ||
283 | } | 244 | } |
284 | 245 | ||
285 | /* Simple Card assumes platform == cpu */ | 246 | /* Simple Card assumes platform == cpu */ |
286 | dai_link->platform_of_node = dai_link->cpu_of_node; | 247 | dai_link->platform_of_node = dai_link->cpu_of_node; |
287 | dai_link->dpcm_playback = 1; | 248 | dai_link->dpcm_playback = 1; |
288 | dai_link->dpcm_capture = 1; | 249 | dai_link->dpcm_capture = 1; |
289 | dai_link->name = dai_props->dai_name; | ||
290 | dai_link->stream_name = dai_props->dai_name; | ||
291 | dai_link->ops = &rsrc_card_ops; | 250 | dai_link->ops = &rsrc_card_ops; |
292 | dai_link->init = rsrc_card_dai_init; | 251 | dai_link->init = rsrc_card_dai_init; |
293 | 252 | ||
@@ -299,7 +258,7 @@ static int rsrc_card_parse_clk(struct device_node *np, | |||
299 | int idx, bool is_fe) | 258 | int idx, bool is_fe) |
300 | { | 259 | { |
301 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | 260 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); |
302 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | 261 | struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); |
303 | struct clk *clk; | 262 | struct clk *clk; |
304 | struct device_node *of_np = is_fe ? dai_link->cpu_of_node : | 263 | struct device_node *of_np = is_fe ? dai_link->cpu_of_node : |
305 | dai_link->codec_of_node; | 264 | dai_link->codec_of_node; |
@@ -336,7 +295,7 @@ static int rsrc_card_dai_sub_link_of(struct device_node *node, | |||
336 | { | 295 | { |
337 | struct device *dev = rsrc_priv_to_dev(priv); | 296 | struct device *dev = rsrc_priv_to_dev(priv); |
338 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | 297 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); |
339 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | 298 | struct asoc_simple_dai *dai_props = rsrc_priv_to_props(priv, idx); |
340 | int ret; | 299 | int ret; |
341 | 300 | ||
342 | ret = rsrc_card_parse_links(np, priv, idx, is_fe); | 301 | ret = rsrc_card_parse_links(np, priv, idx, is_fe); |
@@ -348,7 +307,7 @@ static int rsrc_card_dai_sub_link_of(struct device_node *node, | |||
348 | return ret; | 307 | return ret; |
349 | 308 | ||
350 | dev_dbg(dev, "\t%s / %04x / %d\n", | 309 | dev_dbg(dev, "\t%s / %04x / %d\n", |
351 | dai_props->dai_name, | 310 | dai_link->name, |
352 | dai_link->dai_fmt, | 311 | dai_link->dai_fmt, |
353 | dai_props->sysclk); | 312 | dai_props->sysclk); |
354 | 313 | ||
@@ -358,6 +317,7 @@ static int rsrc_card_dai_sub_link_of(struct device_node *node, | |||
358 | static int rsrc_card_dai_link_of(struct device_node *node, | 317 | static int rsrc_card_dai_link_of(struct device_node *node, |
359 | struct rsrc_card_priv *priv) | 318 | struct rsrc_card_priv *priv) |
360 | { | 319 | { |
320 | struct device *dev = rsrc_priv_to_dev(priv); | ||
361 | struct snd_soc_dai_link *dai_link; | 321 | struct snd_soc_dai_link *dai_link; |
362 | struct device_node *np; | 322 | struct device_node *np; |
363 | unsigned int daifmt = 0; | 323 | unsigned int daifmt = 0; |
@@ -370,8 +330,8 @@ static int rsrc_card_dai_link_of(struct device_node *node, | |||
370 | dai_link = rsrc_priv_to_link(priv, i); | 330 | dai_link = rsrc_priv_to_link(priv, i); |
371 | 331 | ||
372 | if (strcmp(np->name, "codec") == 0) { | 332 | if (strcmp(np->name, "codec") == 0) { |
373 | ret = rsrc_card_parse_daifmt(node, np, priv, | 333 | ret = asoc_simple_card_parse_daifmt(dev, node, np, |
374 | dai_link, &daifmt); | 334 | NULL, &daifmt); |
375 | if (ret < 0) | 335 | if (ret < 0) |
376 | return ret; | 336 | return ret; |
377 | break; | 337 | break; |
@@ -402,7 +362,7 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
402 | struct device *dev) | 362 | struct device *dev) |
403 | { | 363 | { |
404 | const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev); | 364 | const struct rsrc_card_of_data *of_data = of_device_get_match_data(dev); |
405 | struct rsrc_card_dai *props; | 365 | struct asoc_simple_dai *props; |
406 | struct snd_soc_dai_link *links; | 366 | struct snd_soc_dai_link *links; |
407 | int ret; | 367 | int ret; |
408 | int num; | 368 | int num; |
@@ -418,7 +378,6 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
418 | 378 | ||
419 | priv->dai_props = props; | 379 | priv->dai_props = props; |
420 | priv->dai_link = links; | 380 | priv->dai_link = links; |
421 | priv->dai_num = num; | ||
422 | 381 | ||
423 | /* Init snd_soc_card */ | 382 | /* Init snd_soc_card */ |
424 | priv->snd_card.owner = THIS_MODULE; | 383 | priv->snd_card.owner = THIS_MODULE; |
@@ -436,9 +395,6 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
436 | "audio-routing"); | 395 | "audio-routing"); |
437 | } | 396 | } |
438 | 397 | ||
439 | /* Parse the card name from DT */ | ||
440 | snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); | ||
441 | |||
442 | /* sampling rate convert */ | 398 | /* sampling rate convert */ |
443 | of_property_read_u32(node, "convert-rate", &priv->convert_rate); | 399 | of_property_read_u32(node, "convert-rate", &priv->convert_rate); |
444 | 400 | ||
@@ -454,8 +410,9 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
454 | if (ret < 0) | 410 | if (ret < 0) |
455 | return ret; | 411 | return ret; |
456 | 412 | ||
457 | if (!priv->snd_card.name) | 413 | ret = asoc_simple_card_parse_card_name(&priv->snd_card, "card-"); |
458 | priv->snd_card.name = priv->snd_card.dai_link->name; | 414 | if (ret < 0) |
415 | return ret; | ||
459 | 416 | ||
460 | return 0; | 417 | return 0; |
461 | } | 418 | } |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 875733c52953..d2df46c14c68 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -530,14 +530,15 @@ static int soc_compr_pointer(struct snd_compr_stream *cstream, | |||
530 | { | 530 | { |
531 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 531 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
532 | struct snd_soc_platform *platform = rtd->platform; | 532 | struct snd_soc_platform *platform = rtd->platform; |
533 | int ret = 0; | ||
533 | 534 | ||
534 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 535 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
535 | 536 | ||
536 | if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) | 537 | if (platform->driver->compr_ops && platform->driver->compr_ops->pointer) |
537 | platform->driver->compr_ops->pointer(cstream, tstamp); | 538 | ret = platform->driver->compr_ops->pointer(cstream, tstamp); |
538 | 539 | ||
539 | mutex_unlock(&rtd->pcm_mutex); | 540 | mutex_unlock(&rtd->pcm_mutex); |
540 | return 0; | 541 | return ret; |
541 | } | 542 | } |
542 | 543 | ||
543 | static int soc_compr_copy(struct snd_compr_stream *cstream, | 544 | static int soc_compr_copy(struct snd_compr_stream *cstream, |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index c4464858bf01..8698c26773b3 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -1073,7 +1073,11 @@ static int dapm_widget_list_create(struct snd_soc_dapm_widget_list **list, | |||
1073 | */ | 1073 | */ |
1074 | static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, | 1074 | static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, |
1075 | struct list_head *list, enum snd_soc_dapm_direction dir, | 1075 | struct list_head *list, enum snd_soc_dapm_direction dir, |
1076 | int (*fn)(struct snd_soc_dapm_widget *, struct list_head *)) | 1076 | int (*fn)(struct snd_soc_dapm_widget *, struct list_head *, |
1077 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, | ||
1078 | enum snd_soc_dapm_direction)), | ||
1079 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, | ||
1080 | enum snd_soc_dapm_direction)) | ||
1077 | { | 1081 | { |
1078 | enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); | 1082 | enum snd_soc_dapm_direction rdir = SND_SOC_DAPM_DIR_REVERSE(dir); |
1079 | struct snd_soc_dapm_path *path; | 1083 | struct snd_soc_dapm_path *path; |
@@ -1088,6 +1092,11 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, | |||
1088 | if (list) | 1092 | if (list) |
1089 | list_add_tail(&widget->work_list, list); | 1093 | list_add_tail(&widget->work_list, list); |
1090 | 1094 | ||
1095 | if (custom_stop_condition && custom_stop_condition(widget, dir)) { | ||
1096 | widget->endpoints[dir] = 1; | ||
1097 | return widget->endpoints[dir]; | ||
1098 | } | ||
1099 | |||
1091 | if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { | 1100 | if ((widget->is_ep & SND_SOC_DAPM_DIR_TO_EP(dir)) && widget->connected) { |
1092 | widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget); | 1101 | widget->endpoints[dir] = snd_soc_dapm_suspend_check(widget); |
1093 | return widget->endpoints[dir]; | 1102 | return widget->endpoints[dir]; |
@@ -1106,7 +1115,7 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, | |||
1106 | 1115 | ||
1107 | if (path->connect) { | 1116 | if (path->connect) { |
1108 | path->walking = 1; | 1117 | path->walking = 1; |
1109 | con += fn(path->node[dir], list); | 1118 | con += fn(path->node[dir], list, custom_stop_condition); |
1110 | path->walking = 0; | 1119 | path->walking = 0; |
1111 | } | 1120 | } |
1112 | } | 1121 | } |
@@ -1119,23 +1128,37 @@ static __always_inline int is_connected_ep(struct snd_soc_dapm_widget *widget, | |||
1119 | /* | 1128 | /* |
1120 | * Recursively check for a completed path to an active or physically connected | 1129 | * Recursively check for a completed path to an active or physically connected |
1121 | * output widget. Returns number of complete paths. | 1130 | * output widget. Returns number of complete paths. |
1131 | * | ||
1132 | * Optionally, can be supplied with a function acting as a stopping condition. | ||
1133 | * This function takes the dapm widget currently being examined and the walk | ||
1134 | * direction as an arguments, it should return true if the walk should be | ||
1135 | * stopped and false otherwise. | ||
1122 | */ | 1136 | */ |
1123 | static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | 1137 | static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, |
1124 | struct list_head *list) | 1138 | struct list_head *list, |
1139 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i, | ||
1140 | enum snd_soc_dapm_direction)) | ||
1125 | { | 1141 | { |
1126 | return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT, | 1142 | return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_OUT, |
1127 | is_connected_output_ep); | 1143 | is_connected_output_ep, custom_stop_condition); |
1128 | } | 1144 | } |
1129 | 1145 | ||
1130 | /* | 1146 | /* |
1131 | * Recursively check for a completed path to an active or physically connected | 1147 | * Recursively check for a completed path to an active or physically connected |
1132 | * input widget. Returns number of complete paths. | 1148 | * input widget. Returns number of complete paths. |
1149 | * | ||
1150 | * Optionally, can be supplied with a function acting as a stopping condition. | ||
1151 | * This function takes the dapm widget currently being examined and the walk | ||
1152 | * direction as an arguments, it should return true if the walk should be | ||
1153 | * stopped and false otherwise. | ||
1133 | */ | 1154 | */ |
1134 | static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | 1155 | static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, |
1135 | struct list_head *list) | 1156 | struct list_head *list, |
1157 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *i, | ||
1158 | enum snd_soc_dapm_direction)) | ||
1136 | { | 1159 | { |
1137 | return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN, | 1160 | return is_connected_ep(widget, list, SND_SOC_DAPM_DIR_IN, |
1138 | is_connected_input_ep); | 1161 | is_connected_input_ep, custom_stop_condition); |
1139 | } | 1162 | } |
1140 | 1163 | ||
1141 | /** | 1164 | /** |
@@ -1143,15 +1166,24 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
1143 | * @dai: the soc DAI. | 1166 | * @dai: the soc DAI. |
1144 | * @stream: stream direction. | 1167 | * @stream: stream direction. |
1145 | * @list: list of active widgets for this stream. | 1168 | * @list: list of active widgets for this stream. |
1169 | * @custom_stop_condition: (optional) a function meant to stop the widget graph | ||
1170 | * walk based on custom logic. | ||
1146 | * | 1171 | * |
1147 | * Queries DAPM graph as to whether an valid audio stream path exists for | 1172 | * Queries DAPM graph as to whether an valid audio stream path exists for |
1148 | * the initial stream specified by name. This takes into account | 1173 | * the initial stream specified by name. This takes into account |
1149 | * current mixer and mux kcontrol settings. Creates list of valid widgets. | 1174 | * current mixer and mux kcontrol settings. Creates list of valid widgets. |
1150 | * | 1175 | * |
1176 | * Optionally, can be supplied with a function acting as a stopping condition. | ||
1177 | * This function takes the dapm widget currently being examined and the walk | ||
1178 | * direction as an arguments, it should return true if the walk should be | ||
1179 | * stopped and false otherwise. | ||
1180 | * | ||
1151 | * Returns the number of valid paths or negative error. | 1181 | * Returns the number of valid paths or negative error. |
1152 | */ | 1182 | */ |
1153 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | 1183 | int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, |
1154 | struct snd_soc_dapm_widget_list **list) | 1184 | struct snd_soc_dapm_widget_list **list, |
1185 | bool (*custom_stop_condition)(struct snd_soc_dapm_widget *, | ||
1186 | enum snd_soc_dapm_direction)) | ||
1155 | { | 1187 | { |
1156 | struct snd_soc_card *card = dai->component->card; | 1188 | struct snd_soc_card *card = dai->component->card; |
1157 | struct snd_soc_dapm_widget *w; | 1189 | struct snd_soc_dapm_widget *w; |
@@ -1171,9 +1203,11 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, | |||
1171 | } | 1203 | } |
1172 | 1204 | ||
1173 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 1205 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
1174 | paths = is_connected_output_ep(dai->playback_widget, &widgets); | 1206 | paths = is_connected_output_ep(dai->playback_widget, &widgets, |
1207 | custom_stop_condition); | ||
1175 | else | 1208 | else |
1176 | paths = is_connected_input_ep(dai->capture_widget, &widgets); | 1209 | paths = is_connected_input_ep(dai->capture_widget, &widgets, |
1210 | custom_stop_condition); | ||
1177 | 1211 | ||
1178 | /* Drop starting point */ | 1212 | /* Drop starting point */ |
1179 | list_del(widgets.next); | 1213 | list_del(widgets.next); |
@@ -1268,8 +1302,8 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w) | |||
1268 | 1302 | ||
1269 | DAPM_UPDATE_STAT(w, power_checks); | 1303 | DAPM_UPDATE_STAT(w, power_checks); |
1270 | 1304 | ||
1271 | in = is_connected_input_ep(w, NULL); | 1305 | in = is_connected_input_ep(w, NULL, NULL); |
1272 | out = is_connected_output_ep(w, NULL); | 1306 | out = is_connected_output_ep(w, NULL, NULL); |
1273 | return out != 0 && in != 0; | 1307 | return out != 0 && in != 0; |
1274 | } | 1308 | } |
1275 | 1309 | ||
@@ -1928,8 +1962,8 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1928 | in = 0; | 1962 | in = 0; |
1929 | out = 0; | 1963 | out = 0; |
1930 | } else { | 1964 | } else { |
1931 | in = is_connected_input_ep(w, NULL); | 1965 | in = is_connected_input_ep(w, NULL, NULL); |
1932 | out = is_connected_output_ep(w, NULL); | 1966 | out = is_connected_output_ep(w, NULL, NULL); |
1933 | } | 1967 | } |
1934 | 1968 | ||
1935 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", | 1969 | ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d", |
@@ -3282,6 +3316,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3282 | mutex_unlock(&dapm->card->dapm_mutex); | 3316 | mutex_unlock(&dapm->card->dapm_mutex); |
3283 | return w; | 3317 | return w; |
3284 | } | 3318 | } |
3319 | EXPORT_SYMBOL_GPL(snd_soc_dapm_new_control); | ||
3285 | 3320 | ||
3286 | struct snd_soc_dapm_widget * | 3321 | struct snd_soc_dapm_widget * |
3287 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, | 3322 | snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index aa99dac31b3b..60d702f8b9f0 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -1287,6 +1287,46 @@ static int widget_in_list(struct snd_soc_dapm_widget_list *list, | |||
1287 | return 0; | 1287 | return 0; |
1288 | } | 1288 | } |
1289 | 1289 | ||
1290 | static bool dpcm_end_walk_at_be(struct snd_soc_dapm_widget *widget, | ||
1291 | enum snd_soc_dapm_direction dir) | ||
1292 | { | ||
1293 | struct snd_soc_card *card = widget->dapm->card; | ||
1294 | struct snd_soc_pcm_runtime *rtd; | ||
1295 | int i; | ||
1296 | |||
1297 | if (dir == SND_SOC_DAPM_DIR_OUT) { | ||
1298 | list_for_each_entry(rtd, &card->rtd_list, list) { | ||
1299 | if (!rtd->dai_link->no_pcm) | ||
1300 | continue; | ||
1301 | |||
1302 | if (rtd->cpu_dai->playback_widget == widget) | ||
1303 | return true; | ||
1304 | |||
1305 | for (i = 0; i < rtd->num_codecs; ++i) { | ||
1306 | struct snd_soc_dai *dai = rtd->codec_dais[i]; | ||
1307 | if (dai->playback_widget == widget) | ||
1308 | return true; | ||
1309 | } | ||
1310 | } | ||
1311 | } else { /* SND_SOC_DAPM_DIR_IN */ | ||
1312 | list_for_each_entry(rtd, &card->rtd_list, list) { | ||
1313 | if (!rtd->dai_link->no_pcm) | ||
1314 | continue; | ||
1315 | |||
1316 | if (rtd->cpu_dai->capture_widget == widget) | ||
1317 | return true; | ||
1318 | |||
1319 | for (i = 0; i < rtd->num_codecs; ++i) { | ||
1320 | struct snd_soc_dai *dai = rtd->codec_dais[i]; | ||
1321 | if (dai->capture_widget == widget) | ||
1322 | return true; | ||
1323 | } | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | return false; | ||
1328 | } | ||
1329 | |||
1290 | int dpcm_path_get(struct snd_soc_pcm_runtime *fe, | 1330 | int dpcm_path_get(struct snd_soc_pcm_runtime *fe, |
1291 | int stream, struct snd_soc_dapm_widget_list **list) | 1331 | int stream, struct snd_soc_dapm_widget_list **list) |
1292 | { | 1332 | { |
@@ -1294,7 +1334,8 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, | |||
1294 | int paths; | 1334 | int paths; |
1295 | 1335 | ||
1296 | /* get number of valid DAI paths and their widgets */ | 1336 | /* get number of valid DAI paths and their widgets */ |
1297 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list); | 1337 | paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list, |
1338 | dpcm_end_walk_at_be); | ||
1298 | 1339 | ||
1299 | dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, | 1340 | dev_dbg(fe->dev, "ASoC: found %d audio %s paths\n", paths, |
1300 | stream ? "capture" : "playback"); | 1341 | stream ? "capture" : "playback"); |
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index ee1c7c245bc7..1ac2db205a0d 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -1029,9 +1029,9 @@ static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, | |||
1029 | 1029 | ||
1030 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); | 1030 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); |
1031 | 1031 | ||
1032 | if (!regmap) { | 1032 | if (IS_ERR(regmap)) { |
1033 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); | 1033 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); |
1034 | return -EINVAL; | 1034 | return PTR_ERR(regmap); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | player->clk_sel = regmap_field_alloc(regmap, regfield[0]); | 1037 | player->clk_sel = regmap_field_alloc(regmap, regfield[0]); |
diff --git a/sound/soc/sunxi/Kconfig b/sound/soc/sunxi/Kconfig index ae42294ef688..2a954bd01fd8 100644 --- a/sound/soc/sunxi/Kconfig +++ b/sound/soc/sunxi/Kconfig | |||
@@ -8,6 +8,15 @@ config SND_SUN4I_CODEC | |||
8 | Select Y or M to add support for the Codec embedded in the Allwinner | 8 | Select Y or M to add support for the Codec embedded in the Allwinner |
9 | A10 and affiliated SoCs. | 9 | A10 and affiliated SoCs. |
10 | 10 | ||
11 | config SND_SUN4I_I2S | ||
12 | tristate "Allwinner A10 I2S Support" | ||
13 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
14 | select REGMAP_MMIO | ||
15 | help | ||
16 | Say Y or M if you want to add support for codecs attached to | ||
17 | the Allwinner A10 I2S. You will also need to select the | ||
18 | individual machine drivers to support below. | ||
19 | |||
11 | config SND_SUN4I_SPDIF | 20 | config SND_SUN4I_SPDIF |
12 | tristate "Allwinner A10 SPDIF Support" | 21 | tristate "Allwinner A10 SPDIF Support" |
13 | depends on OF | 22 | depends on OF |
diff --git a/sound/soc/sunxi/Makefile b/sound/soc/sunxi/Makefile index 8f5e889667f1..604c7b842837 100644 --- a/sound/soc/sunxi/Makefile +++ b/sound/soc/sunxi/Makefile | |||
@@ -1,3 +1,3 @@ | |||
1 | obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o | 1 | obj-$(CONFIG_SND_SUN4I_CODEC) += sun4i-codec.o |
2 | 2 | obj-$(CONFIG_SND_SUN4I_I2S) += sun4i-i2s.o | |
3 | obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o | 3 | obj-$(CONFIG_SND_SUN4I_SPDIF) += sun4i-spdif.o |
diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c new file mode 100644 index 000000000000..687a8f83dbe5 --- /dev/null +++ b/sound/soc/sunxi/sun4i-i2s.c | |||
@@ -0,0 +1,701 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015 Andrea Venturi | ||
3 | * Andrea Venturi <be17068@iperbole.bo.it> | ||
4 | * | ||
5 | * Copyright (C) 2016 Maxime Ripard | ||
6 | * Maxime Ripard <maxime.ripard@free-electrons.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or | ||
9 | * modify it under the terms of the GNU General Public License as | ||
10 | * published by the Free Software Foundation; either version 2 of | ||
11 | * the License, or (at your option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/dmaengine.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/pm_runtime.h> | ||
19 | #include <linux/regmap.h> | ||
20 | |||
21 | #include <sound/dmaengine_pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/soc-dai.h> | ||
25 | |||
26 | #define SUN4I_I2S_CTRL_REG 0x00 | ||
27 | #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8) | ||
28 | #define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo)) | ||
29 | #define SUN4I_I2S_CTRL_MODE_MASK BIT(5) | ||
30 | #define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5) | ||
31 | #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5) | ||
32 | #define SUN4I_I2S_CTRL_TX_EN BIT(2) | ||
33 | #define SUN4I_I2S_CTRL_RX_EN BIT(1) | ||
34 | #define SUN4I_I2S_CTRL_GL_EN BIT(0) | ||
35 | |||
36 | #define SUN4I_I2S_FMT0_REG 0x04 | ||
37 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7) | ||
38 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7) | ||
39 | #define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 7) | ||
40 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK BIT(6) | ||
41 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 6) | ||
42 | #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 6) | ||
43 | #define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4) | ||
44 | #define SUN4I_I2S_FMT0_SR(sr) ((sr) << 4) | ||
45 | #define SUN4I_I2S_FMT0_WSS_MASK GENMASK(3, 2) | ||
46 | #define SUN4I_I2S_FMT0_WSS(wss) ((wss) << 2) | ||
47 | #define SUN4I_I2S_FMT0_FMT_MASK GENMASK(1, 0) | ||
48 | #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) | ||
49 | #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) | ||
50 | #define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) | ||
51 | |||
52 | #define SUN4I_I2S_FMT1_REG 0x08 | ||
53 | #define SUN4I_I2S_FIFO_TX_REG 0x0c | ||
54 | #define SUN4I_I2S_FIFO_RX_REG 0x10 | ||
55 | |||
56 | #define SUN4I_I2S_FIFO_CTRL_REG 0x14 | ||
57 | #define SUN4I_I2S_FIFO_CTRL_FLUSH_TX BIT(25) | ||
58 | #define SUN4I_I2S_FIFO_CTRL_FLUSH_RX BIT(24) | ||
59 | #define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK BIT(2) | ||
60 | #define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode) ((mode) << 2) | ||
61 | #define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK GENMASK(1, 0) | ||
62 | #define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode) (mode) | ||
63 | |||
64 | #define SUN4I_I2S_FIFO_STA_REG 0x18 | ||
65 | |||
66 | #define SUN4I_I2S_DMA_INT_CTRL_REG 0x1c | ||
67 | #define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN BIT(7) | ||
68 | #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN BIT(3) | ||
69 | |||
70 | #define SUN4I_I2S_INT_STA_REG 0x20 | ||
71 | |||
72 | #define SUN4I_I2S_CLK_DIV_REG 0x24 | ||
73 | #define SUN4I_I2S_CLK_DIV_MCLK_EN BIT(7) | ||
74 | #define SUN4I_I2S_CLK_DIV_BCLK_MASK GENMASK(6, 4) | ||
75 | #define SUN4I_I2S_CLK_DIV_BCLK(bclk) ((bclk) << 4) | ||
76 | #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) | ||
77 | #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) | ||
78 | |||
79 | #define SUN4I_I2S_RX_CNT_REG 0x28 | ||
80 | #define SUN4I_I2S_TX_CNT_REG 0x2c | ||
81 | |||
82 | #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 | ||
83 | #define SUN4I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) | ||
84 | |||
85 | #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 | ||
86 | #define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2)) | ||
87 | |||
88 | #define SUN4I_I2S_RX_CHAN_SEL_REG 0x38 | ||
89 | #define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c | ||
90 | |||
91 | struct sun4i_i2s { | ||
92 | struct clk *bus_clk; | ||
93 | struct clk *mod_clk; | ||
94 | struct regmap *regmap; | ||
95 | |||
96 | struct snd_dmaengine_dai_dma_data playback_dma_data; | ||
97 | }; | ||
98 | |||
99 | struct sun4i_i2s_clk_div { | ||
100 | u8 div; | ||
101 | u8 val; | ||
102 | }; | ||
103 | |||
104 | static const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = { | ||
105 | { .div = 2, .val = 0 }, | ||
106 | { .div = 4, .val = 1 }, | ||
107 | { .div = 6, .val = 2 }, | ||
108 | { .div = 8, .val = 3 }, | ||
109 | { .div = 12, .val = 4 }, | ||
110 | { .div = 16, .val = 5 }, | ||
111 | }; | ||
112 | |||
113 | static const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { | ||
114 | { .div = 1, .val = 0 }, | ||
115 | { .div = 2, .val = 1 }, | ||
116 | { .div = 4, .val = 2 }, | ||
117 | { .div = 6, .val = 3 }, | ||
118 | { .div = 8, .val = 4 }, | ||
119 | { .div = 12, .val = 5 }, | ||
120 | { .div = 16, .val = 6 }, | ||
121 | { .div = 24, .val = 7 }, | ||
122 | }; | ||
123 | |||
124 | static int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, | ||
125 | unsigned int oversample_rate, | ||
126 | unsigned int word_size) | ||
127 | { | ||
128 | int div = oversample_rate / word_size / 2; | ||
129 | int i; | ||
130 | |||
131 | for (i = 0; i < ARRAY_SIZE(sun4i_i2s_bclk_div); i++) { | ||
132 | const struct sun4i_i2s_clk_div *bdiv = &sun4i_i2s_bclk_div[i]; | ||
133 | |||
134 | if (bdiv->div == div) | ||
135 | return bdiv->val; | ||
136 | } | ||
137 | |||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | static int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, | ||
142 | unsigned int oversample_rate, | ||
143 | unsigned int module_rate, | ||
144 | unsigned int sampling_rate) | ||
145 | { | ||
146 | int div = module_rate / sampling_rate / oversample_rate; | ||
147 | int i; | ||
148 | |||
149 | for (i = 0; i < ARRAY_SIZE(sun4i_i2s_mclk_div); i++) { | ||
150 | const struct sun4i_i2s_clk_div *mdiv = &sun4i_i2s_mclk_div[i]; | ||
151 | |||
152 | if (mdiv->div == div) | ||
153 | return mdiv->val; | ||
154 | } | ||
155 | |||
156 | return -EINVAL; | ||
157 | } | ||
158 | |||
159 | static int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; | ||
160 | |||
161 | static int sun4i_i2s_set_clk_rate(struct sun4i_i2s *i2s, | ||
162 | unsigned int rate, | ||
163 | unsigned int word_size) | ||
164 | { | ||
165 | unsigned int clk_rate; | ||
166 | int bclk_div, mclk_div; | ||
167 | int ret, i; | ||
168 | |||
169 | switch (rate) { | ||
170 | case 176400: | ||
171 | case 88200: | ||
172 | case 44100: | ||
173 | case 22050: | ||
174 | case 11025: | ||
175 | clk_rate = 22579200; | ||
176 | break; | ||
177 | |||
178 | case 192000: | ||
179 | case 128000: | ||
180 | case 96000: | ||
181 | case 64000: | ||
182 | case 48000: | ||
183 | case 32000: | ||
184 | case 24000: | ||
185 | case 16000: | ||
186 | case 12000: | ||
187 | case 8000: | ||
188 | clk_rate = 24576000; | ||
189 | break; | ||
190 | |||
191 | default: | ||
192 | return -EINVAL; | ||
193 | } | ||
194 | |||
195 | ret = clk_set_rate(i2s->mod_clk, clk_rate); | ||
196 | if (ret) | ||
197 | return ret; | ||
198 | |||
199 | /* Always favor the highest oversampling rate */ | ||
200 | for (i = (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >= 0; i--) { | ||
201 | unsigned int oversample_rate = sun4i_i2s_oversample_rates[i]; | ||
202 | |||
203 | bclk_div = sun4i_i2s_get_bclk_div(i2s, oversample_rate, | ||
204 | word_size); | ||
205 | mclk_div = sun4i_i2s_get_mclk_div(i2s, oversample_rate, | ||
206 | clk_rate, | ||
207 | rate); | ||
208 | |||
209 | if ((bclk_div >= 0) && (mclk_div >= 0)) | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | if ((bclk_div < 0) || (mclk_div < 0)) | ||
214 | return -EINVAL; | ||
215 | |||
216 | regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, | ||
217 | SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | | ||
218 | SUN4I_I2S_CLK_DIV_MCLK(mclk_div) | | ||
219 | SUN4I_I2S_CLK_DIV_MCLK_EN); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, | ||
225 | struct snd_pcm_hw_params *params, | ||
226 | struct snd_soc_dai *dai) | ||
227 | { | ||
228 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
229 | int sr, wss; | ||
230 | u32 width; | ||
231 | |||
232 | if (params_channels(params) != 2) | ||
233 | return -EINVAL; | ||
234 | |||
235 | switch (params_physical_width(params)) { | ||
236 | case 16: | ||
237 | width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
238 | break; | ||
239 | default: | ||
240 | return -EINVAL; | ||
241 | } | ||
242 | i2s->playback_dma_data.addr_width = width; | ||
243 | |||
244 | switch (params_width(params)) { | ||
245 | case 16: | ||
246 | sr = 0; | ||
247 | wss = 0; | ||
248 | break; | ||
249 | |||
250 | default: | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, | ||
255 | SUN4I_I2S_FMT0_WSS_MASK | SUN4I_I2S_FMT0_SR_MASK, | ||
256 | SUN4I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr)); | ||
257 | |||
258 | return sun4i_i2s_set_clk_rate(i2s, params_rate(params), | ||
259 | params_width(params)); | ||
260 | } | ||
261 | |||
262 | static int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
263 | { | ||
264 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
265 | u32 val; | ||
266 | |||
267 | /* DAI Mode */ | ||
268 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
269 | case SND_SOC_DAIFMT_I2S: | ||
270 | val = SUN4I_I2S_FMT0_FMT_I2S; | ||
271 | break; | ||
272 | case SND_SOC_DAIFMT_LEFT_J: | ||
273 | val = SUN4I_I2S_FMT0_FMT_LEFT_J; | ||
274 | break; | ||
275 | case SND_SOC_DAIFMT_RIGHT_J: | ||
276 | val = SUN4I_I2S_FMT0_FMT_RIGHT_J; | ||
277 | break; | ||
278 | default: | ||
279 | return -EINVAL; | ||
280 | } | ||
281 | |||
282 | regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, | ||
283 | SUN4I_I2S_FMT0_FMT_MASK, | ||
284 | val); | ||
285 | |||
286 | /* DAI clock polarity */ | ||
287 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
288 | case SND_SOC_DAIFMT_IB_IF: | ||
289 | /* Invert both clocks */ | ||
290 | val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | | ||
291 | SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; | ||
292 | break; | ||
293 | case SND_SOC_DAIFMT_IB_NF: | ||
294 | /* Invert bit clock */ | ||
295 | val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | | ||
296 | SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL; | ||
297 | break; | ||
298 | case SND_SOC_DAIFMT_NB_IF: | ||
299 | /* Invert frame clock */ | ||
300 | val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED | | ||
301 | SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL; | ||
302 | break; | ||
303 | case SND_SOC_DAIFMT_NB_NF: | ||
304 | /* Nothing to do for both normal cases */ | ||
305 | val = SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL | | ||
306 | SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL; | ||
307 | break; | ||
308 | default: | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, | ||
313 | SUN4I_I2S_FMT0_BCLK_POLARITY_MASK | | ||
314 | SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK, | ||
315 | val); | ||
316 | |||
317 | /* DAI clock master masks */ | ||
318 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
319 | case SND_SOC_DAIFMT_CBS_CFS: | ||
320 | /* BCLK and LRCLK master */ | ||
321 | val = SUN4I_I2S_CTRL_MODE_MASTER; | ||
322 | break; | ||
323 | case SND_SOC_DAIFMT_CBM_CFM: | ||
324 | /* BCLK and LRCLK slave */ | ||
325 | val = SUN4I_I2S_CTRL_MODE_SLAVE; | ||
326 | break; | ||
327 | default: | ||
328 | return -EINVAL; | ||
329 | } | ||
330 | |||
331 | regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
332 | SUN4I_I2S_CTRL_MODE_MASK, | ||
333 | val); | ||
334 | |||
335 | /* Set significant bits in our FIFOs */ | ||
336 | regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, | ||
337 | SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | | ||
338 | SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, | ||
339 | SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | | ||
340 | SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) | ||
345 | { | ||
346 | /* Flush TX FIFO */ | ||
347 | regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, | ||
348 | SUN4I_I2S_FIFO_CTRL_FLUSH_TX, | ||
349 | SUN4I_I2S_FIFO_CTRL_FLUSH_TX); | ||
350 | |||
351 | /* Clear TX counter */ | ||
352 | regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0); | ||
353 | |||
354 | /* Enable TX Block */ | ||
355 | regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
356 | SUN4I_I2S_CTRL_TX_EN, | ||
357 | SUN4I_I2S_CTRL_TX_EN); | ||
358 | |||
359 | /* Enable TX DRQ */ | ||
360 | regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, | ||
361 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, | ||
362 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); | ||
363 | } | ||
364 | |||
365 | |||
366 | static void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) | ||
367 | { | ||
368 | /* Disable TX Block */ | ||
369 | regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
370 | SUN4I_I2S_CTRL_TX_EN, | ||
371 | 0); | ||
372 | |||
373 | /* Disable TX DRQ */ | ||
374 | regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, | ||
375 | SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, | ||
376 | 0); | ||
377 | } | ||
378 | |||
379 | static int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
380 | struct snd_soc_dai *dai) | ||
381 | { | ||
382 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
383 | |||
384 | switch (cmd) { | ||
385 | case SNDRV_PCM_TRIGGER_START: | ||
386 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
387 | case SNDRV_PCM_TRIGGER_RESUME: | ||
388 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
389 | sun4i_i2s_start_playback(i2s); | ||
390 | else | ||
391 | return -EINVAL; | ||
392 | break; | ||
393 | |||
394 | case SNDRV_PCM_TRIGGER_STOP: | ||
395 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
396 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
397 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
398 | sun4i_i2s_stop_playback(i2s); | ||
399 | else | ||
400 | return -EINVAL; | ||
401 | break; | ||
402 | |||
403 | default: | ||
404 | return -EINVAL; | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int sun4i_i2s_startup(struct snd_pcm_substream *substream, | ||
411 | struct snd_soc_dai *dai) | ||
412 | { | ||
413 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
414 | |||
415 | /* Enable the whole hardware block */ | ||
416 | regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
417 | SUN4I_I2S_CTRL_GL_EN); | ||
418 | |||
419 | /* Enable the first output line */ | ||
420 | regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
421 | SUN4I_I2S_CTRL_SDO_EN_MASK, | ||
422 | SUN4I_I2S_CTRL_SDO_EN(0)); | ||
423 | |||
424 | /* Enable the first two channels */ | ||
425 | regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, | ||
426 | SUN4I_I2S_TX_CHAN_SEL(2)); | ||
427 | |||
428 | /* Map them to the two first samples coming in */ | ||
429 | regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, | ||
430 | SUN4I_I2S_TX_CHAN_MAP(0, 0) | SUN4I_I2S_TX_CHAN_MAP(1, 1)); | ||
431 | |||
432 | return clk_prepare_enable(i2s->mod_clk); | ||
433 | } | ||
434 | |||
435 | static void sun4i_i2s_shutdown(struct snd_pcm_substream *substream, | ||
436 | struct snd_soc_dai *dai) | ||
437 | { | ||
438 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
439 | |||
440 | clk_disable_unprepare(i2s->mod_clk); | ||
441 | |||
442 | /* Disable our output lines */ | ||
443 | regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, | ||
444 | SUN4I_I2S_CTRL_SDO_EN_MASK, 0); | ||
445 | |||
446 | /* Disable the whole hardware block */ | ||
447 | regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); | ||
448 | } | ||
449 | |||
450 | static const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { | ||
451 | .hw_params = sun4i_i2s_hw_params, | ||
452 | .set_fmt = sun4i_i2s_set_fmt, | ||
453 | .shutdown = sun4i_i2s_shutdown, | ||
454 | .startup = sun4i_i2s_startup, | ||
455 | .trigger = sun4i_i2s_trigger, | ||
456 | }; | ||
457 | |||
458 | static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) | ||
459 | { | ||
460 | struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
461 | |||
462 | snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data, NULL); | ||
463 | |||
464 | snd_soc_dai_set_drvdata(dai, i2s); | ||
465 | |||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static struct snd_soc_dai_driver sun4i_i2s_dai = { | ||
470 | .probe = sun4i_i2s_dai_probe, | ||
471 | .playback = { | ||
472 | .stream_name = "Playback", | ||
473 | .channels_min = 2, | ||
474 | .channels_max = 2, | ||
475 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
476 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
477 | }, | ||
478 | .ops = &sun4i_i2s_dai_ops, | ||
479 | .symmetric_rates = 1, | ||
480 | }; | ||
481 | |||
482 | static const struct snd_soc_component_driver sun4i_i2s_component = { | ||
483 | .name = "sun4i-dai", | ||
484 | }; | ||
485 | |||
486 | static bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg) | ||
487 | { | ||
488 | switch (reg) { | ||
489 | case SUN4I_I2S_FIFO_TX_REG: | ||
490 | return false; | ||
491 | |||
492 | default: | ||
493 | return true; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg) | ||
498 | { | ||
499 | switch (reg) { | ||
500 | case SUN4I_I2S_FIFO_RX_REG: | ||
501 | case SUN4I_I2S_FIFO_STA_REG: | ||
502 | return false; | ||
503 | |||
504 | default: | ||
505 | return true; | ||
506 | } | ||
507 | } | ||
508 | |||
509 | static bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg) | ||
510 | { | ||
511 | switch (reg) { | ||
512 | case SUN4I_I2S_FIFO_RX_REG: | ||
513 | case SUN4I_I2S_INT_STA_REG: | ||
514 | case SUN4I_I2S_RX_CNT_REG: | ||
515 | case SUN4I_I2S_TX_CNT_REG: | ||
516 | return true; | ||
517 | |||
518 | default: | ||
519 | return false; | ||
520 | } | ||
521 | } | ||
522 | |||
523 | static const struct reg_default sun4i_i2s_reg_defaults[] = { | ||
524 | { SUN4I_I2S_CTRL_REG, 0x00000000 }, | ||
525 | { SUN4I_I2S_FMT0_REG, 0x0000000c }, | ||
526 | { SUN4I_I2S_FMT1_REG, 0x00004020 }, | ||
527 | { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, | ||
528 | { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, | ||
529 | { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, | ||
530 | { SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 }, | ||
531 | { SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 }, | ||
532 | { SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 }, | ||
533 | { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 }, | ||
534 | }; | ||
535 | |||
536 | static const struct regmap_config sun4i_i2s_regmap_config = { | ||
537 | .reg_bits = 32, | ||
538 | .reg_stride = 4, | ||
539 | .val_bits = 32, | ||
540 | .max_register = SUN4I_I2S_RX_CHAN_MAP_REG, | ||
541 | |||
542 | .cache_type = REGCACHE_FLAT, | ||
543 | .reg_defaults = sun4i_i2s_reg_defaults, | ||
544 | .num_reg_defaults = ARRAY_SIZE(sun4i_i2s_reg_defaults), | ||
545 | .writeable_reg = sun4i_i2s_wr_reg, | ||
546 | .readable_reg = sun4i_i2s_rd_reg, | ||
547 | .volatile_reg = sun4i_i2s_volatile_reg, | ||
548 | }; | ||
549 | |||
550 | static int sun4i_i2s_runtime_resume(struct device *dev) | ||
551 | { | ||
552 | struct sun4i_i2s *i2s = dev_get_drvdata(dev); | ||
553 | int ret; | ||
554 | |||
555 | ret = clk_prepare_enable(i2s->bus_clk); | ||
556 | if (ret) { | ||
557 | dev_err(dev, "Failed to enable bus clock\n"); | ||
558 | return ret; | ||
559 | } | ||
560 | |||
561 | regcache_cache_only(i2s->regmap, false); | ||
562 | regcache_mark_dirty(i2s->regmap); | ||
563 | |||
564 | ret = regcache_sync(i2s->regmap); | ||
565 | if (ret) { | ||
566 | dev_err(dev, "Failed to sync regmap cache\n"); | ||
567 | goto err_disable_clk; | ||
568 | } | ||
569 | |||
570 | return 0; | ||
571 | |||
572 | err_disable_clk: | ||
573 | clk_disable_unprepare(i2s->bus_clk); | ||
574 | return ret; | ||
575 | } | ||
576 | |||
577 | static int sun4i_i2s_runtime_suspend(struct device *dev) | ||
578 | { | ||
579 | struct sun4i_i2s *i2s = dev_get_drvdata(dev); | ||
580 | |||
581 | regcache_cache_only(i2s->regmap, true); | ||
582 | |||
583 | clk_disable_unprepare(i2s->bus_clk); | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int sun4i_i2s_probe(struct platform_device *pdev) | ||
589 | { | ||
590 | struct sun4i_i2s *i2s; | ||
591 | struct resource *res; | ||
592 | void __iomem *regs; | ||
593 | int irq, ret; | ||
594 | |||
595 | i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); | ||
596 | if (!i2s) | ||
597 | return -ENOMEM; | ||
598 | platform_set_drvdata(pdev, i2s); | ||
599 | |||
600 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
601 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
602 | if (IS_ERR(regs)) | ||
603 | return PTR_ERR(regs); | ||
604 | |||
605 | irq = platform_get_irq(pdev, 0); | ||
606 | if (irq < 0) { | ||
607 | dev_err(&pdev->dev, "Can't retrieve our interrupt\n"); | ||
608 | return irq; | ||
609 | } | ||
610 | |||
611 | i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); | ||
612 | if (IS_ERR(i2s->bus_clk)) { | ||
613 | dev_err(&pdev->dev, "Can't get our bus clock\n"); | ||
614 | return PTR_ERR(i2s->bus_clk); | ||
615 | } | ||
616 | |||
617 | i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, | ||
618 | &sun4i_i2s_regmap_config); | ||
619 | if (IS_ERR(i2s->regmap)) { | ||
620 | dev_err(&pdev->dev, "Regmap initialisation failed\n"); | ||
621 | return PTR_ERR(i2s->regmap); | ||
622 | } | ||
623 | |||
624 | i2s->mod_clk = devm_clk_get(&pdev->dev, "mod"); | ||
625 | if (IS_ERR(i2s->mod_clk)) { | ||
626 | dev_err(&pdev->dev, "Can't get our mod clock\n"); | ||
627 | return PTR_ERR(i2s->mod_clk); | ||
628 | } | ||
629 | |||
630 | i2s->playback_dma_data.addr = res->start + SUN4I_I2S_FIFO_TX_REG; | ||
631 | i2s->playback_dma_data.maxburst = 4; | ||
632 | |||
633 | pm_runtime_enable(&pdev->dev); | ||
634 | if (!pm_runtime_enabled(&pdev->dev)) { | ||
635 | ret = sun4i_i2s_runtime_resume(&pdev->dev); | ||
636 | if (ret) | ||
637 | goto err_pm_disable; | ||
638 | } | ||
639 | |||
640 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
641 | &sun4i_i2s_component, | ||
642 | &sun4i_i2s_dai, 1); | ||
643 | if (ret) { | ||
644 | dev_err(&pdev->dev, "Could not register DAI\n"); | ||
645 | goto err_suspend; | ||
646 | } | ||
647 | |||
648 | ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
649 | if (ret) { | ||
650 | dev_err(&pdev->dev, "Could not register PCM\n"); | ||
651 | goto err_suspend; | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | |||
656 | err_suspend: | ||
657 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
658 | sun4i_i2s_runtime_suspend(&pdev->dev); | ||
659 | err_pm_disable: | ||
660 | pm_runtime_disable(&pdev->dev); | ||
661 | |||
662 | return ret; | ||
663 | } | ||
664 | |||
665 | static int sun4i_i2s_remove(struct platform_device *pdev) | ||
666 | { | ||
667 | snd_dmaengine_pcm_unregister(&pdev->dev); | ||
668 | |||
669 | pm_runtime_disable(&pdev->dev); | ||
670 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
671 | sun4i_i2s_runtime_suspend(&pdev->dev); | ||
672 | |||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | static const struct of_device_id sun4i_i2s_match[] = { | ||
677 | { .compatible = "allwinner,sun4i-a10-i2s", }, | ||
678 | {} | ||
679 | }; | ||
680 | MODULE_DEVICE_TABLE(of, sun4i_i2s_match); | ||
681 | |||
682 | static const struct dev_pm_ops sun4i_i2s_pm_ops = { | ||
683 | .runtime_resume = sun4i_i2s_runtime_resume, | ||
684 | .runtime_suspend = sun4i_i2s_runtime_suspend, | ||
685 | }; | ||
686 | |||
687 | static struct platform_driver sun4i_i2s_driver = { | ||
688 | .probe = sun4i_i2s_probe, | ||
689 | .remove = sun4i_i2s_remove, | ||
690 | .driver = { | ||
691 | .name = "sun4i-i2s", | ||
692 | .of_match_table = sun4i_i2s_match, | ||
693 | .pm = &sun4i_i2s_pm_ops, | ||
694 | }, | ||
695 | }; | ||
696 | module_platform_driver(sun4i_i2s_driver); | ||
697 | |||
698 | MODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>"); | ||
699 | MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); | ||
700 | MODULE_DESCRIPTION("Allwinner A10 I2S driver"); | ||
701 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/sound_firmware.c b/sound/sound_firmware.c deleted file mode 100644 index 026347643c81..000000000000 --- a/sound/sound_firmware.c +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | #include <linux/vmalloc.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/fs.h> | ||
4 | #include <linux/file.h> | ||
5 | #include <linux/mm.h> | ||
6 | #include <linux/sched.h> | ||
7 | #include <asm/uaccess.h> | ||
8 | #include "oss/sound_firmware.h" | ||
9 | |||
10 | static int do_mod_firmware_load(const char *fn, char **fp) | ||
11 | { | ||
12 | struct file* filp; | ||
13 | long l; | ||
14 | char *dp; | ||
15 | |||
16 | filp = filp_open(fn, 0, 0); | ||
17 | if (IS_ERR(filp)) | ||
18 | { | ||
19 | printk(KERN_INFO "Unable to load '%s'.\n", fn); | ||
20 | return 0; | ||
21 | } | ||
22 | l = i_size_read(file_inode(filp)); | ||
23 | if (l <= 0 || l > 131072) | ||
24 | { | ||
25 | printk(KERN_INFO "Invalid firmware '%s'\n", fn); | ||
26 | fput(filp); | ||
27 | return 0; | ||
28 | } | ||
29 | dp = vmalloc(l); | ||
30 | if (dp == NULL) | ||
31 | { | ||
32 | printk(KERN_INFO "Out of memory loading '%s'.\n", fn); | ||
33 | fput(filp); | ||
34 | return 0; | ||
35 | } | ||
36 | if (kernel_read(filp, 0, dp, l) != l) | ||
37 | { | ||
38 | printk(KERN_INFO "Failed to read '%s'.\n", fn); | ||
39 | vfree(dp); | ||
40 | fput(filp); | ||
41 | return 0; | ||
42 | } | ||
43 | fput(filp); | ||
44 | *fp = dp; | ||
45 | return (int) l; | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * mod_firmware_load - load sound driver firmware | ||
50 | * @fn: filename | ||
51 | * @fp: return for the buffer. | ||
52 | * | ||
53 | * Load the firmware for a sound module (up to 128K) into a buffer. | ||
54 | * The buffer is returned in *fp. It is allocated with vmalloc so is | ||
55 | * virtually linear and not DMAable. The caller should free it with | ||
56 | * vfree when finished. | ||
57 | * | ||
58 | * The length of the buffer is returned on a successful load, the | ||
59 | * value zero on a failure. | ||
60 | * | ||
61 | * Caution: This API is not recommended. Firmware should be loaded via | ||
62 | * request_firmware. | ||
63 | */ | ||
64 | |||
65 | int mod_firmware_load(const char *fn, char **fp) | ||
66 | { | ||
67 | int r; | ||
68 | mm_segment_t fs = get_fs(); | ||
69 | |||
70 | set_fs(get_ds()); | ||
71 | r = do_mod_firmware_load(fn, fp); | ||
72 | set_fs(fs); | ||
73 | return r; | ||
74 | } | ||
75 | EXPORT_SYMBOL(mod_firmware_load); | ||
76 | |||
77 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 1f8fb0d904e0..9038b2e7df73 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -107,8 +107,10 @@ static struct usbmix_name_map extigy_map[] = { | |||
107 | * e.g. no Master and fake PCM volume | 107 | * e.g. no Master and fake PCM volume |
108 | * Pavel Mihaylov <bin@bash.info> | 108 | * Pavel Mihaylov <bin@bash.info> |
109 | */ | 109 | */ |
110 | static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ | 110 | static struct usbmix_dB_map mp3plus_dB_1 = {.min = -4781, .max = 0}; |
111 | static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ | 111 | /* just guess */ |
112 | static struct usbmix_dB_map mp3plus_dB_2 = {.min = -1781, .max = 618}; | ||
113 | /* just guess */ | ||
112 | 114 | ||
113 | static struct usbmix_name_map mp3plus_map[] = { | 115 | static struct usbmix_name_map mp3plus_map[] = { |
114 | /* 1: IT pcm */ | 116 | /* 1: IT pcm */ |