diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-28 15:23:12 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-28 15:23:12 -0400 |
commit | 0723ab4a97a19bf9da135d68529977aeba17570d (patch) | |
tree | 453051ed67b556ddd13a5921742ba228c22d980a | |
parent | 9ba55cf7cfbfd12a7e914d0d55b7581e896b3f0d (diff) | |
parent | eb4606e64a7d548f5d60a9583baa8104890b2c6e (diff) |
Merge tag 'sound-4.7-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull more sound updates from Takashi Iwai:
"This is the second update round for 4.7-rc1. Most of changes are
about the pending ASoC updates and fixes, including a few new drivers.
Below are some highlights:
ASoC:
- New drivers for MAX98371 and TAS5720
- SPI support for TLV320AIC32x4, along with the module split
- TDM support for STI Uniperf IPs
- Remaining topology API fixes / updates
HDA:
- A couple of Dell quirks and new Realtek codec support"
* tag 'sound-4.7-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (63 commits)
ALSA: hda - Fix headset mic detection problem for one Dell machine
spi: spi-ep93xx: Fix the PTR_ERR() argument
ALSA: hda/realtek - Add support for ALC295/ALC3254
ASoC: kirkwood: fix build failure
ALSA: hda - Fix headphone noise on Dell XPS 13 9360
ASoC: ak4642: Enable cache usage to fix crashes on resume
ASoC: twl6040: Disconnect AUX output pads on digital mute
ASoC: tlv320aic32x4: Properly implement the positive and negative pins into the mixers
rcar: src: skip disabled-SRC nodes
ASoC: max98371 Remove duplicate entry in max98371_reg
ASoC: twl6040: Select LPPLL during standby
ASoC: rsnd: don't use prohibited number to PDMACHCRn.SRS
ASoC: simple-card: Add pm callbacks to platform driver
ASoC: pxa: Fix module autoload for platform drivers
ASoC: topology: Fix memory leak in widget creation
ASoC: Add max98371 codec driver
ASoC: rsnd: count .probe/.remove for rsnd_mod_call()
ASoC: topology: Check size mismatch of ABI objects before parsing
ASoC: topology: Check failure to create a widget
ASoC: add support for TAS5720 digital amplifier
...
56 files changed, 2800 insertions, 331 deletions
diff --git a/Documentation/devicetree/bindings/sound/max98371.txt b/Documentation/devicetree/bindings/sound/max98371.txt new file mode 100644 index 000000000000..6c285235e64b --- /dev/null +++ b/Documentation/devicetree/bindings/sound/max98371.txt | |||
@@ -0,0 +1,17 @@ | |||
1 | max98371 codec | ||
2 | |||
3 | This device supports I2C mode only. | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible : "maxim,max98371" | ||
8 | - reg : The chip select number on the I2C bus | ||
9 | |||
10 | Example: | ||
11 | |||
12 | &i2c { | ||
13 | max98371: max98371@0x31 { | ||
14 | compatible = "maxim,max98371"; | ||
15 | reg = <0x31>; | ||
16 | }; | ||
17 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt index f205ce9e31dd..ac28cdb4910e 100644 --- a/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650-rt5676.txt | |||
@@ -1,15 +1,16 @@ | |||
1 | MT8173 with RT5650 RT5676 CODECS | 1 | MT8173 with RT5650 RT5676 CODECS and HDMI via I2S |
2 | 2 | ||
3 | Required properties: | 3 | Required properties: |
4 | - compatible : "mediatek,mt8173-rt5650-rt5676" | 4 | - compatible : "mediatek,mt8173-rt5650-rt5676" |
5 | - mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs | 5 | - mediatek,audio-codec: the phandles of rt5650 and rt5676 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 | Example: | 9 | Example: |
9 | 10 | ||
10 | sound { | 11 | sound { |
11 | compatible = "mediatek,mt8173-rt5650-rt5676"; | 12 | compatible = "mediatek,mt8173-rt5650-rt5676"; |
12 | mediatek,audio-codec = <&rt5650 &rt5676>; | 13 | mediatek,audio-codec = <&rt5650 &rt5676 &hdmi0>; |
13 | mediatek,platform = <&afe>; | 14 | mediatek,platform = <&afe>; |
14 | }; | 15 | }; |
15 | 16 | ||
diff --git a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt index fe5a5ef1714d..5bfa6b60530b 100644 --- a/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt +++ b/Documentation/devicetree/bindings/sound/mt8173-rt5650.txt | |||
@@ -5,11 +5,21 @@ Required properties: | |||
5 | - mediatek,audio-codec: the phandles of rt5650 codecs | 5 | - mediatek,audio-codec: the phandles of rt5650 codecs |
6 | - mediatek,platform: the phandle of MT8173 ASoC platform | 6 | - mediatek,platform: the phandle of MT8173 ASoC platform |
7 | 7 | ||
8 | Optional subnodes: | ||
9 | - codec-capture : the subnode of rt5650 codec capture | ||
10 | Required codec-capture subnode properties: | ||
11 | - sound-dai: audio codec dai name on capture path | ||
12 | <&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 | |||
8 | Example: | 15 | Example: |
9 | 16 | ||
10 | sound { | 17 | sound { |
11 | compatible = "mediatek,mt8173-rt5650"; | 18 | compatible = "mediatek,mt8173-rt5650"; |
12 | mediatek,audio-codec = <&rt5650>; | 19 | mediatek,audio-codec = <&rt5650>; |
13 | mediatek,platform = <&afe>; | 20 | mediatek,platform = <&afe>; |
21 | codec-capture { | ||
22 | sound-dai = <&rt5650 1>; | ||
23 | }; | ||
14 | }; | 24 | }; |
15 | 25 | ||
diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt index 028fa1c82f50..4d9a83d9a017 100644 --- a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt | |||
@@ -37,17 +37,18 @@ Required properties: | |||
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. | ||
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). | ||
43 | "PCM" PCM standard mode for I2S or TDM bus. | ||
44 | "TDM" TDM mode for TDM bus. | ||
45 | |||
40 | Required properties ("st,sti-uni-player" compatibility only): | 46 | Required properties ("st,sti-uni-player" compatibility only): |
41 | - 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 |
42 | CPU_DAI properties. | 48 | CPU_DAI properties. |
43 | 49 | ||
44 | - uniperiph-id: internal SOC IP instance ID. | 50 | - uniperiph-id: internal SOC IP instance ID. |
45 | 51 | ||
46 | - IP mode: IP working mode depending on associated codec. | ||
47 | "HDMI" connected to HDMI codec IP and IEC HDMI formats. | ||
48 | "SPDIF"connected to SPDIF codec and support SPDIF formats. | ||
49 | "PCM" PCM standard mode for I2S or TDM bus. | ||
50 | |||
51 | Optional properties: | 52 | Optional properties: |
52 | - 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 |
53 | external codecs connection. | 54 | external codecs connection. |
@@ -56,6 +57,22 @@ Optional properties: | |||
56 | 57 | ||
57 | Example: | 58 | Example: |
58 | 59 | ||
60 | sti_uni_player1: sti-uni-player@1 { | ||
61 | compatible = "st,sti-uni-player"; | ||
62 | status = "okay"; | ||
63 | #sound-dai-cells = <0>; | ||
64 | st,syscfg = <&syscfg_core>; | ||
65 | clocks = <&clk_s_d0_flexgen CLK_PCM_1>; | ||
66 | reg = <0x8D81000 0x158>; | ||
67 | interrupts = <GIC_SPI 85 IRQ_TYPE_NONE>; | ||
68 | dmas = <&fdma0 3 0 1>; | ||
69 | st,dai-name = "Uni Player #1 (I2S)"; | ||
70 | dma-names = "tx"; | ||
71 | st,uniperiph-id = <1>; | ||
72 | st,version = <5>; | ||
73 | st,mode = "TDM"; | ||
74 | }; | ||
75 | |||
59 | sti_uni_player2: sti-uni-player@2 { | 76 | sti_uni_player2: sti-uni-player@2 { |
60 | compatible = "st,sti-uni-player"; | 77 | compatible = "st,sti-uni-player"; |
61 | status = "okay"; | 78 | status = "okay"; |
@@ -65,7 +82,7 @@ Example: | |||
65 | reg = <0x8D82000 0x158>; | 82 | reg = <0x8D82000 0x158>; |
66 | interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; | 83 | interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; |
67 | dmas = <&fdma0 4 0 1>; | 84 | dmas = <&fdma0 4 0 1>; |
68 | dai-name = "Uni Player #1 (DAC)"; | 85 | dai-name = "Uni Player #2 (DAC)"; |
69 | dma-names = "tx"; | 86 | dma-names = "tx"; |
70 | uniperiph-id = <2>; | 87 | uniperiph-id = <2>; |
71 | version = <5>; | 88 | version = <5>; |
@@ -82,7 +99,7 @@ Example: | |||
82 | interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>; | 99 | interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>; |
83 | dmas = <&fdma0 7 0 1>; | 100 | dmas = <&fdma0 7 0 1>; |
84 | dma-names = "tx"; | 101 | dma-names = "tx"; |
85 | dai-name = "Uni Player #1 (PIO)"; | 102 | dai-name = "Uni Player #3 (SPDIF)"; |
86 | uniperiph-id = <3>; | 103 | uniperiph-id = <3>; |
87 | version = <5>; | 104 | version = <5>; |
88 | mode = "SPDIF"; | 105 | mode = "SPDIF"; |
@@ -99,6 +116,7 @@ Example: | |||
99 | dma-names = "rx"; | 116 | dma-names = "rx"; |
100 | dai-name = "Uni Reader #1 (HDMI RX)"; | 117 | dai-name = "Uni Reader #1 (HDMI RX)"; |
101 | version = <3>; | 118 | version = <3>; |
119 | st,mode = "PCM"; | ||
102 | }; | 120 | }; |
103 | 121 | ||
104 | 2) sti-sas-codec: internal audio codec IPs driver | 122 | 2) sti-sas-codec: internal audio codec IPs driver |
@@ -152,4 +170,20 @@ Example of audio card declaration: | |||
152 | sound-dai = <&sti_sasg_codec 0>; | 170 | sound-dai = <&sti_sasg_codec 0>; |
153 | }; | 171 | }; |
154 | }; | 172 | }; |
173 | simple-audio-card,dai-link@2 { | ||
174 | /* TDM playback */ | ||
175 | format = "left_j"; | ||
176 | frame-inversion = <1>; | ||
177 | cpu { | ||
178 | sound-dai = <&sti_uni_player1>; | ||
179 | dai-tdm-slot-num = <16>; | ||
180 | dai-tdm-slot-width = <16>; | ||
181 | dai-tdm-slot-tx-mask = | ||
182 | <1 1 1 1 0 0 0 0 0 0 1 1 0 0 1 1>; | ||
183 | }; | ||
184 | |||
185 | codec { | ||
186 | sound-dai = <&sti_sasg_codec 3>; | ||
187 | }; | ||
188 | }; | ||
155 | }; | 189 | }; |
diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt index 0ac31d8d5ac4..b4959f10b74b 100644 --- a/Documentation/devicetree/bindings/sound/tas571x.txt +++ b/Documentation/devicetree/bindings/sound/tas571x.txt | |||
@@ -1,4 +1,4 @@ | |||
1 | Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers | 1 | Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 stereo power amplifiers |
2 | 2 | ||
3 | The codec is controlled through an I2C interface. It also has two other | 3 | The codec is controlled through an I2C interface. It also has two other |
4 | signals that can be wired up to GPIOs: reset (strongly recommended), and | 4 | signals that can be wired up to GPIOs: reset (strongly recommended), and |
@@ -6,7 +6,11 @@ powerdown (optional). | |||
6 | 6 | ||
7 | Required properties: | 7 | Required properties: |
8 | 8 | ||
9 | - compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719" | 9 | - compatible: should be one of the following: |
10 | - "ti,tas5711", | ||
11 | - "ti,tas5717", | ||
12 | - "ti,tas5719", | ||
13 | - "ti,tas5721" | ||
10 | - reg: The I2C address of the device | 14 | - reg: The I2C address of the device |
11 | - #sound-dai-cells: must be equal to 0 | 15 | - #sound-dai-cells: must be equal to 0 |
12 | 16 | ||
@@ -25,6 +29,8 @@ Optional properties: | |||
25 | - PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) | 29 | - PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) |
26 | - PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) | 30 | - PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) |
27 | - PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) | 31 | - PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) |
32 | - DRVDD-supply: regulator phandle for the DRVDD supply (5721) | ||
33 | - PVDD-supply: regulator phandle for the PVDD supply (5721) | ||
28 | 34 | ||
29 | Example: | 35 | Example: |
30 | 36 | ||
diff --git a/Documentation/devicetree/bindings/sound/tas5720.txt b/Documentation/devicetree/bindings/sound/tas5720.txt new file mode 100644 index 000000000000..806ea7381483 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas5720.txt | |||
@@ -0,0 +1,25 @@ | |||
1 | Texas Instruments TAS5720 Mono Audio amplifier | ||
2 | |||
3 | The TAS5720 serial control bus communicates through the I2C protocol only. The | ||
4 | serial bus is also used for periodic codec fault checking/reporting during | ||
5 | audio playback. For more product information please see the links below: | ||
6 | |||
7 | http://www.ti.com/product/TAS5720L | ||
8 | http://www.ti.com/product/TAS5720M | ||
9 | |||
10 | Required properties: | ||
11 | |||
12 | - compatible : "ti,tas5720" | ||
13 | - reg : I2C slave address | ||
14 | - dvdd-supply : phandle to a 3.3-V supply for the digital circuitry | ||
15 | - pvdd-supply : phandle to a supply used for the Class-D amp and the analog | ||
16 | |||
17 | Example: | ||
18 | |||
19 | tas5720: tas5720@6c { | ||
20 | status = "okay"; | ||
21 | compatible = "ti,tas5720"; | ||
22 | reg = <0x6c>; | ||
23 | dvdd-supply = <&vdd_3v3_reg>; | ||
24 | pvdd-supply = <&_supply_reg>; | ||
25 | }; | ||
diff --git a/drivers/spi/spi-ep93xx.c b/drivers/spi/spi-ep93xx.c index bb00be8d1851..17a6387e20b5 100644 --- a/drivers/spi/spi-ep93xx.c +++ b/drivers/spi/spi-ep93xx.c | |||
@@ -567,7 +567,7 @@ static void ep93xx_spi_dma_transfer(struct ep93xx_spi *espi) | |||
567 | txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV); | 567 | txd = ep93xx_spi_dma_prepare(espi, DMA_MEM_TO_DEV); |
568 | if (IS_ERR(txd)) { | 568 | if (IS_ERR(txd)) { |
569 | ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM); | 569 | ep93xx_spi_dma_finish(espi, DMA_DEV_TO_MEM); |
570 | dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(rxd)); | 570 | dev_err(&espi->pdev->dev, "DMA TX failed: %ld\n", PTR_ERR(txd)); |
571 | msg->status = PTR_ERR(txd); | 571 | msg->status = PTR_ERR(txd); |
572 | return; | 572 | return; |
573 | } | 573 | } |
diff --git a/include/linux/mfd/twl6040.h b/include/linux/mfd/twl6040.h index 8f9fc3d26e6d..8e95cd87cd74 100644 --- a/include/linux/mfd/twl6040.h +++ b/include/linux/mfd/twl6040.h | |||
@@ -134,6 +134,7 @@ | |||
134 | #define TWL6040_HFDACENA (1 << 0) | 134 | #define TWL6040_HFDACENA (1 << 0) |
135 | #define TWL6040_HFPGAENA (1 << 1) | 135 | #define TWL6040_HFPGAENA (1 << 1) |
136 | #define TWL6040_HFDRVENA (1 << 4) | 136 | #define TWL6040_HFDRVENA (1 << 4) |
137 | #define TWL6040_HFSWENA (1 << 6) | ||
137 | 138 | ||
138 | /* VIBCTLL/R (0x18/0x1A) fields */ | 139 | /* VIBCTLL/R (0x18/0x1A) fields */ |
139 | 140 | ||
diff --git a/include/uapi/sound/asoc.h b/include/uapi/sound/asoc.h index c4cc1e40b35c..e4701a3c6331 100644 --- a/include/uapi/sound/asoc.h +++ b/include/uapi/sound/asoc.h | |||
@@ -116,6 +116,14 @@ | |||
116 | #define SND_SOC_TPLG_STREAM_PLAYBACK 0 | 116 | #define SND_SOC_TPLG_STREAM_PLAYBACK 0 |
117 | #define SND_SOC_TPLG_STREAM_CAPTURE 1 | 117 | #define SND_SOC_TPLG_STREAM_CAPTURE 1 |
118 | 118 | ||
119 | /* vendor tuple types */ | ||
120 | #define SND_SOC_TPLG_TUPLE_TYPE_UUID 0 | ||
121 | #define SND_SOC_TPLG_TUPLE_TYPE_STRING 1 | ||
122 | #define SND_SOC_TPLG_TUPLE_TYPE_BOOL 2 | ||
123 | #define SND_SOC_TPLG_TUPLE_TYPE_BYTE 3 | ||
124 | #define SND_SOC_TPLG_TUPLE_TYPE_WORD 4 | ||
125 | #define SND_SOC_TPLG_TUPLE_TYPE_SHORT 5 | ||
126 | |||
119 | /* | 127 | /* |
120 | * Block Header. | 128 | * Block Header. |
121 | * This header precedes all object and object arrays below. | 129 | * This header precedes all object and object arrays below. |
@@ -132,6 +140,35 @@ struct snd_soc_tplg_hdr { | |||
132 | __le32 count; /* number of elements in block */ | 140 | __le32 count; /* number of elements in block */ |
133 | } __attribute__((packed)); | 141 | } __attribute__((packed)); |
134 | 142 | ||
143 | /* vendor tuple for uuid */ | ||
144 | struct snd_soc_tplg_vendor_uuid_elem { | ||
145 | __le32 token; | ||
146 | char uuid[16]; | ||
147 | } __attribute__((packed)); | ||
148 | |||
149 | /* vendor tuple for a bool/byte/short/word value */ | ||
150 | struct snd_soc_tplg_vendor_value_elem { | ||
151 | __le32 token; | ||
152 | __le32 value; | ||
153 | } __attribute__((packed)); | ||
154 | |||
155 | /* vendor tuple for string */ | ||
156 | struct snd_soc_tplg_vendor_string_elem { | ||
157 | __le32 token; | ||
158 | char string[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | ||
159 | } __attribute__((packed)); | ||
160 | |||
161 | struct snd_soc_tplg_vendor_array { | ||
162 | __le32 size; /* size in bytes of the array, including all elements */ | ||
163 | __le32 type; /* SND_SOC_TPLG_TUPLE_TYPE_ */ | ||
164 | __le32 num_elems; /* number of elements in array */ | ||
165 | union { | ||
166 | struct snd_soc_tplg_vendor_uuid_elem uuid[0]; | ||
167 | struct snd_soc_tplg_vendor_value_elem value[0]; | ||
168 | struct snd_soc_tplg_vendor_string_elem string[0]; | ||
169 | }; | ||
170 | } __attribute__((packed)); | ||
171 | |||
135 | /* | 172 | /* |
136 | * Private data. | 173 | * Private data. |
137 | * All topology objects may have private data that can be used by the driver or | 174 | * All topology objects may have private data that can be used by the driver or |
@@ -139,7 +176,10 @@ struct snd_soc_tplg_hdr { | |||
139 | */ | 176 | */ |
140 | struct snd_soc_tplg_private { | 177 | struct snd_soc_tplg_private { |
141 | __le32 size; /* in bytes of private data */ | 178 | __le32 size; /* in bytes of private data */ |
142 | char data[0]; | 179 | union { |
180 | char data[0]; | ||
181 | struct snd_soc_tplg_vendor_array array[0]; | ||
182 | }; | ||
143 | } __attribute__((packed)); | 183 | } __attribute__((packed)); |
144 | 184 | ||
145 | /* | 185 | /* |
@@ -383,7 +423,7 @@ struct snd_soc_tplg_pcm { | |||
383 | __le32 size; /* in bytes of this structure */ | 423 | __le32 size; /* in bytes of this structure */ |
384 | char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | 424 | char pcm_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
385 | char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | 425 | char dai_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
386 | __le32 pcm_id; /* unique ID - used to match */ | 426 | __le32 pcm_id; /* unique ID - used to match with DAI link */ |
387 | __le32 dai_id; /* unique ID - used to match */ | 427 | __le32 dai_id; /* unique ID - used to match */ |
388 | __le32 playback; /* supports playback mode */ | 428 | __le32 playback; /* supports playback mode */ |
389 | __le32 capture; /* supports capture mode */ | 429 | __le32 capture; /* supports capture mode */ |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 002f153bc659..d53c25e7a1c1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -335,6 +335,7 @@ static void alc_fill_eapd_coef(struct hda_codec *codec) | |||
335 | case 0x10ec0283: | 335 | case 0x10ec0283: |
336 | case 0x10ec0286: | 336 | case 0x10ec0286: |
337 | case 0x10ec0288: | 337 | case 0x10ec0288: |
338 | case 0x10ec0295: | ||
338 | case 0x10ec0298: | 339 | case 0x10ec0298: |
339 | alc_update_coef_idx(codec, 0x10, 1<<9, 0); | 340 | alc_update_coef_idx(codec, 0x10, 1<<9, 0); |
340 | break; | 341 | break; |
@@ -907,6 +908,7 @@ static struct alc_codec_rename_pci_table rename_pci_tbl[] = { | |||
907 | { 0x10ec0298, 0x1028, 0, "ALC3266" }, | 908 | { 0x10ec0298, 0x1028, 0, "ALC3266" }, |
908 | { 0x10ec0256, 0x1028, 0, "ALC3246" }, | 909 | { 0x10ec0256, 0x1028, 0, "ALC3246" }, |
909 | { 0x10ec0225, 0x1028, 0, "ALC3253" }, | 910 | { 0x10ec0225, 0x1028, 0, "ALC3253" }, |
911 | { 0x10ec0295, 0x1028, 0, "ALC3254" }, | ||
910 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, | 912 | { 0x10ec0670, 0x1025, 0, "ALC669X" }, |
911 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, | 913 | { 0x10ec0676, 0x1025, 0, "ALC679X" }, |
912 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, | 914 | { 0x10ec0282, 0x1043, 0, "ALC3229" }, |
@@ -3697,6 +3699,7 @@ static void alc_headset_mode_unplugged(struct hda_codec *codec) | |||
3697 | alc_process_coef_fw(codec, coef0668); | 3699 | alc_process_coef_fw(codec, coef0668); |
3698 | break; | 3700 | break; |
3699 | case 0x10ec0225: | 3701 | case 0x10ec0225: |
3702 | case 0x10ec0295: | ||
3700 | alc_process_coef_fw(codec, coef0225); | 3703 | alc_process_coef_fw(codec, coef0225); |
3701 | break; | 3704 | break; |
3702 | } | 3705 | } |
@@ -3797,6 +3800,7 @@ static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, | |||
3797 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); | 3800 | snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); |
3798 | break; | 3801 | break; |
3799 | case 0x10ec0225: | 3802 | case 0x10ec0225: |
3803 | case 0x10ec0295: | ||
3800 | alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); | 3804 | alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10); |
3801 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); | 3805 | snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); |
3802 | alc_process_coef_fw(codec, coef0225); | 3806 | alc_process_coef_fw(codec, coef0225); |
@@ -3854,6 +3858,7 @@ static void alc_headset_mode_default(struct hda_codec *codec) | |||
3854 | 3858 | ||
3855 | switch (codec->core.vendor_id) { | 3859 | switch (codec->core.vendor_id) { |
3856 | case 0x10ec0225: | 3860 | case 0x10ec0225: |
3861 | case 0x10ec0295: | ||
3857 | alc_process_coef_fw(codec, coef0225); | 3862 | alc_process_coef_fw(codec, coef0225); |
3858 | break; | 3863 | break; |
3859 | case 0x10ec0255: | 3864 | case 0x10ec0255: |
@@ -3957,6 +3962,7 @@ static void alc_headset_mode_ctia(struct hda_codec *codec) | |||
3957 | alc_process_coef_fw(codec, coef0688); | 3962 | alc_process_coef_fw(codec, coef0688); |
3958 | break; | 3963 | break; |
3959 | case 0x10ec0225: | 3964 | case 0x10ec0225: |
3965 | case 0x10ec0295: | ||
3960 | alc_process_coef_fw(codec, coef0225); | 3966 | alc_process_coef_fw(codec, coef0225); |
3961 | break; | 3967 | break; |
3962 | } | 3968 | } |
@@ -4038,6 +4044,7 @@ static void alc_headset_mode_omtp(struct hda_codec *codec) | |||
4038 | alc_process_coef_fw(codec, coef0688); | 4044 | alc_process_coef_fw(codec, coef0688); |
4039 | break; | 4045 | break; |
4040 | case 0x10ec0225: | 4046 | case 0x10ec0225: |
4047 | case 0x10ec0295: | ||
4041 | alc_process_coef_fw(codec, coef0225); | 4048 | alc_process_coef_fw(codec, coef0225); |
4042 | break; | 4049 | break; |
4043 | } | 4050 | } |
@@ -4121,6 +4128,7 @@ static void alc_determine_headset_type(struct hda_codec *codec) | |||
4121 | is_ctia = (val & 0x1c02) == 0x1c02; | 4128 | is_ctia = (val & 0x1c02) == 0x1c02; |
4122 | break; | 4129 | break; |
4123 | case 0x10ec0225: | 4130 | case 0x10ec0225: |
4131 | case 0x10ec0295: | ||
4124 | alc_process_coef_fw(codec, coef0225); | 4132 | alc_process_coef_fw(codec, coef0225); |
4125 | msleep(800); | 4133 | msleep(800); |
4126 | val = alc_read_coef_idx(codec, 0x46); | 4134 | val = alc_read_coef_idx(codec, 0x46); |
@@ -5466,8 +5474,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
5466 | SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), | 5474 | SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), |
5467 | SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), | 5475 | SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), |
5468 | SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), | 5476 | SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK), |
5469 | SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), | 5477 | SND_PCI_QUIRK(0x1028, 0x0704, "Dell XPS 13 9350", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), |
5470 | SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), | 5478 | SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE), |
5479 | SND_PCI_QUIRK(0x1028, 0x075b, "Dell XPS 13 9360", ALC256_FIXUP_DELL_XPS_13_HEADPHONE_NOISE), | ||
5471 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 5480 | SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
5472 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), | 5481 | SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), |
5473 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), | 5482 | SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), |
@@ -5711,6 +5720,9 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | |||
5711 | {0x14, 0x90170110}, | 5720 | {0x14, 0x90170110}, |
5712 | {0x21, 0x02211020}), | 5721 | {0x21, 0x02211020}), |
5713 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 5722 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
5723 | {0x14, 0x90170130}, | ||
5724 | {0x21, 0x02211040}), | ||
5725 | SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | ||
5714 | {0x12, 0x90a60140}, | 5726 | {0x12, 0x90a60140}, |
5715 | {0x14, 0x90170110}, | 5727 | {0x14, 0x90170110}, |
5716 | {0x21, 0x02211020}), | 5728 | {0x21, 0x02211020}), |
@@ -6033,6 +6045,7 @@ static int patch_alc269(struct hda_codec *codec) | |||
6033 | alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ | 6045 | alc_update_coef_idx(codec, 0x36, 1 << 13, 1 << 5); /* Switch pcbeep path to Line in path*/ |
6034 | break; | 6046 | break; |
6035 | case 0x10ec0225: | 6047 | case 0x10ec0225: |
6048 | case 0x10ec0295: | ||
6036 | spec->codec_variant = ALC269_TYPE_ALC225; | 6049 | spec->codec_variant = ALC269_TYPE_ALC225; |
6037 | break; | 6050 | break; |
6038 | case 0x10ec0234: | 6051 | case 0x10ec0234: |
@@ -6979,6 +6992,7 @@ static const struct hda_device_id snd_hda_id_realtek[] = { | |||
6979 | HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269), | 6992 | HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269), |
6980 | HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269), | 6993 | HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269), |
6981 | HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), | 6994 | HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269), |
6995 | HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269), | ||
6982 | HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), | 6996 | HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269), |
6983 | HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), | 6997 | HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861), |
6984 | HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), | 6998 | HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd), |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index b3afae990e39..4d82a58ff6b0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS | |||
43 | select SND_SOC_AK5386 | 43 | select SND_SOC_AK5386 |
44 | select SND_SOC_ALC5623 if I2C | 44 | select SND_SOC_ALC5623 if I2C |
45 | select SND_SOC_ALC5632 if I2C | 45 | select SND_SOC_ALC5632 if I2C |
46 | select SND_SOC_BT_SCO | ||
46 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 47 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
47 | select SND_SOC_CS35L32 if I2C | 48 | select SND_SOC_CS35L32 if I2C |
48 | select SND_SOC_CS42L51_I2C if I2C | 49 | select SND_SOC_CS42L51_I2C if I2C |
@@ -64,7 +65,6 @@ config SND_SOC_ALL_CODECS | |||
64 | select SND_SOC_DA732X if I2C | 65 | select SND_SOC_DA732X if I2C |
65 | select SND_SOC_DA9055 if I2C | 66 | select SND_SOC_DA9055 if I2C |
66 | select SND_SOC_DMIC | 67 | select SND_SOC_DMIC |
67 | select SND_SOC_BT_SCO | ||
68 | select SND_SOC_ES8328_SPI if SPI_MASTER | 68 | select SND_SOC_ES8328_SPI if SPI_MASTER |
69 | select SND_SOC_ES8328_I2C if I2C | 69 | select SND_SOC_ES8328_I2C if I2C |
70 | select SND_SOC_GTM601 | 70 | select SND_SOC_GTM601 |
@@ -79,6 +79,7 @@ config SND_SOC_ALL_CODECS | |||
79 | select SND_SOC_MAX98090 if I2C | 79 | select SND_SOC_MAX98090 if I2C |
80 | select SND_SOC_MAX98095 if I2C | 80 | select SND_SOC_MAX98095 if I2C |
81 | select SND_SOC_MAX98357A if GPIOLIB | 81 | select SND_SOC_MAX98357A if GPIOLIB |
82 | select SND_SOC_MAX98371 if I2C | ||
82 | select SND_SOC_MAX9867 if I2C | 83 | select SND_SOC_MAX9867 if I2C |
83 | select SND_SOC_MAX98925 if I2C | 84 | select SND_SOC_MAX98925 if I2C |
84 | select SND_SOC_MAX98926 if I2C | 85 | select SND_SOC_MAX98926 if I2C |
@@ -126,12 +127,14 @@ config SND_SOC_ALL_CODECS | |||
126 | select SND_SOC_TAS2552 if I2C | 127 | select SND_SOC_TAS2552 if I2C |
127 | select SND_SOC_TAS5086 if I2C | 128 | select SND_SOC_TAS5086 if I2C |
128 | select SND_SOC_TAS571X if I2C | 129 | select SND_SOC_TAS571X if I2C |
130 | select SND_SOC_TAS5720 if I2C | ||
129 | select SND_SOC_TFA9879 if I2C | 131 | select SND_SOC_TFA9879 if I2C |
130 | select SND_SOC_TLV320AIC23_I2C if I2C | 132 | select SND_SOC_TLV320AIC23_I2C if I2C |
131 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | 133 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER |
132 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 134 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
133 | select SND_SOC_TLV320AIC31XX if I2C | 135 | select SND_SOC_TLV320AIC31XX if I2C |
134 | select SND_SOC_TLV320AIC32X4 if I2C | 136 | select SND_SOC_TLV320AIC32X4_I2C if I2C |
137 | select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER | ||
135 | select SND_SOC_TLV320AIC3X if I2C | 138 | select SND_SOC_TLV320AIC3X if I2C |
136 | select SND_SOC_TPA6130A2 if I2C | 139 | select SND_SOC_TPA6130A2 if I2C |
137 | select SND_SOC_TLV320DAC33 if I2C | 140 | select SND_SOC_TLV320DAC33 if I2C |
@@ -367,6 +370,9 @@ config SND_SOC_ALC5623 | |||
367 | config SND_SOC_ALC5632 | 370 | config SND_SOC_ALC5632 |
368 | tristate | 371 | tristate |
369 | 372 | ||
373 | config SND_SOC_BT_SCO | ||
374 | tristate | ||
375 | |||
370 | config SND_SOC_CQ0093VC | 376 | config SND_SOC_CQ0093VC |
371 | tristate | 377 | tristate |
372 | 378 | ||
@@ -473,9 +479,6 @@ config SND_SOC_DA732X | |||
473 | config SND_SOC_DA9055 | 479 | config SND_SOC_DA9055 |
474 | tristate | 480 | tristate |
475 | 481 | ||
476 | config SND_SOC_BT_SCO | ||
477 | tristate | ||
478 | |||
479 | config SND_SOC_DMIC | 482 | config SND_SOC_DMIC |
480 | tristate | 483 | tristate |
481 | 484 | ||
@@ -529,6 +532,9 @@ config SND_SOC_MAX98095 | |||
529 | config SND_SOC_MAX98357A | 532 | config SND_SOC_MAX98357A |
530 | tristate | 533 | tristate |
531 | 534 | ||
535 | config SND_SOC_MAX98371 | ||
536 | tristate | ||
537 | |||
532 | config SND_SOC_MAX9867 | 538 | config SND_SOC_MAX9867 |
533 | tristate | 539 | tristate |
534 | 540 | ||
@@ -748,9 +754,16 @@ config SND_SOC_TAS5086 | |||
748 | depends on I2C | 754 | depends on I2C |
749 | 755 | ||
750 | config SND_SOC_TAS571X | 756 | config SND_SOC_TAS571X |
751 | tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" | 757 | tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers" |
752 | depends on I2C | 758 | depends on I2C |
753 | 759 | ||
760 | config SND_SOC_TAS5720 | ||
761 | tristate "Texas Instruments TAS5720 Mono Audio amplifier" | ||
762 | depends on I2C | ||
763 | help | ||
764 | Enable support for Texas Instruments TAS5720L/M high-efficiency mono | ||
765 | Class-D audio power amplifiers. | ||
766 | |||
754 | config SND_SOC_TFA9879 | 767 | config SND_SOC_TFA9879 |
755 | tristate "NXP Semiconductors TFA9879 amplifier" | 768 | tristate "NXP Semiconductors TFA9879 amplifier" |
756 | depends on I2C | 769 | depends on I2C |
@@ -780,6 +793,16 @@ config SND_SOC_TLV320AIC31XX | |||
780 | config SND_SOC_TLV320AIC32X4 | 793 | config SND_SOC_TLV320AIC32X4 |
781 | tristate | 794 | tristate |
782 | 795 | ||
796 | config SND_SOC_TLV320AIC32X4_I2C | ||
797 | tristate | ||
798 | depends on I2C | ||
799 | select SND_SOC_TLV320AIC32X4 | ||
800 | |||
801 | config SND_SOC_TLV320AIC32X4_SPI | ||
802 | tristate | ||
803 | depends on SPI_MASTER | ||
804 | select SND_SOC_TLV320AIC32X4 | ||
805 | |||
783 | config SND_SOC_TLV320AIC3X | 806 | config SND_SOC_TLV320AIC3X |
784 | tristate "Texas Instruments TLV320AIC3x CODECs" | 807 | tristate "Texas Instruments TLV320AIC3x CODECs" |
785 | depends on I2C | 808 | depends on I2C |
@@ -920,7 +943,8 @@ config SND_SOC_WM8955 | |||
920 | tristate | 943 | tristate |
921 | 944 | ||
922 | config SND_SOC_WM8960 | 945 | config SND_SOC_WM8960 |
923 | tristate | 946 | tristate "Wolfson Microelectronics WM8960 CODEC" |
947 | depends on I2C | ||
924 | 948 | ||
925 | config SND_SOC_WM8961 | 949 | config SND_SOC_WM8961 |
926 | tristate | 950 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index b7b99416537f..0f548fd34ca3 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -32,6 +32,7 @@ snd-soc-ak4642-objs := ak4642.o | |||
32 | snd-soc-ak4671-objs := ak4671.o | 32 | snd-soc-ak4671-objs := ak4671.o |
33 | snd-soc-ak5386-objs := ak5386.o | 33 | snd-soc-ak5386-objs := ak5386.o |
34 | snd-soc-arizona-objs := arizona.o | 34 | snd-soc-arizona-objs := arizona.o |
35 | snd-soc-bt-sco-objs := bt-sco.o | ||
35 | snd-soc-cq93vc-objs := cq93vc.o | 36 | snd-soc-cq93vc-objs := cq93vc.o |
36 | snd-soc-cs35l32-objs := cs35l32.o | 37 | snd-soc-cs35l32-objs := cs35l32.o |
37 | snd-soc-cs42l51-objs := cs42l51.o | 38 | snd-soc-cs42l51-objs := cs42l51.o |
@@ -55,7 +56,6 @@ snd-soc-da7218-objs := da7218.o | |||
55 | snd-soc-da7219-objs := da7219.o da7219-aad.o | 56 | snd-soc-da7219-objs := da7219.o da7219-aad.o |
56 | snd-soc-da732x-objs := da732x.o | 57 | snd-soc-da732x-objs := da732x.o |
57 | snd-soc-da9055-objs := da9055.o | 58 | snd-soc-da9055-objs := da9055.o |
58 | snd-soc-bt-sco-objs := bt-sco.o | ||
59 | snd-soc-dmic-objs := dmic.o | 59 | snd-soc-dmic-objs := dmic.o |
60 | snd-soc-es8328-objs := es8328.o | 60 | snd-soc-es8328-objs := es8328.o |
61 | snd-soc-es8328-i2c-objs := es8328-i2c.o | 61 | snd-soc-es8328-i2c-objs := es8328-i2c.o |
@@ -74,6 +74,7 @@ snd-soc-max98088-objs := max98088.o | |||
74 | snd-soc-max98090-objs := max98090.o | 74 | snd-soc-max98090-objs := max98090.o |
75 | snd-soc-max98095-objs := max98095.o | 75 | snd-soc-max98095-objs := max98095.o |
76 | snd-soc-max98357a-objs := max98357a.o | 76 | snd-soc-max98357a-objs := max98357a.o |
77 | snd-soc-max98371-objs := max98371.o | ||
77 | snd-soc-max9867-objs := max9867.o | 78 | snd-soc-max9867-objs := max9867.o |
78 | snd-soc-max98925-objs := max98925.o | 79 | snd-soc-max98925-objs := max98925.o |
79 | snd-soc-max98926-objs := max98926.o | 80 | snd-soc-max98926-objs := max98926.o |
@@ -131,6 +132,7 @@ snd-soc-stac9766-objs := stac9766.o | |||
131 | snd-soc-sti-sas-objs := sti-sas.o | 132 | snd-soc-sti-sas-objs := sti-sas.o |
132 | snd-soc-tas5086-objs := tas5086.o | 133 | snd-soc-tas5086-objs := tas5086.o |
133 | snd-soc-tas571x-objs := tas571x.o | 134 | snd-soc-tas571x-objs := tas571x.o |
135 | snd-soc-tas5720-objs := tas5720.o | ||
134 | snd-soc-tfa9879-objs := tfa9879.o | 136 | snd-soc-tfa9879-objs := tfa9879.o |
135 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 137 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
136 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | 138 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o |
@@ -138,6 +140,8 @@ snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | |||
138 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 140 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
139 | snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o | 141 | snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o |
140 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 142 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
143 | snd-soc-tlv320aic32x4-i2c-objs := tlv320aic32x4-i2c.o | ||
144 | snd-soc-tlv320aic32x4-spi-objs := tlv320aic32x4-spi.o | ||
141 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 145 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
142 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 146 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
143 | snd-soc-ts3a227e-objs := ts3a227e.o | 147 | snd-soc-ts3a227e-objs := ts3a227e.o |
@@ -243,6 +247,7 @@ obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o | |||
243 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 247 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o |
244 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o | 248 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o |
245 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o | 249 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o |
250 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | ||
246 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 251 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
247 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o | 252 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o |
248 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 253 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
@@ -266,7 +271,6 @@ obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o | |||
266 | obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o | 271 | obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o |
267 | obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o | 272 | obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o |
268 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o | 273 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o |
269 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | ||
270 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o | 274 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o |
271 | obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o | 275 | obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o |
272 | obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o | 276 | obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o |
@@ -339,6 +343,7 @@ obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o | |||
339 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 343 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
340 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 344 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
341 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o | 345 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o |
346 | obj-$(CONFIG_SND_SOC_TAS5720) += snd-soc-tas5720.o | ||
342 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o | 347 | obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o |
343 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 348 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
344 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | 349 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o |
@@ -346,6 +351,8 @@ obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | |||
346 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 351 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
347 | obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o | 352 | obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o |
348 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 353 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
354 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4_I2C) += snd-soc-tlv320aic32x4-i2c.o | ||
355 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4_SPI) += snd-soc-tlv320aic32x4-spi.o | ||
349 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 356 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
350 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 357 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
351 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o | 358 | obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 1ee8506c06c7..4d8b9e49e8d6 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -560,6 +560,7 @@ static const struct regmap_config ak4642_regmap = { | |||
560 | .max_register = FIL1_3, | 560 | .max_register = FIL1_3, |
561 | .reg_defaults = ak4642_reg, | 561 | .reg_defaults = ak4642_reg, |
562 | .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, | 562 | .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, |
563 | .cache_type = REGCACHE_RBTREE, | ||
563 | }; | 564 | }; |
564 | 565 | ||
565 | static const struct regmap_config ak4643_regmap = { | 566 | static const struct regmap_config ak4643_regmap = { |
@@ -568,6 +569,7 @@ static const struct regmap_config ak4643_regmap = { | |||
568 | .max_register = SPK_MS, | 569 | .max_register = SPK_MS, |
569 | .reg_defaults = ak4643_reg, | 570 | .reg_defaults = ak4643_reg, |
570 | .num_reg_defaults = ARRAY_SIZE(ak4643_reg), | 571 | .num_reg_defaults = ARRAY_SIZE(ak4643_reg), |
572 | .cache_type = REGCACHE_RBTREE, | ||
571 | }; | 573 | }; |
572 | 574 | ||
573 | static const struct regmap_config ak4648_regmap = { | 575 | static const struct regmap_config ak4648_regmap = { |
@@ -576,6 +578,7 @@ static const struct regmap_config ak4648_regmap = { | |||
576 | .max_register = EQ_FBEQE, | 578 | .max_register = EQ_FBEQE, |
577 | .reg_defaults = ak4648_reg, | 579 | .reg_defaults = ak4648_reg, |
578 | .num_reg_defaults = ARRAY_SIZE(ak4648_reg), | 580 | .num_reg_defaults = ARRAY_SIZE(ak4648_reg), |
581 | .cache_type = REGCACHE_RBTREE, | ||
579 | }; | 582 | }; |
580 | 583 | ||
581 | static const struct ak4642_drvdata ak4642_drvdata = { | 584 | static const struct ak4642_drvdata ak4642_drvdata = { |
diff --git a/sound/soc/codecs/max98371.c b/sound/soc/codecs/max98371.c new file mode 100644 index 000000000000..cf0a39bb631a --- /dev/null +++ b/sound/soc/codecs/max98371.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | * max98371.c -- ALSA SoC Stereo MAX98371 driver | ||
3 | * | ||
4 | * Copyright 2015-16 Maxim Integrated Products | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/regmap.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/pcm_params.h> | ||
17 | #include <sound/soc.h> | ||
18 | #include <sound/tlv.h> | ||
19 | #include "max98371.h" | ||
20 | |||
21 | static const char *const monomix_text[] = { | ||
22 | "Left", "Right", "LeftRightDiv2", | ||
23 | }; | ||
24 | |||
25 | static const char *const hpf_cutoff_txt[] = { | ||
26 | "Disable", "DC Block", "50Hz", | ||
27 | "100Hz", "200Hz", "400Hz", "800Hz", | ||
28 | }; | ||
29 | |||
30 | static SOC_ENUM_SINGLE_DECL(max98371_monomix, MAX98371_MONOMIX_CFG, 0, | ||
31 | monomix_text); | ||
32 | |||
33 | static SOC_ENUM_SINGLE_DECL(max98371_hpf_cutoff, MAX98371_HPF, 0, | ||
34 | hpf_cutoff_txt); | ||
35 | |||
36 | static const DECLARE_TLV_DB_RANGE(max98371_dht_min_gain, | ||
37 | 0, 1, TLV_DB_SCALE_ITEM(537, 66, 0), | ||
38 | 2, 3, TLV_DB_SCALE_ITEM(677, 82, 0), | ||
39 | 4, 5, TLV_DB_SCALE_ITEM(852, 104, 0), | ||
40 | 6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0), | ||
41 | 8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0), | ||
42 | 10, 11, TLV_DB_SCALE_ITEM(1699, 101, 0), | ||
43 | ); | ||
44 | |||
45 | static const DECLARE_TLV_DB_RANGE(max98371_dht_max_gain, | ||
46 | 0, 1, TLV_DB_SCALE_ITEM(537, 66, 0), | ||
47 | 2, 3, TLV_DB_SCALE_ITEM(677, 82, 0), | ||
48 | 4, 5, TLV_DB_SCALE_ITEM(852, 104, 0), | ||
49 | 6, 7, TLV_DB_SCALE_ITEM(1072, 131, 0), | ||
50 | 8, 9, TLV_DB_SCALE_ITEM(1350, 165, 0), | ||
51 | 10, 11, TLV_DB_SCALE_ITEM(1699, 208, 0), | ||
52 | ); | ||
53 | |||
54 | static const DECLARE_TLV_DB_RANGE(max98371_dht_rot_gain, | ||
55 | 0, 1, TLV_DB_SCALE_ITEM(-50, -50, 0), | ||
56 | 2, 6, TLV_DB_SCALE_ITEM(-100, -100, 0), | ||
57 | 7, 8, TLV_DB_SCALE_ITEM(-800, -200, 0), | ||
58 | 9, 11, TLV_DB_SCALE_ITEM(-1200, -300, 0), | ||
59 | 12, 13, TLV_DB_SCALE_ITEM(-2000, -200, 0), | ||
60 | 14, 15, TLV_DB_SCALE_ITEM(-2500, -500, 0), | ||
61 | ); | ||
62 | |||
63 | static const struct reg_default max98371_reg[] = { | ||
64 | { 0x01, 0x00 }, | ||
65 | { 0x02, 0x00 }, | ||
66 | { 0x03, 0x00 }, | ||
67 | { 0x04, 0x00 }, | ||
68 | { 0x05, 0x00 }, | ||
69 | { 0x06, 0x00 }, | ||
70 | { 0x07, 0x00 }, | ||
71 | { 0x08, 0x00 }, | ||
72 | { 0x09, 0x00 }, | ||
73 | { 0x0A, 0x00 }, | ||
74 | { 0x10, 0x06 }, | ||
75 | { 0x11, 0x08 }, | ||
76 | { 0x14, 0x80 }, | ||
77 | { 0x15, 0x00 }, | ||
78 | { 0x16, 0x00 }, | ||
79 | { 0x18, 0x00 }, | ||
80 | { 0x19, 0x00 }, | ||
81 | { 0x1C, 0x00 }, | ||
82 | { 0x1D, 0x00 }, | ||
83 | { 0x1E, 0x00 }, | ||
84 | { 0x1F, 0x00 }, | ||
85 | { 0x20, 0x00 }, | ||
86 | { 0x21, 0x00 }, | ||
87 | { 0x22, 0x00 }, | ||
88 | { 0x23, 0x00 }, | ||
89 | { 0x24, 0x00 }, | ||
90 | { 0x25, 0x00 }, | ||
91 | { 0x26, 0x00 }, | ||
92 | { 0x27, 0x00 }, | ||
93 | { 0x28, 0x00 }, | ||
94 | { 0x29, 0x00 }, | ||
95 | { 0x2A, 0x00 }, | ||
96 | { 0x2B, 0x00 }, | ||
97 | { 0x2C, 0x00 }, | ||
98 | { 0x2D, 0x00 }, | ||
99 | { 0x2E, 0x0B }, | ||
100 | { 0x31, 0x00 }, | ||
101 | { 0x32, 0x18 }, | ||
102 | { 0x33, 0x00 }, | ||
103 | { 0x34, 0x00 }, | ||
104 | { 0x36, 0x00 }, | ||
105 | { 0x37, 0x00 }, | ||
106 | { 0x38, 0x00 }, | ||
107 | { 0x39, 0x00 }, | ||
108 | { 0x3A, 0x00 }, | ||
109 | { 0x3B, 0x00 }, | ||
110 | { 0x3C, 0x00 }, | ||
111 | { 0x3D, 0x00 }, | ||
112 | { 0x3E, 0x00 }, | ||
113 | { 0x3F, 0x00 }, | ||
114 | { 0x40, 0x00 }, | ||
115 | { 0x41, 0x00 }, | ||
116 | { 0x42, 0x00 }, | ||
117 | { 0x43, 0x00 }, | ||
118 | { 0x4A, 0x00 }, | ||
119 | { 0x4B, 0x00 }, | ||
120 | { 0x4C, 0x00 }, | ||
121 | { 0x4D, 0x00 }, | ||
122 | { 0x4E, 0x00 }, | ||
123 | { 0x50, 0x00 }, | ||
124 | { 0x51, 0x00 }, | ||
125 | { 0x55, 0x00 }, | ||
126 | { 0x58, 0x00 }, | ||
127 | { 0x59, 0x00 }, | ||
128 | { 0x5C, 0x00 }, | ||
129 | { 0xFF, 0x43 }, | ||
130 | }; | ||
131 | |||
132 | static bool max98371_volatile_register(struct device *dev, unsigned int reg) | ||
133 | { | ||
134 | switch (reg) { | ||
135 | case MAX98371_IRQ_CLEAR1: | ||
136 | case MAX98371_IRQ_CLEAR2: | ||
137 | case MAX98371_IRQ_CLEAR3: | ||
138 | case MAX98371_VERSION: | ||
139 | return true; | ||
140 | default: | ||
141 | return false; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | static bool max98371_readable_register(struct device *dev, unsigned int reg) | ||
146 | { | ||
147 | switch (reg) { | ||
148 | case MAX98371_SOFT_RESET: | ||
149 | return false; | ||
150 | default: | ||
151 | return true; | ||
152 | } | ||
153 | }; | ||
154 | |||
155 | static const DECLARE_TLV_DB_RANGE(max98371_gain_tlv, | ||
156 | 0, 7, TLV_DB_SCALE_ITEM(0, 50, 0), | ||
157 | 8, 10, TLV_DB_SCALE_ITEM(400, 100, 0) | ||
158 | ); | ||
159 | |||
160 | static const DECLARE_TLV_DB_RANGE(max98371_noload_gain_tlv, | ||
161 | 0, 11, TLV_DB_SCALE_ITEM(950, 100, 0), | ||
162 | ); | ||
163 | |||
164 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -6300, 50, 1); | ||
165 | |||
166 | static const struct snd_kcontrol_new max98371_snd_controls[] = { | ||
167 | SOC_SINGLE_TLV("Speaker Volume", MAX98371_GAIN, | ||
168 | MAX98371_GAIN_SHIFT, (1<<MAX98371_GAIN_WIDTH)-1, 0, | ||
169 | max98371_gain_tlv), | ||
170 | SOC_SINGLE_TLV("Digital Volume", MAX98371_DIGITAL_GAIN, 0, | ||
171 | (1<<MAX98371_DIGITAL_GAIN_WIDTH)-1, 1, digital_tlv), | ||
172 | SOC_SINGLE_TLV("Speaker DHT Max Volume", MAX98371_GAIN, | ||
173 | 0, (1<<MAX98371_DHT_MAX_WIDTH)-1, 0, | ||
174 | max98371_dht_max_gain), | ||
175 | SOC_SINGLE_TLV("Speaker DHT Min Volume", MAX98371_DHT_GAIN, | ||
176 | 0, (1<<MAX98371_DHT_GAIN_WIDTH)-1, 0, | ||
177 | max98371_dht_min_gain), | ||
178 | SOC_SINGLE_TLV("Speaker DHT Rotation Volume", MAX98371_DHT_GAIN, | ||
179 | 0, (1<<MAX98371_DHT_ROT_WIDTH)-1, 0, | ||
180 | max98371_dht_rot_gain), | ||
181 | SOC_SINGLE("DHT Attack Step", MAX98371_DHT, MAX98371_DHT_STEP, 3, 0), | ||
182 | SOC_SINGLE("DHT Attack Rate", MAX98371_DHT, 0, 7, 0), | ||
183 | SOC_ENUM("Monomix Select", max98371_monomix), | ||
184 | SOC_ENUM("HPF Cutoff", max98371_hpf_cutoff), | ||
185 | }; | ||
186 | |||
187 | static int max98371_dai_set_fmt(struct snd_soc_dai *codec_dai, | ||
188 | unsigned int fmt) | ||
189 | { | ||
190 | struct snd_soc_codec *codec = codec_dai->codec; | ||
191 | struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec); | ||
192 | unsigned int val = 0; | ||
193 | |||
194 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
195 | case SND_SOC_DAIFMT_CBS_CFS: | ||
196 | break; | ||
197 | default: | ||
198 | dev_err(codec->dev, "DAI clock mode unsupported"); | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
203 | case SND_SOC_DAIFMT_I2S: | ||
204 | val |= 0; | ||
205 | break; | ||
206 | case SND_SOC_DAIFMT_RIGHT_J: | ||
207 | val |= MAX98371_DAI_RIGHT; | ||
208 | break; | ||
209 | case SND_SOC_DAIFMT_LEFT_J: | ||
210 | val |= MAX98371_DAI_LEFT; | ||
211 | break; | ||
212 | default: | ||
213 | dev_err(codec->dev, "DAI wrong mode unsupported"); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
217 | MAX98371_FMT_MODE_MASK, val); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int max98371_dai_hw_params(struct snd_pcm_substream *substream, | ||
222 | struct snd_pcm_hw_params *params, | ||
223 | struct snd_soc_dai *dai) | ||
224 | { | ||
225 | struct snd_soc_codec *codec = dai->codec; | ||
226 | struct max98371_priv *max98371 = snd_soc_codec_get_drvdata(codec); | ||
227 | int blr_clk_ratio, ch_size, channels = params_channels(params); | ||
228 | int rate = params_rate(params); | ||
229 | |||
230 | switch (params_format(params)) { | ||
231 | case SNDRV_PCM_FORMAT_S8: | ||
232 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
233 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16); | ||
234 | ch_size = 8; | ||
235 | break; | ||
236 | case SNDRV_PCM_FORMAT_S16_LE: | ||
237 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
238 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_16); | ||
239 | ch_size = 16; | ||
240 | break; | ||
241 | case SNDRV_PCM_FORMAT_S24_LE: | ||
242 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
243 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32); | ||
244 | ch_size = 24; | ||
245 | break; | ||
246 | case SNDRV_PCM_FORMAT_S32_LE: | ||
247 | regmap_update_bits(max98371->regmap, MAX98371_FMT, | ||
248 | MAX98371_FMT_MASK, MAX98371_DAI_CHANSZ_32); | ||
249 | ch_size = 32; | ||
250 | break; | ||
251 | default: | ||
252 | return -EINVAL; | ||
253 | } | ||
254 | |||
255 | /* BCLK/LRCLK ratio calculation */ | ||
256 | blr_clk_ratio = channels * ch_size; | ||
257 | switch (blr_clk_ratio) { | ||
258 | case 32: | ||
259 | regmap_update_bits(max98371->regmap, | ||
260 | MAX98371_DAI_CLK, | ||
261 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_32); | ||
262 | break; | ||
263 | case 48: | ||
264 | regmap_update_bits(max98371->regmap, | ||
265 | MAX98371_DAI_CLK, | ||
266 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_48); | ||
267 | break; | ||
268 | case 64: | ||
269 | regmap_update_bits(max98371->regmap, | ||
270 | MAX98371_DAI_CLK, | ||
271 | MAX98371_DAI_BSEL_MASK, MAX98371_DAI_BSEL_64); | ||
272 | break; | ||
273 | default: | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | |||
277 | switch (rate) { | ||
278 | case 32000: | ||
279 | regmap_update_bits(max98371->regmap, | ||
280 | MAX98371_SPK_SR, | ||
281 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_32); | ||
282 | break; | ||
283 | case 44100: | ||
284 | regmap_update_bits(max98371->regmap, | ||
285 | MAX98371_SPK_SR, | ||
286 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_44); | ||
287 | break; | ||
288 | case 48000: | ||
289 | regmap_update_bits(max98371->regmap, | ||
290 | MAX98371_SPK_SR, | ||
291 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_48); | ||
292 | break; | ||
293 | case 88200: | ||
294 | regmap_update_bits(max98371->regmap, | ||
295 | MAX98371_SPK_SR, | ||
296 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_88); | ||
297 | break; | ||
298 | case 96000: | ||
299 | regmap_update_bits(max98371->regmap, | ||
300 | MAX98371_SPK_SR, | ||
301 | MAX98371_SPK_SR_MASK, MAX98371_SPK_SR_96); | ||
302 | break; | ||
303 | default: | ||
304 | return -EINVAL; | ||
305 | } | ||
306 | |||
307 | /* enabling both the RX channels*/ | ||
308 | regmap_update_bits(max98371->regmap, MAX98371_MONOMIX_SRC, | ||
309 | MAX98371_MONOMIX_SRC_MASK, MONOMIX_RX_0_1); | ||
310 | regmap_update_bits(max98371->regmap, MAX98371_DAI_CHANNEL, | ||
311 | MAX98371_CHANNEL_MASK, MAX98371_CHANNEL_MASK); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static const struct snd_soc_dapm_widget max98371_dapm_widgets[] = { | ||
316 | SND_SOC_DAPM_DAC("DAC", NULL, MAX98371_SPK_ENABLE, 0, 0), | ||
317 | SND_SOC_DAPM_SUPPLY("Global Enable", MAX98371_GLOBAL_ENABLE, | ||
318 | 0, 0, NULL, 0), | ||
319 | SND_SOC_DAPM_OUTPUT("SPK_OUT"), | ||
320 | }; | ||
321 | |||
322 | static const struct snd_soc_dapm_route max98371_audio_map[] = { | ||
323 | {"DAC", NULL, "HiFi Playback"}, | ||
324 | {"SPK_OUT", NULL, "DAC"}, | ||
325 | {"SPK_OUT", NULL, "Global Enable"}, | ||
326 | }; | ||
327 | |||
328 | #define MAX98371_RATES SNDRV_PCM_RATE_8000_48000 | ||
329 | #define MAX98371_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
330 | SNDRV_PCM_FMTBIT_S24_BE | SNDRV_PCM_FMTBIT_S32_BE) | ||
331 | |||
332 | static const struct snd_soc_dai_ops max98371_dai_ops = { | ||
333 | .set_fmt = max98371_dai_set_fmt, | ||
334 | .hw_params = max98371_dai_hw_params, | ||
335 | }; | ||
336 | |||
337 | static struct snd_soc_dai_driver max98371_dai[] = { | ||
338 | { | ||
339 | .name = "max98371-aif1", | ||
340 | .playback = { | ||
341 | .stream_name = "HiFi Playback", | ||
342 | .channels_min = 1, | ||
343 | .channels_max = 2, | ||
344 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
345 | .formats = MAX98371_FORMATS, | ||
346 | }, | ||
347 | .ops = &max98371_dai_ops, | ||
348 | } | ||
349 | }; | ||
350 | |||
351 | static const struct snd_soc_codec_driver max98371_codec = { | ||
352 | .controls = max98371_snd_controls, | ||
353 | .num_controls = ARRAY_SIZE(max98371_snd_controls), | ||
354 | .dapm_routes = max98371_audio_map, | ||
355 | .num_dapm_routes = ARRAY_SIZE(max98371_audio_map), | ||
356 | .dapm_widgets = max98371_dapm_widgets, | ||
357 | .num_dapm_widgets = ARRAY_SIZE(max98371_dapm_widgets), | ||
358 | }; | ||
359 | |||
360 | static const struct regmap_config max98371_regmap = { | ||
361 | .reg_bits = 8, | ||
362 | .val_bits = 8, | ||
363 | .max_register = MAX98371_VERSION, | ||
364 | .reg_defaults = max98371_reg, | ||
365 | .num_reg_defaults = ARRAY_SIZE(max98371_reg), | ||
366 | .volatile_reg = max98371_volatile_register, | ||
367 | .readable_reg = max98371_readable_register, | ||
368 | .cache_type = REGCACHE_RBTREE, | ||
369 | }; | ||
370 | |||
371 | static int max98371_i2c_probe(struct i2c_client *i2c, | ||
372 | const struct i2c_device_id *id) | ||
373 | { | ||
374 | struct max98371_priv *max98371; | ||
375 | int ret, reg; | ||
376 | |||
377 | max98371 = devm_kzalloc(&i2c->dev, | ||
378 | sizeof(*max98371), GFP_KERNEL); | ||
379 | if (!max98371) | ||
380 | return -ENOMEM; | ||
381 | |||
382 | i2c_set_clientdata(i2c, max98371); | ||
383 | max98371->regmap = devm_regmap_init_i2c(i2c, &max98371_regmap); | ||
384 | if (IS_ERR(max98371->regmap)) { | ||
385 | ret = PTR_ERR(max98371->regmap); | ||
386 | dev_err(&i2c->dev, | ||
387 | "Failed to allocate regmap: %d\n", ret); | ||
388 | return ret; | ||
389 | } | ||
390 | |||
391 | ret = regmap_read(max98371->regmap, MAX98371_VERSION, ®); | ||
392 | if (ret < 0) { | ||
393 | dev_info(&i2c->dev, "device error %d\n", ret); | ||
394 | return ret; | ||
395 | } | ||
396 | dev_info(&i2c->dev, "device version %x\n", reg); | ||
397 | |||
398 | ret = snd_soc_register_codec(&i2c->dev, &max98371_codec, | ||
399 | max98371_dai, ARRAY_SIZE(max98371_dai)); | ||
400 | if (ret < 0) { | ||
401 | dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); | ||
402 | return ret; | ||
403 | } | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | static int max98371_i2c_remove(struct i2c_client *client) | ||
408 | { | ||
409 | snd_soc_unregister_codec(&client->dev); | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static const struct i2c_device_id max98371_i2c_id[] = { | ||
414 | { "max98371", 0 }, | ||
415 | }; | ||
416 | |||
417 | MODULE_DEVICE_TABLE(i2c, max98371_i2c_id); | ||
418 | |||
419 | static const struct of_device_id max98371_of_match[] = { | ||
420 | { .compatible = "maxim,max98371", }, | ||
421 | { } | ||
422 | }; | ||
423 | MODULE_DEVICE_TABLE(of, max98371_of_match); | ||
424 | |||
425 | static struct i2c_driver max98371_i2c_driver = { | ||
426 | .driver = { | ||
427 | .name = "max98371", | ||
428 | .owner = THIS_MODULE, | ||
429 | .pm = NULL, | ||
430 | .of_match_table = of_match_ptr(max98371_of_match), | ||
431 | }, | ||
432 | .probe = max98371_i2c_probe, | ||
433 | .remove = max98371_i2c_remove, | ||
434 | .id_table = max98371_i2c_id, | ||
435 | }; | ||
436 | |||
437 | module_i2c_driver(max98371_i2c_driver); | ||
438 | |||
439 | MODULE_AUTHOR("anish kumar <yesanishhere@gmail.com>"); | ||
440 | MODULE_DESCRIPTION("ALSA SoC MAX98371 driver"); | ||
441 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/max98371.h b/sound/soc/codecs/max98371.h new file mode 100644 index 000000000000..9f6330964d98 --- /dev/null +++ b/sound/soc/codecs/max98371.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * max98371.h -- MAX98371 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2011-2012 Maxim Integrated Products | ||
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 _MAX98371_H | ||
12 | #define _MAX98371_H | ||
13 | |||
14 | #define MAX98371_IRQ_CLEAR1 0x01 | ||
15 | #define MAX98371_IRQ_CLEAR2 0x02 | ||
16 | #define MAX98371_IRQ_CLEAR3 0x03 | ||
17 | #define MAX98371_DAI_CLK 0x10 | ||
18 | #define MAX98371_DAI_BSEL_MASK 0xF | ||
19 | #define MAX98371_DAI_BSEL_32 2 | ||
20 | #define MAX98371_DAI_BSEL_48 3 | ||
21 | #define MAX98371_DAI_BSEL_64 4 | ||
22 | #define MAX98371_SPK_SR 0x11 | ||
23 | #define MAX98371_SPK_SR_MASK 0xF | ||
24 | #define MAX98371_SPK_SR_32 6 | ||
25 | #define MAX98371_SPK_SR_44 7 | ||
26 | #define MAX98371_SPK_SR_48 8 | ||
27 | #define MAX98371_SPK_SR_88 10 | ||
28 | #define MAX98371_SPK_SR_96 11 | ||
29 | #define MAX98371_DAI_CHANNEL 0x15 | ||
30 | #define MAX98371_CHANNEL_MASK 0x3 | ||
31 | #define MAX98371_MONOMIX_SRC 0x18 | ||
32 | #define MAX98371_MONOMIX_CFG 0x19 | ||
33 | #define MAX98371_HPF 0x1C | ||
34 | #define MAX98371_MONOMIX_SRC_MASK 0xFF | ||
35 | #define MONOMIX_RX_0_1 ((0x1)<<(4)) | ||
36 | #define M98371_DAI_CHANNEL_I2S 0x3 | ||
37 | #define MAX98371_DIGITAL_GAIN 0x2D | ||
38 | #define MAX98371_DIGITAL_GAIN_WIDTH 0x7 | ||
39 | #define MAX98371_GAIN 0x2E | ||
40 | #define MAX98371_GAIN_SHIFT 0x4 | ||
41 | #define MAX98371_GAIN_WIDTH 0x4 | ||
42 | #define MAX98371_DHT_MAX_WIDTH 4 | ||
43 | #define MAX98371_FMT 0x14 | ||
44 | #define MAX98371_CHANSZ_WIDTH 6 | ||
45 | #define MAX98371_FMT_MASK ((0x3)<<(MAX98371_CHANSZ_WIDTH)) | ||
46 | #define MAX98371_FMT_MODE_MASK ((0x7)<<(3)) | ||
47 | #define MAX98371_DAI_LEFT ((0x1)<<(3)) | ||
48 | #define MAX98371_DAI_RIGHT ((0x2)<<(3)) | ||
49 | #define MAX98371_DAI_CHANSZ_16 ((1)<<(MAX98371_CHANSZ_WIDTH)) | ||
50 | #define MAX98371_DAI_CHANSZ_24 ((2)<<(MAX98371_CHANSZ_WIDTH)) | ||
51 | #define MAX98371_DAI_CHANSZ_32 ((3)<<(MAX98371_CHANSZ_WIDTH)) | ||
52 | #define MAX98371_DHT 0x32 | ||
53 | #define MAX98371_DHT_STEP 0x3 | ||
54 | #define MAX98371_DHT_GAIN 0x31 | ||
55 | #define MAX98371_DHT_GAIN_WIDTH 0x4 | ||
56 | #define MAX98371_DHT_ROT_WIDTH 0x4 | ||
57 | #define MAX98371_SPK_ENABLE 0x4A | ||
58 | #define MAX98371_GLOBAL_ENABLE 0x50 | ||
59 | #define MAX98371_SOFT_RESET 0x51 | ||
60 | #define MAX98371_VERSION 0xFF | ||
61 | |||
62 | |||
63 | struct max98371_priv { | ||
64 | struct regmap *regmap; | ||
65 | struct snd_soc_codec *codec; | ||
66 | }; | ||
67 | #endif | ||
diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index a1aaffc20862..f80cfe4d2ef2 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c | |||
@@ -276,6 +276,8 @@ static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) | |||
276 | } else { | 276 | } else { |
277 | *mic = false; | 277 | *mic = false; |
278 | regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); | 278 | regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); |
279 | regmap_update_bits(rt298->regmap, | ||
280 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
279 | } | 281 | } |
280 | } else { | 282 | } else { |
281 | regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); | 283 | regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); |
@@ -482,6 +484,26 @@ static int rt298_adc_event(struct snd_soc_dapm_widget *w, | |||
482 | snd_soc_update_bits(codec, | 484 | snd_soc_update_bits(codec, |
483 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), | 485 | VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), |
484 | 0x7080, 0x7000); | 486 | 0x7080, 0x7000); |
487 | /* If MCLK doesn't exist, reset AD filter */ | ||
488 | if (!(snd_soc_read(codec, RT298_VAD_CTRL) & 0x200)) { | ||
489 | pr_info("NO MCLK\n"); | ||
490 | switch (nid) { | ||
491 | case RT298_ADC_IN1: | ||
492 | snd_soc_update_bits(codec, | ||
493 | RT298_D_FILTER_CTRL, 0x2, 0x2); | ||
494 | mdelay(10); | ||
495 | snd_soc_update_bits(codec, | ||
496 | RT298_D_FILTER_CTRL, 0x2, 0x0); | ||
497 | break; | ||
498 | case RT298_ADC_IN2: | ||
499 | snd_soc_update_bits(codec, | ||
500 | RT298_D_FILTER_CTRL, 0x4, 0x4); | ||
501 | mdelay(10); | ||
502 | snd_soc_update_bits(codec, | ||
503 | RT298_D_FILTER_CTRL, 0x4, 0x0); | ||
504 | break; | ||
505 | } | ||
506 | } | ||
485 | break; | 507 | break; |
486 | case SND_SOC_DAPM_PRE_PMD: | 508 | case SND_SOC_DAPM_PRE_PMD: |
487 | snd_soc_update_bits(codec, | 509 | snd_soc_update_bits(codec, |
@@ -520,30 +542,12 @@ static int rt298_mic1_event(struct snd_soc_dapm_widget *w, | |||
520 | return 0; | 542 | return 0; |
521 | } | 543 | } |
522 | 544 | ||
523 | static int rt298_vref_event(struct snd_soc_dapm_widget *w, | ||
524 | struct snd_kcontrol *kcontrol, int event) | ||
525 | { | ||
526 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
527 | |||
528 | switch (event) { | ||
529 | case SND_SOC_DAPM_PRE_PMU: | ||
530 | snd_soc_update_bits(codec, | ||
531 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
532 | mdelay(50); | ||
533 | break; | ||
534 | default: | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { | 545 | static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { |
542 | 546 | ||
543 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, | 547 | SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, |
544 | 12, 1, NULL, 0), | 548 | 12, 1, NULL, 0), |
545 | SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, | 549 | SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, |
546 | 0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU), | 550 | 0, 1, NULL, 0), |
547 | SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, | 551 | SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, |
548 | 1, 0, NULL, 0), | 552 | 1, 0, NULL, 0), |
549 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, | 553 | SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, |
@@ -934,18 +938,9 @@ static int rt298_set_bias_level(struct snd_soc_codec *codec, | |||
934 | } | 938 | } |
935 | break; | 939 | break; |
936 | 940 | ||
937 | case SND_SOC_BIAS_ON: | ||
938 | mdelay(30); | ||
939 | snd_soc_update_bits(codec, | ||
940 | RT298_CBJ_CTRL1, 0x0400, 0x0400); | ||
941 | |||
942 | break; | ||
943 | |||
944 | case SND_SOC_BIAS_STANDBY: | 941 | case SND_SOC_BIAS_STANDBY: |
945 | snd_soc_write(codec, | 942 | snd_soc_write(codec, |
946 | RT298_SET_AUDIO_POWER, AC_PWRST_D3); | 943 | RT298_SET_AUDIO_POWER, AC_PWRST_D3); |
947 | snd_soc_update_bits(codec, | ||
948 | RT298_CBJ_CTRL1, 0x0400, 0x0000); | ||
949 | break; | 944 | break; |
950 | 945 | ||
951 | default: | 946 | default: |
diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h index d66f8847b676..3638f3d61209 100644 --- a/sound/soc/codecs/rt298.h +++ b/sound/soc/codecs/rt298.h | |||
@@ -137,6 +137,7 @@ | |||
137 | #define RT298_A_BIAS_CTRL2 0x02 | 137 | #define RT298_A_BIAS_CTRL2 0x02 |
138 | #define RT298_POWER_CTRL1 0x03 | 138 | #define RT298_POWER_CTRL1 0x03 |
139 | #define RT298_A_BIAS_CTRL3 0x04 | 139 | #define RT298_A_BIAS_CTRL3 0x04 |
140 | #define RT298_D_FILTER_CTRL 0x05 | ||
140 | #define RT298_POWER_CTRL2 0x08 | 141 | #define RT298_POWER_CTRL2 0x08 |
141 | #define RT298_I2S_CTRL1 0x09 | 142 | #define RT298_I2S_CTRL1 0x09 |
142 | #define RT298_I2S_CTRL2 0x0a | 143 | #define RT298_I2S_CTRL2 0x0a |
@@ -148,6 +149,7 @@ | |||
148 | #define RT298_IRQ_CTRL 0x33 | 149 | #define RT298_IRQ_CTRL 0x33 |
149 | #define RT298_WIND_FILTER_CTRL 0x46 | 150 | #define RT298_WIND_FILTER_CTRL 0x46 |
150 | #define RT298_PLL_CTRL1 0x49 | 151 | #define RT298_PLL_CTRL1 0x49 |
152 | #define RT298_VAD_CTRL 0x4e | ||
151 | #define RT298_CBJ_CTRL1 0x4f | 153 | #define RT298_CBJ_CTRL1 0x4f |
152 | #define RT298_CBJ_CTRL2 0x50 | 154 | #define RT298_CBJ_CTRL2 0x50 |
153 | #define RT298_PLL_CTRL 0x63 | 155 | #define RT298_PLL_CTRL 0x63 |
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 60212266d5d1..da9483c1c6fb 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -1241,60 +1241,46 @@ static int rt5677_dmic_use_asrc(struct snd_soc_dapm_widget *source, | |||
1241 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | 1241 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); |
1242 | asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >> | 1242 | asrc_setting = (asrc_setting & RT5677_AD_STO1_CLK_SEL_MASK) >> |
1243 | RT5677_AD_STO1_CLK_SEL_SFT; | 1243 | RT5677_AD_STO1_CLK_SEL_SFT; |
1244 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1245 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1246 | return 1; | ||
1247 | break; | 1244 | break; |
1248 | 1245 | ||
1249 | case 10: | 1246 | case 10: |
1250 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | 1247 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); |
1251 | asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >> | 1248 | asrc_setting = (asrc_setting & RT5677_AD_STO2_CLK_SEL_MASK) >> |
1252 | RT5677_AD_STO2_CLK_SEL_SFT; | 1249 | RT5677_AD_STO2_CLK_SEL_SFT; |
1253 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1254 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1255 | return 1; | ||
1256 | break; | 1250 | break; |
1257 | 1251 | ||
1258 | case 9: | 1252 | case 9: |
1259 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | 1253 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); |
1260 | asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >> | 1254 | asrc_setting = (asrc_setting & RT5677_AD_STO3_CLK_SEL_MASK) >> |
1261 | RT5677_AD_STO3_CLK_SEL_SFT; | 1255 | RT5677_AD_STO3_CLK_SEL_SFT; |
1262 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1263 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1264 | return 1; | ||
1265 | break; | 1256 | break; |
1266 | 1257 | ||
1267 | case 8: | 1258 | case 8: |
1268 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); | 1259 | regmap_read(rt5677->regmap, RT5677_ASRC_5, &asrc_setting); |
1269 | asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >> | 1260 | asrc_setting = (asrc_setting & RT5677_AD_STO4_CLK_SEL_MASK) >> |
1270 | RT5677_AD_STO4_CLK_SEL_SFT; | 1261 | RT5677_AD_STO4_CLK_SEL_SFT; |
1271 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1272 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1273 | return 1; | ||
1274 | break; | 1262 | break; |
1275 | 1263 | ||
1276 | case 7: | 1264 | case 7: |
1277 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); | 1265 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); |
1278 | asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >> | 1266 | asrc_setting = (asrc_setting & RT5677_AD_MONOL_CLK_SEL_MASK) >> |
1279 | RT5677_AD_MONOL_CLK_SEL_SFT; | 1267 | RT5677_AD_MONOL_CLK_SEL_SFT; |
1280 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1281 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1282 | return 1; | ||
1283 | break; | 1268 | break; |
1284 | 1269 | ||
1285 | case 6: | 1270 | case 6: |
1286 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); | 1271 | regmap_read(rt5677->regmap, RT5677_ASRC_6, &asrc_setting); |
1287 | asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >> | 1272 | asrc_setting = (asrc_setting & RT5677_AD_MONOR_CLK_SEL_MASK) >> |
1288 | RT5677_AD_MONOR_CLK_SEL_SFT; | 1273 | RT5677_AD_MONOR_CLK_SEL_SFT; |
1289 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1290 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1291 | return 1; | ||
1292 | break; | 1274 | break; |
1293 | 1275 | ||
1294 | default: | 1276 | default: |
1295 | break; | 1277 | return 0; |
1296 | } | 1278 | } |
1297 | 1279 | ||
1280 | if (asrc_setting >= RT5677_CLK_SEL_I2S1_ASRC && | ||
1281 | asrc_setting <= RT5677_CLK_SEL_I2S6_ASRC) | ||
1282 | return 1; | ||
1283 | |||
1298 | return 0; | 1284 | return 0; |
1299 | } | 1285 | } |
1300 | 1286 | ||
diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 39307ad41a34..b8d19b77bde9 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c | |||
@@ -4,6 +4,9 @@ | |||
4 | * Copyright (C) 2015 Google, Inc. | 4 | * Copyright (C) 2015 Google, Inc. |
5 | * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> | 5 | * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> |
6 | * | 6 | * |
7 | * TAS5721 support: | ||
8 | * Copyright (C) 2016 Petr Kulhavy, Barix AG <petr@barix.com> | ||
9 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
@@ -57,6 +60,10 @@ static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) | |||
57 | case TAS571X_CH1_VOL_REG: | 60 | case TAS571X_CH1_VOL_REG: |
58 | case TAS571X_CH2_VOL_REG: | 61 | case TAS571X_CH2_VOL_REG: |
59 | return priv->chip->vol_reg_size; | 62 | return priv->chip->vol_reg_size; |
63 | case TAS571X_INPUT_MUX_REG: | ||
64 | case TAS571X_CH4_SRC_SELECT_REG: | ||
65 | case TAS571X_PWM_MUX_REG: | ||
66 | return 4; | ||
60 | default: | 67 | default: |
61 | return 1; | 68 | return 1; |
62 | } | 69 | } |
@@ -167,6 +174,23 @@ static int tas571x_hw_params(struct snd_pcm_substream *substream, | |||
167 | TAS571X_SDI_FMT_MASK, val); | 174 | TAS571X_SDI_FMT_MASK, val); |
168 | } | 175 | } |
169 | 176 | ||
177 | static int tas571x_mute(struct snd_soc_dai *dai, int mute) | ||
178 | { | ||
179 | struct snd_soc_codec *codec = dai->codec; | ||
180 | u8 sysctl2; | ||
181 | int ret; | ||
182 | |||
183 | sysctl2 = mute ? TAS571X_SYS_CTRL_2_SDN_MASK : 0; | ||
184 | |||
185 | ret = snd_soc_update_bits(codec, | ||
186 | TAS571X_SYS_CTRL_2_REG, | ||
187 | TAS571X_SYS_CTRL_2_SDN_MASK, | ||
188 | sysctl2); | ||
189 | usleep_range(1000, 2000); | ||
190 | |||
191 | return ret; | ||
192 | } | ||
193 | |||
170 | static int tas571x_set_bias_level(struct snd_soc_codec *codec, | 194 | static int tas571x_set_bias_level(struct snd_soc_codec *codec, |
171 | enum snd_soc_bias_level level) | 195 | enum snd_soc_bias_level level) |
172 | { | 196 | { |
@@ -214,6 +238,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, | |||
214 | static const struct snd_soc_dai_ops tas571x_dai_ops = { | 238 | static const struct snd_soc_dai_ops tas571x_dai_ops = { |
215 | .set_fmt = tas571x_set_dai_fmt, | 239 | .set_fmt = tas571x_set_dai_fmt, |
216 | .hw_params = tas571x_hw_params, | 240 | .hw_params = tas571x_hw_params, |
241 | .digital_mute = tas571x_mute, | ||
217 | }; | 242 | }; |
218 | 243 | ||
219 | static const char *const tas5711_supply_names[] = { | 244 | static const char *const tas5711_supply_names[] = { |
@@ -241,6 +266,26 @@ static const struct snd_kcontrol_new tas5711_controls[] = { | |||
241 | 1, 1), | 266 | 1, 1), |
242 | }; | 267 | }; |
243 | 268 | ||
269 | static const struct regmap_range tas571x_readonly_regs_range[] = { | ||
270 | regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_DEV_ID_REG), | ||
271 | }; | ||
272 | |||
273 | static const struct regmap_range tas571x_volatile_regs_range[] = { | ||
274 | regmap_reg_range(TAS571X_CLK_CTRL_REG, TAS571X_ERR_STATUS_REG), | ||
275 | regmap_reg_range(TAS571X_OSC_TRIM_REG, TAS571X_OSC_TRIM_REG), | ||
276 | }; | ||
277 | |||
278 | static const struct regmap_access_table tas571x_write_regs = { | ||
279 | .no_ranges = tas571x_readonly_regs_range, | ||
280 | .n_no_ranges = ARRAY_SIZE(tas571x_readonly_regs_range), | ||
281 | }; | ||
282 | |||
283 | static const struct regmap_access_table tas571x_volatile_regs = { | ||
284 | .yes_ranges = tas571x_volatile_regs_range, | ||
285 | .n_yes_ranges = ARRAY_SIZE(tas571x_volatile_regs_range), | ||
286 | |||
287 | }; | ||
288 | |||
244 | static const struct reg_default tas5711_reg_defaults[] = { | 289 | static const struct reg_default tas5711_reg_defaults[] = { |
245 | { 0x04, 0x05 }, | 290 | { 0x04, 0x05 }, |
246 | { 0x05, 0x40 }, | 291 | { 0x05, 0x40 }, |
@@ -260,6 +305,8 @@ static const struct regmap_config tas5711_regmap_config = { | |||
260 | .reg_defaults = tas5711_reg_defaults, | 305 | .reg_defaults = tas5711_reg_defaults, |
261 | .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), | 306 | .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), |
262 | .cache_type = REGCACHE_RBTREE, | 307 | .cache_type = REGCACHE_RBTREE, |
308 | .wr_table = &tas571x_write_regs, | ||
309 | .volatile_table = &tas571x_volatile_regs, | ||
263 | }; | 310 | }; |
264 | 311 | ||
265 | static const struct tas571x_chip tas5711_chip = { | 312 | static const struct tas571x_chip tas5711_chip = { |
@@ -314,6 +361,8 @@ static const struct regmap_config tas5717_regmap_config = { | |||
314 | .reg_defaults = tas5717_reg_defaults, | 361 | .reg_defaults = tas5717_reg_defaults, |
315 | .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), | 362 | .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), |
316 | .cache_type = REGCACHE_RBTREE, | 363 | .cache_type = REGCACHE_RBTREE, |
364 | .wr_table = &tas571x_write_regs, | ||
365 | .volatile_table = &tas571x_volatile_regs, | ||
317 | }; | 366 | }; |
318 | 367 | ||
319 | /* This entry is reused for tas5719 as the software interface is identical. */ | 368 | /* This entry is reused for tas5719 as the software interface is identical. */ |
@@ -326,6 +375,77 @@ static const struct tas571x_chip tas5717_chip = { | |||
326 | .vol_reg_size = 2, | 375 | .vol_reg_size = 2, |
327 | }; | 376 | }; |
328 | 377 | ||
378 | static const char *const tas5721_supply_names[] = { | ||
379 | "AVDD", | ||
380 | "DVDD", | ||
381 | "DRVDD", | ||
382 | "PVDD", | ||
383 | }; | ||
384 | |||
385 | static const struct snd_kcontrol_new tas5721_controls[] = { | ||
386 | SOC_SINGLE_TLV("Master Volume", | ||
387 | TAS571X_MVOL_REG, | ||
388 | 0, 0xff, 1, tas5711_volume_tlv), | ||
389 | SOC_DOUBLE_R_TLV("Speaker Volume", | ||
390 | TAS571X_CH1_VOL_REG, | ||
391 | TAS571X_CH2_VOL_REG, | ||
392 | 0, 0xff, 1, tas5711_volume_tlv), | ||
393 | SOC_DOUBLE("Speaker Switch", | ||
394 | TAS571X_SOFT_MUTE_REG, | ||
395 | TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, | ||
396 | 1, 1), | ||
397 | }; | ||
398 | |||
399 | static const struct reg_default tas5721_reg_defaults[] = { | ||
400 | {TAS571X_CLK_CTRL_REG, 0x6c}, | ||
401 | {TAS571X_DEV_ID_REG, 0x00}, | ||
402 | {TAS571X_ERR_STATUS_REG, 0x00}, | ||
403 | {TAS571X_SYS_CTRL_1_REG, 0xa0}, | ||
404 | {TAS571X_SDI_REG, 0x05}, | ||
405 | {TAS571X_SYS_CTRL_2_REG, 0x40}, | ||
406 | {TAS571X_SOFT_MUTE_REG, 0x00}, | ||
407 | {TAS571X_MVOL_REG, 0xff}, | ||
408 | {TAS571X_CH1_VOL_REG, 0x30}, | ||
409 | {TAS571X_CH2_VOL_REG, 0x30}, | ||
410 | {TAS571X_CH3_VOL_REG, 0x30}, | ||
411 | {TAS571X_VOL_CFG_REG, 0x91}, | ||
412 | {TAS571X_MODULATION_LIMIT_REG, 0x02}, | ||
413 | {TAS571X_IC_DELAY_CH1_REG, 0xac}, | ||
414 | {TAS571X_IC_DELAY_CH2_REG, 0x54}, | ||
415 | {TAS571X_IC_DELAY_CH3_REG, 0xac}, | ||
416 | {TAS571X_IC_DELAY_CH4_REG, 0x54}, | ||
417 | {TAS571X_PWM_CH_SDN_GROUP_REG, 0x30}, | ||
418 | {TAS571X_START_STOP_PERIOD_REG, 0x0f}, | ||
419 | {TAS571X_OSC_TRIM_REG, 0x82}, | ||
420 | {TAS571X_BKND_ERR_REG, 0x02}, | ||
421 | {TAS571X_INPUT_MUX_REG, 0x17772}, | ||
422 | {TAS571X_CH4_SRC_SELECT_REG, 0x4303}, | ||
423 | {TAS571X_PWM_MUX_REG, 0x1021345}, | ||
424 | }; | ||
425 | |||
426 | static const struct regmap_config tas5721_regmap_config = { | ||
427 | .reg_bits = 8, | ||
428 | .val_bits = 32, | ||
429 | .max_register = 0xff, | ||
430 | .reg_read = tas571x_reg_read, | ||
431 | .reg_write = tas571x_reg_write, | ||
432 | .reg_defaults = tas5721_reg_defaults, | ||
433 | .num_reg_defaults = ARRAY_SIZE(tas5721_reg_defaults), | ||
434 | .cache_type = REGCACHE_RBTREE, | ||
435 | .wr_table = &tas571x_write_regs, | ||
436 | .volatile_table = &tas571x_volatile_regs, | ||
437 | }; | ||
438 | |||
439 | |||
440 | static const struct tas571x_chip tas5721_chip = { | ||
441 | .supply_names = tas5721_supply_names, | ||
442 | .num_supply_names = ARRAY_SIZE(tas5721_supply_names), | ||
443 | .controls = tas5711_controls, | ||
444 | .num_controls = ARRAY_SIZE(tas5711_controls), | ||
445 | .regmap_config = &tas5721_regmap_config, | ||
446 | .vol_reg_size = 1, | ||
447 | }; | ||
448 | |||
329 | static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { | 449 | static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { |
330 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | 450 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), |
331 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | 451 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), |
@@ -386,11 +506,10 @@ static int tas571x_i2c_probe(struct i2c_client *client, | |||
386 | i2c_set_clientdata(client, priv); | 506 | i2c_set_clientdata(client, priv); |
387 | 507 | ||
388 | of_id = of_match_device(tas571x_of_match, dev); | 508 | of_id = of_match_device(tas571x_of_match, dev); |
389 | if (!of_id) { | 509 | if (of_id) |
390 | dev_err(dev, "Unknown device type\n"); | 510 | priv->chip = of_id->data; |
391 | return -EINVAL; | 511 | else |
392 | } | 512 | priv->chip = (void *) id->driver_data; |
393 | priv->chip = of_id->data; | ||
394 | 513 | ||
395 | priv->mclk = devm_clk_get(dev, "mclk"); | 514 | priv->mclk = devm_clk_get(dev, "mclk"); |
396 | if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { | 515 | if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { |
@@ -445,10 +564,6 @@ static int tas571x_i2c_probe(struct i2c_client *client, | |||
445 | if (ret) | 564 | if (ret) |
446 | return ret; | 565 | return ret; |
447 | 566 | ||
448 | ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG, | ||
449 | TAS571X_SYS_CTRL_2_SDN_MASK, 0); | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | 567 | ||
453 | memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); | 568 | memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); |
454 | priv->codec_driver.controls = priv->chip->controls; | 569 | priv->codec_driver.controls = priv->chip->controls; |
@@ -486,14 +601,16 @@ static const struct of_device_id tas571x_of_match[] = { | |||
486 | { .compatible = "ti,tas5711", .data = &tas5711_chip, }, | 601 | { .compatible = "ti,tas5711", .data = &tas5711_chip, }, |
487 | { .compatible = "ti,tas5717", .data = &tas5717_chip, }, | 602 | { .compatible = "ti,tas5717", .data = &tas5717_chip, }, |
488 | { .compatible = "ti,tas5719", .data = &tas5717_chip, }, | 603 | { .compatible = "ti,tas5719", .data = &tas5717_chip, }, |
604 | { .compatible = "ti,tas5721", .data = &tas5721_chip, }, | ||
489 | { } | 605 | { } |
490 | }; | 606 | }; |
491 | MODULE_DEVICE_TABLE(of, tas571x_of_match); | 607 | MODULE_DEVICE_TABLE(of, tas571x_of_match); |
492 | 608 | ||
493 | static const struct i2c_device_id tas571x_i2c_id[] = { | 609 | static const struct i2c_device_id tas571x_i2c_id[] = { |
494 | { "tas5711", 0 }, | 610 | { "tas5711", (kernel_ulong_t) &tas5711_chip }, |
495 | { "tas5717", 0 }, | 611 | { "tas5717", (kernel_ulong_t) &tas5717_chip }, |
496 | { "tas5719", 0 }, | 612 | { "tas5719", (kernel_ulong_t) &tas5717_chip }, |
613 | { "tas5721", (kernel_ulong_t) &tas5721_chip }, | ||
497 | { } | 614 | { } |
498 | }; | 615 | }; |
499 | MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); | 616 | MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); |
diff --git a/sound/soc/codecs/tas571x.h b/sound/soc/codecs/tas571x.h index 0aee471232cd..cf800c364f0f 100644 --- a/sound/soc/codecs/tas571x.h +++ b/sound/soc/codecs/tas571x.h | |||
@@ -13,6 +13,10 @@ | |||
13 | #define _TAS571X_H | 13 | #define _TAS571X_H |
14 | 14 | ||
15 | /* device registers */ | 15 | /* device registers */ |
16 | #define TAS571X_CLK_CTRL_REG 0x00 | ||
17 | #define TAS571X_DEV_ID_REG 0x01 | ||
18 | #define TAS571X_ERR_STATUS_REG 0x02 | ||
19 | #define TAS571X_SYS_CTRL_1_REG 0x03 | ||
16 | #define TAS571X_SDI_REG 0x04 | 20 | #define TAS571X_SDI_REG 0x04 |
17 | #define TAS571X_SDI_FMT_MASK 0x0f | 21 | #define TAS571X_SDI_FMT_MASK 0x0f |
18 | 22 | ||
@@ -27,7 +31,25 @@ | |||
27 | #define TAS571X_MVOL_REG 0x07 | 31 | #define TAS571X_MVOL_REG 0x07 |
28 | #define TAS571X_CH1_VOL_REG 0x08 | 32 | #define TAS571X_CH1_VOL_REG 0x08 |
29 | #define TAS571X_CH2_VOL_REG 0x09 | 33 | #define TAS571X_CH2_VOL_REG 0x09 |
34 | #define TAS571X_CH3_VOL_REG 0x0a | ||
35 | #define TAS571X_VOL_CFG_REG 0x0e | ||
36 | #define TAS571X_MODULATION_LIMIT_REG 0x10 | ||
37 | #define TAS571X_IC_DELAY_CH1_REG 0x11 | ||
38 | #define TAS571X_IC_DELAY_CH2_REG 0x12 | ||
39 | #define TAS571X_IC_DELAY_CH3_REG 0x13 | ||
40 | #define TAS571X_IC_DELAY_CH4_REG 0x14 | ||
30 | 41 | ||
42 | #define TAS571X_PWM_CH_SDN_GROUP_REG 0x19 /* N/A on TAS5717, TAS5719 */ | ||
43 | #define TAS571X_PWM_CH1_SDN_MASK (1<<0) | ||
44 | #define TAS571X_PWM_CH2_SDN_SHIFT (1<<1) | ||
45 | #define TAS571X_PWM_CH3_SDN_SHIFT (1<<2) | ||
46 | #define TAS571X_PWM_CH4_SDN_SHIFT (1<<3) | ||
47 | |||
48 | #define TAS571X_START_STOP_PERIOD_REG 0x1a | ||
31 | #define TAS571X_OSC_TRIM_REG 0x1b | 49 | #define TAS571X_OSC_TRIM_REG 0x1b |
50 | #define TAS571X_BKND_ERR_REG 0x1c | ||
51 | #define TAS571X_INPUT_MUX_REG 0x20 | ||
52 | #define TAS571X_CH4_SRC_SELECT_REG 0x21 | ||
53 | #define TAS571X_PWM_MUX_REG 0x25 | ||
32 | 54 | ||
33 | #endif /* _TAS571X_H */ | 55 | #endif /* _TAS571X_H */ |
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c new file mode 100644 index 000000000000..f54fb46b77c2 --- /dev/null +++ b/sound/soc/codecs/tas5720.c | |||
@@ -0,0 +1,620 @@ | |||
1 | /* | ||
2 | * tas5720.c - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier | ||
3 | * | ||
4 | * Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Author: Andreas Dannenberg <dannenberg@ti.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 | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/pm_runtime.h> | ||
23 | #include <linux/regmap.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/delay.h> | ||
27 | |||
28 | #include <sound/pcm.h> | ||
29 | #include <sound/pcm_params.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <sound/tlv.h> | ||
33 | |||
34 | #include "tas5720.h" | ||
35 | |||
36 | /* Define how often to check (and clear) the fault status register (in ms) */ | ||
37 | #define TAS5720_FAULT_CHECK_INTERVAL 200 | ||
38 | |||
39 | static const char * const tas5720_supply_names[] = { | ||
40 | "dvdd", /* Digital power supply. Connect to 3.3-V supply. */ | ||
41 | "pvdd", /* Class-D amp and analog power supply (connected). */ | ||
42 | }; | ||
43 | |||
44 | #define TAS5720_NUM_SUPPLIES ARRAY_SIZE(tas5720_supply_names) | ||
45 | |||
46 | struct tas5720_data { | ||
47 | struct snd_soc_codec *codec; | ||
48 | struct regmap *regmap; | ||
49 | struct i2c_client *tas5720_client; | ||
50 | struct regulator_bulk_data supplies[TAS5720_NUM_SUPPLIES]; | ||
51 | struct delayed_work fault_check_work; | ||
52 | unsigned int last_fault; | ||
53 | }; | ||
54 | |||
55 | static int tas5720_hw_params(struct snd_pcm_substream *substream, | ||
56 | struct snd_pcm_hw_params *params, | ||
57 | struct snd_soc_dai *dai) | ||
58 | { | ||
59 | struct snd_soc_codec *codec = dai->codec; | ||
60 | unsigned int rate = params_rate(params); | ||
61 | bool ssz_ds; | ||
62 | int ret; | ||
63 | |||
64 | switch (rate) { | ||
65 | case 44100: | ||
66 | case 48000: | ||
67 | ssz_ds = false; | ||
68 | break; | ||
69 | case 88200: | ||
70 | case 96000: | ||
71 | ssz_ds = true; | ||
72 | break; | ||
73 | default: | ||
74 | dev_err(codec->dev, "unsupported sample rate: %u\n", rate); | ||
75 | return -EINVAL; | ||
76 | } | ||
77 | |||
78 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
79 | TAS5720_SSZ_DS, ssz_ds); | ||
80 | if (ret < 0) { | ||
81 | dev_err(codec->dev, "error setting sample rate: %d\n", ret); | ||
82 | return ret; | ||
83 | } | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int tas5720_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
89 | { | ||
90 | struct snd_soc_codec *codec = dai->codec; | ||
91 | u8 serial_format; | ||
92 | int ret; | ||
93 | |||
94 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { | ||
95 | dev_vdbg(codec->dev, "DAI Format master is not found\n"); | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | |||
99 | switch (fmt & (SND_SOC_DAIFMT_FORMAT_MASK | | ||
100 | SND_SOC_DAIFMT_INV_MASK)) { | ||
101 | case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF): | ||
102 | /* 1st data bit occur one BCLK cycle after the frame sync */ | ||
103 | serial_format = TAS5720_SAIF_I2S; | ||
104 | break; | ||
105 | case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF): | ||
106 | /* | ||
107 | * Note that although the TAS5720 does not have a dedicated DSP | ||
108 | * mode it doesn't care about the LRCLK duty cycle during TDM | ||
109 | * operation. Therefore we can use the device's I2S mode with | ||
110 | * its delaying of the 1st data bit to receive DSP_A formatted | ||
111 | * data. See device datasheet for additional details. | ||
112 | */ | ||
113 | serial_format = TAS5720_SAIF_I2S; | ||
114 | break; | ||
115 | case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF): | ||
116 | /* | ||
117 | * Similar to DSP_A, we can use the fact that the TAS5720 does | ||
118 | * not care about the LRCLK duty cycle during TDM to receive | ||
119 | * DSP_B formatted data in LEFTJ mode (no delaying of the 1st | ||
120 | * data bit). | ||
121 | */ | ||
122 | serial_format = TAS5720_SAIF_LEFTJ; | ||
123 | break; | ||
124 | case (SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF): | ||
125 | /* No delay after the frame sync */ | ||
126 | serial_format = TAS5720_SAIF_LEFTJ; | ||
127 | break; | ||
128 | default: | ||
129 | dev_vdbg(codec->dev, "DAI Format is not found\n"); | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
133 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
134 | TAS5720_SAIF_FORMAT_MASK, | ||
135 | serial_format); | ||
136 | if (ret < 0) { | ||
137 | dev_err(codec->dev, "error setting SAIF format: %d\n", ret); | ||
138 | return ret; | ||
139 | } | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
145 | unsigned int tx_mask, unsigned int rx_mask, | ||
146 | int slots, int slot_width) | ||
147 | { | ||
148 | struct snd_soc_codec *codec = dai->codec; | ||
149 | unsigned int first_slot; | ||
150 | int ret; | ||
151 | |||
152 | if (!tx_mask) { | ||
153 | dev_err(codec->dev, "tx masks must not be 0\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Determine the first slot that is being requested. We will only | ||
159 | * use the first slot that is found since the TAS5720 is a mono | ||
160 | * amplifier. | ||
161 | */ | ||
162 | first_slot = __ffs(tx_mask); | ||
163 | |||
164 | if (first_slot > 7) { | ||
165 | dev_err(codec->dev, "slot selection out of bounds (%u)\n", | ||
166 | first_slot); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | /* Enable manual TDM slot selection (instead of I2C ID based) */ | ||
171 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL1_REG, | ||
172 | TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC); | ||
173 | if (ret < 0) | ||
174 | goto error_snd_soc_update_bits; | ||
175 | |||
176 | /* Configure the TDM slot to process audio from */ | ||
177 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
178 | TAS5720_TDM_SLOT_SEL_MASK, first_slot); | ||
179 | if (ret < 0) | ||
180 | goto error_snd_soc_update_bits; | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | error_snd_soc_update_bits: | ||
185 | dev_err(codec->dev, "error configuring TDM mode: %d\n", ret); | ||
186 | return ret; | ||
187 | } | ||
188 | |||
189 | static int tas5720_mute(struct snd_soc_dai *dai, int mute) | ||
190 | { | ||
191 | struct snd_soc_codec *codec = dai->codec; | ||
192 | int ret; | ||
193 | |||
194 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
195 | TAS5720_MUTE, mute ? TAS5720_MUTE : 0); | ||
196 | if (ret < 0) { | ||
197 | dev_err(codec->dev, "error (un-)muting device: %d\n", ret); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static void tas5720_fault_check_work(struct work_struct *work) | ||
205 | { | ||
206 | struct tas5720_data *tas5720 = container_of(work, struct tas5720_data, | ||
207 | fault_check_work.work); | ||
208 | struct device *dev = tas5720->codec->dev; | ||
209 | unsigned int curr_fault; | ||
210 | int ret; | ||
211 | |||
212 | ret = regmap_read(tas5720->regmap, TAS5720_FAULT_REG, &curr_fault); | ||
213 | if (ret < 0) { | ||
214 | dev_err(dev, "failed to read FAULT register: %d\n", ret); | ||
215 | goto out; | ||
216 | } | ||
217 | |||
218 | /* Check/handle all errors except SAIF clock errors */ | ||
219 | curr_fault &= TAS5720_OCE | TAS5720_DCE | TAS5720_OTE; | ||
220 | |||
221 | /* | ||
222 | * Only flag errors once for a given occurrence. This is needed as | ||
223 | * the TAS5720 will take time clearing the fault condition internally | ||
224 | * during which we don't want to bombard the system with the same | ||
225 | * error message over and over. | ||
226 | */ | ||
227 | if ((curr_fault & TAS5720_OCE) && !(tas5720->last_fault & TAS5720_OCE)) | ||
228 | dev_crit(dev, "experienced an over current hardware fault\n"); | ||
229 | |||
230 | if ((curr_fault & TAS5720_DCE) && !(tas5720->last_fault & TAS5720_DCE)) | ||
231 | dev_crit(dev, "experienced a DC detection fault\n"); | ||
232 | |||
233 | if ((curr_fault & TAS5720_OTE) && !(tas5720->last_fault & TAS5720_OTE)) | ||
234 | dev_crit(dev, "experienced an over temperature fault\n"); | ||
235 | |||
236 | /* Store current fault value so we can detect any changes next time */ | ||
237 | tas5720->last_fault = curr_fault; | ||
238 | |||
239 | if (!curr_fault) | ||
240 | goto out; | ||
241 | |||
242 | /* | ||
243 | * Periodically toggle SDZ (shutdown bit) H->L->H to clear any latching | ||
244 | * faults as long as a fault condition persists. Always going through | ||
245 | * the full sequence no matter the first return value to minimizes | ||
246 | * chances for the device to end up in shutdown mode. | ||
247 | */ | ||
248 | ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG, | ||
249 | TAS5720_SDZ, 0); | ||
250 | if (ret < 0) | ||
251 | dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret); | ||
252 | |||
253 | ret = regmap_write_bits(tas5720->regmap, TAS5720_POWER_CTRL_REG, | ||
254 | TAS5720_SDZ, TAS5720_SDZ); | ||
255 | if (ret < 0) | ||
256 | dev_err(dev, "failed to write POWER_CTRL register: %d\n", ret); | ||
257 | |||
258 | out: | ||
259 | /* Schedule the next fault check at the specified interval */ | ||
260 | schedule_delayed_work(&tas5720->fault_check_work, | ||
261 | msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL)); | ||
262 | } | ||
263 | |||
264 | static int tas5720_codec_probe(struct snd_soc_codec *codec) | ||
265 | { | ||
266 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
267 | unsigned int device_id; | ||
268 | int ret; | ||
269 | |||
270 | tas5720->codec = codec; | ||
271 | |||
272 | ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies), | ||
273 | tas5720->supplies); | ||
274 | if (ret != 0) { | ||
275 | dev_err(codec->dev, "failed to enable supplies: %d\n", ret); | ||
276 | return ret; | ||
277 | } | ||
278 | |||
279 | ret = regmap_read(tas5720->regmap, TAS5720_DEVICE_ID_REG, &device_id); | ||
280 | if (ret < 0) { | ||
281 | dev_err(codec->dev, "failed to read device ID register: %d\n", | ||
282 | ret); | ||
283 | goto probe_fail; | ||
284 | } | ||
285 | |||
286 | if (device_id != TAS5720_DEVICE_ID) { | ||
287 | dev_err(codec->dev, "wrong device ID. expected: %u read: %u\n", | ||
288 | TAS5720_DEVICE_ID, device_id); | ||
289 | ret = -ENODEV; | ||
290 | goto probe_fail; | ||
291 | } | ||
292 | |||
293 | /* Set device to mute */ | ||
294 | ret = snd_soc_update_bits(codec, TAS5720_DIGITAL_CTRL2_REG, | ||
295 | TAS5720_MUTE, TAS5720_MUTE); | ||
296 | if (ret < 0) | ||
297 | goto error_snd_soc_update_bits; | ||
298 | |||
299 | /* | ||
300 | * Enter shutdown mode - our default when not playing audio - to | ||
301 | * minimize current consumption. On the TAS5720 there is no real down | ||
302 | * side doing so as all device registers are preserved and the wakeup | ||
303 | * of the codec is rather quick which we do using a dapm widget. | ||
304 | */ | ||
305 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
306 | TAS5720_SDZ, 0); | ||
307 | if (ret < 0) | ||
308 | goto error_snd_soc_update_bits; | ||
309 | |||
310 | INIT_DELAYED_WORK(&tas5720->fault_check_work, tas5720_fault_check_work); | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | error_snd_soc_update_bits: | ||
315 | dev_err(codec->dev, "error configuring device registers: %d\n", ret); | ||
316 | |||
317 | probe_fail: | ||
318 | regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
319 | tas5720->supplies); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | static int tas5720_codec_remove(struct snd_soc_codec *codec) | ||
324 | { | ||
325 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
326 | int ret; | ||
327 | |||
328 | cancel_delayed_work_sync(&tas5720->fault_check_work); | ||
329 | |||
330 | ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
331 | tas5720->supplies); | ||
332 | if (ret < 0) | ||
333 | dev_err(codec->dev, "failed to disable supplies: %d\n", ret); | ||
334 | |||
335 | return ret; | ||
336 | }; | ||
337 | |||
338 | static int tas5720_dac_event(struct snd_soc_dapm_widget *w, | ||
339 | struct snd_kcontrol *kcontrol, int event) | ||
340 | { | ||
341 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); | ||
342 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
343 | int ret; | ||
344 | |||
345 | if (event & SND_SOC_DAPM_POST_PMU) { | ||
346 | /* Take TAS5720 out of shutdown mode */ | ||
347 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
348 | TAS5720_SDZ, TAS5720_SDZ); | ||
349 | if (ret < 0) { | ||
350 | dev_err(codec->dev, "error waking codec: %d\n", ret); | ||
351 | return ret; | ||
352 | } | ||
353 | |||
354 | /* | ||
355 | * Observe codec shutdown-to-active time. The datasheet only | ||
356 | * lists a nominal value however just use-it as-is without | ||
357 | * additional padding to minimize the delay introduced in | ||
358 | * starting to play audio (actually there is other setup done | ||
359 | * by the ASoC framework that will provide additional delays, | ||
360 | * so we should always be safe). | ||
361 | */ | ||
362 | msleep(25); | ||
363 | |||
364 | /* Turn on TAS5720 periodic fault checking/handling */ | ||
365 | tas5720->last_fault = 0; | ||
366 | schedule_delayed_work(&tas5720->fault_check_work, | ||
367 | msecs_to_jiffies(TAS5720_FAULT_CHECK_INTERVAL)); | ||
368 | } else if (event & SND_SOC_DAPM_PRE_PMD) { | ||
369 | /* Disable TAS5720 periodic fault checking/handling */ | ||
370 | cancel_delayed_work_sync(&tas5720->fault_check_work); | ||
371 | |||
372 | /* Place TAS5720 in shutdown mode to minimize current draw */ | ||
373 | ret = snd_soc_update_bits(codec, TAS5720_POWER_CTRL_REG, | ||
374 | TAS5720_SDZ, 0); | ||
375 | if (ret < 0) { | ||
376 | dev_err(codec->dev, "error shutting down codec: %d\n", | ||
377 | ret); | ||
378 | return ret; | ||
379 | } | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | #ifdef CONFIG_PM | ||
386 | static int tas5720_suspend(struct snd_soc_codec *codec) | ||
387 | { | ||
388 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
389 | int ret; | ||
390 | |||
391 | regcache_cache_only(tas5720->regmap, true); | ||
392 | regcache_mark_dirty(tas5720->regmap); | ||
393 | |||
394 | ret = regulator_bulk_disable(ARRAY_SIZE(tas5720->supplies), | ||
395 | tas5720->supplies); | ||
396 | if (ret < 0) | ||
397 | dev_err(codec->dev, "failed to disable supplies: %d\n", ret); | ||
398 | |||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | static int tas5720_resume(struct snd_soc_codec *codec) | ||
403 | { | ||
404 | struct tas5720_data *tas5720 = snd_soc_codec_get_drvdata(codec); | ||
405 | int ret; | ||
406 | |||
407 | ret = regulator_bulk_enable(ARRAY_SIZE(tas5720->supplies), | ||
408 | tas5720->supplies); | ||
409 | if (ret < 0) { | ||
410 | dev_err(codec->dev, "failed to enable supplies: %d\n", ret); | ||
411 | return ret; | ||
412 | } | ||
413 | |||
414 | regcache_cache_only(tas5720->regmap, false); | ||
415 | |||
416 | ret = regcache_sync(tas5720->regmap); | ||
417 | if (ret < 0) { | ||
418 | dev_err(codec->dev, "failed to sync regcache: %d\n", ret); | ||
419 | return ret; | ||
420 | } | ||
421 | |||
422 | return 0; | ||
423 | } | ||
424 | #else | ||
425 | #define tas5720_suspend NULL | ||
426 | #define tas5720_resume NULL | ||
427 | #endif | ||
428 | |||
429 | static bool tas5720_is_volatile_reg(struct device *dev, unsigned int reg) | ||
430 | { | ||
431 | switch (reg) { | ||
432 | case TAS5720_DEVICE_ID_REG: | ||
433 | case TAS5720_FAULT_REG: | ||
434 | return true; | ||
435 | default: | ||
436 | return false; | ||
437 | } | ||
438 | } | ||
439 | |||
440 | static const struct regmap_config tas5720_regmap_config = { | ||
441 | .reg_bits = 8, | ||
442 | .val_bits = 8, | ||
443 | |||
444 | .max_register = TAS5720_MAX_REG, | ||
445 | .cache_type = REGCACHE_RBTREE, | ||
446 | .volatile_reg = tas5720_is_volatile_reg, | ||
447 | }; | ||
448 | |||
449 | /* | ||
450 | * DAC analog gain. There are four discrete values to select from, ranging | ||
451 | * from 19.2 dB to 26.3dB. | ||
452 | */ | ||
453 | static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, | ||
454 | 0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0), | ||
455 | 0x1, 0x1, TLV_DB_SCALE_ITEM(2070, 0, 0), | ||
456 | 0x2, 0x2, TLV_DB_SCALE_ITEM(2350, 0, 0), | ||
457 | 0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0), | ||
458 | ); | ||
459 | |||
460 | /* | ||
461 | * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that | ||
462 | * setting the gain below -100 dB (register value <0x7) is effectively a MUTE | ||
463 | * as per device datasheet. | ||
464 | */ | ||
465 | static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); | ||
466 | |||
467 | static const struct snd_kcontrol_new tas5720_snd_controls[] = { | ||
468 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", | ||
469 | TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), | ||
470 | SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, | ||
471 | TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), | ||
472 | }; | ||
473 | |||
474 | static const struct snd_soc_dapm_widget tas5720_dapm_widgets[] = { | ||
475 | SND_SOC_DAPM_AIF_IN("DAC IN", "Playback", 0, SND_SOC_NOPM, 0, 0), | ||
476 | SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas5720_dac_event, | ||
477 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
478 | SND_SOC_DAPM_OUTPUT("OUT") | ||
479 | }; | ||
480 | |||
481 | static const struct snd_soc_dapm_route tas5720_audio_map[] = { | ||
482 | { "DAC", NULL, "DAC IN" }, | ||
483 | { "OUT", NULL, "DAC" }, | ||
484 | }; | ||
485 | |||
486 | static struct snd_soc_codec_driver soc_codec_dev_tas5720 = { | ||
487 | .probe = tas5720_codec_probe, | ||
488 | .remove = tas5720_codec_remove, | ||
489 | .suspend = tas5720_suspend, | ||
490 | .resume = tas5720_resume, | ||
491 | |||
492 | .controls = tas5720_snd_controls, | ||
493 | .num_controls = ARRAY_SIZE(tas5720_snd_controls), | ||
494 | .dapm_widgets = tas5720_dapm_widgets, | ||
495 | .num_dapm_widgets = ARRAY_SIZE(tas5720_dapm_widgets), | ||
496 | .dapm_routes = tas5720_audio_map, | ||
497 | .num_dapm_routes = ARRAY_SIZE(tas5720_audio_map), | ||
498 | }; | ||
499 | |||
500 | /* PCM rates supported by the TAS5720 driver */ | ||
501 | #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ | ||
502 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | ||
503 | |||
504 | /* Formats supported by TAS5720 driver */ | ||
505 | #define TAS5720_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S18_3LE |\ | ||
506 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE) | ||
507 | |||
508 | static struct snd_soc_dai_ops tas5720_speaker_dai_ops = { | ||
509 | .hw_params = tas5720_hw_params, | ||
510 | .set_fmt = tas5720_set_dai_fmt, | ||
511 | .set_tdm_slot = tas5720_set_dai_tdm_slot, | ||
512 | .digital_mute = tas5720_mute, | ||
513 | }; | ||
514 | |||
515 | /* | ||
516 | * TAS5720 DAI structure | ||
517 | * | ||
518 | * Note that were are advertising .playback.channels_max = 2 despite this being | ||
519 | * a mono amplifier. The reason for that is that some serial ports such as TI's | ||
520 | * McASP module have a minimum number of channels (2) that they can output. | ||
521 | * Advertising more channels than we have will allow us to interface with such | ||
522 | * a serial port without really any negative side effects as the TAS5720 will | ||
523 | * simply ignore any extra channel(s) asides from the one channel that is | ||
524 | * configured to be played back. | ||
525 | */ | ||
526 | static struct snd_soc_dai_driver tas5720_dai[] = { | ||
527 | { | ||
528 | .name = "tas5720-amplifier", | ||
529 | .playback = { | ||
530 | .stream_name = "Playback", | ||
531 | .channels_min = 1, | ||
532 | .channels_max = 2, | ||
533 | .rates = TAS5720_RATES, | ||
534 | .formats = TAS5720_FORMATS, | ||
535 | }, | ||
536 | .ops = &tas5720_speaker_dai_ops, | ||
537 | }, | ||
538 | }; | ||
539 | |||
540 | static int tas5720_probe(struct i2c_client *client, | ||
541 | const struct i2c_device_id *id) | ||
542 | { | ||
543 | struct device *dev = &client->dev; | ||
544 | struct tas5720_data *data; | ||
545 | int ret; | ||
546 | int i; | ||
547 | |||
548 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
549 | if (!data) | ||
550 | return -ENOMEM; | ||
551 | |||
552 | data->tas5720_client = client; | ||
553 | data->regmap = devm_regmap_init_i2c(client, &tas5720_regmap_config); | ||
554 | if (IS_ERR(data->regmap)) { | ||
555 | ret = PTR_ERR(data->regmap); | ||
556 | dev_err(dev, "failed to allocate register map: %d\n", ret); | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | for (i = 0; i < ARRAY_SIZE(data->supplies); i++) | ||
561 | data->supplies[i].supply = tas5720_supply_names[i]; | ||
562 | |||
563 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), | ||
564 | data->supplies); | ||
565 | if (ret != 0) { | ||
566 | dev_err(dev, "failed to request supplies: %d\n", ret); | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | dev_set_drvdata(dev, data); | ||
571 | |||
572 | ret = snd_soc_register_codec(&client->dev, | ||
573 | &soc_codec_dev_tas5720, | ||
574 | tas5720_dai, ARRAY_SIZE(tas5720_dai)); | ||
575 | if (ret < 0) { | ||
576 | dev_err(dev, "failed to register codec: %d\n", ret); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int tas5720_remove(struct i2c_client *client) | ||
584 | { | ||
585 | struct device *dev = &client->dev; | ||
586 | |||
587 | snd_soc_unregister_codec(dev); | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | static const struct i2c_device_id tas5720_id[] = { | ||
593 | { "tas5720", 0 }, | ||
594 | { } | ||
595 | }; | ||
596 | MODULE_DEVICE_TABLE(i2c, tas5720_id); | ||
597 | |||
598 | #if IS_ENABLED(CONFIG_OF) | ||
599 | static const struct of_device_id tas5720_of_match[] = { | ||
600 | { .compatible = "ti,tas5720", }, | ||
601 | { }, | ||
602 | }; | ||
603 | MODULE_DEVICE_TABLE(of, tas5720_of_match); | ||
604 | #endif | ||
605 | |||
606 | static struct i2c_driver tas5720_i2c_driver = { | ||
607 | .driver = { | ||
608 | .name = "tas5720", | ||
609 | .of_match_table = of_match_ptr(tas5720_of_match), | ||
610 | }, | ||
611 | .probe = tas5720_probe, | ||
612 | .remove = tas5720_remove, | ||
613 | .id_table = tas5720_id, | ||
614 | }; | ||
615 | |||
616 | module_i2c_driver(tas5720_i2c_driver); | ||
617 | |||
618 | MODULE_AUTHOR("Andreas Dannenberg <dannenberg@ti.com>"); | ||
619 | MODULE_DESCRIPTION("TAS5720 Audio amplifier driver"); | ||
620 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h new file mode 100644 index 000000000000..3d077c779b12 --- /dev/null +++ b/sound/soc/codecs/tas5720.h | |||
@@ -0,0 +1,90 @@ | |||
1 | /* | ||
2 | * tas5720.h - ALSA SoC Texas Instruments TAS5720 Mono Audio Amplifier | ||
3 | * | ||
4 | * Copyright (C)2015-2016 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * | ||
6 | * Author: Andreas Dannenberg <dannenberg@ti.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 | ||
10 | * version 2 as published by the Free Software Foundation. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, but | ||
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | * General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #ifndef __TAS5720_H__ | ||
19 | #define __TAS5720_H__ | ||
20 | |||
21 | /* Register Address Map */ | ||
22 | #define TAS5720_DEVICE_ID_REG 0x00 | ||
23 | #define TAS5720_POWER_CTRL_REG 0x01 | ||
24 | #define TAS5720_DIGITAL_CTRL1_REG 0x02 | ||
25 | #define TAS5720_DIGITAL_CTRL2_REG 0x03 | ||
26 | #define TAS5720_VOLUME_CTRL_REG 0x04 | ||
27 | #define TAS5720_ANALOG_CTRL_REG 0x06 | ||
28 | #define TAS5720_FAULT_REG 0x08 | ||
29 | #define TAS5720_DIGITAL_CLIP2_REG 0x10 | ||
30 | #define TAS5720_DIGITAL_CLIP1_REG 0x11 | ||
31 | #define TAS5720_MAX_REG TAS5720_DIGITAL_CLIP1_REG | ||
32 | |||
33 | /* TAS5720_DEVICE_ID_REG */ | ||
34 | #define TAS5720_DEVICE_ID 0x01 | ||
35 | |||
36 | /* TAS5720_POWER_CTRL_REG */ | ||
37 | #define TAS5720_DIG_CLIP_MASK GENMASK(7, 2) | ||
38 | #define TAS5720_SLEEP BIT(1) | ||
39 | #define TAS5720_SDZ BIT(0) | ||
40 | |||
41 | /* TAS5720_DIGITAL_CTRL1_REG */ | ||
42 | #define TAS5720_HPF_BYPASS BIT(7) | ||
43 | #define TAS5720_TDM_CFG_SRC BIT(6) | ||
44 | #define TAS5720_SSZ_DS BIT(3) | ||
45 | #define TAS5720_SAIF_RIGHTJ_24BIT (0x0) | ||
46 | #define TAS5720_SAIF_RIGHTJ_20BIT (0x1) | ||
47 | #define TAS5720_SAIF_RIGHTJ_18BIT (0x2) | ||
48 | #define TAS5720_SAIF_RIGHTJ_16BIT (0x3) | ||
49 | #define TAS5720_SAIF_I2S (0x4) | ||
50 | #define TAS5720_SAIF_LEFTJ (0x5) | ||
51 | #define TAS5720_SAIF_FORMAT_MASK GENMASK(2, 0) | ||
52 | |||
53 | /* TAS5720_DIGITAL_CTRL2_REG */ | ||
54 | #define TAS5720_MUTE BIT(4) | ||
55 | #define TAS5720_TDM_SLOT_SEL_MASK GENMASK(2, 0) | ||
56 | |||
57 | /* TAS5720_ANALOG_CTRL_REG */ | ||
58 | #define TAS5720_PWM_RATE_6_3_FSYNC (0x0 << 4) | ||
59 | #define TAS5720_PWM_RATE_8_4_FSYNC (0x1 << 4) | ||
60 | #define TAS5720_PWM_RATE_10_5_FSYNC (0x2 << 4) | ||
61 | #define TAS5720_PWM_RATE_12_6_FSYNC (0x3 << 4) | ||
62 | #define TAS5720_PWM_RATE_14_7_FSYNC (0x4 << 4) | ||
63 | #define TAS5720_PWM_RATE_16_8_FSYNC (0x5 << 4) | ||
64 | #define TAS5720_PWM_RATE_20_10_FSYNC (0x6 << 4) | ||
65 | #define TAS5720_PWM_RATE_24_12_FSYNC (0x7 << 4) | ||
66 | #define TAS5720_PWM_RATE_MASK GENMASK(6, 4) | ||
67 | #define TAS5720_ANALOG_GAIN_19_2DBV (0x0 << 2) | ||
68 | #define TAS5720_ANALOG_GAIN_20_7DBV (0x1 << 2) | ||
69 | #define TAS5720_ANALOG_GAIN_23_5DBV (0x2 << 2) | ||
70 | #define TAS5720_ANALOG_GAIN_26_3DBV (0x3 << 2) | ||
71 | #define TAS5720_ANALOG_GAIN_MASK GENMASK(3, 2) | ||
72 | #define TAS5720_ANALOG_GAIN_SHIFT (0x2) | ||
73 | |||
74 | /* TAS5720_FAULT_REG */ | ||
75 | #define TAS5720_OC_THRESH_100PCT (0x0 << 4) | ||
76 | #define TAS5720_OC_THRESH_75PCT (0x1 << 4) | ||
77 | #define TAS5720_OC_THRESH_50PCT (0x2 << 4) | ||
78 | #define TAS5720_OC_THRESH_25PCT (0x3 << 4) | ||
79 | #define TAS5720_OC_THRESH_MASK GENMASK(5, 4) | ||
80 | #define TAS5720_CLKE BIT(3) | ||
81 | #define TAS5720_OCE BIT(2) | ||
82 | #define TAS5720_DCE BIT(1) | ||
83 | #define TAS5720_OTE BIT(0) | ||
84 | #define TAS5720_FAULT_MASK GENMASK(3, 0) | ||
85 | |||
86 | /* TAS5720_DIGITAL_CLIP1_REG */ | ||
87 | #define TAS5720_CLIP1_MASK GENMASK(7, 2) | ||
88 | #define TAS5720_CLIP1_SHIFT (0x2) | ||
89 | |||
90 | #endif /* __TAS5720_H__ */ | ||
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index ee4def4f819f..3c5e1df01c19 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/i2c.h> | 28 | #include <linux/i2c.h> |
29 | #include <linux/gpio.h> | 29 | #include <linux/gpio.h> |
30 | #include <linux/regulator/consumer.h> | 30 | #include <linux/regulator/consumer.h> |
31 | #include <linux/acpi.h> | ||
31 | #include <linux/of.h> | 32 | #include <linux/of.h> |
32 | #include <linux/of_gpio.h> | 33 | #include <linux/of_gpio.h> |
33 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
@@ -1280,10 +1281,19 @@ static const struct i2c_device_id aic31xx_i2c_id[] = { | |||
1280 | }; | 1281 | }; |
1281 | MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); | 1282 | MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); |
1282 | 1283 | ||
1284 | #ifdef CONFIG_ACPI | ||
1285 | static const struct acpi_device_id aic31xx_acpi_match[] = { | ||
1286 | { "10TI3100", 0 }, | ||
1287 | { } | ||
1288 | }; | ||
1289 | MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); | ||
1290 | #endif | ||
1291 | |||
1283 | static struct i2c_driver aic31xx_i2c_driver = { | 1292 | static struct i2c_driver aic31xx_i2c_driver = { |
1284 | .driver = { | 1293 | .driver = { |
1285 | .name = "tlv320aic31xx-codec", | 1294 | .name = "tlv320aic31xx-codec", |
1286 | .of_match_table = of_match_ptr(tlv320aic31xx_of_match), | 1295 | .of_match_table = of_match_ptr(tlv320aic31xx_of_match), |
1296 | .acpi_match_table = ACPI_PTR(aic31xx_acpi_match), | ||
1287 | }, | 1297 | }, |
1288 | .probe = aic31xx_i2c_probe, | 1298 | .probe = aic31xx_i2c_probe, |
1289 | .remove = aic31xx_i2c_remove, | 1299 | .remove = aic31xx_i2c_remove, |
diff --git a/sound/soc/codecs/tlv320aic32x4-i2c.c b/sound/soc/codecs/tlv320aic32x4-i2c.c new file mode 100644 index 000000000000..59606cf3008f --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4-i2c.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic32x4-i2c.c | ||
3 | * | ||
4 | * Copyright 2011 NW Digital Radio | ||
5 | * | ||
6 | * Author: Jeremy McDermond <nh6z@nh6z.net> | ||
7 | * | ||
8 | * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "tlv320aic32x4.h" | ||
28 | |||
29 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | ||
30 | const struct i2c_device_id *id) | ||
31 | { | ||
32 | struct regmap *regmap; | ||
33 | struct regmap_config config; | ||
34 | |||
35 | config = aic32x4_regmap_config; | ||
36 | config.reg_bits = 8; | ||
37 | config.val_bits = 8; | ||
38 | |||
39 | regmap = devm_regmap_init_i2c(i2c, &config); | ||
40 | return aic32x4_probe(&i2c->dev, regmap); | ||
41 | } | ||
42 | |||
43 | static int aic32x4_i2c_remove(struct i2c_client *i2c) | ||
44 | { | ||
45 | return aic32x4_remove(&i2c->dev); | ||
46 | } | ||
47 | |||
48 | static const struct i2c_device_id aic32x4_i2c_id[] = { | ||
49 | { "tlv320aic32x4", 0 }, | ||
50 | { /* sentinel */ } | ||
51 | }; | ||
52 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | ||
53 | |||
54 | static const struct of_device_id aic32x4_of_id[] = { | ||
55 | { .compatible = "ti,tlv320aic32x4", }, | ||
56 | { /* senitel */ } | ||
57 | }; | ||
58 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
59 | |||
60 | static struct i2c_driver aic32x4_i2c_driver = { | ||
61 | .driver = { | ||
62 | .name = "tlv320aic32x4", | ||
63 | .of_match_table = aic32x4_of_id, | ||
64 | }, | ||
65 | .probe = aic32x4_i2c_probe, | ||
66 | .remove = aic32x4_i2c_remove, | ||
67 | .id_table = aic32x4_i2c_id, | ||
68 | }; | ||
69 | |||
70 | module_i2c_driver(aic32x4_i2c_driver); | ||
71 | |||
72 | MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver I2C"); | ||
73 | MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>"); | ||
74 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic32x4-spi.c b/sound/soc/codecs/tlv320aic32x4-spi.c new file mode 100644 index 000000000000..724fcdd491b2 --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4-spi.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic32x4-spi.c | ||
3 | * | ||
4 | * Copyright 2011 NW Digital Radio | ||
5 | * | ||
6 | * Author: Jeremy McDermond <nh6z@nh6z.net> | ||
7 | * | ||
8 | * Based on sound/soc/codecs/wm8974 and TI driver for kernel 2.6.27. | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/spi/spi.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/regmap.h> | ||
25 | #include <sound/soc.h> | ||
26 | |||
27 | #include "tlv320aic32x4.h" | ||
28 | |||
29 | static int aic32x4_spi_probe(struct spi_device *spi) | ||
30 | { | ||
31 | struct regmap *regmap; | ||
32 | struct regmap_config config; | ||
33 | |||
34 | config = aic32x4_regmap_config; | ||
35 | config.reg_bits = 7; | ||
36 | config.pad_bits = 1; | ||
37 | config.val_bits = 8; | ||
38 | config.read_flag_mask = 0x01; | ||
39 | |||
40 | regmap = devm_regmap_init_spi(spi, &config); | ||
41 | return aic32x4_probe(&spi->dev, regmap); | ||
42 | } | ||
43 | |||
44 | static int aic32x4_spi_remove(struct spi_device *spi) | ||
45 | { | ||
46 | return aic32x4_remove(&spi->dev); | ||
47 | } | ||
48 | |||
49 | static const struct spi_device_id aic32x4_spi_id[] = { | ||
50 | { "tlv320aic32x4", 0 }, | ||
51 | { /* sentinel */ } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(spi, aic32x4_spi_id); | ||
54 | |||
55 | static const struct of_device_id aic32x4_of_id[] = { | ||
56 | { .compatible = "ti,tlv320aic32x4", }, | ||
57 | { /* senitel */ } | ||
58 | }; | ||
59 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
60 | |||
61 | static struct spi_driver aic32x4_spi_driver = { | ||
62 | .driver = { | ||
63 | .name = "tlv320aic32x4", | ||
64 | .owner = THIS_MODULE, | ||
65 | .of_match_table = aic32x4_of_id, | ||
66 | }, | ||
67 | .probe = aic32x4_spi_probe, | ||
68 | .remove = aic32x4_spi_remove, | ||
69 | .id_table = aic32x4_spi_id, | ||
70 | }; | ||
71 | |||
72 | module_spi_driver(aic32x4_spi_driver); | ||
73 | |||
74 | MODULE_DESCRIPTION("ASoC TLV320AIC32x4 codec driver SPI"); | ||
75 | MODULE_AUTHOR("Jeremy McDermond <nh6z@nh6z.net>"); | ||
76 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index f2d3191961e1..85d4978d0384 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/pm.h> | 30 | #include <linux/pm.h> |
31 | #include <linux/gpio.h> | 31 | #include <linux/gpio.h> |
32 | #include <linux/of_gpio.h> | 32 | #include <linux/of_gpio.h> |
33 | #include <linux/i2c.h> | ||
34 | #include <linux/cdev.h> | 33 | #include <linux/cdev.h> |
35 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
36 | #include <linux/clk.h> | 35 | #include <linux/clk.h> |
@@ -160,7 +159,10 @@ static const struct aic32x4_rate_divs aic32x4_divs[] = { | |||
160 | /* 48k rate */ | 159 | /* 48k rate */ |
161 | {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, | 160 | {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, |
162 | {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, | 161 | {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, |
163 | {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4} | 162 | {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4}, |
163 | |||
164 | /* 96k rate */ | ||
165 | {AIC32X4_FREQ_25000000, 96000, 2, 7, 8643, 64, 4, 4, 64, 4, 4, 1}, | ||
164 | }; | 166 | }; |
165 | 167 | ||
166 | static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { | 168 | static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { |
@@ -181,16 +183,71 @@ static const struct snd_kcontrol_new lor_output_mixer_controls[] = { | |||
181 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0), | 183 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0), |
182 | }; | 184 | }; |
183 | 185 | ||
184 | static const struct snd_kcontrol_new left_input_mixer_controls[] = { | 186 | static const char * const resistor_text[] = { |
185 | SOC_DAPM_SINGLE("IN1_L P Switch", AIC32X4_LMICPGAPIN, 6, 1, 0), | 187 | "Off", "10 kOhm", "20 kOhm", "40 kOhm", |
186 | SOC_DAPM_SINGLE("IN2_L P Switch", AIC32X4_LMICPGAPIN, 4, 1, 0), | ||
187 | SOC_DAPM_SINGLE("IN3_L P Switch", AIC32X4_LMICPGAPIN, 2, 1, 0), | ||
188 | }; | 188 | }; |
189 | 189 | ||
190 | static const struct snd_kcontrol_new right_input_mixer_controls[] = { | 190 | /* Left mixer pins */ |
191 | SOC_DAPM_SINGLE("IN1_R P Switch", AIC32X4_RMICPGAPIN, 6, 1, 0), | 191 | static SOC_ENUM_SINGLE_DECL(in1l_lpga_p_enum, AIC32X4_LMICPGAPIN, 6, resistor_text); |
192 | SOC_DAPM_SINGLE("IN2_R P Switch", AIC32X4_RMICPGAPIN, 4, 1, 0), | 192 | static SOC_ENUM_SINGLE_DECL(in2l_lpga_p_enum, AIC32X4_LMICPGAPIN, 4, resistor_text); |
193 | SOC_DAPM_SINGLE("IN3_R P Switch", AIC32X4_RMICPGAPIN, 2, 1, 0), | 193 | static SOC_ENUM_SINGLE_DECL(in3l_lpga_p_enum, AIC32X4_LMICPGAPIN, 2, resistor_text); |
194 | static SOC_ENUM_SINGLE_DECL(in1r_lpga_p_enum, AIC32X4_LMICPGAPIN, 0, resistor_text); | ||
195 | |||
196 | static SOC_ENUM_SINGLE_DECL(cml_lpga_n_enum, AIC32X4_LMICPGANIN, 6, resistor_text); | ||
197 | static SOC_ENUM_SINGLE_DECL(in2r_lpga_n_enum, AIC32X4_LMICPGANIN, 4, resistor_text); | ||
198 | static SOC_ENUM_SINGLE_DECL(in3r_lpga_n_enum, AIC32X4_LMICPGANIN, 2, resistor_text); | ||
199 | |||
200 | static const struct snd_kcontrol_new in1l_to_lmixer_controls[] = { | ||
201 | SOC_DAPM_ENUM("IN1_L L+ Switch", in1l_lpga_p_enum), | ||
202 | }; | ||
203 | static const struct snd_kcontrol_new in2l_to_lmixer_controls[] = { | ||
204 | SOC_DAPM_ENUM("IN2_L L+ Switch", in2l_lpga_p_enum), | ||
205 | }; | ||
206 | static const struct snd_kcontrol_new in3l_to_lmixer_controls[] = { | ||
207 | SOC_DAPM_ENUM("IN3_L L+ Switch", in3l_lpga_p_enum), | ||
208 | }; | ||
209 | static const struct snd_kcontrol_new in1r_to_lmixer_controls[] = { | ||
210 | SOC_DAPM_ENUM("IN1_R L+ Switch", in1r_lpga_p_enum), | ||
211 | }; | ||
212 | static const struct snd_kcontrol_new cml_to_lmixer_controls[] = { | ||
213 | SOC_DAPM_ENUM("CM_L L- Switch", cml_lpga_n_enum), | ||
214 | }; | ||
215 | static const struct snd_kcontrol_new in2r_to_lmixer_controls[] = { | ||
216 | SOC_DAPM_ENUM("IN2_R L- Switch", in2r_lpga_n_enum), | ||
217 | }; | ||
218 | static const struct snd_kcontrol_new in3r_to_lmixer_controls[] = { | ||
219 | SOC_DAPM_ENUM("IN3_R L- Switch", in3r_lpga_n_enum), | ||
220 | }; | ||
221 | |||
222 | /* Right mixer pins */ | ||
223 | static SOC_ENUM_SINGLE_DECL(in1r_rpga_p_enum, AIC32X4_RMICPGAPIN, 6, resistor_text); | ||
224 | static SOC_ENUM_SINGLE_DECL(in2r_rpga_p_enum, AIC32X4_RMICPGAPIN, 4, resistor_text); | ||
225 | static SOC_ENUM_SINGLE_DECL(in3r_rpga_p_enum, AIC32X4_RMICPGAPIN, 2, resistor_text); | ||
226 | static SOC_ENUM_SINGLE_DECL(in2l_rpga_p_enum, AIC32X4_RMICPGAPIN, 0, resistor_text); | ||
227 | static SOC_ENUM_SINGLE_DECL(cmr_rpga_n_enum, AIC32X4_RMICPGANIN, 6, resistor_text); | ||
228 | static SOC_ENUM_SINGLE_DECL(in1l_rpga_n_enum, AIC32X4_RMICPGANIN, 4, resistor_text); | ||
229 | static SOC_ENUM_SINGLE_DECL(in3l_rpga_n_enum, AIC32X4_RMICPGANIN, 2, resistor_text); | ||
230 | |||
231 | static const struct snd_kcontrol_new in1r_to_rmixer_controls[] = { | ||
232 | SOC_DAPM_ENUM("IN1_R R+ Switch", in1r_rpga_p_enum), | ||
233 | }; | ||
234 | static const struct snd_kcontrol_new in2r_to_rmixer_controls[] = { | ||
235 | SOC_DAPM_ENUM("IN2_R R+ Switch", in2r_rpga_p_enum), | ||
236 | }; | ||
237 | static const struct snd_kcontrol_new in3r_to_rmixer_controls[] = { | ||
238 | SOC_DAPM_ENUM("IN3_R R+ Switch", in3r_rpga_p_enum), | ||
239 | }; | ||
240 | static const struct snd_kcontrol_new in2l_to_rmixer_controls[] = { | ||
241 | SOC_DAPM_ENUM("IN2_L R+ Switch", in2l_rpga_p_enum), | ||
242 | }; | ||
243 | static const struct snd_kcontrol_new cmr_to_rmixer_controls[] = { | ||
244 | SOC_DAPM_ENUM("CM_R R- Switch", cmr_rpga_n_enum), | ||
245 | }; | ||
246 | static const struct snd_kcontrol_new in1l_to_rmixer_controls[] = { | ||
247 | SOC_DAPM_ENUM("IN1_L R- Switch", in1l_rpga_n_enum), | ||
248 | }; | ||
249 | static const struct snd_kcontrol_new in3l_to_rmixer_controls[] = { | ||
250 | SOC_DAPM_ENUM("IN3_L R- Switch", in3l_rpga_n_enum), | ||
194 | }; | 251 | }; |
195 | 252 | ||
196 | static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { | 253 | static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { |
@@ -214,14 +271,39 @@ static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { | |||
214 | &lor_output_mixer_controls[0], | 271 | &lor_output_mixer_controls[0], |
215 | ARRAY_SIZE(lor_output_mixer_controls)), | 272 | ARRAY_SIZE(lor_output_mixer_controls)), |
216 | SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0), | 273 | SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0), |
217 | SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, | 274 | |
218 | &left_input_mixer_controls[0], | ||
219 | ARRAY_SIZE(left_input_mixer_controls)), | ||
220 | SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, | ||
221 | &right_input_mixer_controls[0], | ||
222 | ARRAY_SIZE(right_input_mixer_controls)), | ||
223 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), | ||
224 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), | 275 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), |
276 | SND_SOC_DAPM_MUX("IN1_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
277 | in1r_to_rmixer_controls), | ||
278 | SND_SOC_DAPM_MUX("IN2_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
279 | in2r_to_rmixer_controls), | ||
280 | SND_SOC_DAPM_MUX("IN3_R to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
281 | in3r_to_rmixer_controls), | ||
282 | SND_SOC_DAPM_MUX("IN2_L to Right Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
283 | in2l_to_rmixer_controls), | ||
284 | SND_SOC_DAPM_MUX("CM_R to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
285 | cmr_to_rmixer_controls), | ||
286 | SND_SOC_DAPM_MUX("IN1_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
287 | in1l_to_rmixer_controls), | ||
288 | SND_SOC_DAPM_MUX("IN3_L to Right Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
289 | in3l_to_rmixer_controls), | ||
290 | |||
291 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), | ||
292 | SND_SOC_DAPM_MUX("IN1_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
293 | in1l_to_lmixer_controls), | ||
294 | SND_SOC_DAPM_MUX("IN2_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
295 | in2l_to_lmixer_controls), | ||
296 | SND_SOC_DAPM_MUX("IN3_L to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
297 | in3l_to_lmixer_controls), | ||
298 | SND_SOC_DAPM_MUX("IN1_R to Left Mixer Positive Resistor", SND_SOC_NOPM, 0, 0, | ||
299 | in1r_to_lmixer_controls), | ||
300 | SND_SOC_DAPM_MUX("CM_L to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
301 | cml_to_lmixer_controls), | ||
302 | SND_SOC_DAPM_MUX("IN2_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
303 | in2r_to_lmixer_controls), | ||
304 | SND_SOC_DAPM_MUX("IN3_R to Left Mixer Negative Resistor", SND_SOC_NOPM, 0, 0, | ||
305 | in3r_to_lmixer_controls), | ||
306 | |||
225 | SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), | 307 | SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), |
226 | 308 | ||
227 | SND_SOC_DAPM_OUTPUT("HPL"), | 309 | SND_SOC_DAPM_OUTPUT("HPL"), |
@@ -261,19 +343,77 @@ static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { | |||
261 | {"LOR Power", NULL, "LOR Output Mixer"}, | 343 | {"LOR Power", NULL, "LOR Output Mixer"}, |
262 | {"LOR", NULL, "LOR Power"}, | 344 | {"LOR", NULL, "LOR Power"}, |
263 | 345 | ||
264 | /* Left input */ | ||
265 | {"Left Input Mixer", "IN1_L P Switch", "IN1_L"}, | ||
266 | {"Left Input Mixer", "IN2_L P Switch", "IN2_L"}, | ||
267 | {"Left Input Mixer", "IN3_L P Switch", "IN3_L"}, | ||
268 | |||
269 | {"Left ADC", NULL, "Left Input Mixer"}, | ||
270 | |||
271 | /* Right Input */ | 346 | /* Right Input */ |
272 | {"Right Input Mixer", "IN1_R P Switch", "IN1_R"}, | 347 | {"Right ADC", NULL, "IN1_R to Right Mixer Positive Resistor"}, |
273 | {"Right Input Mixer", "IN2_R P Switch", "IN2_R"}, | 348 | {"IN1_R to Right Mixer Positive Resistor", "10 kOhm", "IN1_R"}, |
274 | {"Right Input Mixer", "IN3_R P Switch", "IN3_R"}, | 349 | {"IN1_R to Right Mixer Positive Resistor", "20 kOhm", "IN1_R"}, |
275 | 350 | {"IN1_R to Right Mixer Positive Resistor", "40 kOhm", "IN1_R"}, | |
276 | {"Right ADC", NULL, "Right Input Mixer"}, | 351 | |
352 | {"Right ADC", NULL, "IN2_R to Right Mixer Positive Resistor"}, | ||
353 | {"IN2_R to Right Mixer Positive Resistor", "10 kOhm", "IN2_R"}, | ||
354 | {"IN2_R to Right Mixer Positive Resistor", "20 kOhm", "IN2_R"}, | ||
355 | {"IN2_R to Right Mixer Positive Resistor", "40 kOhm", "IN2_R"}, | ||
356 | |||
357 | {"Right ADC", NULL, "IN3_R to Right Mixer Positive Resistor"}, | ||
358 | {"IN3_R to Right Mixer Positive Resistor", "10 kOhm", "IN3_R"}, | ||
359 | {"IN3_R to Right Mixer Positive Resistor", "20 kOhm", "IN3_R"}, | ||
360 | {"IN3_R to Right Mixer Positive Resistor", "40 kOhm", "IN3_R"}, | ||
361 | |||
362 | {"Right ADC", NULL, "IN2_L to Right Mixer Positive Resistor"}, | ||
363 | {"IN2_L to Right Mixer Positive Resistor", "10 kOhm", "IN2_L"}, | ||
364 | {"IN2_L to Right Mixer Positive Resistor", "20 kOhm", "IN2_L"}, | ||
365 | {"IN2_L to Right Mixer Positive Resistor", "40 kOhm", "IN2_L"}, | ||
366 | |||
367 | {"Right ADC", NULL, "CM_R to Right Mixer Negative Resistor"}, | ||
368 | {"CM_R to Right Mixer Negative Resistor", "10 kOhm", "CM_R"}, | ||
369 | {"CM_R to Right Mixer Negative Resistor", "20 kOhm", "CM_R"}, | ||
370 | {"CM_R to Right Mixer Negative Resistor", "40 kOhm", "CM_R"}, | ||
371 | |||
372 | {"Right ADC", NULL, "IN1_L to Right Mixer Negative Resistor"}, | ||
373 | {"IN1_L to Right Mixer Negative Resistor", "10 kOhm", "IN1_L"}, | ||
374 | {"IN1_L to Right Mixer Negative Resistor", "20 kOhm", "IN1_L"}, | ||
375 | {"IN1_L to Right Mixer Negative Resistor", "40 kOhm", "IN1_L"}, | ||
376 | |||
377 | {"Right ADC", NULL, "IN3_L to Right Mixer Negative Resistor"}, | ||
378 | {"IN3_L to Right Mixer Negative Resistor", "10 kOhm", "IN3_L"}, | ||
379 | {"IN3_L to Right Mixer Negative Resistor", "20 kOhm", "IN3_L"}, | ||
380 | {"IN3_L to Right Mixer Negative Resistor", "40 kOhm", "IN3_L"}, | ||
381 | |||
382 | /* Left Input */ | ||
383 | {"Left ADC", NULL, "IN1_L to Left Mixer Positive Resistor"}, | ||
384 | {"IN1_L to Left Mixer Positive Resistor", "10 kOhm", "IN1_L"}, | ||
385 | {"IN1_L to Left Mixer Positive Resistor", "20 kOhm", "IN1_L"}, | ||
386 | {"IN1_L to Left Mixer Positive Resistor", "40 kOhm", "IN1_L"}, | ||
387 | |||
388 | {"Left ADC", NULL, "IN2_L to Left Mixer Positive Resistor"}, | ||
389 | {"IN2_L to Left Mixer Positive Resistor", "10 kOhm", "IN2_L"}, | ||
390 | {"IN2_L to Left Mixer Positive Resistor", "20 kOhm", "IN2_L"}, | ||
391 | {"IN2_L to Left Mixer Positive Resistor", "40 kOhm", "IN2_L"}, | ||
392 | |||
393 | {"Left ADC", NULL, "IN3_L to Left Mixer Positive Resistor"}, | ||
394 | {"IN3_L to Left Mixer Positive Resistor", "10 kOhm", "IN3_L"}, | ||
395 | {"IN3_L to Left Mixer Positive Resistor", "20 kOhm", "IN3_L"}, | ||
396 | {"IN3_L to Left Mixer Positive Resistor", "40 kOhm", "IN3_L"}, | ||
397 | |||
398 | {"Left ADC", NULL, "IN1_R to Left Mixer Positive Resistor"}, | ||
399 | {"IN1_R to Left Mixer Positive Resistor", "10 kOhm", "IN1_R"}, | ||
400 | {"IN1_R to Left Mixer Positive Resistor", "20 kOhm", "IN1_R"}, | ||
401 | {"IN1_R to Left Mixer Positive Resistor", "40 kOhm", "IN1_R"}, | ||
402 | |||
403 | {"Left ADC", NULL, "CM_L to Left Mixer Negative Resistor"}, | ||
404 | {"CM_L to Left Mixer Negative Resistor", "10 kOhm", "CM_L"}, | ||
405 | {"CM_L to Left Mixer Negative Resistor", "20 kOhm", "CM_L"}, | ||
406 | {"CM_L to Left Mixer Negative Resistor", "40 kOhm", "CM_L"}, | ||
407 | |||
408 | {"Left ADC", NULL, "IN2_R to Left Mixer Negative Resistor"}, | ||
409 | {"IN2_R to Left Mixer Negative Resistor", "10 kOhm", "IN2_R"}, | ||
410 | {"IN2_R to Left Mixer Negative Resistor", "20 kOhm", "IN2_R"}, | ||
411 | {"IN2_R to Left Mixer Negative Resistor", "40 kOhm", "IN2_R"}, | ||
412 | |||
413 | {"Left ADC", NULL, "IN3_R to Left Mixer Negative Resistor"}, | ||
414 | {"IN3_R to Left Mixer Negative Resistor", "10 kOhm", "IN3_R"}, | ||
415 | {"IN3_R to Left Mixer Negative Resistor", "20 kOhm", "IN3_R"}, | ||
416 | {"IN3_R to Left Mixer Negative Resistor", "40 kOhm", "IN3_R"}, | ||
277 | }; | 417 | }; |
278 | 418 | ||
279 | static const struct regmap_range_cfg aic32x4_regmap_pages[] = { | 419 | static const struct regmap_range_cfg aic32x4_regmap_pages[] = { |
@@ -287,14 +427,12 @@ static const struct regmap_range_cfg aic32x4_regmap_pages[] = { | |||
287 | }, | 427 | }, |
288 | }; | 428 | }; |
289 | 429 | ||
290 | static const struct regmap_config aic32x4_regmap = { | 430 | const struct regmap_config aic32x4_regmap_config = { |
291 | .reg_bits = 8, | ||
292 | .val_bits = 8, | ||
293 | |||
294 | .max_register = AIC32X4_RMICPGAVOL, | 431 | .max_register = AIC32X4_RMICPGAVOL, |
295 | .ranges = aic32x4_regmap_pages, | 432 | .ranges = aic32x4_regmap_pages, |
296 | .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), | 433 | .num_ranges = ARRAY_SIZE(aic32x4_regmap_pages), |
297 | }; | 434 | }; |
435 | EXPORT_SYMBOL(aic32x4_regmap_config); | ||
298 | 436 | ||
299 | static inline int aic32x4_get_divs(int mclk, int rate) | 437 | static inline int aic32x4_get_divs(int mclk, int rate) |
300 | { | 438 | { |
@@ -567,7 +705,7 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | |||
567 | return 0; | 705 | return 0; |
568 | } | 706 | } |
569 | 707 | ||
570 | #define AIC32X4_RATES SNDRV_PCM_RATE_8000_48000 | 708 | #define AIC32X4_RATES SNDRV_PCM_RATE_8000_96000 |
571 | #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ | 709 | #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ |
572 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 710 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) |
573 | 711 | ||
@@ -596,7 +734,7 @@ static struct snd_soc_dai_driver aic32x4_dai = { | |||
596 | .symmetric_rates = 1, | 734 | .symmetric_rates = 1, |
597 | }; | 735 | }; |
598 | 736 | ||
599 | static int aic32x4_probe(struct snd_soc_codec *codec) | 737 | static int aic32x4_codec_probe(struct snd_soc_codec *codec) |
600 | { | 738 | { |
601 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | 739 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); |
602 | u32 tmp_reg; | 740 | u32 tmp_reg; |
@@ -655,7 +793,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec) | |||
655 | } | 793 | } |
656 | 794 | ||
657 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | 795 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { |
658 | .probe = aic32x4_probe, | 796 | .probe = aic32x4_codec_probe, |
659 | .set_bias_level = aic32x4_set_bias_level, | 797 | .set_bias_level = aic32x4_set_bias_level, |
660 | .suspend_bias_off = true, | 798 | .suspend_bias_off = true, |
661 | 799 | ||
@@ -777,24 +915,22 @@ error_ldo: | |||
777 | return ret; | 915 | return ret; |
778 | } | 916 | } |
779 | 917 | ||
780 | static int aic32x4_i2c_probe(struct i2c_client *i2c, | 918 | int aic32x4_probe(struct device *dev, struct regmap *regmap) |
781 | const struct i2c_device_id *id) | ||
782 | { | 919 | { |
783 | struct aic32x4_pdata *pdata = i2c->dev.platform_data; | ||
784 | struct aic32x4_priv *aic32x4; | 920 | struct aic32x4_priv *aic32x4; |
785 | struct device_node *np = i2c->dev.of_node; | 921 | struct aic32x4_pdata *pdata = dev->platform_data; |
922 | struct device_node *np = dev->of_node; | ||
786 | int ret; | 923 | int ret; |
787 | 924 | ||
788 | aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), | 925 | if (IS_ERR(regmap)) |
926 | return PTR_ERR(regmap); | ||
927 | |||
928 | aic32x4 = devm_kzalloc(dev, sizeof(struct aic32x4_priv), | ||
789 | GFP_KERNEL); | 929 | GFP_KERNEL); |
790 | if (aic32x4 == NULL) | 930 | if (aic32x4 == NULL) |
791 | return -ENOMEM; | 931 | return -ENOMEM; |
792 | 932 | ||
793 | aic32x4->regmap = devm_regmap_init_i2c(i2c, &aic32x4_regmap); | 933 | dev_set_drvdata(dev, aic32x4); |
794 | if (IS_ERR(aic32x4->regmap)) | ||
795 | return PTR_ERR(aic32x4->regmap); | ||
796 | |||
797 | i2c_set_clientdata(i2c, aic32x4); | ||
798 | 934 | ||
799 | if (pdata) { | 935 | if (pdata) { |
800 | aic32x4->power_cfg = pdata->power_cfg; | 936 | aic32x4->power_cfg = pdata->power_cfg; |
@@ -804,7 +940,7 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
804 | } else if (np) { | 940 | } else if (np) { |
805 | ret = aic32x4_parse_dt(aic32x4, np); | 941 | ret = aic32x4_parse_dt(aic32x4, np); |
806 | if (ret) { | 942 | if (ret) { |
807 | dev_err(&i2c->dev, "Failed to parse DT node\n"); | 943 | dev_err(dev, "Failed to parse DT node\n"); |
808 | return ret; | 944 | return ret; |
809 | } | 945 | } |
810 | } else { | 946 | } else { |
@@ -814,71 +950,48 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, | |||
814 | aic32x4->rstn_gpio = -1; | 950 | aic32x4->rstn_gpio = -1; |
815 | } | 951 | } |
816 | 952 | ||
817 | aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); | 953 | aic32x4->mclk = devm_clk_get(dev, "mclk"); |
818 | if (IS_ERR(aic32x4->mclk)) { | 954 | if (IS_ERR(aic32x4->mclk)) { |
819 | dev_err(&i2c->dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); | 955 | dev_err(dev, "Failed getting the mclk. The current implementation does not support the usage of this codec without mclk\n"); |
820 | return PTR_ERR(aic32x4->mclk); | 956 | return PTR_ERR(aic32x4->mclk); |
821 | } | 957 | } |
822 | 958 | ||
823 | if (gpio_is_valid(aic32x4->rstn_gpio)) { | 959 | if (gpio_is_valid(aic32x4->rstn_gpio)) { |
824 | ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, | 960 | ret = devm_gpio_request_one(dev, aic32x4->rstn_gpio, |
825 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); | 961 | GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); |
826 | if (ret != 0) | 962 | if (ret != 0) |
827 | return ret; | 963 | return ret; |
828 | } | 964 | } |
829 | 965 | ||
830 | ret = aic32x4_setup_regulators(&i2c->dev, aic32x4); | 966 | ret = aic32x4_setup_regulators(dev, aic32x4); |
831 | if (ret) { | 967 | if (ret) { |
832 | dev_err(&i2c->dev, "Failed to setup regulators\n"); | 968 | dev_err(dev, "Failed to setup regulators\n"); |
833 | return ret; | 969 | return ret; |
834 | } | 970 | } |
835 | 971 | ||
836 | ret = snd_soc_register_codec(&i2c->dev, | 972 | ret = snd_soc_register_codec(dev, |
837 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); | 973 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); |
838 | if (ret) { | 974 | if (ret) { |
839 | dev_err(&i2c->dev, "Failed to register codec\n"); | 975 | dev_err(dev, "Failed to register codec\n"); |
840 | aic32x4_disable_regulators(aic32x4); | 976 | aic32x4_disable_regulators(aic32x4); |
841 | return ret; | 977 | return ret; |
842 | } | 978 | } |
843 | 979 | ||
844 | i2c_set_clientdata(i2c, aic32x4); | ||
845 | |||
846 | return 0; | 980 | return 0; |
847 | } | 981 | } |
982 | EXPORT_SYMBOL(aic32x4_probe); | ||
848 | 983 | ||
849 | static int aic32x4_i2c_remove(struct i2c_client *client) | 984 | int aic32x4_remove(struct device *dev) |
850 | { | 985 | { |
851 | struct aic32x4_priv *aic32x4 = i2c_get_clientdata(client); | 986 | struct aic32x4_priv *aic32x4 = dev_get_drvdata(dev); |
852 | 987 | ||
853 | aic32x4_disable_regulators(aic32x4); | 988 | aic32x4_disable_regulators(aic32x4); |
854 | 989 | ||
855 | snd_soc_unregister_codec(&client->dev); | 990 | snd_soc_unregister_codec(dev); |
991 | |||
856 | return 0; | 992 | return 0; |
857 | } | 993 | } |
858 | 994 | EXPORT_SYMBOL(aic32x4_remove); | |
859 | static const struct i2c_device_id aic32x4_i2c_id[] = { | ||
860 | { "tlv320aic32x4", 0 }, | ||
861 | { } | ||
862 | }; | ||
863 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | ||
864 | |||
865 | static const struct of_device_id aic32x4_of_id[] = { | ||
866 | { .compatible = "ti,tlv320aic32x4", }, | ||
867 | { /* senitel */ } | ||
868 | }; | ||
869 | MODULE_DEVICE_TABLE(of, aic32x4_of_id); | ||
870 | |||
871 | static struct i2c_driver aic32x4_i2c_driver = { | ||
872 | .driver = { | ||
873 | .name = "tlv320aic32x4", | ||
874 | .of_match_table = aic32x4_of_id, | ||
875 | }, | ||
876 | .probe = aic32x4_i2c_probe, | ||
877 | .remove = aic32x4_i2c_remove, | ||
878 | .id_table = aic32x4_i2c_id, | ||
879 | }; | ||
880 | |||
881 | module_i2c_driver(aic32x4_i2c_driver); | ||
882 | 995 | ||
883 | MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); | 996 | MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); |
884 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); | 997 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); |
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h index 995f033a855d..a197dd51addc 100644 --- a/sound/soc/codecs/tlv320aic32x4.h +++ b/sound/soc/codecs/tlv320aic32x4.h | |||
@@ -10,6 +10,13 @@ | |||
10 | #ifndef _TLV320AIC32X4_H | 10 | #ifndef _TLV320AIC32X4_H |
11 | #define _TLV320AIC32X4_H | 11 | #define _TLV320AIC32X4_H |
12 | 12 | ||
13 | struct device; | ||
14 | struct regmap_config; | ||
15 | |||
16 | extern const struct regmap_config aic32x4_regmap_config; | ||
17 | int aic32x4_probe(struct device *dev, struct regmap *regmap); | ||
18 | int aic32x4_remove(struct device *dev); | ||
19 | |||
13 | /* tlv320aic32x4 register space (in decimal to match datasheet) */ | 20 | /* tlv320aic32x4 register space (in decimal to match datasheet) */ |
14 | 21 | ||
15 | #define AIC32X4_PAGE1 128 | 22 | #define AIC32X4_PAGE1 128 |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index bc3de2e844e6..1f7081043566 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -824,7 +824,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
824 | { | 824 | { |
825 | struct twl6040 *twl6040 = codec->control_data; | 825 | struct twl6040 *twl6040 = codec->control_data; |
826 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 826 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
827 | int ret; | 827 | int ret = 0; |
828 | 828 | ||
829 | switch (level) { | 829 | switch (level) { |
830 | case SND_SOC_BIAS_ON: | 830 | case SND_SOC_BIAS_ON: |
@@ -832,12 +832,16 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
832 | case SND_SOC_BIAS_PREPARE: | 832 | case SND_SOC_BIAS_PREPARE: |
833 | break; | 833 | break; |
834 | case SND_SOC_BIAS_STANDBY: | 834 | case SND_SOC_BIAS_STANDBY: |
835 | if (priv->codec_powered) | 835 | if (priv->codec_powered) { |
836 | /* Select low power PLL in standby */ | ||
837 | ret = twl6040_set_pll(twl6040, TWL6040_SYSCLK_SEL_LPPLL, | ||
838 | 32768, 19200000); | ||
836 | break; | 839 | break; |
840 | } | ||
837 | 841 | ||
838 | ret = twl6040_power(twl6040, 1); | 842 | ret = twl6040_power(twl6040, 1); |
839 | if (ret) | 843 | if (ret) |
840 | return ret; | 844 | break; |
841 | 845 | ||
842 | priv->codec_powered = 1; | 846 | priv->codec_powered = 1; |
843 | 847 | ||
@@ -853,7 +857,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec, | |||
853 | break; | 857 | break; |
854 | } | 858 | } |
855 | 859 | ||
856 | return 0; | 860 | return ret; |
857 | } | 861 | } |
858 | 862 | ||
859 | static int twl6040_startup(struct snd_pcm_substream *substream, | 863 | static int twl6040_startup(struct snd_pcm_substream *substream, |
@@ -983,9 +987,9 @@ static void twl6040_mute_path(struct snd_soc_codec *codec, enum twl6040_dai_id i | |||
983 | if (mute) { | 987 | if (mute) { |
984 | /* Power down drivers and DACs */ | 988 | /* Power down drivers and DACs */ |
985 | hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | | 989 | hflctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | |
986 | TWL6040_HFDRVENA); | 990 | TWL6040_HFDRVENA | TWL6040_HFSWENA); |
987 | hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | | 991 | hfrctl &= ~(TWL6040_HFDACENA | TWL6040_HFPGAENA | |
988 | TWL6040_HFDRVENA); | 992 | TWL6040_HFDRVENA | TWL6040_HFSWENA); |
989 | } | 993 | } |
990 | 994 | ||
991 | twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); | 995 | twl6040_reg_write(twl6040, TWL6040_REG_HFLCTL, hflctl); |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index fc164d69a557..f3109da24769 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -3793,9 +3793,8 @@ static int wm8962_runtime_resume(struct device *dev) | |||
3793 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies), | 3793 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8962->supplies), |
3794 | wm8962->supplies); | 3794 | wm8962->supplies); |
3795 | if (ret != 0) { | 3795 | if (ret != 0) { |
3796 | dev_err(dev, | 3796 | dev_err(dev, "Failed to enable supplies: %d\n", ret); |
3797 | "Failed to enable supplies: %d\n", ret); | 3797 | goto disable_clock; |
3798 | return ret; | ||
3799 | } | 3798 | } |
3800 | 3799 | ||
3801 | regcache_cache_only(wm8962->regmap, false); | 3800 | regcache_cache_only(wm8962->regmap, false); |
@@ -3833,6 +3832,10 @@ static int wm8962_runtime_resume(struct device *dev) | |||
3833 | msleep(5); | 3832 | msleep(5); |
3834 | 3833 | ||
3835 | return 0; | 3834 | return 0; |
3835 | |||
3836 | disable_clock: | ||
3837 | clk_disable_unprepare(wm8962->pdata.mclk); | ||
3838 | return ret; | ||
3836 | } | 3839 | } |
3837 | 3840 | ||
3838 | static int wm8962_runtime_suspend(struct device *dev) | 3841 | static int wm8962_runtime_suspend(struct device *dev) |
diff --git a/sound/soc/codecs/wm8962.h b/sound/soc/codecs/wm8962.h index 910aafd09d21..e63a318a3015 100644 --- a/sound/soc/codecs/wm8962.h +++ b/sound/soc/codecs/wm8962.h | |||
@@ -16,9 +16,9 @@ | |||
16 | #include <asm/types.h> | 16 | #include <asm/types.h> |
17 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
18 | 18 | ||
19 | #define WM8962_SYSCLK_MCLK 1 | 19 | #define WM8962_SYSCLK_MCLK 0 |
20 | #define WM8962_SYSCLK_FLL 2 | 20 | #define WM8962_SYSCLK_FLL 1 |
21 | #define WM8962_SYSCLK_PLL3 3 | 21 | #define WM8962_SYSCLK_PLL3 2 |
22 | 22 | ||
23 | #define WM8962_FLL 1 | 23 | #define WM8962_FLL 1 |
24 | 24 | ||
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 2389ab47e25f..466492b7d4f5 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -643,6 +643,7 @@ MODULE_DEVICE_TABLE(of, asoc_simple_of_match); | |||
643 | static struct platform_driver asoc_simple_card = { | 643 | static struct platform_driver asoc_simple_card = { |
644 | .driver = { | 644 | .driver = { |
645 | .name = "asoc-simple-card", | 645 | .name = "asoc-simple-card", |
646 | .pm = &snd_soc_pm_ops, | ||
646 | .of_match_table = asoc_simple_of_match, | 647 | .of_match_table = asoc_simple_of_match, |
647 | }, | 648 | }, |
648 | .probe = asoc_simple_card_probe, | 649 | .probe = asoc_simple_card_probe, |
diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig index 132bb83f8e99..bc3c7b5ac752 100644 --- a/sound/soc/kirkwood/Kconfig +++ b/sound/soc/kirkwood/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_KIRKWOOD_SOC | 1 | config SND_KIRKWOOD_SOC |
2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" | 2 | tristate "SoC Audio for the Marvell Kirkwood and Dove chips" |
3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST | 3 | depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST |
4 | depends on HAS_DMA | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the Kirkwood I2S interface. You will also need to select the | 7 | the Kirkwood I2S interface. You will also need to select the |
diff --git a/sound/soc/mediatek/Kconfig b/sound/soc/mediatek/Kconfig index f7e789e97fbc..3abf51c07851 100644 --- a/sound/soc/mediatek/Kconfig +++ b/sound/soc/mediatek/Kconfig | |||
@@ -43,6 +43,7 @@ config SND_SOC_MT8173_RT5650_RT5676 | |||
43 | depends on SND_SOC_MEDIATEK && I2C | 43 | depends on SND_SOC_MEDIATEK && I2C |
44 | select SND_SOC_RT5645 | 44 | select SND_SOC_RT5645 |
45 | select SND_SOC_RT5677 | 45 | select SND_SOC_RT5677 |
46 | select SND_SOC_HDMI_CODEC | ||
46 | help | 47 | help |
47 | This adds ASoC driver for Mediatek MT8173 boards | 48 | This adds ASoC driver for Mediatek MT8173 boards |
48 | with the RT5650 and RT5676 codecs. | 49 | with the RT5650 and RT5676 codecs. |
diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 5c4c58c69c51..bb593926c62d 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c | |||
@@ -134,7 +134,9 @@ static struct snd_soc_dai_link_component mt8173_rt5650_rt5676_codecs[] = { | |||
134 | enum { | 134 | enum { |
135 | DAI_LINK_PLAYBACK, | 135 | DAI_LINK_PLAYBACK, |
136 | DAI_LINK_CAPTURE, | 136 | DAI_LINK_CAPTURE, |
137 | DAI_LINK_HDMI, | ||
137 | DAI_LINK_CODEC_I2S, | 138 | DAI_LINK_CODEC_I2S, |
139 | DAI_LINK_HDMI_I2S, | ||
138 | DAI_LINK_INTERCODEC | 140 | DAI_LINK_INTERCODEC |
139 | }; | 141 | }; |
140 | 142 | ||
@@ -161,6 +163,16 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { | |||
161 | .dynamic = 1, | 163 | .dynamic = 1, |
162 | .dpcm_capture = 1, | 164 | .dpcm_capture = 1, |
163 | }, | 165 | }, |
166 | [DAI_LINK_HDMI] = { | ||
167 | .name = "HDMI", | ||
168 | .stream_name = "HDMI PCM", | ||
169 | .cpu_dai_name = "HDMI", | ||
170 | .codec_name = "snd-soc-dummy", | ||
171 | .codec_dai_name = "snd-soc-dummy-dai", | ||
172 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
173 | .dynamic = 1, | ||
174 | .dpcm_playback = 1, | ||
175 | }, | ||
164 | 176 | ||
165 | /* Back End DAI links */ | 177 | /* Back End DAI links */ |
166 | [DAI_LINK_CODEC_I2S] = { | 178 | [DAI_LINK_CODEC_I2S] = { |
@@ -177,6 +189,13 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { | |||
177 | .dpcm_playback = 1, | 189 | .dpcm_playback = 1, |
178 | .dpcm_capture = 1, | 190 | .dpcm_capture = 1, |
179 | }, | 191 | }, |
192 | [DAI_LINK_HDMI_I2S] = { | ||
193 | .name = "HDMI BE", | ||
194 | .cpu_dai_name = "HDMIO", | ||
195 | .no_pcm = 1, | ||
196 | .codec_dai_name = "i2s-hifi", | ||
197 | .dpcm_playback = 1, | ||
198 | }, | ||
180 | /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ | 199 | /* rt5676 <-> rt5650 intercodec link: Sets rt5676 I2S2 as master */ |
181 | [DAI_LINK_INTERCODEC] = { | 200 | [DAI_LINK_INTERCODEC] = { |
182 | .name = "rt5650_rt5676 intercodec", | 201 | .name = "rt5650_rt5676 intercodec", |
@@ -251,6 +270,14 @@ static int mt8173_rt5650_rt5676_dev_probe(struct platform_device *pdev) | |||
251 | mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = | 270 | mt8173_rt5650_rt5676_dais[DAI_LINK_INTERCODEC].codec_of_node = |
252 | mt8173_rt5650_rt5676_codecs[1].of_node; | 271 | mt8173_rt5650_rt5676_codecs[1].of_node; |
253 | 272 | ||
273 | mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node = | ||
274 | of_parse_phandle(pdev->dev.of_node, "mediatek,audio-codec", 2); | ||
275 | if (!mt8173_rt5650_rt5676_dais[DAI_LINK_HDMI_I2S].codec_of_node) { | ||
276 | dev_err(&pdev->dev, | ||
277 | "Property 'audio-codec' missing or invalid\n"); | ||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
254 | card->dev = &pdev->dev; | 281 | card->dev = &pdev->dev; |
255 | platform_set_drvdata(pdev, card); | 282 | platform_set_drvdata(pdev, card); |
256 | 283 | ||
diff --git a/sound/soc/mediatek/mt8173-rt5650.c b/sound/soc/mediatek/mt8173-rt5650.c index bb09bb1b7f1c..a27a6673dbe3 100644 --- a/sound/soc/mediatek/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173-rt5650.c | |||
@@ -85,12 +85,29 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) | |||
85 | { | 85 | { |
86 | struct snd_soc_card *card = runtime->card; | 86 | struct snd_soc_card *card = runtime->card; |
87 | struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; | 87 | struct snd_soc_codec *codec = runtime->codec_dais[0]->codec; |
88 | const char *codec_capture_dai = runtime->codec_dais[1]->name; | ||
88 | int ret; | 89 | int ret; |
89 | 90 | ||
90 | rt5645_sel_asrc_clk_src(codec, | 91 | rt5645_sel_asrc_clk_src(codec, |
91 | RT5645_DA_STEREO_FILTER | | 92 | RT5645_DA_STEREO_FILTER, |
92 | RT5645_AD_STEREO_FILTER, | ||
93 | RT5645_CLK_SEL_I2S1_ASRC); | 93 | RT5645_CLK_SEL_I2S1_ASRC); |
94 | |||
95 | if (!strcmp(codec_capture_dai, "rt5645-aif1")) { | ||
96 | rt5645_sel_asrc_clk_src(codec, | ||
97 | RT5645_AD_STEREO_FILTER, | ||
98 | RT5645_CLK_SEL_I2S1_ASRC); | ||
99 | } else if (!strcmp(codec_capture_dai, "rt5645-aif2")) { | ||
100 | rt5645_sel_asrc_clk_src(codec, | ||
101 | RT5645_AD_STEREO_FILTER, | ||
102 | RT5645_CLK_SEL_I2S2_ASRC); | ||
103 | } else { | ||
104 | dev_warn(card->dev, | ||
105 | "Only one dai codec found in DTS, enabled rt5645 AD filter\n"); | ||
106 | rt5645_sel_asrc_clk_src(codec, | ||
107 | RT5645_AD_STEREO_FILTER, | ||
108 | RT5645_CLK_SEL_I2S1_ASRC); | ||
109 | } | ||
110 | |||
94 | /* enable jack detection */ | 111 | /* enable jack detection */ |
95 | ret = snd_soc_card_jack_new(card, "Headset Jack", | 112 | ret = snd_soc_card_jack_new(card, "Headset Jack", |
96 | SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | | 113 | SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | |
@@ -110,6 +127,11 @@ static int mt8173_rt5650_init(struct snd_soc_pcm_runtime *runtime) | |||
110 | 127 | ||
111 | static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { | 128 | static struct snd_soc_dai_link_component mt8173_rt5650_codecs[] = { |
112 | { | 129 | { |
130 | /* Playback */ | ||
131 | .dai_name = "rt5645-aif1", | ||
132 | }, | ||
133 | { | ||
134 | /* Capture */ | ||
113 | .dai_name = "rt5645-aif1", | 135 | .dai_name = "rt5645-aif1", |
114 | }, | 136 | }, |
115 | }; | 137 | }; |
@@ -149,7 +171,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { | |||
149 | .cpu_dai_name = "I2S", | 171 | .cpu_dai_name = "I2S", |
150 | .no_pcm = 1, | 172 | .no_pcm = 1, |
151 | .codecs = mt8173_rt5650_codecs, | 173 | .codecs = mt8173_rt5650_codecs, |
152 | .num_codecs = 1, | 174 | .num_codecs = 2, |
153 | .init = mt8173_rt5650_init, | 175 | .init = mt8173_rt5650_init, |
154 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | 176 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | |
155 | SND_SOC_DAIFMT_CBS_CFS, | 177 | SND_SOC_DAIFMT_CBS_CFS, |
@@ -177,6 +199,8 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) | |||
177 | { | 199 | { |
178 | struct snd_soc_card *card = &mt8173_rt5650_card; | 200 | struct snd_soc_card *card = &mt8173_rt5650_card; |
179 | struct device_node *platform_node; | 201 | struct device_node *platform_node; |
202 | struct device_node *np; | ||
203 | const char *codec_capture_dai; | ||
180 | int i, ret; | 204 | int i, ret; |
181 | 205 | ||
182 | platform_node = of_parse_phandle(pdev->dev.of_node, | 206 | platform_node = of_parse_phandle(pdev->dev.of_node, |
@@ -199,6 +223,26 @@ static int mt8173_rt5650_dev_probe(struct platform_device *pdev) | |||
199 | "Property 'audio-codec' missing or invalid\n"); | 223 | "Property 'audio-codec' missing or invalid\n"); |
200 | return -EINVAL; | 224 | return -EINVAL; |
201 | } | 225 | } |
226 | mt8173_rt5650_codecs[1].of_node = mt8173_rt5650_codecs[0].of_node; | ||
227 | |||
228 | if (of_find_node_by_name(platform_node, "codec-capture")) { | ||
229 | np = of_get_child_by_name(pdev->dev.of_node, "codec-capture"); | ||
230 | if (!np) { | ||
231 | dev_err(&pdev->dev, | ||
232 | "%s: Can't find codec-capture DT node\n", | ||
233 | __func__); | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | ret = snd_soc_of_get_dai_name(np, &codec_capture_dai); | ||
237 | if (ret < 0) { | ||
238 | dev_err(&pdev->dev, | ||
239 | "%s codec_capture_dai name fail %d\n", | ||
240 | __func__, ret); | ||
241 | return ret; | ||
242 | } | ||
243 | mt8173_rt5650_codecs[1].dai_name = codec_capture_dai; | ||
244 | } | ||
245 | |||
202 | card->dev = &pdev->dev; | 246 | card->dev = &pdev->dev; |
203 | platform_set_drvdata(pdev, card); | 247 | platform_set_drvdata(pdev, card); |
204 | 248 | ||
diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index f1c58a2c12fb..2b5df2ef51a3 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c | |||
@@ -123,6 +123,7 @@ | |||
123 | #define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8) | 123 | #define AFE_TDM_CON1_WLEN_32BIT (0x2 << 8) |
124 | #define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4) | 124 | #define AFE_TDM_CON1_MSB_ALIGNED (0x1 << 4) |
125 | #define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3) | 125 | #define AFE_TDM_CON1_1_BCK_DELAY (0x1 << 3) |
126 | #define AFE_TDM_CON1_LRCK_INV (0x1 << 2) | ||
126 | #define AFE_TDM_CON1_BCK_INV (0x1 << 1) | 127 | #define AFE_TDM_CON1_BCK_INV (0x1 << 1) |
127 | #define AFE_TDM_CON1_EN (0x1 << 0) | 128 | #define AFE_TDM_CON1_EN (0x1 << 0) |
128 | 129 | ||
@@ -449,6 +450,7 @@ static int mtk_afe_hdmi_prepare(struct snd_pcm_substream *substream, | |||
449 | runtime->rate * runtime->channels * 32); | 450 | runtime->rate * runtime->channels * 32); |
450 | 451 | ||
451 | val = AFE_TDM_CON1_BCK_INV | | 452 | val = AFE_TDM_CON1_BCK_INV | |
453 | AFE_TDM_CON1_LRCK_INV | | ||
452 | AFE_TDM_CON1_1_BCK_DELAY | | 454 | AFE_TDM_CON1_1_BCK_DELAY | |
453 | AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */ | 455 | AFE_TDM_CON1_MSB_ALIGNED | /* I2S mode */ |
454 | AFE_TDM_CON1_WLEN_32BIT | | 456 | AFE_TDM_CON1_WLEN_32BIT | |
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index c7563e230c7d..4a16e778966b 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c | |||
@@ -260,6 +260,10 @@ static void omap_st_on(struct omap_mcbsp *mcbsp) | |||
260 | if (mcbsp->pdata->enable_st_clock) | 260 | if (mcbsp->pdata->enable_st_clock) |
261 | mcbsp->pdata->enable_st_clock(mcbsp->id, 1); | 261 | mcbsp->pdata->enable_st_clock(mcbsp->id, 1); |
262 | 262 | ||
263 | /* Disable Sidetone clock auto-gating for normal operation */ | ||
264 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
265 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w & ~(ST_AUTOIDLE)); | ||
266 | |||
263 | /* Enable McBSP Sidetone */ | 267 | /* Enable McBSP Sidetone */ |
264 | w = MCBSP_READ(mcbsp, SSELCR); | 268 | w = MCBSP_READ(mcbsp, SSELCR); |
265 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); | 269 | MCBSP_WRITE(mcbsp, SSELCR, w | SIDETONEEN); |
@@ -279,6 +283,10 @@ static void omap_st_off(struct omap_mcbsp *mcbsp) | |||
279 | w = MCBSP_READ(mcbsp, SSELCR); | 283 | w = MCBSP_READ(mcbsp, SSELCR); |
280 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); | 284 | MCBSP_WRITE(mcbsp, SSELCR, w & ~(SIDETONEEN)); |
281 | 285 | ||
286 | /* Enable Sidetone clock auto-gating to reduce power consumption */ | ||
287 | w = MCBSP_ST_READ(mcbsp, SYSCONFIG); | ||
288 | MCBSP_ST_WRITE(mcbsp, SYSCONFIG, w | ST_AUTOIDLE); | ||
289 | |||
282 | if (mcbsp->pdata->enable_st_clock) | 290 | if (mcbsp->pdata->enable_st_clock) |
283 | mcbsp->pdata->enable_st_clock(mcbsp->id, 0); | 291 | mcbsp->pdata->enable_st_clock(mcbsp->id, 0); |
284 | } | 292 | } |
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 99381a27295b..a84f677234f0 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -82,6 +82,8 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream, | |||
82 | struct dma_chan *chan; | 82 | struct dma_chan *chan; |
83 | int err = 0; | 83 | int err = 0; |
84 | 84 | ||
85 | memset(&config, 0x00, sizeof(config)); | ||
86 | |||
85 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | 87 | dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); |
86 | 88 | ||
87 | /* return if this is a bufferless transfer e.g. | 89 | /* return if this is a bufferless transfer e.g. |
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index ec522e94b0e2..b6cb9950f05d 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c | |||
@@ -133,3 +133,4 @@ module_platform_driver(mmp_driver); | |||
133 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 133 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
134 | MODULE_DESCRIPTION("ALSA SoC Brownstone"); | 134 | MODULE_DESCRIPTION("ALSA SoC Brownstone"); |
135 | MODULE_LICENSE("GPL"); | 135 | MODULE_LICENSE("GPL"); |
136 | MODULE_ALIAS("platform:brownstone-audio"); | ||
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c index 5c8f9db50a47..d1661fa6ee08 100644 --- a/sound/soc/pxa/mioa701_wm9713.c +++ b/sound/soc/pxa/mioa701_wm9713.c | |||
@@ -207,3 +207,4 @@ module_platform_driver(mioa701_wm9713_driver); | |||
207 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); | 207 | MODULE_AUTHOR("Robert Jarzmik (rjarzmik@free.fr)"); |
208 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); | 208 | MODULE_DESCRIPTION("ALSA SoC WM9713 MIO A701"); |
209 | MODULE_LICENSE("GPL"); | 209 | MODULE_LICENSE("GPL"); |
210 | MODULE_ALIAS("platform:mioa701-wm9713"); | ||
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 51e790d006f5..96df9b2d8fc4 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c | |||
@@ -248,3 +248,4 @@ module_platform_driver(mmp_pcm_driver); | |||
248 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 248 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
249 | MODULE_DESCRIPTION("MMP Soc Audio DMA module"); | 249 | MODULE_DESCRIPTION("MMP Soc Audio DMA module"); |
250 | MODULE_LICENSE("GPL"); | 250 | MODULE_LICENSE("GPL"); |
251 | MODULE_ALIAS("platform:mmp-pcm-audio"); | ||
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c index eca60c29791a..ca8b23f8c525 100644 --- a/sound/soc/pxa/mmp-sspa.c +++ b/sound/soc/pxa/mmp-sspa.c | |||
@@ -482,3 +482,4 @@ module_platform_driver(asoc_mmp_sspa_driver); | |||
482 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | 482 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); |
483 | MODULE_DESCRIPTION("MMP SSPA SoC Interface"); | 483 | MODULE_DESCRIPTION("MMP SSPA SoC Interface"); |
484 | MODULE_LICENSE("GPL"); | 484 | MODULE_LICENSE("GPL"); |
485 | MODULE_ALIAS("platform:mmp-sspa-dai"); | ||
diff --git a/sound/soc/pxa/palm27x.c b/sound/soc/pxa/palm27x.c index 4e74d9573f03..bcc81e920a67 100644 --- a/sound/soc/pxa/palm27x.c +++ b/sound/soc/pxa/palm27x.c | |||
@@ -161,3 +161,4 @@ module_platform_driver(palm27x_wm9712_driver); | |||
161 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | 161 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); |
162 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); | 162 | MODULE_DESCRIPTION("ALSA SoC Palm T|X, T5 and LifeDrive"); |
163 | MODULE_LICENSE("GPL"); | 163 | MODULE_LICENSE("GPL"); |
164 | MODULE_ALIAS("platform:palm27x-asoc"); | ||
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index da03fad1b9cd..3cad990dad2c 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -833,3 +833,4 @@ module_platform_driver(asoc_ssp_driver); | |||
833 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 833 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
834 | MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); | 834 | MODULE_DESCRIPTION("PXA SSP/PCM SoC Interface"); |
835 | MODULE_LICENSE("GPL"); | 835 | MODULE_LICENSE("GPL"); |
836 | MODULE_ALIAS("platform:pxa-ssp-dai"); | ||
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index f3de615aacd7..9615e6de1306 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -287,3 +287,4 @@ module_platform_driver(pxa2xx_ac97_driver); | |||
287 | MODULE_AUTHOR("Nicolas Pitre"); | 287 | MODULE_AUTHOR("Nicolas Pitre"); |
288 | MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); | 288 | MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); |
289 | MODULE_LICENSE("GPL"); | 289 | MODULE_LICENSE("GPL"); |
290 | MODULE_ALIAS("platform:pxa2xx-ac97"); | ||
diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index 9f390398d518..410d48b93031 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c | |||
@@ -117,3 +117,4 @@ module_platform_driver(pxa_pcm_driver); | |||
117 | MODULE_AUTHOR("Nicolas Pitre"); | 117 | MODULE_AUTHOR("Nicolas Pitre"); |
118 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); | 118 | MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module"); |
119 | MODULE_LICENSE("GPL"); | 119 | MODULE_LICENSE("GPL"); |
120 | MODULE_ALIAS("platform:pxa-pcm-audio"); | ||
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index ddfe34434765..db000c6987a1 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c | |||
@@ -474,7 +474,7 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
474 | struct lpass_data *drvdata = | 474 | struct lpass_data *drvdata = |
475 | snd_soc_platform_get_drvdata(soc_runtime->platform); | 475 | snd_soc_platform_get_drvdata(soc_runtime->platform); |
476 | struct lpass_variant *v = drvdata->variant; | 476 | struct lpass_variant *v = drvdata->variant; |
477 | int ret; | 477 | int ret = -EINVAL; |
478 | struct lpass_pcm_data *data; | 478 | struct lpass_pcm_data *data; |
479 | size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; | 479 | size_t size = lpass_platform_pcm_hardware.buffer_bytes_max; |
480 | 480 | ||
@@ -518,8 +518,10 @@ static int lpass_platform_pcm_new(struct snd_soc_pcm_runtime *soc_runtime) | |||
518 | data->wrdma_ch = v->alloc_dma_channel(drvdata, | 518 | data->wrdma_ch = v->alloc_dma_channel(drvdata, |
519 | SNDRV_PCM_STREAM_CAPTURE); | 519 | SNDRV_PCM_STREAM_CAPTURE); |
520 | 520 | ||
521 | if (data->wrdma_ch < 0) | 521 | if (data->wrdma_ch < 0) { |
522 | ret = data->wrdma_ch; | ||
522 | goto capture_alloc_err; | 523 | goto capture_alloc_err; |
524 | } | ||
523 | 525 | ||
524 | drvdata->substream[data->wrdma_ch] = csubstream; | 526 | drvdata->substream[data->wrdma_ch] = csubstream; |
525 | 527 | ||
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 606399de684d..49354d17ea55 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -492,9 +492,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
492 | */ | 492 | */ |
493 | if (!count) { | 493 | if (!count) { |
494 | clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], | 494 | clk = clk_register_fixed_rate(dev, clkout_name[CLKOUT], |
495 | parent_clk_name, | 495 | parent_clk_name, 0, req_rate); |
496 | (parent_clk_name) ? | ||
497 | 0 : CLK_IS_ROOT, req_rate); | ||
498 | if (!IS_ERR(clk)) { | 496 | if (!IS_ERR(clk)) { |
499 | adg->clkout[CLKOUT] = clk; | 497 | adg->clkout[CLKOUT] = clk; |
500 | of_clk_add_provider(np, of_clk_src_simple_get, clk); | 498 | of_clk_add_provider(np, of_clk_src_simple_get, clk); |
@@ -506,9 +504,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
506 | else { | 504 | else { |
507 | for (i = 0; i < CLKOUTMAX; i++) { | 505 | for (i = 0; i < CLKOUTMAX; i++) { |
508 | clk = clk_register_fixed_rate(dev, clkout_name[i], | 506 | clk = clk_register_fixed_rate(dev, clkout_name[i], |
509 | parent_clk_name, | 507 | parent_clk_name, 0, |
510 | (parent_clk_name) ? | ||
511 | 0 : CLK_IS_ROOT, | ||
512 | req_rate); | 508 | req_rate); |
513 | if (!IS_ERR(clk)) { | 509 | if (!IS_ERR(clk)) { |
514 | adg->onecell.clks = adg->clkout; | 510 | adg->onecell.clks = adg->clkout; |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 7658e8fd7bdc..6bc93cbb3049 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
@@ -316,11 +316,15 @@ static u32 rsnd_dmapp_get_id(struct rsnd_dai_stream *io, | |||
316 | size = ARRAY_SIZE(gen2_id_table_cmd); | 316 | size = ARRAY_SIZE(gen2_id_table_cmd); |
317 | } | 317 | } |
318 | 318 | ||
319 | if (!entry) | 319 | if ((!entry) || (size <= id)) { |
320 | return 0xFF; | 320 | struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); |
321 | 321 | ||
322 | if (size <= id) | 322 | dev_err(dev, "unknown connection (%s[%d])\n", |
323 | return 0xFF; | 323 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
324 | |||
325 | /* use non-prohibited SRS number as error */ | ||
326 | return 0x00; /* SSI00 */ | ||
327 | } | ||
324 | 328 | ||
325 | return entry[id]; | 329 | return entry[id]; |
326 | } | 330 | } |
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index fc89a67258ca..a8f61d79333b 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -276,8 +276,9 @@ struct rsnd_mod { | |||
276 | /* | 276 | /* |
277 | * status | 277 | * status |
278 | * | 278 | * |
279 | * 0xH0000CB0 | 279 | * 0xH0000CBA |
280 | * | 280 | * |
281 | * A 0: probe 1: remove | ||
281 | * B 0: init 1: quit | 282 | * B 0: init 1: quit |
282 | * C 0: start 1: stop | 283 | * C 0: start 1: stop |
283 | * | 284 | * |
@@ -287,19 +288,19 @@ struct rsnd_mod { | |||
287 | * H 0: fallback | 288 | * H 0: fallback |
288 | * H 0: hw_params | 289 | * H 0: hw_params |
289 | */ | 290 | */ |
291 | #define __rsnd_mod_shift_probe 0 | ||
292 | #define __rsnd_mod_shift_remove 0 | ||
290 | #define __rsnd_mod_shift_init 4 | 293 | #define __rsnd_mod_shift_init 4 |
291 | #define __rsnd_mod_shift_quit 4 | 294 | #define __rsnd_mod_shift_quit 4 |
292 | #define __rsnd_mod_shift_start 8 | 295 | #define __rsnd_mod_shift_start 8 |
293 | #define __rsnd_mod_shift_stop 8 | 296 | #define __rsnd_mod_shift_stop 8 |
294 | #define __rsnd_mod_shift_probe 28 /* always called */ | ||
295 | #define __rsnd_mod_shift_remove 28 /* always called */ | ||
296 | #define __rsnd_mod_shift_irq 28 /* always called */ | 297 | #define __rsnd_mod_shift_irq 28 /* always called */ |
297 | #define __rsnd_mod_shift_pcm_new 28 /* always called */ | 298 | #define __rsnd_mod_shift_pcm_new 28 /* always called */ |
298 | #define __rsnd_mod_shift_fallback 28 /* always called */ | 299 | #define __rsnd_mod_shift_fallback 28 /* always called */ |
299 | #define __rsnd_mod_shift_hw_params 28 /* always called */ | 300 | #define __rsnd_mod_shift_hw_params 28 /* always called */ |
300 | 301 | ||
301 | #define __rsnd_mod_add_probe 0 | 302 | #define __rsnd_mod_add_probe 1 |
302 | #define __rsnd_mod_add_remove 0 | 303 | #define __rsnd_mod_add_remove -1 |
303 | #define __rsnd_mod_add_init 1 | 304 | #define __rsnd_mod_add_init 1 |
304 | #define __rsnd_mod_add_quit -1 | 305 | #define __rsnd_mod_add_quit -1 |
305 | #define __rsnd_mod_add_start 1 | 306 | #define __rsnd_mod_add_start 1 |
@@ -310,7 +311,7 @@ struct rsnd_mod { | |||
310 | #define __rsnd_mod_add_hw_params 0 | 311 | #define __rsnd_mod_add_hw_params 0 |
311 | 312 | ||
312 | #define __rsnd_mod_call_probe 0 | 313 | #define __rsnd_mod_call_probe 0 |
313 | #define __rsnd_mod_call_remove 0 | 314 | #define __rsnd_mod_call_remove 1 |
314 | #define __rsnd_mod_call_init 0 | 315 | #define __rsnd_mod_call_init 0 |
315 | #define __rsnd_mod_call_quit 1 | 316 | #define __rsnd_mod_call_quit 1 |
316 | #define __rsnd_mod_call_start 0 | 317 | #define __rsnd_mod_call_start 0 |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 15d6ffe8be74..e39f916d0f2f 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
@@ -572,6 +572,9 @@ int rsnd_src_probe(struct rsnd_priv *priv) | |||
572 | 572 | ||
573 | i = 0; | 573 | i = 0; |
574 | for_each_child_of_node(node, np) { | 574 | for_each_child_of_node(node, np) { |
575 | if (!of_device_is_available(np)) | ||
576 | goto skip; | ||
577 | |||
575 | src = rsnd_src_get(priv, i); | 578 | src = rsnd_src_get(priv, i); |
576 | 579 | ||
577 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", | 580 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", |
@@ -595,6 +598,7 @@ int rsnd_src_probe(struct rsnd_priv *priv) | |||
595 | if (ret) | 598 | if (ret) |
596 | goto rsnd_src_probe_done; | 599 | goto rsnd_src_probe_done; |
597 | 600 | ||
601 | skip: | ||
598 | i++; | 602 | i++; |
599 | } | 603 | } |
600 | 604 | ||
diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 1cf94d7fb9f4..ee7f15aa46fc 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c | |||
@@ -1023,6 +1023,11 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, | |||
1023 | 1023 | ||
1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; | 1024 | control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; |
1025 | 1025 | ||
1026 | if (control_hdr->size != sizeof(*control_hdr)) { | ||
1027 | dev_err(tplg->dev, "ASoC: invalid control size\n"); | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1026 | switch (control_hdr->ops.info) { | 1031 | switch (control_hdr->ops.info) { |
1027 | case SND_SOC_TPLG_CTL_VOLSW: | 1032 | case SND_SOC_TPLG_CTL_VOLSW: |
1028 | case SND_SOC_TPLG_CTL_STROBE: | 1033 | case SND_SOC_TPLG_CTL_STROBE: |
@@ -1476,6 +1481,8 @@ widget: | |||
1476 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; | 1481 | widget->dobj.type = SND_SOC_DOBJ_WIDGET; |
1477 | widget->dobj.ops = tplg->ops; | 1482 | widget->dobj.ops = tplg->ops; |
1478 | widget->dobj.index = tplg->index; | 1483 | widget->dobj.index = tplg->index; |
1484 | kfree(template.sname); | ||
1485 | kfree(template.name); | ||
1479 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); | 1486 | list_add(&widget->dobj.list, &tplg->comp->dobj_list); |
1480 | return 0; | 1487 | return 0; |
1481 | 1488 | ||
@@ -1499,10 +1506,17 @@ static int soc_tplg_dapm_widget_elems_load(struct soc_tplg *tplg, | |||
1499 | 1506 | ||
1500 | for (i = 0; i < count; i++) { | 1507 | for (i = 0; i < count; i++) { |
1501 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; | 1508 | widget = (struct snd_soc_tplg_dapm_widget *) tplg->pos; |
1509 | if (widget->size != sizeof(*widget)) { | ||
1510 | dev_err(tplg->dev, "ASoC: invalid widget size\n"); | ||
1511 | return -EINVAL; | ||
1512 | } | ||
1513 | |||
1502 | ret = soc_tplg_dapm_widget_create(tplg, widget); | 1514 | ret = soc_tplg_dapm_widget_create(tplg, widget); |
1503 | if (ret < 0) | 1515 | if (ret < 0) { |
1504 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", | 1516 | dev_err(tplg->dev, "ASoC: failed to load widget %s\n", |
1505 | widget->name); | 1517 | widget->name); |
1518 | return ret; | ||
1519 | } | ||
1506 | } | 1520 | } |
1507 | 1521 | ||
1508 | return 0; | 1522 | return 0; |
@@ -1586,6 +1600,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg, | |||
1586 | return snd_soc_register_dai(tplg->comp, dai_drv); | 1600 | return snd_soc_register_dai(tplg->comp, dai_drv); |
1587 | } | 1601 | } |
1588 | 1602 | ||
1603 | /* create the FE DAI link */ | ||
1589 | static int soc_tplg_link_create(struct soc_tplg *tplg, | 1604 | static int soc_tplg_link_create(struct soc_tplg *tplg, |
1590 | struct snd_soc_tplg_pcm *pcm) | 1605 | struct snd_soc_tplg_pcm *pcm) |
1591 | { | 1606 | { |
@@ -1598,6 +1613,16 @@ static int soc_tplg_link_create(struct soc_tplg *tplg, | |||
1598 | 1613 | ||
1599 | link->name = pcm->pcm_name; | 1614 | link->name = pcm->pcm_name; |
1600 | link->stream_name = pcm->pcm_name; | 1615 | link->stream_name = pcm->pcm_name; |
1616 | link->id = pcm->pcm_id; | ||
1617 | |||
1618 | link->cpu_dai_name = pcm->dai_name; | ||
1619 | link->codec_name = "snd-soc-dummy"; | ||
1620 | link->codec_dai_name = "snd-soc-dummy-dai"; | ||
1621 | |||
1622 | /* enable DPCM */ | ||
1623 | link->dynamic = 1; | ||
1624 | link->dpcm_playback = pcm->playback; | ||
1625 | link->dpcm_capture = pcm->capture; | ||
1601 | 1626 | ||
1602 | /* pass control to component driver for optional further init */ | 1627 | /* pass control to component driver for optional further init */ |
1603 | ret = soc_tplg_dai_link_load(tplg, link); | 1628 | ret = soc_tplg_dai_link_load(tplg, link); |
@@ -1639,8 +1664,6 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1639 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) | 1664 | if (tplg->pass != SOC_TPLG_PASS_PCM_DAI) |
1640 | return 0; | 1665 | return 0; |
1641 | 1666 | ||
1642 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1643 | |||
1644 | if (soc_tplg_check_elem_count(tplg, | 1667 | if (soc_tplg_check_elem_count(tplg, |
1645 | sizeof(struct snd_soc_tplg_pcm), count, | 1668 | sizeof(struct snd_soc_tplg_pcm), count, |
1646 | hdr->payload_size, "PCM DAI")) { | 1669 | hdr->payload_size, "PCM DAI")) { |
@@ -1650,7 +1673,13 @@ static int soc_tplg_pcm_elems_load(struct soc_tplg *tplg, | |||
1650 | } | 1673 | } |
1651 | 1674 | ||
1652 | /* create the FE DAIs and DAI links */ | 1675 | /* create the FE DAIs and DAI links */ |
1676 | pcm = (struct snd_soc_tplg_pcm *)tplg->pos; | ||
1653 | for (i = 0; i < count; i++) { | 1677 | for (i = 0; i < count; i++) { |
1678 | if (pcm->size != sizeof(*pcm)) { | ||
1679 | dev_err(tplg->dev, "ASoC: invalid pcm size\n"); | ||
1680 | return -EINVAL; | ||
1681 | } | ||
1682 | |||
1654 | soc_tplg_pcm_create(tplg, pcm); | 1683 | soc_tplg_pcm_create(tplg, pcm); |
1655 | pcm++; | 1684 | pcm++; |
1656 | } | 1685 | } |
@@ -1670,6 +1699,11 @@ static int soc_tplg_manifest_load(struct soc_tplg *tplg, | |||
1670 | return 0; | 1699 | return 0; |
1671 | 1700 | ||
1672 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; | 1701 | manifest = (struct snd_soc_tplg_manifest *)tplg->pos; |
1702 | if (manifest->size != sizeof(*manifest)) { | ||
1703 | dev_err(tplg->dev, "ASoC: invalid manifest size\n"); | ||
1704 | return -EINVAL; | ||
1705 | } | ||
1706 | |||
1673 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); | 1707 | tplg->pos += sizeof(struct snd_soc_tplg_manifest); |
1674 | 1708 | ||
1675 | if (tplg->comp && tplg->ops && tplg->ops->manifest) | 1709 | if (tplg->comp && tplg->ops && tplg->ops->manifest) |
@@ -1686,6 +1720,14 @@ static int soc_valid_header(struct soc_tplg *tplg, | |||
1686 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) | 1720 | if (soc_tplg_get_hdr_offset(tplg) >= tplg->fw->size) |
1687 | return 0; | 1721 | return 0; |
1688 | 1722 | ||
1723 | if (hdr->size != sizeof(*hdr)) { | ||
1724 | dev_err(tplg->dev, | ||
1725 | "ASoC: invalid header size for type %d at offset 0x%lx size 0x%zx.\n", | ||
1726 | hdr->type, soc_tplg_get_hdr_offset(tplg), | ||
1727 | tplg->fw->size); | ||
1728 | return -EINVAL; | ||
1729 | } | ||
1730 | |||
1689 | /* big endian firmware objects not supported atm */ | 1731 | /* big endian firmware objects not supported atm */ |
1690 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { | 1732 | if (hdr->magic == cpu_to_be32(SND_SOC_TPLG_MAGIC)) { |
1691 | dev_err(tplg->dev, | 1733 | dev_err(tplg->dev, |
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 39bcefe5eea0..488ef4ed8fba 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c | |||
@@ -11,6 +11,142 @@ | |||
11 | #include "uniperif.h" | 11 | #include "uniperif.h" |
12 | 12 | ||
13 | /* | 13 | /* |
14 | * User frame size shall be 2, 4, 6 or 8 32-bits words length | ||
15 | * (i.e. 8, 16, 24 or 32 bytes) | ||
16 | * This constraint comes from allowed values for | ||
17 | * UNIPERIF_I2S_FMT_NUM_CH register | ||
18 | */ | ||
19 | #define UNIPERIF_MAX_FRAME_SZ 0x20 | ||
20 | #define UNIPERIF_ALLOWED_FRAME_SZ (0x08 | 0x10 | 0x18 | UNIPERIF_MAX_FRAME_SZ) | ||
21 | |||
22 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
23 | unsigned int rx_mask, int slots, | ||
24 | int slot_width) | ||
25 | { | ||
26 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
27 | struct uniperif *uni = priv->dai_data.uni; | ||
28 | int i, frame_size, avail_slots; | ||
29 | |||
30 | if (!UNIPERIF_TYPE_IS_TDM(uni)) { | ||
31 | dev_err(uni->dev, "cpu dai not in tdm mode\n"); | ||
32 | return -EINVAL; | ||
33 | } | ||
34 | |||
35 | /* store info in unip context */ | ||
36 | uni->tdm_slot.slots = slots; | ||
37 | uni->tdm_slot.slot_width = slot_width; | ||
38 | /* unip is unidirectionnal */ | ||
39 | uni->tdm_slot.mask = (tx_mask != 0) ? tx_mask : rx_mask; | ||
40 | |||
41 | /* number of available timeslots */ | ||
42 | for (i = 0, avail_slots = 0; i < uni->tdm_slot.slots; i++) { | ||
43 | if ((uni->tdm_slot.mask >> i) & 0x01) | ||
44 | avail_slots++; | ||
45 | } | ||
46 | uni->tdm_slot.avail_slots = avail_slots; | ||
47 | |||
48 | /* frame size in bytes */ | ||
49 | frame_size = uni->tdm_slot.avail_slots * uni->tdm_slot.slot_width / 8; | ||
50 | |||
51 | /* check frame size is allowed */ | ||
52 | if ((frame_size > UNIPERIF_MAX_FRAME_SZ) || | ||
53 | (frame_size & ~(int)UNIPERIF_ALLOWED_FRAME_SZ)) { | ||
54 | dev_err(uni->dev, "frame size not allowed: %d bytes\n", | ||
55 | frame_size); | ||
56 | return -EINVAL; | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
63 | struct snd_pcm_hw_rule *rule) | ||
64 | { | ||
65 | struct uniperif *uni = rule->private; | ||
66 | struct snd_interval t; | ||
67 | |||
68 | t.min = uni->tdm_slot.avail_slots; | ||
69 | t.max = uni->tdm_slot.avail_slots; | ||
70 | t.openmin = 0; | ||
71 | t.openmax = 0; | ||
72 | t.integer = 0; | ||
73 | |||
74 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
75 | } | ||
76 | |||
77 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
78 | struct snd_pcm_hw_rule *rule) | ||
79 | { | ||
80 | struct uniperif *uni = rule->private; | ||
81 | struct snd_mask *maskp = hw_param_mask(params, rule->var); | ||
82 | u64 format; | ||
83 | |||
84 | switch (uni->tdm_slot.slot_width) { | ||
85 | case 16: | ||
86 | format = SNDRV_PCM_FMTBIT_S16_LE; | ||
87 | break; | ||
88 | case 32: | ||
89 | format = SNDRV_PCM_FMTBIT_S32_LE; | ||
90 | break; | ||
91 | default: | ||
92 | dev_err(uni->dev, "format not supported: %d bits\n", | ||
93 | uni->tdm_slot.slot_width); | ||
94 | return -EINVAL; | ||
95 | } | ||
96 | |||
97 | maskp->bits[0] &= (u_int32_t)format; | ||
98 | maskp->bits[1] &= (u_int32_t)(format >> 32); | ||
99 | /* clear remaining indexes */ | ||
100 | memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX - 64) / 8); | ||
101 | |||
102 | if (!maskp->bits[0] && !maskp->bits[1]) | ||
103 | return -EINVAL; | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
109 | unsigned int *word_pos) | ||
110 | { | ||
111 | int slot_width = uni->tdm_slot.slot_width / 8; | ||
112 | int slots_num = uni->tdm_slot.slots; | ||
113 | unsigned int slots_mask = uni->tdm_slot.mask; | ||
114 | int i, j, k; | ||
115 | unsigned int word16_pos[4]; | ||
116 | |||
117 | /* word16_pos: | ||
118 | * word16_pos[0] = WORDX_LSB | ||
119 | * word16_pos[1] = WORDX_MSB, | ||
120 | * word16_pos[2] = WORDX+1_LSB | ||
121 | * word16_pos[3] = WORDX+1_MSB | ||
122 | */ | ||
123 | |||
124 | /* set unip word position */ | ||
125 | for (i = 0, j = 0, k = 0; (i < slots_num) && (k < WORD_MAX); i++) { | ||
126 | if ((slots_mask >> i) & 0x01) { | ||
127 | word16_pos[j] = i * slot_width; | ||
128 | |||
129 | if (slot_width == 4) { | ||
130 | word16_pos[j + 1] = word16_pos[j] + 2; | ||
131 | j++; | ||
132 | } | ||
133 | j++; | ||
134 | |||
135 | if (j > 3) { | ||
136 | word_pos[k] = word16_pos[1] | | ||
137 | (word16_pos[0] << 8) | | ||
138 | (word16_pos[3] << 16) | | ||
139 | (word16_pos[2] << 24); | ||
140 | j = 0; | ||
141 | k++; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | /* | ||
14 | * sti_uniperiph_dai_create_ctrl | 150 | * sti_uniperiph_dai_create_ctrl |
15 | * This function is used to create Ctrl associated to DAI but also pcm device. | 151 | * This function is used to create Ctrl associated to DAI but also pcm device. |
16 | * Request is done by front end to associate ctrl with pcm device id | 152 | * Request is done by front end to associate ctrl with pcm device id |
@@ -45,10 +181,16 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
45 | struct snd_pcm_hw_params *params, | 181 | struct snd_pcm_hw_params *params, |
46 | struct snd_soc_dai *dai) | 182 | struct snd_soc_dai *dai) |
47 | { | 183 | { |
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *uni = priv->dai_data.uni; | ||
48 | struct snd_dmaengine_dai_dma_data *dma_data; | 186 | struct snd_dmaengine_dai_dma_data *dma_data; |
49 | int transfer_size; | 187 | int transfer_size; |
50 | 188 | ||
51 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | 189 | if (uni->info->type == SND_ST_UNIPERIF_TYPE_TDM) |
190 | /* transfer size = user frame size (in 32-bits FIFO cell) */ | ||
191 | transfer_size = snd_soc_params_to_frame_size(params) / 32; | ||
192 | else | ||
193 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | ||
52 | 194 | ||
53 | dma_data = snd_soc_dai_get_dma_data(dai, substream); | 195 | dma_data = snd_soc_dai_get_dma_data(dai, substream); |
54 | dma_data->maxburst = transfer_size; | 196 | dma_data->maxburst = transfer_size; |
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f0fd5a9944e9..eb9933c62ad6 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h | |||
@@ -25,7 +25,7 @@ | |||
25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) | 25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) |
26 | 26 | ||
27 | /* | 27 | /* |
28 | * AUD_UNIPERIF_SOFT_RST reg | 28 | * UNIPERIF_SOFT_RST reg |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 | 31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 |
@@ -50,7 +50,7 @@ | |||
50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) | 50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) |
51 | 51 | ||
52 | /* | 52 | /* |
53 | * AUD_UNIPERIF_FIFO_DATA reg | 53 | * UNIPERIF_FIFO_DATA reg |
54 | */ | 54 | */ |
55 | 55 | ||
56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 | 56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 |
@@ -58,7 +58,7 @@ | |||
58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) | 58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) |
59 | 59 | ||
60 | /* | 60 | /* |
61 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 61 | * UNIPERIF_CHANNEL_STA_REGN reg |
62 | */ | 62 | */ |
63 | 63 | ||
64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -105,7 +105,7 @@ | |||
105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) | 105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) |
106 | 106 | ||
107 | /* | 107 | /* |
108 | * AUD_UNIPERIF_ITS reg | 108 | * UNIPERIF_ITS reg |
109 | */ | 109 | */ |
110 | 110 | ||
111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C | 111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C |
@@ -143,7 +143,7 @@ | |||
143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
144 | 144 | ||
145 | /* | 145 | /* |
146 | * AUD_UNIPERIF_ITS_BCLR reg | 146 | * UNIPERIF_ITS_BCLR reg |
147 | */ | 147 | */ |
148 | 148 | ||
149 | /* FIFO_ERROR */ | 149 | /* FIFO_ERROR */ |
@@ -160,7 +160,7 @@ | |||
160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) | 160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) |
161 | 161 | ||
162 | /* | 162 | /* |
163 | * AUD_UNIPERIF_ITM reg | 163 | * UNIPERIF_ITM reg |
164 | */ | 164 | */ |
165 | 165 | ||
166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 | 166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 |
@@ -188,7 +188,7 @@ | |||
188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | 188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) |
189 | 189 | ||
190 | /* | 190 | /* |
191 | * AUD_UNIPERIF_ITM_BCLR reg | 191 | * UNIPERIF_ITM_BCLR reg |
192 | */ | 192 | */ |
193 | 193 | ||
194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c | 194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c |
@@ -213,7 +213,7 @@ | |||
213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) | 213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) |
214 | 214 | ||
215 | /* | 215 | /* |
216 | * AUD_UNIPERIF_ITM_BSET reg | 216 | * UNIPERIF_ITM_BSET reg |
217 | */ | 217 | */ |
218 | 218 | ||
219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 | 219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 |
@@ -767,7 +767,7 @@ | |||
767 | SET_UNIPERIF_REG(ip, \ | 767 | SET_UNIPERIF_REG(ip, \ |
768 | UNIPERIF_CTRL_OFFSET(ip), \ | 768 | UNIPERIF_CTRL_OFFSET(ip), \ |
769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | 769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ |
770 | CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) | 770 | UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) |
771 | 771 | ||
772 | /* UNDERFLOW_REC_WINDOW */ | 772 | /* UNDERFLOW_REC_WINDOW */ |
773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 | 773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 |
@@ -1046,7 +1046,7 @@ | |||
1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) | 1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) |
1047 | 1047 | ||
1048 | /* | 1048 | /* |
1049 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | 1049 | * UNIPERIF_CHANNEL_STA_REGN reg |
1050 | */ | 1050 | */ |
1051 | 1051 | ||
1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | 1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) |
@@ -1057,7 +1057,7 @@ | |||
1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) | 1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) |
1058 | 1058 | ||
1059 | /* | 1059 | /* |
1060 | * AUD_UNIPERIF_USER_VALIDITY reg | 1060 | * UNIPERIF_USER_VALIDITY reg |
1061 | */ | 1061 | */ |
1062 | 1062 | ||
1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 | 1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 |
@@ -1101,12 +1101,136 @@ | |||
1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) | 1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) |
1102 | 1102 | ||
1103 | /* | 1103 | /* |
1104 | * UNIPERIF_TDM_ENABLE | ||
1105 | */ | ||
1106 | #define UNIPERIF_TDM_ENABLE_OFFSET(ip) 0x0118 | ||
1107 | #define GET_UNIPERIF_TDM_ENABLE(ip) \ | ||
1108 | readl_relaxed(ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1109 | #define SET_UNIPERIF_TDM_ENABLE(ip, value) \ | ||
1110 | writel_relaxed(value, ip->base + UNIPERIF_TDM_ENABLE_OFFSET(ip)) | ||
1111 | |||
1112 | /* TDM_ENABLE */ | ||
1113 | #define UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip) 0x0 | ||
1114 | #define UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip) 0x1 | ||
1115 | #define GET_UNIPERIF_TDM_ENABLE_EN_TDM(ip) \ | ||
1116 | GET_UNIPERIF_REG(ip, \ | ||
1117 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1118 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1119 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip)) | ||
1120 | #define SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(ip) \ | ||
1121 | SET_UNIPERIF_REG(ip, \ | ||
1122 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1123 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1124 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 1) | ||
1125 | #define SET_UNIPERIF_TDM_ENABLE_TDM_DISABLE(ip) \ | ||
1126 | SET_UNIPERIF_REG(ip, \ | ||
1127 | UNIPERIF_TDM_ENABLE_OFFSET(ip), \ | ||
1128 | UNIPERIF_TDM_ENABLE_EN_TDM_SHIFT(ip), \ | ||
1129 | UNIPERIF_TDM_ENABLE_EN_TDM_MASK(ip), 0) | ||
1130 | |||
1131 | /* | ||
1132 | * UNIPERIF_TDM_FS_REF_FREQ | ||
1133 | */ | ||
1134 | #define UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip) 0x011c | ||
1135 | #define GET_UNIPERIF_TDM_FS_REF_FREQ(ip) \ | ||
1136 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1137 | #define SET_UNIPERIF_TDM_FS_REF_FREQ(ip, value) \ | ||
1138 | writel_relaxed(value, ip->base + \ | ||
1139 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip)) | ||
1140 | |||
1141 | /* REF_FREQ */ | ||
1142 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip) 0x0 | ||
1143 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) 0 | ||
1144 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) 1 | ||
1145 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) 2 | ||
1146 | #define VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) 3 | ||
1147 | #define UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip) 0x3 | ||
1148 | #define GET_UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ(ip) \ | ||
1149 | GET_UNIPERIF_REG(ip, \ | ||
1150 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1151 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1152 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip)) | ||
1153 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip) \ | ||
1154 | SET_UNIPERIF_REG(ip, \ | ||
1155 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1156 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1157 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1158 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_8KHZ(ip)) | ||
1159 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip) \ | ||
1160 | SET_UNIPERIF_REG(ip, \ | ||
1161 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1162 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1163 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1164 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_16KHZ(ip)) | ||
1165 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip) \ | ||
1166 | SET_UNIPERIF_REG(ip, \ | ||
1167 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1168 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1169 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1170 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_32KHZ(ip)) | ||
1171 | #define SET_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip) \ | ||
1172 | SET_UNIPERIF_REG(ip, \ | ||
1173 | UNIPERIF_TDM_FS_REF_FREQ_OFFSET(ip), \ | ||
1174 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_SHIFT(ip), \ | ||
1175 | UNIPERIF_TDM_FS_REF_FREQ_REF_FREQ_MASK(ip), \ | ||
1176 | VALUE_UNIPERIF_TDM_FS_REF_FREQ_48KHZ(ip)) | ||
1177 | |||
1178 | /* | ||
1179 | * UNIPERIF_TDM_FS_REF_DIV | ||
1180 | */ | ||
1181 | #define UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip) 0x0120 | ||
1182 | #define GET_UNIPERIF_TDM_FS_REF_DIV(ip) \ | ||
1183 | readl_relaxed(ip->base + UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1184 | #define SET_UNIPERIF_TDM_FS_REF_DIV(ip, value) \ | ||
1185 | writel_relaxed(value, ip->base + \ | ||
1186 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip)) | ||
1187 | |||
1188 | /* NUM_TIMESLOT */ | ||
1189 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip) 0x0 | ||
1190 | #define UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip) 0xff | ||
1191 | #define GET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip) \ | ||
1192 | GET_UNIPERIF_REG(ip, \ | ||
1193 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1194 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1195 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip)) | ||
1196 | #define SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(ip, value) \ | ||
1197 | SET_UNIPERIF_REG(ip, \ | ||
1198 | UNIPERIF_TDM_FS_REF_DIV_OFFSET(ip), \ | ||
1199 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_SHIFT(ip), \ | ||
1200 | UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT_MASK(ip), value) | ||
1201 | |||
1202 | /* | ||
1203 | * UNIPERIF_TDM_WORD_POS_X_Y | ||
1204 | * 32 bits of UNIPERIF_TDM_WORD_POS_X_Y register shall be set in 1 shot | ||
1205 | */ | ||
1206 | #define UNIPERIF_TDM_WORD_POS_1_2_OFFSET(ip) 0x013c | ||
1207 | #define UNIPERIF_TDM_WORD_POS_3_4_OFFSET(ip) 0x0140 | ||
1208 | #define UNIPERIF_TDM_WORD_POS_5_6_OFFSET(ip) 0x0144 | ||
1209 | #define UNIPERIF_TDM_WORD_POS_7_8_OFFSET(ip) 0x0148 | ||
1210 | #define GET_UNIPERIF_TDM_WORD_POS(ip, words) \ | ||
1211 | readl_relaxed(ip->base + UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1212 | #define SET_UNIPERIF_TDM_WORD_POS(ip, words, value) \ | ||
1213 | writel_relaxed(value, ip->base + \ | ||
1214 | UNIPERIF_TDM_WORD_POS_##words##_OFFSET(ip)) | ||
1215 | /* | ||
1104 | * uniperipheral IP capabilities | 1216 | * uniperipheral IP capabilities |
1105 | */ | 1217 | */ |
1106 | 1218 | ||
1107 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ | 1219 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ |
1108 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ | 1220 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ |
1109 | 1221 | ||
1222 | #define UNIPERIF_TYPE_IS_HDMI(p) \ | ||
1223 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_HDMI) | ||
1224 | #define UNIPERIF_TYPE_IS_PCM(p) \ | ||
1225 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_PCM) | ||
1226 | #define UNIPERIF_TYPE_IS_SPDIF(p) \ | ||
1227 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_SPDIF) | ||
1228 | #define UNIPERIF_TYPE_IS_IEC958(p) \ | ||
1229 | (UNIPERIF_TYPE_IS_HDMI(p) || \ | ||
1230 | UNIPERIF_TYPE_IS_SPDIF(p)) | ||
1231 | #define UNIPERIF_TYPE_IS_TDM(p) \ | ||
1232 | ((p)->info->type == SND_ST_UNIPERIF_TYPE_TDM) | ||
1233 | |||
1110 | /* | 1234 | /* |
1111 | * Uniperipheral IP revisions | 1235 | * Uniperipheral IP revisions |
1112 | */ | 1236 | */ |
@@ -1125,10 +1249,11 @@ enum uniperif_version { | |||
1125 | }; | 1249 | }; |
1126 | 1250 | ||
1127 | enum uniperif_type { | 1251 | enum uniperif_type { |
1128 | SND_ST_UNIPERIF_PLAYER_TYPE_NONE, | 1252 | SND_ST_UNIPERIF_TYPE_NONE, |
1129 | SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, | 1253 | SND_ST_UNIPERIF_TYPE_HDMI, |
1130 | SND_ST_UNIPERIF_PLAYER_TYPE_PCM, | 1254 | SND_ST_UNIPERIF_TYPE_PCM, |
1131 | SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF | 1255 | SND_ST_UNIPERIF_TYPE_SPDIF, |
1256 | SND_ST_UNIPERIF_TYPE_TDM | ||
1132 | }; | 1257 | }; |
1133 | 1258 | ||
1134 | enum uniperif_state { | 1259 | enum uniperif_state { |
@@ -1145,9 +1270,17 @@ enum uniperif_iec958_encoding_mode { | |||
1145 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED | 1270 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED |
1146 | }; | 1271 | }; |
1147 | 1272 | ||
1273 | enum uniperif_word_pos { | ||
1274 | WORD_1_2, | ||
1275 | WORD_3_4, | ||
1276 | WORD_5_6, | ||
1277 | WORD_7_8, | ||
1278 | WORD_MAX | ||
1279 | }; | ||
1280 | |||
1148 | struct uniperif_info { | 1281 | struct uniperif_info { |
1149 | int id; /* instance value of the uniperipheral IP */ | 1282 | int id; /* instance value of the uniperipheral IP */ |
1150 | enum uniperif_type player_type; | 1283 | enum uniperif_type type; |
1151 | int underflow_enabled; /* Underflow recovery mode */ | 1284 | int underflow_enabled; /* Underflow recovery mode */ |
1152 | }; | 1285 | }; |
1153 | 1286 | ||
@@ -1156,12 +1289,20 @@ struct uniperif_iec958_settings { | |||
1156 | struct snd_aes_iec958 iec958; | 1289 | struct snd_aes_iec958 iec958; |
1157 | }; | 1290 | }; |
1158 | 1291 | ||
1292 | struct dai_tdm_slot { | ||
1293 | unsigned int mask; | ||
1294 | int slots; | ||
1295 | int slot_width; | ||
1296 | unsigned int avail_slots; | ||
1297 | }; | ||
1298 | |||
1159 | struct uniperif { | 1299 | struct uniperif { |
1160 | /* System information */ | 1300 | /* System information */ |
1161 | struct uniperif_info *info; | 1301 | struct uniperif_info *info; |
1162 | struct device *dev; | 1302 | struct device *dev; |
1163 | int ver; /* IP version, used by register access macros */ | 1303 | int ver; /* IP version, used by register access macros */ |
1164 | struct regmap_field *clk_sel; | 1304 | struct regmap_field *clk_sel; |
1305 | struct regmap_field *valid_sel; | ||
1165 | 1306 | ||
1166 | /* capabilities */ | 1307 | /* capabilities */ |
1167 | const struct snd_pcm_hardware *hw; | 1308 | const struct snd_pcm_hardware *hw; |
@@ -1192,6 +1333,7 @@ struct uniperif { | |||
1192 | 1333 | ||
1193 | /* dai properties */ | 1334 | /* dai properties */ |
1194 | unsigned int daifmt; | 1335 | unsigned int daifmt; |
1336 | struct dai_tdm_slot tdm_slot; | ||
1195 | 1337 | ||
1196 | /* DAI callbacks */ | 1338 | /* DAI callbacks */ |
1197 | const struct snd_soc_dai_ops *dai_ops; | 1339 | const struct snd_soc_dai_ops *dai_ops; |
@@ -1209,6 +1351,28 @@ struct sti_uniperiph_data { | |||
1209 | struct sti_uniperiph_dai dai_data; | 1351 | struct sti_uniperiph_dai dai_data; |
1210 | }; | 1352 | }; |
1211 | 1353 | ||
1354 | static const struct snd_pcm_hardware uni_tdm_hw = { | ||
1355 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
1356 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | | ||
1357 | SNDRV_PCM_INFO_MMAP_VALID, | ||
1358 | |||
1359 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
1360 | |||
1361 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
1362 | .rate_min = 8000, | ||
1363 | .rate_max = 48000, | ||
1364 | |||
1365 | .channels_min = 1, | ||
1366 | .channels_max = 32, | ||
1367 | |||
1368 | .periods_min = 2, | ||
1369 | .periods_max = 10, | ||
1370 | |||
1371 | .period_bytes_min = 128, | ||
1372 | .period_bytes_max = 64 * PAGE_SIZE, | ||
1373 | .buffer_bytes_max = 256 * PAGE_SIZE | ||
1374 | }; | ||
1375 | |||
1212 | /* uniperiph player*/ | 1376 | /* uniperiph player*/ |
1213 | int uni_player_init(struct platform_device *pdev, | 1377 | int uni_player_init(struct platform_device *pdev, |
1214 | struct uniperif *uni_player); | 1378 | struct uniperif *uni_player); |
@@ -1226,4 +1390,28 @@ int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | |||
1226 | struct snd_pcm_hw_params *params, | 1390 | struct snd_pcm_hw_params *params, |
1227 | struct snd_soc_dai *dai); | 1391 | struct snd_soc_dai *dai); |
1228 | 1392 | ||
1393 | static inline int sti_uniperiph_get_user_frame_size( | ||
1394 | struct snd_pcm_runtime *runtime) | ||
1395 | { | ||
1396 | return (runtime->channels * snd_pcm_format_width(runtime->format) / 8); | ||
1397 | } | ||
1398 | |||
1399 | static inline int sti_uniperiph_get_unip_tdm_frame_size(struct uniperif *uni) | ||
1400 | { | ||
1401 | return (uni->tdm_slot.slots * uni->tdm_slot.slot_width / 8); | ||
1402 | } | ||
1403 | |||
1404 | int sti_uniperiph_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
1405 | unsigned int rx_mask, int slots, | ||
1406 | int slot_width); | ||
1407 | |||
1408 | int sti_uniperiph_get_tdm_word_pos(struct uniperif *uni, | ||
1409 | unsigned int *word_pos); | ||
1410 | |||
1411 | int sti_uniperiph_fix_tdm_chan(struct snd_pcm_hw_params *params, | ||
1412 | struct snd_pcm_hw_rule *rule); | ||
1413 | |||
1414 | int sti_uniperiph_fix_tdm_format(struct snd_pcm_hw_params *params, | ||
1415 | struct snd_pcm_hw_rule *rule); | ||
1416 | |||
1229 | #endif | 1417 | #endif |
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index 7aca6b92f718..ee1c7c245bc7 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -21,23 +21,14 @@ | |||
21 | 21 | ||
22 | /* sys config registers definitions */ | 22 | /* sys config registers definitions */ |
23 | #define SYS_CFG_AUDIO_GLUE 0xA4 | 23 | #define SYS_CFG_AUDIO_GLUE 0xA4 |
24 | #define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 | ||
25 | 24 | ||
26 | /* | 25 | /* |
27 | * Driver specific types. | 26 | * Driver specific types. |
28 | */ | 27 | */ |
29 | #define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ | ||
30 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) | ||
31 | #define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ | ||
32 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) | ||
33 | #define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ | ||
34 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) | ||
35 | #define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ | ||
36 | (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ | ||
37 | UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) | ||
38 | 28 | ||
39 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 | 29 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 |
40 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 | 30 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 |
31 | #define UNIPERIF_PLAYER_I2S_OUT 1 /* player id connected to I2S/TDM TX bus */ | ||
41 | 32 | ||
42 | /* | 33 | /* |
43 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to | 34 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to |
@@ -444,18 +435,11 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
444 | 435 | ||
445 | /* Force slot width to 32 in I2S mode (HW constraint) */ | 436 | /* Force slot width to 32 in I2S mode (HW constraint) */ |
446 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == | 437 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == |
447 | SND_SOC_DAIFMT_I2S) { | 438 | SND_SOC_DAIFMT_I2S) |
448 | slot_width = 32; | 439 | slot_width = 32; |
449 | } else { | 440 | else |
450 | switch (runtime->format) { | 441 | slot_width = snd_pcm_format_width(runtime->format); |
451 | case SNDRV_PCM_FORMAT_S16_LE: | 442 | |
452 | slot_width = 16; | ||
453 | break; | ||
454 | default: | ||
455 | slot_width = 32; | ||
456 | break; | ||
457 | } | ||
458 | } | ||
459 | output_frame_size = slot_width * runtime->channels; | 443 | output_frame_size = slot_width * runtime->channels; |
460 | 444 | ||
461 | clk_div = player->mclk / runtime->rate; | 445 | clk_div = player->mclk / runtime->rate; |
@@ -530,7 +514,6 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
530 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); | 514 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); |
531 | 515 | ||
532 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | 516 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); |
533 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
534 | 517 | ||
535 | /* No iec958 formatting as outputting to DAC */ | 518 | /* No iec958 formatting as outputting to DAC */ |
536 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); | 519 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); |
@@ -538,6 +521,55 @@ static int uni_player_prepare_pcm(struct uniperif *player, | |||
538 | return 0; | 521 | return 0; |
539 | } | 522 | } |
540 | 523 | ||
524 | static int uni_player_prepare_tdm(struct uniperif *player, | ||
525 | struct snd_pcm_runtime *runtime) | ||
526 | { | ||
527 | int tdm_frame_size; /* unip tdm frame size in bytes */ | ||
528 | int user_frame_size; /* user tdm frame size in bytes */ | ||
529 | /* default unip TDM_WORD_POS_X_Y */ | ||
530 | unsigned int word_pos[4] = { | ||
531 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
532 | int freq, ret; | ||
533 | |||
534 | tdm_frame_size = | ||
535 | sti_uniperiph_get_unip_tdm_frame_size(player); | ||
536 | user_frame_size = | ||
537 | sti_uniperiph_get_user_frame_size(runtime); | ||
538 | |||
539 | /* fix 16/0 format */ | ||
540 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); | ||
541 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); | ||
542 | |||
543 | /* number of words inserted on the TDM line */ | ||
544 | SET_UNIPERIF_I2S_FMT_NUM_CH(player, user_frame_size / 4 / 2); | ||
545 | |||
546 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | ||
547 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); | ||
548 | |||
549 | /* Enable the tdm functionality */ | ||
550 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(player); | ||
551 | |||
552 | /* number of 8 bits timeslots avail in unip tdm frame */ | ||
553 | SET_UNIPERIF_TDM_FS_REF_DIV_NUM_TIMESLOT(player, tdm_frame_size); | ||
554 | |||
555 | /* set the timeslot allocation for words in FIFO */ | ||
556 | sti_uniperiph_get_tdm_word_pos(player, word_pos); | ||
557 | SET_UNIPERIF_TDM_WORD_POS(player, 1_2, word_pos[WORD_1_2]); | ||
558 | SET_UNIPERIF_TDM_WORD_POS(player, 3_4, word_pos[WORD_3_4]); | ||
559 | SET_UNIPERIF_TDM_WORD_POS(player, 5_6, word_pos[WORD_5_6]); | ||
560 | SET_UNIPERIF_TDM_WORD_POS(player, 7_8, word_pos[WORD_7_8]); | ||
561 | |||
562 | /* set unip clk rate (not done vai set_sysclk ops) */ | ||
563 | freq = runtime->rate * tdm_frame_size * 8; | ||
564 | mutex_lock(&player->ctrl_lock); | ||
565 | ret = uni_player_clk_set_rate(player, freq); | ||
566 | if (!ret) | ||
567 | player->mclk = freq; | ||
568 | mutex_unlock(&player->ctrl_lock); | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
541 | /* | 573 | /* |
542 | * ALSA uniperipheral iec958 controls | 574 | * ALSA uniperipheral iec958 controls |
543 | */ | 575 | */ |
@@ -668,11 +700,29 @@ static int uni_player_startup(struct snd_pcm_substream *substream, | |||
668 | { | 700 | { |
669 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | 701 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); |
670 | struct uniperif *player = priv->dai_data.uni; | 702 | struct uniperif *player = priv->dai_data.uni; |
703 | int ret; | ||
704 | |||
671 | player->substream = substream; | 705 | player->substream = substream; |
672 | 706 | ||
673 | player->clk_adj = 0; | 707 | player->clk_adj = 0; |
674 | 708 | ||
675 | return 0; | 709 | if (!UNIPERIF_TYPE_IS_TDM(player)) |
710 | return 0; | ||
711 | |||
712 | /* refine hw constraint in tdm mode */ | ||
713 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
714 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
715 | sti_uniperiph_fix_tdm_chan, | ||
716 | player, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
717 | -1); | ||
718 | if (ret < 0) | ||
719 | return ret; | ||
720 | |||
721 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
722 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
723 | sti_uniperiph_fix_tdm_format, | ||
724 | player, SNDRV_PCM_HW_PARAM_FORMAT, | ||
725 | -1); | ||
676 | } | 726 | } |
677 | 727 | ||
678 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 728 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
@@ -682,7 +732,7 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
682 | struct uniperif *player = priv->dai_data.uni; | 732 | struct uniperif *player = priv->dai_data.uni; |
683 | int ret; | 733 | int ret; |
684 | 734 | ||
685 | if (dir == SND_SOC_CLOCK_IN) | 735 | if (UNIPERIF_TYPE_IS_TDM(player) || (dir == SND_SOC_CLOCK_IN)) |
686 | return 0; | 736 | return 0; |
687 | 737 | ||
688 | if (clk_id != 0) | 738 | if (clk_id != 0) |
@@ -714,7 +764,13 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
714 | } | 764 | } |
715 | 765 | ||
716 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | 766 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ |
717 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | 767 | if (player->info->type == SND_ST_UNIPERIF_TYPE_TDM) { |
768 | /* transfer size = user frame size (in 32 bits FIFO cell) */ | ||
769 | transfer_size = | ||
770 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
771 | } else { | ||
772 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
773 | } | ||
718 | 774 | ||
719 | /* Calculate number of empty cells available before asserting DREQ */ | 775 | /* Calculate number of empty cells available before asserting DREQ */ |
720 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { | 776 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { |
@@ -738,16 +794,19 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, | |||
738 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); | 794 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); |
739 | 795 | ||
740 | /* Uniperipheral setup depends on player type */ | 796 | /* Uniperipheral setup depends on player type */ |
741 | switch (player->info->player_type) { | 797 | switch (player->info->type) { |
742 | case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: | 798 | case SND_ST_UNIPERIF_TYPE_HDMI: |
743 | ret = uni_player_prepare_iec958(player, runtime); | 799 | ret = uni_player_prepare_iec958(player, runtime); |
744 | break; | 800 | break; |
745 | case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: | 801 | case SND_ST_UNIPERIF_TYPE_PCM: |
746 | ret = uni_player_prepare_pcm(player, runtime); | 802 | ret = uni_player_prepare_pcm(player, runtime); |
747 | break; | 803 | break; |
748 | case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: | 804 | case SND_ST_UNIPERIF_TYPE_SPDIF: |
749 | ret = uni_player_prepare_iec958(player, runtime); | 805 | ret = uni_player_prepare_iec958(player, runtime); |
750 | break; | 806 | break; |
807 | case SND_ST_UNIPERIF_TYPE_TDM: | ||
808 | ret = uni_player_prepare_tdm(player, runtime); | ||
809 | break; | ||
751 | default: | 810 | default: |
752 | dev_err(player->dev, "invalid player type"); | 811 | dev_err(player->dev, "invalid player type"); |
753 | return -EINVAL; | 812 | return -EINVAL; |
@@ -852,8 +911,8 @@ static int uni_player_start(struct uniperif *player) | |||
852 | * will not take affect and hang the player. | 911 | * will not take affect and hang the player. |
853 | */ | 912 | */ |
854 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 913 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
855 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) | 914 | if (UNIPERIF_TYPE_IS_IEC958(player)) |
856 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); | 915 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); |
857 | 916 | ||
858 | /* Force channel status update (no update if clk disable) */ | 917 | /* Force channel status update (no update if clk disable) */ |
859 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | 918 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) |
@@ -954,27 +1013,30 @@ static void uni_player_shutdown(struct snd_pcm_substream *substream, | |||
954 | player->substream = NULL; | 1013 | player->substream = NULL; |
955 | } | 1014 | } |
956 | 1015 | ||
957 | static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, | 1016 | static int uni_player_parse_dt_audio_glue(struct platform_device *pdev, |
958 | struct uniperif *player) | 1017 | struct uniperif *player) |
959 | { | 1018 | { |
960 | int bit_offset; | ||
961 | struct device_node *node = pdev->dev.of_node; | 1019 | struct device_node *node = pdev->dev.of_node; |
962 | struct regmap *regmap; | 1020 | struct regmap *regmap; |
963 | 1021 | struct reg_field regfield[2] = { | |
964 | bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; | 1022 | /* PCM_CLK_SEL */ |
1023 | REG_FIELD(SYS_CFG_AUDIO_GLUE, | ||
1024 | 8 + player->info->id, | ||
1025 | 8 + player->info->id), | ||
1026 | /* PCMP_VALID_SEL */ | ||
1027 | REG_FIELD(SYS_CFG_AUDIO_GLUE, 0, 1) | ||
1028 | }; | ||
965 | 1029 | ||
966 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); | 1030 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); |
967 | 1031 | ||
968 | if (regmap) { | 1032 | if (!regmap) { |
969 | struct reg_field regfield = | ||
970 | REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); | ||
971 | |||
972 | player->clk_sel = regmap_field_alloc(regmap, regfield); | ||
973 | } else { | ||
974 | 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"); |
975 | return -EINVAL; | 1034 | return -EINVAL; |
976 | } | 1035 | } |
977 | 1036 | ||
1037 | player->clk_sel = regmap_field_alloc(regmap, regfield[0]); | ||
1038 | player->valid_sel = regmap_field_alloc(regmap, regfield[1]); | ||
1039 | |||
978 | return 0; | 1040 | return 0; |
979 | } | 1041 | } |
980 | 1042 | ||
@@ -1012,19 +1074,21 @@ static int uni_player_parse_dt(struct platform_device *pdev, | |||
1012 | } | 1074 | } |
1013 | 1075 | ||
1014 | if (strcasecmp(mode, "hdmi") == 0) | 1076 | if (strcasecmp(mode, "hdmi") == 0) |
1015 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; | 1077 | info->type = SND_ST_UNIPERIF_TYPE_HDMI; |
1016 | else if (strcasecmp(mode, "pcm") == 0) | 1078 | else if (strcasecmp(mode, "pcm") == 0) |
1017 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; | 1079 | info->type = SND_ST_UNIPERIF_TYPE_PCM; |
1018 | else if (strcasecmp(mode, "spdif") == 0) | 1080 | else if (strcasecmp(mode, "spdif") == 0) |
1019 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; | 1081 | info->type = SND_ST_UNIPERIF_TYPE_SPDIF; |
1082 | else if (strcasecmp(mode, "tdm") == 0) | ||
1083 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
1020 | else | 1084 | else |
1021 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; | 1085 | info->type = SND_ST_UNIPERIF_TYPE_NONE; |
1022 | 1086 | ||
1023 | /* Save the info structure */ | 1087 | /* Save the info structure */ |
1024 | player->info = info; | 1088 | player->info = info; |
1025 | 1089 | ||
1026 | /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ | 1090 | /* Get PCM_CLK_SEL & PCMP_VALID_SEL from audio-glue-ctrl SoC reg */ |
1027 | if (uni_player_parse_dt_clk_glue(pdev, player)) | 1091 | if (uni_player_parse_dt_audio_glue(pdev, player)) |
1028 | return -EINVAL; | 1092 | return -EINVAL; |
1029 | 1093 | ||
1030 | return 0; | 1094 | return 0; |
@@ -1037,7 +1101,8 @@ static const struct snd_soc_dai_ops uni_player_dai_ops = { | |||
1037 | .trigger = uni_player_trigger, | 1101 | .trigger = uni_player_trigger, |
1038 | .hw_params = sti_uniperiph_dai_hw_params, | 1102 | .hw_params = sti_uniperiph_dai_hw_params, |
1039 | .set_fmt = sti_uniperiph_dai_set_fmt, | 1103 | .set_fmt = sti_uniperiph_dai_set_fmt, |
1040 | .set_sysclk = uni_player_set_sysclk | 1104 | .set_sysclk = uni_player_set_sysclk, |
1105 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
1041 | }; | 1106 | }; |
1042 | 1107 | ||
1043 | int uni_player_init(struct platform_device *pdev, | 1108 | int uni_player_init(struct platform_device *pdev, |
@@ -1047,7 +1112,6 @@ int uni_player_init(struct platform_device *pdev, | |||
1047 | 1112 | ||
1048 | player->dev = &pdev->dev; | 1113 | player->dev = &pdev->dev; |
1049 | player->state = UNIPERIF_STATE_STOPPED; | 1114 | player->state = UNIPERIF_STATE_STOPPED; |
1050 | player->hw = &uni_player_pcm_hw; | ||
1051 | player->dai_ops = &uni_player_dai_ops; | 1115 | player->dai_ops = &uni_player_dai_ops; |
1052 | 1116 | ||
1053 | ret = uni_player_parse_dt(pdev, player); | 1117 | ret = uni_player_parse_dt(pdev, player); |
@@ -1057,6 +1121,11 @@ int uni_player_init(struct platform_device *pdev, | |||
1057 | return ret; | 1121 | return ret; |
1058 | } | 1122 | } |
1059 | 1123 | ||
1124 | if (UNIPERIF_TYPE_IS_TDM(player)) | ||
1125 | player->hw = &uni_tdm_hw; | ||
1126 | else | ||
1127 | player->hw = &uni_player_pcm_hw; | ||
1128 | |||
1060 | /* Get uniperif resource */ | 1129 | /* Get uniperif resource */ |
1061 | player->clk = of_clk_get(pdev->dev.of_node, 0); | 1130 | player->clk = of_clk_get(pdev->dev.of_node, 0); |
1062 | if (IS_ERR(player->clk)) | 1131 | if (IS_ERR(player->clk)) |
@@ -1073,6 +1142,17 @@ int uni_player_init(struct platform_device *pdev, | |||
1073 | } | 1142 | } |
1074 | } | 1143 | } |
1075 | 1144 | ||
1145 | /* connect to I2S/TDM TX bus */ | ||
1146 | if (player->valid_sel && | ||
1147 | (player->info->id == UNIPERIF_PLAYER_I2S_OUT)) { | ||
1148 | ret = regmap_field_write(player->valid_sel, player->info->id); | ||
1149 | if (ret) { | ||
1150 | dev_err(player->dev, | ||
1151 | "%s: unable to connect to tdm bus", __func__); | ||
1152 | return ret; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1076 | ret = devm_request_irq(&pdev->dev, player->irq, | 1156 | ret = devm_request_irq(&pdev->dev, player->irq, |
1077 | uni_player_irq_handler, IRQF_SHARED, | 1157 | uni_player_irq_handler, IRQF_SHARED, |
1078 | dev_name(&pdev->dev), player); | 1158 | dev_name(&pdev->dev), player); |
@@ -1087,7 +1167,7 @@ int uni_player_init(struct platform_device *pdev, | |||
1087 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | 1167 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); |
1088 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); | 1168 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); |
1089 | 1169 | ||
1090 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { | 1170 | if (UNIPERIF_TYPE_IS_IEC958(player)) { |
1091 | /* Set default iec958 status bits */ | 1171 | /* Set default iec958 status bits */ |
1092 | 1172 | ||
1093 | /* Consumer, PCM, copyright, 2ch, mode 0 */ | 1173 | /* Consumer, PCM, copyright, 2ch, mode 0 */ |
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 8a0eb2050169..eb74a328c928 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c | |||
@@ -73,55 +73,10 @@ static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | |||
73 | return ret; | 73 | return ret; |
74 | } | 74 | } |
75 | 75 | ||
76 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | 76 | static int uni_reader_prepare_pcm(struct snd_pcm_runtime *runtime, |
77 | struct snd_soc_dai *dai) | 77 | struct uniperif *reader) |
78 | { | 78 | { |
79 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
80 | struct uniperif *reader = priv->dai_data.uni; | ||
81 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
82 | int transfer_size, trigger_limit; | ||
83 | int slot_width; | 79 | int slot_width; |
84 | int count = 10; | ||
85 | |||
86 | /* The reader should be stopped */ | ||
87 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
88 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
89 | reader->state); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
94 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
95 | |||
96 | /* Calculate number of empty cells available before asserting DREQ */ | ||
97 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
98 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
99 | else | ||
100 | /* | ||
101 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
102 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
103 | * from OFF or STANDBY to AUDIO DATA. | ||
104 | */ | ||
105 | trigger_limit = transfer_size; | ||
106 | |||
107 | /* Trigger limit must be an even number */ | ||
108 | if ((!trigger_limit % 2) || | ||
109 | (trigger_limit != 1 && transfer_size % 2) || | ||
110 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
111 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
116 | |||
117 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | ||
118 | case SND_SOC_DAIFMT_IB_IF: | ||
119 | case SND_SOC_DAIFMT_NB_IF: | ||
120 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
121 | break; | ||
122 | default: | ||
123 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
124 | } | ||
125 | 80 | ||
126 | /* Force slot width to 32 in I2S mode */ | 81 | /* Force slot width to 32 in I2S mode */ |
127 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) | 82 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) |
@@ -173,6 +128,109 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
173 | return -EINVAL; | 128 | return -EINVAL; |
174 | } | 129 | } |
175 | 130 | ||
131 | /* Number of channels must be even */ | ||
132 | if ((runtime->channels % 2) || (runtime->channels < 2) || | ||
133 | (runtime->channels > 10)) { | ||
134 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
139 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int uni_reader_prepare_tdm(struct snd_pcm_runtime *runtime, | ||
145 | struct uniperif *reader) | ||
146 | { | ||
147 | int frame_size; /* user tdm frame size in bytes */ | ||
148 | /* default unip TDM_WORD_POS_X_Y */ | ||
149 | unsigned int word_pos[4] = { | ||
150 | 0x04060002, 0x0C0E080A, 0x14161012, 0x1C1E181A}; | ||
151 | |||
152 | frame_size = sti_uniperiph_get_user_frame_size(runtime); | ||
153 | |||
154 | /* fix 16/0 format */ | ||
155 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); | ||
156 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); | ||
157 | |||
158 | /* number of words inserted on the TDM line */ | ||
159 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, frame_size / 4 / 2); | ||
160 | |||
161 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
162 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | ||
163 | SET_UNIPERIF_TDM_ENABLE_TDM_ENABLE(reader); | ||
164 | |||
165 | /* | ||
166 | * set the timeslots allocation for words in FIFO | ||
167 | * | ||
168 | * HW bug: (LSB word < MSB word) => this config is not possible | ||
169 | * So if we want (LSB word < MSB) word, then it shall be | ||
170 | * handled by user | ||
171 | */ | ||
172 | sti_uniperiph_get_tdm_word_pos(reader, word_pos); | ||
173 | SET_UNIPERIF_TDM_WORD_POS(reader, 1_2, word_pos[WORD_1_2]); | ||
174 | SET_UNIPERIF_TDM_WORD_POS(reader, 3_4, word_pos[WORD_3_4]); | ||
175 | SET_UNIPERIF_TDM_WORD_POS(reader, 5_6, word_pos[WORD_5_6]); | ||
176 | SET_UNIPERIF_TDM_WORD_POS(reader, 7_8, word_pos[WORD_7_8]); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | ||
182 | struct snd_soc_dai *dai) | ||
183 | { | ||
184 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
185 | struct uniperif *reader = priv->dai_data.uni; | ||
186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
187 | int transfer_size, trigger_limit, ret; | ||
188 | int count = 10; | ||
189 | |||
190 | /* The reader should be stopped */ | ||
191 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
192 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
193 | reader->state); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
198 | if (reader->info->type == SND_ST_UNIPERIF_TYPE_TDM) { | ||
199 | /* transfer size = unip frame size (in 32 bits FIFO cell) */ | ||
200 | transfer_size = | ||
201 | sti_uniperiph_get_user_frame_size(runtime) / 4; | ||
202 | } else { | ||
203 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
204 | } | ||
205 | |||
206 | /* Calculate number of empty cells available before asserting DREQ */ | ||
207 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
208 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
209 | else | ||
210 | /* | ||
211 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
212 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
213 | * from OFF or STANDBY to AUDIO DATA. | ||
214 | */ | ||
215 | trigger_limit = transfer_size; | ||
216 | |||
217 | /* Trigger limit must be an even number */ | ||
218 | if ((!trigger_limit % 2) || | ||
219 | (trigger_limit != 1 && transfer_size % 2) || | ||
220 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
221 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
222 | return -EINVAL; | ||
223 | } | ||
224 | |||
225 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
226 | |||
227 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
228 | ret = uni_reader_prepare_tdm(runtime, reader); | ||
229 | else | ||
230 | ret = uni_reader_prepare_pcm(runtime, reader); | ||
231 | if (ret) | ||
232 | return ret; | ||
233 | |||
176 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 234 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
177 | case SND_SOC_DAIFMT_I2S: | 235 | case SND_SOC_DAIFMT_I2S: |
178 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | 236 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); |
@@ -191,21 +249,26 @@ static int uni_reader_prepare(struct snd_pcm_substream *substream, | |||
191 | return -EINVAL; | 249 | return -EINVAL; |
192 | } | 250 | } |
193 | 251 | ||
194 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | 252 | /* Data clocking (changing) on the rising/falling edge */ |
195 | 253 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | |
196 | /* Data clocking (changing) on the rising edge */ | 254 | case SND_SOC_DAIFMT_NB_NF: |
197 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | 255 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); |
198 | 256 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | |
199 | /* Number of channels must be even */ | 257 | break; |
200 | 258 | case SND_SOC_DAIFMT_NB_IF: | |
201 | if ((runtime->channels % 2) || (runtime->channels < 2) || | 259 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); |
202 | (runtime->channels > 10)) { | 260 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); |
203 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | 261 | break; |
204 | return -EINVAL; | 262 | case SND_SOC_DAIFMT_IB_NF: |
263 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
264 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_IB_IF: | ||
267 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
268 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(reader); | ||
269 | break; | ||
205 | } | 270 | } |
206 | 271 | ||
207 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
208 | |||
209 | /* Clear any pending interrupts */ | 272 | /* Clear any pending interrupts */ |
210 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); | 273 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); |
211 | 274 | ||
@@ -293,6 +356,32 @@ static int uni_reader_trigger(struct snd_pcm_substream *substream, | |||
293 | } | 356 | } |
294 | } | 357 | } |
295 | 358 | ||
359 | static int uni_reader_startup(struct snd_pcm_substream *substream, | ||
360 | struct snd_soc_dai *dai) | ||
361 | { | ||
362 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
363 | struct uniperif *reader = priv->dai_data.uni; | ||
364 | int ret; | ||
365 | |||
366 | if (!UNIPERIF_TYPE_IS_TDM(reader)) | ||
367 | return 0; | ||
368 | |||
369 | /* refine hw constraint in tdm mode */ | ||
370 | ret = snd_pcm_hw_rule_add(substream->runtime, 0, | ||
371 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
372 | sti_uniperiph_fix_tdm_chan, | ||
373 | reader, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
374 | -1); | ||
375 | if (ret < 0) | ||
376 | return ret; | ||
377 | |||
378 | return snd_pcm_hw_rule_add(substream->runtime, 0, | ||
379 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
380 | sti_uniperiph_fix_tdm_format, | ||
381 | reader, SNDRV_PCM_HW_PARAM_FORMAT, | ||
382 | -1); | ||
383 | } | ||
384 | |||
296 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, | 385 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, |
297 | struct snd_soc_dai *dai) | 386 | struct snd_soc_dai *dai) |
298 | { | 387 | { |
@@ -310,6 +399,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
310 | { | 399 | { |
311 | struct uniperif_info *info; | 400 | struct uniperif_info *info; |
312 | struct device_node *node = pdev->dev.of_node; | 401 | struct device_node *node = pdev->dev.of_node; |
402 | const char *mode; | ||
313 | 403 | ||
314 | /* Allocate memory for the info structure */ | 404 | /* Allocate memory for the info structure */ |
315 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | 405 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); |
@@ -322,6 +412,17 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
322 | return -EINVAL; | 412 | return -EINVAL; |
323 | } | 413 | } |
324 | 414 | ||
415 | /* Read the device mode property */ | ||
416 | if (of_property_read_string(node, "st,mode", &mode)) { | ||
417 | dev_err(&pdev->dev, "uniperipheral mode not defined"); | ||
418 | return -EINVAL; | ||
419 | } | ||
420 | |||
421 | if (strcasecmp(mode, "tdm") == 0) | ||
422 | info->type = SND_ST_UNIPERIF_TYPE_TDM; | ||
423 | else | ||
424 | info->type = SND_ST_UNIPERIF_TYPE_PCM; | ||
425 | |||
325 | /* Save the info structure */ | 426 | /* Save the info structure */ |
326 | reader->info = info; | 427 | reader->info = info; |
327 | 428 | ||
@@ -329,11 +430,13 @@ static int uni_reader_parse_dt(struct platform_device *pdev, | |||
329 | } | 430 | } |
330 | 431 | ||
331 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { | 432 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { |
433 | .startup = uni_reader_startup, | ||
332 | .shutdown = uni_reader_shutdown, | 434 | .shutdown = uni_reader_shutdown, |
333 | .prepare = uni_reader_prepare, | 435 | .prepare = uni_reader_prepare, |
334 | .trigger = uni_reader_trigger, | 436 | .trigger = uni_reader_trigger, |
335 | .hw_params = sti_uniperiph_dai_hw_params, | 437 | .hw_params = sti_uniperiph_dai_hw_params, |
336 | .set_fmt = sti_uniperiph_dai_set_fmt, | 438 | .set_fmt = sti_uniperiph_dai_set_fmt, |
439 | .set_tdm_slot = sti_uniperiph_set_tdm_slot | ||
337 | }; | 440 | }; |
338 | 441 | ||
339 | int uni_reader_init(struct platform_device *pdev, | 442 | int uni_reader_init(struct platform_device *pdev, |
@@ -343,7 +446,6 @@ int uni_reader_init(struct platform_device *pdev, | |||
343 | 446 | ||
344 | reader->dev = &pdev->dev; | 447 | reader->dev = &pdev->dev; |
345 | reader->state = UNIPERIF_STATE_STOPPED; | 448 | reader->state = UNIPERIF_STATE_STOPPED; |
346 | reader->hw = &uni_reader_pcm_hw; | ||
347 | reader->dai_ops = &uni_reader_dai_ops; | 449 | reader->dai_ops = &uni_reader_dai_ops; |
348 | 450 | ||
349 | ret = uni_reader_parse_dt(pdev, reader); | 451 | ret = uni_reader_parse_dt(pdev, reader); |
@@ -352,6 +454,11 @@ int uni_reader_init(struct platform_device *pdev, | |||
352 | return ret; | 454 | return ret; |
353 | } | 455 | } |
354 | 456 | ||
457 | if (UNIPERIF_TYPE_IS_TDM(reader)) | ||
458 | reader->hw = &uni_tdm_hw; | ||
459 | else | ||
460 | reader->hw = &uni_reader_pcm_hw; | ||
461 | |||
355 | ret = devm_request_irq(&pdev->dev, reader->irq, | 462 | ret = devm_request_irq(&pdev->dev, reader->irq, |
356 | uni_reader_irq_handler, IRQF_SHARED, | 463 | uni_reader_irq_handler, IRQF_SHARED, |
357 | dev_name(&pdev->dev), reader); | 464 | dev_name(&pdev->dev), reader); |