diff options
Diffstat (limited to 'sound/soc')
119 files changed, 13693 insertions, 2473 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index a3efc52a34da..8224db5f0434 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -50,10 +50,12 @@ source "sound/soc/jz4740/Kconfig" | |||
50 | source "sound/soc/nuc900/Kconfig" | 50 | source "sound/soc/nuc900/Kconfig" |
51 | source "sound/soc/omap/Kconfig" | 51 | source "sound/soc/omap/Kconfig" |
52 | source "sound/soc/kirkwood/Kconfig" | 52 | source "sound/soc/kirkwood/Kconfig" |
53 | source "sound/soc/mid-x86/Kconfig" | ||
53 | source "sound/soc/pxa/Kconfig" | 54 | source "sound/soc/pxa/Kconfig" |
54 | source "sound/soc/samsung/Kconfig" | 55 | source "sound/soc/samsung/Kconfig" |
55 | source "sound/soc/s6000/Kconfig" | 56 | source "sound/soc/s6000/Kconfig" |
56 | source "sound/soc/sh/Kconfig" | 57 | source "sound/soc/sh/Kconfig" |
58 | source "sound/soc/tegra/Kconfig" | ||
57 | source "sound/soc/txx9/Kconfig" | 59 | source "sound/soc/txx9/Kconfig" |
58 | 60 | ||
59 | # Supported codecs | 61 | # Supported codecs |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index ce913bf5213c..1ed61c5df2c5 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_SND_SOC) += ep93xx/ | |||
10 | obj-$(CONFIG_SND_SOC) += fsl/ | 10 | obj-$(CONFIG_SND_SOC) += fsl/ |
11 | obj-$(CONFIG_SND_SOC) += imx/ | 11 | obj-$(CONFIG_SND_SOC) += imx/ |
12 | obj-$(CONFIG_SND_SOC) += jz4740/ | 12 | obj-$(CONFIG_SND_SOC) += jz4740/ |
13 | obj-$(CONFIG_SND_SOC) += mid-x86/ | ||
13 | obj-$(CONFIG_SND_SOC) += nuc900/ | 14 | obj-$(CONFIG_SND_SOC) += nuc900/ |
14 | obj-$(CONFIG_SND_SOC) += omap/ | 15 | obj-$(CONFIG_SND_SOC) += omap/ |
15 | obj-$(CONFIG_SND_SOC) += kirkwood/ | 16 | obj-$(CONFIG_SND_SOC) += kirkwood/ |
@@ -17,4 +18,5 @@ obj-$(CONFIG_SND_SOC) += pxa/ | |||
17 | obj-$(CONFIG_SND_SOC) += samsung/ | 18 | obj-$(CONFIG_SND_SOC) += samsung/ |
18 | obj-$(CONFIG_SND_SOC) += s6000/ | 19 | obj-$(CONFIG_SND_SOC) += s6000/ |
19 | obj-$(CONFIG_SND_SOC) += sh/ | 20 | obj-$(CONFIG_SND_SOC) += sh/ |
21 | obj-$(CONFIG_SND_SOC) += tegra/ | ||
20 | obj-$(CONFIG_SND_SOC) += txx9/ | 22 | obj-$(CONFIG_SND_SOC) += txx9/ |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index c48b23c1d4fc..d63c1754e05f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -26,17 +26,24 @@ config SND_SOC_ALL_CODECS | |||
26 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 26 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
27 | select SND_SOC_CS42L51 if I2C | 27 | select SND_SOC_CS42L51 if I2C |
28 | select SND_SOC_CS4270 if I2C | 28 | select SND_SOC_CS4270 if I2C |
29 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI | ||
29 | select SND_SOC_CX20442 | 30 | select SND_SOC_CX20442 |
30 | select SND_SOC_DA7210 if I2C | 31 | select SND_SOC_DA7210 if I2C |
32 | select SND_SOC_DFBMCS320 | ||
31 | select SND_SOC_JZ4740_CODEC if SOC_JZ4740 | 33 | select SND_SOC_JZ4740_CODEC if SOC_JZ4740 |
34 | select SND_SOC_LM4857 if I2C | ||
32 | select SND_SOC_MAX98088 if I2C | 35 | select SND_SOC_MAX98088 if I2C |
36 | select SND_SOC_MAX9850 if I2C | ||
33 | select SND_SOC_MAX9877 if I2C | 37 | select SND_SOC_MAX9877 if I2C |
34 | select SND_SOC_PCM3008 | 38 | select SND_SOC_PCM3008 |
39 | select SND_SOC_SGTL5000 if I2C | ||
40 | select SND_SOC_SN95031 if INTEL_SCU_IPC | ||
35 | select SND_SOC_SPDIF | 41 | select SND_SOC_SPDIF |
36 | select SND_SOC_SSM2602 if I2C | 42 | select SND_SOC_SSM2602 if I2C |
37 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 43 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
38 | select SND_SOC_TLV320AIC23 if I2C | 44 | select SND_SOC_TLV320AIC23 if I2C |
39 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 45 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
46 | select SND_SOC_TVL320AIC32X4 if I2C | ||
40 | select SND_SOC_TLV320AIC3X if I2C | 47 | select SND_SOC_TLV320AIC3X if I2C |
41 | select SND_SOC_TPA6130A2 if I2C | 48 | select SND_SOC_TPA6130A2 if I2C |
42 | select SND_SOC_TLV320DAC33 if I2C | 49 | select SND_SOC_TLV320DAC33 if I2C |
@@ -76,6 +83,7 @@ config SND_SOC_ALL_CODECS | |||
76 | select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI | 83 | select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI |
77 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI | 84 | select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI |
78 | select SND_SOC_WM8990 if I2C | 85 | select SND_SOC_WM8990 if I2C |
86 | select SND_SOC_WM8991 if I2C | ||
79 | select SND_SOC_WM8993 if I2C | 87 | select SND_SOC_WM8993 if I2C |
80 | select SND_SOC_WM8994 if MFD_WM8994 | 88 | select SND_SOC_WM8994 if MFD_WM8994 |
81 | select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI | 89 | select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI |
@@ -155,6 +163,9 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
155 | bool | 163 | bool |
156 | depends on SND_SOC_CS4270 | 164 | depends on SND_SOC_CS4270 |
157 | 165 | ||
166 | config SND_SOC_CS4271 | ||
167 | tristate | ||
168 | |||
158 | config SND_SOC_CX20442 | 169 | config SND_SOC_CX20442 |
159 | tristate | 170 | tristate |
160 | 171 | ||
@@ -167,15 +178,28 @@ config SND_SOC_L3 | |||
167 | config SND_SOC_DA7210 | 178 | config SND_SOC_DA7210 |
168 | tristate | 179 | tristate |
169 | 180 | ||
181 | config SND_SOC_DFBMCS320 | ||
182 | tristate | ||
183 | |||
170 | config SND_SOC_DMIC | 184 | config SND_SOC_DMIC |
171 | tristate | 185 | tristate |
172 | 186 | ||
173 | config SND_SOC_MAX98088 | 187 | config SND_SOC_MAX98088 |
174 | tristate | 188 | tristate |
175 | 189 | ||
190 | config SND_SOC_MAX9850 | ||
191 | tristate | ||
192 | |||
176 | config SND_SOC_PCM3008 | 193 | config SND_SOC_PCM3008 |
177 | tristate | 194 | tristate |
178 | 195 | ||
196 | #Freescale sgtl5000 codec | ||
197 | config SND_SOC_SGTL5000 | ||
198 | tristate | ||
199 | |||
200 | config SND_SOC_SN95031 | ||
201 | tristate | ||
202 | |||
179 | config SND_SOC_SPDIF | 203 | config SND_SOC_SPDIF |
180 | tristate | 204 | tristate |
181 | 205 | ||
@@ -192,6 +216,9 @@ config SND_SOC_TLV320AIC26 | |||
192 | tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE | 216 | tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE |
193 | depends on SPI | 217 | depends on SPI |
194 | 218 | ||
219 | config SND_SOC_TVL320AIC32X4 | ||
220 | tristate | ||
221 | |||
195 | config SND_SOC_TLV320AIC3X | 222 | config SND_SOC_TLV320AIC3X |
196 | tristate | 223 | tristate |
197 | 224 | ||
@@ -304,6 +331,9 @@ config SND_SOC_WM8988 | |||
304 | config SND_SOC_WM8990 | 331 | config SND_SOC_WM8990 |
305 | tristate | 332 | tristate |
306 | 333 | ||
334 | config SND_SOC_WM8991 | ||
335 | tristate | ||
336 | |||
307 | config SND_SOC_WM8993 | 337 | config SND_SOC_WM8993 |
308 | tristate | 338 | tristate |
309 | 339 | ||
@@ -326,6 +356,9 @@ config SND_SOC_WM9713 | |||
326 | tristate | 356 | tristate |
327 | 357 | ||
328 | # Amp | 358 | # Amp |
359 | config SND_SOC_LM4857 | ||
360 | tristate | ||
361 | |||
329 | config SND_SOC_MAX9877 | 362 | config SND_SOC_MAX9877 |
330 | tristate | 363 | tristate |
331 | 364 | ||
@@ -337,4 +370,3 @@ config SND_SOC_WM2000 | |||
337 | 370 | ||
338 | config SND_SOC_WM9090 | 371 | config SND_SOC_WM9090 |
339 | tristate | 372 | tristate |
340 | |||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 579af9c4f128..379bc55f0723 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -12,19 +12,25 @@ snd-soc-ak4671-objs := ak4671.o | |||
12 | snd-soc-cq93vc-objs := cq93vc.o | 12 | snd-soc-cq93vc-objs := cq93vc.o |
13 | snd-soc-cs42l51-objs := cs42l51.o | 13 | snd-soc-cs42l51-objs := cs42l51.o |
14 | snd-soc-cs4270-objs := cs4270.o | 14 | snd-soc-cs4270-objs := cs4270.o |
15 | snd-soc-cs4271-objs := cs4271.o | ||
15 | snd-soc-cx20442-objs := cx20442.o | 16 | snd-soc-cx20442-objs := cx20442.o |
16 | snd-soc-da7210-objs := da7210.o | 17 | snd-soc-da7210-objs := da7210.o |
18 | snd-soc-dfbmcs320-objs := dfbmcs320.o | ||
17 | snd-soc-dmic-objs := dmic.o | 19 | snd-soc-dmic-objs := dmic.o |
18 | snd-soc-l3-objs := l3.o | 20 | snd-soc-l3-objs := l3.o |
19 | snd-soc-max98088-objs := max98088.o | 21 | snd-soc-max98088-objs := max98088.o |
22 | snd-soc-max9850-objs := max9850.o | ||
20 | snd-soc-pcm3008-objs := pcm3008.o | 23 | snd-soc-pcm3008-objs := pcm3008.o |
24 | snd-soc-sgtl5000-objs := sgtl5000.o | ||
21 | snd-soc-alc5623-objs := alc5623.o | 25 | snd-soc-alc5623-objs := alc5623.o |
26 | snd-soc-sn95031-objs := sn95031.o | ||
22 | snd-soc-spdif-objs := spdif_transciever.o | 27 | snd-soc-spdif-objs := spdif_transciever.o |
23 | snd-soc-ssm2602-objs := ssm2602.o | 28 | snd-soc-ssm2602-objs := ssm2602.o |
24 | snd-soc-stac9766-objs := stac9766.o | 29 | snd-soc-stac9766-objs := stac9766.o |
25 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 30 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
26 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 31 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
27 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 32 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
33 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | ||
28 | snd-soc-tlv320dac33-objs := tlv320dac33.o | 34 | snd-soc-tlv320dac33-objs := tlv320dac33.o |
29 | snd-soc-twl4030-objs := twl4030.o | 35 | snd-soc-twl4030-objs := twl4030.o |
30 | snd-soc-twl6040-objs := twl6040.o | 36 | snd-soc-twl6040-objs := twl6040.o |
@@ -61,6 +67,7 @@ snd-soc-wm8978-objs := wm8978.o | |||
61 | snd-soc-wm8985-objs := wm8985.o | 67 | snd-soc-wm8985-objs := wm8985.o |
62 | snd-soc-wm8988-objs := wm8988.o | 68 | snd-soc-wm8988-objs := wm8988.o |
63 | snd-soc-wm8990-objs := wm8990.o | 69 | snd-soc-wm8990-objs := wm8990.o |
70 | snd-soc-wm8991-objs := wm8991.o | ||
64 | snd-soc-wm8993-objs := wm8993.o | 71 | snd-soc-wm8993-objs := wm8993.o |
65 | snd-soc-wm8994-objs := wm8994.o wm8994-tables.o | 72 | snd-soc-wm8994-objs := wm8994.o wm8994-tables.o |
66 | snd-soc-wm8995-objs := wm8995.o | 73 | snd-soc-wm8995-objs := wm8995.o |
@@ -72,6 +79,7 @@ snd-soc-wm-hubs-objs := wm_hubs.o | |||
72 | snd-soc-jz4740-codec-objs := jz4740.o | 79 | snd-soc-jz4740-codec-objs := jz4740.o |
73 | 80 | ||
74 | # Amp | 81 | # Amp |
82 | snd-soc-lm4857-objs := lm4857.o | ||
75 | snd-soc-max9877-objs := max9877.o | 83 | snd-soc-max9877-objs := max9877.o |
76 | snd-soc-tpa6130a2-objs := tpa6130a2.o | 84 | snd-soc-tpa6130a2-objs := tpa6130a2.o |
77 | snd-soc-wm2000-objs := wm2000.o | 85 | snd-soc-wm2000-objs := wm2000.o |
@@ -88,23 +96,29 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | |||
88 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 96 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
89 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 97 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
90 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 98 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
99 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | ||
91 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 100 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
92 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 101 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
93 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 102 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
103 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o | ||
94 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 104 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
95 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | 105 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o |
106 | obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o | ||
96 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o | 107 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o |
97 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 108 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
98 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | 109 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o |
99 | obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o | 110 | obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o |
111 | obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o | ||
100 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 112 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
101 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 113 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
114 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | ||
102 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 115 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
103 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 116 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
104 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 117 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
105 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 118 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
106 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 119 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
107 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 120 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
121 | obj-$(CONFIG_SND_SOC_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o | ||
108 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o | 122 | obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o |
109 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o | 123 | obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o |
110 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o | 124 | obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o |
@@ -141,6 +155,7 @@ obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o | |||
141 | obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o | 155 | obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o |
142 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o | 156 | obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o |
143 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o | 157 | obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o |
158 | obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o | ||
144 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o | 159 | obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o |
145 | obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o | 160 | obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o |
146 | obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o | 161 | obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o |
@@ -151,6 +166,7 @@ obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o | |||
151 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o | 166 | obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o |
152 | 167 | ||
153 | # Amp | 168 | # Amp |
169 | obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o | ||
154 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o | 170 | obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o |
155 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o | 171 | obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o |
156 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o | 172 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index c27f8f59dc66..cbf0b6d400b8 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
@@ -294,7 +294,6 @@ static struct spi_driver ak4104_spi_driver = { | |||
294 | 294 | ||
295 | static int __init ak4104_init(void) | 295 | static int __init ak4104_init(void) |
296 | { | 296 | { |
297 | pr_info("Asahi Kasei AK4104 ALSA SoC Codec Driver\n"); | ||
298 | return spi_register_driver(&ak4104_spi_driver); | 297 | return spi_register_driver(&ak4104_spi_driver); |
299 | } | 298 | } |
300 | module_init(ak4104_init); | 299 | module_init(ak4104_init); |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index f00eba313dfd..4be0570e3f1f 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -116,6 +116,12 @@ | |||
116 | #define BCKO_MASK (1 << 3) | 116 | #define BCKO_MASK (1 << 3) |
117 | #define BCKO_64 BCKO_MASK | 117 | #define BCKO_64 BCKO_MASK |
118 | 118 | ||
119 | #define DIF_MASK (3 << 0) | ||
120 | #define DSP (0 << 0) | ||
121 | #define RIGHT_J (1 << 0) | ||
122 | #define LEFT_J (2 << 0) | ||
123 | #define I2S (3 << 0) | ||
124 | |||
119 | /* MD_CTL2 */ | 125 | /* MD_CTL2 */ |
120 | #define FS0 (1 << 0) | 126 | #define FS0 (1 << 0) |
121 | #define FS1 (1 << 1) | 127 | #define FS1 (1 << 1) |
@@ -354,6 +360,24 @@ static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
354 | snd_soc_update_bits(codec, PW_MGMT2, MS, data); | 360 | snd_soc_update_bits(codec, PW_MGMT2, MS, data); |
355 | snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko); | 361 | snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko); |
356 | 362 | ||
363 | /* format type */ | ||
364 | data = 0; | ||
365 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
366 | case SND_SOC_DAIFMT_LEFT_J: | ||
367 | data = LEFT_J; | ||
368 | break; | ||
369 | case SND_SOC_DAIFMT_I2S: | ||
370 | data = I2S; | ||
371 | break; | ||
372 | /* FIXME | ||
373 | * Please add RIGHT_J / DSP support here | ||
374 | */ | ||
375 | default: | ||
376 | return -EINVAL; | ||
377 | break; | ||
378 | } | ||
379 | snd_soc_update_bits(codec, MD_CTL1, DIF_MASK, data); | ||
380 | |||
357 | return 0; | 381 | return 0; |
358 | } | 382 | } |
359 | 383 | ||
diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 8b51245f2318..0206a17d7283 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c | |||
@@ -193,12 +193,12 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = { | |||
193 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ | 193 | /* The number of MCLK/LRCK ratios supported by the CS4270 */ |
194 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) | 194 | #define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios) |
195 | 195 | ||
196 | static int cs4270_reg_is_readable(unsigned int reg) | 196 | static int cs4270_reg_is_readable(struct snd_soc_codec *codec, unsigned int reg) |
197 | { | 197 | { |
198 | return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG); | 198 | return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG); |
199 | } | 199 | } |
200 | 200 | ||
201 | static int cs4270_reg_is_volatile(unsigned int reg) | 201 | static int cs4270_reg_is_volatile(struct snd_soc_codec *codec, unsigned int reg) |
202 | { | 202 | { |
203 | /* Unreadable registers are considered volatile */ | 203 | /* Unreadable registers are considered volatile */ |
204 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) | 204 | if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG)) |
@@ -719,7 +719,7 @@ static int cs4270_i2c_remove(struct i2c_client *i2c_client) | |||
719 | /* | 719 | /* |
720 | * cs4270_id - I2C device IDs supported by this driver | 720 | * cs4270_id - I2C device IDs supported by this driver |
721 | */ | 721 | */ |
722 | static struct i2c_device_id cs4270_id[] = { | 722 | static const struct i2c_device_id cs4270_id[] = { |
723 | {"cs4270", 0}, | 723 | {"cs4270", 0}, |
724 | {} | 724 | {} |
725 | }; | 725 | }; |
@@ -743,8 +743,6 @@ static struct i2c_driver cs4270_i2c_driver = { | |||
743 | 743 | ||
744 | static int __init cs4270_init(void) | 744 | static int __init cs4270_init(void) |
745 | { | 745 | { |
746 | pr_info("Cirrus Logic CS4270 ALSA SoC Codec Driver\n"); | ||
747 | |||
748 | return i2c_add_driver(&cs4270_i2c_driver); | 746 | return i2c_add_driver(&cs4270_i2c_driver); |
749 | } | 747 | } |
750 | module_init(cs4270_init); | 748 | module_init(cs4270_init); |
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c new file mode 100644 index 000000000000..083aab96ca80 --- /dev/null +++ b/sound/soc/codecs/cs4271.c | |||
@@ -0,0 +1,667 @@ | |||
1 | /* | ||
2 | * CS4271 ASoC codec driver | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * This driver support CS4271 codec being master or slave, working | ||
17 | * in control port mode, connected either via SPI or I2C. | ||
18 | * The data format accepted is I2S or left-justified. | ||
19 | * DAPM support not implemented. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/tlv.h> | ||
28 | #include <linux/gpio.h> | ||
29 | #include <linux/i2c.h> | ||
30 | #include <linux/spi/spi.h> | ||
31 | #include <sound/cs4271.h> | ||
32 | |||
33 | #define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
34 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
35 | SNDRV_PCM_FMTBIT_S32_LE) | ||
36 | #define CS4271_PCM_RATES SNDRV_PCM_RATE_8000_192000 | ||
37 | |||
38 | /* | ||
39 | * CS4271 registers | ||
40 | * High byte represents SPI chip address (0x10) + write command (0) | ||
41 | * Low byte - codec register address | ||
42 | */ | ||
43 | #define CS4271_MODE1 0x2001 /* Mode Control 1 */ | ||
44 | #define CS4271_DACCTL 0x2002 /* DAC Control */ | ||
45 | #define CS4271_DACVOL 0x2003 /* DAC Volume & Mixing Control */ | ||
46 | #define CS4271_VOLA 0x2004 /* DAC Channel A Volume Control */ | ||
47 | #define CS4271_VOLB 0x2005 /* DAC Channel B Volume Control */ | ||
48 | #define CS4271_ADCCTL 0x2006 /* ADC Control */ | ||
49 | #define CS4271_MODE2 0x2007 /* Mode Control 2 */ | ||
50 | #define CS4271_CHIPID 0x2008 /* Chip ID */ | ||
51 | |||
52 | #define CS4271_FIRSTREG CS4271_MODE1 | ||
53 | #define CS4271_LASTREG CS4271_MODE2 | ||
54 | #define CS4271_NR_REGS ((CS4271_LASTREG & 0xFF) + 1) | ||
55 | |||
56 | /* Bit masks for the CS4271 registers */ | ||
57 | #define CS4271_MODE1_MODE_MASK 0xC0 | ||
58 | #define CS4271_MODE1_MODE_1X 0x00 | ||
59 | #define CS4271_MODE1_MODE_2X 0x80 | ||
60 | #define CS4271_MODE1_MODE_4X 0xC0 | ||
61 | |||
62 | #define CS4271_MODE1_DIV_MASK 0x30 | ||
63 | #define CS4271_MODE1_DIV_1 0x00 | ||
64 | #define CS4271_MODE1_DIV_15 0x10 | ||
65 | #define CS4271_MODE1_DIV_2 0x20 | ||
66 | #define CS4271_MODE1_DIV_3 0x30 | ||
67 | |||
68 | #define CS4271_MODE1_MASTER 0x08 | ||
69 | |||
70 | #define CS4271_MODE1_DAC_DIF_MASK 0x07 | ||
71 | #define CS4271_MODE1_DAC_DIF_LJ 0x00 | ||
72 | #define CS4271_MODE1_DAC_DIF_I2S 0x01 | ||
73 | #define CS4271_MODE1_DAC_DIF_RJ16 0x02 | ||
74 | #define CS4271_MODE1_DAC_DIF_RJ24 0x03 | ||
75 | #define CS4271_MODE1_DAC_DIF_RJ20 0x04 | ||
76 | #define CS4271_MODE1_DAC_DIF_RJ18 0x05 | ||
77 | |||
78 | #define CS4271_DACCTL_AMUTE 0x80 | ||
79 | #define CS4271_DACCTL_IF_SLOW 0x40 | ||
80 | |||
81 | #define CS4271_DACCTL_DEM_MASK 0x30 | ||
82 | #define CS4271_DACCTL_DEM_DIS 0x00 | ||
83 | #define CS4271_DACCTL_DEM_441 0x10 | ||
84 | #define CS4271_DACCTL_DEM_48 0x20 | ||
85 | #define CS4271_DACCTL_DEM_32 0x30 | ||
86 | |||
87 | #define CS4271_DACCTL_SVRU 0x08 | ||
88 | #define CS4271_DACCTL_SRD 0x04 | ||
89 | #define CS4271_DACCTL_INVA 0x02 | ||
90 | #define CS4271_DACCTL_INVB 0x01 | ||
91 | |||
92 | #define CS4271_DACVOL_BEQUA 0x40 | ||
93 | #define CS4271_DACVOL_SOFT 0x20 | ||
94 | #define CS4271_DACVOL_ZEROC 0x10 | ||
95 | |||
96 | #define CS4271_DACVOL_ATAPI_MASK 0x0F | ||
97 | #define CS4271_DACVOL_ATAPI_M_M 0x00 | ||
98 | #define CS4271_DACVOL_ATAPI_M_BR 0x01 | ||
99 | #define CS4271_DACVOL_ATAPI_M_BL 0x02 | ||
100 | #define CS4271_DACVOL_ATAPI_M_BLR2 0x03 | ||
101 | #define CS4271_DACVOL_ATAPI_AR_M 0x04 | ||
102 | #define CS4271_DACVOL_ATAPI_AR_BR 0x05 | ||
103 | #define CS4271_DACVOL_ATAPI_AR_BL 0x06 | ||
104 | #define CS4271_DACVOL_ATAPI_AR_BLR2 0x07 | ||
105 | #define CS4271_DACVOL_ATAPI_AL_M 0x08 | ||
106 | #define CS4271_DACVOL_ATAPI_AL_BR 0x09 | ||
107 | #define CS4271_DACVOL_ATAPI_AL_BL 0x0A | ||
108 | #define CS4271_DACVOL_ATAPI_AL_BLR2 0x0B | ||
109 | #define CS4271_DACVOL_ATAPI_ALR2_M 0x0C | ||
110 | #define CS4271_DACVOL_ATAPI_ALR2_BR 0x0D | ||
111 | #define CS4271_DACVOL_ATAPI_ALR2_BL 0x0E | ||
112 | #define CS4271_DACVOL_ATAPI_ALR2_BLR2 0x0F | ||
113 | |||
114 | #define CS4271_VOLA_MUTE 0x80 | ||
115 | #define CS4271_VOLA_VOL_MASK 0x7F | ||
116 | #define CS4271_VOLB_MUTE 0x80 | ||
117 | #define CS4271_VOLB_VOL_MASK 0x7F | ||
118 | |||
119 | #define CS4271_ADCCTL_DITHER16 0x20 | ||
120 | |||
121 | #define CS4271_ADCCTL_ADC_DIF_MASK 0x10 | ||
122 | #define CS4271_ADCCTL_ADC_DIF_LJ 0x00 | ||
123 | #define CS4271_ADCCTL_ADC_DIF_I2S 0x10 | ||
124 | |||
125 | #define CS4271_ADCCTL_MUTEA 0x08 | ||
126 | #define CS4271_ADCCTL_MUTEB 0x04 | ||
127 | #define CS4271_ADCCTL_HPFDA 0x02 | ||
128 | #define CS4271_ADCCTL_HPFDB 0x01 | ||
129 | |||
130 | #define CS4271_MODE2_LOOP 0x10 | ||
131 | #define CS4271_MODE2_MUTECAEQUB 0x08 | ||
132 | #define CS4271_MODE2_FREEZE 0x04 | ||
133 | #define CS4271_MODE2_CPEN 0x02 | ||
134 | #define CS4271_MODE2_PDN 0x01 | ||
135 | |||
136 | #define CS4271_CHIPID_PART_MASK 0xF0 | ||
137 | #define CS4271_CHIPID_REV_MASK 0x0F | ||
138 | |||
139 | /* | ||
140 | * Default CS4271 power-up configuration | ||
141 | * Array contains non-existing in hw register at address 0 | ||
142 | * Array do not include Chip ID, as codec driver does not use | ||
143 | * registers read operations at all | ||
144 | */ | ||
145 | static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = { | ||
146 | 0, | ||
147 | 0, | ||
148 | CS4271_DACCTL_AMUTE, | ||
149 | CS4271_DACVOL_SOFT | CS4271_DACVOL_ATAPI_AL_BR, | ||
150 | 0, | ||
151 | 0, | ||
152 | 0, | ||
153 | 0, | ||
154 | }; | ||
155 | |||
156 | struct cs4271_private { | ||
157 | /* SND_SOC_I2C or SND_SOC_SPI */ | ||
158 | enum snd_soc_control_type bus_type; | ||
159 | void *control_data; | ||
160 | unsigned int mclk; | ||
161 | bool master; | ||
162 | bool deemph; | ||
163 | /* Current sample rate for de-emphasis control */ | ||
164 | int rate; | ||
165 | /* GPIO driving Reset pin, if any */ | ||
166 | int gpio_nreset; | ||
167 | /* GPIO that disable serial bus, if any */ | ||
168 | int gpio_disable; | ||
169 | }; | ||
170 | |||
171 | /* | ||
172 | * @freq is the desired MCLK rate | ||
173 | * MCLK rate should (c) be the sample rate, multiplied by one of the | ||
174 | * ratios listed in cs4271_mclk_fs_ratios table | ||
175 | */ | ||
176 | static int cs4271_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
177 | int clk_id, unsigned int freq, int dir) | ||
178 | { | ||
179 | struct snd_soc_codec *codec = codec_dai->codec; | ||
180 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
181 | |||
182 | cs4271->mclk = freq; | ||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
187 | unsigned int format) | ||
188 | { | ||
189 | struct snd_soc_codec *codec = codec_dai->codec; | ||
190 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
191 | unsigned int val = 0; | ||
192 | int ret; | ||
193 | |||
194 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
195 | case SND_SOC_DAIFMT_CBS_CFS: | ||
196 | cs4271->master = 0; | ||
197 | break; | ||
198 | case SND_SOC_DAIFMT_CBM_CFM: | ||
199 | cs4271->master = 1; | ||
200 | val |= CS4271_MODE1_MASTER; | ||
201 | break; | ||
202 | default: | ||
203 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
208 | case SND_SOC_DAIFMT_LEFT_J: | ||
209 | val |= CS4271_MODE1_DAC_DIF_LJ; | ||
210 | ret = snd_soc_update_bits(codec, CS4271_ADCCTL, | ||
211 | CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_LJ); | ||
212 | if (ret < 0) | ||
213 | return ret; | ||
214 | break; | ||
215 | case SND_SOC_DAIFMT_I2S: | ||
216 | val |= CS4271_MODE1_DAC_DIF_I2S; | ||
217 | ret = snd_soc_update_bits(codec, CS4271_ADCCTL, | ||
218 | CS4271_ADCCTL_ADC_DIF_MASK, CS4271_ADCCTL_ADC_DIF_I2S); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | break; | ||
222 | default: | ||
223 | dev_err(codec->dev, "Invalid DAI format\n"); | ||
224 | return -EINVAL; | ||
225 | } | ||
226 | |||
227 | ret = snd_soc_update_bits(codec, CS4271_MODE1, | ||
228 | CS4271_MODE1_DAC_DIF_MASK | CS4271_MODE1_MASTER, val); | ||
229 | if (ret < 0) | ||
230 | return ret; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static int cs4271_deemph[] = {0, 44100, 48000, 32000}; | ||
235 | |||
236 | static int cs4271_set_deemph(struct snd_soc_codec *codec) | ||
237 | { | ||
238 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
239 | int i, ret; | ||
240 | int val = CS4271_DACCTL_DEM_DIS; | ||
241 | |||
242 | if (cs4271->deemph) { | ||
243 | /* Find closest de-emphasis freq */ | ||
244 | val = 1; | ||
245 | for (i = 2; i < ARRAY_SIZE(cs4271_deemph); i++) | ||
246 | if (abs(cs4271_deemph[i] - cs4271->rate) < | ||
247 | abs(cs4271_deemph[val] - cs4271->rate)) | ||
248 | val = i; | ||
249 | val <<= 4; | ||
250 | } | ||
251 | |||
252 | ret = snd_soc_update_bits(codec, CS4271_DACCTL, | ||
253 | CS4271_DACCTL_DEM_MASK, val); | ||
254 | if (ret < 0) | ||
255 | return ret; | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int cs4271_get_deemph(struct snd_kcontrol *kcontrol, | ||
260 | struct snd_ctl_elem_value *ucontrol) | ||
261 | { | ||
262 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
263 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
264 | |||
265 | ucontrol->value.enumerated.item[0] = cs4271->deemph; | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int cs4271_put_deemph(struct snd_kcontrol *kcontrol, | ||
270 | struct snd_ctl_elem_value *ucontrol) | ||
271 | { | ||
272 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
273 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
274 | |||
275 | cs4271->deemph = ucontrol->value.enumerated.item[0]; | ||
276 | return cs4271_set_deemph(codec); | ||
277 | } | ||
278 | |||
279 | struct cs4271_clk_cfg { | ||
280 | bool master; /* codec mode */ | ||
281 | u8 speed_mode; /* codec speed mode: 1x, 2x, 4x */ | ||
282 | unsigned short ratio; /* MCLK / sample rate */ | ||
283 | u8 ratio_mask; /* ratio bit mask for Master mode */ | ||
284 | }; | ||
285 | |||
286 | static struct cs4271_clk_cfg cs4271_clk_tab[] = { | ||
287 | {1, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1}, | ||
288 | {1, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_15}, | ||
289 | {1, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_2}, | ||
290 | {1, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_3}, | ||
291 | {1, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1}, | ||
292 | {1, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_15}, | ||
293 | {1, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_2}, | ||
294 | {1, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_3}, | ||
295 | {1, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1}, | ||
296 | {1, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_15}, | ||
297 | {1, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_2}, | ||
298 | {1, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_3}, | ||
299 | {0, CS4271_MODE1_MODE_1X, 256, CS4271_MODE1_DIV_1}, | ||
300 | {0, CS4271_MODE1_MODE_1X, 384, CS4271_MODE1_DIV_1}, | ||
301 | {0, CS4271_MODE1_MODE_1X, 512, CS4271_MODE1_DIV_1}, | ||
302 | {0, CS4271_MODE1_MODE_1X, 768, CS4271_MODE1_DIV_2}, | ||
303 | {0, CS4271_MODE1_MODE_1X, 1024, CS4271_MODE1_DIV_2}, | ||
304 | {0, CS4271_MODE1_MODE_2X, 128, CS4271_MODE1_DIV_1}, | ||
305 | {0, CS4271_MODE1_MODE_2X, 192, CS4271_MODE1_DIV_1}, | ||
306 | {0, CS4271_MODE1_MODE_2X, 256, CS4271_MODE1_DIV_1}, | ||
307 | {0, CS4271_MODE1_MODE_2X, 384, CS4271_MODE1_DIV_2}, | ||
308 | {0, CS4271_MODE1_MODE_2X, 512, CS4271_MODE1_DIV_2}, | ||
309 | {0, CS4271_MODE1_MODE_4X, 64, CS4271_MODE1_DIV_1}, | ||
310 | {0, CS4271_MODE1_MODE_4X, 96, CS4271_MODE1_DIV_1}, | ||
311 | {0, CS4271_MODE1_MODE_4X, 128, CS4271_MODE1_DIV_1}, | ||
312 | {0, CS4271_MODE1_MODE_4X, 192, CS4271_MODE1_DIV_2}, | ||
313 | {0, CS4271_MODE1_MODE_4X, 256, CS4271_MODE1_DIV_2}, | ||
314 | }; | ||
315 | |||
316 | #define CS4171_NR_RATIOS ARRAY_SIZE(cs4271_clk_tab) | ||
317 | |||
318 | static int cs4271_hw_params(struct snd_pcm_substream *substream, | ||
319 | struct snd_pcm_hw_params *params, | ||
320 | struct snd_soc_dai *dai) | ||
321 | { | ||
322 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
323 | struct snd_soc_codec *codec = rtd->codec; | ||
324 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
325 | int i, ret; | ||
326 | unsigned int ratio, val; | ||
327 | |||
328 | cs4271->rate = params_rate(params); | ||
329 | |||
330 | /* Configure DAC */ | ||
331 | if (cs4271->rate < 50000) | ||
332 | val = CS4271_MODE1_MODE_1X; | ||
333 | else if (cs4271->rate < 100000) | ||
334 | val = CS4271_MODE1_MODE_2X; | ||
335 | else | ||
336 | val = CS4271_MODE1_MODE_4X; | ||
337 | |||
338 | ratio = cs4271->mclk / cs4271->rate; | ||
339 | for (i = 0; i < CS4171_NR_RATIOS; i++) | ||
340 | if ((cs4271_clk_tab[i].master == cs4271->master) && | ||
341 | (cs4271_clk_tab[i].speed_mode == val) && | ||
342 | (cs4271_clk_tab[i].ratio == ratio)) | ||
343 | break; | ||
344 | |||
345 | if (i == CS4171_NR_RATIOS) { | ||
346 | dev_err(codec->dev, "Invalid sample rate\n"); | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | val |= cs4271_clk_tab[i].ratio_mask; | ||
351 | |||
352 | ret = snd_soc_update_bits(codec, CS4271_MODE1, | ||
353 | CS4271_MODE1_MODE_MASK | CS4271_MODE1_DIV_MASK, val); | ||
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | |||
357 | return cs4271_set_deemph(codec); | ||
358 | } | ||
359 | |||
360 | static int cs4271_digital_mute(struct snd_soc_dai *dai, int mute) | ||
361 | { | ||
362 | struct snd_soc_codec *codec = dai->codec; | ||
363 | int ret; | ||
364 | int val_a = 0; | ||
365 | int val_b = 0; | ||
366 | |||
367 | if (mute) { | ||
368 | val_a = CS4271_VOLA_MUTE; | ||
369 | val_b = CS4271_VOLB_MUTE; | ||
370 | } | ||
371 | |||
372 | ret = snd_soc_update_bits(codec, CS4271_VOLA, CS4271_VOLA_MUTE, val_a); | ||
373 | if (ret < 0) | ||
374 | return ret; | ||
375 | ret = snd_soc_update_bits(codec, CS4271_VOLB, CS4271_VOLB_MUTE, val_b); | ||
376 | if (ret < 0) | ||
377 | return ret; | ||
378 | |||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | /* CS4271 controls */ | ||
383 | static DECLARE_TLV_DB_SCALE(cs4271_dac_tlv, -12700, 100, 0); | ||
384 | |||
385 | static const struct snd_kcontrol_new cs4271_snd_controls[] = { | ||
386 | SOC_DOUBLE_R_TLV("Master Playback Volume", CS4271_VOLA, CS4271_VOLB, | ||
387 | 0, 0x7F, 1, cs4271_dac_tlv), | ||
388 | SOC_SINGLE("Digital Loopback Switch", CS4271_MODE2, 4, 1, 0), | ||
389 | SOC_SINGLE("Soft Ramp Switch", CS4271_DACVOL, 5, 1, 0), | ||
390 | SOC_SINGLE("Zero Cross Switch", CS4271_DACVOL, 4, 1, 0), | ||
391 | SOC_SINGLE_BOOL_EXT("De-emphasis Switch", 0, | ||
392 | cs4271_get_deemph, cs4271_put_deemph), | ||
393 | SOC_SINGLE("Auto-Mute Switch", CS4271_DACCTL, 7, 1, 0), | ||
394 | SOC_SINGLE("Slow Roll Off Filter Switch", CS4271_DACCTL, 6, 1, 0), | ||
395 | SOC_SINGLE("Soft Volume Ramp-Up Switch", CS4271_DACCTL, 3, 1, 0), | ||
396 | SOC_SINGLE("Soft Ramp-Down Switch", CS4271_DACCTL, 2, 1, 0), | ||
397 | SOC_SINGLE("Left Channel Inversion Switch", CS4271_DACCTL, 1, 1, 0), | ||
398 | SOC_SINGLE("Right Channel Inversion Switch", CS4271_DACCTL, 0, 1, 0), | ||
399 | SOC_DOUBLE("Master Capture Switch", CS4271_ADCCTL, 3, 2, 1, 1), | ||
400 | SOC_SINGLE("Dither 16-Bit Data Switch", CS4271_ADCCTL, 5, 1, 0), | ||
401 | SOC_DOUBLE("High Pass Filter Switch", CS4271_ADCCTL, 1, 0, 1, 1), | ||
402 | SOC_DOUBLE_R("Master Playback Switch", CS4271_VOLA, CS4271_VOLB, | ||
403 | 7, 1, 1), | ||
404 | }; | ||
405 | |||
406 | static struct snd_soc_dai_ops cs4271_dai_ops = { | ||
407 | .hw_params = cs4271_hw_params, | ||
408 | .set_sysclk = cs4271_set_dai_sysclk, | ||
409 | .set_fmt = cs4271_set_dai_fmt, | ||
410 | .digital_mute = cs4271_digital_mute, | ||
411 | }; | ||
412 | |||
413 | static struct snd_soc_dai_driver cs4271_dai = { | ||
414 | .name = "cs4271-hifi", | ||
415 | .playback = { | ||
416 | .stream_name = "Playback", | ||
417 | .channels_min = 2, | ||
418 | .channels_max = 2, | ||
419 | .rates = CS4271_PCM_RATES, | ||
420 | .formats = CS4271_PCM_FORMATS, | ||
421 | }, | ||
422 | .capture = { | ||
423 | .stream_name = "Capture", | ||
424 | .channels_min = 2, | ||
425 | .channels_max = 2, | ||
426 | .rates = CS4271_PCM_RATES, | ||
427 | .formats = CS4271_PCM_FORMATS, | ||
428 | }, | ||
429 | .ops = &cs4271_dai_ops, | ||
430 | .symmetric_rates = 1, | ||
431 | }; | ||
432 | |||
433 | #ifdef CONFIG_PM | ||
434 | static int cs4271_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg) | ||
435 | { | ||
436 | int ret; | ||
437 | /* Set power-down bit */ | ||
438 | ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, CS4271_MODE2_PDN); | ||
439 | if (ret < 0) | ||
440 | return ret; | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | static int cs4271_soc_resume(struct snd_soc_codec *codec) | ||
445 | { | ||
446 | int ret; | ||
447 | /* Restore codec state */ | ||
448 | ret = snd_soc_cache_sync(codec); | ||
449 | if (ret < 0) | ||
450 | return ret; | ||
451 | /* then disable the power-down bit */ | ||
452 | ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); | ||
453 | if (ret < 0) | ||
454 | return ret; | ||
455 | return 0; | ||
456 | } | ||
457 | #else | ||
458 | #define cs4271_soc_suspend NULL | ||
459 | #define cs4271_soc_resume NULL | ||
460 | #endif /* CONFIG_PM */ | ||
461 | |||
462 | static int cs4271_probe(struct snd_soc_codec *codec) | ||
463 | { | ||
464 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
465 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | ||
466 | int ret; | ||
467 | int gpio_nreset = -EINVAL; | ||
468 | |||
469 | codec->control_data = cs4271->control_data; | ||
470 | |||
471 | if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) | ||
472 | gpio_nreset = cs4271plat->gpio_nreset; | ||
473 | |||
474 | if (gpio_nreset >= 0) | ||
475 | if (gpio_request(gpio_nreset, "CS4271 Reset")) | ||
476 | gpio_nreset = -EINVAL; | ||
477 | if (gpio_nreset >= 0) { | ||
478 | /* Reset codec */ | ||
479 | gpio_direction_output(gpio_nreset, 0); | ||
480 | udelay(1); | ||
481 | gpio_set_value(gpio_nreset, 1); | ||
482 | /* Give the codec time to wake up */ | ||
483 | udelay(1); | ||
484 | } | ||
485 | |||
486 | cs4271->gpio_nreset = gpio_nreset; | ||
487 | |||
488 | /* | ||
489 | * In case of I2C, chip address specified in board data. | ||
490 | * So cache IO operations use 8 bit codec register address. | ||
491 | * In case of SPI, chip address and register address | ||
492 | * passed together as 16 bit value. | ||
493 | * Anyway, register address is masked with 0xFF inside | ||
494 | * soc-cache code. | ||
495 | */ | ||
496 | if (cs4271->bus_type == SND_SOC_SPI) | ||
497 | ret = snd_soc_codec_set_cache_io(codec, 16, 8, | ||
498 | cs4271->bus_type); | ||
499 | else | ||
500 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, | ||
501 | cs4271->bus_type); | ||
502 | if (ret) { | ||
503 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
504 | return ret; | ||
505 | } | ||
506 | |||
507 | ret = snd_soc_update_bits(codec, CS4271_MODE2, 0, | ||
508 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); | ||
509 | if (ret < 0) | ||
510 | return ret; | ||
511 | ret = snd_soc_update_bits(codec, CS4271_MODE2, CS4271_MODE2_PDN, 0); | ||
512 | if (ret < 0) | ||
513 | return ret; | ||
514 | /* Power-up sequence requires 85 uS */ | ||
515 | udelay(85); | ||
516 | |||
517 | return snd_soc_add_controls(codec, cs4271_snd_controls, | ||
518 | ARRAY_SIZE(cs4271_snd_controls)); | ||
519 | } | ||
520 | |||
521 | static int cs4271_remove(struct snd_soc_codec *codec) | ||
522 | { | ||
523 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | ||
524 | int gpio_nreset; | ||
525 | |||
526 | gpio_nreset = cs4271->gpio_nreset; | ||
527 | |||
528 | if (gpio_is_valid(gpio_nreset)) { | ||
529 | /* Set codec to the reset state */ | ||
530 | gpio_set_value(gpio_nreset, 0); | ||
531 | gpio_free(gpio_nreset); | ||
532 | } | ||
533 | |||
534 | return 0; | ||
535 | }; | ||
536 | |||
537 | static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | ||
538 | .probe = cs4271_probe, | ||
539 | .remove = cs4271_remove, | ||
540 | .suspend = cs4271_soc_suspend, | ||
541 | .resume = cs4271_soc_resume, | ||
542 | .reg_cache_default = cs4271_dflt_reg, | ||
543 | .reg_cache_size = ARRAY_SIZE(cs4271_dflt_reg), | ||
544 | .reg_word_size = sizeof(cs4271_dflt_reg[0]), | ||
545 | .compress_type = SND_SOC_FLAT_COMPRESSION, | ||
546 | }; | ||
547 | |||
548 | #if defined(CONFIG_SPI_MASTER) | ||
549 | static int __devinit cs4271_spi_probe(struct spi_device *spi) | ||
550 | { | ||
551 | struct cs4271_private *cs4271; | ||
552 | |||
553 | cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); | ||
554 | if (!cs4271) | ||
555 | return -ENOMEM; | ||
556 | |||
557 | spi_set_drvdata(spi, cs4271); | ||
558 | cs4271->control_data = spi; | ||
559 | cs4271->bus_type = SND_SOC_SPI; | ||
560 | |||
561 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, | ||
562 | &cs4271_dai, 1); | ||
563 | } | ||
564 | |||
565 | static int __devexit cs4271_spi_remove(struct spi_device *spi) | ||
566 | { | ||
567 | snd_soc_unregister_codec(&spi->dev); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static struct spi_driver cs4271_spi_driver = { | ||
572 | .driver = { | ||
573 | .name = "cs4271", | ||
574 | .owner = THIS_MODULE, | ||
575 | }, | ||
576 | .probe = cs4271_spi_probe, | ||
577 | .remove = __devexit_p(cs4271_spi_remove), | ||
578 | }; | ||
579 | #endif /* defined(CONFIG_SPI_MASTER) */ | ||
580 | |||
581 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
582 | static const struct i2c_device_id cs4271_i2c_id[] = { | ||
583 | {"cs4271", 0}, | ||
584 | {} | ||
585 | }; | ||
586 | MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); | ||
587 | |||
588 | static int __devinit cs4271_i2c_probe(struct i2c_client *client, | ||
589 | const struct i2c_device_id *id) | ||
590 | { | ||
591 | struct cs4271_private *cs4271; | ||
592 | |||
593 | cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); | ||
594 | if (!cs4271) | ||
595 | return -ENOMEM; | ||
596 | |||
597 | i2c_set_clientdata(client, cs4271); | ||
598 | cs4271->control_data = client; | ||
599 | cs4271->bus_type = SND_SOC_I2C; | ||
600 | |||
601 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, | ||
602 | &cs4271_dai, 1); | ||
603 | } | ||
604 | |||
605 | static int __devexit cs4271_i2c_remove(struct i2c_client *client) | ||
606 | { | ||
607 | snd_soc_unregister_codec(&client->dev); | ||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static struct i2c_driver cs4271_i2c_driver = { | ||
612 | .driver = { | ||
613 | .name = "cs4271", | ||
614 | .owner = THIS_MODULE, | ||
615 | }, | ||
616 | .id_table = cs4271_i2c_id, | ||
617 | .probe = cs4271_i2c_probe, | ||
618 | .remove = __devexit_p(cs4271_i2c_remove), | ||
619 | }; | ||
620 | #endif /* defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) */ | ||
621 | |||
622 | /* | ||
623 | * We only register our serial bus driver here without | ||
624 | * assignment to particular chip. So if any of the below | ||
625 | * fails, there is some problem with I2C or SPI subsystem. | ||
626 | * In most cases this module will be compiled with support | ||
627 | * of only one serial bus. | ||
628 | */ | ||
629 | static int __init cs4271_modinit(void) | ||
630 | { | ||
631 | int ret; | ||
632 | |||
633 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
634 | ret = i2c_add_driver(&cs4271_i2c_driver); | ||
635 | if (ret) { | ||
636 | pr_err("Failed to register CS4271 I2C driver: %d\n", ret); | ||
637 | return ret; | ||
638 | } | ||
639 | #endif | ||
640 | |||
641 | #if defined(CONFIG_SPI_MASTER) | ||
642 | ret = spi_register_driver(&cs4271_spi_driver); | ||
643 | if (ret) { | ||
644 | pr_err("Failed to register CS4271 SPI driver: %d\n", ret); | ||
645 | return ret; | ||
646 | } | ||
647 | #endif | ||
648 | |||
649 | return 0; | ||
650 | } | ||
651 | module_init(cs4271_modinit); | ||
652 | |||
653 | static void __exit cs4271_modexit(void) | ||
654 | { | ||
655 | #if defined(CONFIG_SPI_MASTER) | ||
656 | spi_unregister_driver(&cs4271_spi_driver); | ||
657 | #endif | ||
658 | |||
659 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
660 | i2c_del_driver(&cs4271_i2c_driver); | ||
661 | #endif | ||
662 | } | ||
663 | module_exit(cs4271_modexit); | ||
664 | |||
665 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
666 | MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver"); | ||
667 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/dfbmcs320.c b/sound/soc/codecs/dfbmcs320.c new file mode 100644 index 000000000000..704bbde65737 --- /dev/null +++ b/sound/soc/codecs/dfbmcs320.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* | ||
2 | * Driver for the DFBM-CS320 bluetooth module | ||
3 | * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License as published by the | ||
7 | * Free Software Foundation; either version 2 of the License, or (at your | ||
8 | * option) any later version. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/init.h> | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | |||
16 | #include <sound/soc.h> | ||
17 | |||
18 | static struct snd_soc_dai_driver dfbmcs320_dai = { | ||
19 | .name = "dfbmcs320-pcm", | ||
20 | .playback = { | ||
21 | .channels_min = 1, | ||
22 | .channels_max = 1, | ||
23 | .rates = SNDRV_PCM_RATE_8000, | ||
24 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
25 | }, | ||
26 | .capture = { | ||
27 | .channels_min = 1, | ||
28 | .channels_max = 1, | ||
29 | .rates = SNDRV_PCM_RATE_8000, | ||
30 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
31 | }, | ||
32 | }; | ||
33 | |||
34 | static struct snd_soc_codec_driver soc_codec_dev_dfbmcs320; | ||
35 | |||
36 | static int __devinit dfbmcs320_probe(struct platform_device *pdev) | ||
37 | { | ||
38 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_dfbmcs320, | ||
39 | &dfbmcs320_dai, 1); | ||
40 | } | ||
41 | |||
42 | static int __devexit dfbmcs320_remove(struct platform_device *pdev) | ||
43 | { | ||
44 | snd_soc_unregister_codec(&pdev->dev); | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static struct platform_driver dfmcs320_driver = { | ||
50 | .driver = { | ||
51 | .name = "dfbmcs320", | ||
52 | .owner = THIS_MODULE, | ||
53 | }, | ||
54 | .probe = dfbmcs320_probe, | ||
55 | .remove = __devexit_p(dfbmcs320_remove), | ||
56 | }; | ||
57 | |||
58 | static int __init dfbmcs320_init(void) | ||
59 | { | ||
60 | return platform_driver_register(&dfmcs320_driver); | ||
61 | } | ||
62 | module_init(dfbmcs320_init); | ||
63 | |||
64 | static void __exit dfbmcs320_exit(void) | ||
65 | { | ||
66 | platform_driver_unregister(&dfmcs320_driver); | ||
67 | } | ||
68 | module_exit(dfbmcs320_exit); | ||
69 | |||
70 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
71 | MODULE_DESCRIPTION("ASoC DFBM-CS320 bluethooth module driver"); | ||
72 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c new file mode 100644 index 000000000000..72de47e5d040 --- /dev/null +++ b/sound/soc/codecs/lm4857.c | |||
@@ -0,0 +1,276 @@ | |||
1 | /* | ||
2 | * LM4857 AMP driver | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the | ||
11 | * Free Software Foundation; either version 2 of the License, or (at your | ||
12 | * option) any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/soc.h> | ||
23 | #include <sound/tlv.h> | ||
24 | |||
25 | struct lm4857 { | ||
26 | struct i2c_client *i2c; | ||
27 | uint8_t mode; | ||
28 | }; | ||
29 | |||
30 | static const uint8_t lm4857_default_regs[] = { | ||
31 | 0x00, 0x00, 0x00, 0x00, | ||
32 | }; | ||
33 | |||
34 | /* The register offsets in the cache array */ | ||
35 | #define LM4857_MVOL 0 | ||
36 | #define LM4857_LVOL 1 | ||
37 | #define LM4857_RVOL 2 | ||
38 | #define LM4857_CTRL 3 | ||
39 | |||
40 | /* the shifts required to set these bits */ | ||
41 | #define LM4857_3D 5 | ||
42 | #define LM4857_WAKEUP 5 | ||
43 | #define LM4857_EPGAIN 4 | ||
44 | |||
45 | static int lm4857_write(struct snd_soc_codec *codec, unsigned int reg, | ||
46 | unsigned int value) | ||
47 | { | ||
48 | uint8_t data; | ||
49 | int ret; | ||
50 | |||
51 | ret = snd_soc_cache_write(codec, reg, value); | ||
52 | if (ret < 0) | ||
53 | return ret; | ||
54 | |||
55 | data = (reg << 6) | value; | ||
56 | ret = i2c_master_send(codec->control_data, &data, 1); | ||
57 | if (ret != 1) { | ||
58 | dev_err(codec->dev, "Failed to write register: %d\n", ret); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static unsigned int lm4857_read(struct snd_soc_codec *codec, | ||
66 | unsigned int reg) | ||
67 | { | ||
68 | unsigned int val; | ||
69 | int ret; | ||
70 | |||
71 | ret = snd_soc_cache_read(codec, reg, &val); | ||
72 | if (ret) | ||
73 | return -1; | ||
74 | |||
75 | return val; | ||
76 | } | ||
77 | |||
78 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | ||
79 | struct snd_ctl_elem_value *ucontrol) | ||
80 | { | ||
81 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
82 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
83 | |||
84 | ucontrol->value.integer.value[0] = lm4857->mode; | ||
85 | |||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | ||
90 | struct snd_ctl_elem_value *ucontrol) | ||
91 | { | ||
92 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
93 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
94 | uint8_t value = ucontrol->value.integer.value[0]; | ||
95 | |||
96 | lm4857->mode = value; | ||
97 | |||
98 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | ||
99 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, value + 6); | ||
100 | |||
101 | return 1; | ||
102 | } | ||
103 | |||
104 | static int lm4857_set_bias_level(struct snd_soc_codec *codec, | ||
105 | enum snd_soc_bias_level level) | ||
106 | { | ||
107 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
108 | |||
109 | switch (level) { | ||
110 | case SND_SOC_BIAS_ON: | ||
111 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, lm4857->mode + 6); | ||
112 | break; | ||
113 | case SND_SOC_BIAS_STANDBY: | ||
114 | snd_soc_update_bits(codec, LM4857_CTRL, 0x0F, 0); | ||
115 | break; | ||
116 | default: | ||
117 | break; | ||
118 | } | ||
119 | |||
120 | codec->dapm.bias_level = level; | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static const char *lm4857_mode[] = { | ||
126 | "Earpiece", | ||
127 | "Loudspeaker", | ||
128 | "Loudspeaker + Headphone", | ||
129 | "Headphone", | ||
130 | }; | ||
131 | |||
132 | static const struct soc_enum lm4857_mode_enum = | ||
133 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode); | ||
134 | |||
135 | static const struct snd_soc_dapm_widget lm4857_dapm_widgets[] = { | ||
136 | SND_SOC_DAPM_INPUT("IN"), | ||
137 | |||
138 | SND_SOC_DAPM_OUTPUT("LS"), | ||
139 | SND_SOC_DAPM_OUTPUT("HP"), | ||
140 | SND_SOC_DAPM_OUTPUT("EP"), | ||
141 | }; | ||
142 | |||
143 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | ||
144 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | ||
145 | |||
146 | static const struct snd_kcontrol_new lm4857_controls[] = { | ||
147 | SOC_SINGLE_TLV("Left Playback Volume", LM4857_LVOL, 0, 31, 0, | ||
148 | stereo_tlv), | ||
149 | SOC_SINGLE_TLV("Right Playback Volume", LM4857_RVOL, 0, 31, 0, | ||
150 | stereo_tlv), | ||
151 | SOC_SINGLE_TLV("Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | ||
152 | mono_tlv), | ||
153 | SOC_SINGLE("Spk 3D Playback Switch", LM4857_LVOL, LM4857_3D, 1, 0), | ||
154 | SOC_SINGLE("HP 3D Playback Switch", LM4857_RVOL, LM4857_3D, 1, 0), | ||
155 | SOC_SINGLE("Fast Wakeup Playback Switch", LM4857_CTRL, | ||
156 | LM4857_WAKEUP, 1, 0), | ||
157 | SOC_SINGLE("Earpiece 6dB Playback Switch", LM4857_CTRL, | ||
158 | LM4857_EPGAIN, 1, 0), | ||
159 | |||
160 | SOC_ENUM_EXT("Mode", lm4857_mode_enum, | ||
161 | lm4857_get_mode, lm4857_set_mode), | ||
162 | }; | ||
163 | |||
164 | /* There is a demux inbetween the the input signal and the output signals. | ||
165 | * Currently there is no easy way to model it in ASoC and since it does not make | ||
166 | * much of a difference in practice simply connect the input direclty to the | ||
167 | * outputs. */ | ||
168 | static const struct snd_soc_dapm_route lm4857_routes[] = { | ||
169 | {"LS", NULL, "IN"}, | ||
170 | {"HP", NULL, "IN"}, | ||
171 | {"EP", NULL, "IN"}, | ||
172 | }; | ||
173 | |||
174 | static int lm4857_probe(struct snd_soc_codec *codec) | ||
175 | { | ||
176 | struct lm4857 *lm4857 = snd_soc_codec_get_drvdata(codec); | ||
177 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
178 | int ret; | ||
179 | |||
180 | codec->control_data = lm4857->i2c; | ||
181 | |||
182 | ret = snd_soc_add_controls(codec, lm4857_controls, | ||
183 | ARRAY_SIZE(lm4857_controls)); | ||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | ret = snd_soc_dapm_new_controls(dapm, lm4857_dapm_widgets, | ||
188 | ARRAY_SIZE(lm4857_dapm_widgets)); | ||
189 | if (ret) | ||
190 | return ret; | ||
191 | |||
192 | ret = snd_soc_dapm_add_routes(dapm, lm4857_routes, | ||
193 | ARRAY_SIZE(lm4857_routes)); | ||
194 | if (ret) | ||
195 | return ret; | ||
196 | |||
197 | snd_soc_dapm_new_widgets(dapm); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static struct snd_soc_codec_driver soc_codec_dev_lm4857 = { | ||
203 | .write = lm4857_write, | ||
204 | .read = lm4857_read, | ||
205 | .probe = lm4857_probe, | ||
206 | .reg_cache_size = ARRAY_SIZE(lm4857_default_regs), | ||
207 | .reg_word_size = sizeof(uint8_t), | ||
208 | .reg_cache_default = lm4857_default_regs, | ||
209 | .set_bias_level = lm4857_set_bias_level, | ||
210 | }; | ||
211 | |||
212 | static int __devinit lm4857_i2c_probe(struct i2c_client *i2c, | ||
213 | const struct i2c_device_id *id) | ||
214 | { | ||
215 | struct lm4857 *lm4857; | ||
216 | int ret; | ||
217 | |||
218 | lm4857 = kzalloc(sizeof(*lm4857), GFP_KERNEL); | ||
219 | if (!lm4857) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | i2c_set_clientdata(i2c, lm4857); | ||
223 | |||
224 | lm4857->i2c = i2c; | ||
225 | |||
226 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_lm4857, NULL, 0); | ||
227 | |||
228 | if (ret) { | ||
229 | kfree(lm4857); | ||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int __devexit lm4857_i2c_remove(struct i2c_client *i2c) | ||
237 | { | ||
238 | struct lm4857 *lm4857 = i2c_get_clientdata(i2c); | ||
239 | |||
240 | snd_soc_unregister_codec(&i2c->dev); | ||
241 | kfree(lm4857); | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static const struct i2c_device_id lm4857_i2c_id[] = { | ||
247 | { "lm4857", 0 }, | ||
248 | { } | ||
249 | }; | ||
250 | MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); | ||
251 | |||
252 | static struct i2c_driver lm4857_i2c_driver = { | ||
253 | .driver = { | ||
254 | .name = "lm4857", | ||
255 | .owner = THIS_MODULE, | ||
256 | }, | ||
257 | .probe = lm4857_i2c_probe, | ||
258 | .remove = __devexit_p(lm4857_i2c_remove), | ||
259 | .id_table = lm4857_i2c_id, | ||
260 | }; | ||
261 | |||
262 | static int __init lm4857_init(void) | ||
263 | { | ||
264 | return i2c_add_driver(&lm4857_i2c_driver); | ||
265 | } | ||
266 | module_init(lm4857_init); | ||
267 | |||
268 | static void __exit lm4857_exit(void) | ||
269 | { | ||
270 | i2c_del_driver(&lm4857_i2c_driver); | ||
271 | } | ||
272 | module_exit(lm4857_exit); | ||
273 | |||
274 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
275 | MODULE_DESCRIPTION("LM4857 amplifier driver"); | ||
276 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index 89498f9ad2e5..bd0517cb7980 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -608,7 +608,7 @@ static struct { | |||
608 | { 0xFF, 0x00, 1 }, /* FF */ | 608 | { 0xFF, 0x00, 1 }, /* FF */ |
609 | }; | 609 | }; |
610 | 610 | ||
611 | static int max98088_volatile_register(unsigned int reg) | 611 | static int max98088_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
612 | { | 612 | { |
613 | return max98088_access[reg].vol; | 613 | return max98088_access[reg].vol; |
614 | } | 614 | } |
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c new file mode 100644 index 000000000000..208d2ee61855 --- /dev/null +++ b/sound/soc/codecs/max9850.c | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | * max9850.c -- codec driver for max9850 | ||
3 | * | ||
4 | * Copyright (C) 2011 taskit GmbH | ||
5 | * | ||
6 | * Author: Christian Glindkamp <christian.glindkamp@taskit.de> | ||
7 | * | ||
8 | * Initial development of this code was funded by | ||
9 | * MICRONIC Computer Systeme GmbH, http://www.mcsberlin.de/ | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/tlv.h> | ||
26 | |||
27 | #include "max9850.h" | ||
28 | |||
29 | struct max9850_priv { | ||
30 | unsigned int sysclk; | ||
31 | }; | ||
32 | |||
33 | /* max9850 register cache */ | ||
34 | static const u8 max9850_reg[MAX9850_CACHEREGNUM] = { | ||
35 | 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
36 | }; | ||
37 | |||
38 | /* these registers are not used at the moment but provided for the sake of | ||
39 | * completeness */ | ||
40 | static int max9850_volatile_register(struct snd_soc_codec *codec, | ||
41 | unsigned int reg) | ||
42 | { | ||
43 | switch (reg) { | ||
44 | case MAX9850_STATUSA: | ||
45 | case MAX9850_STATUSB: | ||
46 | return 1; | ||
47 | default: | ||
48 | return 0; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | static const unsigned int max9850_tlv[] = { | ||
53 | TLV_DB_RANGE_HEAD(4), | ||
54 | 0x18, 0x1f, TLV_DB_SCALE_ITEM(-7450, 400, 0), | ||
55 | 0x20, 0x33, TLV_DB_SCALE_ITEM(-4150, 200, 0), | ||
56 | 0x34, 0x37, TLV_DB_SCALE_ITEM(-150, 100, 0), | ||
57 | 0x38, 0x3f, TLV_DB_SCALE_ITEM(250, 50, 0), | ||
58 | }; | ||
59 | |||
60 | static const struct snd_kcontrol_new max9850_controls[] = { | ||
61 | SOC_SINGLE_TLV("Headphone Volume", MAX9850_VOLUME, 0, 0x3f, 1, max9850_tlv), | ||
62 | SOC_SINGLE("Headphone Switch", MAX9850_VOLUME, 7, 1, 1), | ||
63 | SOC_SINGLE("Mono Switch", MAX9850_GENERAL_PURPOSE, 2, 1, 0), | ||
64 | }; | ||
65 | |||
66 | static const struct snd_kcontrol_new max9850_mixer_controls[] = { | ||
67 | SOC_DAPM_SINGLE("Line In Switch", MAX9850_ENABLE, 1, 1, 0), | ||
68 | }; | ||
69 | |||
70 | static const struct snd_soc_dapm_widget max9850_dapm_widgets[] = { | ||
71 | SND_SOC_DAPM_SUPPLY("Charge Pump 1", MAX9850_ENABLE, 4, 0, NULL, 0), | ||
72 | SND_SOC_DAPM_SUPPLY("Charge Pump 2", MAX9850_ENABLE, 5, 0, NULL, 0), | ||
73 | SND_SOC_DAPM_SUPPLY("MCLK", MAX9850_ENABLE, 6, 0, NULL, 0), | ||
74 | SND_SOC_DAPM_SUPPLY("SHDN", MAX9850_ENABLE, 7, 0, NULL, 0), | ||
75 | SND_SOC_DAPM_MIXER_NAMED_CTL("Output Mixer", MAX9850_ENABLE, 2, 0, | ||
76 | &max9850_mixer_controls[0], | ||
77 | ARRAY_SIZE(max9850_mixer_controls)), | ||
78 | SND_SOC_DAPM_PGA("Headphone Output", MAX9850_ENABLE, 3, 0, NULL, 0), | ||
79 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", MAX9850_ENABLE, 0, 0), | ||
80 | SND_SOC_DAPM_OUTPUT("OUTL"), | ||
81 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
82 | SND_SOC_DAPM_OUTPUT("OUTR"), | ||
83 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
84 | SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
85 | SND_SOC_DAPM_INPUT("INL"), | ||
86 | SND_SOC_DAPM_INPUT("INR"), | ||
87 | }; | ||
88 | |||
89 | static const struct snd_soc_dapm_route intercon[] = { | ||
90 | /* output mixer */ | ||
91 | {"Output Mixer", NULL, "DAC"}, | ||
92 | {"Output Mixer", "Line In Switch", "Line Input"}, | ||
93 | |||
94 | /* outputs */ | ||
95 | {"Headphone Output", NULL, "Output Mixer"}, | ||
96 | {"HPL", NULL, "Headphone Output"}, | ||
97 | {"HPR", NULL, "Headphone Output"}, | ||
98 | {"OUTL", NULL, "Output Mixer"}, | ||
99 | {"OUTR", NULL, "Output Mixer"}, | ||
100 | |||
101 | /* inputs */ | ||
102 | {"Line Input", NULL, "INL"}, | ||
103 | {"Line Input", NULL, "INR"}, | ||
104 | |||
105 | /* supplies */ | ||
106 | {"Output Mixer", NULL, "Charge Pump 1"}, | ||
107 | {"Output Mixer", NULL, "Charge Pump 2"}, | ||
108 | {"Output Mixer", NULL, "SHDN"}, | ||
109 | {"DAC", NULL, "MCLK"}, | ||
110 | }; | ||
111 | |||
112 | static int max9850_hw_params(struct snd_pcm_substream *substream, | ||
113 | struct snd_pcm_hw_params *params, | ||
114 | struct snd_soc_dai *dai) | ||
115 | { | ||
116 | struct snd_soc_codec *codec = dai->codec; | ||
117 | struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec); | ||
118 | u64 lrclk_div; | ||
119 | u8 sf, da; | ||
120 | |||
121 | if (!max9850->sysclk) | ||
122 | return -EINVAL; | ||
123 | |||
124 | /* lrclk_div = 2^22 * rate / iclk with iclk = mclk / sf */ | ||
125 | sf = (snd_soc_read(codec, MAX9850_CLOCK) >> 2) + 1; | ||
126 | lrclk_div = (1 << 22); | ||
127 | lrclk_div *= params_rate(params); | ||
128 | lrclk_div *= sf; | ||
129 | do_div(lrclk_div, max9850->sysclk); | ||
130 | |||
131 | snd_soc_write(codec, MAX9850_LRCLK_MSB, (lrclk_div >> 8) & 0x7f); | ||
132 | snd_soc_write(codec, MAX9850_LRCLK_LSB, lrclk_div & 0xff); | ||
133 | |||
134 | switch (params_format(params)) { | ||
135 | case SNDRV_PCM_FORMAT_S16_LE: | ||
136 | da = 0; | ||
137 | break; | ||
138 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
139 | da = 0x2; | ||
140 | break; | ||
141 | case SNDRV_PCM_FORMAT_S24_LE: | ||
142 | da = 0x3; | ||
143 | break; | ||
144 | default: | ||
145 | return -EINVAL; | ||
146 | } | ||
147 | snd_soc_update_bits(codec, MAX9850_DIGITAL_AUDIO, 0x3, da); | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static int max9850_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
153 | int clk_id, unsigned int freq, int dir) | ||
154 | { | ||
155 | struct snd_soc_codec *codec = codec_dai->codec; | ||
156 | struct max9850_priv *max9850 = snd_soc_codec_get_drvdata(codec); | ||
157 | |||
158 | /* calculate mclk -> iclk divider */ | ||
159 | if (freq <= 13000000) | ||
160 | snd_soc_write(codec, MAX9850_CLOCK, 0x0); | ||
161 | else if (freq <= 26000000) | ||
162 | snd_soc_write(codec, MAX9850_CLOCK, 0x4); | ||
163 | else if (freq <= 40000000) | ||
164 | snd_soc_write(codec, MAX9850_CLOCK, 0x8); | ||
165 | else | ||
166 | return -EINVAL; | ||
167 | |||
168 | max9850->sysclk = freq; | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static int max9850_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
173 | { | ||
174 | struct snd_soc_codec *codec = codec_dai->codec; | ||
175 | u8 da = 0; | ||
176 | |||
177 | /* set master/slave audio interface */ | ||
178 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
179 | case SND_SOC_DAIFMT_CBM_CFM: | ||
180 | da |= MAX9850_MASTER; | ||
181 | break; | ||
182 | case SND_SOC_DAIFMT_CBS_CFS: | ||
183 | break; | ||
184 | default: | ||
185 | return -EINVAL; | ||
186 | } | ||
187 | |||
188 | /* interface format */ | ||
189 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
190 | case SND_SOC_DAIFMT_I2S: | ||
191 | da |= MAX9850_DLY; | ||
192 | break; | ||
193 | case SND_SOC_DAIFMT_RIGHT_J: | ||
194 | da |= MAX9850_RTJ; | ||
195 | break; | ||
196 | case SND_SOC_DAIFMT_LEFT_J: | ||
197 | break; | ||
198 | default: | ||
199 | return -EINVAL; | ||
200 | } | ||
201 | |||
202 | /* clock inversion */ | ||
203 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
204 | case SND_SOC_DAIFMT_NB_NF: | ||
205 | break; | ||
206 | case SND_SOC_DAIFMT_IB_IF: | ||
207 | da |= MAX9850_BCINV | MAX9850_INV; | ||
208 | break; | ||
209 | case SND_SOC_DAIFMT_IB_NF: | ||
210 | da |= MAX9850_BCINV; | ||
211 | break; | ||
212 | case SND_SOC_DAIFMT_NB_IF: | ||
213 | da |= MAX9850_INV; | ||
214 | break; | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | /* set da */ | ||
220 | snd_soc_write(codec, MAX9850_DIGITAL_AUDIO, da); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int max9850_set_bias_level(struct snd_soc_codec *codec, | ||
226 | enum snd_soc_bias_level level) | ||
227 | { | ||
228 | int ret; | ||
229 | |||
230 | switch (level) { | ||
231 | case SND_SOC_BIAS_ON: | ||
232 | break; | ||
233 | case SND_SOC_BIAS_PREPARE: | ||
234 | break; | ||
235 | case SND_SOC_BIAS_STANDBY: | ||
236 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
237 | ret = snd_soc_cache_sync(codec); | ||
238 | if (ret) { | ||
239 | dev_err(codec->dev, | ||
240 | "Failed to sync cache: %d\n", ret); | ||
241 | return ret; | ||
242 | } | ||
243 | } | ||
244 | break; | ||
245 | case SND_SOC_BIAS_OFF: | ||
246 | break; | ||
247 | } | ||
248 | codec->dapm.bias_level = level; | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | #define MAX9850_RATES SNDRV_PCM_RATE_8000_48000 | ||
253 | |||
254 | #define MAX9850_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
255 | SNDRV_PCM_FMTBIT_S24_LE) | ||
256 | |||
257 | static struct snd_soc_dai_ops max9850_dai_ops = { | ||
258 | .hw_params = max9850_hw_params, | ||
259 | .set_sysclk = max9850_set_dai_sysclk, | ||
260 | .set_fmt = max9850_set_dai_fmt, | ||
261 | }; | ||
262 | |||
263 | static struct snd_soc_dai_driver max9850_dai = { | ||
264 | .name = "max9850-hifi", | ||
265 | .playback = { | ||
266 | .stream_name = "Playback", | ||
267 | .channels_min = 1, | ||
268 | .channels_max = 2, | ||
269 | .rates = MAX9850_RATES, | ||
270 | .formats = MAX9850_FORMATS | ||
271 | }, | ||
272 | .ops = &max9850_dai_ops, | ||
273 | }; | ||
274 | |||
275 | #ifdef CONFIG_PM | ||
276 | static int max9850_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
277 | { | ||
278 | max9850_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
279 | |||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int max9850_resume(struct snd_soc_codec *codec) | ||
284 | { | ||
285 | max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
286 | |||
287 | return 0; | ||
288 | } | ||
289 | #else | ||
290 | #define max9850_suspend NULL | ||
291 | #define max9850_resume NULL | ||
292 | #endif | ||
293 | |||
294 | static int max9850_probe(struct snd_soc_codec *codec) | ||
295 | { | ||
296 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
297 | int ret; | ||
298 | |||
299 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
300 | if (ret < 0) { | ||
301 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
302 | return ret; | ||
303 | } | ||
304 | |||
305 | /* enable zero-detect */ | ||
306 | snd_soc_update_bits(codec, MAX9850_GENERAL_PURPOSE, 1, 1); | ||
307 | /* enable slew-rate control */ | ||
308 | snd_soc_update_bits(codec, MAX9850_VOLUME, 0x40, 0x40); | ||
309 | /* set slew-rate 125ms */ | ||
310 | snd_soc_update_bits(codec, MAX9850_CHARGE_PUMP, 0xff, 0xc0); | ||
311 | |||
312 | snd_soc_dapm_new_controls(dapm, max9850_dapm_widgets, | ||
313 | ARRAY_SIZE(max9850_dapm_widgets)); | ||
314 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
315 | |||
316 | snd_soc_add_controls(codec, max9850_controls, | ||
317 | ARRAY_SIZE(max9850_controls)); | ||
318 | |||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | static struct snd_soc_codec_driver soc_codec_dev_max9850 = { | ||
323 | .probe = max9850_probe, | ||
324 | .suspend = max9850_suspend, | ||
325 | .resume = max9850_resume, | ||
326 | .set_bias_level = max9850_set_bias_level, | ||
327 | .reg_cache_size = ARRAY_SIZE(max9850_reg), | ||
328 | .reg_word_size = sizeof(u8), | ||
329 | .reg_cache_default = max9850_reg, | ||
330 | .volatile_register = max9850_volatile_register, | ||
331 | }; | ||
332 | |||
333 | static int __devinit max9850_i2c_probe(struct i2c_client *i2c, | ||
334 | const struct i2c_device_id *id) | ||
335 | { | ||
336 | struct max9850_priv *max9850; | ||
337 | int ret; | ||
338 | |||
339 | max9850 = kzalloc(sizeof(struct max9850_priv), GFP_KERNEL); | ||
340 | if (max9850 == NULL) | ||
341 | return -ENOMEM; | ||
342 | |||
343 | i2c_set_clientdata(i2c, max9850); | ||
344 | |||
345 | ret = snd_soc_register_codec(&i2c->dev, | ||
346 | &soc_codec_dev_max9850, &max9850_dai, 1); | ||
347 | if (ret < 0) | ||
348 | kfree(max9850); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | static __devexit int max9850_i2c_remove(struct i2c_client *client) | ||
353 | { | ||
354 | snd_soc_unregister_codec(&client->dev); | ||
355 | kfree(i2c_get_clientdata(client)); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | static const struct i2c_device_id max9850_i2c_id[] = { | ||
360 | { "max9850", 0 }, | ||
361 | { } | ||
362 | }; | ||
363 | MODULE_DEVICE_TABLE(i2c, max9850_i2c_id); | ||
364 | |||
365 | static struct i2c_driver max9850_i2c_driver = { | ||
366 | .driver = { | ||
367 | .name = "max9850", | ||
368 | .owner = THIS_MODULE, | ||
369 | }, | ||
370 | .probe = max9850_i2c_probe, | ||
371 | .remove = __devexit_p(max9850_i2c_remove), | ||
372 | .id_table = max9850_i2c_id, | ||
373 | }; | ||
374 | |||
375 | static int __init max9850_init(void) | ||
376 | { | ||
377 | return i2c_add_driver(&max9850_i2c_driver); | ||
378 | } | ||
379 | module_init(max9850_init); | ||
380 | |||
381 | static void __exit max9850_exit(void) | ||
382 | { | ||
383 | i2c_del_driver(&max9850_i2c_driver); | ||
384 | } | ||
385 | module_exit(max9850_exit); | ||
386 | |||
387 | MODULE_AUTHOR("Christian Glindkamp <christian.glindkamp@taskit.de>"); | ||
388 | MODULE_DESCRIPTION("ASoC MAX9850 codec driver"); | ||
389 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/max9850.h b/sound/soc/codecs/max9850.h new file mode 100644 index 000000000000..72b1ddb04b0d --- /dev/null +++ b/sound/soc/codecs/max9850.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | * max9850.h -- codec driver for max9850 | ||
3 | * | ||
4 | * Copyright (C) 2011 taskit GmbH | ||
5 | * Author: Christian Glindkamp <christian.glindkamp@taskit.de> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _MAX9850_H | ||
15 | #define _MAX9850_H | ||
16 | |||
17 | #define MAX9850_STATUSA 0x00 | ||
18 | #define MAX9850_STATUSB 0x01 | ||
19 | #define MAX9850_VOLUME 0x02 | ||
20 | #define MAX9850_GENERAL_PURPOSE 0x03 | ||
21 | #define MAX9850_INTERRUPT 0x04 | ||
22 | #define MAX9850_ENABLE 0x05 | ||
23 | #define MAX9850_CLOCK 0x06 | ||
24 | #define MAX9850_CHARGE_PUMP 0x07 | ||
25 | #define MAX9850_LRCLK_MSB 0x08 | ||
26 | #define MAX9850_LRCLK_LSB 0x09 | ||
27 | #define MAX9850_DIGITAL_AUDIO 0x0a | ||
28 | |||
29 | #define MAX9850_CACHEREGNUM 11 | ||
30 | |||
31 | /* MAX9850_DIGITAL_AUDIO */ | ||
32 | #define MAX9850_MASTER (1<<7) | ||
33 | #define MAX9850_INV (1<<6) | ||
34 | #define MAX9850_BCINV (1<<5) | ||
35 | #define MAX9850_DLY (1<<3) | ||
36 | #define MAX9850_RTJ (1<<2) | ||
37 | |||
38 | #endif | ||
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c new file mode 100644 index 000000000000..1f7217f703ee --- /dev/null +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -0,0 +1,1513 @@ | |||
1 | /* | ||
2 | * sgtl5000.c -- SGTL5000 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2010-2011 Freescale Semiconductor, Inc. All Rights Reserved. | ||
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/module.h> | ||
12 | #include <linux/moduleparam.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/pm.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/clk.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/regulator/driver.h> | ||
21 | #include <linux/regulator/machine.h> | ||
22 | #include <linux/regulator/consumer.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/tlv.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dapm.h> | ||
29 | #include <sound/initval.h> | ||
30 | |||
31 | #include "sgtl5000.h" | ||
32 | |||
33 | #define SGTL5000_DAP_REG_OFFSET 0x0100 | ||
34 | #define SGTL5000_MAX_REG_OFFSET 0x013A | ||
35 | |||
36 | /* default value of sgtl5000 registers except DAP */ | ||
37 | static const u16 sgtl5000_regs[SGTL5000_MAX_REG_OFFSET >> 1] = { | ||
38 | 0xa011, /* 0x0000, CHIP_ID. 11 stand for revison 17 */ | ||
39 | 0x0000, /* 0x0002, CHIP_DIG_POWER. */ | ||
40 | 0x0008, /* 0x0004, CHIP_CKL_CTRL */ | ||
41 | 0x0010, /* 0x0006, CHIP_I2S_CTRL */ | ||
42 | 0x0000, /* 0x0008, reserved */ | ||
43 | 0x0008, /* 0x000A, CHIP_SSS_CTRL */ | ||
44 | 0x0000, /* 0x000C, reserved */ | ||
45 | 0x020c, /* 0x000E, CHIP_ADCDAC_CTRL */ | ||
46 | 0x3c3c, /* 0x0010, CHIP_DAC_VOL */ | ||
47 | 0x0000, /* 0x0012, reserved */ | ||
48 | 0x015f, /* 0x0014, CHIP_PAD_STRENGTH */ | ||
49 | 0x0000, /* 0x0016, reserved */ | ||
50 | 0x0000, /* 0x0018, reserved */ | ||
51 | 0x0000, /* 0x001A, reserved */ | ||
52 | 0x0000, /* 0x001E, reserved */ | ||
53 | 0x0000, /* 0x0020, CHIP_ANA_ADC_CTRL */ | ||
54 | 0x1818, /* 0x0022, CHIP_ANA_HP_CTRL */ | ||
55 | 0x0111, /* 0x0024, CHIP_ANN_CTRL */ | ||
56 | 0x0000, /* 0x0026, CHIP_LINREG_CTRL */ | ||
57 | 0x0000, /* 0x0028, CHIP_REF_CTRL */ | ||
58 | 0x0000, /* 0x002A, CHIP_MIC_CTRL */ | ||
59 | 0x0000, /* 0x002C, CHIP_LINE_OUT_CTRL */ | ||
60 | 0x0404, /* 0x002E, CHIP_LINE_OUT_VOL */ | ||
61 | 0x7060, /* 0x0030, CHIP_ANA_POWER */ | ||
62 | 0x5000, /* 0x0032, CHIP_PLL_CTRL */ | ||
63 | 0x0000, /* 0x0034, CHIP_CLK_TOP_CTRL */ | ||
64 | 0x0000, /* 0x0036, CHIP_ANA_STATUS */ | ||
65 | 0x0000, /* 0x0038, reserved */ | ||
66 | 0x0000, /* 0x003A, CHIP_ANA_TEST2 */ | ||
67 | 0x0000, /* 0x003C, CHIP_SHORT_CTRL */ | ||
68 | 0x0000, /* reserved */ | ||
69 | }; | ||
70 | |||
71 | /* default value of dap registers */ | ||
72 | static const u16 sgtl5000_dap_regs[] = { | ||
73 | 0x0000, /* 0x0100, DAP_CONTROL */ | ||
74 | 0x0000, /* 0x0102, DAP_PEQ */ | ||
75 | 0x0040, /* 0x0104, DAP_BASS_ENHANCE */ | ||
76 | 0x051f, /* 0x0106, DAP_BASS_ENHANCE_CTRL */ | ||
77 | 0x0000, /* 0x0108, DAP_AUDIO_EQ */ | ||
78 | 0x0040, /* 0x010A, DAP_SGTL_SURROUND */ | ||
79 | 0x0000, /* 0x010C, DAP_FILTER_COEF_ACCESS */ | ||
80 | 0x0000, /* 0x010E, DAP_COEF_WR_B0_MSB */ | ||
81 | 0x0000, /* 0x0110, DAP_COEF_WR_B0_LSB */ | ||
82 | 0x0000, /* 0x0112, reserved */ | ||
83 | 0x0000, /* 0x0114, reserved */ | ||
84 | 0x002f, /* 0x0116, DAP_AUDIO_EQ_BASS_BAND0 */ | ||
85 | 0x002f, /* 0x0118, DAP_AUDIO_EQ_BAND0 */ | ||
86 | 0x002f, /* 0x011A, DAP_AUDIO_EQ_BAND2 */ | ||
87 | 0x002f, /* 0x011C, DAP_AUDIO_EQ_BAND3 */ | ||
88 | 0x002f, /* 0x011E, DAP_AUDIO_EQ_TREBLE_BAND4 */ | ||
89 | 0x8000, /* 0x0120, DAP_MAIN_CHAN */ | ||
90 | 0x0000, /* 0x0122, DAP_MIX_CHAN */ | ||
91 | 0x0510, /* 0x0124, DAP_AVC_CTRL */ | ||
92 | 0x1473, /* 0x0126, DAP_AVC_THRESHOLD */ | ||
93 | 0x0028, /* 0x0128, DAP_AVC_ATTACK */ | ||
94 | 0x0050, /* 0x012A, DAP_AVC_DECAY */ | ||
95 | 0x0000, /* 0x012C, DAP_COEF_WR_B1_MSB */ | ||
96 | 0x0000, /* 0x012E, DAP_COEF_WR_B1_LSB */ | ||
97 | 0x0000, /* 0x0130, DAP_COEF_WR_B2_MSB */ | ||
98 | 0x0000, /* 0x0132, DAP_COEF_WR_B2_LSB */ | ||
99 | 0x0000, /* 0x0134, DAP_COEF_WR_A1_MSB */ | ||
100 | 0x0000, /* 0x0136, DAP_COEF_WR_A1_LSB */ | ||
101 | 0x0000, /* 0x0138, DAP_COEF_WR_A2_MSB */ | ||
102 | 0x0000, /* 0x013A, DAP_COEF_WR_A2_LSB */ | ||
103 | }; | ||
104 | |||
105 | /* regulator supplies for sgtl5000, VDDD is an optional external supply */ | ||
106 | enum sgtl5000_regulator_supplies { | ||
107 | VDDA, | ||
108 | VDDIO, | ||
109 | VDDD, | ||
110 | SGTL5000_SUPPLY_NUM | ||
111 | }; | ||
112 | |||
113 | /* vddd is optional supply */ | ||
114 | static const char *supply_names[SGTL5000_SUPPLY_NUM] = { | ||
115 | "VDDA", | ||
116 | "VDDIO", | ||
117 | "VDDD" | ||
118 | }; | ||
119 | |||
120 | #define LDO_CONSUMER_NAME "VDDD_LDO" | ||
121 | #define LDO_VOLTAGE 1200000 | ||
122 | |||
123 | static struct regulator_consumer_supply ldo_consumer[] = { | ||
124 | REGULATOR_SUPPLY(LDO_CONSUMER_NAME, NULL), | ||
125 | }; | ||
126 | |||
127 | static struct regulator_init_data ldo_init_data = { | ||
128 | .constraints = { | ||
129 | .min_uV = 850000, | ||
130 | .max_uV = 1600000, | ||
131 | .valid_modes_mask = REGULATOR_MODE_NORMAL, | ||
132 | .valid_ops_mask = REGULATOR_CHANGE_STATUS, | ||
133 | }, | ||
134 | .num_consumer_supplies = 1, | ||
135 | .consumer_supplies = &ldo_consumer[0], | ||
136 | }; | ||
137 | |||
138 | /* | ||
139 | * sgtl5000 internal ldo regulator, | ||
140 | * enabled when VDDD not provided | ||
141 | */ | ||
142 | struct ldo_regulator { | ||
143 | struct regulator_desc desc; | ||
144 | struct regulator_dev *dev; | ||
145 | int voltage; | ||
146 | void *codec_data; | ||
147 | bool enabled; | ||
148 | }; | ||
149 | |||
150 | /* sgtl5000 private structure in codec */ | ||
151 | struct sgtl5000_priv { | ||
152 | int sysclk; /* sysclk rate */ | ||
153 | int master; /* i2s master or not */ | ||
154 | int fmt; /* i2s data format */ | ||
155 | struct regulator_bulk_data supplies[SGTL5000_SUPPLY_NUM]; | ||
156 | struct ldo_regulator *ldo; | ||
157 | }; | ||
158 | |||
159 | /* | ||
160 | * mic_bias power on/off share the same register bits with | ||
161 | * output impedance of mic bias, when power on mic bias, we | ||
162 | * need reclaim it to impedance value. | ||
163 | * 0x0 = Powered off | ||
164 | * 0x1 = 2Kohm | ||
165 | * 0x2 = 4Kohm | ||
166 | * 0x3 = 8Kohm | ||
167 | */ | ||
168 | static int mic_bias_event(struct snd_soc_dapm_widget *w, | ||
169 | struct snd_kcontrol *kcontrol, int event) | ||
170 | { | ||
171 | switch (event) { | ||
172 | case SND_SOC_DAPM_POST_PMU: | ||
173 | /* change mic bias resistor to 4Kohm */ | ||
174 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, | ||
175 | SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k); | ||
176 | break; | ||
177 | |||
178 | case SND_SOC_DAPM_PRE_PMD: | ||
179 | /* | ||
180 | * SGTL5000_BIAS_R_8k as mask to clean the two bits | ||
181 | * of mic bias and output impedance | ||
182 | */ | ||
183 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, | ||
184 | SGTL5000_BIAS_R_8k, 0); | ||
185 | break; | ||
186 | } | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | /* | ||
191 | * using codec assist to small pop, hp_powerup or lineout_powerup | ||
192 | * should stay setting until vag_powerup is fully ramped down, | ||
193 | * vag fully ramped down require 400ms. | ||
194 | */ | ||
195 | static int small_pop_event(struct snd_soc_dapm_widget *w, | ||
196 | struct snd_kcontrol *kcontrol, int event) | ||
197 | { | ||
198 | switch (event) { | ||
199 | case SND_SOC_DAPM_PRE_PMU: | ||
200 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, | ||
201 | SGTL5000_VAG_POWERUP, SGTL5000_VAG_POWERUP); | ||
202 | break; | ||
203 | |||
204 | case SND_SOC_DAPM_PRE_PMD: | ||
205 | snd_soc_update_bits(w->codec, SGTL5000_CHIP_ANA_POWER, | ||
206 | SGTL5000_VAG_POWERUP, 0); | ||
207 | msleep(400); | ||
208 | break; | ||
209 | default: | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | /* input sources for ADC */ | ||
217 | static const char *adc_mux_text[] = { | ||
218 | "MIC_IN", "LINE_IN" | ||
219 | }; | ||
220 | |||
221 | static const struct soc_enum adc_enum = | ||
222 | SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 2, 2, adc_mux_text); | ||
223 | |||
224 | static const struct snd_kcontrol_new adc_mux = | ||
225 | SOC_DAPM_ENUM("Capture Mux", adc_enum); | ||
226 | |||
227 | /* input sources for DAC */ | ||
228 | static const char *dac_mux_text[] = { | ||
229 | "DAC", "LINE_IN" | ||
230 | }; | ||
231 | |||
232 | static const struct soc_enum dac_enum = | ||
233 | SOC_ENUM_SINGLE(SGTL5000_CHIP_ANA_CTRL, 6, 2, dac_mux_text); | ||
234 | |||
235 | static const struct snd_kcontrol_new dac_mux = | ||
236 | SOC_DAPM_ENUM("Headphone Mux", dac_enum); | ||
237 | |||
238 | static const struct snd_soc_dapm_widget sgtl5000_dapm_widgets[] = { | ||
239 | SND_SOC_DAPM_INPUT("LINE_IN"), | ||
240 | SND_SOC_DAPM_INPUT("MIC_IN"), | ||
241 | |||
242 | SND_SOC_DAPM_OUTPUT("HP_OUT"), | ||
243 | SND_SOC_DAPM_OUTPUT("LINE_OUT"), | ||
244 | |||
245 | SND_SOC_DAPM_MICBIAS_E("Mic Bias", SGTL5000_CHIP_MIC_CTRL, 8, 0, | ||
246 | mic_bias_event, | ||
247 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
248 | |||
249 | SND_SOC_DAPM_PGA_E("HP", SGTL5000_CHIP_ANA_POWER, 4, 0, NULL, 0, | ||
250 | small_pop_event, | ||
251 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), | ||
252 | SND_SOC_DAPM_PGA_E("LO", SGTL5000_CHIP_ANA_POWER, 0, 0, NULL, 0, | ||
253 | small_pop_event, | ||
254 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), | ||
255 | |||
256 | SND_SOC_DAPM_MUX("Capture Mux", SND_SOC_NOPM, 0, 0, &adc_mux), | ||
257 | SND_SOC_DAPM_MUX("Headphone Mux", SND_SOC_NOPM, 0, 0, &dac_mux), | ||
258 | |||
259 | /* aif for i2s input */ | ||
260 | SND_SOC_DAPM_AIF_IN("AIFIN", "Playback", | ||
261 | 0, SGTL5000_CHIP_DIG_POWER, | ||
262 | 0, 0), | ||
263 | |||
264 | /* aif for i2s output */ | ||
265 | SND_SOC_DAPM_AIF_OUT("AIFOUT", "Capture", | ||
266 | 0, SGTL5000_CHIP_DIG_POWER, | ||
267 | 1, 0), | ||
268 | |||
269 | SND_SOC_DAPM_ADC("ADC", "Capture", SGTL5000_CHIP_ANA_POWER, 1, 0), | ||
270 | |||
271 | SND_SOC_DAPM_DAC("DAC", "Playback", SGTL5000_CHIP_ANA_POWER, 3, 0), | ||
272 | }; | ||
273 | |||
274 | /* routes for sgtl5000 */ | ||
275 | static const struct snd_soc_dapm_route audio_map[] = { | ||
276 | {"Capture Mux", "LINE_IN", "LINE_IN"}, /* line_in --> adc_mux */ | ||
277 | {"Capture Mux", "MIC_IN", "MIC_IN"}, /* mic_in --> adc_mux */ | ||
278 | |||
279 | {"ADC", NULL, "Capture Mux"}, /* adc_mux --> adc */ | ||
280 | {"AIFOUT", NULL, "ADC"}, /* adc --> i2s_out */ | ||
281 | |||
282 | {"DAC", NULL, "AIFIN"}, /* i2s-->dac,skip audio mux */ | ||
283 | {"Headphone Mux", "DAC", "DAC"}, /* dac --> hp_mux */ | ||
284 | {"LO", NULL, "DAC"}, /* dac --> line_out */ | ||
285 | |||
286 | {"Headphone Mux", "LINE_IN", "LINE_IN"},/* line_in --> hp_mux */ | ||
287 | {"HP", NULL, "Headphone Mux"}, /* hp_mux --> hp */ | ||
288 | |||
289 | {"LINE_OUT", NULL, "LO"}, | ||
290 | {"HP_OUT", NULL, "HP"}, | ||
291 | }; | ||
292 | |||
293 | /* custom function to fetch info of PCM playback volume */ | ||
294 | static int dac_info_volsw(struct snd_kcontrol *kcontrol, | ||
295 | struct snd_ctl_elem_info *uinfo) | ||
296 | { | ||
297 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
298 | uinfo->count = 2; | ||
299 | uinfo->value.integer.min = 0; | ||
300 | uinfo->value.integer.max = 0xfc - 0x3c; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * custom function to get of PCM playback volume | ||
306 | * | ||
307 | * dac volume register | ||
308 | * 15-------------8-7--------------0 | ||
309 | * | R channel vol | L channel vol | | ||
310 | * ------------------------------- | ||
311 | * | ||
312 | * PCM volume with 0.5017 dB steps from 0 to -90 dB | ||
313 | * | ||
314 | * register values map to dB | ||
315 | * 0x3B and less = Reserved | ||
316 | * 0x3C = 0 dB | ||
317 | * 0x3D = -0.5 dB | ||
318 | * 0xF0 = -90 dB | ||
319 | * 0xFC and greater = Muted | ||
320 | * | ||
321 | * register value map to userspace value | ||
322 | * | ||
323 | * register value 0x3c(0dB) 0xf0(-90dB)0xfc | ||
324 | * ------------------------------ | ||
325 | * userspace value 0xc0 0 | ||
326 | */ | ||
327 | static int dac_get_volsw(struct snd_kcontrol *kcontrol, | ||
328 | struct snd_ctl_elem_value *ucontrol) | ||
329 | { | ||
330 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
331 | int reg; | ||
332 | int l; | ||
333 | int r; | ||
334 | |||
335 | reg = snd_soc_read(codec, SGTL5000_CHIP_DAC_VOL); | ||
336 | |||
337 | /* get left channel volume */ | ||
338 | l = (reg & SGTL5000_DAC_VOL_LEFT_MASK) >> SGTL5000_DAC_VOL_LEFT_SHIFT; | ||
339 | |||
340 | /* get right channel volume */ | ||
341 | r = (reg & SGTL5000_DAC_VOL_RIGHT_MASK) >> SGTL5000_DAC_VOL_RIGHT_SHIFT; | ||
342 | |||
343 | /* make sure value fall in (0x3c,0xfc) */ | ||
344 | l = clamp(l, 0x3c, 0xfc); | ||
345 | r = clamp(r, 0x3c, 0xfc); | ||
346 | |||
347 | /* invert it and map to userspace value */ | ||
348 | l = 0xfc - l; | ||
349 | r = 0xfc - r; | ||
350 | |||
351 | ucontrol->value.integer.value[0] = l; | ||
352 | ucontrol->value.integer.value[1] = r; | ||
353 | |||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | /* | ||
358 | * custom function to put of PCM playback volume | ||
359 | * | ||
360 | * dac volume register | ||
361 | * 15-------------8-7--------------0 | ||
362 | * | R channel vol | L channel vol | | ||
363 | * ------------------------------- | ||
364 | * | ||
365 | * PCM volume with 0.5017 dB steps from 0 to -90 dB | ||
366 | * | ||
367 | * register values map to dB | ||
368 | * 0x3B and less = Reserved | ||
369 | * 0x3C = 0 dB | ||
370 | * 0x3D = -0.5 dB | ||
371 | * 0xF0 = -90 dB | ||
372 | * 0xFC and greater = Muted | ||
373 | * | ||
374 | * userspace value map to register value | ||
375 | * | ||
376 | * userspace value 0xc0 0 | ||
377 | * ------------------------------ | ||
378 | * register value 0x3c(0dB) 0xf0(-90dB)0xfc | ||
379 | */ | ||
380 | static int dac_put_volsw(struct snd_kcontrol *kcontrol, | ||
381 | struct snd_ctl_elem_value *ucontrol) | ||
382 | { | ||
383 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
384 | int reg; | ||
385 | int l; | ||
386 | int r; | ||
387 | |||
388 | l = ucontrol->value.integer.value[0]; | ||
389 | r = ucontrol->value.integer.value[1]; | ||
390 | |||
391 | /* make sure userspace volume fall in (0, 0xfc-0x3c) */ | ||
392 | l = clamp(l, 0, 0xfc - 0x3c); | ||
393 | r = clamp(r, 0, 0xfc - 0x3c); | ||
394 | |||
395 | /* invert it, get the value can be set to register */ | ||
396 | l = 0xfc - l; | ||
397 | r = 0xfc - r; | ||
398 | |||
399 | /* shift to get the register value */ | ||
400 | reg = l << SGTL5000_DAC_VOL_LEFT_SHIFT | | ||
401 | r << SGTL5000_DAC_VOL_RIGHT_SHIFT; | ||
402 | |||
403 | snd_soc_write(codec, SGTL5000_CHIP_DAC_VOL, reg); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static const DECLARE_TLV_DB_SCALE(capture_6db_attenuate, -600, 600, 0); | ||
409 | |||
410 | /* tlv for mic gain, 0db 20db 30db 40db */ | ||
411 | static const unsigned int mic_gain_tlv[] = { | ||
412 | TLV_DB_RANGE_HEAD(4), | ||
413 | 0, 0, TLV_DB_SCALE_ITEM(0, 0, 0), | ||
414 | 1, 3, TLV_DB_SCALE_ITEM(2000, 1000, 0), | ||
415 | }; | ||
416 | |||
417 | /* tlv for hp volume, -51.5db to 12.0db, step .5db */ | ||
418 | static const DECLARE_TLV_DB_SCALE(headphone_volume, -5150, 50, 0); | ||
419 | |||
420 | static const struct snd_kcontrol_new sgtl5000_snd_controls[] = { | ||
421 | /* SOC_DOUBLE_S8_TLV with invert */ | ||
422 | { | ||
423 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
424 | .name = "PCM Playback Volume", | ||
425 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | | ||
426 | SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
427 | .info = dac_info_volsw, | ||
428 | .get = dac_get_volsw, | ||
429 | .put = dac_put_volsw, | ||
430 | }, | ||
431 | |||
432 | SOC_DOUBLE("Capture Volume", SGTL5000_CHIP_ANA_ADC_CTRL, 0, 4, 0xf, 0), | ||
433 | SOC_SINGLE_TLV("Capture Attenuate Switch (-6dB)", | ||
434 | SGTL5000_CHIP_ANA_ADC_CTRL, | ||
435 | 8, 2, 0, capture_6db_attenuate), | ||
436 | SOC_SINGLE("Capture ZC Switch", SGTL5000_CHIP_ANA_CTRL, 1, 1, 0), | ||
437 | |||
438 | SOC_DOUBLE_TLV("Headphone Playback Volume", | ||
439 | SGTL5000_CHIP_ANA_HP_CTRL, | ||
440 | 0, 8, | ||
441 | 0x7f, 1, | ||
442 | headphone_volume), | ||
443 | SOC_SINGLE("Headphone Playback ZC Switch", SGTL5000_CHIP_ANA_CTRL, | ||
444 | 5, 1, 0), | ||
445 | |||
446 | SOC_SINGLE_TLV("Mic Volume", SGTL5000_CHIP_MIC_CTRL, | ||
447 | 0, 4, 0, mic_gain_tlv), | ||
448 | }; | ||
449 | |||
450 | /* mute the codec used by alsa core */ | ||
451 | static int sgtl5000_digital_mute(struct snd_soc_dai *codec_dai, int mute) | ||
452 | { | ||
453 | struct snd_soc_codec *codec = codec_dai->codec; | ||
454 | u16 adcdac_ctrl = SGTL5000_DAC_MUTE_LEFT | SGTL5000_DAC_MUTE_RIGHT; | ||
455 | |||
456 | snd_soc_update_bits(codec, SGTL5000_CHIP_ADCDAC_CTRL, | ||
457 | adcdac_ctrl, mute ? adcdac_ctrl : 0); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | /* set codec format */ | ||
463 | static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
464 | { | ||
465 | struct snd_soc_codec *codec = codec_dai->codec; | ||
466 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
467 | u16 i2sctl = 0; | ||
468 | |||
469 | sgtl5000->master = 0; | ||
470 | /* | ||
471 | * i2s clock and frame master setting. | ||
472 | * ONLY support: | ||
473 | * - clock and frame slave, | ||
474 | * - clock and frame master | ||
475 | */ | ||
476 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
477 | case SND_SOC_DAIFMT_CBS_CFS: | ||
478 | break; | ||
479 | case SND_SOC_DAIFMT_CBM_CFM: | ||
480 | i2sctl |= SGTL5000_I2S_MASTER; | ||
481 | sgtl5000->master = 1; | ||
482 | break; | ||
483 | default: | ||
484 | return -EINVAL; | ||
485 | } | ||
486 | |||
487 | /* setting i2s data format */ | ||
488 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
489 | case SND_SOC_DAIFMT_DSP_A: | ||
490 | i2sctl |= SGTL5000_I2S_MODE_PCM; | ||
491 | break; | ||
492 | case SND_SOC_DAIFMT_DSP_B: | ||
493 | i2sctl |= SGTL5000_I2S_MODE_PCM; | ||
494 | i2sctl |= SGTL5000_I2S_LRALIGN; | ||
495 | break; | ||
496 | case SND_SOC_DAIFMT_I2S: | ||
497 | i2sctl |= SGTL5000_I2S_MODE_I2S_LJ; | ||
498 | break; | ||
499 | case SND_SOC_DAIFMT_RIGHT_J: | ||
500 | i2sctl |= SGTL5000_I2S_MODE_RJ; | ||
501 | i2sctl |= SGTL5000_I2S_LRPOL; | ||
502 | break; | ||
503 | case SND_SOC_DAIFMT_LEFT_J: | ||
504 | i2sctl |= SGTL5000_I2S_MODE_I2S_LJ; | ||
505 | i2sctl |= SGTL5000_I2S_LRALIGN; | ||
506 | break; | ||
507 | default: | ||
508 | return -EINVAL; | ||
509 | } | ||
510 | |||
511 | sgtl5000->fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; | ||
512 | |||
513 | /* Clock inversion */ | ||
514 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
515 | case SND_SOC_DAIFMT_NB_NF: | ||
516 | break; | ||
517 | case SND_SOC_DAIFMT_IB_NF: | ||
518 | i2sctl |= SGTL5000_I2S_SCLK_INV; | ||
519 | break; | ||
520 | default: | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | snd_soc_write(codec, SGTL5000_CHIP_I2S_CTRL, i2sctl); | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | /* set codec sysclk */ | ||
530 | static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
531 | int clk_id, unsigned int freq, int dir) | ||
532 | { | ||
533 | struct snd_soc_codec *codec = codec_dai->codec; | ||
534 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
535 | |||
536 | switch (clk_id) { | ||
537 | case SGTL5000_SYSCLK: | ||
538 | sgtl5000->sysclk = freq; | ||
539 | break; | ||
540 | default: | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | |||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | /* | ||
548 | * set clock according to i2s frame clock, | ||
549 | * sgtl5000 provide 2 clock sources. | ||
550 | * 1. sys_mclk. sample freq can only configure to | ||
551 | * 1/256, 1/384, 1/512 of sys_mclk. | ||
552 | * 2. pll. can derive any audio clocks. | ||
553 | * | ||
554 | * clock setting rules: | ||
555 | * 1. in slave mode, only sys_mclk can use. | ||
556 | * 2. as constraint by sys_mclk, sample freq should | ||
557 | * set to 32k, 44.1k and above. | ||
558 | * 3. using sys_mclk prefer to pll to save power. | ||
559 | */ | ||
560 | static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | ||
561 | { | ||
562 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
563 | int clk_ctl = 0; | ||
564 | int sys_fs; /* sample freq */ | ||
565 | |||
566 | /* | ||
567 | * sample freq should be divided by frame clock, | ||
568 | * if frame clock lower than 44.1khz, sample feq should set to | ||
569 | * 32khz or 44.1khz. | ||
570 | */ | ||
571 | switch (frame_rate) { | ||
572 | case 8000: | ||
573 | case 16000: | ||
574 | sys_fs = 32000; | ||
575 | break; | ||
576 | case 11025: | ||
577 | case 22050: | ||
578 | sys_fs = 44100; | ||
579 | break; | ||
580 | default: | ||
581 | sys_fs = frame_rate; | ||
582 | break; | ||
583 | } | ||
584 | |||
585 | /* set divided factor of frame clock */ | ||
586 | switch (sys_fs / frame_rate) { | ||
587 | case 4: | ||
588 | clk_ctl |= SGTL5000_RATE_MODE_DIV_4 << SGTL5000_RATE_MODE_SHIFT; | ||
589 | break; | ||
590 | case 2: | ||
591 | clk_ctl |= SGTL5000_RATE_MODE_DIV_2 << SGTL5000_RATE_MODE_SHIFT; | ||
592 | break; | ||
593 | case 1: | ||
594 | clk_ctl |= SGTL5000_RATE_MODE_DIV_1 << SGTL5000_RATE_MODE_SHIFT; | ||
595 | break; | ||
596 | default: | ||
597 | return -EINVAL; | ||
598 | } | ||
599 | |||
600 | /* set the sys_fs according to frame rate */ | ||
601 | switch (sys_fs) { | ||
602 | case 32000: | ||
603 | clk_ctl |= SGTL5000_SYS_FS_32k << SGTL5000_SYS_FS_SHIFT; | ||
604 | break; | ||
605 | case 44100: | ||
606 | clk_ctl |= SGTL5000_SYS_FS_44_1k << SGTL5000_SYS_FS_SHIFT; | ||
607 | break; | ||
608 | case 48000: | ||
609 | clk_ctl |= SGTL5000_SYS_FS_48k << SGTL5000_SYS_FS_SHIFT; | ||
610 | break; | ||
611 | case 96000: | ||
612 | clk_ctl |= SGTL5000_SYS_FS_96k << SGTL5000_SYS_FS_SHIFT; | ||
613 | break; | ||
614 | default: | ||
615 | dev_err(codec->dev, "frame rate %d not supported\n", | ||
616 | frame_rate); | ||
617 | return -EINVAL; | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * calculate the divider of mclk/sample_freq, | ||
622 | * factor of freq =96k can only be 256, since mclk in range (12m,27m) | ||
623 | */ | ||
624 | switch (sgtl5000->sysclk / sys_fs) { | ||
625 | case 256: | ||
626 | clk_ctl |= SGTL5000_MCLK_FREQ_256FS << | ||
627 | SGTL5000_MCLK_FREQ_SHIFT; | ||
628 | break; | ||
629 | case 384: | ||
630 | clk_ctl |= SGTL5000_MCLK_FREQ_384FS << | ||
631 | SGTL5000_MCLK_FREQ_SHIFT; | ||
632 | break; | ||
633 | case 512: | ||
634 | clk_ctl |= SGTL5000_MCLK_FREQ_512FS << | ||
635 | SGTL5000_MCLK_FREQ_SHIFT; | ||
636 | break; | ||
637 | default: | ||
638 | /* if mclk not satisify the divider, use pll */ | ||
639 | if (sgtl5000->master) { | ||
640 | clk_ctl |= SGTL5000_MCLK_FREQ_PLL << | ||
641 | SGTL5000_MCLK_FREQ_SHIFT; | ||
642 | } else { | ||
643 | dev_err(codec->dev, | ||
644 | "PLL not supported in slave mode\n"); | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | /* if using pll, please check manual 6.4.2 for detail */ | ||
650 | if ((clk_ctl & SGTL5000_MCLK_FREQ_MASK) == SGTL5000_MCLK_FREQ_PLL) { | ||
651 | u64 out, t; | ||
652 | int div2; | ||
653 | int pll_ctl; | ||
654 | unsigned int in, int_div, frac_div; | ||
655 | |||
656 | if (sgtl5000->sysclk > 17000000) { | ||
657 | div2 = 1; | ||
658 | in = sgtl5000->sysclk / 2; | ||
659 | } else { | ||
660 | div2 = 0; | ||
661 | in = sgtl5000->sysclk; | ||
662 | } | ||
663 | if (sys_fs == 44100) | ||
664 | out = 180633600; | ||
665 | else | ||
666 | out = 196608000; | ||
667 | t = do_div(out, in); | ||
668 | int_div = out; | ||
669 | t *= 2048; | ||
670 | do_div(t, in); | ||
671 | frac_div = t; | ||
672 | pll_ctl = int_div << SGTL5000_PLL_INT_DIV_SHIFT | | ||
673 | frac_div << SGTL5000_PLL_FRAC_DIV_SHIFT; | ||
674 | |||
675 | snd_soc_write(codec, SGTL5000_CHIP_PLL_CTRL, pll_ctl); | ||
676 | if (div2) | ||
677 | snd_soc_update_bits(codec, | ||
678 | SGTL5000_CHIP_CLK_TOP_CTRL, | ||
679 | SGTL5000_INPUT_FREQ_DIV2, | ||
680 | SGTL5000_INPUT_FREQ_DIV2); | ||
681 | else | ||
682 | snd_soc_update_bits(codec, | ||
683 | SGTL5000_CHIP_CLK_TOP_CTRL, | ||
684 | SGTL5000_INPUT_FREQ_DIV2, | ||
685 | 0); | ||
686 | |||
687 | /* power up pll */ | ||
688 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
689 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, | ||
690 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP); | ||
691 | } else { | ||
692 | /* power down pll */ | ||
693 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
694 | SGTL5000_PLL_POWERUP | SGTL5000_VCOAMP_POWERUP, | ||
695 | 0); | ||
696 | } | ||
697 | |||
698 | /* if using pll, clk_ctrl must be set after pll power up */ | ||
699 | snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, clk_ctl); | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | /* | ||
705 | * Set PCM DAI bit size and sample rate. | ||
706 | * input: params_rate, params_fmt | ||
707 | */ | ||
708 | static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream, | ||
709 | struct snd_pcm_hw_params *params, | ||
710 | struct snd_soc_dai *dai) | ||
711 | { | ||
712 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
713 | struct snd_soc_codec *codec = rtd->codec; | ||
714 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
715 | int channels = params_channels(params); | ||
716 | int i2s_ctl = 0; | ||
717 | int stereo; | ||
718 | int ret; | ||
719 | |||
720 | /* sysclk should already set */ | ||
721 | if (!sgtl5000->sysclk) { | ||
722 | dev_err(codec->dev, "%s: set sysclk first!\n", __func__); | ||
723 | return -EFAULT; | ||
724 | } | ||
725 | |||
726 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
727 | stereo = SGTL5000_DAC_STEREO; | ||
728 | else | ||
729 | stereo = SGTL5000_ADC_STEREO; | ||
730 | |||
731 | /* set mono to save power */ | ||
732 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, stereo, | ||
733 | channels == 1 ? 0 : stereo); | ||
734 | |||
735 | /* set codec clock base on lrclk */ | ||
736 | ret = sgtl5000_set_clock(codec, params_rate(params)); | ||
737 | if (ret) | ||
738 | return ret; | ||
739 | |||
740 | /* set i2s data format */ | ||
741 | switch (params_format(params)) { | ||
742 | case SNDRV_PCM_FORMAT_S16_LE: | ||
743 | if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J) | ||
744 | return -EINVAL; | ||
745 | i2s_ctl |= SGTL5000_I2S_DLEN_16 << SGTL5000_I2S_DLEN_SHIFT; | ||
746 | i2s_ctl |= SGTL5000_I2S_SCLKFREQ_32FS << | ||
747 | SGTL5000_I2S_SCLKFREQ_SHIFT; | ||
748 | break; | ||
749 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
750 | i2s_ctl |= SGTL5000_I2S_DLEN_20 << SGTL5000_I2S_DLEN_SHIFT; | ||
751 | i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << | ||
752 | SGTL5000_I2S_SCLKFREQ_SHIFT; | ||
753 | break; | ||
754 | case SNDRV_PCM_FORMAT_S24_LE: | ||
755 | i2s_ctl |= SGTL5000_I2S_DLEN_24 << SGTL5000_I2S_DLEN_SHIFT; | ||
756 | i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << | ||
757 | SGTL5000_I2S_SCLKFREQ_SHIFT; | ||
758 | break; | ||
759 | case SNDRV_PCM_FORMAT_S32_LE: | ||
760 | if (sgtl5000->fmt == SND_SOC_DAIFMT_RIGHT_J) | ||
761 | return -EINVAL; | ||
762 | i2s_ctl |= SGTL5000_I2S_DLEN_32 << SGTL5000_I2S_DLEN_SHIFT; | ||
763 | i2s_ctl |= SGTL5000_I2S_SCLKFREQ_64FS << | ||
764 | SGTL5000_I2S_SCLKFREQ_SHIFT; | ||
765 | break; | ||
766 | default: | ||
767 | return -EINVAL; | ||
768 | } | ||
769 | |||
770 | snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | |||
775 | static int ldo_regulator_is_enabled(struct regulator_dev *dev) | ||
776 | { | ||
777 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
778 | |||
779 | return ldo->enabled; | ||
780 | } | ||
781 | |||
782 | static int ldo_regulator_enable(struct regulator_dev *dev) | ||
783 | { | ||
784 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
785 | struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data; | ||
786 | int reg; | ||
787 | |||
788 | if (ldo_regulator_is_enabled(dev)) | ||
789 | return 0; | ||
790 | |||
791 | /* set regulator value firstly */ | ||
792 | reg = (1600 - ldo->voltage / 1000) / 50; | ||
793 | reg = clamp(reg, 0x0, 0xf); | ||
794 | |||
795 | /* amend the voltage value, unit: uV */ | ||
796 | ldo->voltage = (1600 - reg * 50) * 1000; | ||
797 | |||
798 | /* set voltage to register */ | ||
799 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
800 | (0x1 << 4) - 1, reg); | ||
801 | |||
802 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
803 | SGTL5000_LINEREG_D_POWERUP, | ||
804 | SGTL5000_LINEREG_D_POWERUP); | ||
805 | |||
806 | /* when internal ldo enabled, simple digital power can be disabled */ | ||
807 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
808 | SGTL5000_LINREG_SIMPLE_POWERUP, | ||
809 | 0); | ||
810 | |||
811 | ldo->enabled = 1; | ||
812 | return 0; | ||
813 | } | ||
814 | |||
815 | static int ldo_regulator_disable(struct regulator_dev *dev) | ||
816 | { | ||
817 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
818 | struct snd_soc_codec *codec = (struct snd_soc_codec *)ldo->codec_data; | ||
819 | |||
820 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
821 | SGTL5000_LINEREG_D_POWERUP, | ||
822 | 0); | ||
823 | |||
824 | /* clear voltage info */ | ||
825 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
826 | (0x1 << 4) - 1, 0); | ||
827 | |||
828 | ldo->enabled = 0; | ||
829 | |||
830 | return 0; | ||
831 | } | ||
832 | |||
833 | static int ldo_regulator_get_voltage(struct regulator_dev *dev) | ||
834 | { | ||
835 | struct ldo_regulator *ldo = rdev_get_drvdata(dev); | ||
836 | |||
837 | return ldo->voltage; | ||
838 | } | ||
839 | |||
840 | static struct regulator_ops ldo_regulator_ops = { | ||
841 | .is_enabled = ldo_regulator_is_enabled, | ||
842 | .enable = ldo_regulator_enable, | ||
843 | .disable = ldo_regulator_disable, | ||
844 | .get_voltage = ldo_regulator_get_voltage, | ||
845 | }; | ||
846 | |||
847 | static int ldo_regulator_register(struct snd_soc_codec *codec, | ||
848 | struct regulator_init_data *init_data, | ||
849 | int voltage) | ||
850 | { | ||
851 | struct ldo_regulator *ldo; | ||
852 | |||
853 | ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL); | ||
854 | |||
855 | if (!ldo) { | ||
856 | dev_err(codec->dev, "failed to allocate ldo_regulator\n"); | ||
857 | return -ENOMEM; | ||
858 | } | ||
859 | |||
860 | ldo->desc.name = kstrdup(dev_name(codec->dev), GFP_KERNEL); | ||
861 | if (!ldo->desc.name) { | ||
862 | kfree(ldo); | ||
863 | dev_err(codec->dev, "failed to allocate decs name memory\n"); | ||
864 | return -ENOMEM; | ||
865 | } | ||
866 | |||
867 | ldo->desc.type = REGULATOR_VOLTAGE; | ||
868 | ldo->desc.owner = THIS_MODULE; | ||
869 | ldo->desc.ops = &ldo_regulator_ops; | ||
870 | ldo->desc.n_voltages = 1; | ||
871 | |||
872 | ldo->codec_data = codec; | ||
873 | ldo->voltage = voltage; | ||
874 | |||
875 | ldo->dev = regulator_register(&ldo->desc, codec->dev, | ||
876 | init_data, ldo); | ||
877 | if (IS_ERR(ldo->dev)) { | ||
878 | int ret = PTR_ERR(ldo->dev); | ||
879 | |||
880 | dev_err(codec->dev, "failed to register regulator\n"); | ||
881 | kfree(ldo->desc.name); | ||
882 | kfree(ldo); | ||
883 | |||
884 | return ret; | ||
885 | } | ||
886 | |||
887 | return 0; | ||
888 | } | ||
889 | |||
890 | static int ldo_regulator_remove(struct snd_soc_codec *codec) | ||
891 | { | ||
892 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
893 | struct ldo_regulator *ldo = sgtl5000->ldo; | ||
894 | |||
895 | if (!ldo) | ||
896 | return 0; | ||
897 | |||
898 | regulator_unregister(ldo->dev); | ||
899 | kfree(ldo->desc.name); | ||
900 | kfree(ldo); | ||
901 | |||
902 | return 0; | ||
903 | } | ||
904 | |||
905 | /* | ||
906 | * set dac bias | ||
907 | * common state changes: | ||
908 | * startup: | ||
909 | * off --> standby --> prepare --> on | ||
910 | * standby --> prepare --> on | ||
911 | * | ||
912 | * stop: | ||
913 | * on --> prepare --> standby | ||
914 | */ | ||
915 | static int sgtl5000_set_bias_level(struct snd_soc_codec *codec, | ||
916 | enum snd_soc_bias_level level) | ||
917 | { | ||
918 | int ret; | ||
919 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
920 | |||
921 | switch (level) { | ||
922 | case SND_SOC_BIAS_ON: | ||
923 | case SND_SOC_BIAS_PREPARE: | ||
924 | break; | ||
925 | case SND_SOC_BIAS_STANDBY: | ||
926 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
927 | ret = regulator_bulk_enable( | ||
928 | ARRAY_SIZE(sgtl5000->supplies), | ||
929 | sgtl5000->supplies); | ||
930 | if (ret) | ||
931 | return ret; | ||
932 | udelay(10); | ||
933 | } | ||
934 | |||
935 | break; | ||
936 | case SND_SOC_BIAS_OFF: | ||
937 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
938 | sgtl5000->supplies); | ||
939 | break; | ||
940 | } | ||
941 | |||
942 | codec->dapm.bias_level = level; | ||
943 | return 0; | ||
944 | } | ||
945 | |||
946 | #define SGTL5000_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | ||
947 | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
948 | SNDRV_PCM_FMTBIT_S24_LE |\ | ||
949 | SNDRV_PCM_FMTBIT_S32_LE) | ||
950 | |||
951 | static struct snd_soc_dai_ops sgtl5000_ops = { | ||
952 | .hw_params = sgtl5000_pcm_hw_params, | ||
953 | .digital_mute = sgtl5000_digital_mute, | ||
954 | .set_fmt = sgtl5000_set_dai_fmt, | ||
955 | .set_sysclk = sgtl5000_set_dai_sysclk, | ||
956 | }; | ||
957 | |||
958 | static struct snd_soc_dai_driver sgtl5000_dai = { | ||
959 | .name = "sgtl5000", | ||
960 | .playback = { | ||
961 | .stream_name = "Playback", | ||
962 | .channels_min = 1, | ||
963 | .channels_max = 2, | ||
964 | /* | ||
965 | * only support 8~48K + 96K, | ||
966 | * TODO modify hw_param to support more | ||
967 | */ | ||
968 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, | ||
969 | .formats = SGTL5000_FORMATS, | ||
970 | }, | ||
971 | .capture = { | ||
972 | .stream_name = "Capture", | ||
973 | .channels_min = 1, | ||
974 | .channels_max = 2, | ||
975 | .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_96000, | ||
976 | .formats = SGTL5000_FORMATS, | ||
977 | }, | ||
978 | .ops = &sgtl5000_ops, | ||
979 | .symmetric_rates = 1, | ||
980 | }; | ||
981 | |||
982 | static int sgtl5000_volatile_register(struct snd_soc_codec *codec, | ||
983 | unsigned int reg) | ||
984 | { | ||
985 | switch (reg) { | ||
986 | case SGTL5000_CHIP_ID: | ||
987 | case SGTL5000_CHIP_ADCDAC_CTRL: | ||
988 | case SGTL5000_CHIP_ANA_STATUS: | ||
989 | return 1; | ||
990 | } | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | #ifdef CONFIG_SUSPEND | ||
996 | static int sgtl5000_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
997 | { | ||
998 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
999 | |||
1000 | return 0; | ||
1001 | } | ||
1002 | |||
1003 | /* | ||
1004 | * restore all sgtl5000 registers, | ||
1005 | * since a big hole between dap and regular registers, | ||
1006 | * we will restore them respectively. | ||
1007 | */ | ||
1008 | static int sgtl5000_restore_regs(struct snd_soc_codec *codec) | ||
1009 | { | ||
1010 | u16 *cache = codec->reg_cache; | ||
1011 | int i; | ||
1012 | int regular_regs = SGTL5000_CHIP_SHORT_CTRL >> 1; | ||
1013 | |||
1014 | /* restore regular registers */ | ||
1015 | for (i = 0; i < regular_regs; i++) { | ||
1016 | int reg = i << 1; | ||
1017 | |||
1018 | /* this regs depends on the others */ | ||
1019 | if (reg == SGTL5000_CHIP_ANA_POWER || | ||
1020 | reg == SGTL5000_CHIP_CLK_CTRL || | ||
1021 | reg == SGTL5000_CHIP_LINREG_CTRL || | ||
1022 | reg == SGTL5000_CHIP_LINE_OUT_CTRL || | ||
1023 | reg == SGTL5000_CHIP_CLK_CTRL) | ||
1024 | continue; | ||
1025 | |||
1026 | snd_soc_write(codec, reg, cache[i]); | ||
1027 | } | ||
1028 | |||
1029 | /* restore dap registers */ | ||
1030 | for (i = SGTL5000_DAP_REG_OFFSET >> 1; | ||
1031 | i < SGTL5000_MAX_REG_OFFSET >> 1; i++) { | ||
1032 | int reg = i << 1; | ||
1033 | |||
1034 | snd_soc_write(codec, reg, cache[i]); | ||
1035 | } | ||
1036 | |||
1037 | /* | ||
1038 | * restore power and other regs according | ||
1039 | * to set_power() and set_clock() | ||
1040 | */ | ||
1041 | snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
1042 | cache[SGTL5000_CHIP_LINREG_CTRL >> 1]); | ||
1043 | |||
1044 | snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, | ||
1045 | cache[SGTL5000_CHIP_ANA_POWER >> 1]); | ||
1046 | |||
1047 | snd_soc_write(codec, SGTL5000_CHIP_CLK_CTRL, | ||
1048 | cache[SGTL5000_CHIP_CLK_CTRL >> 1]); | ||
1049 | |||
1050 | snd_soc_write(codec, SGTL5000_CHIP_REF_CTRL, | ||
1051 | cache[SGTL5000_CHIP_REF_CTRL >> 1]); | ||
1052 | |||
1053 | snd_soc_write(codec, SGTL5000_CHIP_LINE_OUT_CTRL, | ||
1054 | cache[SGTL5000_CHIP_LINE_OUT_CTRL >> 1]); | ||
1055 | return 0; | ||
1056 | } | ||
1057 | |||
1058 | static int sgtl5000_resume(struct snd_soc_codec *codec) | ||
1059 | { | ||
1060 | /* Bring the codec back up to standby to enable regulators */ | ||
1061 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1062 | |||
1063 | /* Restore registers by cached in memory */ | ||
1064 | sgtl5000_restore_regs(codec); | ||
1065 | return 0; | ||
1066 | } | ||
1067 | #else | ||
1068 | #define sgtl5000_suspend NULL | ||
1069 | #define sgtl5000_resume NULL | ||
1070 | #endif /* CONFIG_SUSPEND */ | ||
1071 | |||
1072 | /* | ||
1073 | * sgtl5000 has 3 internal power supplies: | ||
1074 | * 1. VAG, normally set to vdda/2 | ||
1075 | * 2. chargepump, set to different value | ||
1076 | * according to voltage of vdda and vddio | ||
1077 | * 3. line out VAG, normally set to vddio/2 | ||
1078 | * | ||
1079 | * and should be set according to: | ||
1080 | * 1. vddd provided by external or not | ||
1081 | * 2. vdda and vddio voltage value. > 3.1v or not | ||
1082 | * 3. chip revision >=0x11 or not. If >=0x11, not use external vddd. | ||
1083 | */ | ||
1084 | static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) | ||
1085 | { | ||
1086 | int vddd; | ||
1087 | int vdda; | ||
1088 | int vddio; | ||
1089 | u16 ana_pwr; | ||
1090 | u16 lreg_ctrl; | ||
1091 | int vag; | ||
1092 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1093 | |||
1094 | vdda = regulator_get_voltage(sgtl5000->supplies[VDDA].consumer); | ||
1095 | vddio = regulator_get_voltage(sgtl5000->supplies[VDDIO].consumer); | ||
1096 | vddd = regulator_get_voltage(sgtl5000->supplies[VDDD].consumer); | ||
1097 | |||
1098 | vdda = vdda / 1000; | ||
1099 | vddio = vddio / 1000; | ||
1100 | vddd = vddd / 1000; | ||
1101 | |||
1102 | if (vdda <= 0 || vddio <= 0 || vddd < 0) { | ||
1103 | dev_err(codec->dev, "regulator voltage not set correctly\n"); | ||
1104 | |||
1105 | return -EINVAL; | ||
1106 | } | ||
1107 | |||
1108 | /* according to datasheet, maximum voltage of supplies */ | ||
1109 | if (vdda > 3600 || vddio > 3600 || vddd > 1980) { | ||
1110 | dev_err(codec->dev, | ||
1111 | "exceed max voltage vdda %dmv vddio %dma vddd %dma\n", | ||
1112 | vdda, vddio, vddd); | ||
1113 | |||
1114 | return -EINVAL; | ||
1115 | } | ||
1116 | |||
1117 | /* reset value */ | ||
1118 | ana_pwr = snd_soc_read(codec, SGTL5000_CHIP_ANA_POWER); | ||
1119 | ana_pwr |= SGTL5000_DAC_STEREO | | ||
1120 | SGTL5000_ADC_STEREO | | ||
1121 | SGTL5000_REFTOP_POWERUP; | ||
1122 | lreg_ctrl = snd_soc_read(codec, SGTL5000_CHIP_LINREG_CTRL); | ||
1123 | |||
1124 | if (vddio < 3100 && vdda < 3100) { | ||
1125 | /* enable internal oscillator used for charge pump */ | ||
1126 | snd_soc_update_bits(codec, SGTL5000_CHIP_CLK_TOP_CTRL, | ||
1127 | SGTL5000_INT_OSC_EN, | ||
1128 | SGTL5000_INT_OSC_EN); | ||
1129 | /* Enable VDDC charge pump */ | ||
1130 | ana_pwr |= SGTL5000_VDDC_CHRGPMP_POWERUP; | ||
1131 | } else if (vddio >= 3100 && vdda >= 3100) { | ||
1132 | /* | ||
1133 | * if vddio and vddd > 3.1v, | ||
1134 | * charge pump should be clean before set ana_pwr | ||
1135 | */ | ||
1136 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
1137 | SGTL5000_VDDC_CHRGPMP_POWERUP, 0); | ||
1138 | |||
1139 | /* VDDC use VDDIO rail */ | ||
1140 | lreg_ctrl |= SGTL5000_VDDC_ASSN_OVRD; | ||
1141 | lreg_ctrl |= SGTL5000_VDDC_MAN_ASSN_VDDIO << | ||
1142 | SGTL5000_VDDC_MAN_ASSN_SHIFT; | ||
1143 | } | ||
1144 | |||
1145 | snd_soc_write(codec, SGTL5000_CHIP_LINREG_CTRL, lreg_ctrl); | ||
1146 | |||
1147 | snd_soc_write(codec, SGTL5000_CHIP_ANA_POWER, ana_pwr); | ||
1148 | |||
1149 | /* set voltage to register */ | ||
1150 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, | ||
1151 | (0x1 << 4) - 1, 0x8); | ||
1152 | |||
1153 | /* | ||
1154 | * if vddd linear reg has been enabled, | ||
1155 | * simple digital supply should be clear to get | ||
1156 | * proper VDDD voltage. | ||
1157 | */ | ||
1158 | if (ana_pwr & SGTL5000_LINEREG_D_POWERUP) | ||
1159 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
1160 | SGTL5000_LINREG_SIMPLE_POWERUP, | ||
1161 | 0); | ||
1162 | else | ||
1163 | snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, | ||
1164 | SGTL5000_LINREG_SIMPLE_POWERUP | | ||
1165 | SGTL5000_STARTUP_POWERUP, | ||
1166 | 0); | ||
1167 | |||
1168 | /* | ||
1169 | * set ADC/DAC VAG to vdda / 2, | ||
1170 | * should stay in range (0.8v, 1.575v) | ||
1171 | */ | ||
1172 | vag = vdda / 2; | ||
1173 | if (vag <= SGTL5000_ANA_GND_BASE) | ||
1174 | vag = 0; | ||
1175 | else if (vag >= SGTL5000_ANA_GND_BASE + SGTL5000_ANA_GND_STP * | ||
1176 | (SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT)) | ||
1177 | vag = SGTL5000_ANA_GND_MASK >> SGTL5000_ANA_GND_SHIFT; | ||
1178 | else | ||
1179 | vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP; | ||
1180 | |||
1181 | snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, | ||
1182 | vag << SGTL5000_ANA_GND_SHIFT, | ||
1183 | vag << SGTL5000_ANA_GND_SHIFT); | ||
1184 | |||
1185 | /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */ | ||
1186 | vag = vddio / 2; | ||
1187 | if (vag <= SGTL5000_LINE_OUT_GND_BASE) | ||
1188 | vag = 0; | ||
1189 | else if (vag >= SGTL5000_LINE_OUT_GND_BASE + | ||
1190 | SGTL5000_LINE_OUT_GND_STP * SGTL5000_LINE_OUT_GND_MAX) | ||
1191 | vag = SGTL5000_LINE_OUT_GND_MAX; | ||
1192 | else | ||
1193 | vag = (vag - SGTL5000_LINE_OUT_GND_BASE) / | ||
1194 | SGTL5000_LINE_OUT_GND_STP; | ||
1195 | |||
1196 | snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL, | ||
1197 | vag << SGTL5000_LINE_OUT_GND_SHIFT | | ||
1198 | SGTL5000_LINE_OUT_CURRENT_360u << | ||
1199 | SGTL5000_LINE_OUT_CURRENT_SHIFT, | ||
1200 | vag << SGTL5000_LINE_OUT_GND_SHIFT | | ||
1201 | SGTL5000_LINE_OUT_CURRENT_360u << | ||
1202 | SGTL5000_LINE_OUT_CURRENT_SHIFT); | ||
1203 | |||
1204 | return 0; | ||
1205 | } | ||
1206 | |||
1207 | static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) | ||
1208 | { | ||
1209 | u16 reg; | ||
1210 | int ret; | ||
1211 | int rev; | ||
1212 | int i; | ||
1213 | int external_vddd = 0; | ||
1214 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1215 | |||
1216 | for (i = 0; i < ARRAY_SIZE(sgtl5000->supplies); i++) | ||
1217 | sgtl5000->supplies[i].supply = supply_names[i]; | ||
1218 | |||
1219 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), | ||
1220 | sgtl5000->supplies); | ||
1221 | if (!ret) | ||
1222 | external_vddd = 1; | ||
1223 | else { | ||
1224 | /* set internal ldo to 1.2v */ | ||
1225 | int voltage = LDO_VOLTAGE; | ||
1226 | |||
1227 | ret = ldo_regulator_register(codec, &ldo_init_data, voltage); | ||
1228 | if (ret) { | ||
1229 | dev_err(codec->dev, | ||
1230 | "Failed to register vddd internal supplies: %d\n", | ||
1231 | ret); | ||
1232 | return ret; | ||
1233 | } | ||
1234 | |||
1235 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
1236 | |||
1237 | ret = regulator_bulk_get(codec->dev, | ||
1238 | ARRAY_SIZE(sgtl5000->supplies), | ||
1239 | sgtl5000->supplies); | ||
1240 | |||
1241 | if (ret) { | ||
1242 | ldo_regulator_remove(codec); | ||
1243 | dev_err(codec->dev, | ||
1244 | "Failed to request supplies: %d\n", ret); | ||
1245 | |||
1246 | return ret; | ||
1247 | } | ||
1248 | } | ||
1249 | |||
1250 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | ||
1251 | sgtl5000->supplies); | ||
1252 | if (ret) | ||
1253 | goto err_regulator_free; | ||
1254 | |||
1255 | /* wait for all power rails bring up */ | ||
1256 | udelay(10); | ||
1257 | |||
1258 | /* read chip information */ | ||
1259 | reg = snd_soc_read(codec, SGTL5000_CHIP_ID); | ||
1260 | if (((reg & SGTL5000_PARTID_MASK) >> SGTL5000_PARTID_SHIFT) != | ||
1261 | SGTL5000_PARTID_PART_ID) { | ||
1262 | dev_err(codec->dev, | ||
1263 | "Device with ID register %x is not a sgtl5000\n", reg); | ||
1264 | ret = -ENODEV; | ||
1265 | goto err_regulator_disable; | ||
1266 | } | ||
1267 | |||
1268 | rev = (reg & SGTL5000_REVID_MASK) >> SGTL5000_REVID_SHIFT; | ||
1269 | dev_info(codec->dev, "sgtl5000 revision %d\n", rev); | ||
1270 | |||
1271 | /* | ||
1272 | * workaround for revision 0x11 and later, | ||
1273 | * roll back to use internal LDO | ||
1274 | */ | ||
1275 | if (external_vddd && rev >= 0x11) { | ||
1276 | int voltage = LDO_VOLTAGE; | ||
1277 | /* disable all regulator first */ | ||
1278 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1279 | sgtl5000->supplies); | ||
1280 | /* free VDDD regulator */ | ||
1281 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1282 | sgtl5000->supplies); | ||
1283 | |||
1284 | ret = ldo_regulator_register(codec, &ldo_init_data, voltage); | ||
1285 | if (ret) | ||
1286 | return ret; | ||
1287 | |||
1288 | sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; | ||
1289 | |||
1290 | ret = regulator_bulk_get(codec->dev, | ||
1291 | ARRAY_SIZE(sgtl5000->supplies), | ||
1292 | sgtl5000->supplies); | ||
1293 | if (ret) { | ||
1294 | ldo_regulator_remove(codec); | ||
1295 | dev_err(codec->dev, | ||
1296 | "Failed to request supplies: %d\n", ret); | ||
1297 | |||
1298 | return ret; | ||
1299 | } | ||
1300 | |||
1301 | ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), | ||
1302 | sgtl5000->supplies); | ||
1303 | if (ret) | ||
1304 | goto err_regulator_free; | ||
1305 | |||
1306 | /* wait for all power rails bring up */ | ||
1307 | udelay(10); | ||
1308 | } | ||
1309 | |||
1310 | return 0; | ||
1311 | |||
1312 | err_regulator_disable: | ||
1313 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1314 | sgtl5000->supplies); | ||
1315 | err_regulator_free: | ||
1316 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1317 | sgtl5000->supplies); | ||
1318 | if (external_vddd) | ||
1319 | ldo_regulator_remove(codec); | ||
1320 | return ret; | ||
1321 | |||
1322 | } | ||
1323 | |||
1324 | static int sgtl5000_probe(struct snd_soc_codec *codec) | ||
1325 | { | ||
1326 | int ret; | ||
1327 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1328 | |||
1329 | /* setup i2c data ops */ | ||
1330 | ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C); | ||
1331 | if (ret < 0) { | ||
1332 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1333 | return ret; | ||
1334 | } | ||
1335 | |||
1336 | ret = sgtl5000_enable_regulators(codec); | ||
1337 | if (ret) | ||
1338 | return ret; | ||
1339 | |||
1340 | /* power up sgtl5000 */ | ||
1341 | ret = sgtl5000_set_power_regs(codec); | ||
1342 | if (ret) | ||
1343 | goto err; | ||
1344 | |||
1345 | /* enable small pop, introduce 400ms delay in turning off */ | ||
1346 | snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, | ||
1347 | SGTL5000_SMALL_POP, | ||
1348 | SGTL5000_SMALL_POP); | ||
1349 | |||
1350 | /* disable short cut detector */ | ||
1351 | snd_soc_write(codec, SGTL5000_CHIP_SHORT_CTRL, 0); | ||
1352 | |||
1353 | /* | ||
1354 | * set i2s as default input of sound switch | ||
1355 | * TODO: add sound switch to control and dapm widge. | ||
1356 | */ | ||
1357 | snd_soc_write(codec, SGTL5000_CHIP_SSS_CTRL, | ||
1358 | SGTL5000_DAC_SEL_I2S_IN << SGTL5000_DAC_SEL_SHIFT); | ||
1359 | snd_soc_write(codec, SGTL5000_CHIP_DIG_POWER, | ||
1360 | SGTL5000_ADC_EN | SGTL5000_DAC_EN); | ||
1361 | |||
1362 | /* enable dac volume ramp by default */ | ||
1363 | snd_soc_write(codec, SGTL5000_CHIP_ADCDAC_CTRL, | ||
1364 | SGTL5000_DAC_VOL_RAMP_EN | | ||
1365 | SGTL5000_DAC_MUTE_RIGHT | | ||
1366 | SGTL5000_DAC_MUTE_LEFT); | ||
1367 | |||
1368 | snd_soc_write(codec, SGTL5000_CHIP_PAD_STRENGTH, 0x015f); | ||
1369 | |||
1370 | snd_soc_write(codec, SGTL5000_CHIP_ANA_CTRL, | ||
1371 | SGTL5000_HP_ZCD_EN | | ||
1372 | SGTL5000_ADC_ZCD_EN); | ||
1373 | |||
1374 | snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 0); | ||
1375 | |||
1376 | /* | ||
1377 | * disable DAP | ||
1378 | * TODO: | ||
1379 | * Enable DAP in kcontrol and dapm. | ||
1380 | */ | ||
1381 | snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); | ||
1382 | |||
1383 | /* leading to standby state */ | ||
1384 | ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1385 | if (ret) | ||
1386 | goto err; | ||
1387 | |||
1388 | snd_soc_add_controls(codec, sgtl5000_snd_controls, | ||
1389 | ARRAY_SIZE(sgtl5000_snd_controls)); | ||
1390 | |||
1391 | snd_soc_dapm_new_controls(&codec->dapm, sgtl5000_dapm_widgets, | ||
1392 | ARRAY_SIZE(sgtl5000_dapm_widgets)); | ||
1393 | |||
1394 | snd_soc_dapm_add_routes(&codec->dapm, audio_map, | ||
1395 | ARRAY_SIZE(audio_map)); | ||
1396 | |||
1397 | snd_soc_dapm_new_widgets(&codec->dapm); | ||
1398 | |||
1399 | return 0; | ||
1400 | |||
1401 | err: | ||
1402 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1403 | sgtl5000->supplies); | ||
1404 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1405 | sgtl5000->supplies); | ||
1406 | ldo_regulator_remove(codec); | ||
1407 | |||
1408 | return ret; | ||
1409 | } | ||
1410 | |||
1411 | static int sgtl5000_remove(struct snd_soc_codec *codec) | ||
1412 | { | ||
1413 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | ||
1414 | |||
1415 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1416 | |||
1417 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | ||
1418 | sgtl5000->supplies); | ||
1419 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | ||
1420 | sgtl5000->supplies); | ||
1421 | ldo_regulator_remove(codec); | ||
1422 | |||
1423 | return 0; | ||
1424 | } | ||
1425 | |||
1426 | static struct snd_soc_codec_driver sgtl5000_driver = { | ||
1427 | .probe = sgtl5000_probe, | ||
1428 | .remove = sgtl5000_remove, | ||
1429 | .suspend = sgtl5000_suspend, | ||
1430 | .resume = sgtl5000_resume, | ||
1431 | .set_bias_level = sgtl5000_set_bias_level, | ||
1432 | .reg_cache_size = ARRAY_SIZE(sgtl5000_regs), | ||
1433 | .reg_word_size = sizeof(u16), | ||
1434 | .reg_cache_step = 2, | ||
1435 | .reg_cache_default = sgtl5000_regs, | ||
1436 | .volatile_register = sgtl5000_volatile_register, | ||
1437 | }; | ||
1438 | |||
1439 | static __devinit int sgtl5000_i2c_probe(struct i2c_client *client, | ||
1440 | const struct i2c_device_id *id) | ||
1441 | { | ||
1442 | struct sgtl5000_priv *sgtl5000; | ||
1443 | int ret; | ||
1444 | |||
1445 | sgtl5000 = kzalloc(sizeof(struct sgtl5000_priv), GFP_KERNEL); | ||
1446 | if (!sgtl5000) | ||
1447 | return -ENOMEM; | ||
1448 | |||
1449 | /* | ||
1450 | * copy DAP default values to default value array. | ||
1451 | * sgtl5000 register space has a big hole, merge it | ||
1452 | * at init phase makes life easy. | ||
1453 | * FIXME: should we drop 'const' of sgtl5000_regs? | ||
1454 | */ | ||
1455 | memcpy((void *)(&sgtl5000_regs[0] + (SGTL5000_DAP_REG_OFFSET >> 1)), | ||
1456 | sgtl5000_dap_regs, | ||
1457 | SGTL5000_MAX_REG_OFFSET - SGTL5000_DAP_REG_OFFSET); | ||
1458 | |||
1459 | i2c_set_clientdata(client, sgtl5000); | ||
1460 | |||
1461 | ret = snd_soc_register_codec(&client->dev, | ||
1462 | &sgtl5000_driver, &sgtl5000_dai, 1); | ||
1463 | if (ret) { | ||
1464 | dev_err(&client->dev, "Failed to register codec: %d\n", ret); | ||
1465 | kfree(sgtl5000); | ||
1466 | return ret; | ||
1467 | } | ||
1468 | |||
1469 | return 0; | ||
1470 | } | ||
1471 | |||
1472 | static __devexit int sgtl5000_i2c_remove(struct i2c_client *client) | ||
1473 | { | ||
1474 | struct sgtl5000_priv *sgtl5000 = i2c_get_clientdata(client); | ||
1475 | |||
1476 | snd_soc_unregister_codec(&client->dev); | ||
1477 | |||
1478 | kfree(sgtl5000); | ||
1479 | return 0; | ||
1480 | } | ||
1481 | |||
1482 | static const struct i2c_device_id sgtl5000_id[] = { | ||
1483 | {"sgtl5000", 0}, | ||
1484 | {}, | ||
1485 | }; | ||
1486 | |||
1487 | MODULE_DEVICE_TABLE(i2c, sgtl5000_id); | ||
1488 | |||
1489 | static struct i2c_driver sgtl5000_i2c_driver = { | ||
1490 | .driver = { | ||
1491 | .name = "sgtl5000", | ||
1492 | .owner = THIS_MODULE, | ||
1493 | }, | ||
1494 | .probe = sgtl5000_i2c_probe, | ||
1495 | .remove = __devexit_p(sgtl5000_i2c_remove), | ||
1496 | .id_table = sgtl5000_id, | ||
1497 | }; | ||
1498 | |||
1499 | static int __init sgtl5000_modinit(void) | ||
1500 | { | ||
1501 | return i2c_add_driver(&sgtl5000_i2c_driver); | ||
1502 | } | ||
1503 | module_init(sgtl5000_modinit); | ||
1504 | |||
1505 | static void __exit sgtl5000_exit(void) | ||
1506 | { | ||
1507 | i2c_del_driver(&sgtl5000_i2c_driver); | ||
1508 | } | ||
1509 | module_exit(sgtl5000_exit); | ||
1510 | |||
1511 | MODULE_DESCRIPTION("Freescale SGTL5000 ALSA SoC Codec Driver"); | ||
1512 | MODULE_AUTHOR("Zeng Zhaoming <zhaoming.zeng@freescale.com>"); | ||
1513 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sgtl5000.h b/sound/soc/codecs/sgtl5000.h new file mode 100644 index 000000000000..eec3ab368f39 --- /dev/null +++ b/sound/soc/codecs/sgtl5000.h | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * sgtl5000.h - SGTL5000 audio codec interface | ||
3 | * | ||
4 | * Copyright 2010-2011 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #ifndef _SGTL5000_H | ||
12 | #define _SGTL5000_H | ||
13 | |||
14 | /* | ||
15 | * Register values. | ||
16 | */ | ||
17 | #define SGTL5000_CHIP_ID 0x0000 | ||
18 | #define SGTL5000_CHIP_DIG_POWER 0x0002 | ||
19 | #define SGTL5000_CHIP_CLK_CTRL 0x0004 | ||
20 | #define SGTL5000_CHIP_I2S_CTRL 0x0006 | ||
21 | #define SGTL5000_CHIP_SSS_CTRL 0x000a | ||
22 | #define SGTL5000_CHIP_ADCDAC_CTRL 0x000e | ||
23 | #define SGTL5000_CHIP_DAC_VOL 0x0010 | ||
24 | #define SGTL5000_CHIP_PAD_STRENGTH 0x0014 | ||
25 | #define SGTL5000_CHIP_ANA_ADC_CTRL 0x0020 | ||
26 | #define SGTL5000_CHIP_ANA_HP_CTRL 0x0022 | ||
27 | #define SGTL5000_CHIP_ANA_CTRL 0x0024 | ||
28 | #define SGTL5000_CHIP_LINREG_CTRL 0x0026 | ||
29 | #define SGTL5000_CHIP_REF_CTRL 0x0028 | ||
30 | #define SGTL5000_CHIP_MIC_CTRL 0x002a | ||
31 | #define SGTL5000_CHIP_LINE_OUT_CTRL 0x002c | ||
32 | #define SGTL5000_CHIP_LINE_OUT_VOL 0x002e | ||
33 | #define SGTL5000_CHIP_ANA_POWER 0x0030 | ||
34 | #define SGTL5000_CHIP_PLL_CTRL 0x0032 | ||
35 | #define SGTL5000_CHIP_CLK_TOP_CTRL 0x0034 | ||
36 | #define SGTL5000_CHIP_ANA_STATUS 0x0036 | ||
37 | #define SGTL5000_CHIP_SHORT_CTRL 0x003c | ||
38 | #define SGTL5000_CHIP_ANA_TEST2 0x003a | ||
39 | #define SGTL5000_DAP_CTRL 0x0100 | ||
40 | #define SGTL5000_DAP_PEQ 0x0102 | ||
41 | #define SGTL5000_DAP_BASS_ENHANCE 0x0104 | ||
42 | #define SGTL5000_DAP_BASS_ENHANCE_CTRL 0x0106 | ||
43 | #define SGTL5000_DAP_AUDIO_EQ 0x0108 | ||
44 | #define SGTL5000_DAP_SURROUND 0x010a | ||
45 | #define SGTL5000_DAP_FLT_COEF_ACCESS 0x010c | ||
46 | #define SGTL5000_DAP_COEF_WR_B0_MSB 0x010e | ||
47 | #define SGTL5000_DAP_COEF_WR_B0_LSB 0x0110 | ||
48 | #define SGTL5000_DAP_EQ_BASS_BAND0 0x0116 | ||
49 | #define SGTL5000_DAP_EQ_BASS_BAND1 0x0118 | ||
50 | #define SGTL5000_DAP_EQ_BASS_BAND2 0x011a | ||
51 | #define SGTL5000_DAP_EQ_BASS_BAND3 0x011c | ||
52 | #define SGTL5000_DAP_EQ_BASS_BAND4 0x011e | ||
53 | #define SGTL5000_DAP_MAIN_CHAN 0x0120 | ||
54 | #define SGTL5000_DAP_MIX_CHAN 0x0122 | ||
55 | #define SGTL5000_DAP_AVC_CTRL 0x0124 | ||
56 | #define SGTL5000_DAP_AVC_THRESHOLD 0x0126 | ||
57 | #define SGTL5000_DAP_AVC_ATTACK 0x0128 | ||
58 | #define SGTL5000_DAP_AVC_DECAY 0x012a | ||
59 | #define SGTL5000_DAP_COEF_WR_B1_MSB 0x012c | ||
60 | #define SGTL5000_DAP_COEF_WR_B1_LSB 0x012e | ||
61 | #define SGTL5000_DAP_COEF_WR_B2_MSB 0x0130 | ||
62 | #define SGTL5000_DAP_COEF_WR_B2_LSB 0x0132 | ||
63 | #define SGTL5000_DAP_COEF_WR_A1_MSB 0x0134 | ||
64 | #define SGTL5000_DAP_COEF_WR_A1_LSB 0x0136 | ||
65 | #define SGTL5000_DAP_COEF_WR_A2_MSB 0x0138 | ||
66 | #define SGTL5000_DAP_COEF_WR_A2_LSB 0x013a | ||
67 | |||
68 | /* | ||
69 | * Field Definitions. | ||
70 | */ | ||
71 | |||
72 | /* | ||
73 | * SGTL5000_CHIP_ID | ||
74 | */ | ||
75 | #define SGTL5000_PARTID_MASK 0xff00 | ||
76 | #define SGTL5000_PARTID_SHIFT 8 | ||
77 | #define SGTL5000_PARTID_WIDTH 8 | ||
78 | #define SGTL5000_PARTID_PART_ID 0xa0 | ||
79 | #define SGTL5000_REVID_MASK 0x00ff | ||
80 | #define SGTL5000_REVID_SHIFT 0 | ||
81 | #define SGTL5000_REVID_WIDTH 8 | ||
82 | |||
83 | /* | ||
84 | * SGTL5000_CHIP_DIG_POWER | ||
85 | */ | ||
86 | #define SGTL5000_ADC_EN 0x0040 | ||
87 | #define SGTL5000_DAC_EN 0x0020 | ||
88 | #define SGTL5000_DAP_POWERUP 0x0010 | ||
89 | #define SGTL5000_I2S_OUT_POWERUP 0x0002 | ||
90 | #define SGTL5000_I2S_IN_POWERUP 0x0001 | ||
91 | |||
92 | /* | ||
93 | * SGTL5000_CHIP_CLK_CTRL | ||
94 | */ | ||
95 | #define SGTL5000_RATE_MODE_MASK 0x0030 | ||
96 | #define SGTL5000_RATE_MODE_SHIFT 4 | ||
97 | #define SGTL5000_RATE_MODE_WIDTH 2 | ||
98 | #define SGTL5000_RATE_MODE_DIV_1 0 | ||
99 | #define SGTL5000_RATE_MODE_DIV_2 1 | ||
100 | #define SGTL5000_RATE_MODE_DIV_4 2 | ||
101 | #define SGTL5000_RATE_MODE_DIV_6 3 | ||
102 | #define SGTL5000_SYS_FS_MASK 0x000c | ||
103 | #define SGTL5000_SYS_FS_SHIFT 2 | ||
104 | #define SGTL5000_SYS_FS_WIDTH 2 | ||
105 | #define SGTL5000_SYS_FS_32k 0x0 | ||
106 | #define SGTL5000_SYS_FS_44_1k 0x1 | ||
107 | #define SGTL5000_SYS_FS_48k 0x2 | ||
108 | #define SGTL5000_SYS_FS_96k 0x3 | ||
109 | #define SGTL5000_MCLK_FREQ_MASK 0x0003 | ||
110 | #define SGTL5000_MCLK_FREQ_SHIFT 0 | ||
111 | #define SGTL5000_MCLK_FREQ_WIDTH 2 | ||
112 | #define SGTL5000_MCLK_FREQ_256FS 0x0 | ||
113 | #define SGTL5000_MCLK_FREQ_384FS 0x1 | ||
114 | #define SGTL5000_MCLK_FREQ_512FS 0x2 | ||
115 | #define SGTL5000_MCLK_FREQ_PLL 0x3 | ||
116 | |||
117 | /* | ||
118 | * SGTL5000_CHIP_I2S_CTRL | ||
119 | */ | ||
120 | #define SGTL5000_I2S_SCLKFREQ_MASK 0x0100 | ||
121 | #define SGTL5000_I2S_SCLKFREQ_SHIFT 8 | ||
122 | #define SGTL5000_I2S_SCLKFREQ_WIDTH 1 | ||
123 | #define SGTL5000_I2S_SCLKFREQ_64FS 0x0 | ||
124 | #define SGTL5000_I2S_SCLKFREQ_32FS 0x1 /* Not for RJ mode */ | ||
125 | #define SGTL5000_I2S_MASTER 0x0080 | ||
126 | #define SGTL5000_I2S_SCLK_INV 0x0040 | ||
127 | #define SGTL5000_I2S_DLEN_MASK 0x0030 | ||
128 | #define SGTL5000_I2S_DLEN_SHIFT 4 | ||
129 | #define SGTL5000_I2S_DLEN_WIDTH 2 | ||
130 | #define SGTL5000_I2S_DLEN_32 0x0 | ||
131 | #define SGTL5000_I2S_DLEN_24 0x1 | ||
132 | #define SGTL5000_I2S_DLEN_20 0x2 | ||
133 | #define SGTL5000_I2S_DLEN_16 0x3 | ||
134 | #define SGTL5000_I2S_MODE_MASK 0x000c | ||
135 | #define SGTL5000_I2S_MODE_SHIFT 2 | ||
136 | #define SGTL5000_I2S_MODE_WIDTH 2 | ||
137 | #define SGTL5000_I2S_MODE_I2S_LJ 0x0 | ||
138 | #define SGTL5000_I2S_MODE_RJ 0x1 | ||
139 | #define SGTL5000_I2S_MODE_PCM 0x2 | ||
140 | #define SGTL5000_I2S_LRALIGN 0x0002 | ||
141 | #define SGTL5000_I2S_LRPOL 0x0001 /* set for which mode */ | ||
142 | |||
143 | /* | ||
144 | * SGTL5000_CHIP_SSS_CTRL | ||
145 | */ | ||
146 | #define SGTL5000_DAP_MIX_LRSWAP 0x4000 | ||
147 | #define SGTL5000_DAP_LRSWAP 0x2000 | ||
148 | #define SGTL5000_DAC_LRSWAP 0x1000 | ||
149 | #define SGTL5000_I2S_OUT_LRSWAP 0x0400 | ||
150 | #define SGTL5000_DAP_MIX_SEL_MASK 0x0300 | ||
151 | #define SGTL5000_DAP_MIX_SEL_SHIFT 8 | ||
152 | #define SGTL5000_DAP_MIX_SEL_WIDTH 2 | ||
153 | #define SGTL5000_DAP_MIX_SEL_ADC 0x0 | ||
154 | #define SGTL5000_DAP_MIX_SEL_I2S_IN 0x1 | ||
155 | #define SGTL5000_DAP_SEL_MASK 0x00c0 | ||
156 | #define SGTL5000_DAP_SEL_SHIFT 6 | ||
157 | #define SGTL5000_DAP_SEL_WIDTH 2 | ||
158 | #define SGTL5000_DAP_SEL_ADC 0x0 | ||
159 | #define SGTL5000_DAP_SEL_I2S_IN 0x1 | ||
160 | #define SGTL5000_DAC_SEL_MASK 0x0030 | ||
161 | #define SGTL5000_DAC_SEL_SHIFT 4 | ||
162 | #define SGTL5000_DAC_SEL_WIDTH 2 | ||
163 | #define SGTL5000_DAC_SEL_ADC 0x0 | ||
164 | #define SGTL5000_DAC_SEL_I2S_IN 0x1 | ||
165 | #define SGTL5000_DAC_SEL_DAP 0x3 | ||
166 | #define SGTL5000_I2S_OUT_SEL_MASK 0x0003 | ||
167 | #define SGTL5000_I2S_OUT_SEL_SHIFT 0 | ||
168 | #define SGTL5000_I2S_OUT_SEL_WIDTH 2 | ||
169 | #define SGTL5000_I2S_OUT_SEL_ADC 0x0 | ||
170 | #define SGTL5000_I2S_OUT_SEL_I2S_IN 0x1 | ||
171 | #define SGTL5000_I2S_OUT_SEL_DAP 0x3 | ||
172 | |||
173 | /* | ||
174 | * SGTL5000_CHIP_ADCDAC_CTRL | ||
175 | */ | ||
176 | #define SGTL5000_VOL_BUSY_DAC_RIGHT 0x2000 | ||
177 | #define SGTL5000_VOL_BUSY_DAC_LEFT 0x1000 | ||
178 | #define SGTL5000_DAC_VOL_RAMP_EN 0x0200 | ||
179 | #define SGTL5000_DAC_VOL_RAMP_EXPO 0x0100 | ||
180 | #define SGTL5000_DAC_MUTE_RIGHT 0x0008 | ||
181 | #define SGTL5000_DAC_MUTE_LEFT 0x0004 | ||
182 | #define SGTL5000_ADC_HPF_FREEZE 0x0002 | ||
183 | #define SGTL5000_ADC_HPF_BYPASS 0x0001 | ||
184 | |||
185 | /* | ||
186 | * SGTL5000_CHIP_DAC_VOL | ||
187 | */ | ||
188 | #define SGTL5000_DAC_VOL_RIGHT_MASK 0xff00 | ||
189 | #define SGTL5000_DAC_VOL_RIGHT_SHIFT 8 | ||
190 | #define SGTL5000_DAC_VOL_RIGHT_WIDTH 8 | ||
191 | #define SGTL5000_DAC_VOL_LEFT_MASK 0x00ff | ||
192 | #define SGTL5000_DAC_VOL_LEFT_SHIFT 0 | ||
193 | #define SGTL5000_DAC_VOL_LEFT_WIDTH 8 | ||
194 | |||
195 | /* | ||
196 | * SGTL5000_CHIP_PAD_STRENGTH | ||
197 | */ | ||
198 | #define SGTL5000_PAD_I2S_LRCLK_MASK 0x0300 | ||
199 | #define SGTL5000_PAD_I2S_LRCLK_SHIFT 8 | ||
200 | #define SGTL5000_PAD_I2S_LRCLK_WIDTH 2 | ||
201 | #define SGTL5000_PAD_I2S_SCLK_MASK 0x00c0 | ||
202 | #define SGTL5000_PAD_I2S_SCLK_SHIFT 6 | ||
203 | #define SGTL5000_PAD_I2S_SCLK_WIDTH 2 | ||
204 | #define SGTL5000_PAD_I2S_DOUT_MASK 0x0030 | ||
205 | #define SGTL5000_PAD_I2S_DOUT_SHIFT 4 | ||
206 | #define SGTL5000_PAD_I2S_DOUT_WIDTH 2 | ||
207 | #define SGTL5000_PAD_I2C_SDA_MASK 0x000c | ||
208 | #define SGTL5000_PAD_I2C_SDA_SHIFT 2 | ||
209 | #define SGTL5000_PAD_I2C_SDA_WIDTH 2 | ||
210 | #define SGTL5000_PAD_I2C_SCL_MASK 0x0003 | ||
211 | #define SGTL5000_PAD_I2C_SCL_SHIFT 0 | ||
212 | #define SGTL5000_PAD_I2C_SCL_WIDTH 2 | ||
213 | |||
214 | /* | ||
215 | * SGTL5000_CHIP_ANA_ADC_CTRL | ||
216 | */ | ||
217 | #define SGTL5000_ADC_VOL_M6DB 0x0100 | ||
218 | #define SGTL5000_ADC_VOL_RIGHT_MASK 0x00f0 | ||
219 | #define SGTL5000_ADC_VOL_RIGHT_SHIFT 4 | ||
220 | #define SGTL5000_ADC_VOL_RIGHT_WIDTH 4 | ||
221 | #define SGTL5000_ADC_VOL_LEFT_MASK 0x000f | ||
222 | #define SGTL5000_ADC_VOL_LEFT_SHIFT 0 | ||
223 | #define SGTL5000_ADC_VOL_LEFT_WIDTH 4 | ||
224 | |||
225 | /* | ||
226 | * SGTL5000_CHIP_ANA_HP_CTRL | ||
227 | */ | ||
228 | #define SGTL5000_HP_VOL_RIGHT_MASK 0x7f00 | ||
229 | #define SGTL5000_HP_VOL_RIGHT_SHIFT 8 | ||
230 | #define SGTL5000_HP_VOL_RIGHT_WIDTH 7 | ||
231 | #define SGTL5000_HP_VOL_LEFT_MASK 0x007f | ||
232 | #define SGTL5000_HP_VOL_LEFT_SHIFT 0 | ||
233 | #define SGTL5000_HP_VOL_LEFT_WIDTH 7 | ||
234 | |||
235 | /* | ||
236 | * SGTL5000_CHIP_ANA_CTRL | ||
237 | */ | ||
238 | #define SGTL5000_LINE_OUT_MUTE 0x0100 | ||
239 | #define SGTL5000_HP_SEL_MASK 0x0040 | ||
240 | #define SGTL5000_HP_SEL_SHIFT 6 | ||
241 | #define SGTL5000_HP_SEL_WIDTH 1 | ||
242 | #define SGTL5000_HP_SEL_DAC 0x0 | ||
243 | #define SGTL5000_HP_SEL_LINE_IN 0x1 | ||
244 | #define SGTL5000_HP_ZCD_EN 0x0020 | ||
245 | #define SGTL5000_HP_MUTE 0x0010 | ||
246 | #define SGTL5000_ADC_SEL_MASK 0x0004 | ||
247 | #define SGTL5000_ADC_SEL_SHIFT 2 | ||
248 | #define SGTL5000_ADC_SEL_WIDTH 1 | ||
249 | #define SGTL5000_ADC_SEL_MIC 0x0 | ||
250 | #define SGTL5000_ADC_SEL_LINE_IN 0x1 | ||
251 | #define SGTL5000_ADC_ZCD_EN 0x0002 | ||
252 | #define SGTL5000_ADC_MUTE 0x0001 | ||
253 | |||
254 | /* | ||
255 | * SGTL5000_CHIP_LINREG_CTRL | ||
256 | */ | ||
257 | #define SGTL5000_VDDC_MAN_ASSN_MASK 0x0040 | ||
258 | #define SGTL5000_VDDC_MAN_ASSN_SHIFT 6 | ||
259 | #define SGTL5000_VDDC_MAN_ASSN_WIDTH 1 | ||
260 | #define SGTL5000_VDDC_MAN_ASSN_VDDA 0x0 | ||
261 | #define SGTL5000_VDDC_MAN_ASSN_VDDIO 0x1 | ||
262 | #define SGTL5000_VDDC_ASSN_OVRD 0x0020 | ||
263 | #define SGTL5000_LINREG_VDDD_MASK 0x000f | ||
264 | #define SGTL5000_LINREG_VDDD_SHIFT 0 | ||
265 | #define SGTL5000_LINREG_VDDD_WIDTH 4 | ||
266 | |||
267 | /* | ||
268 | * SGTL5000_CHIP_REF_CTRL | ||
269 | */ | ||
270 | #define SGTL5000_ANA_GND_MASK 0x01f0 | ||
271 | #define SGTL5000_ANA_GND_SHIFT 4 | ||
272 | #define SGTL5000_ANA_GND_WIDTH 5 | ||
273 | #define SGTL5000_ANA_GND_BASE 800 /* mv */ | ||
274 | #define SGTL5000_ANA_GND_STP 25 /*mv */ | ||
275 | #define SGTL5000_BIAS_CTRL_MASK 0x000e | ||
276 | #define SGTL5000_BIAS_CTRL_SHIFT 1 | ||
277 | #define SGTL5000_BIAS_CTRL_WIDTH 3 | ||
278 | #define SGTL5000_SMALL_POP 0x0001 | ||
279 | |||
280 | /* | ||
281 | * SGTL5000_CHIP_MIC_CTRL | ||
282 | */ | ||
283 | #define SGTL5000_BIAS_R_MASK 0x0200 | ||
284 | #define SGTL5000_BIAS_R_SHIFT 8 | ||
285 | #define SGTL5000_BIAS_R_WIDTH 2 | ||
286 | #define SGTL5000_BIAS_R_off 0x0 | ||
287 | #define SGTL5000_BIAS_R_2K 0x1 | ||
288 | #define SGTL5000_BIAS_R_4k 0x2 | ||
289 | #define SGTL5000_BIAS_R_8k 0x3 | ||
290 | #define SGTL5000_BIAS_VOLT_MASK 0x0070 | ||
291 | #define SGTL5000_BIAS_VOLT_SHIFT 4 | ||
292 | #define SGTL5000_BIAS_VOLT_WIDTH 3 | ||
293 | #define SGTL5000_MIC_GAIN_MASK 0x0003 | ||
294 | #define SGTL5000_MIC_GAIN_SHIFT 0 | ||
295 | #define SGTL5000_MIC_GAIN_WIDTH 2 | ||
296 | |||
297 | /* | ||
298 | * SGTL5000_CHIP_LINE_OUT_CTRL | ||
299 | */ | ||
300 | #define SGTL5000_LINE_OUT_CURRENT_MASK 0x0f00 | ||
301 | #define SGTL5000_LINE_OUT_CURRENT_SHIFT 8 | ||
302 | #define SGTL5000_LINE_OUT_CURRENT_WIDTH 4 | ||
303 | #define SGTL5000_LINE_OUT_CURRENT_180u 0x0 | ||
304 | #define SGTL5000_LINE_OUT_CURRENT_270u 0x1 | ||
305 | #define SGTL5000_LINE_OUT_CURRENT_360u 0x3 | ||
306 | #define SGTL5000_LINE_OUT_CURRENT_450u 0x7 | ||
307 | #define SGTL5000_LINE_OUT_CURRENT_540u 0xf | ||
308 | #define SGTL5000_LINE_OUT_GND_MASK 0x003f | ||
309 | #define SGTL5000_LINE_OUT_GND_SHIFT 0 | ||
310 | #define SGTL5000_LINE_OUT_GND_WIDTH 6 | ||
311 | #define SGTL5000_LINE_OUT_GND_BASE 800 /* mv */ | ||
312 | #define SGTL5000_LINE_OUT_GND_STP 25 | ||
313 | #define SGTL5000_LINE_OUT_GND_MAX 0x23 | ||
314 | |||
315 | /* | ||
316 | * SGTL5000_CHIP_LINE_OUT_VOL | ||
317 | */ | ||
318 | #define SGTL5000_LINE_OUT_VOL_RIGHT_MASK 0x1f00 | ||
319 | #define SGTL5000_LINE_OUT_VOL_RIGHT_SHIFT 8 | ||
320 | #define SGTL5000_LINE_OUT_VOL_RIGHT_WIDTH 5 | ||
321 | #define SGTL5000_LINE_OUT_VOL_LEFT_MASK 0x001f | ||
322 | #define SGTL5000_LINE_OUT_VOL_LEFT_SHIFT 0 | ||
323 | #define SGTL5000_LINE_OUT_VOL_LEFT_WIDTH 5 | ||
324 | |||
325 | /* | ||
326 | * SGTL5000_CHIP_ANA_POWER | ||
327 | */ | ||
328 | #define SGTL5000_DAC_STEREO 0x4000 | ||
329 | #define SGTL5000_LINREG_SIMPLE_POWERUP 0x2000 | ||
330 | #define SGTL5000_STARTUP_POWERUP 0x1000 | ||
331 | #define SGTL5000_VDDC_CHRGPMP_POWERUP 0x0800 | ||
332 | #define SGTL5000_PLL_POWERUP 0x0400 | ||
333 | #define SGTL5000_LINEREG_D_POWERUP 0x0200 | ||
334 | #define SGTL5000_VCOAMP_POWERUP 0x0100 | ||
335 | #define SGTL5000_VAG_POWERUP 0x0080 | ||
336 | #define SGTL5000_ADC_STEREO 0x0040 | ||
337 | #define SGTL5000_REFTOP_POWERUP 0x0020 | ||
338 | #define SGTL5000_HP_POWERUP 0x0010 | ||
339 | #define SGTL5000_DAC_POWERUP 0x0008 | ||
340 | #define SGTL5000_CAPLESS_HP_POWERUP 0x0004 | ||
341 | #define SGTL5000_ADC_POWERUP 0x0002 | ||
342 | #define SGTL5000_LINE_OUT_POWERUP 0x0001 | ||
343 | |||
344 | /* | ||
345 | * SGTL5000_CHIP_PLL_CTRL | ||
346 | */ | ||
347 | #define SGTL5000_PLL_INT_DIV_MASK 0xf800 | ||
348 | #define SGTL5000_PLL_INT_DIV_SHIFT 11 | ||
349 | #define SGTL5000_PLL_INT_DIV_WIDTH 5 | ||
350 | #define SGTL5000_PLL_FRAC_DIV_MASK 0x0700 | ||
351 | #define SGTL5000_PLL_FRAC_DIV_SHIFT 0 | ||
352 | #define SGTL5000_PLL_FRAC_DIV_WIDTH 11 | ||
353 | |||
354 | /* | ||
355 | * SGTL5000_CHIP_CLK_TOP_CTRL | ||
356 | */ | ||
357 | #define SGTL5000_INT_OSC_EN 0x0800 | ||
358 | #define SGTL5000_INPUT_FREQ_DIV2 0x0008 | ||
359 | |||
360 | /* | ||
361 | * SGTL5000_CHIP_ANA_STATUS | ||
362 | */ | ||
363 | #define SGTL5000_HP_LRSHORT 0x0200 | ||
364 | #define SGTL5000_CAPLESS_SHORT 0x0100 | ||
365 | #define SGTL5000_PLL_LOCKED 0x0010 | ||
366 | |||
367 | /* | ||
368 | * SGTL5000_CHIP_SHORT_CTRL | ||
369 | */ | ||
370 | #define SGTL5000_LVLADJR_MASK 0x7000 | ||
371 | #define SGTL5000_LVLADJR_SHIFT 12 | ||
372 | #define SGTL5000_LVLADJR_WIDTH 3 | ||
373 | #define SGTL5000_LVLADJL_MASK 0x0700 | ||
374 | #define SGTL5000_LVLADJL_SHIFT 8 | ||
375 | #define SGTL5000_LVLADJL_WIDTH 3 | ||
376 | #define SGTL5000_LVLADJC_MASK 0x0070 | ||
377 | #define SGTL5000_LVLADJC_SHIFT 4 | ||
378 | #define SGTL5000_LVLADJC_WIDTH 3 | ||
379 | #define SGTL5000_LR_SHORT_MOD_MASK 0x000c | ||
380 | #define SGTL5000_LR_SHORT_MOD_SHIFT 2 | ||
381 | #define SGTL5000_LR_SHORT_MOD_WIDTH 2 | ||
382 | #define SGTL5000_CM_SHORT_MOD_MASK 0x0003 | ||
383 | #define SGTL5000_CM_SHORT_MOD_SHIFT 0 | ||
384 | #define SGTL5000_CM_SHORT_MOD_WIDTH 2 | ||
385 | |||
386 | /* | ||
387 | *SGTL5000_CHIP_ANA_TEST2 | ||
388 | */ | ||
389 | #define SGTL5000_MONO_DAC 0x1000 | ||
390 | |||
391 | /* | ||
392 | * SGTL5000_DAP_CTRL | ||
393 | */ | ||
394 | #define SGTL5000_DAP_MIX_EN 0x0010 | ||
395 | #define SGTL5000_DAP_EN 0x0001 | ||
396 | |||
397 | #define SGTL5000_SYSCLK 0x00 | ||
398 | #define SGTL5000_LRCLK 0x01 | ||
399 | |||
400 | #endif | ||
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c new file mode 100644 index 000000000000..2a30eae1881c --- /dev/null +++ b/sound/soc/codecs/sn95031.c | |||
@@ -0,0 +1,949 @@ | |||
1 | /* | ||
2 | * sn95031.c - TI sn95031 Codec driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
27 | |||
28 | #include <linux/platform_device.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <asm/intel_scu_ipc.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/soc-dapm.h> | ||
35 | #include <sound/initval.h> | ||
36 | #include <sound/tlv.h> | ||
37 | #include <sound/jack.h> | ||
38 | #include "sn95031.h" | ||
39 | |||
40 | #define SN95031_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_44100) | ||
41 | #define SN95031_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | ||
42 | |||
43 | /* adc helper functions */ | ||
44 | |||
45 | /* enables mic bias voltage */ | ||
46 | static void sn95031_enable_mic_bias(struct snd_soc_codec *codec) | ||
47 | { | ||
48 | snd_soc_write(codec, SN95031_VAUD, BIT(2)|BIT(1)|BIT(0)); | ||
49 | snd_soc_update_bits(codec, SN95031_MICBIAS, BIT(2), BIT(2)); | ||
50 | } | ||
51 | |||
52 | /* Enable/Disable the ADC depending on the argument */ | ||
53 | static void configure_adc(struct snd_soc_codec *sn95031_codec, int val) | ||
54 | { | ||
55 | int value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); | ||
56 | |||
57 | if (val) { | ||
58 | /* Enable and start the ADC */ | ||
59 | value |= (SN95031_ADC_ENBL | SN95031_ADC_START); | ||
60 | value &= (~SN95031_ADC_NO_LOOP); | ||
61 | } else { | ||
62 | /* Just stop the ADC */ | ||
63 | value &= (~SN95031_ADC_START); | ||
64 | } | ||
65 | snd_soc_write(sn95031_codec, SN95031_ADC1CNTL1, value); | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * finds an empty channel for conversion | ||
70 | * If the ADC is not enabled then start using 0th channel | ||
71 | * itself. Otherwise find an empty channel by looking for a | ||
72 | * channel in which the stopbit is set to 1. returns the index | ||
73 | * of the first free channel if succeeds or an error code. | ||
74 | * | ||
75 | * Context: can sleep | ||
76 | * | ||
77 | */ | ||
78 | static int find_free_channel(struct snd_soc_codec *sn95031_codec) | ||
79 | { | ||
80 | int ret = 0, i, value; | ||
81 | |||
82 | /* check whether ADC is enabled */ | ||
83 | value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1); | ||
84 | |||
85 | if ((value & SN95031_ADC_ENBL) == 0) | ||
86 | return 0; | ||
87 | |||
88 | /* ADC is already enabled; Looking for an empty channel */ | ||
89 | for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) { | ||
90 | value = snd_soc_read(sn95031_codec, | ||
91 | SN95031_ADC_CHNL_START_ADDR + i); | ||
92 | if (value & SN95031_STOPBIT_MASK) { | ||
93 | ret = i; | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | return (ret > SN95031_ADC_LOOP_MAX) ? (-EINVAL) : ret; | ||
98 | } | ||
99 | |||
100 | /* Initialize the ADC for reading micbias values. Can sleep. */ | ||
101 | static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec) | ||
102 | { | ||
103 | int base_addr, chnl_addr; | ||
104 | int value; | ||
105 | static int channel_index; | ||
106 | |||
107 | /* Index of the first channel in which the stop bit is set */ | ||
108 | channel_index = find_free_channel(sn95031_codec); | ||
109 | if (channel_index < 0) { | ||
110 | pr_err("No free ADC channels"); | ||
111 | return channel_index; | ||
112 | } | ||
113 | |||
114 | base_addr = SN95031_ADC_CHNL_START_ADDR + channel_index; | ||
115 | |||
116 | if (!(channel_index == 0 || channel_index == SN95031_ADC_LOOP_MAX)) { | ||
117 | /* Reset stop bit for channels other than 0 and 12 */ | ||
118 | value = snd_soc_read(sn95031_codec, base_addr); | ||
119 | /* Set the stop bit to zero */ | ||
120 | snd_soc_write(sn95031_codec, base_addr, value & 0xEF); | ||
121 | /* Index of the first free channel */ | ||
122 | base_addr++; | ||
123 | channel_index++; | ||
124 | } | ||
125 | |||
126 | /* Since this is the last channel, set the stop bit | ||
127 | to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ | ||
128 | snd_soc_write(sn95031_codec, base_addr, | ||
129 | SN95031_AUDIO_DETECT_CODE | 0x10); | ||
130 | |||
131 | chnl_addr = SN95031_ADC_DATA_START_ADDR + 2 * channel_index; | ||
132 | pr_debug("mid_initialize : %x", chnl_addr); | ||
133 | configure_adc(sn95031_codec, 1); | ||
134 | return chnl_addr; | ||
135 | } | ||
136 | |||
137 | |||
138 | /* reads the ADC registers and gets the mic bias value in mV. */ | ||
139 | static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec) | ||
140 | { | ||
141 | u16 adc_adr = sn95031_initialize_adc(codec); | ||
142 | u16 adc_val1, adc_val2; | ||
143 | unsigned int mic_bias; | ||
144 | |||
145 | sn95031_enable_mic_bias(codec); | ||
146 | |||
147 | /* Enable the sound card for conversion before reading */ | ||
148 | snd_soc_write(codec, SN95031_ADC1CNTL3, 0x05); | ||
149 | /* Re-toggle the RRDATARD bit */ | ||
150 | snd_soc_write(codec, SN95031_ADC1CNTL3, 0x04); | ||
151 | |||
152 | /* Read the higher bits of data */ | ||
153 | msleep(1000); | ||
154 | adc_val1 = snd_soc_read(codec, adc_adr); | ||
155 | adc_adr++; | ||
156 | adc_val2 = snd_soc_read(codec, adc_adr); | ||
157 | |||
158 | /* Adding lower two bits to the higher bits */ | ||
159 | mic_bias = (adc_val1 << 2) + (adc_val2 & 3); | ||
160 | mic_bias = (mic_bias * SN95031_ADC_ONE_LSB_MULTIPLIER) / 1000; | ||
161 | pr_debug("mic bias = %dmV\n", mic_bias); | ||
162 | return mic_bias; | ||
163 | } | ||
164 | EXPORT_SYMBOL_GPL(sn95031_get_mic_bias); | ||
165 | /*end - adc helper functions */ | ||
166 | |||
167 | static inline unsigned int sn95031_read(struct snd_soc_codec *codec, | ||
168 | unsigned int reg) | ||
169 | { | ||
170 | u8 value = 0; | ||
171 | int ret; | ||
172 | |||
173 | ret = intel_scu_ipc_ioread8(reg, &value); | ||
174 | if (ret) | ||
175 | pr_err("read of %x failed, err %d\n", reg, ret); | ||
176 | return value; | ||
177 | |||
178 | } | ||
179 | |||
180 | static inline int sn95031_write(struct snd_soc_codec *codec, | ||
181 | unsigned int reg, unsigned int value) | ||
182 | { | ||
183 | int ret; | ||
184 | |||
185 | ret = intel_scu_ipc_iowrite8(reg, value); | ||
186 | if (ret) | ||
187 | pr_err("write of %x failed, err %d\n", reg, ret); | ||
188 | return ret; | ||
189 | } | ||
190 | |||
191 | static int sn95031_set_vaud_bias(struct snd_soc_codec *codec, | ||
192 | enum snd_soc_bias_level level) | ||
193 | { | ||
194 | switch (level) { | ||
195 | case SND_SOC_BIAS_ON: | ||
196 | break; | ||
197 | |||
198 | case SND_SOC_BIAS_PREPARE: | ||
199 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) { | ||
200 | pr_debug("vaud_bias powering up pll\n"); | ||
201 | /* power up the pll */ | ||
202 | snd_soc_write(codec, SN95031_AUDPLLCTRL, BIT(5)); | ||
203 | /* enable pcm 2 */ | ||
204 | snd_soc_update_bits(codec, SN95031_PCM2C2, | ||
205 | BIT(0), BIT(0)); | ||
206 | } | ||
207 | break; | ||
208 | |||
209 | case SND_SOC_BIAS_STANDBY: | ||
210 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
211 | pr_debug("vaud_bias power up rail\n"); | ||
212 | /* power up the rail */ | ||
213 | snd_soc_write(codec, SN95031_VAUD, | ||
214 | BIT(2)|BIT(1)|BIT(0)); | ||
215 | msleep(1); | ||
216 | } else if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE) { | ||
217 | /* turn off pcm */ | ||
218 | pr_debug("vaud_bias power dn pcm\n"); | ||
219 | snd_soc_update_bits(codec, SN95031_PCM2C2, BIT(0), 0); | ||
220 | snd_soc_write(codec, SN95031_AUDPLLCTRL, 0); | ||
221 | } | ||
222 | break; | ||
223 | |||
224 | |||
225 | case SND_SOC_BIAS_OFF: | ||
226 | pr_debug("vaud_bias _OFF doing rail shutdown\n"); | ||
227 | snd_soc_write(codec, SN95031_VAUD, BIT(3)); | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | codec->dapm.bias_level = level; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int sn95031_vhs_event(struct snd_soc_dapm_widget *w, | ||
236 | struct snd_kcontrol *kcontrol, int event) | ||
237 | { | ||
238 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
239 | pr_debug("VHS SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); | ||
240 | /* power up the rail */ | ||
241 | snd_soc_write(w->codec, SN95031_VHSP, 0x3D); | ||
242 | snd_soc_write(w->codec, SN95031_VHSN, 0x3F); | ||
243 | msleep(1); | ||
244 | } else if (SND_SOC_DAPM_EVENT_OFF(event)) { | ||
245 | pr_debug("VHS SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); | ||
246 | snd_soc_write(w->codec, SN95031_VHSP, 0xC4); | ||
247 | snd_soc_write(w->codec, SN95031_VHSN, 0x04); | ||
248 | } | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int sn95031_vihf_event(struct snd_soc_dapm_widget *w, | ||
253 | struct snd_kcontrol *kcontrol, int event) | ||
254 | { | ||
255 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
256 | pr_debug("VIHF SND_SOC_DAPM_EVENT_ON doing rail startup now\n"); | ||
257 | /* power up the rail */ | ||
258 | snd_soc_write(w->codec, SN95031_VIHF, 0x27); | ||
259 | msleep(1); | ||
260 | } else if (SND_SOC_DAPM_EVENT_OFF(event)) { | ||
261 | pr_debug("VIHF SND_SOC_DAPM_EVENT_OFF doing rail shutdown\n"); | ||
262 | snd_soc_write(w->codec, SN95031_VIHF, 0x24); | ||
263 | } | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int sn95031_dmic12_event(struct snd_soc_dapm_widget *w, | ||
268 | struct snd_kcontrol *k, int event) | ||
269 | { | ||
270 | unsigned int ldo = 0, clk_dir = 0, data_dir = 0; | ||
271 | |||
272 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
273 | ldo = BIT(5)|BIT(4); | ||
274 | clk_dir = BIT(0); | ||
275 | data_dir = BIT(7); | ||
276 | } | ||
277 | /* program DMIC LDO, clock and set clock */ | ||
278 | snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); | ||
279 | snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(0), clk_dir); | ||
280 | snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(7), data_dir); | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static int sn95031_dmic34_event(struct snd_soc_dapm_widget *w, | ||
285 | struct snd_kcontrol *k, int event) | ||
286 | { | ||
287 | unsigned int ldo = 0, clk_dir = 0, data_dir = 0; | ||
288 | |||
289 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
290 | ldo = BIT(5)|BIT(4); | ||
291 | clk_dir = BIT(2); | ||
292 | data_dir = BIT(1); | ||
293 | } | ||
294 | /* program DMIC LDO, clock and set clock */ | ||
295 | snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(5)|BIT(4), ldo); | ||
296 | snd_soc_update_bits(w->codec, SN95031_DMICBUF0123, BIT(2), clk_dir); | ||
297 | snd_soc_update_bits(w->codec, SN95031_DMICBUF45, BIT(1), data_dir); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int sn95031_dmic56_event(struct snd_soc_dapm_widget *w, | ||
302 | struct snd_kcontrol *k, int event) | ||
303 | { | ||
304 | unsigned int ldo = 0; | ||
305 | |||
306 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
307 | ldo = BIT(7)|BIT(6); | ||
308 | |||
309 | /* program DMIC LDO */ | ||
310 | snd_soc_update_bits(w->codec, SN95031_MICBIAS, BIT(7)|BIT(6), ldo); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | /* mux controls */ | ||
315 | static const char *sn95031_mic_texts[] = { "AMIC", "LineIn" }; | ||
316 | |||
317 | static const struct soc_enum sn95031_micl_enum = | ||
318 | SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 1, 2, sn95031_mic_texts); | ||
319 | |||
320 | static const struct snd_kcontrol_new sn95031_micl_mux_control = | ||
321 | SOC_DAPM_ENUM("Route", sn95031_micl_enum); | ||
322 | |||
323 | static const struct soc_enum sn95031_micr_enum = | ||
324 | SOC_ENUM_SINGLE(SN95031_ADCCONFIG, 3, 2, sn95031_mic_texts); | ||
325 | |||
326 | static const struct snd_kcontrol_new sn95031_micr_mux_control = | ||
327 | SOC_DAPM_ENUM("Route", sn95031_micr_enum); | ||
328 | |||
329 | static const char *sn95031_input_texts[] = { "DMIC1", "DMIC2", "DMIC3", | ||
330 | "DMIC4", "DMIC5", "DMIC6", | ||
331 | "ADC Left", "ADC Right" }; | ||
332 | |||
333 | static const struct soc_enum sn95031_input1_enum = | ||
334 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 0, 8, sn95031_input_texts); | ||
335 | |||
336 | static const struct snd_kcontrol_new sn95031_input1_mux_control = | ||
337 | SOC_DAPM_ENUM("Route", sn95031_input1_enum); | ||
338 | |||
339 | static const struct soc_enum sn95031_input2_enum = | ||
340 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX12, 4, 8, sn95031_input_texts); | ||
341 | |||
342 | static const struct snd_kcontrol_new sn95031_input2_mux_control = | ||
343 | SOC_DAPM_ENUM("Route", sn95031_input2_enum); | ||
344 | |||
345 | static const struct soc_enum sn95031_input3_enum = | ||
346 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 0, 8, sn95031_input_texts); | ||
347 | |||
348 | static const struct snd_kcontrol_new sn95031_input3_mux_control = | ||
349 | SOC_DAPM_ENUM("Route", sn95031_input3_enum); | ||
350 | |||
351 | static const struct soc_enum sn95031_input4_enum = | ||
352 | SOC_ENUM_SINGLE(SN95031_AUDIOMUX34, 4, 8, sn95031_input_texts); | ||
353 | |||
354 | static const struct snd_kcontrol_new sn95031_input4_mux_control = | ||
355 | SOC_DAPM_ENUM("Route", sn95031_input4_enum); | ||
356 | |||
357 | /* capture path controls */ | ||
358 | |||
359 | static const char *sn95031_micmode_text[] = {"Single Ended", "Differential"}; | ||
360 | |||
361 | /* 0dB to 30dB in 10dB steps */ | ||
362 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 10, 0); | ||
363 | |||
364 | static const struct soc_enum sn95031_micmode1_enum = | ||
365 | SOC_ENUM_SINGLE(SN95031_MICAMP1, 1, 2, sn95031_micmode_text); | ||
366 | static const struct soc_enum sn95031_micmode2_enum = | ||
367 | SOC_ENUM_SINGLE(SN95031_MICAMP2, 1, 2, sn95031_micmode_text); | ||
368 | |||
369 | static const char *sn95031_dmic_cfg_text[] = {"GPO", "DMIC"}; | ||
370 | |||
371 | static const struct soc_enum sn95031_dmic12_cfg_enum = | ||
372 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 0, 2, sn95031_dmic_cfg_text); | ||
373 | static const struct soc_enum sn95031_dmic34_cfg_enum = | ||
374 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 1, 2, sn95031_dmic_cfg_text); | ||
375 | static const struct soc_enum sn95031_dmic56_cfg_enum = | ||
376 | SOC_ENUM_SINGLE(SN95031_DMICMUX, 2, 2, sn95031_dmic_cfg_text); | ||
377 | |||
378 | static const struct snd_kcontrol_new sn95031_snd_controls[] = { | ||
379 | SOC_ENUM("Mic1Mode Capture Route", sn95031_micmode1_enum), | ||
380 | SOC_ENUM("Mic2Mode Capture Route", sn95031_micmode2_enum), | ||
381 | SOC_ENUM("DMIC12 Capture Route", sn95031_dmic12_cfg_enum), | ||
382 | SOC_ENUM("DMIC34 Capture Route", sn95031_dmic34_cfg_enum), | ||
383 | SOC_ENUM("DMIC56 Capture Route", sn95031_dmic56_cfg_enum), | ||
384 | SOC_SINGLE_TLV("Mic1 Capture Volume", SN95031_MICAMP1, | ||
385 | 2, 4, 0, mic_tlv), | ||
386 | SOC_SINGLE_TLV("Mic2 Capture Volume", SN95031_MICAMP2, | ||
387 | 2, 4, 0, mic_tlv), | ||
388 | }; | ||
389 | |||
390 | /* DAPM widgets */ | ||
391 | static const struct snd_soc_dapm_widget sn95031_dapm_widgets[] = { | ||
392 | |||
393 | /* all end points mic, hs etc */ | ||
394 | SND_SOC_DAPM_OUTPUT("HPOUTL"), | ||
395 | SND_SOC_DAPM_OUTPUT("HPOUTR"), | ||
396 | SND_SOC_DAPM_OUTPUT("EPOUT"), | ||
397 | SND_SOC_DAPM_OUTPUT("IHFOUTL"), | ||
398 | SND_SOC_DAPM_OUTPUT("IHFOUTR"), | ||
399 | SND_SOC_DAPM_OUTPUT("LINEOUTL"), | ||
400 | SND_SOC_DAPM_OUTPUT("LINEOUTR"), | ||
401 | SND_SOC_DAPM_OUTPUT("VIB1OUT"), | ||
402 | SND_SOC_DAPM_OUTPUT("VIB2OUT"), | ||
403 | |||
404 | SND_SOC_DAPM_INPUT("AMIC1"), /* headset mic */ | ||
405 | SND_SOC_DAPM_INPUT("AMIC2"), | ||
406 | SND_SOC_DAPM_INPUT("DMIC1"), | ||
407 | SND_SOC_DAPM_INPUT("DMIC2"), | ||
408 | SND_SOC_DAPM_INPUT("DMIC3"), | ||
409 | SND_SOC_DAPM_INPUT("DMIC4"), | ||
410 | SND_SOC_DAPM_INPUT("DMIC5"), | ||
411 | SND_SOC_DAPM_INPUT("DMIC6"), | ||
412 | SND_SOC_DAPM_INPUT("LINEINL"), | ||
413 | SND_SOC_DAPM_INPUT("LINEINR"), | ||
414 | |||
415 | SND_SOC_DAPM_MICBIAS("AMIC1Bias", SN95031_MICBIAS, 2, 0), | ||
416 | SND_SOC_DAPM_MICBIAS("AMIC2Bias", SN95031_MICBIAS, 3, 0), | ||
417 | SND_SOC_DAPM_MICBIAS("DMIC12Bias", SN95031_DMICMUX, 3, 0), | ||
418 | SND_SOC_DAPM_MICBIAS("DMIC34Bias", SN95031_DMICMUX, 4, 0), | ||
419 | SND_SOC_DAPM_MICBIAS("DMIC56Bias", SN95031_DMICMUX, 5, 0), | ||
420 | |||
421 | SND_SOC_DAPM_SUPPLY("DMIC12supply", SN95031_DMICLK, 0, 0, | ||
422 | sn95031_dmic12_event, | ||
423 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
424 | SND_SOC_DAPM_SUPPLY("DMIC34supply", SN95031_DMICLK, 1, 0, | ||
425 | sn95031_dmic34_event, | ||
426 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
427 | SND_SOC_DAPM_SUPPLY("DMIC56supply", SN95031_DMICLK, 2, 0, | ||
428 | sn95031_dmic56_event, | ||
429 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
430 | |||
431 | SND_SOC_DAPM_AIF_OUT("PCM_Out", "Capture", 0, | ||
432 | SND_SOC_NOPM, 0, 0), | ||
433 | |||
434 | SND_SOC_DAPM_SUPPLY("Headset Rail", SND_SOC_NOPM, 0, 0, | ||
435 | sn95031_vhs_event, | ||
436 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
437 | SND_SOC_DAPM_SUPPLY("Speaker Rail", SND_SOC_NOPM, 0, 0, | ||
438 | sn95031_vihf_event, | ||
439 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
440 | |||
441 | /* playback path driver enables */ | ||
442 | SND_SOC_DAPM_PGA("Headset Left Playback", | ||
443 | SN95031_DRIVEREN, 0, 0, NULL, 0), | ||
444 | SND_SOC_DAPM_PGA("Headset Right Playback", | ||
445 | SN95031_DRIVEREN, 1, 0, NULL, 0), | ||
446 | SND_SOC_DAPM_PGA("Speaker Left Playback", | ||
447 | SN95031_DRIVEREN, 2, 0, NULL, 0), | ||
448 | SND_SOC_DAPM_PGA("Speaker Right Playback", | ||
449 | SN95031_DRIVEREN, 3, 0, NULL, 0), | ||
450 | SND_SOC_DAPM_PGA("Vibra1 Playback", | ||
451 | SN95031_DRIVEREN, 4, 0, NULL, 0), | ||
452 | SND_SOC_DAPM_PGA("Vibra2 Playback", | ||
453 | SN95031_DRIVEREN, 5, 0, NULL, 0), | ||
454 | SND_SOC_DAPM_PGA("Earpiece Playback", | ||
455 | SN95031_DRIVEREN, 6, 0, NULL, 0), | ||
456 | SND_SOC_DAPM_PGA("Lineout Left Playback", | ||
457 | SN95031_LOCTL, 0, 0, NULL, 0), | ||
458 | SND_SOC_DAPM_PGA("Lineout Right Playback", | ||
459 | SN95031_LOCTL, 4, 0, NULL, 0), | ||
460 | |||
461 | /* playback path filter enable */ | ||
462 | SND_SOC_DAPM_PGA("Headset Left Filter", | ||
463 | SN95031_HSEPRXCTRL, 4, 0, NULL, 0), | ||
464 | SND_SOC_DAPM_PGA("Headset Right Filter", | ||
465 | SN95031_HSEPRXCTRL, 5, 0, NULL, 0), | ||
466 | SND_SOC_DAPM_PGA("Speaker Left Filter", | ||
467 | SN95031_IHFRXCTRL, 0, 0, NULL, 0), | ||
468 | SND_SOC_DAPM_PGA("Speaker Right Filter", | ||
469 | SN95031_IHFRXCTRL, 1, 0, NULL, 0), | ||
470 | |||
471 | /* DACs */ | ||
472 | SND_SOC_DAPM_DAC("HSDAC Left", "Headset", | ||
473 | SN95031_DACCONFIG, 0, 0), | ||
474 | SND_SOC_DAPM_DAC("HSDAC Right", "Headset", | ||
475 | SN95031_DACCONFIG, 1, 0), | ||
476 | SND_SOC_DAPM_DAC("IHFDAC Left", "Speaker", | ||
477 | SN95031_DACCONFIG, 2, 0), | ||
478 | SND_SOC_DAPM_DAC("IHFDAC Right", "Speaker", | ||
479 | SN95031_DACCONFIG, 3, 0), | ||
480 | SND_SOC_DAPM_DAC("Vibra1 DAC", "Vibra1", | ||
481 | SN95031_VIB1C5, 1, 0), | ||
482 | SND_SOC_DAPM_DAC("Vibra2 DAC", "Vibra2", | ||
483 | SN95031_VIB2C5, 1, 0), | ||
484 | |||
485 | /* capture widgets */ | ||
486 | SND_SOC_DAPM_PGA("LineIn Enable Left", SN95031_MICAMP1, | ||
487 | 7, 0, NULL, 0), | ||
488 | SND_SOC_DAPM_PGA("LineIn Enable Right", SN95031_MICAMP2, | ||
489 | 7, 0, NULL, 0), | ||
490 | |||
491 | SND_SOC_DAPM_PGA("MIC1 Enable", SN95031_MICAMP1, 0, 0, NULL, 0), | ||
492 | SND_SOC_DAPM_PGA("MIC2 Enable", SN95031_MICAMP2, 0, 0, NULL, 0), | ||
493 | SND_SOC_DAPM_PGA("TX1 Enable", SN95031_AUDIOTXEN, 2, 0, NULL, 0), | ||
494 | SND_SOC_DAPM_PGA("TX2 Enable", SN95031_AUDIOTXEN, 3, 0, NULL, 0), | ||
495 | SND_SOC_DAPM_PGA("TX3 Enable", SN95031_AUDIOTXEN, 4, 0, NULL, 0), | ||
496 | SND_SOC_DAPM_PGA("TX4 Enable", SN95031_AUDIOTXEN, 5, 0, NULL, 0), | ||
497 | |||
498 | /* ADC have null stream as they will be turned ON by TX path */ | ||
499 | SND_SOC_DAPM_ADC("ADC Left", NULL, | ||
500 | SN95031_ADCCONFIG, 0, 0), | ||
501 | SND_SOC_DAPM_ADC("ADC Right", NULL, | ||
502 | SN95031_ADCCONFIG, 2, 0), | ||
503 | |||
504 | SND_SOC_DAPM_MUX("Mic_InputL Capture Route", | ||
505 | SND_SOC_NOPM, 0, 0, &sn95031_micl_mux_control), | ||
506 | SND_SOC_DAPM_MUX("Mic_InputR Capture Route", | ||
507 | SND_SOC_NOPM, 0, 0, &sn95031_micr_mux_control), | ||
508 | |||
509 | SND_SOC_DAPM_MUX("Txpath1 Capture Route", | ||
510 | SND_SOC_NOPM, 0, 0, &sn95031_input1_mux_control), | ||
511 | SND_SOC_DAPM_MUX("Txpath2 Capture Route", | ||
512 | SND_SOC_NOPM, 0, 0, &sn95031_input2_mux_control), | ||
513 | SND_SOC_DAPM_MUX("Txpath3 Capture Route", | ||
514 | SND_SOC_NOPM, 0, 0, &sn95031_input3_mux_control), | ||
515 | SND_SOC_DAPM_MUX("Txpath4 Capture Route", | ||
516 | SND_SOC_NOPM, 0, 0, &sn95031_input4_mux_control), | ||
517 | |||
518 | }; | ||
519 | |||
520 | static const struct snd_soc_dapm_route sn95031_audio_map[] = { | ||
521 | /* headset and earpiece map */ | ||
522 | { "HPOUTL", NULL, "Headset Rail"}, | ||
523 | { "HPOUTR", NULL, "Headset Rail"}, | ||
524 | { "HPOUTL", NULL, "Headset Left Playback" }, | ||
525 | { "HPOUTR", NULL, "Headset Right Playback" }, | ||
526 | { "EPOUT", NULL, "Earpiece Playback" }, | ||
527 | { "Headset Left Playback", NULL, "Headset Left Filter"}, | ||
528 | { "Headset Right Playback", NULL, "Headset Right Filter"}, | ||
529 | { "Earpiece Playback", NULL, "Headset Left Filter"}, | ||
530 | { "Headset Left Filter", NULL, "HSDAC Left"}, | ||
531 | { "Headset Right Filter", NULL, "HSDAC Right"}, | ||
532 | |||
533 | /* speaker map */ | ||
534 | { "IHFOUTL", NULL, "Speaker Rail"}, | ||
535 | { "IHFOUTR", NULL, "Speaker Rail"}, | ||
536 | { "IHFOUTL", "NULL", "Speaker Left Playback"}, | ||
537 | { "IHFOUTR", "NULL", "Speaker Right Playback"}, | ||
538 | { "Speaker Left Playback", NULL, "Speaker Left Filter"}, | ||
539 | { "Speaker Right Playback", NULL, "Speaker Right Filter"}, | ||
540 | { "Speaker Left Filter", NULL, "IHFDAC Left"}, | ||
541 | { "Speaker Right Filter", NULL, "IHFDAC Right"}, | ||
542 | |||
543 | /* vibra map */ | ||
544 | { "VIB1OUT", NULL, "Vibra1 Playback"}, | ||
545 | { "Vibra1 Playback", NULL, "Vibra1 DAC"}, | ||
546 | |||
547 | { "VIB2OUT", NULL, "Vibra2 Playback"}, | ||
548 | { "Vibra2 Playback", NULL, "Vibra2 DAC"}, | ||
549 | |||
550 | /* lineout */ | ||
551 | { "LINEOUTL", NULL, "Lineout Left Playback"}, | ||
552 | { "LINEOUTR", NULL, "Lineout Right Playback"}, | ||
553 | { "Lineout Left Playback", NULL, "Headset Left Filter"}, | ||
554 | { "Lineout Left Playback", NULL, "Speaker Left Filter"}, | ||
555 | { "Lineout Left Playback", NULL, "Vibra1 DAC"}, | ||
556 | { "Lineout Right Playback", NULL, "Headset Right Filter"}, | ||
557 | { "Lineout Right Playback", NULL, "Speaker Right Filter"}, | ||
558 | { "Lineout Right Playback", NULL, "Vibra2 DAC"}, | ||
559 | |||
560 | /* Headset (AMIC1) mic */ | ||
561 | { "AMIC1Bias", NULL, "AMIC1"}, | ||
562 | { "MIC1 Enable", NULL, "AMIC1Bias"}, | ||
563 | { "Mic_InputL Capture Route", "AMIC", "MIC1 Enable"}, | ||
564 | |||
565 | /* AMIC2 */ | ||
566 | { "AMIC2Bias", NULL, "AMIC2"}, | ||
567 | { "MIC2 Enable", NULL, "AMIC2Bias"}, | ||
568 | { "Mic_InputR Capture Route", "AMIC", "MIC2 Enable"}, | ||
569 | |||
570 | |||
571 | /* Linein */ | ||
572 | { "LineIn Enable Left", NULL, "LINEINL"}, | ||
573 | { "LineIn Enable Right", NULL, "LINEINR"}, | ||
574 | { "Mic_InputL Capture Route", "LineIn", "LineIn Enable Left"}, | ||
575 | { "Mic_InputR Capture Route", "LineIn", "LineIn Enable Right"}, | ||
576 | |||
577 | /* ADC connection */ | ||
578 | { "ADC Left", NULL, "Mic_InputL Capture Route"}, | ||
579 | { "ADC Right", NULL, "Mic_InputR Capture Route"}, | ||
580 | |||
581 | /*DMIC connections */ | ||
582 | { "DMIC1", NULL, "DMIC12supply"}, | ||
583 | { "DMIC2", NULL, "DMIC12supply"}, | ||
584 | { "DMIC3", NULL, "DMIC34supply"}, | ||
585 | { "DMIC4", NULL, "DMIC34supply"}, | ||
586 | { "DMIC5", NULL, "DMIC56supply"}, | ||
587 | { "DMIC6", NULL, "DMIC56supply"}, | ||
588 | |||
589 | { "DMIC12Bias", NULL, "DMIC1"}, | ||
590 | { "DMIC12Bias", NULL, "DMIC2"}, | ||
591 | { "DMIC34Bias", NULL, "DMIC3"}, | ||
592 | { "DMIC34Bias", NULL, "DMIC4"}, | ||
593 | { "DMIC56Bias", NULL, "DMIC5"}, | ||
594 | { "DMIC56Bias", NULL, "DMIC6"}, | ||
595 | |||
596 | /*TX path inputs*/ | ||
597 | { "Txpath1 Capture Route", "ADC Left", "ADC Left"}, | ||
598 | { "Txpath2 Capture Route", "ADC Left", "ADC Left"}, | ||
599 | { "Txpath3 Capture Route", "ADC Left", "ADC Left"}, | ||
600 | { "Txpath4 Capture Route", "ADC Left", "ADC Left"}, | ||
601 | { "Txpath1 Capture Route", "ADC Right", "ADC Right"}, | ||
602 | { "Txpath2 Capture Route", "ADC Right", "ADC Right"}, | ||
603 | { "Txpath3 Capture Route", "ADC Right", "ADC Right"}, | ||
604 | { "Txpath4 Capture Route", "ADC Right", "ADC Right"}, | ||
605 | { "Txpath1 Capture Route", "DMIC1", "DMIC1"}, | ||
606 | { "Txpath2 Capture Route", "DMIC1", "DMIC1"}, | ||
607 | { "Txpath3 Capture Route", "DMIC1", "DMIC1"}, | ||
608 | { "Txpath4 Capture Route", "DMIC1", "DMIC1"}, | ||
609 | { "Txpath1 Capture Route", "DMIC2", "DMIC2"}, | ||
610 | { "Txpath2 Capture Route", "DMIC2", "DMIC2"}, | ||
611 | { "Txpath3 Capture Route", "DMIC2", "DMIC2"}, | ||
612 | { "Txpath4 Capture Route", "DMIC2", "DMIC2"}, | ||
613 | { "Txpath1 Capture Route", "DMIC3", "DMIC3"}, | ||
614 | { "Txpath2 Capture Route", "DMIC3", "DMIC3"}, | ||
615 | { "Txpath3 Capture Route", "DMIC3", "DMIC3"}, | ||
616 | { "Txpath4 Capture Route", "DMIC3", "DMIC3"}, | ||
617 | { "Txpath1 Capture Route", "DMIC4", "DMIC4"}, | ||
618 | { "Txpath2 Capture Route", "DMIC4", "DMIC4"}, | ||
619 | { "Txpath3 Capture Route", "DMIC4", "DMIC4"}, | ||
620 | { "Txpath4 Capture Route", "DMIC4", "DMIC4"}, | ||
621 | { "Txpath1 Capture Route", "DMIC5", "DMIC5"}, | ||
622 | { "Txpath2 Capture Route", "DMIC5", "DMIC5"}, | ||
623 | { "Txpath3 Capture Route", "DMIC5", "DMIC5"}, | ||
624 | { "Txpath4 Capture Route", "DMIC5", "DMIC5"}, | ||
625 | { "Txpath1 Capture Route", "DMIC6", "DMIC6"}, | ||
626 | { "Txpath2 Capture Route", "DMIC6", "DMIC6"}, | ||
627 | { "Txpath3 Capture Route", "DMIC6", "DMIC6"}, | ||
628 | { "Txpath4 Capture Route", "DMIC6", "DMIC6"}, | ||
629 | |||
630 | /* tx path */ | ||
631 | { "TX1 Enable", NULL, "Txpath1 Capture Route"}, | ||
632 | { "TX2 Enable", NULL, "Txpath2 Capture Route"}, | ||
633 | { "TX3 Enable", NULL, "Txpath3 Capture Route"}, | ||
634 | { "TX4 Enable", NULL, "Txpath4 Capture Route"}, | ||
635 | { "PCM_Out", NULL, "TX1 Enable"}, | ||
636 | { "PCM_Out", NULL, "TX2 Enable"}, | ||
637 | { "PCM_Out", NULL, "TX3 Enable"}, | ||
638 | { "PCM_Out", NULL, "TX4 Enable"}, | ||
639 | |||
640 | }; | ||
641 | |||
642 | /* speaker and headset mutes, for audio pops and clicks */ | ||
643 | static int sn95031_pcm_hs_mute(struct snd_soc_dai *dai, int mute) | ||
644 | { | ||
645 | snd_soc_update_bits(dai->codec, | ||
646 | SN95031_HSLVOLCTRL, BIT(7), (!mute << 7)); | ||
647 | snd_soc_update_bits(dai->codec, | ||
648 | SN95031_HSRVOLCTRL, BIT(7), (!mute << 7)); | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute) | ||
653 | { | ||
654 | snd_soc_update_bits(dai->codec, | ||
655 | SN95031_IHFLVOLCTRL, BIT(7), (!mute << 7)); | ||
656 | snd_soc_update_bits(dai->codec, | ||
657 | SN95031_IHFRVOLCTRL, BIT(7), (!mute << 7)); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | int sn95031_pcm_hw_params(struct snd_pcm_substream *substream, | ||
662 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
663 | { | ||
664 | unsigned int format, rate; | ||
665 | |||
666 | switch (params_format(params)) { | ||
667 | case SNDRV_PCM_FORMAT_S16_LE: | ||
668 | format = BIT(4)|BIT(5); | ||
669 | break; | ||
670 | |||
671 | case SNDRV_PCM_FORMAT_S24_LE: | ||
672 | format = 0; | ||
673 | break; | ||
674 | default: | ||
675 | return -EINVAL; | ||
676 | } | ||
677 | snd_soc_update_bits(dai->codec, SN95031_PCM2C2, | ||
678 | BIT(4)|BIT(5), format); | ||
679 | |||
680 | switch (params_rate(params)) { | ||
681 | case 48000: | ||
682 | pr_debug("RATE_48000\n"); | ||
683 | rate = 0; | ||
684 | break; | ||
685 | |||
686 | case 44100: | ||
687 | pr_debug("RATE_44100\n"); | ||
688 | rate = BIT(7); | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | pr_err("ERR rate %d\n", params_rate(params)); | ||
693 | return -EINVAL; | ||
694 | } | ||
695 | snd_soc_update_bits(dai->codec, SN95031_PCM1C1, BIT(7), rate); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | /* Codec DAI section */ | ||
701 | static struct snd_soc_dai_ops sn95031_headset_dai_ops = { | ||
702 | .digital_mute = sn95031_pcm_hs_mute, | ||
703 | .hw_params = sn95031_pcm_hw_params, | ||
704 | }; | ||
705 | |||
706 | static struct snd_soc_dai_ops sn95031_speaker_dai_ops = { | ||
707 | .digital_mute = sn95031_pcm_spkr_mute, | ||
708 | .hw_params = sn95031_pcm_hw_params, | ||
709 | }; | ||
710 | |||
711 | static struct snd_soc_dai_ops sn95031_vib1_dai_ops = { | ||
712 | .hw_params = sn95031_pcm_hw_params, | ||
713 | }; | ||
714 | |||
715 | static struct snd_soc_dai_ops sn95031_vib2_dai_ops = { | ||
716 | .hw_params = sn95031_pcm_hw_params, | ||
717 | }; | ||
718 | |||
719 | struct snd_soc_dai_driver sn95031_dais[] = { | ||
720 | { | ||
721 | .name = "SN95031 Headset", | ||
722 | .playback = { | ||
723 | .stream_name = "Headset", | ||
724 | .channels_min = 2, | ||
725 | .channels_max = 2, | ||
726 | .rates = SN95031_RATES, | ||
727 | .formats = SN95031_FORMATS, | ||
728 | }, | ||
729 | .capture = { | ||
730 | .stream_name = "Capture", | ||
731 | .channels_min = 1, | ||
732 | .channels_max = 5, | ||
733 | .rates = SN95031_RATES, | ||
734 | .formats = SN95031_FORMATS, | ||
735 | }, | ||
736 | .ops = &sn95031_headset_dai_ops, | ||
737 | }, | ||
738 | { .name = "SN95031 Speaker", | ||
739 | .playback = { | ||
740 | .stream_name = "Speaker", | ||
741 | .channels_min = 2, | ||
742 | .channels_max = 2, | ||
743 | .rates = SN95031_RATES, | ||
744 | .formats = SN95031_FORMATS, | ||
745 | }, | ||
746 | .ops = &sn95031_speaker_dai_ops, | ||
747 | }, | ||
748 | { .name = "SN95031 Vibra1", | ||
749 | .playback = { | ||
750 | .stream_name = "Vibra1", | ||
751 | .channels_min = 1, | ||
752 | .channels_max = 1, | ||
753 | .rates = SN95031_RATES, | ||
754 | .formats = SN95031_FORMATS, | ||
755 | }, | ||
756 | .ops = &sn95031_vib1_dai_ops, | ||
757 | }, | ||
758 | { .name = "SN95031 Vibra2", | ||
759 | .playback = { | ||
760 | .stream_name = "Vibra2", | ||
761 | .channels_min = 1, | ||
762 | .channels_max = 1, | ||
763 | .rates = SN95031_RATES, | ||
764 | .formats = SN95031_FORMATS, | ||
765 | }, | ||
766 | .ops = &sn95031_vib2_dai_ops, | ||
767 | }, | ||
768 | }; | ||
769 | |||
770 | static inline void sn95031_disable_jack_btn(struct snd_soc_codec *codec) | ||
771 | { | ||
772 | snd_soc_write(codec, SN95031_BTNCTRL2, 0x00); | ||
773 | } | ||
774 | |||
775 | static inline void sn95031_enable_jack_btn(struct snd_soc_codec *codec) | ||
776 | { | ||
777 | snd_soc_write(codec, SN95031_BTNCTRL1, 0x77); | ||
778 | snd_soc_write(codec, SN95031_BTNCTRL2, 0x01); | ||
779 | } | ||
780 | |||
781 | static int sn95031_get_headset_state(struct snd_soc_jack *mfld_jack) | ||
782 | { | ||
783 | int micbias = sn95031_get_mic_bias(mfld_jack->codec); | ||
784 | |||
785 | int jack_type = snd_soc_jack_get_type(mfld_jack, micbias); | ||
786 | |||
787 | pr_debug("jack type detected = %d\n", jack_type); | ||
788 | if (jack_type == SND_JACK_HEADSET) | ||
789 | sn95031_enable_jack_btn(mfld_jack->codec); | ||
790 | return jack_type; | ||
791 | } | ||
792 | |||
793 | void sn95031_jack_detection(struct mfld_jack_data *jack_data) | ||
794 | { | ||
795 | unsigned int status; | ||
796 | unsigned int mask = SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_HEADSET; | ||
797 | |||
798 | pr_debug("interrupt id read in sram = 0x%x\n", jack_data->intr_id); | ||
799 | if (jack_data->intr_id & 0x1) { | ||
800 | pr_debug("short_push detected\n"); | ||
801 | status = SND_JACK_HEADSET | SND_JACK_BTN_0; | ||
802 | } else if (jack_data->intr_id & 0x2) { | ||
803 | pr_debug("long_push detected\n"); | ||
804 | status = SND_JACK_HEADSET | SND_JACK_BTN_1; | ||
805 | } else if (jack_data->intr_id & 0x4) { | ||
806 | pr_debug("headset or headphones inserted\n"); | ||
807 | status = sn95031_get_headset_state(jack_data->mfld_jack); | ||
808 | } else if (jack_data->intr_id & 0x8) { | ||
809 | pr_debug("headset or headphones removed\n"); | ||
810 | status = 0; | ||
811 | sn95031_disable_jack_btn(jack_data->mfld_jack->codec); | ||
812 | } else { | ||
813 | pr_err("unidentified interrupt\n"); | ||
814 | return; | ||
815 | } | ||
816 | |||
817 | snd_soc_jack_report(jack_data->mfld_jack, status, mask); | ||
818 | /*button pressed and released so we send explicit button release */ | ||
819 | if ((status & SND_JACK_BTN_0) | (status & SND_JACK_BTN_1)) | ||
820 | snd_soc_jack_report(jack_data->mfld_jack, | ||
821 | SND_JACK_HEADSET, mask); | ||
822 | } | ||
823 | EXPORT_SYMBOL_GPL(sn95031_jack_detection); | ||
824 | |||
825 | /* codec registration */ | ||
826 | static int sn95031_codec_probe(struct snd_soc_codec *codec) | ||
827 | { | ||
828 | int ret; | ||
829 | |||
830 | pr_debug("codec_probe called\n"); | ||
831 | |||
832 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | ||
833 | codec->dapm.idle_bias_off = 1; | ||
834 | |||
835 | /* PCM interface config | ||
836 | * This sets the pcm rx slot conguration to max 6 slots | ||
837 | * for max 4 dais (2 stereo and 2 mono) | ||
838 | */ | ||
839 | snd_soc_write(codec, SN95031_PCM2RXSLOT01, 0x10); | ||
840 | snd_soc_write(codec, SN95031_PCM2RXSLOT23, 0x32); | ||
841 | snd_soc_write(codec, SN95031_PCM2RXSLOT45, 0x54); | ||
842 | snd_soc_write(codec, SN95031_PCM2TXSLOT01, 0x10); | ||
843 | snd_soc_write(codec, SN95031_PCM2TXSLOT23, 0x32); | ||
844 | /* pcm port setting | ||
845 | * This sets the pcm port to slave and clock at 19.2Mhz which | ||
846 | * can support 6slots, sampling rate set per stream in hw-params | ||
847 | */ | ||
848 | snd_soc_write(codec, SN95031_PCM1C1, 0x00); | ||
849 | snd_soc_write(codec, SN95031_PCM2C1, 0x01); | ||
850 | snd_soc_write(codec, SN95031_PCM2C2, 0x0A); | ||
851 | snd_soc_write(codec, SN95031_HSMIXER, BIT(0)|BIT(4)); | ||
852 | /* vendor vibra workround, the vibras are muted by | ||
853 | * custom register so unmute them | ||
854 | */ | ||
855 | snd_soc_write(codec, SN95031_SSR5, 0x80); | ||
856 | snd_soc_write(codec, SN95031_SSR6, 0x80); | ||
857 | snd_soc_write(codec, SN95031_VIB1C5, 0x00); | ||
858 | snd_soc_write(codec, SN95031_VIB2C5, 0x00); | ||
859 | /* configure vibras for pcm port */ | ||
860 | snd_soc_write(codec, SN95031_VIB1C3, 0x00); | ||
861 | snd_soc_write(codec, SN95031_VIB2C3, 0x00); | ||
862 | |||
863 | /* soft mute ramp time */ | ||
864 | snd_soc_write(codec, SN95031_SOFTMUTE, 0x3); | ||
865 | /* fix the initial volume at 1dB, | ||
866 | * default in +9dB, | ||
867 | * 1dB give optimal swing on DAC, amps | ||
868 | */ | ||
869 | snd_soc_write(codec, SN95031_HSLVOLCTRL, 0x08); | ||
870 | snd_soc_write(codec, SN95031_HSRVOLCTRL, 0x08); | ||
871 | snd_soc_write(codec, SN95031_IHFLVOLCTRL, 0x08); | ||
872 | snd_soc_write(codec, SN95031_IHFRVOLCTRL, 0x08); | ||
873 | /* dac mode and lineout workaround */ | ||
874 | snd_soc_write(codec, SN95031_SSR2, 0x10); | ||
875 | snd_soc_write(codec, SN95031_SSR3, 0x40); | ||
876 | |||
877 | snd_soc_add_controls(codec, sn95031_snd_controls, | ||
878 | ARRAY_SIZE(sn95031_snd_controls)); | ||
879 | |||
880 | ret = snd_soc_dapm_new_controls(&codec->dapm, sn95031_dapm_widgets, | ||
881 | ARRAY_SIZE(sn95031_dapm_widgets)); | ||
882 | if (ret) | ||
883 | pr_err("soc_dapm_new_control failed %d", ret); | ||
884 | ret = snd_soc_dapm_add_routes(&codec->dapm, sn95031_audio_map, | ||
885 | ARRAY_SIZE(sn95031_audio_map)); | ||
886 | if (ret) | ||
887 | pr_err("soc_dapm_add_routes failed %d", ret); | ||
888 | |||
889 | return ret; | ||
890 | } | ||
891 | |||
892 | static int sn95031_codec_remove(struct snd_soc_codec *codec) | ||
893 | { | ||
894 | pr_debug("codec_remove called\n"); | ||
895 | sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | struct snd_soc_codec_driver sn95031_codec = { | ||
901 | .probe = sn95031_codec_probe, | ||
902 | .remove = sn95031_codec_remove, | ||
903 | .read = sn95031_read, | ||
904 | .write = sn95031_write, | ||
905 | .set_bias_level = sn95031_set_vaud_bias, | ||
906 | }; | ||
907 | |||
908 | static int __devinit sn95031_device_probe(struct platform_device *pdev) | ||
909 | { | ||
910 | pr_debug("codec device probe called for %s\n", dev_name(&pdev->dev)); | ||
911 | return snd_soc_register_codec(&pdev->dev, &sn95031_codec, | ||
912 | sn95031_dais, ARRAY_SIZE(sn95031_dais)); | ||
913 | } | ||
914 | |||
915 | static int __devexit sn95031_device_remove(struct platform_device *pdev) | ||
916 | { | ||
917 | pr_debug("codec device remove called\n"); | ||
918 | snd_soc_unregister_codec(&pdev->dev); | ||
919 | return 0; | ||
920 | } | ||
921 | |||
922 | static struct platform_driver sn95031_codec_driver = { | ||
923 | .driver = { | ||
924 | .name = "sn95031", | ||
925 | .owner = THIS_MODULE, | ||
926 | }, | ||
927 | .probe = sn95031_device_probe, | ||
928 | .remove = sn95031_device_remove, | ||
929 | }; | ||
930 | |||
931 | static int __init sn95031_init(void) | ||
932 | { | ||
933 | pr_debug("driver init called\n"); | ||
934 | return platform_driver_register(&sn95031_codec_driver); | ||
935 | } | ||
936 | module_init(sn95031_init); | ||
937 | |||
938 | static void __exit sn95031_exit(void) | ||
939 | { | ||
940 | pr_debug("driver exit called\n"); | ||
941 | platform_driver_unregister(&sn95031_codec_driver); | ||
942 | } | ||
943 | module_exit(sn95031_exit); | ||
944 | |||
945 | MODULE_DESCRIPTION("ASoC TI SN95031 codec driver"); | ||
946 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
947 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
948 | MODULE_LICENSE("GPL v2"); | ||
949 | MODULE_ALIAS("platform:sn95031"); | ||
diff --git a/sound/soc/codecs/sn95031.h b/sound/soc/codecs/sn95031.h new file mode 100644 index 000000000000..20376d234fb8 --- /dev/null +++ b/sound/soc/codecs/sn95031.h | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * sn95031.h - TI sn95031 Codec driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #ifndef _SN95031_H | ||
27 | #define _SN95031_H | ||
28 | |||
29 | /*register map*/ | ||
30 | #define SN95031_VAUD 0xDB | ||
31 | #define SN95031_VHSP 0xDC | ||
32 | #define SN95031_VHSN 0xDD | ||
33 | #define SN95031_VIHF 0xC9 | ||
34 | |||
35 | #define SN95031_AUDPLLCTRL 0x240 | ||
36 | #define SN95031_DMICBUF0123 0x241 | ||
37 | #define SN95031_DMICBUF45 0x242 | ||
38 | #define SN95031_DMICGPO 0x244 | ||
39 | #define SN95031_DMICMUX 0x245 | ||
40 | #define SN95031_DMICLK 0x246 | ||
41 | #define SN95031_MICBIAS 0x247 | ||
42 | #define SN95031_ADCCONFIG 0x248 | ||
43 | #define SN95031_MICAMP1 0x249 | ||
44 | #define SN95031_MICAMP2 0x24A | ||
45 | #define SN95031_NOISEMUX 0x24B | ||
46 | #define SN95031_AUDIOMUX12 0x24C | ||
47 | #define SN95031_AUDIOMUX34 0x24D | ||
48 | #define SN95031_AUDIOSINC 0x24E | ||
49 | #define SN95031_AUDIOTXEN 0x24F | ||
50 | #define SN95031_HSEPRXCTRL 0x250 | ||
51 | #define SN95031_IHFRXCTRL 0x251 | ||
52 | #define SN95031_HSMIXER 0x256 | ||
53 | #define SN95031_DACCONFIG 0x257 | ||
54 | #define SN95031_SOFTMUTE 0x258 | ||
55 | #define SN95031_HSLVOLCTRL 0x259 | ||
56 | #define SN95031_HSRVOLCTRL 0x25A | ||
57 | #define SN95031_IHFLVOLCTRL 0x25B | ||
58 | #define SN95031_IHFRVOLCTRL 0x25C | ||
59 | #define SN95031_DRIVEREN 0x25D | ||
60 | #define SN95031_LOCTL 0x25E | ||
61 | #define SN95031_VIB1C1 0x25F | ||
62 | #define SN95031_VIB1C2 0x260 | ||
63 | #define SN95031_VIB1C3 0x261 | ||
64 | #define SN95031_VIB1SPIPCM1 0x262 | ||
65 | #define SN95031_VIB1SPIPCM2 0x263 | ||
66 | #define SN95031_VIB1C5 0x264 | ||
67 | #define SN95031_VIB2C1 0x265 | ||
68 | #define SN95031_VIB2C2 0x266 | ||
69 | #define SN95031_VIB2C3 0x267 | ||
70 | #define SN95031_VIB2SPIPCM1 0x268 | ||
71 | #define SN95031_VIB2SPIPCM2 0x269 | ||
72 | #define SN95031_VIB2C5 0x26A | ||
73 | #define SN95031_BTNCTRL1 0x26B | ||
74 | #define SN95031_BTNCTRL2 0x26C | ||
75 | #define SN95031_PCM1TXSLOT01 0x26D | ||
76 | #define SN95031_PCM1TXSLOT23 0x26E | ||
77 | #define SN95031_PCM1TXSLOT45 0x26F | ||
78 | #define SN95031_PCM1RXSLOT0_3 0x270 | ||
79 | #define SN95031_PCM1RXSLOT45 0x271 | ||
80 | #define SN95031_PCM2TXSLOT01 0x272 | ||
81 | #define SN95031_PCM2TXSLOT23 0x273 | ||
82 | #define SN95031_PCM2TXSLOT45 0x274 | ||
83 | #define SN95031_PCM2RXSLOT01 0x275 | ||
84 | #define SN95031_PCM2RXSLOT23 0x276 | ||
85 | #define SN95031_PCM2RXSLOT45 0x277 | ||
86 | #define SN95031_PCM1C1 0x278 | ||
87 | #define SN95031_PCM1C2 0x279 | ||
88 | #define SN95031_PCM1C3 0x27A | ||
89 | #define SN95031_PCM2C1 0x27B | ||
90 | #define SN95031_PCM2C2 0x27C | ||
91 | /*end codec register defn*/ | ||
92 | |||
93 | /*vendor defn these are not part of avp*/ | ||
94 | #define SN95031_SSR2 0x381 | ||
95 | #define SN95031_SSR3 0x382 | ||
96 | #define SN95031_SSR5 0x384 | ||
97 | #define SN95031_SSR6 0x385 | ||
98 | |||
99 | /* ADC registers */ | ||
100 | |||
101 | #define SN95031_ADC1CNTL1 0x1C0 | ||
102 | #define SN95031_ADC_ENBL 0x10 | ||
103 | #define SN95031_ADC_START 0x08 | ||
104 | #define SN95031_ADC1CNTL3 0x1C2 | ||
105 | #define SN95031_ADCTHERM_ENBL 0x04 | ||
106 | #define SN95031_ADCRRDATA_ENBL 0x05 | ||
107 | #define SN95031_STOPBIT_MASK 16 | ||
108 | #define SN95031_ADCTHERM_MASK 4 | ||
109 | #define SN95031_ADC_CHANLS_MAX 15 /* Number of ADC channels */ | ||
110 | #define SN95031_ADC_LOOP_MAX (SN95031_ADC_CHANLS_MAX - 1) | ||
111 | #define SN95031_ADC_NO_LOOP 0x07 | ||
112 | #define SN95031_AUDIO_GPIO_CTRL 0x070 | ||
113 | |||
114 | /* ADC channel code values */ | ||
115 | #define SN95031_AUDIO_DETECT_CODE 0x06 | ||
116 | |||
117 | /* ADC base addresses */ | ||
118 | #define SN95031_ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ | ||
119 | #define SN95031_ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ | ||
120 | /* multipier to convert to mV */ | ||
121 | #define SN95031_ADC_ONE_LSB_MULTIPLIER 2346 | ||
122 | |||
123 | |||
124 | struct mfld_jack_data { | ||
125 | int intr_id; | ||
126 | int micbias_vol; | ||
127 | struct snd_soc_jack *mfld_jack; | ||
128 | }; | ||
129 | |||
130 | extern void sn95031_jack_detection(struct mfld_jack_data *jack_data); | ||
131 | |||
132 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c new file mode 100644 index 000000000000..e93b9d1ae1dd --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4.c | |||
@@ -0,0 +1,794 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/codecs/tlv320aic32x4.c | ||
3 | * | ||
4 | * Copyright 2011 Vista Silicon S.L. | ||
5 | * | ||
6 | * Author: Javier Martin <javier.martin@vista-silicon.com> | ||
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 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
23 | * MA 02110-1301, USA. | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/pm.h> | ||
31 | #include <linux/i2c.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/cdev.h> | ||
34 | #include <linux/slab.h> | ||
35 | |||
36 | #include <sound/tlv320aic32x4.h> | ||
37 | #include <sound/core.h> | ||
38 | #include <sound/pcm.h> | ||
39 | #include <sound/pcm_params.h> | ||
40 | #include <sound/soc.h> | ||
41 | #include <sound/soc-dapm.h> | ||
42 | #include <sound/initval.h> | ||
43 | #include <sound/tlv.h> | ||
44 | |||
45 | #include "tlv320aic32x4.h" | ||
46 | |||
47 | struct aic32x4_rate_divs { | ||
48 | u32 mclk; | ||
49 | u32 rate; | ||
50 | u8 p_val; | ||
51 | u8 pll_j; | ||
52 | u16 pll_d; | ||
53 | u16 dosr; | ||
54 | u8 ndac; | ||
55 | u8 mdac; | ||
56 | u8 aosr; | ||
57 | u8 nadc; | ||
58 | u8 madc; | ||
59 | u8 blck_N; | ||
60 | }; | ||
61 | |||
62 | struct aic32x4_priv { | ||
63 | u32 sysclk; | ||
64 | s32 master; | ||
65 | u8 page_no; | ||
66 | void *control_data; | ||
67 | u32 power_cfg; | ||
68 | u32 micpga_routing; | ||
69 | bool swapdacs; | ||
70 | }; | ||
71 | |||
72 | /* 0dB min, 1dB steps */ | ||
73 | static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0); | ||
74 | /* 0dB min, 0.5dB steps */ | ||
75 | static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0); | ||
76 | |||
77 | static const struct snd_kcontrol_new aic32x4_snd_controls[] = { | ||
78 | SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL, | ||
79 | AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5), | ||
80 | SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, | ||
81 | AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1), | ||
82 | SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, | ||
83 | AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1), | ||
84 | SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, | ||
85 | AIC32X4_HPRGAIN, 6, 0x01, 1), | ||
86 | SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, | ||
87 | AIC32X4_LORGAIN, 6, 0x01, 1), | ||
88 | SOC_DOUBLE_R("Mic PGA Switch", AIC32X4_LMICPGAVOL, | ||
89 | AIC32X4_RMICPGAVOL, 7, 0x01, 1), | ||
90 | |||
91 | SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), | ||
92 | SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0), | ||
93 | |||
94 | SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL, | ||
95 | AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5), | ||
96 | SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, | ||
97 | AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5), | ||
98 | |||
99 | SOC_SINGLE("Auto-mute Switch", AIC32X4_DACMUTE, 4, 7, 0), | ||
100 | |||
101 | SOC_SINGLE("AGC Left Switch", AIC32X4_LAGC1, 7, 1, 0), | ||
102 | SOC_SINGLE("AGC Right Switch", AIC32X4_RAGC1, 7, 1, 0), | ||
103 | SOC_DOUBLE_R("AGC Target Level", AIC32X4_LAGC1, AIC32X4_RAGC1, | ||
104 | 4, 0x07, 0), | ||
105 | SOC_DOUBLE_R("AGC Gain Hysteresis", AIC32X4_LAGC1, AIC32X4_RAGC1, | ||
106 | 0, 0x03, 0), | ||
107 | SOC_DOUBLE_R("AGC Hysteresis", AIC32X4_LAGC2, AIC32X4_RAGC2, | ||
108 | 6, 0x03, 0), | ||
109 | SOC_DOUBLE_R("AGC Noise Threshold", AIC32X4_LAGC2, AIC32X4_RAGC2, | ||
110 | 1, 0x1F, 0), | ||
111 | SOC_DOUBLE_R("AGC Max PGA", AIC32X4_LAGC3, AIC32X4_RAGC3, | ||
112 | 0, 0x7F, 0), | ||
113 | SOC_DOUBLE_R("AGC Attack Time", AIC32X4_LAGC4, AIC32X4_RAGC4, | ||
114 | 3, 0x1F, 0), | ||
115 | SOC_DOUBLE_R("AGC Decay Time", AIC32X4_LAGC5, AIC32X4_RAGC5, | ||
116 | 3, 0x1F, 0), | ||
117 | SOC_DOUBLE_R("AGC Noise Debounce", AIC32X4_LAGC6, AIC32X4_RAGC6, | ||
118 | 0, 0x1F, 0), | ||
119 | SOC_DOUBLE_R("AGC Signal Debounce", AIC32X4_LAGC7, AIC32X4_RAGC7, | ||
120 | 0, 0x0F, 0), | ||
121 | }; | ||
122 | |||
123 | static const struct aic32x4_rate_divs aic32x4_divs[] = { | ||
124 | /* 8k rate */ | ||
125 | {AIC32X4_FREQ_12000000, 8000, 1, 7, 6800, 768, 5, 3, 128, 5, 18, 24}, | ||
126 | {AIC32X4_FREQ_24000000, 8000, 2, 7, 6800, 768, 15, 1, 64, 45, 4, 24}, | ||
127 | {AIC32X4_FREQ_25000000, 8000, 2, 7, 3728, 768, 15, 1, 64, 45, 4, 24}, | ||
128 | /* 11.025k rate */ | ||
129 | {AIC32X4_FREQ_12000000, 11025, 1, 7, 5264, 512, 8, 2, 128, 8, 8, 16}, | ||
130 | {AIC32X4_FREQ_24000000, 11025, 2, 7, 5264, 512, 16, 1, 64, 32, 4, 16}, | ||
131 | /* 16k rate */ | ||
132 | {AIC32X4_FREQ_12000000, 16000, 1, 7, 6800, 384, 5, 3, 128, 5, 9, 12}, | ||
133 | {AIC32X4_FREQ_24000000, 16000, 2, 7, 6800, 384, 15, 1, 64, 18, 5, 12}, | ||
134 | {AIC32X4_FREQ_25000000, 16000, 2, 7, 3728, 384, 15, 1, 64, 18, 5, 12}, | ||
135 | /* 22.05k rate */ | ||
136 | {AIC32X4_FREQ_12000000, 22050, 1, 7, 5264, 256, 4, 4, 128, 4, 8, 8}, | ||
137 | {AIC32X4_FREQ_24000000, 22050, 2, 7, 5264, 256, 16, 1, 64, 16, 4, 8}, | ||
138 | {AIC32X4_FREQ_25000000, 22050, 2, 7, 2253, 256, 16, 1, 64, 16, 4, 8}, | ||
139 | /* 32k rate */ | ||
140 | {AIC32X4_FREQ_12000000, 32000, 1, 7, 1680, 192, 2, 7, 64, 2, 21, 6}, | ||
141 | {AIC32X4_FREQ_24000000, 32000, 2, 7, 1680, 192, 7, 2, 64, 7, 6, 6}, | ||
142 | /* 44.1k rate */ | ||
143 | {AIC32X4_FREQ_12000000, 44100, 1, 7, 5264, 128, 2, 8, 128, 2, 8, 4}, | ||
144 | {AIC32X4_FREQ_24000000, 44100, 2, 7, 5264, 128, 8, 2, 64, 8, 4, 4}, | ||
145 | {AIC32X4_FREQ_25000000, 44100, 2, 7, 2253, 128, 8, 2, 64, 8, 4, 4}, | ||
146 | /* 48k rate */ | ||
147 | {AIC32X4_FREQ_12000000, 48000, 1, 8, 1920, 128, 2, 8, 128, 2, 8, 4}, | ||
148 | {AIC32X4_FREQ_24000000, 48000, 2, 8, 1920, 128, 8, 2, 64, 8, 4, 4}, | ||
149 | {AIC32X4_FREQ_25000000, 48000, 2, 7, 8643, 128, 8, 2, 64, 8, 4, 4} | ||
150 | }; | ||
151 | |||
152 | static const struct snd_kcontrol_new hpl_output_mixer_controls[] = { | ||
153 | SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_HPLROUTE, 3, 1, 0), | ||
154 | SOC_DAPM_SINGLE("IN1_L Switch", AIC32X4_HPLROUTE, 2, 1, 0), | ||
155 | }; | ||
156 | |||
157 | static const struct snd_kcontrol_new hpr_output_mixer_controls[] = { | ||
158 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_HPRROUTE, 3, 1, 0), | ||
159 | SOC_DAPM_SINGLE("IN1_R Switch", AIC32X4_HPRROUTE, 2, 1, 0), | ||
160 | }; | ||
161 | |||
162 | static const struct snd_kcontrol_new lol_output_mixer_controls[] = { | ||
163 | SOC_DAPM_SINGLE("L_DAC Switch", AIC32X4_LOLROUTE, 3, 1, 0), | ||
164 | }; | ||
165 | |||
166 | static const struct snd_kcontrol_new lor_output_mixer_controls[] = { | ||
167 | SOC_DAPM_SINGLE("R_DAC Switch", AIC32X4_LORROUTE, 3, 1, 0), | ||
168 | }; | ||
169 | |||
170 | static const struct snd_kcontrol_new left_input_mixer_controls[] = { | ||
171 | SOC_DAPM_SINGLE("IN1_L P Switch", AIC32X4_LMICPGAPIN, 6, 1, 0), | ||
172 | SOC_DAPM_SINGLE("IN2_L P Switch", AIC32X4_LMICPGAPIN, 4, 1, 0), | ||
173 | SOC_DAPM_SINGLE("IN3_L P Switch", AIC32X4_LMICPGAPIN, 2, 1, 0), | ||
174 | }; | ||
175 | |||
176 | static const struct snd_kcontrol_new right_input_mixer_controls[] = { | ||
177 | SOC_DAPM_SINGLE("IN1_R P Switch", AIC32X4_RMICPGAPIN, 6, 1, 0), | ||
178 | SOC_DAPM_SINGLE("IN2_R P Switch", AIC32X4_RMICPGAPIN, 4, 1, 0), | ||
179 | SOC_DAPM_SINGLE("IN3_R P Switch", AIC32X4_RMICPGAPIN, 2, 1, 0), | ||
180 | }; | ||
181 | |||
182 | static const struct snd_soc_dapm_widget aic32x4_dapm_widgets[] = { | ||
183 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", AIC32X4_DACSETUP, 7, 0), | ||
184 | SND_SOC_DAPM_MIXER("HPL Output Mixer", SND_SOC_NOPM, 0, 0, | ||
185 | &hpl_output_mixer_controls[0], | ||
186 | ARRAY_SIZE(hpl_output_mixer_controls)), | ||
187 | SND_SOC_DAPM_PGA("HPL Power", AIC32X4_OUTPWRCTL, 5, 0, NULL, 0), | ||
188 | |||
189 | SND_SOC_DAPM_MIXER("LOL Output Mixer", SND_SOC_NOPM, 0, 0, | ||
190 | &lol_output_mixer_controls[0], | ||
191 | ARRAY_SIZE(lol_output_mixer_controls)), | ||
192 | SND_SOC_DAPM_PGA("LOL Power", AIC32X4_OUTPWRCTL, 3, 0, NULL, 0), | ||
193 | |||
194 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", AIC32X4_DACSETUP, 6, 0), | ||
195 | SND_SOC_DAPM_MIXER("HPR Output Mixer", SND_SOC_NOPM, 0, 0, | ||
196 | &hpr_output_mixer_controls[0], | ||
197 | ARRAY_SIZE(hpr_output_mixer_controls)), | ||
198 | SND_SOC_DAPM_PGA("HPR Power", AIC32X4_OUTPWRCTL, 4, 0, NULL, 0), | ||
199 | SND_SOC_DAPM_MIXER("LOR Output Mixer", SND_SOC_NOPM, 0, 0, | ||
200 | &lor_output_mixer_controls[0], | ||
201 | ARRAY_SIZE(lor_output_mixer_controls)), | ||
202 | SND_SOC_DAPM_PGA("LOR Power", AIC32X4_OUTPWRCTL, 2, 0, NULL, 0), | ||
203 | SND_SOC_DAPM_MIXER("Left Input Mixer", SND_SOC_NOPM, 0, 0, | ||
204 | &left_input_mixer_controls[0], | ||
205 | ARRAY_SIZE(left_input_mixer_controls)), | ||
206 | SND_SOC_DAPM_MIXER("Right Input Mixer", SND_SOC_NOPM, 0, 0, | ||
207 | &right_input_mixer_controls[0], | ||
208 | ARRAY_SIZE(right_input_mixer_controls)), | ||
209 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", AIC32X4_ADCSETUP, 7, 0), | ||
210 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", AIC32X4_ADCSETUP, 6, 0), | ||
211 | SND_SOC_DAPM_MICBIAS("Mic Bias", AIC32X4_MICBIAS, 6, 0), | ||
212 | |||
213 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
214 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
215 | SND_SOC_DAPM_OUTPUT("LOL"), | ||
216 | SND_SOC_DAPM_OUTPUT("LOR"), | ||
217 | SND_SOC_DAPM_INPUT("IN1_L"), | ||
218 | SND_SOC_DAPM_INPUT("IN1_R"), | ||
219 | SND_SOC_DAPM_INPUT("IN2_L"), | ||
220 | SND_SOC_DAPM_INPUT("IN2_R"), | ||
221 | SND_SOC_DAPM_INPUT("IN3_L"), | ||
222 | SND_SOC_DAPM_INPUT("IN3_R"), | ||
223 | }; | ||
224 | |||
225 | static const struct snd_soc_dapm_route aic32x4_dapm_routes[] = { | ||
226 | /* Left Output */ | ||
227 | {"HPL Output Mixer", "L_DAC Switch", "Left DAC"}, | ||
228 | {"HPL Output Mixer", "IN1_L Switch", "IN1_L"}, | ||
229 | |||
230 | {"HPL Power", NULL, "HPL Output Mixer"}, | ||
231 | {"HPL", NULL, "HPL Power"}, | ||
232 | |||
233 | {"LOL Output Mixer", "L_DAC Switch", "Left DAC"}, | ||
234 | |||
235 | {"LOL Power", NULL, "LOL Output Mixer"}, | ||
236 | {"LOL", NULL, "LOL Power"}, | ||
237 | |||
238 | /* Right Output */ | ||
239 | {"HPR Output Mixer", "R_DAC Switch", "Right DAC"}, | ||
240 | {"HPR Output Mixer", "IN1_R Switch", "IN1_R"}, | ||
241 | |||
242 | {"HPR Power", NULL, "HPR Output Mixer"}, | ||
243 | {"HPR", NULL, "HPR Power"}, | ||
244 | |||
245 | {"LOR Output Mixer", "R_DAC Switch", "Right DAC"}, | ||
246 | |||
247 | {"LOR Power", NULL, "LOR Output Mixer"}, | ||
248 | {"LOR", NULL, "LOR Power"}, | ||
249 | |||
250 | /* Left input */ | ||
251 | {"Left Input Mixer", "IN1_L P Switch", "IN1_L"}, | ||
252 | {"Left Input Mixer", "IN2_L P Switch", "IN2_L"}, | ||
253 | {"Left Input Mixer", "IN3_L P Switch", "IN3_L"}, | ||
254 | |||
255 | {"Left ADC", NULL, "Left Input Mixer"}, | ||
256 | |||
257 | /* Right Input */ | ||
258 | {"Right Input Mixer", "IN1_R P Switch", "IN1_R"}, | ||
259 | {"Right Input Mixer", "IN2_R P Switch", "IN2_R"}, | ||
260 | {"Right Input Mixer", "IN3_R P Switch", "IN3_R"}, | ||
261 | |||
262 | {"Right ADC", NULL, "Right Input Mixer"}, | ||
263 | }; | ||
264 | |||
265 | static inline int aic32x4_change_page(struct snd_soc_codec *codec, | ||
266 | unsigned int new_page) | ||
267 | { | ||
268 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
269 | u8 data[2]; | ||
270 | int ret; | ||
271 | |||
272 | data[0] = 0x00; | ||
273 | data[1] = new_page & 0xff; | ||
274 | |||
275 | ret = codec->hw_write(codec->control_data, data, 2); | ||
276 | if (ret == 2) { | ||
277 | aic32x4->page_no = new_page; | ||
278 | return 0; | ||
279 | } else { | ||
280 | return ret; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static int aic32x4_write(struct snd_soc_codec *codec, unsigned int reg, | ||
285 | unsigned int val) | ||
286 | { | ||
287 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
288 | unsigned int page = reg / 128; | ||
289 | unsigned int fixed_reg = reg % 128; | ||
290 | u8 data[2]; | ||
291 | int ret; | ||
292 | |||
293 | /* A write to AIC32X4_PSEL is really a non-explicit page change */ | ||
294 | if (reg == AIC32X4_PSEL) | ||
295 | return aic32x4_change_page(codec, val); | ||
296 | |||
297 | if (aic32x4->page_no != page) { | ||
298 | ret = aic32x4_change_page(codec, page); | ||
299 | if (ret != 0) | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | data[0] = fixed_reg & 0xff; | ||
304 | data[1] = val & 0xff; | ||
305 | |||
306 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
307 | return 0; | ||
308 | else | ||
309 | return -EIO; | ||
310 | } | ||
311 | |||
312 | static unsigned int aic32x4_read(struct snd_soc_codec *codec, unsigned int reg) | ||
313 | { | ||
314 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
315 | unsigned int page = reg / 128; | ||
316 | unsigned int fixed_reg = reg % 128; | ||
317 | int ret; | ||
318 | |||
319 | if (aic32x4->page_no != page) { | ||
320 | ret = aic32x4_change_page(codec, page); | ||
321 | if (ret != 0) | ||
322 | return ret; | ||
323 | } | ||
324 | return i2c_smbus_read_byte_data(codec->control_data, fixed_reg & 0xff); | ||
325 | } | ||
326 | |||
327 | static inline int aic32x4_get_divs(int mclk, int rate) | ||
328 | { | ||
329 | int i; | ||
330 | |||
331 | for (i = 0; i < ARRAY_SIZE(aic32x4_divs); i++) { | ||
332 | if ((aic32x4_divs[i].rate == rate) | ||
333 | && (aic32x4_divs[i].mclk == mclk)) { | ||
334 | return i; | ||
335 | } | ||
336 | } | ||
337 | printk(KERN_ERR "aic32x4: master clock and sample rate is not supported\n"); | ||
338 | return -EINVAL; | ||
339 | } | ||
340 | |||
341 | static int aic32x4_add_widgets(struct snd_soc_codec *codec) | ||
342 | { | ||
343 | snd_soc_dapm_new_controls(&codec->dapm, aic32x4_dapm_widgets, | ||
344 | ARRAY_SIZE(aic32x4_dapm_widgets)); | ||
345 | |||
346 | snd_soc_dapm_add_routes(&codec->dapm, aic32x4_dapm_routes, | ||
347 | ARRAY_SIZE(aic32x4_dapm_routes)); | ||
348 | |||
349 | snd_soc_dapm_new_widgets(&codec->dapm); | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int aic32x4_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
354 | int clk_id, unsigned int freq, int dir) | ||
355 | { | ||
356 | struct snd_soc_codec *codec = codec_dai->codec; | ||
357 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
358 | |||
359 | switch (freq) { | ||
360 | case AIC32X4_FREQ_12000000: | ||
361 | case AIC32X4_FREQ_24000000: | ||
362 | case AIC32X4_FREQ_25000000: | ||
363 | aic32x4->sysclk = freq; | ||
364 | return 0; | ||
365 | } | ||
366 | printk(KERN_ERR "aic32x4: invalid frequency to set DAI system clock\n"); | ||
367 | return -EINVAL; | ||
368 | } | ||
369 | |||
370 | static int aic32x4_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
371 | { | ||
372 | struct snd_soc_codec *codec = codec_dai->codec; | ||
373 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
374 | u8 iface_reg_1; | ||
375 | u8 iface_reg_2; | ||
376 | u8 iface_reg_3; | ||
377 | |||
378 | iface_reg_1 = snd_soc_read(codec, AIC32X4_IFACE1); | ||
379 | iface_reg_1 = iface_reg_1 & ~(3 << 6 | 3 << 2); | ||
380 | iface_reg_2 = snd_soc_read(codec, AIC32X4_IFACE2); | ||
381 | iface_reg_2 = 0; | ||
382 | iface_reg_3 = snd_soc_read(codec, AIC32X4_IFACE3); | ||
383 | iface_reg_3 = iface_reg_3 & ~(1 << 3); | ||
384 | |||
385 | /* set master/slave audio interface */ | ||
386 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
387 | case SND_SOC_DAIFMT_CBM_CFM: | ||
388 | aic32x4->master = 1; | ||
389 | iface_reg_1 |= AIC32X4_BCLKMASTER | AIC32X4_WCLKMASTER; | ||
390 | break; | ||
391 | case SND_SOC_DAIFMT_CBS_CFS: | ||
392 | aic32x4->master = 0; | ||
393 | break; | ||
394 | default: | ||
395 | printk(KERN_ERR "aic32x4: invalid DAI master/slave interface\n"); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | |||
399 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
400 | case SND_SOC_DAIFMT_I2S: | ||
401 | break; | ||
402 | case SND_SOC_DAIFMT_DSP_A: | ||
403 | iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); | ||
404 | iface_reg_3 |= (1 << 3); /* invert bit clock */ | ||
405 | iface_reg_2 = 0x01; /* add offset 1 */ | ||
406 | break; | ||
407 | case SND_SOC_DAIFMT_DSP_B: | ||
408 | iface_reg_1 |= (AIC32X4_DSP_MODE << AIC32X4_PLLJ_SHIFT); | ||
409 | iface_reg_3 |= (1 << 3); /* invert bit clock */ | ||
410 | break; | ||
411 | case SND_SOC_DAIFMT_RIGHT_J: | ||
412 | iface_reg_1 |= | ||
413 | (AIC32X4_RIGHT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); | ||
414 | break; | ||
415 | case SND_SOC_DAIFMT_LEFT_J: | ||
416 | iface_reg_1 |= | ||
417 | (AIC32X4_LEFT_JUSTIFIED_MODE << AIC32X4_PLLJ_SHIFT); | ||
418 | break; | ||
419 | default: | ||
420 | printk(KERN_ERR "aic32x4: invalid DAI interface format\n"); | ||
421 | return -EINVAL; | ||
422 | } | ||
423 | |||
424 | snd_soc_write(codec, AIC32X4_IFACE1, iface_reg_1); | ||
425 | snd_soc_write(codec, AIC32X4_IFACE2, iface_reg_2); | ||
426 | snd_soc_write(codec, AIC32X4_IFACE3, iface_reg_3); | ||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int aic32x4_hw_params(struct snd_pcm_substream *substream, | ||
431 | struct snd_pcm_hw_params *params, | ||
432 | struct snd_soc_dai *dai) | ||
433 | { | ||
434 | struct snd_soc_codec *codec = dai->codec; | ||
435 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
436 | u8 data; | ||
437 | int i; | ||
438 | |||
439 | i = aic32x4_get_divs(aic32x4->sysclk, params_rate(params)); | ||
440 | if (i < 0) { | ||
441 | printk(KERN_ERR "aic32x4: sampling rate not supported\n"); | ||
442 | return i; | ||
443 | } | ||
444 | |||
445 | /* Use PLL as CODEC_CLKIN and DAC_MOD_CLK as BDIV_CLKIN */ | ||
446 | snd_soc_write(codec, AIC32X4_CLKMUX, AIC32X4_PLLCLKIN); | ||
447 | snd_soc_write(codec, AIC32X4_IFACE3, AIC32X4_DACMOD2BCLK); | ||
448 | |||
449 | /* We will fix R value to 1 and will make P & J=K.D as varialble */ | ||
450 | data = snd_soc_read(codec, AIC32X4_PLLPR); | ||
451 | data &= ~(7 << 4); | ||
452 | snd_soc_write(codec, AIC32X4_PLLPR, | ||
453 | (data | (aic32x4_divs[i].p_val << 4) | 0x01)); | ||
454 | |||
455 | snd_soc_write(codec, AIC32X4_PLLJ, aic32x4_divs[i].pll_j); | ||
456 | |||
457 | snd_soc_write(codec, AIC32X4_PLLDMSB, (aic32x4_divs[i].pll_d >> 8)); | ||
458 | snd_soc_write(codec, AIC32X4_PLLDLSB, | ||
459 | (aic32x4_divs[i].pll_d & 0xff)); | ||
460 | |||
461 | /* NDAC divider value */ | ||
462 | data = snd_soc_read(codec, AIC32X4_NDAC); | ||
463 | data &= ~(0x7f); | ||
464 | snd_soc_write(codec, AIC32X4_NDAC, data | aic32x4_divs[i].ndac); | ||
465 | |||
466 | /* MDAC divider value */ | ||
467 | data = snd_soc_read(codec, AIC32X4_MDAC); | ||
468 | data &= ~(0x7f); | ||
469 | snd_soc_write(codec, AIC32X4_MDAC, data | aic32x4_divs[i].mdac); | ||
470 | |||
471 | /* DOSR MSB & LSB values */ | ||
472 | snd_soc_write(codec, AIC32X4_DOSRMSB, aic32x4_divs[i].dosr >> 8); | ||
473 | snd_soc_write(codec, AIC32X4_DOSRLSB, | ||
474 | (aic32x4_divs[i].dosr & 0xff)); | ||
475 | |||
476 | /* NADC divider value */ | ||
477 | data = snd_soc_read(codec, AIC32X4_NADC); | ||
478 | data &= ~(0x7f); | ||
479 | snd_soc_write(codec, AIC32X4_NADC, data | aic32x4_divs[i].nadc); | ||
480 | |||
481 | /* MADC divider value */ | ||
482 | data = snd_soc_read(codec, AIC32X4_MADC); | ||
483 | data &= ~(0x7f); | ||
484 | snd_soc_write(codec, AIC32X4_MADC, data | aic32x4_divs[i].madc); | ||
485 | |||
486 | /* AOSR value */ | ||
487 | snd_soc_write(codec, AIC32X4_AOSR, aic32x4_divs[i].aosr); | ||
488 | |||
489 | /* BCLK N divider */ | ||
490 | data = snd_soc_read(codec, AIC32X4_BCLKN); | ||
491 | data &= ~(0x7f); | ||
492 | snd_soc_write(codec, AIC32X4_BCLKN, data | aic32x4_divs[i].blck_N); | ||
493 | |||
494 | data = snd_soc_read(codec, AIC32X4_IFACE1); | ||
495 | data = data & ~(3 << 4); | ||
496 | switch (params_format(params)) { | ||
497 | case SNDRV_PCM_FORMAT_S16_LE: | ||
498 | break; | ||
499 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
500 | data |= (AIC32X4_WORD_LEN_20BITS << AIC32X4_DOSRMSB_SHIFT); | ||
501 | break; | ||
502 | case SNDRV_PCM_FORMAT_S24_LE: | ||
503 | data |= (AIC32X4_WORD_LEN_24BITS << AIC32X4_DOSRMSB_SHIFT); | ||
504 | break; | ||
505 | case SNDRV_PCM_FORMAT_S32_LE: | ||
506 | data |= (AIC32X4_WORD_LEN_32BITS << AIC32X4_DOSRMSB_SHIFT); | ||
507 | break; | ||
508 | } | ||
509 | snd_soc_write(codec, AIC32X4_IFACE1, data); | ||
510 | |||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | static int aic32x4_mute(struct snd_soc_dai *dai, int mute) | ||
515 | { | ||
516 | struct snd_soc_codec *codec = dai->codec; | ||
517 | u8 dac_reg; | ||
518 | |||
519 | dac_reg = snd_soc_read(codec, AIC32X4_DACMUTE) & ~AIC32X4_MUTEON; | ||
520 | if (mute) | ||
521 | snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg | AIC32X4_MUTEON); | ||
522 | else | ||
523 | snd_soc_write(codec, AIC32X4_DACMUTE, dac_reg); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int aic32x4_set_bias_level(struct snd_soc_codec *codec, | ||
528 | enum snd_soc_bias_level level) | ||
529 | { | ||
530 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
531 | u8 value; | ||
532 | |||
533 | switch (level) { | ||
534 | case SND_SOC_BIAS_ON: | ||
535 | if (aic32x4->master) { | ||
536 | /* Switch on PLL */ | ||
537 | value = snd_soc_read(codec, AIC32X4_PLLPR); | ||
538 | snd_soc_write(codec, AIC32X4_PLLPR, | ||
539 | (value | AIC32X4_PLLEN)); | ||
540 | |||
541 | /* Switch on NDAC Divider */ | ||
542 | value = snd_soc_read(codec, AIC32X4_NDAC); | ||
543 | snd_soc_write(codec, AIC32X4_NDAC, | ||
544 | value | AIC32X4_NDACEN); | ||
545 | |||
546 | /* Switch on MDAC Divider */ | ||
547 | value = snd_soc_read(codec, AIC32X4_MDAC); | ||
548 | snd_soc_write(codec, AIC32X4_MDAC, | ||
549 | value | AIC32X4_MDACEN); | ||
550 | |||
551 | /* Switch on NADC Divider */ | ||
552 | value = snd_soc_read(codec, AIC32X4_NADC); | ||
553 | snd_soc_write(codec, AIC32X4_NADC, | ||
554 | value | AIC32X4_MDACEN); | ||
555 | |||
556 | /* Switch on MADC Divider */ | ||
557 | value = snd_soc_read(codec, AIC32X4_MADC); | ||
558 | snd_soc_write(codec, AIC32X4_MADC, | ||
559 | value | AIC32X4_MDACEN); | ||
560 | |||
561 | /* Switch on BCLK_N Divider */ | ||
562 | value = snd_soc_read(codec, AIC32X4_BCLKN); | ||
563 | snd_soc_write(codec, AIC32X4_BCLKN, | ||
564 | value | AIC32X4_BCLKEN); | ||
565 | } | ||
566 | break; | ||
567 | case SND_SOC_BIAS_PREPARE: | ||
568 | break; | ||
569 | case SND_SOC_BIAS_STANDBY: | ||
570 | if (aic32x4->master) { | ||
571 | /* Switch off PLL */ | ||
572 | value = snd_soc_read(codec, AIC32X4_PLLPR); | ||
573 | snd_soc_write(codec, AIC32X4_PLLPR, | ||
574 | (value & ~AIC32X4_PLLEN)); | ||
575 | |||
576 | /* Switch off NDAC Divider */ | ||
577 | value = snd_soc_read(codec, AIC32X4_NDAC); | ||
578 | snd_soc_write(codec, AIC32X4_NDAC, | ||
579 | value & ~AIC32X4_NDACEN); | ||
580 | |||
581 | /* Switch off MDAC Divider */ | ||
582 | value = snd_soc_read(codec, AIC32X4_MDAC); | ||
583 | snd_soc_write(codec, AIC32X4_MDAC, | ||
584 | value & ~AIC32X4_MDACEN); | ||
585 | |||
586 | /* Switch off NADC Divider */ | ||
587 | value = snd_soc_read(codec, AIC32X4_NADC); | ||
588 | snd_soc_write(codec, AIC32X4_NADC, | ||
589 | value & ~AIC32X4_NDACEN); | ||
590 | |||
591 | /* Switch off MADC Divider */ | ||
592 | value = snd_soc_read(codec, AIC32X4_MADC); | ||
593 | snd_soc_write(codec, AIC32X4_MADC, | ||
594 | value & ~AIC32X4_MDACEN); | ||
595 | value = snd_soc_read(codec, AIC32X4_BCLKN); | ||
596 | |||
597 | /* Switch off BCLK_N Divider */ | ||
598 | snd_soc_write(codec, AIC32X4_BCLKN, | ||
599 | value & ~AIC32X4_BCLKEN); | ||
600 | } | ||
601 | break; | ||
602 | case SND_SOC_BIAS_OFF: | ||
603 | break; | ||
604 | } | ||
605 | codec->dapm.bias_level = level; | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | #define AIC32X4_RATES SNDRV_PCM_RATE_8000_48000 | ||
610 | #define AIC32X4_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ | ||
611 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
612 | |||
613 | static struct snd_soc_dai_ops aic32x4_ops = { | ||
614 | .hw_params = aic32x4_hw_params, | ||
615 | .digital_mute = aic32x4_mute, | ||
616 | .set_fmt = aic32x4_set_dai_fmt, | ||
617 | .set_sysclk = aic32x4_set_dai_sysclk, | ||
618 | }; | ||
619 | |||
620 | static struct snd_soc_dai_driver aic32x4_dai = { | ||
621 | .name = "tlv320aic32x4-hifi", | ||
622 | .playback = { | ||
623 | .stream_name = "Playback", | ||
624 | .channels_min = 1, | ||
625 | .channels_max = 2, | ||
626 | .rates = AIC32X4_RATES, | ||
627 | .formats = AIC32X4_FORMATS,}, | ||
628 | .capture = { | ||
629 | .stream_name = "Capture", | ||
630 | .channels_min = 1, | ||
631 | .channels_max = 2, | ||
632 | .rates = AIC32X4_RATES, | ||
633 | .formats = AIC32X4_FORMATS,}, | ||
634 | .ops = &aic32x4_ops, | ||
635 | .symmetric_rates = 1, | ||
636 | }; | ||
637 | |||
638 | static int aic32x4_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
639 | { | ||
640 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
641 | return 0; | ||
642 | } | ||
643 | |||
644 | static int aic32x4_resume(struct snd_soc_codec *codec) | ||
645 | { | ||
646 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static int aic32x4_probe(struct snd_soc_codec *codec) | ||
651 | { | ||
652 | struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); | ||
653 | u32 tmp_reg; | ||
654 | |||
655 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
656 | codec->control_data = aic32x4->control_data; | ||
657 | |||
658 | snd_soc_write(codec, AIC32X4_RESET, 0x01); | ||
659 | |||
660 | /* Power platform configuration */ | ||
661 | if (aic32x4->power_cfg & AIC32X4_PWR_MICBIAS_2075_LDOIN) { | ||
662 | snd_soc_write(codec, AIC32X4_MICBIAS, AIC32X4_MICBIAS_LDOIN | | ||
663 | AIC32X4_MICBIAS_2075V); | ||
664 | } | ||
665 | if (aic32x4->power_cfg & AIC32X4_PWR_AVDD_DVDD_WEAK_DISABLE) { | ||
666 | snd_soc_write(codec, AIC32X4_PWRCFG, AIC32X4_AVDDWEAKDISABLE); | ||
667 | } | ||
668 | if (aic32x4->power_cfg & AIC32X4_PWR_AIC32X4_LDO_ENABLE) { | ||
669 | snd_soc_write(codec, AIC32X4_LDOCTL, AIC32X4_LDOCTLEN); | ||
670 | } | ||
671 | tmp_reg = snd_soc_read(codec, AIC32X4_CMMODE); | ||
672 | if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_LDOIN_RANGE_18_36) { | ||
673 | tmp_reg |= AIC32X4_LDOIN_18_36; | ||
674 | } | ||
675 | if (aic32x4->power_cfg & AIC32X4_PWR_CMMODE_HP_LDOIN_POWERED) { | ||
676 | tmp_reg |= AIC32X4_LDOIN2HP; | ||
677 | } | ||
678 | snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg); | ||
679 | |||
680 | /* Do DACs need to be swapped? */ | ||
681 | if (aic32x4->swapdacs) { | ||
682 | snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN); | ||
683 | } else { | ||
684 | snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN); | ||
685 | } | ||
686 | |||
687 | /* Mic PGA routing */ | ||
688 | if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) { | ||
689 | snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K); | ||
690 | } | ||
691 | if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) { | ||
692 | snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K); | ||
693 | } | ||
694 | |||
695 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
696 | snd_soc_add_controls(codec, aic32x4_snd_controls, | ||
697 | ARRAY_SIZE(aic32x4_snd_controls)); | ||
698 | aic32x4_add_widgets(codec); | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static int aic32x4_remove(struct snd_soc_codec *codec) | ||
704 | { | ||
705 | aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { | ||
710 | .read = aic32x4_read, | ||
711 | .write = aic32x4_write, | ||
712 | .probe = aic32x4_probe, | ||
713 | .remove = aic32x4_remove, | ||
714 | .suspend = aic32x4_suspend, | ||
715 | .resume = aic32x4_resume, | ||
716 | .set_bias_level = aic32x4_set_bias_level, | ||
717 | }; | ||
718 | |||
719 | static __devinit int aic32x4_i2c_probe(struct i2c_client *i2c, | ||
720 | const struct i2c_device_id *id) | ||
721 | { | ||
722 | struct aic32x4_pdata *pdata = i2c->dev.platform_data; | ||
723 | struct aic32x4_priv *aic32x4; | ||
724 | int ret; | ||
725 | |||
726 | aic32x4 = kzalloc(sizeof(struct aic32x4_priv), GFP_KERNEL); | ||
727 | if (aic32x4 == NULL) | ||
728 | return -ENOMEM; | ||
729 | |||
730 | aic32x4->control_data = i2c; | ||
731 | i2c_set_clientdata(i2c, aic32x4); | ||
732 | |||
733 | if (pdata) { | ||
734 | aic32x4->power_cfg = pdata->power_cfg; | ||
735 | aic32x4->swapdacs = pdata->swapdacs; | ||
736 | aic32x4->micpga_routing = pdata->micpga_routing; | ||
737 | } else { | ||
738 | aic32x4->power_cfg = 0; | ||
739 | aic32x4->swapdacs = false; | ||
740 | aic32x4->micpga_routing = 0; | ||
741 | } | ||
742 | |||
743 | ret = snd_soc_register_codec(&i2c->dev, | ||
744 | &soc_codec_dev_aic32x4, &aic32x4_dai, 1); | ||
745 | if (ret < 0) | ||
746 | kfree(aic32x4); | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | static __devexit int aic32x4_i2c_remove(struct i2c_client *client) | ||
751 | { | ||
752 | snd_soc_unregister_codec(&client->dev); | ||
753 | kfree(i2c_get_clientdata(client)); | ||
754 | return 0; | ||
755 | } | ||
756 | |||
757 | static const struct i2c_device_id aic32x4_i2c_id[] = { | ||
758 | { "tlv320aic32x4", 0 }, | ||
759 | { } | ||
760 | }; | ||
761 | MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id); | ||
762 | |||
763 | static struct i2c_driver aic32x4_i2c_driver = { | ||
764 | .driver = { | ||
765 | .name = "tlv320aic32x4", | ||
766 | .owner = THIS_MODULE, | ||
767 | }, | ||
768 | .probe = aic32x4_i2c_probe, | ||
769 | .remove = __devexit_p(aic32x4_i2c_remove), | ||
770 | .id_table = aic32x4_i2c_id, | ||
771 | }; | ||
772 | |||
773 | static int __init aic32x4_modinit(void) | ||
774 | { | ||
775 | int ret = 0; | ||
776 | |||
777 | ret = i2c_add_driver(&aic32x4_i2c_driver); | ||
778 | if (ret != 0) { | ||
779 | printk(KERN_ERR "Failed to register aic32x4 I2C driver: %d\n", | ||
780 | ret); | ||
781 | } | ||
782 | return ret; | ||
783 | } | ||
784 | module_init(aic32x4_modinit); | ||
785 | |||
786 | static void __exit aic32x4_exit(void) | ||
787 | { | ||
788 | i2c_del_driver(&aic32x4_i2c_driver); | ||
789 | } | ||
790 | module_exit(aic32x4_exit); | ||
791 | |||
792 | MODULE_DESCRIPTION("ASoC tlv320aic32x4 codec driver"); | ||
793 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); | ||
794 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic32x4.h b/sound/soc/codecs/tlv320aic32x4.h new file mode 100644 index 000000000000..aae2b2440398 --- /dev/null +++ b/sound/soc/codecs/tlv320aic32x4.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * tlv320aic32x4.h | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | |||
10 | #ifndef _TLV320AIC32X4_H | ||
11 | #define _TLV320AIC32X4_H | ||
12 | |||
13 | /* tlv320aic32x4 register space (in decimal to match datasheet) */ | ||
14 | |||
15 | #define AIC32X4_PAGE1 128 | ||
16 | |||
17 | #define AIC32X4_PSEL 0 | ||
18 | #define AIC32X4_RESET 1 | ||
19 | #define AIC32X4_CLKMUX 4 | ||
20 | #define AIC32X4_PLLPR 5 | ||
21 | #define AIC32X4_PLLJ 6 | ||
22 | #define AIC32X4_PLLDMSB 7 | ||
23 | #define AIC32X4_PLLDLSB 8 | ||
24 | #define AIC32X4_NDAC 11 | ||
25 | #define AIC32X4_MDAC 12 | ||
26 | #define AIC32X4_DOSRMSB 13 | ||
27 | #define AIC32X4_DOSRLSB 14 | ||
28 | #define AIC32X4_NADC 18 | ||
29 | #define AIC32X4_MADC 19 | ||
30 | #define AIC32X4_AOSR 20 | ||
31 | #define AIC32X4_CLKMUX2 25 | ||
32 | #define AIC32X4_CLKOUTM 26 | ||
33 | #define AIC32X4_IFACE1 27 | ||
34 | #define AIC32X4_IFACE2 28 | ||
35 | #define AIC32X4_IFACE3 29 | ||
36 | #define AIC32X4_BCLKN 30 | ||
37 | #define AIC32X4_IFACE4 31 | ||
38 | #define AIC32X4_IFACE5 32 | ||
39 | #define AIC32X4_IFACE6 33 | ||
40 | #define AIC32X4_DOUTCTL 53 | ||
41 | #define AIC32X4_DINCTL 54 | ||
42 | #define AIC32X4_DACSPB 60 | ||
43 | #define AIC32X4_ADCSPB 61 | ||
44 | #define AIC32X4_DACSETUP 63 | ||
45 | #define AIC32X4_DACMUTE 64 | ||
46 | #define AIC32X4_LDACVOL 65 | ||
47 | #define AIC32X4_RDACVOL 66 | ||
48 | #define AIC32X4_ADCSETUP 81 | ||
49 | #define AIC32X4_ADCFGA 82 | ||
50 | #define AIC32X4_LADCVOL 83 | ||
51 | #define AIC32X4_RADCVOL 84 | ||
52 | #define AIC32X4_LAGC1 86 | ||
53 | #define AIC32X4_LAGC2 87 | ||
54 | #define AIC32X4_LAGC3 88 | ||
55 | #define AIC32X4_LAGC4 89 | ||
56 | #define AIC32X4_LAGC5 90 | ||
57 | #define AIC32X4_LAGC6 91 | ||
58 | #define AIC32X4_LAGC7 92 | ||
59 | #define AIC32X4_RAGC1 94 | ||
60 | #define AIC32X4_RAGC2 95 | ||
61 | #define AIC32X4_RAGC3 96 | ||
62 | #define AIC32X4_RAGC4 97 | ||
63 | #define AIC32X4_RAGC5 98 | ||
64 | #define AIC32X4_RAGC6 99 | ||
65 | #define AIC32X4_RAGC7 100 | ||
66 | #define AIC32X4_PWRCFG (AIC32X4_PAGE1 + 1) | ||
67 | #define AIC32X4_LDOCTL (AIC32X4_PAGE1 + 2) | ||
68 | #define AIC32X4_OUTPWRCTL (AIC32X4_PAGE1 + 9) | ||
69 | #define AIC32X4_CMMODE (AIC32X4_PAGE1 + 10) | ||
70 | #define AIC32X4_HPLROUTE (AIC32X4_PAGE1 + 12) | ||
71 | #define AIC32X4_HPRROUTE (AIC32X4_PAGE1 + 13) | ||
72 | #define AIC32X4_LOLROUTE (AIC32X4_PAGE1 + 14) | ||
73 | #define AIC32X4_LORROUTE (AIC32X4_PAGE1 + 15) | ||
74 | #define AIC32X4_HPLGAIN (AIC32X4_PAGE1 + 16) | ||
75 | #define AIC32X4_HPRGAIN (AIC32X4_PAGE1 + 17) | ||
76 | #define AIC32X4_LOLGAIN (AIC32X4_PAGE1 + 18) | ||
77 | #define AIC32X4_LORGAIN (AIC32X4_PAGE1 + 19) | ||
78 | #define AIC32X4_HEADSTART (AIC32X4_PAGE1 + 20) | ||
79 | #define AIC32X4_MICBIAS (AIC32X4_PAGE1 + 51) | ||
80 | #define AIC32X4_LMICPGAPIN (AIC32X4_PAGE1 + 52) | ||
81 | #define AIC32X4_LMICPGANIN (AIC32X4_PAGE1 + 54) | ||
82 | #define AIC32X4_RMICPGAPIN (AIC32X4_PAGE1 + 55) | ||
83 | #define AIC32X4_RMICPGANIN (AIC32X4_PAGE1 + 57) | ||
84 | #define AIC32X4_FLOATINGINPUT (AIC32X4_PAGE1 + 58) | ||
85 | #define AIC32X4_LMICPGAVOL (AIC32X4_PAGE1 + 59) | ||
86 | #define AIC32X4_RMICPGAVOL (AIC32X4_PAGE1 + 60) | ||
87 | |||
88 | #define AIC32X4_FREQ_12000000 12000000 | ||
89 | #define AIC32X4_FREQ_24000000 24000000 | ||
90 | #define AIC32X4_FREQ_25000000 25000000 | ||
91 | |||
92 | #define AIC32X4_WORD_LEN_16BITS 0x00 | ||
93 | #define AIC32X4_WORD_LEN_20BITS 0x01 | ||
94 | #define AIC32X4_WORD_LEN_24BITS 0x02 | ||
95 | #define AIC32X4_WORD_LEN_32BITS 0x03 | ||
96 | |||
97 | #define AIC32X4_I2S_MODE 0x00 | ||
98 | #define AIC32X4_DSP_MODE 0x01 | ||
99 | #define AIC32X4_RIGHT_JUSTIFIED_MODE 0x02 | ||
100 | #define AIC32X4_LEFT_JUSTIFIED_MODE 0x03 | ||
101 | |||
102 | #define AIC32X4_AVDDWEAKDISABLE 0x08 | ||
103 | #define AIC32X4_LDOCTLEN 0x01 | ||
104 | |||
105 | #define AIC32X4_LDOIN_18_36 0x01 | ||
106 | #define AIC32X4_LDOIN2HP 0x02 | ||
107 | |||
108 | #define AIC32X4_DACSPBLOCK_MASK 0x1f | ||
109 | #define AIC32X4_ADCSPBLOCK_MASK 0x1f | ||
110 | |||
111 | #define AIC32X4_PLLJ_SHIFT 6 | ||
112 | #define AIC32X4_DOSRMSB_SHIFT 4 | ||
113 | |||
114 | #define AIC32X4_PLLCLKIN 0x03 | ||
115 | |||
116 | #define AIC32X4_MICBIAS_LDOIN 0x08 | ||
117 | #define AIC32X4_MICBIAS_2075V 0x60 | ||
118 | |||
119 | #define AIC32X4_LMICPGANIN_IN2R_10K 0x10 | ||
120 | #define AIC32X4_RMICPGANIN_IN1L_10K 0x10 | ||
121 | |||
122 | #define AIC32X4_LMICPGAVOL_NOGAIN 0x80 | ||
123 | #define AIC32X4_RMICPGAVOL_NOGAIN 0x80 | ||
124 | |||
125 | #define AIC32X4_BCLKMASTER 0x08 | ||
126 | #define AIC32X4_WCLKMASTER 0x04 | ||
127 | #define AIC32X4_PLLEN (0x01 << 7) | ||
128 | #define AIC32X4_NDACEN (0x01 << 7) | ||
129 | #define AIC32X4_MDACEN (0x01 << 7) | ||
130 | #define AIC32X4_NADCEN (0x01 << 7) | ||
131 | #define AIC32X4_MADCEN (0x01 << 7) | ||
132 | #define AIC32X4_BCLKEN (0x01 << 7) | ||
133 | #define AIC32X4_DACEN (0x03 << 6) | ||
134 | #define AIC32X4_RDAC2LCHN (0x02 << 2) | ||
135 | #define AIC32X4_LDAC2RCHN (0x02 << 4) | ||
136 | #define AIC32X4_LDAC2LCHN (0x01 << 4) | ||
137 | #define AIC32X4_RDAC2RCHN (0x01 << 2) | ||
138 | |||
139 | #define AIC32X4_SSTEP2WCLK 0x01 | ||
140 | #define AIC32X4_MUTEON 0x0C | ||
141 | #define AIC32X4_DACMOD2BCLK 0x01 | ||
142 | |||
143 | #endif /* _TLV320AIC32X4_H */ | ||
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 71d7be8ac488..00b6d87e7bdb 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -1615,6 +1615,7 @@ static const struct i2c_device_id tlv320dac33_i2c_id[] = { | |||
1615 | }, | 1615 | }, |
1616 | { }, | 1616 | { }, |
1617 | }; | 1617 | }; |
1618 | MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id); | ||
1618 | 1619 | ||
1619 | static struct i2c_driver tlv320dac33_i2c_driver = { | 1620 | static struct i2c_driver tlv320dac33_i2c_driver = { |
1620 | .driver = { | 1621 | .driver = { |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index 4bbf1b15a493..482fcdb59bfa 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -724,8 +724,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | |||
724 | return 0; | 724 | return 0; |
725 | } | 725 | } |
726 | 726 | ||
727 | void twl6040_hs_jack_report(struct snd_soc_codec *codec, | 727 | static void twl6040_hs_jack_report(struct snd_soc_codec *codec, |
728 | struct snd_soc_jack *jack, int report) | 728 | struct snd_soc_jack *jack, int report) |
729 | { | 729 | { |
730 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); | 730 | struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec); |
731 | int status; | 731 | int status; |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 80ddf4fd23db..a3b9cbb20ee9 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -836,24 +836,25 @@ static void wm2000_i2c_shutdown(struct i2c_client *i2c) | |||
836 | } | 836 | } |
837 | 837 | ||
838 | #ifdef CONFIG_PM | 838 | #ifdef CONFIG_PM |
839 | static int wm2000_i2c_suspend(struct i2c_client *i2c, pm_message_t mesg) | 839 | static int wm2000_i2c_suspend(struct device *dev) |
840 | { | 840 | { |
841 | struct i2c_client *i2c = to_i2c_client(dev); | ||
841 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | 842 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); |
842 | 843 | ||
843 | return wm2000_anc_transition(wm2000, ANC_OFF); | 844 | return wm2000_anc_transition(wm2000, ANC_OFF); |
844 | } | 845 | } |
845 | 846 | ||
846 | static int wm2000_i2c_resume(struct i2c_client *i2c) | 847 | static int wm2000_i2c_resume(struct device *dev) |
847 | { | 848 | { |
849 | struct i2c_client *i2c = to_i2c_client(dev); | ||
848 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); | 850 | struct wm2000_priv *wm2000 = dev_get_drvdata(&i2c->dev); |
849 | 851 | ||
850 | return wm2000_anc_set_mode(wm2000); | 852 | return wm2000_anc_set_mode(wm2000); |
851 | } | 853 | } |
852 | #else | ||
853 | #define wm2000_i2c_suspend NULL | ||
854 | #define wm2000_i2c_resume NULL | ||
855 | #endif | 854 | #endif |
856 | 855 | ||
856 | static SIMPLE_DEV_PM_OPS(wm2000_pm, wm2000_i2c_suspend, wm2000_i2c_resume); | ||
857 | |||
857 | static const struct i2c_device_id wm2000_i2c_id[] = { | 858 | static const struct i2c_device_id wm2000_i2c_id[] = { |
858 | { "wm2000", 0 }, | 859 | { "wm2000", 0 }, |
859 | { } | 860 | { } |
@@ -864,11 +865,10 @@ static struct i2c_driver wm2000_i2c_driver = { | |||
864 | .driver = { | 865 | .driver = { |
865 | .name = "wm2000", | 866 | .name = "wm2000", |
866 | .owner = THIS_MODULE, | 867 | .owner = THIS_MODULE, |
868 | .pm = &wm2000_pm, | ||
867 | }, | 869 | }, |
868 | .probe = wm2000_i2c_probe, | 870 | .probe = wm2000_i2c_probe, |
869 | .remove = __devexit_p(wm2000_i2c_remove), | 871 | .remove = __devexit_p(wm2000_i2c_remove), |
870 | .suspend = wm2000_i2c_suspend, | ||
871 | .resume = wm2000_i2c_resume, | ||
872 | .shutdown = wm2000_i2c_shutdown, | 872 | .shutdown = wm2000_i2c_shutdown, |
873 | .id_table = wm2000_i2c_id, | 873 | .id_table = wm2000_i2c_id, |
874 | }; | 874 | }; |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 5eb2f501ce32..4fd4d8dca0fc 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -58,7 +58,7 @@ static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { | |||
58 | 0x0000, /* R8 - ZERO_DETECT */ | 58 | 0x0000, /* R8 - ZERO_DETECT */ |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static int wm8523_volatile_register(unsigned int reg) | 61 | static int wm8523_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
62 | { | 62 | { |
63 | switch (reg) { | 63 | switch (reg) { |
64 | case WM8523_DEVICE_ID: | 64 | case WM8523_DEVICE_ID: |
@@ -414,7 +414,6 @@ static int wm8523_resume(struct snd_soc_codec *codec) | |||
414 | static int wm8523_probe(struct snd_soc_codec *codec) | 414 | static int wm8523_probe(struct snd_soc_codec *codec) |
415 | { | 415 | { |
416 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); | 416 | struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); |
417 | u16 *reg_cache = codec->reg_cache; | ||
418 | int ret, i; | 417 | int ret, i; |
419 | 418 | ||
420 | codec->hw_write = (hw_write_t)i2c_master_send; | 419 | codec->hw_write = (hw_write_t)i2c_master_send; |
@@ -471,8 +470,9 @@ static int wm8523_probe(struct snd_soc_codec *codec) | |||
471 | } | 470 | } |
472 | 471 | ||
473 | /* Change some default settings - latch VU and enable ZC */ | 472 | /* Change some default settings - latch VU and enable ZC */ |
474 | reg_cache[WM8523_DAC_GAINR] |= WM8523_DACR_VU; | 473 | snd_soc_update_bits(codec, WM8523_DAC_GAINR, |
475 | reg_cache[WM8523_DAC_CTRL3] |= WM8523_ZC; | 474 | WM8523_DACR_VU, WM8523_DACR_VU); |
475 | snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC); | ||
476 | 476 | ||
477 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 477 | wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
478 | 478 | ||
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 494f2d31d75b..25af901fe813 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
@@ -421,7 +421,6 @@ static int wm8741_resume(struct snd_soc_codec *codec) | |||
421 | static int wm8741_probe(struct snd_soc_codec *codec) | 421 | static int wm8741_probe(struct snd_soc_codec *codec) |
422 | { | 422 | { |
423 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | 423 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); |
424 | u16 *reg_cache = codec->reg_cache; | ||
425 | int ret = 0; | 424 | int ret = 0; |
426 | 425 | ||
427 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type); | 426 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type); |
@@ -437,10 +436,14 @@ static int wm8741_probe(struct snd_soc_codec *codec) | |||
437 | } | 436 | } |
438 | 437 | ||
439 | /* Change some default settings - latch VU */ | 438 | /* Change some default settings - latch VU */ |
440 | reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | 439 | snd_soc_update_bits(codec, WM8741_DACLLSB_ATTENUATION, |
441 | reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | 440 | WM8741_UPDATELL, WM8741_UPDATELL); |
442 | reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | 441 | snd_soc_update_bits(codec, WM8741_DACLMSB_ATTENUATION, |
443 | reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | 442 | WM8741_UPDATELM, WM8741_UPDATELM); |
443 | snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, | ||
444 | WM8741_UPDATERL, WM8741_UPDATERL); | ||
445 | snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, | ||
446 | WM8741_UPDATERM, WM8741_UPDATERM); | ||
444 | 447 | ||
445 | snd_soc_add_controls(codec, wm8741_snd_controls, | 448 | snd_soc_add_controls(codec, wm8741_snd_controls, |
446 | ARRAY_SIZE(wm8741_snd_controls)); | 449 | ARRAY_SIZE(wm8741_snd_controls)); |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 79b02ae125c5..3f09deea8d9d 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -55,8 +55,10 @@ static int caps_charge = 2000; | |||
55 | module_param(caps_charge, int, 0); | 55 | module_param(caps_charge, int, 0); |
56 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); | 56 | MODULE_PARM_DESC(caps_charge, "WM8753 cap charge time (msecs)"); |
57 | 57 | ||
58 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | 58 | static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, |
59 | struct snd_soc_dai *dai, unsigned int hifi); | 59 | unsigned int fmt); |
60 | static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, | ||
61 | unsigned int fmt); | ||
60 | 62 | ||
61 | /* | 63 | /* |
62 | * wm8753 register cache | 64 | * wm8753 register cache |
@@ -87,6 +89,10 @@ struct wm8753_priv { | |||
87 | enum snd_soc_control_type control_type; | 89 | enum snd_soc_control_type control_type; |
88 | unsigned int sysclk; | 90 | unsigned int sysclk; |
89 | unsigned int pcmclk; | 91 | unsigned int pcmclk; |
92 | |||
93 | unsigned int voice_fmt; | ||
94 | unsigned int hifi_fmt; | ||
95 | |||
90 | int dai_func; | 96 | int dai_func; |
91 | }; | 97 | }; |
92 | 98 | ||
@@ -170,9 +176,9 @@ static int wm8753_get_dai(struct snd_kcontrol *kcontrol, | |||
170 | struct snd_ctl_elem_value *ucontrol) | 176 | struct snd_ctl_elem_value *ucontrol) |
171 | { | 177 | { |
172 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 178 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
173 | int mode = snd_soc_read(codec, WM8753_IOCTL); | 179 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
174 | 180 | ||
175 | ucontrol->value.integer.value[0] = (mode & 0xc) >> 2; | 181 | ucontrol->value.integer.value[0] = wm8753->dai_func; |
176 | return 0; | 182 | return 0; |
177 | } | 183 | } |
178 | 184 | ||
@@ -180,16 +186,26 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
180 | struct snd_ctl_elem_value *ucontrol) | 186 | struct snd_ctl_elem_value *ucontrol) |
181 | { | 187 | { |
182 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 188 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
183 | int mode = snd_soc_read(codec, WM8753_IOCTL); | ||
184 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | 189 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); |
190 | u16 ioctl; | ||
191 | |||
192 | if (codec->active) | ||
193 | return -EBUSY; | ||
194 | |||
195 | ioctl = snd_soc_read(codec, WM8753_IOCTL); | ||
196 | |||
197 | wm8753->dai_func = ucontrol->value.integer.value[0]; | ||
198 | |||
199 | if (((ioctl >> 2) & 0x3) == wm8753->dai_func) | ||
200 | return 1; | ||
201 | |||
202 | ioctl = (ioctl & 0x1f3) | (wm8753->dai_func << 2); | ||
203 | snd_soc_write(codec, WM8753_IOCTL, ioctl); | ||
185 | 204 | ||
186 | if (((mode & 0xc) >> 2) == ucontrol->value.integer.value[0]) | ||
187 | return 0; | ||
188 | 205 | ||
189 | mode &= 0xfff3; | 206 | wm8753_hifi_write_dai_fmt(codec, wm8753->hifi_fmt); |
190 | mode |= (ucontrol->value.integer.value[0] << 2); | 207 | wm8753_voice_write_dai_fmt(codec, wm8753->voice_fmt); |
191 | 208 | ||
192 | wm8753->dai_func = ucontrol->value.integer.value[0]; | ||
193 | return 1; | 209 | return 1; |
194 | } | 210 | } |
195 | 211 | ||
@@ -828,10 +844,9 @@ static int wm8753_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
828 | /* | 844 | /* |
829 | * Set's ADC and Voice DAC format. | 845 | * Set's ADC and Voice DAC format. |
830 | */ | 846 | */ |
831 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, | 847 | static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_codec *codec, |
832 | unsigned int fmt) | 848 | unsigned int fmt) |
833 | { | 849 | { |
834 | struct snd_soc_codec *codec = codec_dai->codec; | ||
835 | u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec; | 850 | u16 voice = snd_soc_read(codec, WM8753_PCM) & 0x01ec; |
836 | 851 | ||
837 | /* interface format */ | 852 | /* interface format */ |
@@ -858,13 +873,6 @@ static int wm8753_vdac_adc_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
858 | return 0; | 873 | return 0; |
859 | } | 874 | } |
860 | 875 | ||
861 | static int wm8753_pcm_startup(struct snd_pcm_substream *substream, | ||
862 | struct snd_soc_dai *dai) | ||
863 | { | ||
864 | wm8753_set_dai_mode(dai->codec, dai, 0); | ||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | /* | 876 | /* |
869 | * Set PCM DAI bit size and sample rate. | 877 | * Set PCM DAI bit size and sample rate. |
870 | */ | 878 | */ |
@@ -905,10 +913,9 @@ static int wm8753_pcm_hw_params(struct snd_pcm_substream *substream, | |||
905 | /* | 913 | /* |
906 | * Set's PCM dai fmt and BCLK. | 914 | * Set's PCM dai fmt and BCLK. |
907 | */ | 915 | */ |
908 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_dai *codec_dai, | 916 | static int wm8753_pcm_set_dai_fmt(struct snd_soc_codec *codec, |
909 | unsigned int fmt) | 917 | unsigned int fmt) |
910 | { | 918 | { |
911 | struct snd_soc_codec *codec = codec_dai->codec; | ||
912 | u16 voice, ioctl; | 919 | u16 voice, ioctl; |
913 | 920 | ||
914 | voice = snd_soc_read(codec, WM8753_PCM) & 0x011f; | 921 | voice = snd_soc_read(codec, WM8753_PCM) & 0x011f; |
@@ -999,10 +1006,9 @@ static int wm8753_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | |||
999 | /* | 1006 | /* |
1000 | * Set's HiFi DAC format. | 1007 | * Set's HiFi DAC format. |
1001 | */ | 1008 | */ |
1002 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1009 | static int wm8753_hdac_set_dai_fmt(struct snd_soc_codec *codec, |
1003 | unsigned int fmt) | 1010 | unsigned int fmt) |
1004 | { | 1011 | { |
1005 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1006 | u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0; | 1012 | u16 hifi = snd_soc_read(codec, WM8753_HIFI) & 0x01e0; |
1007 | 1013 | ||
1008 | /* interface format */ | 1014 | /* interface format */ |
@@ -1032,10 +1038,9 @@ static int wm8753_hdac_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1032 | /* | 1038 | /* |
1033 | * Set's I2S DAI format. | 1039 | * Set's I2S DAI format. |
1034 | */ | 1040 | */ |
1035 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1041 | static int wm8753_i2s_set_dai_fmt(struct snd_soc_codec *codec, |
1036 | unsigned int fmt) | 1042 | unsigned int fmt) |
1037 | { | 1043 | { |
1038 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1039 | u16 ioctl, hifi; | 1044 | u16 ioctl, hifi; |
1040 | 1045 | ||
1041 | hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f; | 1046 | hifi = snd_soc_read(codec, WM8753_HIFI) & 0x011f; |
@@ -1098,13 +1103,6 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1098 | return 0; | 1103 | return 0; |
1099 | } | 1104 | } |
1100 | 1105 | ||
1101 | static int wm8753_i2s_startup(struct snd_pcm_substream *substream, | ||
1102 | struct snd_soc_dai *dai) | ||
1103 | { | ||
1104 | wm8753_set_dai_mode(dai->codec, dai, 1); | ||
1105 | return 0; | ||
1106 | } | ||
1107 | |||
1108 | /* | 1106 | /* |
1109 | * Set PCM DAI bit size and sample rate. | 1107 | * Set PCM DAI bit size and sample rate. |
1110 | */ | 1108 | */ |
@@ -1147,61 +1145,117 @@ static int wm8753_i2s_hw_params(struct snd_pcm_substream *substream, | |||
1147 | return 0; | 1145 | return 0; |
1148 | } | 1146 | } |
1149 | 1147 | ||
1150 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1148 | static int wm8753_mode1v_set_dai_fmt(struct snd_soc_codec *codec, |
1151 | unsigned int fmt) | 1149 | unsigned int fmt) |
1152 | { | 1150 | { |
1153 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1154 | u16 clock; | 1151 | u16 clock; |
1155 | 1152 | ||
1156 | /* set clk source as pcmclk */ | 1153 | /* set clk source as pcmclk */ |
1157 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1154 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
1158 | snd_soc_write(codec, WM8753_CLOCK, clock); | 1155 | snd_soc_write(codec, WM8753_CLOCK, clock); |
1159 | 1156 | ||
1160 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1157 | return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
1161 | return -EINVAL; | ||
1162 | return wm8753_pcm_set_dai_fmt(codec_dai, fmt); | ||
1163 | } | 1158 | } |
1164 | 1159 | ||
1165 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1160 | static int wm8753_mode1h_set_dai_fmt(struct snd_soc_codec *codec, |
1166 | unsigned int fmt) | 1161 | unsigned int fmt) |
1167 | { | 1162 | { |
1168 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1163 | return wm8753_hdac_set_dai_fmt(codec, fmt); |
1169 | return -EINVAL; | ||
1170 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | ||
1171 | } | 1164 | } |
1172 | 1165 | ||
1173 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1166 | static int wm8753_mode2_set_dai_fmt(struct snd_soc_codec *codec, |
1174 | unsigned int fmt) | 1167 | unsigned int fmt) |
1175 | { | 1168 | { |
1176 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1177 | u16 clock; | 1169 | u16 clock; |
1178 | 1170 | ||
1179 | /* set clk source as pcmclk */ | 1171 | /* set clk source as pcmclk */ |
1180 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1172 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
1181 | snd_soc_write(codec, WM8753_CLOCK, clock); | 1173 | snd_soc_write(codec, WM8753_CLOCK, clock); |
1182 | 1174 | ||
1183 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1175 | return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
1184 | return -EINVAL; | ||
1185 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | ||
1186 | } | 1176 | } |
1187 | 1177 | ||
1188 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_dai *codec_dai, | 1178 | static int wm8753_mode3_4_set_dai_fmt(struct snd_soc_codec *codec, |
1189 | unsigned int fmt) | 1179 | unsigned int fmt) |
1190 | { | 1180 | { |
1191 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1192 | u16 clock; | 1181 | u16 clock; |
1193 | 1182 | ||
1194 | /* set clk source as mclk */ | 1183 | /* set clk source as mclk */ |
1195 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; | 1184 | clock = snd_soc_read(codec, WM8753_CLOCK) & 0xfffb; |
1196 | snd_soc_write(codec, WM8753_CLOCK, clock | 0x4); | 1185 | snd_soc_write(codec, WM8753_CLOCK, clock | 0x4); |
1197 | 1186 | ||
1198 | if (wm8753_hdac_set_dai_fmt(codec_dai, fmt) < 0) | 1187 | if (wm8753_hdac_set_dai_fmt(codec, fmt) < 0) |
1199 | return -EINVAL; | 1188 | return -EINVAL; |
1200 | if (wm8753_vdac_adc_set_dai_fmt(codec_dai, fmt) < 0) | 1189 | return wm8753_vdac_adc_set_dai_fmt(codec, fmt); |
1201 | return -EINVAL; | ||
1202 | return wm8753_i2s_set_dai_fmt(codec_dai, fmt); | ||
1203 | } | 1190 | } |
1204 | 1191 | ||
1192 | static int wm8753_hifi_write_dai_fmt(struct snd_soc_codec *codec, | ||
1193 | unsigned int fmt) | ||
1194 | { | ||
1195 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1196 | int ret = 0; | ||
1197 | |||
1198 | switch (wm8753->dai_func) { | ||
1199 | case 0: | ||
1200 | ret = wm8753_mode1h_set_dai_fmt(codec, fmt); | ||
1201 | break; | ||
1202 | case 1: | ||
1203 | ret = wm8753_mode2_set_dai_fmt(codec, fmt); | ||
1204 | break; | ||
1205 | case 2: | ||
1206 | case 3: | ||
1207 | ret = wm8753_mode3_4_set_dai_fmt(codec, fmt); | ||
1208 | break; | ||
1209 | default: | ||
1210 | break; | ||
1211 | } | ||
1212 | if (ret) | ||
1213 | return ret; | ||
1214 | |||
1215 | return wm8753_i2s_set_dai_fmt(codec, fmt); | ||
1216 | } | ||
1217 | |||
1218 | static int wm8753_hifi_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1219 | unsigned int fmt) | ||
1220 | { | ||
1221 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1222 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1223 | |||
1224 | wm8753->hifi_fmt = fmt; | ||
1225 | |||
1226 | return wm8753_hifi_write_dai_fmt(codec, fmt); | ||
1227 | }; | ||
1228 | |||
1229 | static int wm8753_voice_write_dai_fmt(struct snd_soc_codec *codec, | ||
1230 | unsigned int fmt) | ||
1231 | { | ||
1232 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1233 | int ret = 0; | ||
1234 | |||
1235 | if (wm8753->dai_func != 0) | ||
1236 | return 0; | ||
1237 | |||
1238 | ret = wm8753_mode1v_set_dai_fmt(codec, fmt); | ||
1239 | if (ret) | ||
1240 | return ret; | ||
1241 | ret = wm8753_pcm_set_dai_fmt(codec, fmt); | ||
1242 | if (ret) | ||
1243 | return ret; | ||
1244 | |||
1245 | return 0; | ||
1246 | }; | ||
1247 | |||
1248 | static int wm8753_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1249 | unsigned int fmt) | ||
1250 | { | ||
1251 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1252 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1253 | |||
1254 | wm8753->voice_fmt = fmt; | ||
1255 | |||
1256 | return wm8753_voice_write_dai_fmt(codec, fmt); | ||
1257 | }; | ||
1258 | |||
1205 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) | 1259 | static int wm8753_mute(struct snd_soc_dai *dai, int mute) |
1206 | { | 1260 | { |
1207 | struct snd_soc_codec *codec = dai->codec; | 1261 | struct snd_soc_codec *codec = dai->codec; |
@@ -1268,57 +1322,25 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec, | |||
1268 | * 3. Voice disabled - HIFI over HIFI | 1322 | * 3. Voice disabled - HIFI over HIFI |
1269 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture | 1323 | * 4. Voice disabled - HIFI over HIFI, uses voice DAI LRC for capture |
1270 | */ | 1324 | */ |
1271 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode1 = { | 1325 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode = { |
1272 | .startup = wm8753_i2s_startup, | ||
1273 | .hw_params = wm8753_i2s_hw_params, | 1326 | .hw_params = wm8753_i2s_hw_params, |
1274 | .digital_mute = wm8753_mute, | 1327 | .digital_mute = wm8753_mute, |
1275 | .set_fmt = wm8753_mode1h_set_dai_fmt, | 1328 | .set_fmt = wm8753_hifi_set_dai_fmt, |
1276 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1277 | .set_pll = wm8753_set_dai_pll, | ||
1278 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1279 | }; | ||
1280 | |||
1281 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode1 = { | ||
1282 | .startup = wm8753_pcm_startup, | ||
1283 | .hw_params = wm8753_pcm_hw_params, | ||
1284 | .digital_mute = wm8753_mute, | ||
1285 | .set_fmt = wm8753_mode1v_set_dai_fmt, | ||
1286 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1329 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1287 | .set_pll = wm8753_set_dai_pll, | 1330 | .set_pll = wm8753_set_dai_pll, |
1288 | .set_sysclk = wm8753_set_dai_sysclk, | 1331 | .set_sysclk = wm8753_set_dai_sysclk, |
1289 | }; | 1332 | }; |
1290 | 1333 | ||
1291 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode2 = { | 1334 | static struct snd_soc_dai_ops wm8753_dai_ops_voice_mode = { |
1292 | .startup = wm8753_pcm_startup, | ||
1293 | .hw_params = wm8753_pcm_hw_params, | 1335 | .hw_params = wm8753_pcm_hw_params, |
1294 | .digital_mute = wm8753_mute, | 1336 | .digital_mute = wm8753_mute, |
1295 | .set_fmt = wm8753_mode2_set_dai_fmt, | 1337 | .set_fmt = wm8753_voice_set_dai_fmt, |
1296 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1297 | .set_pll = wm8753_set_dai_pll, | ||
1298 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1299 | }; | ||
1300 | |||
1301 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode3 = { | ||
1302 | .startup = wm8753_i2s_startup, | ||
1303 | .hw_params = wm8753_i2s_hw_params, | ||
1304 | .digital_mute = wm8753_mute, | ||
1305 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1306 | .set_clkdiv = wm8753_set_dai_clkdiv, | ||
1307 | .set_pll = wm8753_set_dai_pll, | ||
1308 | .set_sysclk = wm8753_set_dai_sysclk, | ||
1309 | }; | ||
1310 | |||
1311 | static struct snd_soc_dai_ops wm8753_dai_ops_hifi_mode4 = { | ||
1312 | .startup = wm8753_i2s_startup, | ||
1313 | .hw_params = wm8753_i2s_hw_params, | ||
1314 | .digital_mute = wm8753_mute, | ||
1315 | .set_fmt = wm8753_mode3_4_set_dai_fmt, | ||
1316 | .set_clkdiv = wm8753_set_dai_clkdiv, | 1338 | .set_clkdiv = wm8753_set_dai_clkdiv, |
1317 | .set_pll = wm8753_set_dai_pll, | 1339 | .set_pll = wm8753_set_dai_pll, |
1318 | .set_sysclk = wm8753_set_dai_sysclk, | 1340 | .set_sysclk = wm8753_set_dai_sysclk, |
1319 | }; | 1341 | }; |
1320 | 1342 | ||
1321 | static struct snd_soc_dai_driver wm8753_all_dai[] = { | 1343 | static struct snd_soc_dai_driver wm8753_dai[] = { |
1322 | /* DAI HiFi mode 1 */ | 1344 | /* DAI HiFi mode 1 */ |
1323 | { .name = "wm8753-hifi", | 1345 | { .name = "wm8753-hifi", |
1324 | .playback = { | 1346 | .playback = { |
@@ -1326,14 +1348,16 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = { | |||
1326 | .channels_min = 1, | 1348 | .channels_min = 1, |
1327 | .channels_max = 2, | 1349 | .channels_max = 2, |
1328 | .rates = WM8753_RATES, | 1350 | .rates = WM8753_RATES, |
1329 | .formats = WM8753_FORMATS}, | 1351 | .formats = WM8753_FORMATS |
1352 | }, | ||
1330 | .capture = { /* dummy for fast DAI switching */ | 1353 | .capture = { /* dummy for fast DAI switching */ |
1331 | .stream_name = "Capture", | 1354 | .stream_name = "Capture", |
1332 | .channels_min = 1, | 1355 | .channels_min = 1, |
1333 | .channels_max = 2, | 1356 | .channels_max = 2, |
1334 | .rates = WM8753_RATES, | 1357 | .rates = WM8753_RATES, |
1335 | .formats = WM8753_FORMATS}, | 1358 | .formats = WM8753_FORMATS |
1336 | .ops = &wm8753_dai_ops_hifi_mode1, | 1359 | }, |
1360 | .ops = &wm8753_dai_ops_hifi_mode, | ||
1337 | }, | 1361 | }, |
1338 | /* DAI Voice mode 1 */ | 1362 | /* DAI Voice mode 1 */ |
1339 | { .name = "wm8753-voice", | 1363 | { .name = "wm8753-voice", |
@@ -1342,97 +1366,19 @@ static struct snd_soc_dai_driver wm8753_all_dai[] = { | |||
1342 | .channels_min = 1, | 1366 | .channels_min = 1, |
1343 | .channels_max = 1, | 1367 | .channels_max = 1, |
1344 | .rates = WM8753_RATES, | 1368 | .rates = WM8753_RATES, |
1345 | .formats = WM8753_FORMATS,}, | 1369 | .formats = WM8753_FORMATS, |
1346 | .capture = { | 1370 | }, |
1347 | .stream_name = "Capture", | ||
1348 | .channels_min = 1, | ||
1349 | .channels_max = 2, | ||
1350 | .rates = WM8753_RATES, | ||
1351 | .formats = WM8753_FORMATS,}, | ||
1352 | .ops = &wm8753_dai_ops_voice_mode1, | ||
1353 | }, | ||
1354 | /* DAI HiFi mode 2 - dummy */ | ||
1355 | { .name = "wm8753-hifi", | ||
1356 | }, | ||
1357 | /* DAI Voice mode 2 */ | ||
1358 | { .name = "wm8753-voice", | ||
1359 | .playback = { | ||
1360 | .stream_name = "Voice Playback", | ||
1361 | .channels_min = 1, | ||
1362 | .channels_max = 1, | ||
1363 | .rates = WM8753_RATES, | ||
1364 | .formats = WM8753_FORMATS,}, | ||
1365 | .capture = { | ||
1366 | .stream_name = "Capture", | ||
1367 | .channels_min = 1, | ||
1368 | .channels_max = 2, | ||
1369 | .rates = WM8753_RATES, | ||
1370 | .formats = WM8753_FORMATS,}, | ||
1371 | .ops = &wm8753_dai_ops_voice_mode2, | ||
1372 | }, | ||
1373 | /* DAI HiFi mode 3 */ | ||
1374 | { .name = "wm8753-hifi", | ||
1375 | .playback = { | ||
1376 | .stream_name = "HiFi Playback", | ||
1377 | .channels_min = 1, | ||
1378 | .channels_max = 2, | ||
1379 | .rates = WM8753_RATES, | ||
1380 | .formats = WM8753_FORMATS,}, | ||
1381 | .capture = { | ||
1382 | .stream_name = "Capture", | ||
1383 | .channels_min = 1, | ||
1384 | .channels_max = 2, | ||
1385 | .rates = WM8753_RATES, | ||
1386 | .formats = WM8753_FORMATS,}, | ||
1387 | .ops = &wm8753_dai_ops_hifi_mode3, | ||
1388 | }, | ||
1389 | /* DAI Voice mode 3 - dummy */ | ||
1390 | { .name = "wm8753-voice", | ||
1391 | }, | ||
1392 | /* DAI HiFi mode 4 */ | ||
1393 | { .name = "wm8753-hifi", | ||
1394 | .playback = { | ||
1395 | .stream_name = "HiFi Playback", | ||
1396 | .channels_min = 1, | ||
1397 | .channels_max = 2, | ||
1398 | .rates = WM8753_RATES, | ||
1399 | .formats = WM8753_FORMATS,}, | ||
1400 | .capture = { | 1371 | .capture = { |
1401 | .stream_name = "Capture", | 1372 | .stream_name = "Capture", |
1402 | .channels_min = 1, | 1373 | .channels_min = 1, |
1403 | .channels_max = 2, | 1374 | .channels_max = 2, |
1404 | .rates = WM8753_RATES, | 1375 | .rates = WM8753_RATES, |
1405 | .formats = WM8753_FORMATS,}, | 1376 | .formats = WM8753_FORMATS, |
1406 | .ops = &wm8753_dai_ops_hifi_mode4, | ||
1407 | }, | ||
1408 | /* DAI Voice mode 4 - dummy */ | ||
1409 | { .name = "wm8753-voice", | ||
1410 | }, | ||
1411 | }; | ||
1412 | |||
1413 | static struct snd_soc_dai_driver wm8753_dai[] = { | ||
1414 | { | ||
1415 | .name = "wm8753-aif0", | ||
1416 | }, | ||
1417 | { | ||
1418 | .name = "wm8753-aif1", | ||
1419 | }, | 1377 | }, |
1378 | .ops = &wm8753_dai_ops_voice_mode, | ||
1379 | }, | ||
1420 | }; | 1380 | }; |
1421 | 1381 | ||
1422 | static void wm8753_set_dai_mode(struct snd_soc_codec *codec, | ||
1423 | struct snd_soc_dai *dai, unsigned int hifi) | ||
1424 | { | ||
1425 | struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec); | ||
1426 | |||
1427 | if (wm8753->dai_func < 4) { | ||
1428 | if (hifi) | ||
1429 | dai->driver = &wm8753_all_dai[wm8753->dai_func << 1]; | ||
1430 | else | ||
1431 | dai->driver = &wm8753_all_dai[(wm8753->dai_func << 1) + 1]; | ||
1432 | } | ||
1433 | snd_soc_write(codec, WM8753_IOCTL, wm8753->dai_func); | ||
1434 | } | ||
1435 | |||
1436 | static void wm8753_work(struct work_struct *work) | 1382 | static void wm8753_work(struct work_struct *work) |
1437 | { | 1383 | { |
1438 | struct snd_soc_dapm_context *dapm = | 1384 | struct snd_soc_dapm_context *dapm = |
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 6dae1b40c9f7..6785688f8806 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -175,7 +175,7 @@ static int txsrc_put(struct snd_kcontrol *kcontrol, | |||
175 | return 0; | 175 | return 0; |
176 | } | 176 | } |
177 | 177 | ||
178 | static int wm8804_volatile(unsigned int reg) | 178 | static int wm8804_volatile(struct snd_soc_codec *codec, unsigned int reg) |
179 | { | 179 | { |
180 | switch (reg) { | 180 | switch (reg) { |
181 | case WM8804_RST_DEVID1: | 181 | case WM8804_RST_DEVID1: |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index cd0959926d12..449ea09a193d 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -180,7 +180,7 @@ static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { | |||
180 | /* Remaining registers all zero */ | 180 | /* Remaining registers all zero */ |
181 | }; | 181 | }; |
182 | 182 | ||
183 | static int wm8900_volatile_register(unsigned int reg) | 183 | static int wm8900_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
184 | { | 184 | { |
185 | switch (reg) { | 185 | switch (reg) { |
186 | case WM8900_REG_ID: | 186 | case WM8900_REG_ID: |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 017d99ceb42e..ae1cadfae84c 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * wm8903.c -- WM8903 ALSA SoC Audio driver | 2 | * wm8903.c -- WM8903 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics | 4 | * Copyright 2008 Wolfson Microelectronics |
5 | * Copyright 2011 NVIDIA, Inc. | ||
5 | * | 6 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 8 | * |
@@ -19,6 +20,7 @@ | |||
19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
20 | #include <linux/completion.h> | 21 | #include <linux/completion.h> |
21 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/gpio.h> | ||
22 | #include <linux/pm.h> | 24 | #include <linux/pm.h> |
23 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
24 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
@@ -213,6 +215,7 @@ static u16 wm8903_reg_defaults[] = { | |||
213 | }; | 215 | }; |
214 | 216 | ||
215 | struct wm8903_priv { | 217 | struct wm8903_priv { |
218 | struct snd_soc_codec *codec; | ||
216 | 219 | ||
217 | int sysclk; | 220 | int sysclk; |
218 | int irq; | 221 | int irq; |
@@ -220,25 +223,36 @@ struct wm8903_priv { | |||
220 | int fs; | 223 | int fs; |
221 | int deemph; | 224 | int deemph; |
222 | 225 | ||
226 | int dcs_pending; | ||
227 | int dcs_cache[4]; | ||
228 | |||
223 | /* Reference count */ | 229 | /* Reference count */ |
224 | int class_w_users; | 230 | int class_w_users; |
225 | 231 | ||
226 | struct completion wseq; | ||
227 | |||
228 | struct snd_soc_jack *mic_jack; | 232 | struct snd_soc_jack *mic_jack; |
229 | int mic_det; | 233 | int mic_det; |
230 | int mic_short; | 234 | int mic_short; |
231 | int mic_last_report; | 235 | int mic_last_report; |
232 | int mic_delay; | 236 | int mic_delay; |
237 | |||
238 | #ifdef CONFIG_GPIOLIB | ||
239 | struct gpio_chip gpio_chip; | ||
240 | #endif | ||
233 | }; | 241 | }; |
234 | 242 | ||
235 | static int wm8903_volatile_register(unsigned int reg) | 243 | static int wm8903_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
236 | { | 244 | { |
237 | switch (reg) { | 245 | switch (reg) { |
238 | case WM8903_SW_RESET_AND_ID: | 246 | case WM8903_SW_RESET_AND_ID: |
239 | case WM8903_REVISION_NUMBER: | 247 | case WM8903_REVISION_NUMBER: |
240 | case WM8903_INTERRUPT_STATUS_1: | 248 | case WM8903_INTERRUPT_STATUS_1: |
241 | case WM8903_WRITE_SEQUENCER_4: | 249 | case WM8903_WRITE_SEQUENCER_4: |
250 | case WM8903_POWER_MANAGEMENT_3: | ||
251 | case WM8903_POWER_MANAGEMENT_2: | ||
252 | case WM8903_DC_SERVO_READBACK_1: | ||
253 | case WM8903_DC_SERVO_READBACK_2: | ||
254 | case WM8903_DC_SERVO_READBACK_3: | ||
255 | case WM8903_DC_SERVO_READBACK_4: | ||
242 | return 1; | 256 | return 1; |
243 | 257 | ||
244 | default: | 258 | default: |
@@ -246,50 +260,6 @@ static int wm8903_volatile_register(unsigned int reg) | |||
246 | } | 260 | } |
247 | } | 261 | } |
248 | 262 | ||
249 | static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) | ||
250 | { | ||
251 | u16 reg[5]; | ||
252 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
253 | |||
254 | BUG_ON(start > 48); | ||
255 | |||
256 | /* Enable the sequencer if it's not already on */ | ||
257 | reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0); | ||
258 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, | ||
259 | reg[0] | WM8903_WSEQ_ENA); | ||
260 | |||
261 | dev_dbg(codec->dev, "Starting sequence at %d\n", start); | ||
262 | |||
263 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3, | ||
264 | start | WM8903_WSEQ_START); | ||
265 | |||
266 | /* Wait for it to complete. If we have the interrupt wired up then | ||
267 | * that will break us out of the poll early. | ||
268 | */ | ||
269 | do { | ||
270 | wait_for_completion_timeout(&wm8903->wseq, | ||
271 | msecs_to_jiffies(10)); | ||
272 | |||
273 | reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4); | ||
274 | } while (reg[4] & WM8903_WSEQ_BUSY); | ||
275 | |||
276 | dev_dbg(codec->dev, "Sequence complete\n"); | ||
277 | |||
278 | /* Disable the sequencer again if we enabled it */ | ||
279 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) | ||
285 | { | ||
286 | int i; | ||
287 | |||
288 | /* There really ought to be something better we can do here :/ */ | ||
289 | for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) | ||
290 | cache[i] = codec->hw_read(codec, i); | ||
291 | } | ||
292 | |||
293 | static void wm8903_reset(struct snd_soc_codec *codec) | 263 | static void wm8903_reset(struct snd_soc_codec *codec) |
294 | { | 264 | { |
295 | snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0); | 265 | snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0); |
@@ -297,11 +267,6 @@ static void wm8903_reset(struct snd_soc_codec *codec) | |||
297 | sizeof(wm8903_reg_defaults)); | 267 | sizeof(wm8903_reg_defaults)); |
298 | } | 268 | } |
299 | 269 | ||
300 | #define WM8903_OUTPUT_SHORT 0x8 | ||
301 | #define WM8903_OUTPUT_OUT 0x4 | ||
302 | #define WM8903_OUTPUT_INT 0x2 | ||
303 | #define WM8903_OUTPUT_IN 0x1 | ||
304 | |||
305 | static int wm8903_cp_event(struct snd_soc_dapm_widget *w, | 270 | static int wm8903_cp_event(struct snd_soc_dapm_widget *w, |
306 | struct snd_kcontrol *kcontrol, int event) | 271 | struct snd_kcontrol *kcontrol, int event) |
307 | { | 272 | { |
@@ -311,97 +276,101 @@ static int wm8903_cp_event(struct snd_soc_dapm_widget *w, | |||
311 | return 0; | 276 | return 0; |
312 | } | 277 | } |
313 | 278 | ||
314 | /* | 279 | static int wm8903_dcs_event(struct snd_soc_dapm_widget *w, |
315 | * Event for headphone and line out amplifier power changes. Special | 280 | struct snd_kcontrol *kcontrol, int event) |
316 | * power up/down sequences are required in order to maximise pop/click | ||
317 | * performance. | ||
318 | */ | ||
319 | static int wm8903_output_event(struct snd_soc_dapm_widget *w, | ||
320 | struct snd_kcontrol *kcontrol, int event) | ||
321 | { | 281 | { |
322 | struct snd_soc_codec *codec = w->codec; | 282 | struct snd_soc_codec *codec = w->codec; |
323 | u16 val; | 283 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
324 | u16 reg; | ||
325 | u16 dcs_reg; | ||
326 | u16 dcs_bit; | ||
327 | int shift; | ||
328 | 284 | ||
329 | switch (w->reg) { | 285 | switch (event) { |
330 | case WM8903_POWER_MANAGEMENT_2: | 286 | case SND_SOC_DAPM_POST_PMU: |
331 | reg = WM8903_ANALOGUE_HP_0; | 287 | wm8903->dcs_pending |= 1 << w->shift; |
332 | dcs_bit = 0 + w->shift; | ||
333 | break; | 288 | break; |
334 | case WM8903_POWER_MANAGEMENT_3: | 289 | case SND_SOC_DAPM_PRE_PMD: |
335 | reg = WM8903_ANALOGUE_LINEOUT_0; | 290 | snd_soc_update_bits(codec, WM8903_DC_SERVO_0, |
336 | dcs_bit = 2 + w->shift; | 291 | 1 << w->shift, 0); |
337 | break; | 292 | break; |
338 | default: | ||
339 | BUG(); | ||
340 | return -EINVAL; /* Spurious warning from some compilers */ | ||
341 | } | 293 | } |
342 | 294 | ||
343 | switch (w->shift) { | 295 | return 0; |
344 | case 0: | 296 | } |
345 | shift = 0; | ||
346 | break; | ||
347 | case 1: | ||
348 | shift = 4; | ||
349 | break; | ||
350 | default: | ||
351 | BUG(); | ||
352 | return -EINVAL; /* Spurious warning from some compilers */ | ||
353 | } | ||
354 | 297 | ||
355 | if (event & SND_SOC_DAPM_PRE_PMU) { | 298 | #define WM8903_DCS_MODE_WRITE_STOP 0 |
356 | val = snd_soc_read(codec, reg); | 299 | #define WM8903_DCS_MODE_START_STOP 2 |
357 | 300 | ||
358 | /* Short the output */ | 301 | static void wm8903_seq_notifier(struct snd_soc_dapm_context *dapm, |
359 | val &= ~(WM8903_OUTPUT_SHORT << shift); | 302 | enum snd_soc_dapm_type event, int subseq) |
360 | snd_soc_write(codec, reg, val); | 303 | { |
361 | } | 304 | struct snd_soc_codec *codec = container_of(dapm, |
305 | struct snd_soc_codec, dapm); | ||
306 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
307 | int dcs_mode = WM8903_DCS_MODE_WRITE_STOP; | ||
308 | int i, val; | ||
362 | 309 | ||
363 | if (event & SND_SOC_DAPM_POST_PMU) { | 310 | /* Complete any pending DC servo starts */ |
364 | val = snd_soc_read(codec, reg); | 311 | if (wm8903->dcs_pending) { |
312 | dev_dbg(codec->dev, "Starting DC servo for %x\n", | ||
313 | wm8903->dcs_pending); | ||
365 | 314 | ||
366 | val |= (WM8903_OUTPUT_IN << shift); | 315 | /* If we've no cached values then we need to do startup */ |
367 | snd_soc_write(codec, reg, val); | 316 | for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) { |
317 | if (!(wm8903->dcs_pending & (1 << i))) | ||
318 | continue; | ||
368 | 319 | ||
369 | val |= (WM8903_OUTPUT_INT << shift); | 320 | if (wm8903->dcs_cache[i]) { |
370 | snd_soc_write(codec, reg, val); | 321 | dev_dbg(codec->dev, |
322 | "Restore DC servo %d value %x\n", | ||
323 | 3 - i, wm8903->dcs_cache[i]); | ||
324 | |||
325 | snd_soc_write(codec, WM8903_DC_SERVO_4 + i, | ||
326 | wm8903->dcs_cache[i] & 0xff); | ||
327 | } else { | ||
328 | dev_dbg(codec->dev, | ||
329 | "Calibrate DC servo %d\n", 3 - i); | ||
330 | dcs_mode = WM8903_DCS_MODE_START_STOP; | ||
331 | } | ||
332 | } | ||
371 | 333 | ||
372 | /* Turn on the output ENA_OUTP */ | 334 | /* Don't trust the cache for analogue */ |
373 | val |= (WM8903_OUTPUT_OUT << shift); | 335 | if (wm8903->class_w_users) |
374 | snd_soc_write(codec, reg, val); | 336 | dcs_mode = WM8903_DCS_MODE_START_STOP; |
375 | 337 | ||
376 | /* Enable the DC servo */ | 338 | snd_soc_update_bits(codec, WM8903_DC_SERVO_2, |
377 | dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); | 339 | WM8903_DCS_MODE_MASK, dcs_mode); |
378 | dcs_reg |= dcs_bit; | ||
379 | snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); | ||
380 | 340 | ||
381 | /* Remove the short */ | 341 | snd_soc_update_bits(codec, WM8903_DC_SERVO_0, |
382 | val |= (WM8903_OUTPUT_SHORT << shift); | 342 | WM8903_DCS_ENA_MASK, wm8903->dcs_pending); |
383 | snd_soc_write(codec, reg, val); | ||
384 | } | ||
385 | 343 | ||
386 | if (event & SND_SOC_DAPM_PRE_PMD) { | 344 | switch (dcs_mode) { |
387 | val = snd_soc_read(codec, reg); | 345 | case WM8903_DCS_MODE_WRITE_STOP: |
346 | break; | ||
388 | 347 | ||
389 | /* Short the output */ | 348 | case WM8903_DCS_MODE_START_STOP: |
390 | val &= ~(WM8903_OUTPUT_SHORT << shift); | 349 | msleep(270); |
391 | snd_soc_write(codec, reg, val); | ||
392 | 350 | ||
393 | /* Disable the DC servo */ | 351 | /* Cache the measured offsets for digital */ |
394 | dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); | 352 | if (wm8903->class_w_users) |
395 | dcs_reg &= ~dcs_bit; | 353 | break; |
396 | snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); | ||
397 | 354 | ||
398 | /* Then disable the intermediate and output stages */ | 355 | for (i = 0; i < ARRAY_SIZE(wm8903->dcs_cache); i++) { |
399 | val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | | 356 | if (!(wm8903->dcs_pending & (1 << i))) |
400 | WM8903_OUTPUT_IN) << shift); | 357 | continue; |
401 | snd_soc_write(codec, reg, val); | ||
402 | } | ||
403 | 358 | ||
404 | return 0; | 359 | val = snd_soc_read(codec, |
360 | WM8903_DC_SERVO_READBACK_1 + i); | ||
361 | dev_dbg(codec->dev, "DC servo %d: %x\n", | ||
362 | 3 - i, val); | ||
363 | wm8903->dcs_cache[i] = val; | ||
364 | } | ||
365 | break; | ||
366 | |||
367 | default: | ||
368 | pr_warn("DCS mode %d delay not set\n", dcs_mode); | ||
369 | break; | ||
370 | } | ||
371 | |||
372 | wm8903->dcs_pending = 0; | ||
373 | } | ||
405 | } | 374 | } |
406 | 375 | ||
407 | /* | 376 | /* |
@@ -667,6 +636,22 @@ static const struct soc_enum lsidetone_enum = | |||
667 | static const struct soc_enum rsidetone_enum = | 636 | static const struct soc_enum rsidetone_enum = |
668 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); | 637 | SOC_ENUM_SINGLE(WM8903_DAC_DIGITAL_0, 0, 3, sidetone_text); |
669 | 638 | ||
639 | static const char *aif_text[] = { | ||
640 | "Left", "Right" | ||
641 | }; | ||
642 | |||
643 | static const struct soc_enum lcapture_enum = | ||
644 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 7, 2, aif_text); | ||
645 | |||
646 | static const struct soc_enum rcapture_enum = | ||
647 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 6, 2, aif_text); | ||
648 | |||
649 | static const struct soc_enum lplay_enum = | ||
650 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 5, 2, aif_text); | ||
651 | |||
652 | static const struct soc_enum rplay_enum = | ||
653 | SOC_ENUM_SINGLE(WM8903_AUDIO_INTERFACE_0, 4, 2, aif_text); | ||
654 | |||
670 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { | 655 | static const struct snd_kcontrol_new wm8903_snd_controls[] = { |
671 | 656 | ||
672 | /* Input PGAs - No TLV since the scale depends on PGA mode */ | 657 | /* Input PGAs - No TLV since the scale depends on PGA mode */ |
@@ -784,6 +769,18 @@ static const struct snd_kcontrol_new lsidetone_mux = | |||
784 | static const struct snd_kcontrol_new rsidetone_mux = | 769 | static const struct snd_kcontrol_new rsidetone_mux = |
785 | SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum); | 770 | SOC_DAPM_ENUM("DACR Sidetone Mux", rsidetone_enum); |
786 | 771 | ||
772 | static const struct snd_kcontrol_new lcapture_mux = | ||
773 | SOC_DAPM_ENUM("Left Capture Mux", lcapture_enum); | ||
774 | |||
775 | static const struct snd_kcontrol_new rcapture_mux = | ||
776 | SOC_DAPM_ENUM("Right Capture Mux", rcapture_enum); | ||
777 | |||
778 | static const struct snd_kcontrol_new lplay_mux = | ||
779 | SOC_DAPM_ENUM("Left Playback Mux", lplay_enum); | ||
780 | |||
781 | static const struct snd_kcontrol_new rplay_mux = | ||
782 | SOC_DAPM_ENUM("Right Playback Mux", rplay_enum); | ||
783 | |||
787 | static const struct snd_kcontrol_new left_output_mixer[] = { | 784 | static const struct snd_kcontrol_new left_output_mixer[] = { |
788 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), | 785 | SOC_DAPM_SINGLE("DACL Switch", WM8903_ANALOGUE_LEFT_MIX_0, 3, 1, 0), |
789 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), | 786 | SOC_DAPM_SINGLE("DACR Switch", WM8903_ANALOGUE_LEFT_MIX_0, 2, 1, 0), |
@@ -847,14 +844,26 @@ SND_SOC_DAPM_MUX("Right Input Mode Mux", SND_SOC_NOPM, 0, 0, &rinput_mode_mux), | |||
847 | SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0), | 844 | SND_SOC_DAPM_PGA("Left Input PGA", WM8903_POWER_MANAGEMENT_0, 1, 0, NULL, 0), |
848 | SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), | 845 | SND_SOC_DAPM_PGA("Right Input PGA", WM8903_POWER_MANAGEMENT_0, 0, 0, NULL, 0), |
849 | 846 | ||
850 | SND_SOC_DAPM_ADC("ADCL", "Left HiFi Capture", WM8903_POWER_MANAGEMENT_6, 1, 0), | 847 | SND_SOC_DAPM_ADC("ADCL", NULL, WM8903_POWER_MANAGEMENT_6, 1, 0), |
851 | SND_SOC_DAPM_ADC("ADCR", "Right HiFi Capture", WM8903_POWER_MANAGEMENT_6, 0, 0), | 848 | SND_SOC_DAPM_ADC("ADCR", NULL, WM8903_POWER_MANAGEMENT_6, 0, 0), |
849 | |||
850 | SND_SOC_DAPM_MUX("Left Capture Mux", SND_SOC_NOPM, 0, 0, &lcapture_mux), | ||
851 | SND_SOC_DAPM_MUX("Right Capture Mux", SND_SOC_NOPM, 0, 0, &rcapture_mux), | ||
852 | |||
853 | SND_SOC_DAPM_AIF_OUT("AIFTXL", "Left HiFi Capture", 0, SND_SOC_NOPM, 0, 0), | ||
854 | SND_SOC_DAPM_AIF_OUT("AIFTXR", "Right HiFi Capture", 0, SND_SOC_NOPM, 0, 0), | ||
852 | 855 | ||
853 | SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux), | 856 | SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &lsidetone_mux), |
854 | SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux), | 857 | SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &rsidetone_mux), |
855 | 858 | ||
856 | SND_SOC_DAPM_DAC("DACL", "Left Playback", WM8903_POWER_MANAGEMENT_6, 3, 0), | 859 | SND_SOC_DAPM_AIF_IN("AIFRXL", "Left Playback", 0, SND_SOC_NOPM, 0, 0), |
857 | SND_SOC_DAPM_DAC("DACR", "Right Playback", WM8903_POWER_MANAGEMENT_6, 2, 0), | 860 | SND_SOC_DAPM_AIF_IN("AIFRXR", "Right Playback", 0, SND_SOC_NOPM, 0, 0), |
861 | |||
862 | SND_SOC_DAPM_MUX("Left Playback Mux", SND_SOC_NOPM, 0, 0, &lplay_mux), | ||
863 | SND_SOC_DAPM_MUX("Right Playback Mux", SND_SOC_NOPM, 0, 0, &rplay_mux), | ||
864 | |||
865 | SND_SOC_DAPM_DAC("DACL", NULL, WM8903_POWER_MANAGEMENT_6, 3, 0), | ||
866 | SND_SOC_DAPM_DAC("DACR", NULL, WM8903_POWER_MANAGEMENT_6, 2, 0), | ||
858 | 867 | ||
859 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0, | 868 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8903_POWER_MANAGEMENT_1, 1, 0, |
860 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), | 869 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), |
@@ -866,23 +875,45 @@ SND_SOC_DAPM_MIXER("Left Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 1, 0, | |||
866 | SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, | 875 | SND_SOC_DAPM_MIXER("Right Speaker Mixer", WM8903_POWER_MANAGEMENT_4, 0, 0, |
867 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), | 876 | right_speaker_mixer, ARRAY_SIZE(right_speaker_mixer)), |
868 | 877 | ||
869 | SND_SOC_DAPM_PGA_E("Left Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | 878 | SND_SOC_DAPM_PGA_S("Left Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, |
870 | 1, 0, NULL, 0, wm8903_output_event, | 879 | 4, 0, NULL, 0), |
871 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | 880 | SND_SOC_DAPM_PGA_S("Right Headphone Output PGA", 0, WM8903_ANALOGUE_HP_0, |
872 | SND_SOC_DAPM_PRE_PMD), | 881 | 0, 0, NULL, 0), |
873 | SND_SOC_DAPM_PGA_E("Right Headphone Output PGA", WM8903_POWER_MANAGEMENT_2, | 882 | |
874 | 0, 0, NULL, 0, wm8903_output_event, | 883 | SND_SOC_DAPM_PGA_S("Left Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 4, 0, |
875 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | 884 | NULL, 0), |
876 | SND_SOC_DAPM_PRE_PMD), | 885 | SND_SOC_DAPM_PGA_S("Right Line Output PGA", 0, WM8903_ANALOGUE_LINEOUT_0, 0, 0, |
877 | 886 | NULL, 0), | |
878 | SND_SOC_DAPM_PGA_E("Left Line Output PGA", WM8903_POWER_MANAGEMENT_3, 1, 0, | 887 | |
879 | NULL, 0, wm8903_output_event, | 888 | SND_SOC_DAPM_PGA_S("HPL_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 7, 0, NULL, 0), |
880 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | 889 | SND_SOC_DAPM_PGA_S("HPL_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 6, 0, NULL, 0), |
881 | SND_SOC_DAPM_PRE_PMD), | 890 | SND_SOC_DAPM_PGA_S("HPL_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 5, 0, NULL, 0), |
882 | SND_SOC_DAPM_PGA_E("Right Line Output PGA", WM8903_POWER_MANAGEMENT_3, 0, 0, | 891 | SND_SOC_DAPM_PGA_S("HPR_RMV_SHORT", 4, WM8903_ANALOGUE_HP_0, 3, 0, NULL, 0), |
883 | NULL, 0, wm8903_output_event, | 892 | SND_SOC_DAPM_PGA_S("HPR_ENA_OUTP", 3, WM8903_ANALOGUE_HP_0, 2, 0, NULL, 0), |
884 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU | | 893 | SND_SOC_DAPM_PGA_S("HPR_ENA_DLY", 1, WM8903_ANALOGUE_HP_0, 1, 0, NULL, 0), |
885 | SND_SOC_DAPM_PRE_PMD), | 894 | |
895 | SND_SOC_DAPM_PGA_S("LINEOUTL_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 7, 0, | ||
896 | NULL, 0), | ||
897 | SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 6, 0, | ||
898 | NULL, 0), | ||
899 | SND_SOC_DAPM_PGA_S("LINEOUTL_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 5, 0, | ||
900 | NULL, 0), | ||
901 | SND_SOC_DAPM_PGA_S("LINEOUTR_RMV_SHORT", 4, WM8903_ANALOGUE_LINEOUT_0, 3, 0, | ||
902 | NULL, 0), | ||
903 | SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_OUTP", 3, WM8903_ANALOGUE_LINEOUT_0, 2, 0, | ||
904 | NULL, 0), | ||
905 | SND_SOC_DAPM_PGA_S("LINEOUTR_ENA_DLY", 1, WM8903_ANALOGUE_LINEOUT_0, 1, 0, | ||
906 | NULL, 0), | ||
907 | |||
908 | SND_SOC_DAPM_SUPPLY("DCS Master", WM8903_DC_SERVO_0, 4, 0, NULL, 0), | ||
909 | SND_SOC_DAPM_PGA_S("HPL_DCS", 3, SND_SOC_NOPM, 3, 0, wm8903_dcs_event, | ||
910 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
911 | SND_SOC_DAPM_PGA_S("HPR_DCS", 3, SND_SOC_NOPM, 2, 0, wm8903_dcs_event, | ||
912 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
913 | SND_SOC_DAPM_PGA_S("LINEOUTL_DCS", 3, SND_SOC_NOPM, 1, 0, wm8903_dcs_event, | ||
914 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
915 | SND_SOC_DAPM_PGA_S("LINEOUTR_DCS", 3, SND_SOC_NOPM, 0, 0, wm8903_dcs_event, | ||
916 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
886 | 917 | ||
887 | SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, | 918 | SND_SOC_DAPM_PGA("Left Speaker PGA", WM8903_POWER_MANAGEMENT_5, 1, 0, |
888 | NULL, 0), | 919 | NULL, 0), |
@@ -892,10 +923,18 @@ SND_SOC_DAPM_PGA("Right Speaker PGA", WM8903_POWER_MANAGEMENT_5, 0, 0, | |||
892 | SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0, | 923 | SND_SOC_DAPM_SUPPLY("Charge Pump", WM8903_CHARGE_PUMP_0, 0, 0, |
893 | wm8903_cp_event, SND_SOC_DAPM_POST_PMU), | 924 | wm8903_cp_event, SND_SOC_DAPM_POST_PMU), |
894 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0), | 925 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8903_CLOCK_RATES_2, 1, 0, NULL, 0), |
926 | SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8903_CLOCK_RATES_2, 2, 0, NULL, 0), | ||
895 | }; | 927 | }; |
896 | 928 | ||
897 | static const struct snd_soc_dapm_route intercon[] = { | 929 | static const struct snd_soc_dapm_route intercon[] = { |
898 | 930 | ||
931 | { "CLK_DSP", NULL, "CLK_SYS" }, | ||
932 | { "Mic Bias", NULL, "CLK_SYS" }, | ||
933 | { "HPL_DCS", NULL, "CLK_SYS" }, | ||
934 | { "HPR_DCS", NULL, "CLK_SYS" }, | ||
935 | { "LINEOUTL_DCS", NULL, "CLK_SYS" }, | ||
936 | { "LINEOUTR_DCS", NULL, "CLK_SYS" }, | ||
937 | |||
899 | { "Left Input Mux", "IN1L", "IN1L" }, | 938 | { "Left Input Mux", "IN1L", "IN1L" }, |
900 | { "Left Input Mux", "IN2L", "IN2L" }, | 939 | { "Left Input Mux", "IN2L", "IN2L" }, |
901 | { "Left Input Mux", "IN3L", "IN3L" }, | 940 | { "Left Input Mux", "IN3L", "IN3L" }, |
@@ -936,18 +975,36 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
936 | { "Left Input PGA", NULL, "Left Input Mode Mux" }, | 975 | { "Left Input PGA", NULL, "Left Input Mode Mux" }, |
937 | { "Right Input PGA", NULL, "Right Input Mode Mux" }, | 976 | { "Right Input PGA", NULL, "Right Input Mode Mux" }, |
938 | 977 | ||
978 | { "Left Capture Mux", "Left", "ADCL" }, | ||
979 | { "Left Capture Mux", "Right", "ADCR" }, | ||
980 | |||
981 | { "Right Capture Mux", "Left", "ADCL" }, | ||
982 | { "Right Capture Mux", "Right", "ADCR" }, | ||
983 | |||
984 | { "AIFTXL", NULL, "Left Capture Mux" }, | ||
985 | { "AIFTXR", NULL, "Right Capture Mux" }, | ||
986 | |||
939 | { "ADCL", NULL, "Left Input PGA" }, | 987 | { "ADCL", NULL, "Left Input PGA" }, |
940 | { "ADCL", NULL, "CLK_DSP" }, | 988 | { "ADCL", NULL, "CLK_DSP" }, |
941 | { "ADCR", NULL, "Right Input PGA" }, | 989 | { "ADCR", NULL, "Right Input PGA" }, |
942 | { "ADCR", NULL, "CLK_DSP" }, | 990 | { "ADCR", NULL, "CLK_DSP" }, |
943 | 991 | ||
992 | { "Left Playback Mux", "Left", "AIFRXL" }, | ||
993 | { "Left Playback Mux", "Right", "AIFRXR" }, | ||
994 | |||
995 | { "Right Playback Mux", "Left", "AIFRXL" }, | ||
996 | { "Right Playback Mux", "Right", "AIFRXR" }, | ||
997 | |||
944 | { "DACL Sidetone", "Left", "ADCL" }, | 998 | { "DACL Sidetone", "Left", "ADCL" }, |
945 | { "DACL Sidetone", "Right", "ADCR" }, | 999 | { "DACL Sidetone", "Right", "ADCR" }, |
946 | { "DACR Sidetone", "Left", "ADCL" }, | 1000 | { "DACR Sidetone", "Left", "ADCL" }, |
947 | { "DACR Sidetone", "Right", "ADCR" }, | 1001 | { "DACR Sidetone", "Right", "ADCR" }, |
948 | 1002 | ||
1003 | { "DACL", NULL, "Left Playback Mux" }, | ||
949 | { "DACL", NULL, "DACL Sidetone" }, | 1004 | { "DACL", NULL, "DACL Sidetone" }, |
950 | { "DACL", NULL, "CLK_DSP" }, | 1005 | { "DACL", NULL, "CLK_DSP" }, |
1006 | |||
1007 | { "DACR", NULL, "Right Playback Mux" }, | ||
951 | { "DACR", NULL, "DACR Sidetone" }, | 1008 | { "DACR", NULL, "DACR Sidetone" }, |
952 | { "DACR", NULL, "CLK_DSP" }, | 1009 | { "DACR", NULL, "CLK_DSP" }, |
953 | 1010 | ||
@@ -980,11 +1037,35 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
980 | { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, | 1037 | { "Left Speaker PGA", NULL, "Left Speaker Mixer" }, |
981 | { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, | 1038 | { "Right Speaker PGA", NULL, "Right Speaker Mixer" }, |
982 | 1039 | ||
983 | { "HPOUTL", NULL, "Left Headphone Output PGA" }, | 1040 | { "HPL_ENA_DLY", NULL, "Left Headphone Output PGA" }, |
984 | { "HPOUTR", NULL, "Right Headphone Output PGA" }, | 1041 | { "HPR_ENA_DLY", NULL, "Right Headphone Output PGA" }, |
1042 | { "LINEOUTL_ENA_DLY", NULL, "Left Line Output PGA" }, | ||
1043 | { "LINEOUTR_ENA_DLY", NULL, "Right Line Output PGA" }, | ||
1044 | |||
1045 | { "HPL_DCS", NULL, "DCS Master" }, | ||
1046 | { "HPR_DCS", NULL, "DCS Master" }, | ||
1047 | { "LINEOUTL_DCS", NULL, "DCS Master" }, | ||
1048 | { "LINEOUTR_DCS", NULL, "DCS Master" }, | ||
1049 | |||
1050 | { "HPL_DCS", NULL, "HPL_ENA_DLY" }, | ||
1051 | { "HPR_DCS", NULL, "HPR_ENA_DLY" }, | ||
1052 | { "LINEOUTL_DCS", NULL, "LINEOUTL_ENA_DLY" }, | ||
1053 | { "LINEOUTR_DCS", NULL, "LINEOUTR_ENA_DLY" }, | ||
985 | 1054 | ||
986 | { "LINEOUTL", NULL, "Left Line Output PGA" }, | 1055 | { "HPL_ENA_OUTP", NULL, "HPL_DCS" }, |
987 | { "LINEOUTR", NULL, "Right Line Output PGA" }, | 1056 | { "HPR_ENA_OUTP", NULL, "HPR_DCS" }, |
1057 | { "LINEOUTL_ENA_OUTP", NULL, "LINEOUTL_DCS" }, | ||
1058 | { "LINEOUTR_ENA_OUTP", NULL, "LINEOUTR_DCS" }, | ||
1059 | |||
1060 | { "HPL_RMV_SHORT", NULL, "HPL_ENA_OUTP" }, | ||
1061 | { "HPR_RMV_SHORT", NULL, "HPR_ENA_OUTP" }, | ||
1062 | { "LINEOUTL_RMV_SHORT", NULL, "LINEOUTL_ENA_OUTP" }, | ||
1063 | { "LINEOUTR_RMV_SHORT", NULL, "LINEOUTR_ENA_OUTP" }, | ||
1064 | |||
1065 | { "HPOUTL", NULL, "HPL_RMV_SHORT" }, | ||
1066 | { "HPOUTR", NULL, "HPR_RMV_SHORT" }, | ||
1067 | { "LINEOUTL", NULL, "LINEOUTL_RMV_SHORT" }, | ||
1068 | { "LINEOUTR", NULL, "LINEOUTR_RMV_SHORT" }, | ||
988 | 1069 | ||
989 | { "LOP", NULL, "Left Speaker PGA" }, | 1070 | { "LOP", NULL, "Left Speaker PGA" }, |
990 | { "LON", NULL, "Left Speaker PGA" }, | 1071 | { "LON", NULL, "Left Speaker PGA" }, |
@@ -1012,29 +1093,71 @@ static int wm8903_add_widgets(struct snd_soc_codec *codec) | |||
1012 | static int wm8903_set_bias_level(struct snd_soc_codec *codec, | 1093 | static int wm8903_set_bias_level(struct snd_soc_codec *codec, |
1013 | enum snd_soc_bias_level level) | 1094 | enum snd_soc_bias_level level) |
1014 | { | 1095 | { |
1015 | u16 reg; | ||
1016 | |||
1017 | switch (level) { | 1096 | switch (level) { |
1018 | case SND_SOC_BIAS_ON: | 1097 | case SND_SOC_BIAS_ON: |
1098 | break; | ||
1099 | |||
1019 | case SND_SOC_BIAS_PREPARE: | 1100 | case SND_SOC_BIAS_PREPARE: |
1020 | reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); | 1101 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, |
1021 | reg &= ~(WM8903_VMID_RES_MASK); | 1102 | WM8903_VMID_RES_MASK, |
1022 | reg |= WM8903_VMID_RES_50K; | 1103 | WM8903_VMID_RES_50K); |
1023 | snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
1024 | break; | 1104 | break; |
1025 | 1105 | ||
1026 | case SND_SOC_BIAS_STANDBY: | 1106 | case SND_SOC_BIAS_STANDBY: |
1027 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1107 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
1028 | snd_soc_write(codec, WM8903_CLOCK_RATES_2, | 1108 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, |
1029 | WM8903_CLK_SYS_ENA); | 1109 | WM8903_POBCTRL | WM8903_ISEL_MASK | |
1030 | 1110 | WM8903_STARTUP_BIAS_ENA | | |
1031 | /* Change DC servo dither level in startup sequence */ | 1111 | WM8903_BIAS_ENA, |
1032 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); | 1112 | WM8903_POBCTRL | |
1033 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); | 1113 | (2 << WM8903_ISEL_SHIFT) | |
1034 | snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); | 1114 | WM8903_STARTUP_BIAS_ENA); |
1035 | 1115 | ||
1036 | wm8903_run_sequence(codec, 0); | 1116 | snd_soc_update_bits(codec, |
1037 | wm8903_sync_reg_cache(codec, codec->reg_cache); | 1117 | WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0, |
1118 | WM8903_SPK_DISCHARGE, | ||
1119 | WM8903_SPK_DISCHARGE); | ||
1120 | |||
1121 | msleep(33); | ||
1122 | |||
1123 | snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5, | ||
1124 | WM8903_SPKL_ENA | WM8903_SPKR_ENA, | ||
1125 | WM8903_SPKL_ENA | WM8903_SPKR_ENA); | ||
1126 | |||
1127 | snd_soc_update_bits(codec, | ||
1128 | WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0, | ||
1129 | WM8903_SPK_DISCHARGE, 0); | ||
1130 | |||
1131 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, | ||
1132 | WM8903_VMID_TIE_ENA | | ||
1133 | WM8903_BUFIO_ENA | | ||
1134 | WM8903_VMID_IO_ENA | | ||
1135 | WM8903_VMID_SOFT_MASK | | ||
1136 | WM8903_VMID_RES_MASK | | ||
1137 | WM8903_VMID_BUF_ENA, | ||
1138 | WM8903_VMID_TIE_ENA | | ||
1139 | WM8903_BUFIO_ENA | | ||
1140 | WM8903_VMID_IO_ENA | | ||
1141 | (2 << WM8903_VMID_SOFT_SHIFT) | | ||
1142 | WM8903_VMID_RES_250K | | ||
1143 | WM8903_VMID_BUF_ENA); | ||
1144 | |||
1145 | msleep(129); | ||
1146 | |||
1147 | snd_soc_update_bits(codec, WM8903_POWER_MANAGEMENT_5, | ||
1148 | WM8903_SPKL_ENA | WM8903_SPKR_ENA, | ||
1149 | 0); | ||
1150 | |||
1151 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, | ||
1152 | WM8903_VMID_SOFT_MASK, 0); | ||
1153 | |||
1154 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, | ||
1155 | WM8903_VMID_RES_MASK, | ||
1156 | WM8903_VMID_RES_50K); | ||
1157 | |||
1158 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, | ||
1159 | WM8903_BIAS_ENA | WM8903_POBCTRL, | ||
1160 | WM8903_BIAS_ENA); | ||
1038 | 1161 | ||
1039 | /* By default no bypass paths are enabled so | 1162 | /* By default no bypass paths are enabled so |
1040 | * enable Class W support. | 1163 | * enable Class W support. |
@@ -1047,17 +1170,32 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, | |||
1047 | WM8903_CP_DYN_V); | 1170 | WM8903_CP_DYN_V); |
1048 | } | 1171 | } |
1049 | 1172 | ||
1050 | reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); | 1173 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, |
1051 | reg &= ~(WM8903_VMID_RES_MASK); | 1174 | WM8903_VMID_RES_MASK, |
1052 | reg |= WM8903_VMID_RES_250K; | 1175 | WM8903_VMID_RES_250K); |
1053 | snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); | ||
1054 | break; | 1176 | break; |
1055 | 1177 | ||
1056 | case SND_SOC_BIAS_OFF: | 1178 | case SND_SOC_BIAS_OFF: |
1057 | wm8903_run_sequence(codec, 32); | 1179 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, |
1058 | reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2); | 1180 | WM8903_BIAS_ENA, 0); |
1059 | reg &= ~WM8903_CLK_SYS_ENA; | 1181 | |
1060 | snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg); | 1182 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, |
1183 | WM8903_VMID_SOFT_MASK, | ||
1184 | 2 << WM8903_VMID_SOFT_SHIFT); | ||
1185 | |||
1186 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, | ||
1187 | WM8903_VMID_BUF_ENA, 0); | ||
1188 | |||
1189 | msleep(290); | ||
1190 | |||
1191 | snd_soc_update_bits(codec, WM8903_VMID_CONTROL_0, | ||
1192 | WM8903_VMID_TIE_ENA | WM8903_BUFIO_ENA | | ||
1193 | WM8903_VMID_IO_ENA | WM8903_VMID_RES_MASK | | ||
1194 | WM8903_VMID_SOFT_MASK | | ||
1195 | WM8903_VMID_BUF_ENA, 0); | ||
1196 | |||
1197 | snd_soc_update_bits(codec, WM8903_BIAS_CONTROL_0, | ||
1198 | WM8903_STARTUP_BIAS_ENA, 0); | ||
1061 | break; | 1199 | break; |
1062 | } | 1200 | } |
1063 | 1201 | ||
@@ -1510,8 +1648,7 @@ static irqreturn_t wm8903_irq(int irq, void *data) | |||
1510 | int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask; | 1648 | int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask; |
1511 | 1649 | ||
1512 | if (int_val & WM8903_WSEQ_BUSY_EINT) { | 1650 | if (int_val & WM8903_WSEQ_BUSY_EINT) { |
1513 | dev_dbg(codec->dev, "Write sequencer done\n"); | 1651 | dev_warn(codec->dev, "Write sequencer done\n"); |
1514 | complete(&wm8903->wseq); | ||
1515 | } | 1652 | } |
1516 | 1653 | ||
1517 | /* | 1654 | /* |
@@ -1635,6 +1772,120 @@ static int wm8903_resume(struct snd_soc_codec *codec) | |||
1635 | return 0; | 1772 | return 0; |
1636 | } | 1773 | } |
1637 | 1774 | ||
1775 | #ifdef CONFIG_GPIOLIB | ||
1776 | static inline struct wm8903_priv *gpio_to_wm8903(struct gpio_chip *chip) | ||
1777 | { | ||
1778 | return container_of(chip, struct wm8903_priv, gpio_chip); | ||
1779 | } | ||
1780 | |||
1781 | static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) | ||
1782 | { | ||
1783 | if (offset >= WM8903_NUM_GPIO) | ||
1784 | return -EINVAL; | ||
1785 | |||
1786 | return 0; | ||
1787 | } | ||
1788 | |||
1789 | static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | ||
1790 | { | ||
1791 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1792 | struct snd_soc_codec *codec = wm8903->codec; | ||
1793 | unsigned int mask, val; | ||
1794 | |||
1795 | mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK; | ||
1796 | val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | | ||
1797 | WM8903_GP1_DIR; | ||
1798 | |||
1799 | return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1800 | mask, val); | ||
1801 | } | ||
1802 | |||
1803 | static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
1804 | { | ||
1805 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1806 | struct snd_soc_codec *codec = wm8903->codec; | ||
1807 | int reg; | ||
1808 | |||
1809 | reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset); | ||
1810 | |||
1811 | return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; | ||
1812 | } | ||
1813 | |||
1814 | static int wm8903_gpio_direction_out(struct gpio_chip *chip, | ||
1815 | unsigned offset, int value) | ||
1816 | { | ||
1817 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1818 | struct snd_soc_codec *codec = wm8903->codec; | ||
1819 | unsigned int mask, val; | ||
1820 | |||
1821 | mask = WM8903_GP1_FN_MASK | WM8903_GP1_DIR_MASK | WM8903_GP1_LVL_MASK; | ||
1822 | val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | | ||
1823 | (value << WM8903_GP2_LVL_SHIFT); | ||
1824 | |||
1825 | return snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1826 | mask, val); | ||
1827 | } | ||
1828 | |||
1829 | static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
1830 | { | ||
1831 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | ||
1832 | struct snd_soc_codec *codec = wm8903->codec; | ||
1833 | |||
1834 | snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | ||
1835 | WM8903_GP1_LVL_MASK, | ||
1836 | !!value << WM8903_GP1_LVL_SHIFT); | ||
1837 | } | ||
1838 | |||
1839 | static struct gpio_chip wm8903_template_chip = { | ||
1840 | .label = "wm8903", | ||
1841 | .owner = THIS_MODULE, | ||
1842 | .request = wm8903_gpio_request, | ||
1843 | .direction_input = wm8903_gpio_direction_in, | ||
1844 | .get = wm8903_gpio_get, | ||
1845 | .direction_output = wm8903_gpio_direction_out, | ||
1846 | .set = wm8903_gpio_set, | ||
1847 | .can_sleep = 1, | ||
1848 | }; | ||
1849 | |||
1850 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | ||
1851 | { | ||
1852 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1853 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); | ||
1854 | int ret; | ||
1855 | |||
1856 | wm8903->gpio_chip = wm8903_template_chip; | ||
1857 | wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; | ||
1858 | wm8903->gpio_chip.dev = codec->dev; | ||
1859 | |||
1860 | if (pdata && pdata->gpio_base) | ||
1861 | wm8903->gpio_chip.base = pdata->gpio_base; | ||
1862 | else | ||
1863 | wm8903->gpio_chip.base = -1; | ||
1864 | |||
1865 | ret = gpiochip_add(&wm8903->gpio_chip); | ||
1866 | if (ret != 0) | ||
1867 | dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); | ||
1868 | } | ||
1869 | |||
1870 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | ||
1871 | { | ||
1872 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1873 | int ret; | ||
1874 | |||
1875 | ret = gpiochip_remove(&wm8903->gpio_chip); | ||
1876 | if (ret != 0) | ||
1877 | dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); | ||
1878 | } | ||
1879 | #else | ||
1880 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | ||
1881 | { | ||
1882 | } | ||
1883 | |||
1884 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | ||
1885 | { | ||
1886 | } | ||
1887 | #endif | ||
1888 | |||
1638 | static int wm8903_probe(struct snd_soc_codec *codec) | 1889 | static int wm8903_probe(struct snd_soc_codec *codec) |
1639 | { | 1890 | { |
1640 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); | 1891 | struct wm8903_platform_data *pdata = dev_get_platdata(codec->dev); |
@@ -1643,7 +1894,7 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1643 | int trigger, irq_pol; | 1894 | int trigger, irq_pol; |
1644 | u16 val; | 1895 | u16 val; |
1645 | 1896 | ||
1646 | init_completion(&wm8903->wseq); | 1897 | wm8903->codec = codec; |
1647 | 1898 | ||
1648 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); | 1899 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); |
1649 | if (ret != 0) { | 1900 | if (ret != 0) { |
@@ -1659,19 +1910,33 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1659 | } | 1910 | } |
1660 | 1911 | ||
1661 | val = snd_soc_read(codec, WM8903_REVISION_NUMBER); | 1912 | val = snd_soc_read(codec, WM8903_REVISION_NUMBER); |
1662 | dev_info(codec->dev, "WM8903 revision %d\n", | 1913 | dev_info(codec->dev, "WM8903 revision %c\n", |
1663 | val & WM8903_CHIP_REV_MASK); | 1914 | (val & WM8903_CHIP_REV_MASK) + 'A'); |
1664 | 1915 | ||
1665 | wm8903_reset(codec); | 1916 | wm8903_reset(codec); |
1666 | 1917 | ||
1667 | /* Set up GPIOs and microphone detection */ | 1918 | /* Set up GPIOs and microphone detection */ |
1668 | if (pdata) { | 1919 | if (pdata) { |
1920 | bool mic_gpio = false; | ||
1921 | |||
1669 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { | 1922 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { |
1670 | if (!pdata->gpio_cfg[i]) | 1923 | if (pdata->gpio_cfg[i] == WM8903_GPIO_NO_CONFIG) |
1671 | continue; | 1924 | continue; |
1672 | 1925 | ||
1673 | snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, | 1926 | snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, |
1674 | pdata->gpio_cfg[i] & 0xffff); | 1927 | pdata->gpio_cfg[i] & 0xffff); |
1928 | |||
1929 | val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK) | ||
1930 | >> WM8903_GP1_FN_SHIFT; | ||
1931 | |||
1932 | switch (val) { | ||
1933 | case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT: | ||
1934 | case WM8903_GPn_FN_MICBIAS_SHORT_DETECT: | ||
1935 | mic_gpio = true; | ||
1936 | break; | ||
1937 | default: | ||
1938 | break; | ||
1939 | } | ||
1675 | } | 1940 | } |
1676 | 1941 | ||
1677 | snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, | 1942 | snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, |
@@ -1682,6 +1947,14 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1682 | snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0, | 1947 | snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0, |
1683 | WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); | 1948 | WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); |
1684 | 1949 | ||
1950 | /* If microphone detection is enabled by pdata but | ||
1951 | * detected via IRQ then interrupts can be lost before | ||
1952 | * the machine driver has set up microphone detection | ||
1953 | * IRQs as the IRQs are clear on read. The detection | ||
1954 | * will be enabled when the machine driver configures. | ||
1955 | */ | ||
1956 | WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA)); | ||
1957 | |||
1685 | wm8903->mic_delay = pdata->micdet_delay; | 1958 | wm8903->mic_delay = pdata->micdet_delay; |
1686 | } | 1959 | } |
1687 | 1960 | ||
@@ -1741,20 +2014,23 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1741 | snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); | 2014 | snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); |
1742 | 2015 | ||
1743 | /* Enable DAC soft mute by default */ | 2016 | /* Enable DAC soft mute by default */ |
1744 | val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); | 2017 | snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1, |
1745 | val |= WM8903_DAC_MUTEMODE; | 2018 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE, |
1746 | snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val); | 2019 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE); |
1747 | 2020 | ||
1748 | snd_soc_add_controls(codec, wm8903_snd_controls, | 2021 | snd_soc_add_controls(codec, wm8903_snd_controls, |
1749 | ARRAY_SIZE(wm8903_snd_controls)); | 2022 | ARRAY_SIZE(wm8903_snd_controls)); |
1750 | wm8903_add_widgets(codec); | 2023 | wm8903_add_widgets(codec); |
1751 | 2024 | ||
2025 | wm8903_init_gpio(codec); | ||
2026 | |||
1752 | return ret; | 2027 | return ret; |
1753 | } | 2028 | } |
1754 | 2029 | ||
1755 | /* power down chip */ | 2030 | /* power down chip */ |
1756 | static int wm8903_remove(struct snd_soc_codec *codec) | 2031 | static int wm8903_remove(struct snd_soc_codec *codec) |
1757 | { | 2032 | { |
2033 | wm8903_free_gpio(codec); | ||
1758 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2034 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1759 | return 0; | 2035 | return 0; |
1760 | } | 2036 | } |
@@ -1769,6 +2045,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8903 = { | |||
1769 | .reg_word_size = sizeof(u16), | 2045 | .reg_word_size = sizeof(u16), |
1770 | .reg_cache_default = wm8903_reg_defaults, | 2046 | .reg_cache_default = wm8903_reg_defaults, |
1771 | .volatile_register = wm8903_volatile_register, | 2047 | .volatile_register = wm8903_volatile_register, |
2048 | .seq_notifier = wm8903_seq_notifier, | ||
1772 | }; | 2049 | }; |
1773 | 2050 | ||
1774 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 2051 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
@@ -1807,7 +2084,7 @@ MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id); | |||
1807 | 2084 | ||
1808 | static struct i2c_driver wm8903_i2c_driver = { | 2085 | static struct i2c_driver wm8903_i2c_driver = { |
1809 | .driver = { | 2086 | .driver = { |
1810 | .name = "wm8903-codec", | 2087 | .name = "wm8903", |
1811 | .owner = THIS_MODULE, | 2088 | .owner = THIS_MODULE, |
1812 | }, | 2089 | }, |
1813 | .probe = wm8903_i2c_probe, | 2090 | .probe = wm8903_i2c_probe, |
diff --git a/sound/soc/codecs/wm8903.h b/sound/soc/codecs/wm8903.h index e3ec2433b215..db949311c0f2 100644 --- a/sound/soc/codecs/wm8903.h +++ b/sound/soc/codecs/wm8903.h | |||
@@ -75,6 +75,14 @@ extern int wm8903_mic_detect(struct snd_soc_codec *codec, | |||
75 | #define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0 0x41 | 75 | #define WM8903_ANALOGUE_SPK_OUTPUT_CONTROL_0 0x41 |
76 | #define WM8903_DC_SERVO_0 0x43 | 76 | #define WM8903_DC_SERVO_0 0x43 |
77 | #define WM8903_DC_SERVO_2 0x45 | 77 | #define WM8903_DC_SERVO_2 0x45 |
78 | #define WM8903_DC_SERVO_4 0x47 | ||
79 | #define WM8903_DC_SERVO_5 0x48 | ||
80 | #define WM8903_DC_SERVO_6 0x49 | ||
81 | #define WM8903_DC_SERVO_7 0x4A | ||
82 | #define WM8903_DC_SERVO_READBACK_1 0x51 | ||
83 | #define WM8903_DC_SERVO_READBACK_2 0x52 | ||
84 | #define WM8903_DC_SERVO_READBACK_3 0x53 | ||
85 | #define WM8903_DC_SERVO_READBACK_4 0x54 | ||
78 | #define WM8903_ANALOGUE_HP_0 0x5A | 86 | #define WM8903_ANALOGUE_HP_0 0x5A |
79 | #define WM8903_ANALOGUE_LINEOUT_0 0x5E | 87 | #define WM8903_ANALOGUE_LINEOUT_0 0x5E |
80 | #define WM8903_CHARGE_PUMP_0 0x62 | 88 | #define WM8903_CHARGE_PUMP_0 0x62 |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 9de44a4c05c0..443ae580445c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -596,7 +596,7 @@ static struct { | |||
596 | { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ | 596 | { 0x003F, 0x003F, 0 }, /* R248 - FLL NCO Test 1 */ |
597 | }; | 597 | }; |
598 | 598 | ||
599 | static int wm8904_volatile_register(unsigned int reg) | 599 | static int wm8904_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
600 | { | 600 | { |
601 | return wm8904_access[reg].vol; | 601 | return wm8904_access[reg].vol; |
602 | } | 602 | } |
@@ -2436,19 +2436,28 @@ static int wm8904_probe(struct snd_soc_codec *codec) | |||
2436 | } | 2436 | } |
2437 | 2437 | ||
2438 | /* Change some default settings - latch VU and enable ZC */ | 2438 | /* Change some default settings - latch VU and enable ZC */ |
2439 | reg_cache[WM8904_ADC_DIGITAL_VOLUME_LEFT] |= WM8904_ADC_VU; | 2439 | snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT, |
2440 | reg_cache[WM8904_ADC_DIGITAL_VOLUME_RIGHT] |= WM8904_ADC_VU; | 2440 | WM8904_ADC_VU, WM8904_ADC_VU); |
2441 | reg_cache[WM8904_DAC_DIGITAL_VOLUME_LEFT] |= WM8904_DAC_VU; | 2441 | snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT, |
2442 | reg_cache[WM8904_DAC_DIGITAL_VOLUME_RIGHT] |= WM8904_DAC_VU; | 2442 | WM8904_ADC_VU, WM8904_ADC_VU); |
2443 | reg_cache[WM8904_ANALOGUE_OUT1_LEFT] |= WM8904_HPOUT_VU | | 2443 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT, |
2444 | WM8904_HPOUTLZC; | 2444 | WM8904_DAC_VU, WM8904_DAC_VU); |
2445 | reg_cache[WM8904_ANALOGUE_OUT1_RIGHT] |= WM8904_HPOUT_VU | | 2445 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT, |
2446 | WM8904_HPOUTRZC; | 2446 | WM8904_DAC_VU, WM8904_DAC_VU); |
2447 | reg_cache[WM8904_ANALOGUE_OUT2_LEFT] |= WM8904_LINEOUT_VU | | 2447 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT, |
2448 | WM8904_LINEOUTLZC; | 2448 | WM8904_HPOUT_VU | WM8904_HPOUTLZC, |
2449 | reg_cache[WM8904_ANALOGUE_OUT2_RIGHT] |= WM8904_LINEOUT_VU | | 2449 | WM8904_HPOUT_VU | WM8904_HPOUTLZC); |
2450 | WM8904_LINEOUTRZC; | 2450 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT, |
2451 | reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE; | 2451 | WM8904_HPOUT_VU | WM8904_HPOUTRZC, |
2452 | WM8904_HPOUT_VU | WM8904_HPOUTRZC); | ||
2453 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT, | ||
2454 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC, | ||
2455 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC); | ||
2456 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT, | ||
2457 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC, | ||
2458 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC); | ||
2459 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, | ||
2460 | WM8904_SR_MODE, 0); | ||
2452 | 2461 | ||
2453 | /* Apply configuration from the platform data. */ | 2462 | /* Apply configuration from the platform data. */ |
2454 | if (wm8904->pdata) { | 2463 | if (wm8904->pdata) { |
@@ -2469,10 +2478,12 @@ static int wm8904_probe(struct snd_soc_codec *codec) | |||
2469 | /* Set Class W by default - this will be managed by the Class | 2478 | /* Set Class W by default - this will be managed by the Class |
2470 | * G widget at runtime where bypass paths are available. | 2479 | * G widget at runtime where bypass paths are available. |
2471 | */ | 2480 | */ |
2472 | reg_cache[WM8904_CLASS_W_0] |= WM8904_CP_DYN_PWR; | 2481 | snd_soc_update_bits(codec, WM8904_CLASS_W_0, |
2482 | WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR); | ||
2473 | 2483 | ||
2474 | /* Use normal bias source */ | 2484 | /* Use normal bias source */ |
2475 | reg_cache[WM8904_BIAS_CONTROL_0] &= ~WM8904_POBCTRL; | 2485 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, |
2486 | WM8904_POBCTRL, 0); | ||
2476 | 2487 | ||
2477 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 2488 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
2478 | 2489 | ||
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 7167dfc96aa7..5e0214d6293e 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -934,16 +934,27 @@ static int wm8955_probe(struct snd_soc_codec *codec) | |||
934 | } | 934 | } |
935 | 935 | ||
936 | /* Change some default settings - latch VU and enable ZC */ | 936 | /* Change some default settings - latch VU and enable ZC */ |
937 | reg_cache[WM8955_LEFT_DAC_VOLUME] |= WM8955_LDVU; | 937 | snd_soc_update_bits(codec, WM8955_LEFT_DAC_VOLUME, |
938 | reg_cache[WM8955_RIGHT_DAC_VOLUME] |= WM8955_RDVU; | 938 | WM8955_LDVU, WM8955_LDVU); |
939 | reg_cache[WM8955_LOUT1_VOLUME] |= WM8955_LO1VU | WM8955_LO1ZC; | 939 | snd_soc_update_bits(codec, WM8955_RIGHT_DAC_VOLUME, |
940 | reg_cache[WM8955_ROUT1_VOLUME] |= WM8955_RO1VU | WM8955_RO1ZC; | 940 | WM8955_RDVU, WM8955_RDVU); |
941 | reg_cache[WM8955_LOUT2_VOLUME] |= WM8955_LO2VU | WM8955_LO2ZC; | 941 | snd_soc_update_bits(codec, WM8955_LOUT1_VOLUME, |
942 | reg_cache[WM8955_ROUT2_VOLUME] |= WM8955_RO2VU | WM8955_RO2ZC; | 942 | WM8955_LO1VU | WM8955_LO1ZC, |
943 | reg_cache[WM8955_MONOOUT_VOLUME] |= WM8955_MOZC; | 943 | WM8955_LO1VU | WM8955_LO1ZC); |
944 | snd_soc_update_bits(codec, WM8955_ROUT1_VOLUME, | ||
945 | WM8955_RO1VU | WM8955_RO1ZC, | ||
946 | WM8955_RO1VU | WM8955_RO1ZC); | ||
947 | snd_soc_update_bits(codec, WM8955_LOUT2_VOLUME, | ||
948 | WM8955_LO2VU | WM8955_LO2ZC, | ||
949 | WM8955_LO2VU | WM8955_LO2ZC); | ||
950 | snd_soc_update_bits(codec, WM8955_ROUT2_VOLUME, | ||
951 | WM8955_RO2VU | WM8955_RO2ZC, | ||
952 | WM8955_RO2VU | WM8955_RO2ZC); | ||
953 | snd_soc_update_bits(codec, WM8955_MONOOUT_VOLUME, | ||
954 | WM8955_MOZC, WM8955_MOZC); | ||
944 | 955 | ||
945 | /* Also enable adaptive bass boost by default */ | 956 | /* Also enable adaptive bass boost by default */ |
946 | reg_cache[WM8955_BASS_CONTROL] |= WM8955_BB; | 957 | snd_soc_update_bits(codec, WM8955_BASS_CONTROL, WM8955_BB, WM8955_BB); |
947 | 958 | ||
948 | /* Set platform data values */ | 959 | /* Set platform data values */ |
949 | if (pdata) { | 960 | if (pdata) { |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 55252e7d02c9..cdee8103d09b 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -291,7 +291,7 @@ struct wm8961_priv { | |||
291 | int sysclk; | 291 | int sysclk; |
292 | }; | 292 | }; |
293 | 293 | ||
294 | static int wm8961_volatile_register(unsigned int reg) | 294 | static int wm8961_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
295 | { | 295 | { |
296 | switch (reg) { | 296 | switch (reg) { |
297 | case WM8961_SOFTWARE_RESET: | 297 | case WM8961_SOFTWARE_RESET: |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index b9cb1fcf8c92..3b71dd65c966 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -1938,7 +1938,7 @@ static const struct wm8962_reg_access { | |||
1938 | [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */ | 1938 | [21139] = { 0xFFFF, 0xFFFF, 0x0000 }, /* R21139 - VSS_XTS32_0 */ |
1939 | }; | 1939 | }; |
1940 | 1940 | ||
1941 | static int wm8962_volatile_register(unsigned int reg) | 1941 | static int wm8962_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
1942 | { | 1942 | { |
1943 | if (wm8962_reg_access[reg].vol) | 1943 | if (wm8962_reg_access[reg].vol) |
1944 | return 1; | 1944 | return 1; |
@@ -1946,7 +1946,7 @@ static int wm8962_volatile_register(unsigned int reg) | |||
1946 | return 0; | 1946 | return 0; |
1947 | } | 1947 | } |
1948 | 1948 | ||
1949 | static int wm8962_readable_register(unsigned int reg) | 1949 | static int wm8962_readable_register(struct snd_soc_codec *codec, unsigned int reg) |
1950 | { | 1950 | { |
1951 | if (wm8962_reg_access[reg].read) | 1951 | if (wm8962_reg_access[reg].read) |
1952 | return 1; | 1952 | return 1; |
@@ -3635,7 +3635,7 @@ static void wm8962_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | |||
3635 | struct snd_soc_codec *codec = wm8962->codec; | 3635 | struct snd_soc_codec *codec = wm8962->codec; |
3636 | 3636 | ||
3637 | snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, | 3637 | snd_soc_update_bits(codec, WM8962_GPIO_BASE + offset, |
3638 | WM8962_GP2_LVL, value << WM8962_GP2_LVL_SHIFT); | 3638 | WM8962_GP2_LVL, !!value << WM8962_GP2_LVL_SHIFT); |
3639 | } | 3639 | } |
3640 | 3640 | ||
3641 | static int wm8962_gpio_direction_out(struct gpio_chip *chip, | 3641 | static int wm8962_gpio_direction_out(struct gpio_chip *chip, |
@@ -3822,16 +3822,26 @@ static int wm8962_probe(struct snd_soc_codec *codec) | |||
3822 | } | 3822 | } |
3823 | 3823 | ||
3824 | /* Latch volume update bits */ | 3824 | /* Latch volume update bits */ |
3825 | reg_cache[WM8962_LEFT_INPUT_VOLUME] |= WM8962_IN_VU; | 3825 | snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME, |
3826 | reg_cache[WM8962_RIGHT_INPUT_VOLUME] |= WM8962_IN_VU; | 3826 | WM8962_IN_VU, WM8962_IN_VU); |
3827 | reg_cache[WM8962_LEFT_ADC_VOLUME] |= WM8962_ADC_VU; | 3827 | snd_soc_update_bits(codec, WM8962_RIGHT_INPUT_VOLUME, |
3828 | reg_cache[WM8962_RIGHT_ADC_VOLUME] |= WM8962_ADC_VU; | 3828 | WM8962_IN_VU, WM8962_IN_VU); |
3829 | reg_cache[WM8962_LEFT_DAC_VOLUME] |= WM8962_DAC_VU; | 3829 | snd_soc_update_bits(codec, WM8962_LEFT_ADC_VOLUME, |
3830 | reg_cache[WM8962_RIGHT_DAC_VOLUME] |= WM8962_DAC_VU; | 3830 | WM8962_ADC_VU, WM8962_ADC_VU); |
3831 | reg_cache[WM8962_SPKOUTL_VOLUME] |= WM8962_SPKOUT_VU; | 3831 | snd_soc_update_bits(codec, WM8962_RIGHT_ADC_VOLUME, |
3832 | reg_cache[WM8962_SPKOUTR_VOLUME] |= WM8962_SPKOUT_VU; | 3832 | WM8962_ADC_VU, WM8962_ADC_VU); |
3833 | reg_cache[WM8962_HPOUTL_VOLUME] |= WM8962_HPOUT_VU; | 3833 | snd_soc_update_bits(codec, WM8962_LEFT_DAC_VOLUME, |
3834 | reg_cache[WM8962_HPOUTR_VOLUME] |= WM8962_HPOUT_VU; | 3834 | WM8962_DAC_VU, WM8962_DAC_VU); |
3835 | snd_soc_update_bits(codec, WM8962_RIGHT_DAC_VOLUME, | ||
3836 | WM8962_DAC_VU, WM8962_DAC_VU); | ||
3837 | snd_soc_update_bits(codec, WM8962_SPKOUTL_VOLUME, | ||
3838 | WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); | ||
3839 | snd_soc_update_bits(codec, WM8962_SPKOUTR_VOLUME, | ||
3840 | WM8962_SPKOUT_VU, WM8962_SPKOUT_VU); | ||
3841 | snd_soc_update_bits(codec, WM8962_HPOUTL_VOLUME, | ||
3842 | WM8962_HPOUT_VU, WM8962_HPOUT_VU); | ||
3843 | snd_soc_update_bits(codec, WM8962_HPOUTR_VOLUME, | ||
3844 | WM8962_HPOUT_VU, WM8962_HPOUT_VU); | ||
3835 | 3845 | ||
3836 | wm8962_add_widgets(codec); | 3846 | wm8962_add_widgets(codec); |
3837 | 3847 | ||
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 8dfb0a0da673..85e3e630e763 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -93,6 +93,7 @@ static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | |||
93 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); | 93 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, -1200, 75, 0); |
94 | static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); | 94 | static const DECLARE_TLV_DB_SCALE(spk_tlv, -5700, 100, 0); |
95 | static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); | 95 | static const DECLARE_TLV_DB_SCALE(boost_tlv, -1500, 300, 1); |
96 | static const DECLARE_TLV_DB_SCALE(limiter_tlv, 0, 100, 0); | ||
96 | 97 | ||
97 | static const struct snd_kcontrol_new wm8978_snd_controls[] = { | 98 | static const struct snd_kcontrol_new wm8978_snd_controls[] = { |
98 | 99 | ||
@@ -144,8 +145,8 @@ static const struct snd_kcontrol_new wm8978_snd_controls[] = { | |||
144 | 145 | ||
145 | SOC_SINGLE("DAC Playback Limiter Threshold", | 146 | SOC_SINGLE("DAC Playback Limiter Threshold", |
146 | WM8978_DAC_LIMITER_2, 4, 7, 0), | 147 | WM8978_DAC_LIMITER_2, 4, 7, 0), |
147 | SOC_SINGLE("DAC Playback Limiter Boost", | 148 | SOC_SINGLE_TLV("DAC Playback Limiter Volume", |
148 | WM8978_DAC_LIMITER_2, 0, 12, 0), | 149 | WM8978_DAC_LIMITER_2, 0, 12, 0, limiter_tlv), |
149 | 150 | ||
150 | SOC_ENUM("ALC Enable Switch", alc1), | 151 | SOC_ENUM("ALC Enable Switch", alc1), |
151 | SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0), | 152 | SOC_SINGLE("ALC Capture Min Gain", WM8978_ALC_CONTROL_1, 0, 7, 0), |
@@ -967,7 +968,7 @@ static int wm8978_probe(struct snd_soc_codec *codec) | |||
967 | * written. | 968 | * written. |
968 | */ | 969 | */ |
969 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) | 970 | for (i = 0; i < ARRAY_SIZE(update_reg); i++) |
970 | ((u16 *)codec->reg_cache)[update_reg[i]] |= 0x100; | 971 | snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100); |
971 | 972 | ||
972 | /* Reset the codec */ | 973 | /* Reset the codec */ |
973 | ret = snd_soc_write(codec, WM8978_RESET, 0); | 974 | ret = snd_soc_write(codec, WM8978_RESET, 0); |
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c new file mode 100644 index 000000000000..28fdfd66661d --- /dev/null +++ b/sound/soc/codecs/wm8991.c | |||
@@ -0,0 +1,1427 @@ | |||
1 | /* | ||
2 | * wm8991.c -- WM8991 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright 2007-2010 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dapm.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/tlv.h> | ||
31 | #include <asm/div64.h> | ||
32 | |||
33 | #include "wm8991.h" | ||
34 | |||
35 | struct wm8991_priv { | ||
36 | enum snd_soc_control_type control_type; | ||
37 | unsigned int pcmclk; | ||
38 | }; | ||
39 | |||
40 | static const u16 wm8991_reg_defs[] = { | ||
41 | 0x8991, /* R0 - Reset */ | ||
42 | 0x0000, /* R1 - Power Management (1) */ | ||
43 | 0x6000, /* R2 - Power Management (2) */ | ||
44 | 0x0000, /* R3 - Power Management (3) */ | ||
45 | 0x4050, /* R4 - Audio Interface (1) */ | ||
46 | 0x4000, /* R5 - Audio Interface (2) */ | ||
47 | 0x01C8, /* R6 - Clocking (1) */ | ||
48 | 0x0000, /* R7 - Clocking (2) */ | ||
49 | 0x0040, /* R8 - Audio Interface (3) */ | ||
50 | 0x0040, /* R9 - Audio Interface (4) */ | ||
51 | 0x0004, /* R10 - DAC CTRL */ | ||
52 | 0x00C0, /* R11 - Left DAC Digital Volume */ | ||
53 | 0x00C0, /* R12 - Right DAC Digital Volume */ | ||
54 | 0x0000, /* R13 - Digital Side Tone */ | ||
55 | 0x0100, /* R14 - ADC CTRL */ | ||
56 | 0x00C0, /* R15 - Left ADC Digital Volume */ | ||
57 | 0x00C0, /* R16 - Right ADC Digital Volume */ | ||
58 | 0x0000, /* R17 */ | ||
59 | 0x0000, /* R18 - GPIO CTRL 1 */ | ||
60 | 0x1000, /* R19 - GPIO1 & GPIO2 */ | ||
61 | 0x1010, /* R20 - GPIO3 & GPIO4 */ | ||
62 | 0x1010, /* R21 - GPIO5 & GPIO6 */ | ||
63 | 0x8000, /* R22 - GPIOCTRL 2 */ | ||
64 | 0x0800, /* R23 - GPIO_POL */ | ||
65 | 0x008B, /* R24 - Left Line Input 1&2 Volume */ | ||
66 | 0x008B, /* R25 - Left Line Input 3&4 Volume */ | ||
67 | 0x008B, /* R26 - Right Line Input 1&2 Volume */ | ||
68 | 0x008B, /* R27 - Right Line Input 3&4 Volume */ | ||
69 | 0x0000, /* R28 - Left Output Volume */ | ||
70 | 0x0000, /* R29 - Right Output Volume */ | ||
71 | 0x0066, /* R30 - Line Outputs Volume */ | ||
72 | 0x0022, /* R31 - Out3/4 Volume */ | ||
73 | 0x0079, /* R32 - Left OPGA Volume */ | ||
74 | 0x0079, /* R33 - Right OPGA Volume */ | ||
75 | 0x0003, /* R34 - Speaker Volume */ | ||
76 | 0x0003, /* R35 - ClassD1 */ | ||
77 | 0x0000, /* R36 */ | ||
78 | 0x0100, /* R37 - ClassD3 */ | ||
79 | 0x0000, /* R38 */ | ||
80 | 0x0000, /* R39 - Input Mixer1 */ | ||
81 | 0x0000, /* R40 - Input Mixer2 */ | ||
82 | 0x0000, /* R41 - Input Mixer3 */ | ||
83 | 0x0000, /* R42 - Input Mixer4 */ | ||
84 | 0x0000, /* R43 - Input Mixer5 */ | ||
85 | 0x0000, /* R44 - Input Mixer6 */ | ||
86 | 0x0000, /* R45 - Output Mixer1 */ | ||
87 | 0x0000, /* R46 - Output Mixer2 */ | ||
88 | 0x0000, /* R47 - Output Mixer3 */ | ||
89 | 0x0000, /* R48 - Output Mixer4 */ | ||
90 | 0x0000, /* R49 - Output Mixer5 */ | ||
91 | 0x0000, /* R50 - Output Mixer6 */ | ||
92 | 0x0180, /* R51 - Out3/4 Mixer */ | ||
93 | 0x0000, /* R52 - Line Mixer1 */ | ||
94 | 0x0000, /* R53 - Line Mixer2 */ | ||
95 | 0x0000, /* R54 - Speaker Mixer */ | ||
96 | 0x0000, /* R55 - Additional Control */ | ||
97 | 0x0000, /* R56 - AntiPOP1 */ | ||
98 | 0x0000, /* R57 - AntiPOP2 */ | ||
99 | 0x0000, /* R58 - MICBIAS */ | ||
100 | 0x0000, /* R59 */ | ||
101 | 0x0008, /* R60 - PLL1 */ | ||
102 | 0x0031, /* R61 - PLL2 */ | ||
103 | 0x0026, /* R62 - PLL3 */ | ||
104 | }; | ||
105 | |||
106 | #define wm8991_reset(c) snd_soc_write(c, WM8991_RESET, 0) | ||
107 | |||
108 | static const unsigned int rec_mix_tlv[] = { | ||
109 | TLV_DB_RANGE_HEAD(1), | ||
110 | 0, 7, TLV_DB_LINEAR_ITEM(-1500, 600), | ||
111 | }; | ||
112 | |||
113 | static const unsigned int in_pga_tlv[] = { | ||
114 | TLV_DB_RANGE_HEAD(1), | ||
115 | 0, 0x1F, TLV_DB_LINEAR_ITEM(-1650, 3000), | ||
116 | }; | ||
117 | |||
118 | static const unsigned int out_mix_tlv[] = { | ||
119 | TLV_DB_RANGE_HEAD(1), | ||
120 | 0, 7, TLV_DB_LINEAR_ITEM(0, -2100), | ||
121 | }; | ||
122 | |||
123 | static const unsigned int out_pga_tlv[] = { | ||
124 | TLV_DB_RANGE_HEAD(1), | ||
125 | 0, 127, TLV_DB_LINEAR_ITEM(-7300, 600), | ||
126 | }; | ||
127 | |||
128 | static const unsigned int out_omix_tlv[] = { | ||
129 | TLV_DB_RANGE_HEAD(1), | ||
130 | 0, 7, TLV_DB_LINEAR_ITEM(-600, 0), | ||
131 | }; | ||
132 | |||
133 | static const unsigned int out_dac_tlv[] = { | ||
134 | TLV_DB_RANGE_HEAD(1), | ||
135 | 0, 255, TLV_DB_LINEAR_ITEM(-7163, 0), | ||
136 | }; | ||
137 | |||
138 | static const unsigned int in_adc_tlv[] = { | ||
139 | TLV_DB_RANGE_HEAD(1), | ||
140 | 0, 255, TLV_DB_LINEAR_ITEM(-7163, 1763), | ||
141 | }; | ||
142 | |||
143 | static const unsigned int out_sidetone_tlv[] = { | ||
144 | TLV_DB_RANGE_HEAD(1), | ||
145 | 0, 31, TLV_DB_LINEAR_ITEM(-3600, 0), | ||
146 | }; | ||
147 | |||
148 | static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | ||
149 | struct snd_ctl_elem_value *ucontrol) | ||
150 | { | ||
151 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
152 | int reg = kcontrol->private_value & 0xff; | ||
153 | int ret; | ||
154 | u16 val; | ||
155 | |||
156 | ret = snd_soc_put_volsw(kcontrol, ucontrol); | ||
157 | if (ret < 0) | ||
158 | return ret; | ||
159 | |||
160 | /* now hit the volume update bits (always bit 8) */ | ||
161 | val = snd_soc_read(codec, reg); | ||
162 | return snd_soc_write(codec, reg, val | 0x0100); | ||
163 | } | ||
164 | |||
165 | static const char *wm8991_digital_sidetone[] = | ||
166 | {"None", "Left ADC", "Right ADC", "Reserved"}; | ||
167 | |||
168 | static const struct soc_enum wm8991_left_digital_sidetone_enum = | ||
169 | SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, | ||
170 | WM8991_ADC_TO_DACL_SHIFT, | ||
171 | WM8991_ADC_TO_DACL_MASK, | ||
172 | wm8991_digital_sidetone); | ||
173 | |||
174 | static const struct soc_enum wm8991_right_digital_sidetone_enum = | ||
175 | SOC_ENUM_SINGLE(WM8991_DIGITAL_SIDE_TONE, | ||
176 | WM8991_ADC_TO_DACR_SHIFT, | ||
177 | WM8991_ADC_TO_DACR_MASK, | ||
178 | wm8991_digital_sidetone); | ||
179 | |||
180 | static const char *wm8991_adcmode[] = | ||
181 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | ||
182 | |||
183 | static const struct soc_enum wm8991_right_adcmode_enum = | ||
184 | SOC_ENUM_SINGLE(WM8991_ADC_CTRL, | ||
185 | WM8991_ADC_HPF_CUT_SHIFT, | ||
186 | WM8991_ADC_HPF_CUT_MASK, | ||
187 | wm8991_adcmode); | ||
188 | |||
189 | static const struct snd_kcontrol_new wm8991_snd_controls[] = { | ||
190 | /* INMIXL */ | ||
191 | SOC_SINGLE("LIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L12MNBST_BIT, 1, 0), | ||
192 | SOC_SINGLE("LIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_L34MNBST_BIT, 1, 0), | ||
193 | /* INMIXR */ | ||
194 | SOC_SINGLE("RIN12 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R12MNBST_BIT, 1, 0), | ||
195 | SOC_SINGLE("RIN34 PGA Boost", WM8991_INPUT_MIXER3, WM8991_R34MNBST_BIT, 1, 0), | ||
196 | |||
197 | /* LOMIX */ | ||
198 | SOC_SINGLE_TLV("LOMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER3, | ||
199 | WM8991_LLI3LOVOL_SHIFT, WM8991_LLI3LOVOL_MASK, 1, out_mix_tlv), | ||
200 | SOC_SINGLE_TLV("LOMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3, | ||
201 | WM8991_LR12LOVOL_SHIFT, WM8991_LR12LOVOL_MASK, 1, out_mix_tlv), | ||
202 | SOC_SINGLE_TLV("LOMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER3, | ||
203 | WM8991_LL12LOVOL_SHIFT, WM8991_LL12LOVOL_MASK, 1, out_mix_tlv), | ||
204 | SOC_SINGLE_TLV("LOMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER5, | ||
205 | WM8991_LRI3LOVOL_SHIFT, WM8991_LRI3LOVOL_MASK, 1, out_mix_tlv), | ||
206 | SOC_SINGLE_TLV("LOMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER5, | ||
207 | WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
208 | SOC_SINGLE_TLV("LOMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER5, | ||
209 | WM8991_LRBLOVOL_SHIFT, WM8991_LRBLOVOL_MASK, 1, out_mix_tlv), | ||
210 | |||
211 | /* ROMIX */ | ||
212 | SOC_SINGLE_TLV("ROMIX RIN3 Bypass Volume", WM8991_OUTPUT_MIXER4, | ||
213 | WM8991_RRI3ROVOL_SHIFT, WM8991_RRI3ROVOL_MASK, 1, out_mix_tlv), | ||
214 | SOC_SINGLE_TLV("ROMIX LIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4, | ||
215 | WM8991_RL12ROVOL_SHIFT, WM8991_RL12ROVOL_MASK, 1, out_mix_tlv), | ||
216 | SOC_SINGLE_TLV("ROMIX RIN12 PGA Bypass Volume", WM8991_OUTPUT_MIXER4, | ||
217 | WM8991_RR12ROVOL_SHIFT, WM8991_RR12ROVOL_MASK, 1, out_mix_tlv), | ||
218 | SOC_SINGLE_TLV("ROMIX LIN3 Bypass Volume", WM8991_OUTPUT_MIXER6, | ||
219 | WM8991_RLI3ROVOL_SHIFT, WM8991_RLI3ROVOL_MASK, 1, out_mix_tlv), | ||
220 | SOC_SINGLE_TLV("ROMIX AINLMUX Bypass Volume", WM8991_OUTPUT_MIXER6, | ||
221 | WM8991_RLBROVOL_SHIFT, WM8991_RLBROVOL_MASK, 1, out_mix_tlv), | ||
222 | SOC_SINGLE_TLV("ROMIX AINRMUX Bypass Volume", WM8991_OUTPUT_MIXER6, | ||
223 | WM8991_RRBROVOL_SHIFT, WM8991_RRBROVOL_MASK, 1, out_mix_tlv), | ||
224 | |||
225 | /* LOUT */ | ||
226 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOUT Volume", WM8991_LEFT_OUTPUT_VOLUME, | ||
227 | WM8991_LOUTVOL_SHIFT, WM8991_LOUTVOL_MASK, 0, out_pga_tlv), | ||
228 | SOC_SINGLE("LOUT ZC", WM8991_LEFT_OUTPUT_VOLUME, WM8991_LOZC_BIT, 1, 0), | ||
229 | |||
230 | /* ROUT */ | ||
231 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROUT Volume", WM8991_RIGHT_OUTPUT_VOLUME, | ||
232 | WM8991_ROUTVOL_SHIFT, WM8991_ROUTVOL_MASK, 0, out_pga_tlv), | ||
233 | SOC_SINGLE("ROUT ZC", WM8991_RIGHT_OUTPUT_VOLUME, WM8991_ROZC_BIT, 1, 0), | ||
234 | |||
235 | /* LOPGA */ | ||
236 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LOPGA Volume", WM8991_LEFT_OPGA_VOLUME, | ||
237 | WM8991_LOPGAVOL_SHIFT, WM8991_LOPGAVOL_MASK, 0, out_pga_tlv), | ||
238 | SOC_SINGLE("LOPGA ZC Switch", WM8991_LEFT_OPGA_VOLUME, | ||
239 | WM8991_LOPGAZC_BIT, 1, 0), | ||
240 | |||
241 | /* ROPGA */ | ||
242 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("ROPGA Volume", WM8991_RIGHT_OPGA_VOLUME, | ||
243 | WM8991_ROPGAVOL_SHIFT, WM8991_ROPGAVOL_MASK, 0, out_pga_tlv), | ||
244 | SOC_SINGLE("ROPGA ZC Switch", WM8991_RIGHT_OPGA_VOLUME, | ||
245 | WM8991_ROPGAZC_BIT, 1, 0), | ||
246 | |||
247 | SOC_SINGLE("LON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
248 | WM8991_LONMUTE_BIT, 1, 0), | ||
249 | SOC_SINGLE("LOP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
250 | WM8991_LOPMUTE_BIT, 1, 0), | ||
251 | SOC_SINGLE("LOP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
252 | WM8991_LOATTN_BIT, 1, 0), | ||
253 | SOC_SINGLE("RON Mute Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
254 | WM8991_RONMUTE_BIT, 1, 0), | ||
255 | SOC_SINGLE("ROP Mute Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
256 | WM8991_ROPMUTE_BIT, 1, 0), | ||
257 | SOC_SINGLE("ROP Attenuation Switch", WM8991_LINE_OUTPUTS_VOLUME, | ||
258 | WM8991_ROATTN_BIT, 1, 0), | ||
259 | |||
260 | SOC_SINGLE("OUT3 Mute Switch", WM8991_OUT3_4_VOLUME, | ||
261 | WM8991_OUT3MUTE_BIT, 1, 0), | ||
262 | SOC_SINGLE("OUT3 Attenuation Switch", WM8991_OUT3_4_VOLUME, | ||
263 | WM8991_OUT3ATTN_BIT, 1, 0), | ||
264 | |||
265 | SOC_SINGLE("OUT4 Mute Switch", WM8991_OUT3_4_VOLUME, | ||
266 | WM8991_OUT4MUTE_BIT, 1, 0), | ||
267 | SOC_SINGLE("OUT4 Attenuation Switch", WM8991_OUT3_4_VOLUME, | ||
268 | WM8991_OUT4ATTN_BIT, 1, 0), | ||
269 | |||
270 | SOC_SINGLE("Speaker Mode Switch", WM8991_CLASSD1, | ||
271 | WM8991_CDMODE_BIT, 1, 0), | ||
272 | |||
273 | SOC_SINGLE("Speaker Output Attenuation Volume", WM8991_SPEAKER_VOLUME, | ||
274 | WM8991_SPKVOL_SHIFT, WM8991_SPKVOL_MASK, 0), | ||
275 | SOC_SINGLE("Speaker DC Boost Volume", WM8991_CLASSD3, | ||
276 | WM8991_DCGAIN_SHIFT, WM8991_DCGAIN_MASK, 0), | ||
277 | SOC_SINGLE("Speaker AC Boost Volume", WM8991_CLASSD3, | ||
278 | WM8991_ACGAIN_SHIFT, WM8991_ACGAIN_MASK, 0), | ||
279 | |||
280 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left DAC Digital Volume", | ||
281 | WM8991_LEFT_DAC_DIGITAL_VOLUME, | ||
282 | WM8991_DACL_VOL_SHIFT, | ||
283 | WM8991_DACL_VOL_MASK, | ||
284 | 0, | ||
285 | out_dac_tlv), | ||
286 | |||
287 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right DAC Digital Volume", | ||
288 | WM8991_RIGHT_DAC_DIGITAL_VOLUME, | ||
289 | WM8991_DACR_VOL_SHIFT, | ||
290 | WM8991_DACR_VOL_MASK, | ||
291 | 0, | ||
292 | out_dac_tlv), | ||
293 | |||
294 | SOC_ENUM("Left Digital Sidetone", wm8991_left_digital_sidetone_enum), | ||
295 | SOC_ENUM("Right Digital Sidetone", wm8991_right_digital_sidetone_enum), | ||
296 | |||
297 | SOC_SINGLE_TLV("Left Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE, | ||
298 | WM8991_ADCL_DAC_SVOL_SHIFT, WM8991_ADCL_DAC_SVOL_MASK, 0, | ||
299 | out_sidetone_tlv), | ||
300 | SOC_SINGLE_TLV("Right Digital Sidetone Volume", WM8991_DIGITAL_SIDE_TONE, | ||
301 | WM8991_ADCR_DAC_SVOL_SHIFT, WM8991_ADCR_DAC_SVOL_MASK, 0, | ||
302 | out_sidetone_tlv), | ||
303 | |||
304 | SOC_SINGLE("ADC Digital High Pass Filter Switch", WM8991_ADC_CTRL, | ||
305 | WM8991_ADC_HPF_ENA_BIT, 1, 0), | ||
306 | |||
307 | SOC_ENUM("ADC HPF Mode", wm8991_right_adcmode_enum), | ||
308 | |||
309 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Left ADC Digital Volume", | ||
310 | WM8991_LEFT_ADC_DIGITAL_VOLUME, | ||
311 | WM8991_ADCL_VOL_SHIFT, | ||
312 | WM8991_ADCL_VOL_MASK, | ||
313 | 0, | ||
314 | in_adc_tlv), | ||
315 | |||
316 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("Right ADC Digital Volume", | ||
317 | WM8991_RIGHT_ADC_DIGITAL_VOLUME, | ||
318 | WM8991_ADCR_VOL_SHIFT, | ||
319 | WM8991_ADCR_VOL_MASK, | ||
320 | 0, | ||
321 | in_adc_tlv), | ||
322 | |||
323 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN12 Volume", | ||
324 | WM8991_LEFT_LINE_INPUT_1_2_VOLUME, | ||
325 | WM8991_LIN12VOL_SHIFT, | ||
326 | WM8991_LIN12VOL_MASK, | ||
327 | 0, | ||
328 | in_pga_tlv), | ||
329 | |||
330 | SOC_SINGLE("LIN12 ZC Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME, | ||
331 | WM8991_LI12ZC_BIT, 1, 0), | ||
332 | |||
333 | SOC_SINGLE("LIN12 Mute Switch", WM8991_LEFT_LINE_INPUT_1_2_VOLUME, | ||
334 | WM8991_LI12MUTE_BIT, 1, 0), | ||
335 | |||
336 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("LIN34 Volume", | ||
337 | WM8991_LEFT_LINE_INPUT_3_4_VOLUME, | ||
338 | WM8991_LIN34VOL_SHIFT, | ||
339 | WM8991_LIN34VOL_MASK, | ||
340 | 0, | ||
341 | in_pga_tlv), | ||
342 | |||
343 | SOC_SINGLE("LIN34 ZC Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME, | ||
344 | WM8991_LI34ZC_BIT, 1, 0), | ||
345 | |||
346 | SOC_SINGLE("LIN34 Mute Switch", WM8991_LEFT_LINE_INPUT_3_4_VOLUME, | ||
347 | WM8991_LI34MUTE_BIT, 1, 0), | ||
348 | |||
349 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN12 Volume", | ||
350 | WM8991_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
351 | WM8991_RIN12VOL_SHIFT, | ||
352 | WM8991_RIN12VOL_MASK, | ||
353 | 0, | ||
354 | in_pga_tlv), | ||
355 | |||
356 | SOC_SINGLE("RIN12 ZC Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
357 | WM8991_RI12ZC_BIT, 1, 0), | ||
358 | |||
359 | SOC_SINGLE("RIN12 Mute Switch", WM8991_RIGHT_LINE_INPUT_1_2_VOLUME, | ||
360 | WM8991_RI12MUTE_BIT, 1, 0), | ||
361 | |||
362 | SOC_WM899X_OUTPGA_SINGLE_R_TLV("RIN34 Volume", | ||
363 | WM8991_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
364 | WM8991_RIN34VOL_SHIFT, | ||
365 | WM8991_RIN34VOL_MASK, | ||
366 | 0, | ||
367 | in_pga_tlv), | ||
368 | |||
369 | SOC_SINGLE("RIN34 ZC Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
370 | WM8991_RI34ZC_BIT, 1, 0), | ||
371 | |||
372 | SOC_SINGLE("RIN34 Mute Switch", WM8991_RIGHT_LINE_INPUT_3_4_VOLUME, | ||
373 | WM8991_RI34MUTE_BIT, 1, 0), | ||
374 | }; | ||
375 | |||
376 | /* | ||
377 | * _DAPM_ Controls | ||
378 | */ | ||
379 | static int inmixer_event(struct snd_soc_dapm_widget *w, | ||
380 | struct snd_kcontrol *kcontrol, int event) | ||
381 | { | ||
382 | u16 reg, fakepower; | ||
383 | |||
384 | reg = snd_soc_read(w->codec, WM8991_POWER_MANAGEMENT_2); | ||
385 | fakepower = snd_soc_read(w->codec, WM8991_INTDRIVBITS); | ||
386 | |||
387 | if (fakepower & ((1 << WM8991_INMIXL_PWR_BIT) | | ||
388 | (1 << WM8991_AINLMUX_PWR_BIT))) | ||
389 | reg |= WM8991_AINL_ENA; | ||
390 | else | ||
391 | reg &= ~WM8991_AINL_ENA; | ||
392 | |||
393 | if (fakepower & ((1 << WM8991_INMIXR_PWR_BIT) | | ||
394 | (1 << WM8991_AINRMUX_PWR_BIT))) | ||
395 | reg |= WM8991_AINR_ENA; | ||
396 | else | ||
397 | reg &= ~WM8991_AINL_ENA; | ||
398 | |||
399 | snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg); | ||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static int outmixer_event(struct snd_soc_dapm_widget *w, | ||
404 | struct snd_kcontrol *kcontrol, int event) | ||
405 | { | ||
406 | u32 reg_shift = kcontrol->private_value & 0xfff; | ||
407 | int ret = 0; | ||
408 | u16 reg; | ||
409 | |||
410 | switch (reg_shift) { | ||
411 | case WM8991_SPEAKER_MIXER | (WM8991_LDSPK_BIT << 8): | ||
412 | reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER1); | ||
413 | if (reg & WM8991_LDLO) { | ||
414 | printk(KERN_WARNING | ||
415 | "Cannot set as Output Mixer 1 LDLO Set\n"); | ||
416 | ret = -1; | ||
417 | } | ||
418 | break; | ||
419 | |||
420 | case WM8991_SPEAKER_MIXER | (WM8991_RDSPK_BIT << 8): | ||
421 | reg = snd_soc_read(w->codec, WM8991_OUTPUT_MIXER2); | ||
422 | if (reg & WM8991_RDRO) { | ||
423 | printk(KERN_WARNING | ||
424 | "Cannot set as Output Mixer 2 RDRO Set\n"); | ||
425 | ret = -1; | ||
426 | } | ||
427 | break; | ||
428 | |||
429 | case WM8991_OUTPUT_MIXER1 | (WM8991_LDLO_BIT << 8): | ||
430 | reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER); | ||
431 | if (reg & WM8991_LDSPK) { | ||
432 | printk(KERN_WARNING | ||
433 | "Cannot set as Speaker Mixer LDSPK Set\n"); | ||
434 | ret = -1; | ||
435 | } | ||
436 | break; | ||
437 | |||
438 | case WM8991_OUTPUT_MIXER2 | (WM8991_RDRO_BIT << 8): | ||
439 | reg = snd_soc_read(w->codec, WM8991_SPEAKER_MIXER); | ||
440 | if (reg & WM8991_RDSPK) { | ||
441 | printk(KERN_WARNING | ||
442 | "Cannot set as Speaker Mixer RDSPK Set\n"); | ||
443 | ret = -1; | ||
444 | } | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | /* INMIX dB values */ | ||
452 | static const unsigned int in_mix_tlv[] = { | ||
453 | TLV_DB_RANGE_HEAD(1), | ||
454 | 0, 7, TLV_DB_LINEAR_ITEM(-1200, 600), | ||
455 | }; | ||
456 | |||
457 | /* Left In PGA Connections */ | ||
458 | static const struct snd_kcontrol_new wm8991_dapm_lin12_pga_controls[] = { | ||
459 | SOC_DAPM_SINGLE("LIN1 Switch", WM8991_INPUT_MIXER2, WM8991_LMN1_BIT, 1, 0), | ||
460 | SOC_DAPM_SINGLE("LIN2 Switch", WM8991_INPUT_MIXER2, WM8991_LMP2_BIT, 1, 0), | ||
461 | }; | ||
462 | |||
463 | static const struct snd_kcontrol_new wm8991_dapm_lin34_pga_controls[] = { | ||
464 | SOC_DAPM_SINGLE("LIN3 Switch", WM8991_INPUT_MIXER2, WM8991_LMN3_BIT, 1, 0), | ||
465 | SOC_DAPM_SINGLE("LIN4 Switch", WM8991_INPUT_MIXER2, WM8991_LMP4_BIT, 1, 0), | ||
466 | }; | ||
467 | |||
468 | /* Right In PGA Connections */ | ||
469 | static const struct snd_kcontrol_new wm8991_dapm_rin12_pga_controls[] = { | ||
470 | SOC_DAPM_SINGLE("RIN1 Switch", WM8991_INPUT_MIXER2, WM8991_RMN1_BIT, 1, 0), | ||
471 | SOC_DAPM_SINGLE("RIN2 Switch", WM8991_INPUT_MIXER2, WM8991_RMP2_BIT, 1, 0), | ||
472 | }; | ||
473 | |||
474 | static const struct snd_kcontrol_new wm8991_dapm_rin34_pga_controls[] = { | ||
475 | SOC_DAPM_SINGLE("RIN3 Switch", WM8991_INPUT_MIXER2, WM8991_RMN3_BIT, 1, 0), | ||
476 | SOC_DAPM_SINGLE("RIN4 Switch", WM8991_INPUT_MIXER2, WM8991_RMP4_BIT, 1, 0), | ||
477 | }; | ||
478 | |||
479 | /* INMIXL */ | ||
480 | static const struct snd_kcontrol_new wm8991_dapm_inmixl_controls[] = { | ||
481 | SOC_DAPM_SINGLE_TLV("Record Left Volume", WM8991_INPUT_MIXER3, | ||
482 | WM8991_LDBVOL_SHIFT, WM8991_LDBVOL_MASK, 0, in_mix_tlv), | ||
483 | SOC_DAPM_SINGLE_TLV("LIN2 Volume", WM8991_INPUT_MIXER5, WM8991_LI2BVOL_SHIFT, | ||
484 | 7, 0, in_mix_tlv), | ||
485 | SOC_DAPM_SINGLE("LINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT, | ||
486 | 1, 0), | ||
487 | SOC_DAPM_SINGLE("LINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT, | ||
488 | 1, 0), | ||
489 | }; | ||
490 | |||
491 | /* INMIXR */ | ||
492 | static const struct snd_kcontrol_new wm8991_dapm_inmixr_controls[] = { | ||
493 | SOC_DAPM_SINGLE_TLV("Record Right Volume", WM8991_INPUT_MIXER4, | ||
494 | WM8991_RDBVOL_SHIFT, WM8991_RDBVOL_MASK, 0, in_mix_tlv), | ||
495 | SOC_DAPM_SINGLE_TLV("RIN2 Volume", WM8991_INPUT_MIXER6, WM8991_RI2BVOL_SHIFT, | ||
496 | 7, 0, in_mix_tlv), | ||
497 | SOC_DAPM_SINGLE("RINPGA12 Switch", WM8991_INPUT_MIXER3, WM8991_L12MNB_BIT, | ||
498 | 1, 0), | ||
499 | SOC_DAPM_SINGLE("RINPGA34 Switch", WM8991_INPUT_MIXER3, WM8991_L34MNB_BIT, | ||
500 | 1, 0), | ||
501 | }; | ||
502 | |||
503 | /* AINLMUX */ | ||
504 | static const char *wm8991_ainlmux[] = | ||
505 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | ||
506 | |||
507 | static const struct soc_enum wm8991_ainlmux_enum = | ||
508 | SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINLMODE_SHIFT, | ||
509 | ARRAY_SIZE(wm8991_ainlmux), wm8991_ainlmux); | ||
510 | |||
511 | static const struct snd_kcontrol_new wm8991_dapm_ainlmux_controls = | ||
512 | SOC_DAPM_ENUM("Route", wm8991_ainlmux_enum); | ||
513 | |||
514 | /* DIFFINL */ | ||
515 | |||
516 | /* AINRMUX */ | ||
517 | static const char *wm8991_ainrmux[] = | ||
518 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | ||
519 | |||
520 | static const struct soc_enum wm8991_ainrmux_enum = | ||
521 | SOC_ENUM_SINGLE(WM8991_INPUT_MIXER1, WM8991_AINRMODE_SHIFT, | ||
522 | ARRAY_SIZE(wm8991_ainrmux), wm8991_ainrmux); | ||
523 | |||
524 | static const struct snd_kcontrol_new wm8991_dapm_ainrmux_controls = | ||
525 | SOC_DAPM_ENUM("Route", wm8991_ainrmux_enum); | ||
526 | |||
527 | /* RXVOICE */ | ||
528 | static const struct snd_kcontrol_new wm8991_dapm_rxvoice_controls[] = { | ||
529 | SOC_DAPM_SINGLE_TLV("LIN4RXN", WM8991_INPUT_MIXER5, WM8991_LR4BVOL_SHIFT, | ||
530 | WM8991_LR4BVOL_MASK, 0, in_mix_tlv), | ||
531 | SOC_DAPM_SINGLE_TLV("RIN4RXP", WM8991_INPUT_MIXER6, WM8991_RL4BVOL_SHIFT, | ||
532 | WM8991_RL4BVOL_MASK, 0, in_mix_tlv), | ||
533 | }; | ||
534 | |||
535 | /* LOMIX */ | ||
536 | static const struct snd_kcontrol_new wm8991_dapm_lomix_controls[] = { | ||
537 | SOC_DAPM_SINGLE("LOMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
538 | WM8991_LRBLO_BIT, 1, 0), | ||
539 | SOC_DAPM_SINGLE("LOMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
540 | WM8991_LLBLO_BIT, 1, 0), | ||
541 | SOC_DAPM_SINGLE("LOMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
542 | WM8991_LRI3LO_BIT, 1, 0), | ||
543 | SOC_DAPM_SINGLE("LOMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
544 | WM8991_LLI3LO_BIT, 1, 0), | ||
545 | SOC_DAPM_SINGLE("LOMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
546 | WM8991_LR12LO_BIT, 1, 0), | ||
547 | SOC_DAPM_SINGLE("LOMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER1, | ||
548 | WM8991_LL12LO_BIT, 1, 0), | ||
549 | SOC_DAPM_SINGLE("LOMIX Left DAC Switch", WM8991_OUTPUT_MIXER1, | ||
550 | WM8991_LDLO_BIT, 1, 0), | ||
551 | }; | ||
552 | |||
553 | /* ROMIX */ | ||
554 | static const struct snd_kcontrol_new wm8991_dapm_romix_controls[] = { | ||
555 | SOC_DAPM_SINGLE("ROMIX Left ADC Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
556 | WM8991_RLBRO_BIT, 1, 0), | ||
557 | SOC_DAPM_SINGLE("ROMIX Right ADC Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
558 | WM8991_RRBRO_BIT, 1, 0), | ||
559 | SOC_DAPM_SINGLE("ROMIX LIN3 Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
560 | WM8991_RLI3RO_BIT, 1, 0), | ||
561 | SOC_DAPM_SINGLE("ROMIX RIN3 Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
562 | WM8991_RRI3RO_BIT, 1, 0), | ||
563 | SOC_DAPM_SINGLE("ROMIX LIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
564 | WM8991_RL12RO_BIT, 1, 0), | ||
565 | SOC_DAPM_SINGLE("ROMIX RIN12 PGA Bypass Switch", WM8991_OUTPUT_MIXER2, | ||
566 | WM8991_RR12RO_BIT, 1, 0), | ||
567 | SOC_DAPM_SINGLE("ROMIX Right DAC Switch", WM8991_OUTPUT_MIXER2, | ||
568 | WM8991_RDRO_BIT, 1, 0), | ||
569 | }; | ||
570 | |||
571 | /* LONMIX */ | ||
572 | static const struct snd_kcontrol_new wm8991_dapm_lonmix_controls[] = { | ||
573 | SOC_DAPM_SINGLE("LONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1, | ||
574 | WM8991_LLOPGALON_BIT, 1, 0), | ||
575 | SOC_DAPM_SINGLE("LONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER1, | ||
576 | WM8991_LROPGALON_BIT, 1, 0), | ||
577 | SOC_DAPM_SINGLE("LONMIX Inverted LOP Switch", WM8991_LINE_MIXER1, | ||
578 | WM8991_LOPLON_BIT, 1, 0), | ||
579 | }; | ||
580 | |||
581 | /* LOPMIX */ | ||
582 | static const struct snd_kcontrol_new wm8991_dapm_lopmix_controls[] = { | ||
583 | SOC_DAPM_SINGLE("LOPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER1, | ||
584 | WM8991_LR12LOP_BIT, 1, 0), | ||
585 | SOC_DAPM_SINGLE("LOPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER1, | ||
586 | WM8991_LL12LOP_BIT, 1, 0), | ||
587 | SOC_DAPM_SINGLE("LOPMIX Left Mixer PGA Switch", WM8991_LINE_MIXER1, | ||
588 | WM8991_LLOPGALOP_BIT, 1, 0), | ||
589 | }; | ||
590 | |||
591 | /* RONMIX */ | ||
592 | static const struct snd_kcontrol_new wm8991_dapm_ronmix_controls[] = { | ||
593 | SOC_DAPM_SINGLE("RONMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2, | ||
594 | WM8991_RROPGARON_BIT, 1, 0), | ||
595 | SOC_DAPM_SINGLE("RONMIX Left Mixer PGA Switch", WM8991_LINE_MIXER2, | ||
596 | WM8991_RLOPGARON_BIT, 1, 0), | ||
597 | SOC_DAPM_SINGLE("RONMIX Inverted ROP Switch", WM8991_LINE_MIXER2, | ||
598 | WM8991_ROPRON_BIT, 1, 0), | ||
599 | }; | ||
600 | |||
601 | /* ROPMIX */ | ||
602 | static const struct snd_kcontrol_new wm8991_dapm_ropmix_controls[] = { | ||
603 | SOC_DAPM_SINGLE("ROPMIX Left Mic Bypass Switch", WM8991_LINE_MIXER2, | ||
604 | WM8991_RL12ROP_BIT, 1, 0), | ||
605 | SOC_DAPM_SINGLE("ROPMIX Right Mic Bypass Switch", WM8991_LINE_MIXER2, | ||
606 | WM8991_RR12ROP_BIT, 1, 0), | ||
607 | SOC_DAPM_SINGLE("ROPMIX Right Mixer PGA Switch", WM8991_LINE_MIXER2, | ||
608 | WM8991_RROPGAROP_BIT, 1, 0), | ||
609 | }; | ||
610 | |||
611 | /* OUT3MIX */ | ||
612 | static const struct snd_kcontrol_new wm8991_dapm_out3mix_controls[] = { | ||
613 | SOC_DAPM_SINGLE("OUT3MIX LIN4RXN Bypass Switch", WM8991_OUT3_4_MIXER, | ||
614 | WM8991_LI4O3_BIT, 1, 0), | ||
615 | SOC_DAPM_SINGLE("OUT3MIX Left Out PGA Switch", WM8991_OUT3_4_MIXER, | ||
616 | WM8991_LPGAO3_BIT, 1, 0), | ||
617 | }; | ||
618 | |||
619 | /* OUT4MIX */ | ||
620 | static const struct snd_kcontrol_new wm8991_dapm_out4mix_controls[] = { | ||
621 | SOC_DAPM_SINGLE("OUT4MIX Right Out PGA Switch", WM8991_OUT3_4_MIXER, | ||
622 | WM8991_RPGAO4_BIT, 1, 0), | ||
623 | SOC_DAPM_SINGLE("OUT4MIX RIN4RXP Bypass Switch", WM8991_OUT3_4_MIXER, | ||
624 | WM8991_RI4O4_BIT, 1, 0), | ||
625 | }; | ||
626 | |||
627 | /* SPKMIX */ | ||
628 | static const struct snd_kcontrol_new wm8991_dapm_spkmix_controls[] = { | ||
629 | SOC_DAPM_SINGLE("SPKMIX LIN2 Bypass Switch", WM8991_SPEAKER_MIXER, | ||
630 | WM8991_LI2SPK_BIT, 1, 0), | ||
631 | SOC_DAPM_SINGLE("SPKMIX LADC Bypass Switch", WM8991_SPEAKER_MIXER, | ||
632 | WM8991_LB2SPK_BIT, 1, 0), | ||
633 | SOC_DAPM_SINGLE("SPKMIX Left Mixer PGA Switch", WM8991_SPEAKER_MIXER, | ||
634 | WM8991_LOPGASPK_BIT, 1, 0), | ||
635 | SOC_DAPM_SINGLE("SPKMIX Left DAC Switch", WM8991_SPEAKER_MIXER, | ||
636 | WM8991_LDSPK_BIT, 1, 0), | ||
637 | SOC_DAPM_SINGLE("SPKMIX Right DAC Switch", WM8991_SPEAKER_MIXER, | ||
638 | WM8991_RDSPK_BIT, 1, 0), | ||
639 | SOC_DAPM_SINGLE("SPKMIX Right Mixer PGA Switch", WM8991_SPEAKER_MIXER, | ||
640 | WM8991_ROPGASPK_BIT, 1, 0), | ||
641 | SOC_DAPM_SINGLE("SPKMIX RADC Bypass Switch", WM8991_SPEAKER_MIXER, | ||
642 | WM8991_RL12ROP_BIT, 1, 0), | ||
643 | SOC_DAPM_SINGLE("SPKMIX RIN2 Bypass Switch", WM8991_SPEAKER_MIXER, | ||
644 | WM8991_RI2SPK_BIT, 1, 0), | ||
645 | }; | ||
646 | |||
647 | static const struct snd_soc_dapm_widget wm8991_dapm_widgets[] = { | ||
648 | /* Input Side */ | ||
649 | /* Input Lines */ | ||
650 | SND_SOC_DAPM_INPUT("LIN1"), | ||
651 | SND_SOC_DAPM_INPUT("LIN2"), | ||
652 | SND_SOC_DAPM_INPUT("LIN3"), | ||
653 | SND_SOC_DAPM_INPUT("LIN4RXN"), | ||
654 | SND_SOC_DAPM_INPUT("RIN3"), | ||
655 | SND_SOC_DAPM_INPUT("RIN4RXP"), | ||
656 | SND_SOC_DAPM_INPUT("RIN1"), | ||
657 | SND_SOC_DAPM_INPUT("RIN2"), | ||
658 | SND_SOC_DAPM_INPUT("Internal ADC Source"), | ||
659 | |||
660 | /* DACs */ | ||
661 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", WM8991_POWER_MANAGEMENT_2, | ||
662 | WM8991_ADCL_ENA_BIT, 0), | ||
663 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", WM8991_POWER_MANAGEMENT_2, | ||
664 | WM8991_ADCR_ENA_BIT, 0), | ||
665 | |||
666 | /* Input PGAs */ | ||
667 | SND_SOC_DAPM_MIXER("LIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN12_ENA_BIT, | ||
668 | 0, &wm8991_dapm_lin12_pga_controls[0], | ||
669 | ARRAY_SIZE(wm8991_dapm_lin12_pga_controls)), | ||
670 | SND_SOC_DAPM_MIXER("LIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_LIN34_ENA_BIT, | ||
671 | 0, &wm8991_dapm_lin34_pga_controls[0], | ||
672 | ARRAY_SIZE(wm8991_dapm_lin34_pga_controls)), | ||
673 | SND_SOC_DAPM_MIXER("RIN12 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN12_ENA_BIT, | ||
674 | 0, &wm8991_dapm_rin12_pga_controls[0], | ||
675 | ARRAY_SIZE(wm8991_dapm_rin12_pga_controls)), | ||
676 | SND_SOC_DAPM_MIXER("RIN34 PGA", WM8991_POWER_MANAGEMENT_2, WM8991_RIN34_ENA_BIT, | ||
677 | 0, &wm8991_dapm_rin34_pga_controls[0], | ||
678 | ARRAY_SIZE(wm8991_dapm_rin34_pga_controls)), | ||
679 | |||
680 | /* INMIXL */ | ||
681 | SND_SOC_DAPM_MIXER_E("INMIXL", WM8991_INTDRIVBITS, WM8991_INMIXL_PWR_BIT, 0, | ||
682 | &wm8991_dapm_inmixl_controls[0], | ||
683 | ARRAY_SIZE(wm8991_dapm_inmixl_controls), | ||
684 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
685 | |||
686 | /* AINLMUX */ | ||
687 | SND_SOC_DAPM_MUX_E("AINLMUX", WM8991_INTDRIVBITS, WM8991_AINLMUX_PWR_BIT, 0, | ||
688 | &wm8991_dapm_ainlmux_controls, inmixer_event, | ||
689 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
690 | |||
691 | /* INMIXR */ | ||
692 | SND_SOC_DAPM_MIXER_E("INMIXR", WM8991_INTDRIVBITS, WM8991_INMIXR_PWR_BIT, 0, | ||
693 | &wm8991_dapm_inmixr_controls[0], | ||
694 | ARRAY_SIZE(wm8991_dapm_inmixr_controls), | ||
695 | inmixer_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
696 | |||
697 | /* AINRMUX */ | ||
698 | SND_SOC_DAPM_MUX_E("AINRMUX", WM8991_INTDRIVBITS, WM8991_AINRMUX_PWR_BIT, 0, | ||
699 | &wm8991_dapm_ainrmux_controls, inmixer_event, | ||
700 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
701 | |||
702 | /* Output Side */ | ||
703 | /* DACs */ | ||
704 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", WM8991_POWER_MANAGEMENT_3, | ||
705 | WM8991_DACL_ENA_BIT, 0), | ||
706 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", WM8991_POWER_MANAGEMENT_3, | ||
707 | WM8991_DACR_ENA_BIT, 0), | ||
708 | |||
709 | /* LOMIX */ | ||
710 | SND_SOC_DAPM_MIXER_E("LOMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOMIX_ENA_BIT, | ||
711 | 0, &wm8991_dapm_lomix_controls[0], | ||
712 | ARRAY_SIZE(wm8991_dapm_lomix_controls), | ||
713 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
714 | |||
715 | /* LONMIX */ | ||
716 | SND_SOC_DAPM_MIXER("LONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LON_ENA_BIT, 0, | ||
717 | &wm8991_dapm_lonmix_controls[0], | ||
718 | ARRAY_SIZE(wm8991_dapm_lonmix_controls)), | ||
719 | |||
720 | /* LOPMIX */ | ||
721 | SND_SOC_DAPM_MIXER("LOPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_LOP_ENA_BIT, 0, | ||
722 | &wm8991_dapm_lopmix_controls[0], | ||
723 | ARRAY_SIZE(wm8991_dapm_lopmix_controls)), | ||
724 | |||
725 | /* OUT3MIX */ | ||
726 | SND_SOC_DAPM_MIXER("OUT3MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT3_ENA_BIT, 0, | ||
727 | &wm8991_dapm_out3mix_controls[0], | ||
728 | ARRAY_SIZE(wm8991_dapm_out3mix_controls)), | ||
729 | |||
730 | /* SPKMIX */ | ||
731 | SND_SOC_DAPM_MIXER_E("SPKMIX", WM8991_POWER_MANAGEMENT_1, WM8991_SPK_ENA_BIT, 0, | ||
732 | &wm8991_dapm_spkmix_controls[0], | ||
733 | ARRAY_SIZE(wm8991_dapm_spkmix_controls), outmixer_event, | ||
734 | SND_SOC_DAPM_PRE_REG), | ||
735 | |||
736 | /* OUT4MIX */ | ||
737 | SND_SOC_DAPM_MIXER("OUT4MIX", WM8991_POWER_MANAGEMENT_1, WM8991_OUT4_ENA_BIT, 0, | ||
738 | &wm8991_dapm_out4mix_controls[0], | ||
739 | ARRAY_SIZE(wm8991_dapm_out4mix_controls)), | ||
740 | |||
741 | /* ROPMIX */ | ||
742 | SND_SOC_DAPM_MIXER("ROPMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROP_ENA_BIT, 0, | ||
743 | &wm8991_dapm_ropmix_controls[0], | ||
744 | ARRAY_SIZE(wm8991_dapm_ropmix_controls)), | ||
745 | |||
746 | /* RONMIX */ | ||
747 | SND_SOC_DAPM_MIXER("RONMIX", WM8991_POWER_MANAGEMENT_3, WM8991_RON_ENA_BIT, 0, | ||
748 | &wm8991_dapm_ronmix_controls[0], | ||
749 | ARRAY_SIZE(wm8991_dapm_ronmix_controls)), | ||
750 | |||
751 | /* ROMIX */ | ||
752 | SND_SOC_DAPM_MIXER_E("ROMIX", WM8991_POWER_MANAGEMENT_3, WM8991_ROMIX_ENA_BIT, | ||
753 | 0, &wm8991_dapm_romix_controls[0], | ||
754 | ARRAY_SIZE(wm8991_dapm_romix_controls), | ||
755 | outmixer_event, SND_SOC_DAPM_PRE_REG), | ||
756 | |||
757 | /* LOUT PGA */ | ||
758 | SND_SOC_DAPM_PGA("LOUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_LOUT_ENA_BIT, 0, | ||
759 | NULL, 0), | ||
760 | |||
761 | /* ROUT PGA */ | ||
762 | SND_SOC_DAPM_PGA("ROUT PGA", WM8991_POWER_MANAGEMENT_1, WM8991_ROUT_ENA_BIT, 0, | ||
763 | NULL, 0), | ||
764 | |||
765 | /* LOPGA */ | ||
766 | SND_SOC_DAPM_PGA("LOPGA", WM8991_POWER_MANAGEMENT_3, WM8991_LOPGA_ENA_BIT, 0, | ||
767 | NULL, 0), | ||
768 | |||
769 | /* ROPGA */ | ||
770 | SND_SOC_DAPM_PGA("ROPGA", WM8991_POWER_MANAGEMENT_3, WM8991_ROPGA_ENA_BIT, 0, | ||
771 | NULL, 0), | ||
772 | |||
773 | /* MICBIAS */ | ||
774 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8991_POWER_MANAGEMENT_1, | ||
775 | WM8991_MICBIAS_ENA_BIT, 0), | ||
776 | |||
777 | SND_SOC_DAPM_OUTPUT("LON"), | ||
778 | SND_SOC_DAPM_OUTPUT("LOP"), | ||
779 | SND_SOC_DAPM_OUTPUT("OUT3"), | ||
780 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
781 | SND_SOC_DAPM_OUTPUT("SPKN"), | ||
782 | SND_SOC_DAPM_OUTPUT("SPKP"), | ||
783 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
784 | SND_SOC_DAPM_OUTPUT("OUT4"), | ||
785 | SND_SOC_DAPM_OUTPUT("ROP"), | ||
786 | SND_SOC_DAPM_OUTPUT("RON"), | ||
787 | SND_SOC_DAPM_OUTPUT("OUT"), | ||
788 | |||
789 | SND_SOC_DAPM_OUTPUT("Internal DAC Sink"), | ||
790 | }; | ||
791 | |||
792 | static const struct snd_soc_dapm_route audio_map[] = { | ||
793 | /* Make DACs turn on when playing even if not mixed into any outputs */ | ||
794 | {"Internal DAC Sink", NULL, "Left DAC"}, | ||
795 | {"Internal DAC Sink", NULL, "Right DAC"}, | ||
796 | |||
797 | /* Make ADCs turn on when recording even if not mixed from any inputs */ | ||
798 | {"Left ADC", NULL, "Internal ADC Source"}, | ||
799 | {"Right ADC", NULL, "Internal ADC Source"}, | ||
800 | |||
801 | /* Input Side */ | ||
802 | /* LIN12 PGA */ | ||
803 | {"LIN12 PGA", "LIN1 Switch", "LIN1"}, | ||
804 | {"LIN12 PGA", "LIN2 Switch", "LIN2"}, | ||
805 | /* LIN34 PGA */ | ||
806 | {"LIN34 PGA", "LIN3 Switch", "LIN3"}, | ||
807 | {"LIN34 PGA", "LIN4 Switch", "LIN4RXN"}, | ||
808 | /* INMIXL */ | ||
809 | {"INMIXL", "Record Left Volume", "LOMIX"}, | ||
810 | {"INMIXL", "LIN2 Volume", "LIN2"}, | ||
811 | {"INMIXL", "LINPGA12 Switch", "LIN12 PGA"}, | ||
812 | {"INMIXL", "LINPGA34 Switch", "LIN34 PGA"}, | ||
813 | /* AINLMUX */ | ||
814 | {"AINLMUX", "INMIXL Mix", "INMIXL"}, | ||
815 | {"AINLMUX", "DIFFINL Mix", "LIN12 PGA"}, | ||
816 | {"AINLMUX", "DIFFINL Mix", "LIN34 PGA"}, | ||
817 | {"AINLMUX", "RXVOICE Mix", "LIN4RXN"}, | ||
818 | {"AINLMUX", "RXVOICE Mix", "RIN4RXP"}, | ||
819 | /* ADC */ | ||
820 | {"Left ADC", NULL, "AINLMUX"}, | ||
821 | |||
822 | /* RIN12 PGA */ | ||
823 | {"RIN12 PGA", "RIN1 Switch", "RIN1"}, | ||
824 | {"RIN12 PGA", "RIN2 Switch", "RIN2"}, | ||
825 | /* RIN34 PGA */ | ||
826 | {"RIN34 PGA", "RIN3 Switch", "RIN3"}, | ||
827 | {"RIN34 PGA", "RIN4 Switch", "RIN4RXP"}, | ||
828 | /* INMIXL */ | ||
829 | {"INMIXR", "Record Right Volume", "ROMIX"}, | ||
830 | {"INMIXR", "RIN2 Volume", "RIN2"}, | ||
831 | {"INMIXR", "RINPGA12 Switch", "RIN12 PGA"}, | ||
832 | {"INMIXR", "RINPGA34 Switch", "RIN34 PGA"}, | ||
833 | /* AINRMUX */ | ||
834 | {"AINRMUX", "INMIXR Mix", "INMIXR"}, | ||
835 | {"AINRMUX", "DIFFINR Mix", "RIN12 PGA"}, | ||
836 | {"AINRMUX", "DIFFINR Mix", "RIN34 PGA"}, | ||
837 | {"AINRMUX", "RXVOICE Mix", "LIN4RXN"}, | ||
838 | {"AINRMUX", "RXVOICE Mix", "RIN4RXP"}, | ||
839 | /* ADC */ | ||
840 | {"Right ADC", NULL, "AINRMUX"}, | ||
841 | |||
842 | /* LOMIX */ | ||
843 | {"LOMIX", "LOMIX RIN3 Bypass Switch", "RIN3"}, | ||
844 | {"LOMIX", "LOMIX LIN3 Bypass Switch", "LIN3"}, | ||
845 | {"LOMIX", "LOMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
846 | {"LOMIX", "LOMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
847 | {"LOMIX", "LOMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
848 | {"LOMIX", "LOMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
849 | {"LOMIX", "LOMIX Left DAC Switch", "Left DAC"}, | ||
850 | |||
851 | /* ROMIX */ | ||
852 | {"ROMIX", "ROMIX RIN3 Bypass Switch", "RIN3"}, | ||
853 | {"ROMIX", "ROMIX LIN3 Bypass Switch", "LIN3"}, | ||
854 | {"ROMIX", "ROMIX LIN12 PGA Bypass Switch", "LIN12 PGA"}, | ||
855 | {"ROMIX", "ROMIX RIN12 PGA Bypass Switch", "RIN12 PGA"}, | ||
856 | {"ROMIX", "ROMIX Right ADC Bypass Switch", "AINRMUX"}, | ||
857 | {"ROMIX", "ROMIX Left ADC Bypass Switch", "AINLMUX"}, | ||
858 | {"ROMIX", "ROMIX Right DAC Switch", "Right DAC"}, | ||
859 | |||
860 | /* SPKMIX */ | ||
861 | {"SPKMIX", "SPKMIX LIN2 Bypass Switch", "LIN2"}, | ||
862 | {"SPKMIX", "SPKMIX RIN2 Bypass Switch", "RIN2"}, | ||
863 | {"SPKMIX", "SPKMIX LADC Bypass Switch", "AINLMUX"}, | ||
864 | {"SPKMIX", "SPKMIX RADC Bypass Switch", "AINRMUX"}, | ||
865 | {"SPKMIX", "SPKMIX Left Mixer PGA Switch", "LOPGA"}, | ||
866 | {"SPKMIX", "SPKMIX Right Mixer PGA Switch", "ROPGA"}, | ||
867 | {"SPKMIX", "SPKMIX Right DAC Switch", "Right DAC"}, | ||
868 | {"SPKMIX", "SPKMIX Left DAC Switch", "Right DAC"}, | ||
869 | |||
870 | /* LONMIX */ | ||
871 | {"LONMIX", "LONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
872 | {"LONMIX", "LONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
873 | {"LONMIX", "LONMIX Inverted LOP Switch", "LOPMIX"}, | ||
874 | |||
875 | /* LOPMIX */ | ||
876 | {"LOPMIX", "LOPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
877 | {"LOPMIX", "LOPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
878 | {"LOPMIX", "LOPMIX Left Mixer PGA Switch", "LOPGA"}, | ||
879 | |||
880 | /* OUT3MIX */ | ||
881 | {"OUT3MIX", "OUT3MIX LIN4RXN Bypass Switch", "LIN4RXN"}, | ||
882 | {"OUT3MIX", "OUT3MIX Left Out PGA Switch", "LOPGA"}, | ||
883 | |||
884 | /* OUT4MIX */ | ||
885 | {"OUT4MIX", "OUT4MIX Right Out PGA Switch", "ROPGA"}, | ||
886 | {"OUT4MIX", "OUT4MIX RIN4RXP Bypass Switch", "RIN4RXP"}, | ||
887 | |||
888 | /* RONMIX */ | ||
889 | {"RONMIX", "RONMIX Right Mixer PGA Switch", "ROPGA"}, | ||
890 | {"RONMIX", "RONMIX Left Mixer PGA Switch", "LOPGA"}, | ||
891 | {"RONMIX", "RONMIX Inverted ROP Switch", "ROPMIX"}, | ||
892 | |||
893 | /* ROPMIX */ | ||
894 | {"ROPMIX", "ROPMIX Left Mic Bypass Switch", "LIN12 PGA"}, | ||
895 | {"ROPMIX", "ROPMIX Right Mic Bypass Switch", "RIN12 PGA"}, | ||
896 | {"ROPMIX", "ROPMIX Right Mixer PGA Switch", "ROPGA"}, | ||
897 | |||
898 | /* Out Mixer PGAs */ | ||
899 | {"LOPGA", NULL, "LOMIX"}, | ||
900 | {"ROPGA", NULL, "ROMIX"}, | ||
901 | |||
902 | {"LOUT PGA", NULL, "LOMIX"}, | ||
903 | {"ROUT PGA", NULL, "ROMIX"}, | ||
904 | |||
905 | /* Output Pins */ | ||
906 | {"LON", NULL, "LONMIX"}, | ||
907 | {"LOP", NULL, "LOPMIX"}, | ||
908 | {"OUT", NULL, "OUT3MIX"}, | ||
909 | {"LOUT", NULL, "LOUT PGA"}, | ||
910 | {"SPKN", NULL, "SPKMIX"}, | ||
911 | {"ROUT", NULL, "ROUT PGA"}, | ||
912 | {"OUT4", NULL, "OUT4MIX"}, | ||
913 | {"ROP", NULL, "ROPMIX"}, | ||
914 | {"RON", NULL, "RONMIX"}, | ||
915 | }; | ||
916 | |||
917 | /* PLL divisors */ | ||
918 | struct _pll_div { | ||
919 | u32 div2; | ||
920 | u32 n; | ||
921 | u32 k; | ||
922 | }; | ||
923 | |||
924 | /* The size in bits of the pll divide multiplied by 10 | ||
925 | * to allow rounding later */ | ||
926 | #define FIXED_PLL_SIZE ((1 << 16) * 10) | ||
927 | |||
928 | static void pll_factors(struct _pll_div *pll_div, unsigned int target, | ||
929 | unsigned int source) | ||
930 | { | ||
931 | u64 Kpart; | ||
932 | unsigned int K, Ndiv, Nmod; | ||
933 | |||
934 | |||
935 | Ndiv = target / source; | ||
936 | if (Ndiv < 6) { | ||
937 | source >>= 1; | ||
938 | pll_div->div2 = 1; | ||
939 | Ndiv = target / source; | ||
940 | } else | ||
941 | pll_div->div2 = 0; | ||
942 | |||
943 | if ((Ndiv < 6) || (Ndiv > 12)) | ||
944 | printk(KERN_WARNING | ||
945 | "WM8991 N value outwith recommended range! N = %d\n", Ndiv); | ||
946 | |||
947 | pll_div->n = Ndiv; | ||
948 | Nmod = target % source; | ||
949 | Kpart = FIXED_PLL_SIZE * (long long)Nmod; | ||
950 | |||
951 | do_div(Kpart, source); | ||
952 | |||
953 | K = Kpart & 0xFFFFFFFF; | ||
954 | |||
955 | /* Check if we need to round */ | ||
956 | if ((K % 10) >= 5) | ||
957 | K += 5; | ||
958 | |||
959 | /* Move down to proper range now rounding is done */ | ||
960 | K /= 10; | ||
961 | |||
962 | pll_div->k = K; | ||
963 | } | ||
964 | |||
965 | static int wm8991_set_dai_pll(struct snd_soc_dai *codec_dai, | ||
966 | int pll_id, int src, unsigned int freq_in, unsigned int freq_out) | ||
967 | { | ||
968 | u16 reg; | ||
969 | struct snd_soc_codec *codec = codec_dai->codec; | ||
970 | struct _pll_div pll_div; | ||
971 | |||
972 | if (freq_in && freq_out) { | ||
973 | pll_factors(&pll_div, freq_out * 4, freq_in); | ||
974 | |||
975 | /* Turn on PLL */ | ||
976 | reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2); | ||
977 | reg |= WM8991_PLL_ENA; | ||
978 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg); | ||
979 | |||
980 | /* sysclk comes from PLL */ | ||
981 | reg = snd_soc_read(codec, WM8991_CLOCKING_2); | ||
982 | snd_soc_write(codec, WM8991_CLOCKING_2, reg | WM8991_SYSCLK_SRC); | ||
983 | |||
984 | /* set up N , fractional mode and pre-divisor if neccessary */ | ||
985 | snd_soc_write(codec, WM8991_PLL1, pll_div.n | WM8991_SDM | | ||
986 | (pll_div.div2 ? WM8991_PRESCALE : 0)); | ||
987 | snd_soc_write(codec, WM8991_PLL2, (u8)(pll_div.k>>8)); | ||
988 | snd_soc_write(codec, WM8991_PLL3, (u8)(pll_div.k & 0xFF)); | ||
989 | } else { | ||
990 | /* Turn on PLL */ | ||
991 | reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2); | ||
992 | reg &= ~WM8991_PLL_ENA; | ||
993 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg); | ||
994 | } | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | /* | ||
999 | * Set's ADC and Voice DAC format. | ||
1000 | */ | ||
1001 | static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
1002 | unsigned int fmt) | ||
1003 | { | ||
1004 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1005 | u16 audio1, audio3; | ||
1006 | |||
1007 | audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1); | ||
1008 | audio3 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_3); | ||
1009 | |||
1010 | /* set master/slave audio interface */ | ||
1011 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1012 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1013 | audio3 &= ~WM8991_AIF_MSTR1; | ||
1014 | break; | ||
1015 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1016 | audio3 |= WM8991_AIF_MSTR1; | ||
1017 | break; | ||
1018 | default: | ||
1019 | return -EINVAL; | ||
1020 | } | ||
1021 | |||
1022 | audio1 &= ~WM8991_AIF_FMT_MASK; | ||
1023 | |||
1024 | /* interface format */ | ||
1025 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1026 | case SND_SOC_DAIFMT_I2S: | ||
1027 | audio1 |= WM8991_AIF_TMF_I2S; | ||
1028 | audio1 &= ~WM8991_AIF_LRCLK_INV; | ||
1029 | break; | ||
1030 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1031 | audio1 |= WM8991_AIF_TMF_RIGHTJ; | ||
1032 | audio1 &= ~WM8991_AIF_LRCLK_INV; | ||
1033 | break; | ||
1034 | case SND_SOC_DAIFMT_LEFT_J: | ||
1035 | audio1 |= WM8991_AIF_TMF_LEFTJ; | ||
1036 | audio1 &= ~WM8991_AIF_LRCLK_INV; | ||
1037 | break; | ||
1038 | case SND_SOC_DAIFMT_DSP_A: | ||
1039 | audio1 |= WM8991_AIF_TMF_DSP; | ||
1040 | audio1 &= ~WM8991_AIF_LRCLK_INV; | ||
1041 | break; | ||
1042 | case SND_SOC_DAIFMT_DSP_B: | ||
1043 | audio1 |= WM8991_AIF_TMF_DSP | WM8991_AIF_LRCLK_INV; | ||
1044 | break; | ||
1045 | default: | ||
1046 | return -EINVAL; | ||
1047 | } | ||
1048 | |||
1049 | snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1); | ||
1050 | snd_soc_write(codec, WM8991_AUDIO_INTERFACE_3, audio3); | ||
1051 | return 0; | ||
1052 | } | ||
1053 | |||
1054 | static int wm8991_set_dai_clkdiv(struct snd_soc_dai *codec_dai, | ||
1055 | int div_id, int div) | ||
1056 | { | ||
1057 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1058 | u16 reg; | ||
1059 | |||
1060 | switch (div_id) { | ||
1061 | case WM8991_MCLK_DIV: | ||
1062 | reg = snd_soc_read(codec, WM8991_CLOCKING_2) & | ||
1063 | ~WM8991_MCLK_DIV_MASK; | ||
1064 | snd_soc_write(codec, WM8991_CLOCKING_2, reg | div); | ||
1065 | break; | ||
1066 | case WM8991_DACCLK_DIV: | ||
1067 | reg = snd_soc_read(codec, WM8991_CLOCKING_2) & | ||
1068 | ~WM8991_DAC_CLKDIV_MASK; | ||
1069 | snd_soc_write(codec, WM8991_CLOCKING_2, reg | div); | ||
1070 | break; | ||
1071 | case WM8991_ADCCLK_DIV: | ||
1072 | reg = snd_soc_read(codec, WM8991_CLOCKING_2) & | ||
1073 | ~WM8991_ADC_CLKDIV_MASK; | ||
1074 | snd_soc_write(codec, WM8991_CLOCKING_2, reg | div); | ||
1075 | break; | ||
1076 | case WM8991_BCLK_DIV: | ||
1077 | reg = snd_soc_read(codec, WM8991_CLOCKING_1) & | ||
1078 | ~WM8991_BCLK_DIV_MASK; | ||
1079 | snd_soc_write(codec, WM8991_CLOCKING_1, reg | div); | ||
1080 | break; | ||
1081 | default: | ||
1082 | return -EINVAL; | ||
1083 | } | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | /* | ||
1089 | * Set PCM DAI bit size and sample rate. | ||
1090 | */ | ||
1091 | static int wm8991_hw_params(struct snd_pcm_substream *substream, | ||
1092 | struct snd_pcm_hw_params *params, | ||
1093 | struct snd_soc_dai *dai) | ||
1094 | { | ||
1095 | struct snd_soc_codec *codec = dai->codec; | ||
1096 | u16 audio1 = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_1); | ||
1097 | |||
1098 | audio1 &= ~WM8991_AIF_WL_MASK; | ||
1099 | /* bit size */ | ||
1100 | switch (params_format(params)) { | ||
1101 | case SNDRV_PCM_FORMAT_S16_LE: | ||
1102 | break; | ||
1103 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
1104 | audio1 |= WM8991_AIF_WL_20BITS; | ||
1105 | break; | ||
1106 | case SNDRV_PCM_FORMAT_S24_LE: | ||
1107 | audio1 |= WM8991_AIF_WL_24BITS; | ||
1108 | break; | ||
1109 | case SNDRV_PCM_FORMAT_S32_LE: | ||
1110 | audio1 |= WM8991_AIF_WL_32BITS; | ||
1111 | break; | ||
1112 | } | ||
1113 | |||
1114 | snd_soc_write(codec, WM8991_AUDIO_INTERFACE_1, audio1); | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int wm8991_mute(struct snd_soc_dai *dai, int mute) | ||
1119 | { | ||
1120 | struct snd_soc_codec *codec = dai->codec; | ||
1121 | u16 val; | ||
1122 | |||
1123 | val = snd_soc_read(codec, WM8991_DAC_CTRL) & ~WM8991_DAC_MUTE; | ||
1124 | if (mute) | ||
1125 | snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE); | ||
1126 | else | ||
1127 | snd_soc_write(codec, WM8991_DAC_CTRL, val); | ||
1128 | return 0; | ||
1129 | } | ||
1130 | |||
1131 | static int wm8991_set_bias_level(struct snd_soc_codec *codec, | ||
1132 | enum snd_soc_bias_level level) | ||
1133 | { | ||
1134 | u16 val; | ||
1135 | |||
1136 | switch (level) { | ||
1137 | case SND_SOC_BIAS_ON: | ||
1138 | break; | ||
1139 | |||
1140 | case SND_SOC_BIAS_PREPARE: | ||
1141 | /* VMID=2*50k */ | ||
1142 | val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) & | ||
1143 | ~WM8991_VMID_MODE_MASK; | ||
1144 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x2); | ||
1145 | break; | ||
1146 | |||
1147 | case SND_SOC_BIAS_STANDBY: | ||
1148 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
1149 | snd_soc_cache_sync(codec); | ||
1150 | /* Enable all output discharge bits */ | ||
1151 | snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE | | ||
1152 | WM8991_DIS_RLINE | WM8991_DIS_OUT3 | | ||
1153 | WM8991_DIS_OUT4 | WM8991_DIS_LOUT | | ||
1154 | WM8991_DIS_ROUT); | ||
1155 | |||
1156 | /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ | ||
1157 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST | | ||
1158 | WM8991_BUFDCOPEN | WM8991_POBCTRL | | ||
1159 | WM8991_VMIDTOG); | ||
1160 | |||
1161 | /* Delay to allow output caps to discharge */ | ||
1162 | msleep(300); | ||
1163 | |||
1164 | /* Disable VMIDTOG */ | ||
1165 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST | | ||
1166 | WM8991_BUFDCOPEN | WM8991_POBCTRL); | ||
1167 | |||
1168 | /* disable all output discharge bits */ | ||
1169 | snd_soc_write(codec, WM8991_ANTIPOP1, 0); | ||
1170 | |||
1171 | /* Enable outputs */ | ||
1172 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1b00); | ||
1173 | |||
1174 | msleep(50); | ||
1175 | |||
1176 | /* Enable VMID at 2x50k */ | ||
1177 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f02); | ||
1178 | |||
1179 | msleep(100); | ||
1180 | |||
1181 | /* Enable VREF */ | ||
1182 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03); | ||
1183 | |||
1184 | msleep(600); | ||
1185 | |||
1186 | /* Enable BUFIOEN */ | ||
1187 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST | | ||
1188 | WM8991_BUFDCOPEN | WM8991_POBCTRL | | ||
1189 | WM8991_BUFIOEN); | ||
1190 | |||
1191 | /* Disable outputs */ | ||
1192 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x3); | ||
1193 | |||
1194 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1195 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_BUFIOEN); | ||
1196 | } | ||
1197 | |||
1198 | /* VMID=2*250k */ | ||
1199 | val = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1) & | ||
1200 | ~WM8991_VMID_MODE_MASK; | ||
1201 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, val | 0x4); | ||
1202 | break; | ||
1203 | |||
1204 | case SND_SOC_BIAS_OFF: | ||
1205 | /* Enable POBCTRL and SOFT_ST */ | ||
1206 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST | | ||
1207 | WM8991_POBCTRL | WM8991_BUFIOEN); | ||
1208 | |||
1209 | /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1210 | snd_soc_write(codec, WM8991_ANTIPOP2, WM8991_SOFTST | | ||
1211 | WM8991_BUFDCOPEN | WM8991_POBCTRL | | ||
1212 | WM8991_BUFIOEN); | ||
1213 | |||
1214 | /* mute DAC */ | ||
1215 | val = snd_soc_read(codec, WM8991_DAC_CTRL); | ||
1216 | snd_soc_write(codec, WM8991_DAC_CTRL, val | WM8991_DAC_MUTE); | ||
1217 | |||
1218 | /* Enable any disabled outputs */ | ||
1219 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f03); | ||
1220 | |||
1221 | /* Disable VMID */ | ||
1222 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x1f01); | ||
1223 | |||
1224 | msleep(300); | ||
1225 | |||
1226 | /* Enable all output discharge bits */ | ||
1227 | snd_soc_write(codec, WM8991_ANTIPOP1, WM8991_DIS_LLINE | | ||
1228 | WM8991_DIS_RLINE | WM8991_DIS_OUT3 | | ||
1229 | WM8991_DIS_OUT4 | WM8991_DIS_LOUT | | ||
1230 | WM8991_DIS_ROUT); | ||
1231 | |||
1232 | /* Disable VREF */ | ||
1233 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, 0x0); | ||
1234 | |||
1235 | /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ | ||
1236 | snd_soc_write(codec, WM8991_ANTIPOP2, 0x0); | ||
1237 | codec->cache_sync = 1; | ||
1238 | break; | ||
1239 | } | ||
1240 | |||
1241 | codec->dapm.bias_level = level; | ||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | static int wm8991_suspend(struct snd_soc_codec *codec, pm_message_t state) | ||
1246 | { | ||
1247 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | static int wm8991_resume(struct snd_soc_codec *codec) | ||
1252 | { | ||
1253 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | /* power down chip */ | ||
1258 | static int wm8991_remove(struct snd_soc_codec *codec) | ||
1259 | { | ||
1260 | wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1261 | return 0; | ||
1262 | } | ||
1263 | |||
1264 | static int wm8991_probe(struct snd_soc_codec *codec) | ||
1265 | { | ||
1266 | struct wm8991_priv *wm8991; | ||
1267 | int ret; | ||
1268 | unsigned int reg; | ||
1269 | |||
1270 | wm8991 = snd_soc_codec_get_drvdata(codec); | ||
1271 | |||
1272 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8991->control_type); | ||
1273 | if (ret < 0) { | ||
1274 | dev_err(codec->dev, "Failed to set cache i/o: %d\n", ret); | ||
1275 | return ret; | ||
1276 | } | ||
1277 | |||
1278 | ret = wm8991_reset(codec); | ||
1279 | if (ret < 0) { | ||
1280 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
1281 | return ret; | ||
1282 | } | ||
1283 | |||
1284 | wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1285 | |||
1286 | reg = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_4); | ||
1287 | snd_soc_write(codec, WM8991_AUDIO_INTERFACE_4, reg | WM8991_ALRCGPIO1); | ||
1288 | |||
1289 | reg = snd_soc_read(codec, WM8991_GPIO1_GPIO2) & | ||
1290 | ~WM8991_GPIO1_SEL_MASK; | ||
1291 | snd_soc_write(codec, WM8991_GPIO1_GPIO2, reg | 1); | ||
1292 | |||
1293 | reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1); | ||
1294 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, reg | WM8991_VREF_ENA| | ||
1295 | WM8991_VMID_MODE_MASK); | ||
1296 | |||
1297 | reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2); | ||
1298 | snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg | WM8991_OPCLK_ENA); | ||
1299 | |||
1300 | snd_soc_write(codec, WM8991_DAC_CTRL, 0); | ||
1301 | snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1302 | snd_soc_write(codec, WM8991_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); | ||
1303 | |||
1304 | snd_soc_add_controls(codec, wm8991_snd_controls, | ||
1305 | ARRAY_SIZE(wm8991_snd_controls)); | ||
1306 | |||
1307 | snd_soc_dapm_new_controls(&codec->dapm, wm8991_dapm_widgets, | ||
1308 | ARRAY_SIZE(wm8991_dapm_widgets)); | ||
1309 | snd_soc_dapm_add_routes(&codec->dapm, audio_map, | ||
1310 | ARRAY_SIZE(audio_map)); | ||
1311 | return 0; | ||
1312 | } | ||
1313 | |||
1314 | #define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1315 | SNDRV_PCM_FMTBIT_S24_LE) | ||
1316 | |||
1317 | static struct snd_soc_dai_ops wm8991_ops = { | ||
1318 | .hw_params = wm8991_hw_params, | ||
1319 | .digital_mute = wm8991_mute, | ||
1320 | .set_fmt = wm8991_set_dai_fmt, | ||
1321 | .set_clkdiv = wm8991_set_dai_clkdiv, | ||
1322 | .set_pll = wm8991_set_dai_pll | ||
1323 | }; | ||
1324 | |||
1325 | /* | ||
1326 | * The WM8991 supports 2 different and mutually exclusive DAI | ||
1327 | * configurations. | ||
1328 | * | ||
1329 | * 1. ADC/DAC on Primary Interface | ||
1330 | * 2. ADC on Primary Interface/DAC on secondary | ||
1331 | */ | ||
1332 | static struct snd_soc_dai_driver wm8991_dai = { | ||
1333 | /* ADC/DAC on primary */ | ||
1334 | .name = "wm8991", | ||
1335 | .id = 1, | ||
1336 | .playback = { | ||
1337 | .stream_name = "Playback", | ||
1338 | .channels_min = 1, | ||
1339 | .channels_max = 2, | ||
1340 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
1341 | .formats = WM8991_FORMATS | ||
1342 | }, | ||
1343 | .capture = { | ||
1344 | .stream_name = "Capture", | ||
1345 | .channels_min = 1, | ||
1346 | .channels_max = 2, | ||
1347 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
1348 | .formats = WM8991_FORMATS | ||
1349 | }, | ||
1350 | .ops = &wm8991_ops | ||
1351 | }; | ||
1352 | |||
1353 | static struct snd_soc_codec_driver soc_codec_dev_wm8991 = { | ||
1354 | .probe = wm8991_probe, | ||
1355 | .remove = wm8991_remove, | ||
1356 | .suspend = wm8991_suspend, | ||
1357 | .resume = wm8991_resume, | ||
1358 | .set_bias_level = wm8991_set_bias_level, | ||
1359 | .reg_cache_size = WM8991_MAX_REGISTER + 1, | ||
1360 | .reg_word_size = sizeof(u16), | ||
1361 | .reg_cache_default = wm8991_reg_defs | ||
1362 | }; | ||
1363 | |||
1364 | static __devinit int wm8991_i2c_probe(struct i2c_client *i2c, | ||
1365 | const struct i2c_device_id *id) | ||
1366 | { | ||
1367 | struct wm8991_priv *wm8991; | ||
1368 | int ret; | ||
1369 | |||
1370 | wm8991 = kzalloc(sizeof *wm8991, GFP_KERNEL); | ||
1371 | if (!wm8991) | ||
1372 | return -ENOMEM; | ||
1373 | |||
1374 | wm8991->control_type = SND_SOC_I2C; | ||
1375 | i2c_set_clientdata(i2c, wm8991); | ||
1376 | |||
1377 | ret = snd_soc_register_codec(&i2c->dev, | ||
1378 | &soc_codec_dev_wm8991, &wm8991_dai, 1); | ||
1379 | if (ret < 0) | ||
1380 | kfree(wm8991); | ||
1381 | return ret; | ||
1382 | } | ||
1383 | |||
1384 | static __devexit int wm8991_i2c_remove(struct i2c_client *client) | ||
1385 | { | ||
1386 | snd_soc_unregister_codec(&client->dev); | ||
1387 | kfree(i2c_get_clientdata(client)); | ||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | static const struct i2c_device_id wm8991_i2c_id[] = { | ||
1392 | { "wm8991", 0 }, | ||
1393 | { } | ||
1394 | }; | ||
1395 | MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id); | ||
1396 | |||
1397 | static struct i2c_driver wm8991_i2c_driver = { | ||
1398 | .driver = { | ||
1399 | .name = "wm8991", | ||
1400 | .owner = THIS_MODULE, | ||
1401 | }, | ||
1402 | .probe = wm8991_i2c_probe, | ||
1403 | .remove = __devexit_p(wm8991_i2c_remove), | ||
1404 | .id_table = wm8991_i2c_id, | ||
1405 | }; | ||
1406 | |||
1407 | static int __init wm8991_modinit(void) | ||
1408 | { | ||
1409 | int ret; | ||
1410 | ret = i2c_add_driver(&wm8991_i2c_driver); | ||
1411 | if (ret != 0) { | ||
1412 | printk(KERN_ERR "Failed to register WM8991 I2C driver: %d\n", | ||
1413 | ret); | ||
1414 | } | ||
1415 | return 0; | ||
1416 | } | ||
1417 | module_init(wm8991_modinit); | ||
1418 | |||
1419 | static void __exit wm8991_exit(void) | ||
1420 | { | ||
1421 | i2c_del_driver(&wm8991_i2c_driver); | ||
1422 | } | ||
1423 | module_exit(wm8991_exit); | ||
1424 | |||
1425 | MODULE_DESCRIPTION("ASoC WM8991 driver"); | ||
1426 | MODULE_AUTHOR("Graeme Gregory"); | ||
1427 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8991.h b/sound/soc/codecs/wm8991.h new file mode 100644 index 000000000000..8a942efd18a5 --- /dev/null +++ b/sound/soc/codecs/wm8991.h | |||
@@ -0,0 +1,833 @@ | |||
1 | /* | ||
2 | * wm8991.h -- audio driver for WM8991 | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #ifndef _WM8991_H | ||
15 | #define _WM8991_H | ||
16 | |||
17 | /* | ||
18 | * Register values. | ||
19 | */ | ||
20 | #define WM8991_RESET 0x00 | ||
21 | #define WM8991_POWER_MANAGEMENT_1 0x01 | ||
22 | #define WM8991_POWER_MANAGEMENT_2 0x02 | ||
23 | #define WM8991_POWER_MANAGEMENT_3 0x03 | ||
24 | #define WM8991_AUDIO_INTERFACE_1 0x04 | ||
25 | #define WM8991_AUDIO_INTERFACE_2 0x05 | ||
26 | #define WM8991_CLOCKING_1 0x06 | ||
27 | #define WM8991_CLOCKING_2 0x07 | ||
28 | #define WM8991_AUDIO_INTERFACE_3 0x08 | ||
29 | #define WM8991_AUDIO_INTERFACE_4 0x09 | ||
30 | #define WM8991_DAC_CTRL 0x0A | ||
31 | #define WM8991_LEFT_DAC_DIGITAL_VOLUME 0x0B | ||
32 | #define WM8991_RIGHT_DAC_DIGITAL_VOLUME 0x0C | ||
33 | #define WM8991_DIGITAL_SIDE_TONE 0x0D | ||
34 | #define WM8991_ADC_CTRL 0x0E | ||
35 | #define WM8991_LEFT_ADC_DIGITAL_VOLUME 0x0F | ||
36 | #define WM8991_RIGHT_ADC_DIGITAL_VOLUME 0x10 | ||
37 | #define WM8991_GPIO_CTRL_1 0x12 | ||
38 | #define WM8991_GPIO1_GPIO2 0x13 | ||
39 | #define WM8991_GPIO3_GPIO4 0x14 | ||
40 | #define WM8991_GPIO5_GPIO6 0x15 | ||
41 | #define WM8991_GPIOCTRL_2 0x16 | ||
42 | #define WM8991_GPIO_POL 0x17 | ||
43 | #define WM8991_LEFT_LINE_INPUT_1_2_VOLUME 0x18 | ||
44 | #define WM8991_LEFT_LINE_INPUT_3_4_VOLUME 0x19 | ||
45 | #define WM8991_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A | ||
46 | #define WM8991_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B | ||
47 | #define WM8991_LEFT_OUTPUT_VOLUME 0x1C | ||
48 | #define WM8991_RIGHT_OUTPUT_VOLUME 0x1D | ||
49 | #define WM8991_LINE_OUTPUTS_VOLUME 0x1E | ||
50 | #define WM8991_OUT3_4_VOLUME 0x1F | ||
51 | #define WM8991_LEFT_OPGA_VOLUME 0x20 | ||
52 | #define WM8991_RIGHT_OPGA_VOLUME 0x21 | ||
53 | #define WM8991_SPEAKER_VOLUME 0x22 | ||
54 | #define WM8991_CLASSD1 0x23 | ||
55 | #define WM8991_CLASSD3 0x25 | ||
56 | #define WM8991_INPUT_MIXER1 0x27 | ||
57 | #define WM8991_INPUT_MIXER2 0x28 | ||
58 | #define WM8991_INPUT_MIXER3 0x29 | ||
59 | #define WM8991_INPUT_MIXER4 0x2A | ||
60 | #define WM8991_INPUT_MIXER5 0x2B | ||
61 | #define WM8991_INPUT_MIXER6 0x2C | ||
62 | #define WM8991_OUTPUT_MIXER1 0x2D | ||
63 | #define WM8991_OUTPUT_MIXER2 0x2E | ||
64 | #define WM8991_OUTPUT_MIXER3 0x2F | ||
65 | #define WM8991_OUTPUT_MIXER4 0x30 | ||
66 | #define WM8991_OUTPUT_MIXER5 0x31 | ||
67 | #define WM8991_OUTPUT_MIXER6 0x32 | ||
68 | #define WM8991_OUT3_4_MIXER 0x33 | ||
69 | #define WM8991_LINE_MIXER1 0x34 | ||
70 | #define WM8991_LINE_MIXER2 0x35 | ||
71 | #define WM8991_SPEAKER_MIXER 0x36 | ||
72 | #define WM8991_ADDITIONAL_CONTROL 0x37 | ||
73 | #define WM8991_ANTIPOP1 0x38 | ||
74 | #define WM8991_ANTIPOP2 0x39 | ||
75 | #define WM8991_MICBIAS 0x3A | ||
76 | #define WM8991_PLL1 0x3C | ||
77 | #define WM8991_PLL2 0x3D | ||
78 | #define WM8991_PLL3 0x3E | ||
79 | #define WM8991_INTDRIVBITS 0x3F | ||
80 | |||
81 | #define WM8991_REGISTER_COUNT 60 | ||
82 | #define WM8991_MAX_REGISTER 0x3F | ||
83 | |||
84 | /* | ||
85 | * Field Definitions. | ||
86 | */ | ||
87 | |||
88 | /* | ||
89 | * R0 (0x00) - Reset | ||
90 | */ | ||
91 | #define WM8991_SW_RESET_CHIP_ID_MASK 0xFFFF /* SW_RESET_CHIP_ID - [15:0] */ | ||
92 | |||
93 | /* | ||
94 | * R1 (0x01) - Power Management (1) | ||
95 | */ | ||
96 | #define WM8991_SPK_ENA 0x1000 /* SPK_ENA */ | ||
97 | #define WM8991_SPK_ENA_BIT 12 | ||
98 | #define WM8991_OUT3_ENA 0x0800 /* OUT3_ENA */ | ||
99 | #define WM8991_OUT3_ENA_BIT 11 | ||
100 | #define WM8991_OUT4_ENA 0x0400 /* OUT4_ENA */ | ||
101 | #define WM8991_OUT4_ENA_BIT 10 | ||
102 | #define WM8991_LOUT_ENA 0x0200 /* LOUT_ENA */ | ||
103 | #define WM8991_LOUT_ENA_BIT 9 | ||
104 | #define WM8991_ROUT_ENA 0x0100 /* ROUT_ENA */ | ||
105 | #define WM8991_ROUT_ENA_BIT 8 | ||
106 | #define WM8991_MICBIAS_ENA 0x0010 /* MICBIAS_ENA */ | ||
107 | #define WM8991_MICBIAS_ENA_BIT 4 | ||
108 | #define WM8991_VMID_MODE_MASK 0x0006 /* VMID_MODE - [2:1] */ | ||
109 | #define WM8991_VREF_ENA 0x0001 /* VREF_ENA */ | ||
110 | #define WM8991_VREF_ENA_BIT 0 | ||
111 | |||
112 | /* | ||
113 | * R2 (0x02) - Power Management (2) | ||
114 | */ | ||
115 | #define WM8991_PLL_ENA 0x8000 /* PLL_ENA */ | ||
116 | #define WM8991_PLL_ENA_BIT 15 | ||
117 | #define WM8991_TSHUT_ENA 0x4000 /* TSHUT_ENA */ | ||
118 | #define WM8991_TSHUT_ENA_BIT 14 | ||
119 | #define WM8991_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */ | ||
120 | #define WM8991_TSHUT_OPDIS_BIT 13 | ||
121 | #define WM8991_OPCLK_ENA 0x0800 /* OPCLK_ENA */ | ||
122 | #define WM8991_OPCLK_ENA_BIT 11 | ||
123 | #define WM8991_AINL_ENA 0x0200 /* AINL_ENA */ | ||
124 | #define WM8991_AINL_ENA_BIT 9 | ||
125 | #define WM8991_AINR_ENA 0x0100 /* AINR_ENA */ | ||
126 | #define WM8991_AINR_ENA_BIT 8 | ||
127 | #define WM8991_LIN34_ENA 0x0080 /* LIN34_ENA */ | ||
128 | #define WM8991_LIN34_ENA_BIT 7 | ||
129 | #define WM8991_LIN12_ENA 0x0040 /* LIN12_ENA */ | ||
130 | #define WM8991_LIN12_ENA_BIT 6 | ||
131 | #define WM8991_RIN34_ENA 0x0020 /* RIN34_ENA */ | ||
132 | #define WM8991_RIN34_ENA_BIT 5 | ||
133 | #define WM8991_RIN12_ENA 0x0010 /* RIN12_ENA */ | ||
134 | #define WM8991_RIN12_ENA_BIT 4 | ||
135 | #define WM8991_ADCL_ENA 0x0002 /* ADCL_ENA */ | ||
136 | #define WM8991_ADCL_ENA_BIT 1 | ||
137 | #define WM8991_ADCR_ENA 0x0001 /* ADCR_ENA */ | ||
138 | #define WM8991_ADCR_ENA_BIT 0 | ||
139 | |||
140 | /* | ||
141 | * R3 (0x03) - Power Management (3) | ||
142 | */ | ||
143 | #define WM8991_LON_ENA 0x2000 /* LON_ENA */ | ||
144 | #define WM8991_LON_ENA_BIT 13 | ||
145 | #define WM8991_LOP_ENA 0x1000 /* LOP_ENA */ | ||
146 | #define WM8991_LOP_ENA_BIT 12 | ||
147 | #define WM8991_RON_ENA 0x0800 /* RON_ENA */ | ||
148 | #define WM8991_RON_ENA_BIT 11 | ||
149 | #define WM8991_ROP_ENA 0x0400 /* ROP_ENA */ | ||
150 | #define WM8991_ROP_ENA_BIT 10 | ||
151 | #define WM8991_LOPGA_ENA 0x0080 /* LOPGA_ENA */ | ||
152 | #define WM8991_LOPGA_ENA_BIT 7 | ||
153 | #define WM8991_ROPGA_ENA 0x0040 /* ROPGA_ENA */ | ||
154 | #define WM8991_ROPGA_ENA_BIT 6 | ||
155 | #define WM8991_LOMIX_ENA 0x0020 /* LOMIX_ENA */ | ||
156 | #define WM8991_LOMIX_ENA_BIT 5 | ||
157 | #define WM8991_ROMIX_ENA 0x0010 /* ROMIX_ENA */ | ||
158 | #define WM8991_ROMIX_ENA_BIT 4 | ||
159 | #define WM8991_DACL_ENA 0x0002 /* DACL_ENA */ | ||
160 | #define WM8991_DACL_ENA_BIT 1 | ||
161 | #define WM8991_DACR_ENA 0x0001 /* DACR_ENA */ | ||
162 | #define WM8991_DACR_ENA_BIT 0 | ||
163 | |||
164 | /* | ||
165 | * R4 (0x04) - Audio Interface (1) | ||
166 | */ | ||
167 | #define WM8991_AIFADCL_SRC 0x8000 /* AIFADCL_SRC */ | ||
168 | #define WM8991_AIFADCR_SRC 0x4000 /* AIFADCR_SRC */ | ||
169 | #define WM8991_AIFADC_TDM 0x2000 /* AIFADC_TDM */ | ||
170 | #define WM8991_AIFADC_TDM_CHAN 0x1000 /* AIFADC_TDM_CHAN */ | ||
171 | #define WM8991_AIF_BCLK_INV 0x0100 /* AIF_BCLK_INV */ | ||
172 | #define WM8991_AIF_LRCLK_INV 0x0080 /* AIF_LRCLK_INV */ | ||
173 | #define WM8991_AIF_WL_MASK 0x0060 /* AIF_WL - [6:5] */ | ||
174 | #define WM8991_AIF_WL_16BITS (0 << 5) | ||
175 | #define WM8991_AIF_WL_20BITS (1 << 5) | ||
176 | #define WM8991_AIF_WL_24BITS (2 << 5) | ||
177 | #define WM8991_AIF_WL_32BITS (3 << 5) | ||
178 | #define WM8991_AIF_FMT_MASK 0x0018 /* AIF_FMT - [4:3] */ | ||
179 | #define WM8991_AIF_TMF_RIGHTJ (0 << 3) | ||
180 | #define WM8991_AIF_TMF_LEFTJ (1 << 3) | ||
181 | #define WM8991_AIF_TMF_I2S (2 << 3) | ||
182 | #define WM8991_AIF_TMF_DSP (3 << 3) | ||
183 | |||
184 | /* | ||
185 | * R5 (0x05) - Audio Interface (2) | ||
186 | */ | ||
187 | #define WM8991_DACL_SRC 0x8000 /* DACL_SRC */ | ||
188 | #define WM8991_DACR_SRC 0x4000 /* DACR_SRC */ | ||
189 | #define WM8991_AIFDAC_TDM 0x2000 /* AIFDAC_TDM */ | ||
190 | #define WM8991_AIFDAC_TDM_CHAN 0x1000 /* AIFDAC_TDM_CHAN */ | ||
191 | #define WM8991_DAC_BOOST_MASK 0x0C00 /* DAC_BOOST - [11:10] */ | ||
192 | #define WM8991_DAC_COMP 0x0010 /* DAC_COMP */ | ||
193 | #define WM8991_DAC_COMPMODE 0x0008 /* DAC_COMPMODE */ | ||
194 | #define WM8991_ADC_COMP 0x0004 /* ADC_COMP */ | ||
195 | #define WM8991_ADC_COMPMODE 0x0002 /* ADC_COMPMODE */ | ||
196 | #define WM8991_LOOPBACK 0x0001 /* LOOPBACK */ | ||
197 | |||
198 | /* | ||
199 | * R6 (0x06) - Clocking (1) | ||
200 | */ | ||
201 | #define WM8991_TOCLK_RATE 0x8000 /* TOCLK_RATE */ | ||
202 | #define WM8991_TOCLK_ENA 0x4000 /* TOCLK_ENA */ | ||
203 | #define WM8991_OPCLKDIV_MASK 0x1E00 /* OPCLKDIV - [12:9] */ | ||
204 | #define WM8991_DCLKDIV_MASK 0x01C0 /* DCLKDIV - [8:6] */ | ||
205 | #define WM8991_BCLK_DIV_MASK 0x001E /* BCLK_DIV - [4:1] */ | ||
206 | #define WM8991_BCLK_DIV_1 (0x0 << 1) | ||
207 | #define WM8991_BCLK_DIV_1_5 (0x1 << 1) | ||
208 | #define WM8991_BCLK_DIV_2 (0x2 << 1) | ||
209 | #define WM8991_BCLK_DIV_3 (0x3 << 1) | ||
210 | #define WM8991_BCLK_DIV_4 (0x4 << 1) | ||
211 | #define WM8991_BCLK_DIV_5_5 (0x5 << 1) | ||
212 | #define WM8991_BCLK_DIV_6 (0x6 << 1) | ||
213 | #define WM8991_BCLK_DIV_8 (0x7 << 1) | ||
214 | #define WM8991_BCLK_DIV_11 (0x8 << 1) | ||
215 | #define WM8991_BCLK_DIV_12 (0x9 << 1) | ||
216 | #define WM8991_BCLK_DIV_16 (0xA << 1) | ||
217 | #define WM8991_BCLK_DIV_22 (0xB << 1) | ||
218 | #define WM8991_BCLK_DIV_24 (0xC << 1) | ||
219 | #define WM8991_BCLK_DIV_32 (0xD << 1) | ||
220 | #define WM8991_BCLK_DIV_44 (0xE << 1) | ||
221 | #define WM8991_BCLK_DIV_48 (0xF << 1) | ||
222 | |||
223 | /* | ||
224 | * R7 (0x07) - Clocking (2) | ||
225 | */ | ||
226 | #define WM8991_MCLK_SRC 0x8000 /* MCLK_SRC */ | ||
227 | #define WM8991_SYSCLK_SRC 0x4000 /* SYSCLK_SRC */ | ||
228 | #define WM8991_CLK_FORCE 0x2000 /* CLK_FORCE */ | ||
229 | #define WM8991_MCLK_DIV_MASK 0x1800 /* MCLK_DIV - [12:11] */ | ||
230 | #define WM8991_MCLK_DIV_1 (0 << 11) | ||
231 | #define WM8991_MCLK_DIV_2 ( 2 << 11) | ||
232 | #define WM8991_MCLK_INV 0x0400 /* MCLK_INV */ | ||
233 | #define WM8991_ADC_CLKDIV_MASK 0x00E0 /* ADC_CLKDIV - [7:5] */ | ||
234 | #define WM8991_ADC_CLKDIV_1 (0 << 5) | ||
235 | #define WM8991_ADC_CLKDIV_1_5 (1 << 5) | ||
236 | #define WM8991_ADC_CLKDIV_2 (2 << 5) | ||
237 | #define WM8991_ADC_CLKDIV_3 (3 << 5) | ||
238 | #define WM8991_ADC_CLKDIV_4 (4 << 5) | ||
239 | #define WM8991_ADC_CLKDIV_5_5 (5 << 5) | ||
240 | #define WM8991_ADC_CLKDIV_6 (6 << 5) | ||
241 | #define WM8991_DAC_CLKDIV_MASK 0x001C /* DAC_CLKDIV - [4:2] */ | ||
242 | #define WM8991_DAC_CLKDIV_1 (0 << 2) | ||
243 | #define WM8991_DAC_CLKDIV_1_5 (1 << 2) | ||
244 | #define WM8991_DAC_CLKDIV_2 (2 << 2) | ||
245 | #define WM8991_DAC_CLKDIV_3 (3 << 2) | ||
246 | #define WM8991_DAC_CLKDIV_4 (4 << 2) | ||
247 | #define WM8991_DAC_CLKDIV_5_5 (5 << 2) | ||
248 | #define WM8991_DAC_CLKDIV_6 (6 << 2) | ||
249 | |||
250 | /* | ||
251 | * R8 (0x08) - Audio Interface (3) | ||
252 | */ | ||
253 | #define WM8991_AIF_MSTR1 0x8000 /* AIF_MSTR1 */ | ||
254 | #define WM8991_AIF_MSTR2 0x4000 /* AIF_MSTR2 */ | ||
255 | #define WM8991_AIF_SEL 0x2000 /* AIF_SEL */ | ||
256 | #define WM8991_ADCLRC_DIR 0x0800 /* ADCLRC_DIR */ | ||
257 | #define WM8991_ADCLRC_RATE_MASK 0x07FF /* ADCLRC_RATE - [10:0] */ | ||
258 | |||
259 | /* | ||
260 | * R9 (0x09) - Audio Interface (4) | ||
261 | */ | ||
262 | #define WM8991_ALRCGPIO1 0x8000 /* ALRCGPIO1 */ | ||
263 | #define WM8991_ALRCBGPIO6 0x4000 /* ALRCBGPIO6 */ | ||
264 | #define WM8991_AIF_TRIS 0x2000 /* AIF_TRIS */ | ||
265 | #define WM8991_DACLRC_DIR 0x0800 /* DACLRC_DIR */ | ||
266 | #define WM8991_DACLRC_RATE_MASK 0x07FF /* DACLRC_RATE - [10:0] */ | ||
267 | |||
268 | /* | ||
269 | * R10 (0x0A) - DAC CTRL | ||
270 | */ | ||
271 | #define WM8991_AIF_LRCLKRATE 0x0400 /* AIF_LRCLKRATE */ | ||
272 | #define WM8991_DAC_MONO 0x0200 /* DAC_MONO */ | ||
273 | #define WM8991_DAC_SB_FILT 0x0100 /* DAC_SB_FILT */ | ||
274 | #define WM8991_DAC_MUTERATE 0x0080 /* DAC_MUTERATE */ | ||
275 | #define WM8991_DAC_MUTEMODE 0x0040 /* DAC_MUTEMODE */ | ||
276 | #define WM8991_DEEMP_MASK 0x0030 /* DEEMP - [5:4] */ | ||
277 | #define WM8991_DAC_MUTE 0x0004 /* DAC_MUTE */ | ||
278 | #define WM8991_DACL_DATINV 0x0002 /* DACL_DATINV */ | ||
279 | #define WM8991_DACR_DATINV 0x0001 /* DACR_DATINV */ | ||
280 | |||
281 | /* | ||
282 | * R11 (0x0B) - Left DAC Digital Volume | ||
283 | */ | ||
284 | #define WM8991_DAC_VU 0x0100 /* DAC_VU */ | ||
285 | #define WM8991_DACL_VOL_MASK 0x00FF /* DACL_VOL - [7:0] */ | ||
286 | #define WM8991_DACL_VOL_SHIFT 0 | ||
287 | /* | ||
288 | * R12 (0x0C) - Right DAC Digital Volume | ||
289 | */ | ||
290 | #define WM8991_DAC_VU 0x0100 /* DAC_VU */ | ||
291 | #define WM8991_DACR_VOL_MASK 0x00FF /* DACR_VOL - [7:0] */ | ||
292 | #define WM8991_DACR_VOL_SHIFT 0 | ||
293 | /* | ||
294 | * R13 (0x0D) - Digital Side Tone | ||
295 | */ | ||
296 | #define WM8991_ADCL_DAC_SVOL_MASK 0x0F /* ADCL_DAC_SVOL - [12:9] */ | ||
297 | #define WM8991_ADCL_DAC_SVOL_SHIFT 9 | ||
298 | #define WM8991_ADCR_DAC_SVOL_MASK 0x0F /* ADCR_DAC_SVOL - [8:5] */ | ||
299 | #define WM8991_ADCR_DAC_SVOL_SHIFT 5 | ||
300 | #define WM8991_ADC_TO_DACL_MASK 0x03 /* ADC_TO_DACL - [3:2] */ | ||
301 | #define WM8991_ADC_TO_DACL_SHIFT 2 | ||
302 | #define WM8991_ADC_TO_DACR_MASK 0x03 /* ADC_TO_DACR - [1:0] */ | ||
303 | #define WM8991_ADC_TO_DACR_SHIFT 0 | ||
304 | |||
305 | /* | ||
306 | * R14 (0x0E) - ADC CTRL | ||
307 | */ | ||
308 | #define WM8991_ADC_HPF_ENA 0x0100 /* ADC_HPF_ENA */ | ||
309 | #define WM8991_ADC_HPF_ENA_BIT 8 | ||
310 | #define WM8991_ADC_HPF_CUT_MASK 0x03 /* ADC_HPF_CUT - [6:5] */ | ||
311 | #define WM8991_ADC_HPF_CUT_SHIFT 5 | ||
312 | #define WM8991_ADCL_DATINV 0x0002 /* ADCL_DATINV */ | ||
313 | #define WM8991_ADCL_DATINV_BIT 1 | ||
314 | #define WM8991_ADCR_DATINV 0x0001 /* ADCR_DATINV */ | ||
315 | #define WM8991_ADCR_DATINV_BIT 0 | ||
316 | |||
317 | /* | ||
318 | * R15 (0x0F) - Left ADC Digital Volume | ||
319 | */ | ||
320 | #define WM8991_ADC_VU 0x0100 /* ADC_VU */ | ||
321 | #define WM8991_ADCL_VOL_MASK 0x00FF /* ADCL_VOL - [7:0] */ | ||
322 | #define WM8991_ADCL_VOL_SHIFT 0 | ||
323 | |||
324 | /* | ||
325 | * R16 (0x10) - Right ADC Digital Volume | ||
326 | */ | ||
327 | #define WM8991_ADC_VU 0x0100 /* ADC_VU */ | ||
328 | #define WM8991_ADCR_VOL_MASK 0x00FF /* ADCR_VOL - [7:0] */ | ||
329 | #define WM8991_ADCR_VOL_SHIFT 0 | ||
330 | |||
331 | /* | ||
332 | * R18 (0x12) - GPIO CTRL 1 | ||
333 | */ | ||
334 | #define WM8991_IRQ 0x1000 /* IRQ */ | ||
335 | #define WM8991_TEMPOK 0x0800 /* TEMPOK */ | ||
336 | #define WM8991_MICSHRT 0x0400 /* MICSHRT */ | ||
337 | #define WM8991_MICDET 0x0200 /* MICDET */ | ||
338 | #define WM8991_PLL_LCK 0x0100 /* PLL_LCK */ | ||
339 | #define WM8991_GPI8_STATUS 0x0080 /* GPI8_STATUS */ | ||
340 | #define WM8991_GPI7_STATUS 0x0040 /* GPI7_STATUS */ | ||
341 | #define WM8991_GPIO6_STATUS 0x0020 /* GPIO6_STATUS */ | ||
342 | #define WM8991_GPIO5_STATUS 0x0010 /* GPIO5_STATUS */ | ||
343 | #define WM8991_GPIO4_STATUS 0x0008 /* GPIO4_STATUS */ | ||
344 | #define WM8991_GPIO3_STATUS 0x0004 /* GPIO3_STATUS */ | ||
345 | #define WM8991_GPIO2_STATUS 0x0002 /* GPIO2_STATUS */ | ||
346 | #define WM8991_GPIO1_STATUS 0x0001 /* GPIO1_STATUS */ | ||
347 | |||
348 | /* | ||
349 | * R19 (0x13) - GPIO1 & GPIO2 | ||
350 | */ | ||
351 | #define WM8991_GPIO2_DEB_ENA 0x8000 /* GPIO2_DEB_ENA */ | ||
352 | #define WM8991_GPIO2_IRQ_ENA 0x4000 /* GPIO2_IRQ_ENA */ | ||
353 | #define WM8991_GPIO2_PU 0x2000 /* GPIO2_PU */ | ||
354 | #define WM8991_GPIO2_PD 0x1000 /* GPIO2_PD */ | ||
355 | #define WM8991_GPIO2_SEL_MASK 0x0F00 /* GPIO2_SEL - [11:8] */ | ||
356 | #define WM8991_GPIO1_DEB_ENA 0x0080 /* GPIO1_DEB_ENA */ | ||
357 | #define WM8991_GPIO1_IRQ_ENA 0x0040 /* GPIO1_IRQ_ENA */ | ||
358 | #define WM8991_GPIO1_PU 0x0020 /* GPIO1_PU */ | ||
359 | #define WM8991_GPIO1_PD 0x0010 /* GPIO1_PD */ | ||
360 | #define WM8991_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */ | ||
361 | |||
362 | /* | ||
363 | * R20 (0x14) - GPIO3 & GPIO4 | ||
364 | */ | ||
365 | #define WM8991_GPIO4_DEB_ENA 0x8000 /* GPIO4_DEB_ENA */ | ||
366 | #define WM8991_GPIO4_IRQ_ENA 0x4000 /* GPIO4_IRQ_ENA */ | ||
367 | #define WM8991_GPIO4_PU 0x2000 /* GPIO4_PU */ | ||
368 | #define WM8991_GPIO4_PD 0x1000 /* GPIO4_PD */ | ||
369 | #define WM8991_GPIO4_SEL_MASK 0x0F00 /* GPIO4_SEL - [11:8] */ | ||
370 | #define WM8991_GPIO3_DEB_ENA 0x0080 /* GPIO3_DEB_ENA */ | ||
371 | #define WM8991_GPIO3_IRQ_ENA 0x0040 /* GPIO3_IRQ_ENA */ | ||
372 | #define WM8991_GPIO3_PU 0x0020 /* GPIO3_PU */ | ||
373 | #define WM8991_GPIO3_PD 0x0010 /* GPIO3_PD */ | ||
374 | #define WM8991_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */ | ||
375 | |||
376 | /* | ||
377 | * R21 (0x15) - GPIO5 & GPIO6 | ||
378 | */ | ||
379 | #define WM8991_GPIO6_DEB_ENA 0x8000 /* GPIO6_DEB_ENA */ | ||
380 | #define WM8991_GPIO6_IRQ_ENA 0x4000 /* GPIO6_IRQ_ENA */ | ||
381 | #define WM8991_GPIO6_PU 0x2000 /* GPIO6_PU */ | ||
382 | #define WM8991_GPIO6_PD 0x1000 /* GPIO6_PD */ | ||
383 | #define WM8991_GPIO6_SEL_MASK 0x0F00 /* GPIO6_SEL - [11:8] */ | ||
384 | #define WM8991_GPIO5_DEB_ENA 0x0080 /* GPIO5_DEB_ENA */ | ||
385 | #define WM8991_GPIO5_IRQ_ENA 0x0040 /* GPIO5_IRQ_ENA */ | ||
386 | #define WM8991_GPIO5_PU 0x0020 /* GPIO5_PU */ | ||
387 | #define WM8991_GPIO5_PD 0x0010 /* GPIO5_PD */ | ||
388 | #define WM8991_GPIO5_SEL_MASK 0x000F /* GPIO5_SEL - [3:0] */ | ||
389 | |||
390 | /* | ||
391 | * R22 (0x16) - GPIOCTRL 2 | ||
392 | */ | ||
393 | #define WM8991_RD_3W_ENA 0x8000 /* RD_3W_ENA */ | ||
394 | #define WM8991_MODE_3W4W 0x4000 /* MODE_3W4W */ | ||
395 | #define WM8991_TEMPOK_IRQ_ENA 0x0800 /* TEMPOK_IRQ_ENA */ | ||
396 | #define WM8991_MICSHRT_IRQ_ENA 0x0400 /* MICSHRT_IRQ_ENA */ | ||
397 | #define WM8991_MICDET_IRQ_ENA 0x0200 /* MICDET_IRQ_ENA */ | ||
398 | #define WM8991_PLL_LCK_IRQ_ENA 0x0100 /* PLL_LCK_IRQ_ENA */ | ||
399 | #define WM8991_GPI8_DEB_ENA 0x0080 /* GPI8_DEB_ENA */ | ||
400 | #define WM8991_GPI8_IRQ_ENA 0x0040 /* GPI8_IRQ_ENA */ | ||
401 | #define WM8991_GPI8_ENA 0x0010 /* GPI8_ENA */ | ||
402 | #define WM8991_GPI7_DEB_ENA 0x0008 /* GPI7_DEB_ENA */ | ||
403 | #define WM8991_GPI7_IRQ_ENA 0x0004 /* GPI7_IRQ_ENA */ | ||
404 | #define WM8991_GPI7_ENA 0x0001 /* GPI7_ENA */ | ||
405 | |||
406 | /* | ||
407 | * R23 (0x17) - GPIO_POL | ||
408 | */ | ||
409 | #define WM8991_IRQ_INV 0x1000 /* IRQ_INV */ | ||
410 | #define WM8991_TEMPOK_POL 0x0800 /* TEMPOK_POL */ | ||
411 | #define WM8991_MICSHRT_POL 0x0400 /* MICSHRT_POL */ | ||
412 | #define WM8991_MICDET_POL 0x0200 /* MICDET_POL */ | ||
413 | #define WM8991_PLL_LCK_POL 0x0100 /* PLL_LCK_POL */ | ||
414 | #define WM8991_GPI8_POL 0x0080 /* GPI8_POL */ | ||
415 | #define WM8991_GPI7_POL 0x0040 /* GPI7_POL */ | ||
416 | #define WM8991_GPIO6_POL 0x0020 /* GPIO6_POL */ | ||
417 | #define WM8991_GPIO5_POL 0x0010 /* GPIO5_POL */ | ||
418 | #define WM8991_GPIO4_POL 0x0008 /* GPIO4_POL */ | ||
419 | #define WM8991_GPIO3_POL 0x0004 /* GPIO3_POL */ | ||
420 | #define WM8991_GPIO2_POL 0x0002 /* GPIO2_POL */ | ||
421 | #define WM8991_GPIO1_POL 0x0001 /* GPIO1_POL */ | ||
422 | |||
423 | /* | ||
424 | * R24 (0x18) - Left Line Input 1&2 Volume | ||
425 | */ | ||
426 | #define WM8991_IPVU 0x0100 /* IPVU */ | ||
427 | #define WM8991_LI12MUTE 0x0080 /* LI12MUTE */ | ||
428 | #define WM8991_LI12MUTE_BIT 7 | ||
429 | #define WM8991_LI12ZC 0x0040 /* LI12ZC */ | ||
430 | #define WM8991_LI12ZC_BIT 6 | ||
431 | #define WM8991_LIN12VOL_MASK 0x001F /* LIN12VOL - [4:0] */ | ||
432 | #define WM8991_LIN12VOL_SHIFT 0 | ||
433 | /* | ||
434 | * R25 (0x19) - Left Line Input 3&4 Volume | ||
435 | */ | ||
436 | #define WM8991_IPVU 0x0100 /* IPVU */ | ||
437 | #define WM8991_LI34MUTE 0x0080 /* LI34MUTE */ | ||
438 | #define WM8991_LI34MUTE_BIT 7 | ||
439 | #define WM8991_LI34ZC 0x0040 /* LI34ZC */ | ||
440 | #define WM8991_LI34ZC_BIT 6 | ||
441 | #define WM8991_LIN34VOL_MASK 0x001F /* LIN34VOL - [4:0] */ | ||
442 | #define WM8991_LIN34VOL_SHIFT 0 | ||
443 | |||
444 | /* | ||
445 | * R26 (0x1A) - Right Line Input 1&2 Volume | ||
446 | */ | ||
447 | #define WM8991_IPVU 0x0100 /* IPVU */ | ||
448 | #define WM8991_RI12MUTE 0x0080 /* RI12MUTE */ | ||
449 | #define WM8991_RI12MUTE_BIT 7 | ||
450 | #define WM8991_RI12ZC 0x0040 /* RI12ZC */ | ||
451 | #define WM8991_RI12ZC_BIT 6 | ||
452 | #define WM8991_RIN12VOL_MASK 0x001F /* RIN12VOL - [4:0] */ | ||
453 | #define WM8991_RIN12VOL_SHIFT 0 | ||
454 | |||
455 | /* | ||
456 | * R27 (0x1B) - Right Line Input 3&4 Volume | ||
457 | */ | ||
458 | #define WM8991_IPVU 0x0100 /* IPVU */ | ||
459 | #define WM8991_RI34MUTE 0x0080 /* RI34MUTE */ | ||
460 | #define WM8991_RI34MUTE_BIT 7 | ||
461 | #define WM8991_RI34ZC 0x0040 /* RI34ZC */ | ||
462 | #define WM8991_RI34ZC_BIT 6 | ||
463 | #define WM8991_RIN34VOL_MASK 0x001F /* RIN34VOL - [4:0] */ | ||
464 | #define WM8991_RIN34VOL_SHIFT 0 | ||
465 | |||
466 | /* | ||
467 | * R28 (0x1C) - Left Output Volume | ||
468 | */ | ||
469 | #define WM8991_OPVU 0x0100 /* OPVU */ | ||
470 | #define WM8991_LOZC 0x0080 /* LOZC */ | ||
471 | #define WM8991_LOZC_BIT 7 | ||
472 | #define WM8991_LOUTVOL_MASK 0x007F /* LOUTVOL - [6:0] */ | ||
473 | #define WM8991_LOUTVOL_SHIFT 0 | ||
474 | /* | ||
475 | * R29 (0x1D) - Right Output Volume | ||
476 | */ | ||
477 | #define WM8991_OPVU 0x0100 /* OPVU */ | ||
478 | #define WM8991_ROZC 0x0080 /* ROZC */ | ||
479 | #define WM8991_ROZC_BIT 7 | ||
480 | #define WM8991_ROUTVOL_MASK 0x007F /* ROUTVOL - [6:0] */ | ||
481 | #define WM8991_ROUTVOL_SHIFT 0 | ||
482 | /* | ||
483 | * R30 (0x1E) - Line Outputs Volume | ||
484 | */ | ||
485 | #define WM8991_LONMUTE 0x0040 /* LONMUTE */ | ||
486 | #define WM8991_LONMUTE_BIT 6 | ||
487 | #define WM8991_LOPMUTE 0x0020 /* LOPMUTE */ | ||
488 | #define WM8991_LOPMUTE_BIT 5 | ||
489 | #define WM8991_LOATTN 0x0010 /* LOATTN */ | ||
490 | #define WM8991_LOATTN_BIT 4 | ||
491 | #define WM8991_RONMUTE 0x0004 /* RONMUTE */ | ||
492 | #define WM8991_RONMUTE_BIT 2 | ||
493 | #define WM8991_ROPMUTE 0x0002 /* ROPMUTE */ | ||
494 | #define WM8991_ROPMUTE_BIT 1 | ||
495 | #define WM8991_ROATTN 0x0001 /* ROATTN */ | ||
496 | #define WM8991_ROATTN_BIT 0 | ||
497 | |||
498 | /* | ||
499 | * R31 (0x1F) - Out3/4 Volume | ||
500 | */ | ||
501 | #define WM8991_OUT3MUTE 0x0020 /* OUT3MUTE */ | ||
502 | #define WM8991_OUT3MUTE_BIT 5 | ||
503 | #define WM8991_OUT3ATTN 0x0010 /* OUT3ATTN */ | ||
504 | #define WM8991_OUT3ATTN_BIT 4 | ||
505 | #define WM8991_OUT4MUTE 0x0002 /* OUT4MUTE */ | ||
506 | #define WM8991_OUT4MUTE_BIT 1 | ||
507 | #define WM8991_OUT4ATTN 0x0001 /* OUT4ATTN */ | ||
508 | #define WM8991_OUT4ATTN_BIT 0 | ||
509 | |||
510 | /* | ||
511 | * R32 (0x20) - Left OPGA Volume | ||
512 | */ | ||
513 | #define WM8991_OPVU 0x0100 /* OPVU */ | ||
514 | #define WM8991_LOPGAZC 0x0080 /* LOPGAZC */ | ||
515 | #define WM8991_LOPGAZC_BIT 7 | ||
516 | #define WM8991_LOPGAVOL_MASK 0x007F /* LOPGAVOL - [6:0] */ | ||
517 | #define WM8991_LOPGAVOL_SHIFT 0 | ||
518 | |||
519 | /* | ||
520 | * R33 (0x21) - Right OPGA Volume | ||
521 | */ | ||
522 | #define WM8991_OPVU 0x0100 /* OPVU */ | ||
523 | #define WM8991_ROPGAZC 0x0080 /* ROPGAZC */ | ||
524 | #define WM8991_ROPGAZC_BIT 7 | ||
525 | #define WM8991_ROPGAVOL_MASK 0x007F /* ROPGAVOL - [6:0] */ | ||
526 | #define WM8991_ROPGAVOL_SHIFT 0 | ||
527 | /* | ||
528 | * R34 (0x22) - Speaker Volume | ||
529 | */ | ||
530 | #define WM8991_SPKVOL_MASK 0x0003 /* SPKVOL - [1:0] */ | ||
531 | #define WM8991_SPKVOL_SHIFT 0 | ||
532 | |||
533 | /* | ||
534 | * R35 (0x23) - ClassD1 | ||
535 | */ | ||
536 | #define WM8991_CDMODE 0x0100 /* CDMODE */ | ||
537 | #define WM8991_CDMODE_BIT 8 | ||
538 | |||
539 | /* | ||
540 | * R37 (0x25) - ClassD3 | ||
541 | */ | ||
542 | #define WM8991_DCGAIN_MASK 0x0007 /* DCGAIN - [5:3] */ | ||
543 | #define WM8991_DCGAIN_SHIFT 3 | ||
544 | #define WM8991_ACGAIN_MASK 0x0007 /* ACGAIN - [2:0] */ | ||
545 | #define WM8991_ACGAIN_SHIFT 0 | ||
546 | /* | ||
547 | * R39 (0x27) - Input Mixer1 | ||
548 | */ | ||
549 | #define WM8991_AINLMODE_MASK 0x000C /* AINLMODE - [3:2] */ | ||
550 | #define WM8991_AINLMODE_SHIFT 2 | ||
551 | #define WM8991_AINRMODE_MASK 0x0003 /* AINRMODE - [1:0] */ | ||
552 | #define WM8991_AINRMODE_SHIFT 0 | ||
553 | |||
554 | /* | ||
555 | * R40 (0x28) - Input Mixer2 | ||
556 | */ | ||
557 | #define WM8991_LMP4 0x0080 /* LMP4 */ | ||
558 | #define WM8991_LMP4_BIT 7 /* LMP4 */ | ||
559 | #define WM8991_LMN3 0x0040 /* LMN3 */ | ||
560 | #define WM8991_LMN3_BIT 6 /* LMN3 */ | ||
561 | #define WM8991_LMP2 0x0020 /* LMP2 */ | ||
562 | #define WM8991_LMP2_BIT 5 /* LMP2 */ | ||
563 | #define WM8991_LMN1 0x0010 /* LMN1 */ | ||
564 | #define WM8991_LMN1_BIT 4 /* LMN1 */ | ||
565 | #define WM8991_RMP4 0x0008 /* RMP4 */ | ||
566 | #define WM8991_RMP4_BIT 3 /* RMP4 */ | ||
567 | #define WM8991_RMN3 0x0004 /* RMN3 */ | ||
568 | #define WM8991_RMN3_BIT 2 /* RMN3 */ | ||
569 | #define WM8991_RMP2 0x0002 /* RMP2 */ | ||
570 | #define WM8991_RMP2_BIT 1 /* RMP2 */ | ||
571 | #define WM8991_RMN1 0x0001 /* RMN1 */ | ||
572 | #define WM8991_RMN1_BIT 0 /* RMN1 */ | ||
573 | |||
574 | /* | ||
575 | * R41 (0x29) - Input Mixer3 | ||
576 | */ | ||
577 | #define WM8991_L34MNB 0x0100 /* L34MNB */ | ||
578 | #define WM8991_L34MNB_BIT 8 | ||
579 | #define WM8991_L34MNBST 0x0080 /* L34MNBST */ | ||
580 | #define WM8991_L34MNBST_BIT 7 | ||
581 | #define WM8991_L12MNB 0x0020 /* L12MNB */ | ||
582 | #define WM8991_L12MNB_BIT 5 | ||
583 | #define WM8991_L12MNBST 0x0010 /* L12MNBST */ | ||
584 | #define WM8991_L12MNBST_BIT 4 | ||
585 | #define WM8991_LDBVOL_MASK 0x0007 /* LDBVOL - [2:0] */ | ||
586 | #define WM8991_LDBVOL_SHIFT 0 | ||
587 | |||
588 | /* | ||
589 | * R42 (0x2A) - Input Mixer4 | ||
590 | */ | ||
591 | #define WM8991_R34MNB 0x0100 /* R34MNB */ | ||
592 | #define WM8991_R34MNB_BIT 8 | ||
593 | #define WM8991_R34MNBST 0x0080 /* R34MNBST */ | ||
594 | #define WM8991_R34MNBST_BIT 7 | ||
595 | #define WM8991_R12MNB 0x0020 /* R12MNB */ | ||
596 | #define WM8991_R12MNB_BIT 5 | ||
597 | #define WM8991_R12MNBST 0x0010 /* R12MNBST */ | ||
598 | #define WM8991_R12MNBST_BIT 4 | ||
599 | #define WM8991_RDBVOL_MASK 0x0007 /* RDBVOL - [2:0] */ | ||
600 | #define WM8991_RDBVOL_SHIFT 0 | ||
601 | |||
602 | /* | ||
603 | * R43 (0x2B) - Input Mixer5 | ||
604 | */ | ||
605 | #define WM8991_LI2BVOL_MASK 0x07 /* LI2BVOL - [8:6] */ | ||
606 | #define WM8991_LI2BVOL_SHIFT 6 | ||
607 | #define WM8991_LR4BVOL_MASK 0x07 /* LR4BVOL - [5:3] */ | ||
608 | #define WM8991_LR4BVOL_SHIFT 3 | ||
609 | #define WM8991_LL4BVOL_MASK 0x07 /* LL4BVOL - [2:0] */ | ||
610 | #define WM8991_LL4BVOL_SHIFT 0 | ||
611 | |||
612 | /* | ||
613 | * R44 (0x2C) - Input Mixer6 | ||
614 | */ | ||
615 | #define WM8991_RI2BVOL_MASK 0x07 /* RI2BVOL - [8:6] */ | ||
616 | #define WM8991_RI2BVOL_SHIFT 6 | ||
617 | #define WM8991_RL4BVOL_MASK 0x07 /* RL4BVOL - [5:3] */ | ||
618 | #define WM8991_RL4BVOL_SHIFT 3 | ||
619 | #define WM8991_RR4BVOL_MASK 0x07 /* RR4BVOL - [2:0] */ | ||
620 | #define WM8991_RR4BVOL_SHIFT 0 | ||
621 | |||
622 | /* | ||
623 | * R45 (0x2D) - Output Mixer1 | ||
624 | */ | ||
625 | #define WM8991_LRBLO 0x0080 /* LRBLO */ | ||
626 | #define WM8991_LRBLO_BIT 7 | ||
627 | #define WM8991_LLBLO 0x0040 /* LLBLO */ | ||
628 | #define WM8991_LLBLO_BIT 6 | ||
629 | #define WM8991_LRI3LO 0x0020 /* LRI3LO */ | ||
630 | #define WM8991_LRI3LO_BIT 5 | ||
631 | #define WM8991_LLI3LO 0x0010 /* LLI3LO */ | ||
632 | #define WM8991_LLI3LO_BIT 4 | ||
633 | #define WM8991_LR12LO 0x0008 /* LR12LO */ | ||
634 | #define WM8991_LR12LO_BIT 3 | ||
635 | #define WM8991_LL12LO 0x0004 /* LL12LO */ | ||
636 | #define WM8991_LL12LO_BIT 2 | ||
637 | #define WM8991_LDLO 0x0001 /* LDLO */ | ||
638 | #define WM8991_LDLO_BIT 0 | ||
639 | |||
640 | /* | ||
641 | * R46 (0x2E) - Output Mixer2 | ||
642 | */ | ||
643 | #define WM8991_RLBRO 0x0080 /* RLBRO */ | ||
644 | #define WM8991_RLBRO_BIT 7 | ||
645 | #define WM8991_RRBRO 0x0040 /* RRBRO */ | ||
646 | #define WM8991_RRBRO_BIT 6 | ||
647 | #define WM8991_RLI3RO 0x0020 /* RLI3RO */ | ||
648 | #define WM8991_RLI3RO_BIT 5 | ||
649 | #define WM8991_RRI3RO 0x0010 /* RRI3RO */ | ||
650 | #define WM8991_RRI3RO_BIT 4 | ||
651 | #define WM8991_RL12RO 0x0008 /* RL12RO */ | ||
652 | #define WM8991_RL12RO_BIT 3 | ||
653 | #define WM8991_RR12RO 0x0004 /* RR12RO */ | ||
654 | #define WM8991_RR12RO_BIT 2 | ||
655 | #define WM8991_RDRO 0x0001 /* RDRO */ | ||
656 | #define WM8991_RDRO_BIT 0 | ||
657 | |||
658 | /* | ||
659 | * R47 (0x2F) - Output Mixer3 | ||
660 | */ | ||
661 | #define WM8991_LLI3LOVOL_MASK 0x07 /* LLI3LOVOL - [8:6] */ | ||
662 | #define WM8991_LLI3LOVOL_SHIFT 6 | ||
663 | #define WM8991_LR12LOVOL_MASK 0x07 /* LR12LOVOL - [5:3] */ | ||
664 | #define WM8991_LR12LOVOL_SHIFT 3 | ||
665 | #define WM8991_LL12LOVOL_MASK 0x07 /* LL12LOVOL - [2:0] */ | ||
666 | #define WM8991_LL12LOVOL_SHIFT 0 | ||
667 | |||
668 | /* | ||
669 | * R48 (0x30) - Output Mixer4 | ||
670 | */ | ||
671 | #define WM8991_RRI3ROVOL_MASK 0x07 /* RRI3ROVOL - [8:6] */ | ||
672 | #define WM8991_RRI3ROVOL_SHIFT 6 | ||
673 | #define WM8991_RL12ROVOL_MASK 0x07 /* RL12ROVOL - [5:3] */ | ||
674 | #define WM8991_RL12ROVOL_SHIFT 3 | ||
675 | #define WM8991_RR12ROVOL_MASK 0x07 /* RR12ROVOL - [2:0] */ | ||
676 | #define WM8991_RR12ROVOL_SHIFT 0 | ||
677 | |||
678 | /* | ||
679 | * R49 (0x31) - Output Mixer5 | ||
680 | */ | ||
681 | #define WM8991_LRI3LOVOL_MASK 0x07 /* LRI3LOVOL - [8:6] */ | ||
682 | #define WM8991_LRI3LOVOL_SHIFT 6 | ||
683 | #define WM8991_LRBLOVOL_MASK 0x07 /* LRBLOVOL - [5:3] */ | ||
684 | #define WM8991_LRBLOVOL_SHIFT 3 | ||
685 | #define WM8991_LLBLOVOL_MASK 0x07 /* LLBLOVOL - [2:0] */ | ||
686 | #define WM8991_LLBLOVOL_SHIFT 0 | ||
687 | |||
688 | /* | ||
689 | * R50 (0x32) - Output Mixer6 | ||
690 | */ | ||
691 | #define WM8991_RLI3ROVOL_MASK 0x07 /* RLI3ROVOL - [8:6] */ | ||
692 | #define WM8991_RLI3ROVOL_SHIFT 6 | ||
693 | #define WM8991_RLBROVOL_MASK 0x07 /* RLBROVOL - [5:3] */ | ||
694 | #define WM8991_RLBROVOL_SHIFT 3 | ||
695 | #define WM8991_RRBROVOL_MASK 0x07 /* RRBROVOL - [2:0] */ | ||
696 | #define WM8991_RRBROVOL_SHIFT 0 | ||
697 | |||
698 | /* | ||
699 | * R51 (0x33) - Out3/4 Mixer | ||
700 | */ | ||
701 | #define WM8991_VSEL_MASK 0x0180 /* VSEL - [8:7] */ | ||
702 | #define WM8991_LI4O3 0x0020 /* LI4O3 */ | ||
703 | #define WM8991_LI4O3_BIT 5 | ||
704 | #define WM8991_LPGAO3 0x0010 /* LPGAO3 */ | ||
705 | #define WM8991_LPGAO3_BIT 4 | ||
706 | #define WM8991_RI4O4 0x0002 /* RI4O4 */ | ||
707 | #define WM8991_RI4O4_BIT 1 | ||
708 | #define WM8991_RPGAO4 0x0001 /* RPGAO4 */ | ||
709 | #define WM8991_RPGAO4_BIT 0 | ||
710 | /* | ||
711 | * R52 (0x34) - Line Mixer1 | ||
712 | */ | ||
713 | #define WM8991_LLOPGALON 0x0040 /* LLOPGALON */ | ||
714 | #define WM8991_LLOPGALON_BIT 6 | ||
715 | #define WM8991_LROPGALON 0x0020 /* LROPGALON */ | ||
716 | #define WM8991_LROPGALON_BIT 5 | ||
717 | #define WM8991_LOPLON 0x0010 /* LOPLON */ | ||
718 | #define WM8991_LOPLON_BIT 4 | ||
719 | #define WM8991_LR12LOP 0x0004 /* LR12LOP */ | ||
720 | #define WM8991_LR12LOP_BIT 2 | ||
721 | #define WM8991_LL12LOP 0x0002 /* LL12LOP */ | ||
722 | #define WM8991_LL12LOP_BIT 1 | ||
723 | #define WM8991_LLOPGALOP 0x0001 /* LLOPGALOP */ | ||
724 | #define WM8991_LLOPGALOP_BIT 0 | ||
725 | /* | ||
726 | * R53 (0x35) - Line Mixer2 | ||
727 | */ | ||
728 | #define WM8991_RROPGARON 0x0040 /* RROPGARON */ | ||
729 | #define WM8991_RROPGARON_BIT 6 | ||
730 | #define WM8991_RLOPGARON 0x0020 /* RLOPGARON */ | ||
731 | #define WM8991_RLOPGARON_BIT 5 | ||
732 | #define WM8991_ROPRON 0x0010 /* ROPRON */ | ||
733 | #define WM8991_ROPRON_BIT 4 | ||
734 | #define WM8991_RL12ROP 0x0004 /* RL12ROP */ | ||
735 | #define WM8991_RL12ROP_BIT 2 | ||
736 | #define WM8991_RR12ROP 0x0002 /* RR12ROP */ | ||
737 | #define WM8991_RR12ROP_BIT 1 | ||
738 | #define WM8991_RROPGAROP 0x0001 /* RROPGAROP */ | ||
739 | #define WM8991_RROPGAROP_BIT 0 | ||
740 | |||
741 | /* | ||
742 | * R54 (0x36) - Speaker Mixer | ||
743 | */ | ||
744 | #define WM8991_LB2SPK 0x0080 /* LB2SPK */ | ||
745 | #define WM8991_LB2SPK_BIT 7 | ||
746 | #define WM8991_RB2SPK 0x0040 /* RB2SPK */ | ||
747 | #define WM8991_RB2SPK_BIT 6 | ||
748 | #define WM8991_LI2SPK 0x0020 /* LI2SPK */ | ||
749 | #define WM8991_LI2SPK_BIT 5 | ||
750 | #define WM8991_RI2SPK 0x0010 /* RI2SPK */ | ||
751 | #define WM8991_RI2SPK_BIT 4 | ||
752 | #define WM8991_LOPGASPK 0x0008 /* LOPGASPK */ | ||
753 | #define WM8991_LOPGASPK_BIT 3 | ||
754 | #define WM8991_ROPGASPK 0x0004 /* ROPGASPK */ | ||
755 | #define WM8991_ROPGASPK_BIT 2 | ||
756 | #define WM8991_LDSPK 0x0002 /* LDSPK */ | ||
757 | #define WM8991_LDSPK_BIT 1 | ||
758 | #define WM8991_RDSPK 0x0001 /* RDSPK */ | ||
759 | #define WM8991_RDSPK_BIT 0 | ||
760 | |||
761 | /* | ||
762 | * R55 (0x37) - Additional Control | ||
763 | */ | ||
764 | #define WM8991_VROI 0x0001 /* VROI */ | ||
765 | |||
766 | /* | ||
767 | * R56 (0x38) - AntiPOP1 | ||
768 | */ | ||
769 | #define WM8991_DIS_LLINE 0x0020 /* DIS_LLINE */ | ||
770 | #define WM8991_DIS_RLINE 0x0010 /* DIS_RLINE */ | ||
771 | #define WM8991_DIS_OUT3 0x0008 /* DIS_OUT3 */ | ||
772 | #define WM8991_DIS_OUT4 0x0004 /* DIS_OUT4 */ | ||
773 | #define WM8991_DIS_LOUT 0x0002 /* DIS_LOUT */ | ||
774 | #define WM8991_DIS_ROUT 0x0001 /* DIS_ROUT */ | ||
775 | |||
776 | /* | ||
777 | * R57 (0x39) - AntiPOP2 | ||
778 | */ | ||
779 | #define WM8991_SOFTST 0x0040 /* SOFTST */ | ||
780 | #define WM8991_BUFIOEN 0x0008 /* BUFIOEN */ | ||
781 | #define WM8991_BUFDCOPEN 0x0004 /* BUFDCOPEN */ | ||
782 | #define WM8991_POBCTRL 0x0002 /* POBCTRL */ | ||
783 | #define WM8991_VMIDTOG 0x0001 /* VMIDTOG */ | ||
784 | |||
785 | /* | ||
786 | * R58 (0x3A) - MICBIAS | ||
787 | */ | ||
788 | #define WM8991_MCDSCTH_MASK 0x00C0 /* MCDSCTH - [7:6] */ | ||
789 | #define WM8991_MCDTHR_MASK 0x0038 /* MCDTHR - [5:3] */ | ||
790 | #define WM8991_MCD 0x0004 /* MCD */ | ||
791 | #define WM8991_MBSEL 0x0001 /* MBSEL */ | ||
792 | |||
793 | /* | ||
794 | * R60 (0x3C) - PLL1 | ||
795 | */ | ||
796 | #define WM8991_SDM 0x0080 /* SDM */ | ||
797 | #define WM8991_PRESCALE 0x0040 /* PRESCALE */ | ||
798 | #define WM8991_PLLN_MASK 0x000F /* PLLN - [3:0] */ | ||
799 | |||
800 | /* | ||
801 | * R61 (0x3D) - PLL2 | ||
802 | */ | ||
803 | #define WM8991_PLLK1_MASK 0x00FF /* PLLK1 - [7:0] */ | ||
804 | |||
805 | /* | ||
806 | * R62 (0x3E) - PLL3 | ||
807 | */ | ||
808 | #define WM8991_PLLK2_MASK 0x00FF /* PLLK2 - [7:0] */ | ||
809 | |||
810 | /* | ||
811 | * R63 (0x3F) - Internal Driver Bits | ||
812 | */ | ||
813 | #define WM8991_INMIXL_PWR_BIT 0 | ||
814 | #define WM8991_AINLMUX_PWR_BIT 1 | ||
815 | #define WM8991_INMIXR_PWR_BIT 2 | ||
816 | #define WM8991_AINRMUX_PWR_BIT 3 | ||
817 | |||
818 | #define WM8991_MCLK_DIV 0 | ||
819 | #define WM8991_DACCLK_DIV 1 | ||
820 | #define WM8991_ADCCLK_DIV 2 | ||
821 | #define WM8991_BCLK_DIV 3 | ||
822 | |||
823 | #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ | ||
824 | tlv_array) \ | ||
825 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
826 | .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ | ||
827 | SNDRV_CTL_ELEM_ACCESS_READWRITE,\ | ||
828 | .tlv.p = (tlv_array), \ | ||
829 | .info = snd_soc_info_volsw, \ | ||
830 | .get = snd_soc_get_volsw, .put = wm899x_outpga_put_volsw_vu, \ | ||
831 | .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } | ||
832 | |||
833 | #endif /* _WM8991_H */ | ||
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 18c0d9ce7c32..379fa22c5b6c 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -242,7 +242,7 @@ struct wm8993_priv { | |||
242 | int fll_src; | 242 | int fll_src; |
243 | }; | 243 | }; |
244 | 244 | ||
245 | static int wm8993_volatile(unsigned int reg) | 245 | static int wm8993_volatile(struct snd_soc_codec *codec, unsigned int reg) |
246 | { | 246 | { |
247 | switch (reg) { | 247 | switch (reg) { |
248 | case WM8993_SOFTWARE_RESET: | 248 | case WM8993_SOFTWARE_RESET: |
diff --git a/sound/soc/codecs/wm8994-tables.c b/sound/soc/codecs/wm8994-tables.c index 68e9b024dd48..a87adbd05ee1 100644 --- a/sound/soc/codecs/wm8994-tables.c +++ b/sound/soc/codecs/wm8994-tables.c | |||
@@ -62,8 +62,8 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = { | |||
62 | { 0x00FF, 0x00FF }, /* R58 - MICBIAS */ | 62 | { 0x00FF, 0x00FF }, /* R58 - MICBIAS */ |
63 | { 0x000F, 0x000F }, /* R59 - LDO 1 */ | 63 | { 0x000F, 0x000F }, /* R59 - LDO 1 */ |
64 | { 0x0007, 0x0007 }, /* R60 - LDO 2 */ | 64 | { 0x0007, 0x0007 }, /* R60 - LDO 2 */ |
65 | { 0x0000, 0x0000 }, /* R61 */ | 65 | { 0xFFFF, 0xFFFF }, /* R61 */ |
66 | { 0x0000, 0x0000 }, /* R62 */ | 66 | { 0xFFFF, 0xFFFF }, /* R62 */ |
67 | { 0x0000, 0x0000 }, /* R63 */ | 67 | { 0x0000, 0x0000 }, /* R63 */ |
68 | { 0x0000, 0x0000 }, /* R64 */ | 68 | { 0x0000, 0x0000 }, /* R64 */ |
69 | { 0x0000, 0x0000 }, /* R65 */ | 69 | { 0x0000, 0x0000 }, /* R65 */ |
@@ -209,9 +209,9 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = { | |||
209 | { 0x0000, 0x0000 }, /* R205 */ | 209 | { 0x0000, 0x0000 }, /* R205 */ |
210 | { 0x0000, 0x0000 }, /* R206 */ | 210 | { 0x0000, 0x0000 }, /* R206 */ |
211 | { 0x0000, 0x0000 }, /* R207 */ | 211 | { 0x0000, 0x0000 }, /* R207 */ |
212 | { 0x0000, 0x0000 }, /* R208 */ | 212 | { 0xFFFF, 0xFFFF }, /* R208 */ |
213 | { 0x0000, 0x0000 }, /* R209 */ | 213 | { 0xFFFF, 0xFFFF }, /* R209 */ |
214 | { 0x0000, 0x0000 }, /* R210 */ | 214 | { 0xFFFF, 0xFFFF }, /* R210 */ |
215 | { 0x0000, 0x0000 }, /* R211 */ | 215 | { 0x0000, 0x0000 }, /* R211 */ |
216 | { 0x0000, 0x0000 }, /* R212 */ | 216 | { 0x0000, 0x0000 }, /* R212 */ |
217 | { 0x0000, 0x0000 }, /* R213 */ | 217 | { 0x0000, 0x0000 }, /* R213 */ |
@@ -1573,7 +1573,7 @@ const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE] = { | |||
1573 | { 0x03C3, 0x03C3 }, /* R1569 - Sidetone */ | 1573 | { 0x03C3, 0x03C3 }, /* R1569 - Sidetone */ |
1574 | }; | 1574 | }; |
1575 | 1575 | ||
1576 | const __devinitdata u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = { | 1576 | const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE] = { |
1577 | 0x8994, /* R0 - Software Reset */ | 1577 | 0x8994, /* R0 - Software Reset */ |
1578 | 0x0000, /* R1 - Power Management (1) */ | 1578 | 0x0000, /* R1 - Power Management (1) */ |
1579 | 0x6000, /* R2 - Power Management (2) */ | 1579 | 0x6000, /* R2 - Power Management (2) */ |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index c6c958ee5d59..3dc64c8b6a5c 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -102,8 +102,7 @@ struct wm8994_priv { | |||
102 | 102 | ||
103 | wm8958_micdet_cb jack_cb; | 103 | wm8958_micdet_cb jack_cb; |
104 | void *jack_cb_data; | 104 | void *jack_cb_data; |
105 | bool jack_is_mic; | 105 | int micdet_irq; |
106 | bool jack_is_video; | ||
107 | 106 | ||
108 | int revision; | 107 | int revision; |
109 | struct wm8994_pdata *pdata; | 108 | struct wm8994_pdata *pdata; |
@@ -115,7 +114,7 @@ struct wm8994_priv { | |||
115 | unsigned int aif2clk_disable:1; | 114 | unsigned int aif2clk_disable:1; |
116 | }; | 115 | }; |
117 | 116 | ||
118 | static int wm8994_readable(unsigned int reg) | 117 | static int wm8994_readable(struct snd_soc_codec *codec, unsigned int reg) |
119 | { | 118 | { |
120 | switch (reg) { | 119 | switch (reg) { |
121 | case WM8994_GPIO_1: | 120 | case WM8994_GPIO_1: |
@@ -142,7 +141,7 @@ static int wm8994_readable(unsigned int reg) | |||
142 | return wm8994_access_masks[reg].readable != 0; | 141 | return wm8994_access_masks[reg].readable != 0; |
143 | } | 142 | } |
144 | 143 | ||
145 | static int wm8994_volatile(unsigned int reg) | 144 | static int wm8994_volatile(struct snd_soc_codec *codec, unsigned int reg) |
146 | { | 145 | { |
147 | if (reg >= WM8994_CACHE_SIZE) | 146 | if (reg >= WM8994_CACHE_SIZE) |
148 | return 1; | 147 | return 1; |
@@ -170,7 +169,7 @@ static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg, | |||
170 | 169 | ||
171 | BUG_ON(reg > WM8994_MAX_REGISTER); | 170 | BUG_ON(reg > WM8994_MAX_REGISTER); |
172 | 171 | ||
173 | if (!wm8994_volatile(reg)) { | 172 | if (!wm8994_volatile(codec, reg)) { |
174 | ret = snd_soc_cache_write(codec, reg, value); | 173 | ret = snd_soc_cache_write(codec, reg, value); |
175 | if (ret != 0) | 174 | if (ret != 0) |
176 | dev_err(codec->dev, "Cache write to %x failed: %d\n", | 175 | dev_err(codec->dev, "Cache write to %x failed: %d\n", |
@@ -188,7 +187,7 @@ static unsigned int wm8994_read(struct snd_soc_codec *codec, | |||
188 | 187 | ||
189 | BUG_ON(reg > WM8994_MAX_REGISTER); | 188 | BUG_ON(reg > WM8994_MAX_REGISTER); |
190 | 189 | ||
191 | if (!wm8994_volatile(reg) && wm8994_readable(reg) && | 190 | if (!wm8994_volatile(codec, reg) && wm8994_readable(codec, reg) && |
192 | reg < codec->driver->reg_cache_size) { | 191 | reg < codec->driver->reg_cache_size) { |
193 | ret = snd_soc_cache_read(codec, reg, &val); | 192 | ret = snd_soc_cache_read(codec, reg, &val); |
194 | if (ret >= 0) | 193 | if (ret >= 0) |
@@ -529,7 +528,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol, | |||
529 | struct snd_ctl_elem_value *ucontrol) | 528 | struct snd_ctl_elem_value *ucontrol) |
530 | { | 529 | { |
531 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 530 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
532 | struct wm8994_priv *wm8994 =snd_soc_codec_get_drvdata(codec); | 531 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
533 | int block = wm8994_get_retune_mobile_block(kcontrol->id.name); | 532 | int block = wm8994_get_retune_mobile_block(kcontrol->id.name); |
534 | 533 | ||
535 | ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; | 534 | ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block]; |
@@ -1103,6 +1102,13 @@ static int adc_mux_ev(struct snd_soc_dapm_widget *w, | |||
1103 | return 0; | 1102 | return 0; |
1104 | } | 1103 | } |
1105 | 1104 | ||
1105 | static int micbias_ev(struct snd_soc_dapm_widget *w, | ||
1106 | struct snd_kcontrol *kcontrol, int event) | ||
1107 | { | ||
1108 | late_enable_ev(w, kcontrol, event); | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1106 | static int dac_ev(struct snd_soc_dapm_widget *w, | 1112 | static int dac_ev(struct snd_soc_dapm_widget *w, |
1107 | struct snd_kcontrol *kcontrol, int event) | 1113 | struct snd_kcontrol *kcontrol, int event) |
1108 | { | 1114 | { |
@@ -1440,6 +1446,10 @@ SND_SOC_DAPM_INPUT("DMIC1DAT"), | |||
1440 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 1446 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
1441 | SND_SOC_DAPM_INPUT("Clock"), | 1447 | SND_SOC_DAPM_INPUT("Clock"), |
1442 | 1448 | ||
1449 | SND_SOC_DAPM_MICBIAS("MICBIAS", WM8994_MICBIAS, 2, 0), | ||
1450 | SND_SOC_DAPM_SUPPLY_S("MICBIAS Supply", 1, SND_SOC_NOPM, 0, 0, micbias_ev, | ||
1451 | SND_SOC_DAPM_PRE_PMU), | ||
1452 | |||
1443 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | 1453 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, |
1444 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 1454 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
1445 | 1455 | ||
@@ -1755,6 +1765,8 @@ static const struct snd_soc_dapm_route wm8994_revd_intercon[] = { | |||
1755 | { "AIF2DACDAT", NULL, "AIF1DACDAT" }, | 1765 | { "AIF2DACDAT", NULL, "AIF1DACDAT" }, |
1756 | { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, | 1766 | { "AIF1ADCDAT", NULL, "AIF2ADCDAT" }, |
1757 | { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, | 1767 | { "AIF2ADCDAT", NULL, "AIF1ADCDAT" }, |
1768 | { "MICBIAS", NULL, "CLK_SYS" }, | ||
1769 | { "MICBIAS", NULL, "MICBIAS Supply" }, | ||
1758 | }; | 1770 | }; |
1759 | 1771 | ||
1760 | static const struct snd_soc_dapm_route wm8994_intercon[] = { | 1772 | static const struct snd_soc_dapm_route wm8994_intercon[] = { |
@@ -2883,6 +2895,13 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | |||
2883 | else | 2895 | else |
2884 | snd_soc_add_controls(wm8994->codec, wm8994_eq_controls, | 2896 | snd_soc_add_controls(wm8994->codec, wm8994_eq_controls, |
2885 | ARRAY_SIZE(wm8994_eq_controls)); | 2897 | ARRAY_SIZE(wm8994_eq_controls)); |
2898 | |||
2899 | for (i = 0; i < ARRAY_SIZE(pdata->micbias); i++) { | ||
2900 | if (pdata->micbias[i]) { | ||
2901 | snd_soc_write(codec, WM8958_MICBIAS1 + i, | ||
2902 | pdata->micbias[i] & 0xffff); | ||
2903 | } | ||
2904 | } | ||
2886 | } | 2905 | } |
2887 | 2906 | ||
2888 | /** | 2907 | /** |
@@ -2993,46 +3012,18 @@ static void wm8958_default_micdet(u16 status, void *data) | |||
2993 | int report = 0; | 3012 | int report = 0; |
2994 | 3013 | ||
2995 | /* If nothing present then clear our statuses */ | 3014 | /* If nothing present then clear our statuses */ |
2996 | if (!(status & WM8958_MICD_STS)) { | 3015 | if (!(status & WM8958_MICD_STS)) |
2997 | wm8994->jack_is_video = false; | ||
2998 | wm8994->jack_is_mic = false; | ||
2999 | goto done; | 3016 | goto done; |
3000 | } | ||
3001 | 3017 | ||
3002 | /* Assume anything over 475 ohms is a microphone and remember | 3018 | report = SND_JACK_MICROPHONE; |
3003 | * that we've seen one (since buttons override it) */ | ||
3004 | if (status & 0x600) | ||
3005 | wm8994->jack_is_mic = true; | ||
3006 | if (wm8994->jack_is_mic) | ||
3007 | report |= SND_JACK_MICROPHONE; | ||
3008 | |||
3009 | /* Video has an impedence of approximately 75 ohms; assume | ||
3010 | * this isn't used as a button and remember it since buttons | ||
3011 | * override it. */ | ||
3012 | if (status & 0x40) | ||
3013 | wm8994->jack_is_video = true; | ||
3014 | if (wm8994->jack_is_video) | ||
3015 | report |= SND_JACK_VIDEOOUT; | ||
3016 | 3019 | ||
3017 | /* Everything else is buttons; just assign slots */ | 3020 | /* Everything else is buttons; just assign slots */ |
3018 | if (status & 0x4) | 3021 | if (status & 0x1c0) |
3019 | report |= SND_JACK_BTN_0; | 3022 | report |= SND_JACK_BTN_0; |
3020 | if (status & 0x8) | ||
3021 | report |= SND_JACK_BTN_1; | ||
3022 | if (status & 0x10) | ||
3023 | report |= SND_JACK_BTN_2; | ||
3024 | if (status & 0x20) | ||
3025 | report |= SND_JACK_BTN_3; | ||
3026 | if (status & 0x80) | ||
3027 | report |= SND_JACK_BTN_4; | ||
3028 | if (status & 0x100) | ||
3029 | report |= SND_JACK_BTN_5; | ||
3030 | 3023 | ||
3031 | done: | 3024 | done: |
3032 | snd_soc_jack_report(wm8994->micdet[0].jack, report, | 3025 | snd_soc_jack_report(wm8994->micdet[0].jack, report, |
3033 | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | | 3026 | SND_JACK_BTN_0 | SND_JACK_MICROPHONE); |
3034 | SND_JACK_BTN_3 | SND_JACK_BTN_4 | SND_JACK_BTN_5 | | ||
3035 | SND_JACK_MICROPHONE | SND_JACK_VIDEOOUT); | ||
3036 | } | 3027 | } |
3037 | 3028 | ||
3038 | /** | 3029 | /** |
@@ -3131,13 +3122,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3131 | wm8994->pdata = dev_get_platdata(codec->dev->parent); | 3122 | wm8994->pdata = dev_get_platdata(codec->dev->parent); |
3132 | wm8994->codec = codec; | 3123 | wm8994->codec = codec; |
3133 | 3124 | ||
3125 | if (wm8994->pdata && wm8994->pdata->micdet_irq) | ||
3126 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; | ||
3127 | else if (wm8994->pdata && wm8994->pdata->irq_base) | ||
3128 | wm8994->micdet_irq = wm8994->pdata->irq_base + | ||
3129 | WM8994_IRQ_MIC1_DET; | ||
3130 | |||
3134 | pm_runtime_enable(codec->dev); | 3131 | pm_runtime_enable(codec->dev); |
3135 | pm_runtime_resume(codec->dev); | 3132 | pm_runtime_resume(codec->dev); |
3136 | 3133 | ||
3137 | /* Read our current status back from the chip - we don't want to | 3134 | /* Read our current status back from the chip - we don't want to |
3138 | * reset as this may interfere with the GPIO or LDO operation. */ | 3135 | * reset as this may interfere with the GPIO or LDO operation. */ |
3139 | for (i = 0; i < WM8994_CACHE_SIZE; i++) { | 3136 | for (i = 0; i < WM8994_CACHE_SIZE; i++) { |
3140 | if (!wm8994_readable(i) || wm8994_volatile(i)) | 3137 | if (!wm8994_readable(codec, i) || wm8994_volatile(codec, i)) |
3141 | continue; | 3138 | continue; |
3142 | 3139 | ||
3143 | ret = wm8994_reg_read(codec->control_data, i); | 3140 | ret = wm8994_reg_read(codec->control_data, i); |
@@ -3179,14 +3176,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3179 | 3176 | ||
3180 | switch (control->type) { | 3177 | switch (control->type) { |
3181 | case WM8994: | 3178 | case WM8994: |
3182 | ret = wm8994_request_irq(codec->control_data, | 3179 | if (wm8994->micdet_irq) { |
3183 | WM8994_IRQ_MIC1_DET, | 3180 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, |
3184 | wm8994_mic_irq, "Mic 1 detect", | 3181 | wm8994_mic_irq, |
3185 | wm8994); | 3182 | IRQF_TRIGGER_RISING, |
3186 | if (ret != 0) | 3183 | "Mic1 detect", |
3187 | dev_warn(codec->dev, | 3184 | wm8994); |
3188 | "Failed to request Mic1 detect IRQ: %d\n", | 3185 | if (ret != 0) |
3189 | ret); | 3186 | dev_warn(codec->dev, |
3187 | "Failed to request Mic1 detect IRQ: %d\n", | ||
3188 | ret); | ||
3189 | } | ||
3190 | 3190 | ||
3191 | ret = wm8994_request_irq(codec->control_data, | 3191 | ret = wm8994_request_irq(codec->control_data, |
3192 | WM8994_IRQ_MIC1_SHRT, | 3192 | WM8994_IRQ_MIC1_SHRT, |
@@ -3217,15 +3217,17 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3217 | break; | 3217 | break; |
3218 | 3218 | ||
3219 | case WM8958: | 3219 | case WM8958: |
3220 | ret = wm8994_request_irq(codec->control_data, | 3220 | if (wm8994->micdet_irq) { |
3221 | WM8994_IRQ_MIC1_DET, | 3221 | ret = request_threaded_irq(wm8994->micdet_irq, NULL, |
3222 | wm8958_mic_irq, "Mic detect", | 3222 | wm8958_mic_irq, |
3223 | wm8994); | 3223 | IRQF_TRIGGER_RISING, |
3224 | if (ret != 0) | 3224 | "Mic detect", |
3225 | dev_warn(codec->dev, | 3225 | wm8994); |
3226 | "Failed to request Mic detect IRQ: %d\n", | 3226 | if (ret != 0) |
3227 | ret); | 3227 | dev_warn(codec->dev, |
3228 | break; | 3228 | "Failed to request Mic detect IRQ: %d\n", |
3229 | ret); | ||
3230 | } | ||
3229 | } | 3231 | } |
3230 | 3232 | ||
3231 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be | 3233 | /* Remember if AIFnLRCLK is configured as a GPIO. This should be |
@@ -3369,7 +3371,8 @@ err_irq: | |||
3369 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); | 3371 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994); |
3370 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); | 3372 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994); |
3371 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); | 3373 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994); |
3372 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994); | 3374 | if (wm8994->micdet_irq) |
3375 | free_irq(wm8994->micdet_irq, wm8994); | ||
3373 | err: | 3376 | err: |
3374 | kfree(wm8994); | 3377 | kfree(wm8994); |
3375 | return ret; | 3378 | return ret; |
@@ -3386,8 +3389,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3386 | 3389 | ||
3387 | switch (control->type) { | 3390 | switch (control->type) { |
3388 | case WM8994: | 3391 | case WM8994: |
3389 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, | 3392 | if (wm8994->micdet_irq) |
3390 | wm8994); | 3393 | free_irq(wm8994->micdet_irq, wm8994); |
3391 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, | 3394 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, |
3392 | wm8994); | 3395 | wm8994); |
3393 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, | 3396 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, |
@@ -3397,8 +3400,8 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec) | |||
3397 | break; | 3400 | break; |
3398 | 3401 | ||
3399 | case WM8958: | 3402 | case WM8958: |
3400 | wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, | 3403 | if (wm8994->micdet_irq) |
3401 | wm8994); | 3404 | free_irq(wm8994->micdet_irq, wm8994); |
3402 | break; | 3405 | break; |
3403 | } | 3406 | } |
3404 | kfree(wm8994->retune_mobile_texts); | 3407 | kfree(wm8994->retune_mobile_texts); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 0c355bfc88f1..999b8851226b 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -43,6 +43,6 @@ struct wm8994_access_mask { | |||
43 | }; | 43 | }; |
44 | 44 | ||
45 | extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE]; | 45 | extern const struct wm8994_access_mask wm8994_access_masks[WM8994_CACHE_SIZE]; |
46 | extern const __devinitdata u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; | 46 | extern const u16 wm8994_reg_defaults[WM8994_CACHE_SIZE]; |
47 | 47 | ||
48 | #endif | 48 | #endif |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 608c84c5aa8e..67eaaecbb42e 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/pm.h> | 19 | #include <linux/pm.h> |
20 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
21 | #include <linux/spi/spi.h> | 21 | #include <linux/spi/spi.h> |
22 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
@@ -30,6 +31,18 @@ | |||
30 | 31 | ||
31 | #include "wm8995.h" | 32 | #include "wm8995.h" |
32 | 33 | ||
34 | #define WM8995_NUM_SUPPLIES 8 | ||
35 | static const char *wm8995_supply_names[WM8995_NUM_SUPPLIES] = { | ||
36 | "DCVDD", | ||
37 | "DBVDD1", | ||
38 | "DBVDD2", | ||
39 | "DBVDD3", | ||
40 | "AVDD1", | ||
41 | "AVDD2", | ||
42 | "CPVDD", | ||
43 | "MICVDD" | ||
44 | }; | ||
45 | |||
33 | static const u16 wm8995_reg_defs[WM8995_MAX_REGISTER + 1] = { | 46 | static const u16 wm8995_reg_defs[WM8995_MAX_REGISTER + 1] = { |
34 | [0] = 0x8995, [5] = 0x0100, [16] = 0x000b, [17] = 0x000b, | 47 | [0] = 0x8995, [5] = 0x0100, [16] = 0x000b, [17] = 0x000b, |
35 | [24] = 0x02c0, [25] = 0x02c0, [26] = 0x02c0, [27] = 0x02c0, | 48 | [24] = 0x02c0, [25] = 0x02c0, [26] = 0x02c0, [27] = 0x02c0, |
@@ -126,8 +139,37 @@ struct wm8995_priv { | |||
126 | int mclk[2]; | 139 | int mclk[2]; |
127 | int aifclk[2]; | 140 | int aifclk[2]; |
128 | struct fll_config fll[2], fll_suspend[2]; | 141 | struct fll_config fll[2], fll_suspend[2]; |
142 | struct regulator_bulk_data supplies[WM8995_NUM_SUPPLIES]; | ||
143 | struct notifier_block disable_nb[WM8995_NUM_SUPPLIES]; | ||
144 | struct snd_soc_codec *codec; | ||
129 | }; | 145 | }; |
130 | 146 | ||
147 | /* | ||
148 | * We can't use the same notifier block for more than one supply and | ||
149 | * there's no way I can see to get from a callback to the caller | ||
150 | * except container_of(). | ||
151 | */ | ||
152 | #define WM8995_REGULATOR_EVENT(n) \ | ||
153 | static int wm8995_regulator_event_##n(struct notifier_block *nb, \ | ||
154 | unsigned long event, void *data) \ | ||
155 | { \ | ||
156 | struct wm8995_priv *wm8995 = container_of(nb, struct wm8995_priv, \ | ||
157 | disable_nb[n]); \ | ||
158 | if (event & REGULATOR_EVENT_DISABLE) { \ | ||
159 | wm8995->codec->cache_sync = 1; \ | ||
160 | } \ | ||
161 | return 0; \ | ||
162 | } | ||
163 | |||
164 | WM8995_REGULATOR_EVENT(0) | ||
165 | WM8995_REGULATOR_EVENT(1) | ||
166 | WM8995_REGULATOR_EVENT(2) | ||
167 | WM8995_REGULATOR_EVENT(3) | ||
168 | WM8995_REGULATOR_EVENT(4) | ||
169 | WM8995_REGULATOR_EVENT(5) | ||
170 | WM8995_REGULATOR_EVENT(6) | ||
171 | WM8995_REGULATOR_EVENT(7) | ||
172 | |||
131 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | 173 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); |
132 | static const DECLARE_TLV_DB_SCALE(in1lr_pga_tlv, -1650, 150, 0); | 174 | static const DECLARE_TLV_DB_SCALE(in1lr_pga_tlv, -1650, 150, 0); |
133 | static const DECLARE_TLV_DB_SCALE(in1l_boost_tlv, 0, 600, 0); | 175 | static const DECLARE_TLV_DB_SCALE(in1l_boost_tlv, 0, 600, 0); |
@@ -909,7 +951,7 @@ static const struct snd_soc_dapm_route wm8995_intercon[] = { | |||
909 | { "SPK2R", NULL, "SPK2R Driver" } | 951 | { "SPK2R", NULL, "SPK2R Driver" } |
910 | }; | 952 | }; |
911 | 953 | ||
912 | static int wm8995_volatile(unsigned int reg) | 954 | static int wm8995_volatile(struct snd_soc_codec *codec, unsigned int reg) |
913 | { | 955 | { |
914 | /* out of bounds registers are generally considered | 956 | /* out of bounds registers are generally considered |
915 | * volatile to support register banks that are partially | 957 | * volatile to support register banks that are partially |
@@ -1483,6 +1525,11 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, | |||
1483 | break; | 1525 | break; |
1484 | case SND_SOC_BIAS_STANDBY: | 1526 | case SND_SOC_BIAS_STANDBY: |
1485 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | 1527 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { |
1528 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies), | ||
1529 | wm8995->supplies); | ||
1530 | if (ret) | ||
1531 | return ret; | ||
1532 | |||
1486 | ret = snd_soc_cache_sync(codec); | 1533 | ret = snd_soc_cache_sync(codec); |
1487 | if (ret) { | 1534 | if (ret) { |
1488 | dev_err(codec->dev, | 1535 | dev_err(codec->dev, |
@@ -1492,12 +1539,13 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, | |||
1492 | 1539 | ||
1493 | snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1, | 1540 | snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1, |
1494 | WM8995_BG_ENA_MASK, WM8995_BG_ENA); | 1541 | WM8995_BG_ENA_MASK, WM8995_BG_ENA); |
1495 | |||
1496 | } | 1542 | } |
1497 | break; | 1543 | break; |
1498 | case SND_SOC_BIAS_OFF: | 1544 | case SND_SOC_BIAS_OFF: |
1499 | snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1, | 1545 | snd_soc_update_bits(codec, WM8995_POWER_MANAGEMENT_1, |
1500 | WM8995_BG_ENA_MASK, 0); | 1546 | WM8995_BG_ENA_MASK, 0); |
1547 | regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), | ||
1548 | wm8995->supplies); | ||
1501 | break; | 1549 | break; |
1502 | } | 1550 | } |
1503 | 1551 | ||
@@ -1536,10 +1584,12 @@ static int wm8995_remove(struct snd_soc_codec *codec) | |||
1536 | static int wm8995_probe(struct snd_soc_codec *codec) | 1584 | static int wm8995_probe(struct snd_soc_codec *codec) |
1537 | { | 1585 | { |
1538 | struct wm8995_priv *wm8995; | 1586 | struct wm8995_priv *wm8995; |
1587 | int i; | ||
1539 | int ret; | 1588 | int ret; |
1540 | 1589 | ||
1541 | codec->dapm.idle_bias_off = 1; | 1590 | codec->dapm.idle_bias_off = 1; |
1542 | wm8995 = snd_soc_codec_get_drvdata(codec); | 1591 | wm8995 = snd_soc_codec_get_drvdata(codec); |
1592 | wm8995->codec = codec; | ||
1543 | 1593 | ||
1544 | ret = snd_soc_codec_set_cache_io(codec, 16, 16, wm8995->control_type); | 1594 | ret = snd_soc_codec_set_cache_io(codec, 16, 16, wm8995->control_type); |
1545 | if (ret < 0) { | 1595 | if (ret < 0) { |
@@ -1547,21 +1597,58 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
1547 | return ret; | 1597 | return ret; |
1548 | } | 1598 | } |
1549 | 1599 | ||
1600 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) | ||
1601 | wm8995->supplies[i].supply = wm8995_supply_names[i]; | ||
1602 | |||
1603 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8995->supplies), | ||
1604 | wm8995->supplies); | ||
1605 | if (ret) { | ||
1606 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
1607 | return ret; | ||
1608 | } | ||
1609 | |||
1610 | wm8995->disable_nb[0].notifier_call = wm8995_regulator_event_0; | ||
1611 | wm8995->disable_nb[1].notifier_call = wm8995_regulator_event_1; | ||
1612 | wm8995->disable_nb[2].notifier_call = wm8995_regulator_event_2; | ||
1613 | wm8995->disable_nb[3].notifier_call = wm8995_regulator_event_3; | ||
1614 | wm8995->disable_nb[4].notifier_call = wm8995_regulator_event_4; | ||
1615 | wm8995->disable_nb[5].notifier_call = wm8995_regulator_event_5; | ||
1616 | wm8995->disable_nb[6].notifier_call = wm8995_regulator_event_6; | ||
1617 | wm8995->disable_nb[7].notifier_call = wm8995_regulator_event_7; | ||
1618 | |||
1619 | /* This should really be moved into the regulator core */ | ||
1620 | for (i = 0; i < ARRAY_SIZE(wm8995->supplies); i++) { | ||
1621 | ret = regulator_register_notifier(wm8995->supplies[i].consumer, | ||
1622 | &wm8995->disable_nb[i]); | ||
1623 | if (ret) { | ||
1624 | dev_err(codec->dev, | ||
1625 | "Failed to register regulator notifier: %d\n", | ||
1626 | ret); | ||
1627 | } | ||
1628 | } | ||
1629 | |||
1630 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8995->supplies), | ||
1631 | wm8995->supplies); | ||
1632 | if (ret) { | ||
1633 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
1634 | goto err_reg_get; | ||
1635 | } | ||
1636 | |||
1550 | ret = snd_soc_read(codec, WM8995_SOFTWARE_RESET); | 1637 | ret = snd_soc_read(codec, WM8995_SOFTWARE_RESET); |
1551 | if (ret < 0) { | 1638 | if (ret < 0) { |
1552 | dev_err(codec->dev, "Failed to read device ID: %d\n", ret); | 1639 | dev_err(codec->dev, "Failed to read device ID: %d\n", ret); |
1553 | return ret; | 1640 | goto err_reg_enable; |
1554 | } | 1641 | } |
1555 | 1642 | ||
1556 | if (ret != 0x8995) { | 1643 | if (ret != 0x8995) { |
1557 | dev_err(codec->dev, "Invalid device ID: %#x\n", ret); | 1644 | dev_err(codec->dev, "Invalid device ID: %#x\n", ret); |
1558 | return -EINVAL; | 1645 | goto err_reg_enable; |
1559 | } | 1646 | } |
1560 | 1647 | ||
1561 | ret = snd_soc_write(codec, WM8995_SOFTWARE_RESET, 0); | 1648 | ret = snd_soc_write(codec, WM8995_SOFTWARE_RESET, 0); |
1562 | if (ret < 0) { | 1649 | if (ret < 0) { |
1563 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); | 1650 | dev_err(codec->dev, "Failed to issue reset: %d\n", ret); |
1564 | return ret; | 1651 | goto err_reg_enable; |
1565 | } | 1652 | } |
1566 | 1653 | ||
1567 | wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1654 | wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -1596,6 +1683,12 @@ static int wm8995_probe(struct snd_soc_codec *codec) | |||
1596 | ARRAY_SIZE(wm8995_intercon)); | 1683 | ARRAY_SIZE(wm8995_intercon)); |
1597 | 1684 | ||
1598 | return 0; | 1685 | return 0; |
1686 | |||
1687 | err_reg_enable: | ||
1688 | regulator_bulk_disable(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); | ||
1689 | err_reg_get: | ||
1690 | regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies); | ||
1691 | return ret; | ||
1599 | } | 1692 | } |
1600 | 1693 | ||
1601 | #define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1694 | #define WM8995_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index cce704c275c6..55cdf2982020 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -167,10 +167,10 @@ struct wm9081_priv { | |||
167 | int fll_fref; | 167 | int fll_fref; |
168 | int fll_fout; | 168 | int fll_fout; |
169 | int tdm_width; | 169 | int tdm_width; |
170 | struct wm9081_retune_mobile_config *retune; | 170 | struct wm9081_pdata pdata; |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static int wm9081_volatile_register(unsigned int reg) | 173 | static int wm9081_volatile_register(struct snd_soc_codec *codec, unsigned int reg) |
174 | { | 174 | { |
175 | switch (reg) { | 175 | switch (reg) { |
176 | case WM9081_SOFTWARE_RESET: | 176 | case WM9081_SOFTWARE_RESET: |
@@ -389,27 +389,6 @@ SOC_DAPM_SINGLE("IN2 Switch", WM9081_ANALOGUE_MIXER, 2, 1, 0), | |||
389 | SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0), | 389 | SOC_DAPM_SINGLE("Playback Switch", WM9081_ANALOGUE_MIXER, 4, 1, 0), |
390 | }; | 390 | }; |
391 | 391 | ||
392 | static int speaker_event(struct snd_soc_dapm_widget *w, | ||
393 | struct snd_kcontrol *kcontrol, int event) | ||
394 | { | ||
395 | struct snd_soc_codec *codec = w->codec; | ||
396 | unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); | ||
397 | |||
398 | switch (event) { | ||
399 | case SND_SOC_DAPM_POST_PMU: | ||
400 | reg |= WM9081_SPK_ENA; | ||
401 | break; | ||
402 | |||
403 | case SND_SOC_DAPM_PRE_PMD: | ||
404 | reg &= ~WM9081_SPK_ENA; | ||
405 | break; | ||
406 | } | ||
407 | |||
408 | snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg); | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | struct _fll_div { | 392 | struct _fll_div { |
414 | u16 fll_fratio; | 393 | u16 fll_fratio; |
415 | u16 fll_outdiv; | 394 | u16 fll_outdiv; |
@@ -747,9 +726,8 @@ SND_SOC_DAPM_MIXER_NAMED_CTL("Mixer", SND_SOC_NOPM, 0, 0, | |||
747 | 726 | ||
748 | SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), | 727 | SND_SOC_DAPM_PGA("LINEOUT PGA", WM9081_POWER_MANAGEMENT, 4, 0, NULL, 0), |
749 | 728 | ||
750 | SND_SOC_DAPM_PGA_E("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0, | 729 | SND_SOC_DAPM_PGA("Speaker PGA", WM9081_POWER_MANAGEMENT, 2, 0, NULL, 0), |
751 | speaker_event, | 730 | SND_SOC_DAPM_PGA("Speaker", WM9081_POWER_MANAGEMENT, 1, 0, NULL, 0), |
752 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | ||
753 | 731 | ||
754 | SND_SOC_DAPM_OUTPUT("LINEOUT"), | 732 | SND_SOC_DAPM_OUTPUT("LINEOUT"), |
755 | SND_SOC_DAPM_OUTPUT("SPKN"), | 733 | SND_SOC_DAPM_OUTPUT("SPKN"), |
@@ -762,7 +740,7 @@ SND_SOC_DAPM_SUPPLY("TOCLK", WM9081_CLOCK_CONTROL_3, 2, 0, NULL, 0), | |||
762 | }; | 740 | }; |
763 | 741 | ||
764 | 742 | ||
765 | static const struct snd_soc_dapm_route audio_paths[] = { | 743 | static const struct snd_soc_dapm_route wm9081_audio_paths[] = { |
766 | { "DAC", NULL, "CLK_SYS" }, | 744 | { "DAC", NULL, "CLK_SYS" }, |
767 | { "DAC", NULL, "CLK_DSP" }, | 745 | { "DAC", NULL, "CLK_DSP" }, |
768 | 746 | ||
@@ -780,8 +758,10 @@ static const struct snd_soc_dapm_route audio_paths[] = { | |||
780 | { "Speaker PGA", NULL, "TOCLK" }, | 758 | { "Speaker PGA", NULL, "TOCLK" }, |
781 | { "Speaker PGA", NULL, "CLK_SYS" }, | 759 | { "Speaker PGA", NULL, "CLK_SYS" }, |
782 | 760 | ||
783 | { "SPKN", NULL, "Speaker PGA" }, | 761 | { "Speaker", NULL, "Speaker PGA" }, |
784 | { "SPKP", NULL, "Speaker PGA" }, | 762 | |
763 | { "SPKN", NULL, "Speaker" }, | ||
764 | { "SPKP", NULL, "Speaker" }, | ||
785 | }; | 765 | }; |
786 | 766 | ||
787 | static int wm9081_set_bias_level(struct snd_soc_codec *codec, | 767 | static int wm9081_set_bias_level(struct snd_soc_codec *codec, |
@@ -1082,21 +1062,22 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, | |||
1082 | aif4 |= wm9081->bclk / wm9081->fs; | 1062 | aif4 |= wm9081->bclk / wm9081->fs; |
1083 | 1063 | ||
1084 | /* Apply a ReTune Mobile configuration if it's in use */ | 1064 | /* Apply a ReTune Mobile configuration if it's in use */ |
1085 | if (wm9081->retune) { | 1065 | if (wm9081->pdata.num_retune_configs) { |
1086 | struct wm9081_retune_mobile_config *retune = wm9081->retune; | 1066 | struct wm9081_pdata *pdata = &wm9081->pdata; |
1087 | struct wm9081_retune_mobile_setting *s; | 1067 | struct wm9081_retune_mobile_setting *s; |
1088 | int eq1; | 1068 | int eq1; |
1089 | 1069 | ||
1090 | best = 0; | 1070 | best = 0; |
1091 | best_val = abs(retune->configs[0].rate - wm9081->fs); | 1071 | best_val = abs(pdata->retune_configs[0].rate - wm9081->fs); |
1092 | for (i = 0; i < retune->num_configs; i++) { | 1072 | for (i = 0; i < pdata->num_retune_configs; i++) { |
1093 | cur_val = abs(retune->configs[i].rate - wm9081->fs); | 1073 | cur_val = abs(pdata->retune_configs[i].rate - |
1074 | wm9081->fs); | ||
1094 | if (cur_val < best_val) { | 1075 | if (cur_val < best_val) { |
1095 | best_val = cur_val; | 1076 | best_val = cur_val; |
1096 | best = i; | 1077 | best = i; |
1097 | } | 1078 | } |
1098 | } | 1079 | } |
1099 | s = &retune->configs[best]; | 1080 | s = &pdata->retune_configs[best]; |
1100 | 1081 | ||
1101 | dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n", | 1082 | dev_dbg(codec->dev, "ReTune Mobile %s tuned for %dHz\n", |
1102 | s->name, s->rate); | 1083 | s->name, s->rate); |
@@ -1139,10 +1120,9 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
1139 | return 0; | 1120 | return 0; |
1140 | } | 1121 | } |
1141 | 1122 | ||
1142 | static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, | 1123 | static int wm9081_set_sysclk(struct snd_soc_codec *codec, |
1143 | int clk_id, unsigned int freq, int dir) | 1124 | int clk_id, unsigned int freq, int dir) |
1144 | { | 1125 | { |
1145 | struct snd_soc_codec *codec = codec_dai->codec; | ||
1146 | struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); | 1126 | struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); |
1147 | 1127 | ||
1148 | switch (clk_id) { | 1128 | switch (clk_id) { |
@@ -1207,7 +1187,6 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, | |||
1207 | 1187 | ||
1208 | static struct snd_soc_dai_ops wm9081_dai_ops = { | 1188 | static struct snd_soc_dai_ops wm9081_dai_ops = { |
1209 | .hw_params = wm9081_hw_params, | 1189 | .hw_params = wm9081_hw_params, |
1210 | .set_sysclk = wm9081_set_sysclk, | ||
1211 | .set_fmt = wm9081_set_dai_fmt, | 1190 | .set_fmt = wm9081_set_dai_fmt, |
1212 | .digital_mute = wm9081_digital_mute, | 1191 | .digital_mute = wm9081_digital_mute, |
1213 | .set_tdm_slot = wm9081_set_tdm_slot, | 1192 | .set_tdm_slot = wm9081_set_tdm_slot, |
@@ -1231,7 +1210,6 @@ static struct snd_soc_dai_driver wm9081_dai = { | |||
1231 | static int wm9081_probe(struct snd_soc_codec *codec) | 1210 | static int wm9081_probe(struct snd_soc_codec *codec) |
1232 | { | 1211 | { |
1233 | struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); | 1212 | struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec); |
1234 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
1235 | int ret; | 1213 | int ret; |
1236 | u16 reg; | 1214 | u16 reg; |
1237 | 1215 | ||
@@ -1255,6 +1233,14 @@ static int wm9081_probe(struct snd_soc_codec *codec) | |||
1255 | return ret; | 1233 | return ret; |
1256 | } | 1234 | } |
1257 | 1235 | ||
1236 | reg = 0; | ||
1237 | if (wm9081->pdata.irq_high) | ||
1238 | reg |= WM9081_IRQ_POL; | ||
1239 | if (!wm9081->pdata.irq_cmos) | ||
1240 | reg |= WM9081_IRQ_OP_CTRL; | ||
1241 | snd_soc_update_bits(codec, WM9081_INTERRUPT_CONTROL, | ||
1242 | WM9081_IRQ_POL | WM9081_IRQ_OP_CTRL, reg); | ||
1243 | |||
1258 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1244 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1259 | 1245 | ||
1260 | /* Enable zero cross by default */ | 1246 | /* Enable zero cross by default */ |
@@ -1266,17 +1252,13 @@ static int wm9081_probe(struct snd_soc_codec *codec) | |||
1266 | 1252 | ||
1267 | snd_soc_add_controls(codec, wm9081_snd_controls, | 1253 | snd_soc_add_controls(codec, wm9081_snd_controls, |
1268 | ARRAY_SIZE(wm9081_snd_controls)); | 1254 | ARRAY_SIZE(wm9081_snd_controls)); |
1269 | if (!wm9081->retune) { | 1255 | if (!wm9081->pdata.num_retune_configs) { |
1270 | dev_dbg(codec->dev, | 1256 | dev_dbg(codec->dev, |
1271 | "No ReTune Mobile data, using normal EQ\n"); | 1257 | "No ReTune Mobile data, using normal EQ\n"); |
1272 | snd_soc_add_controls(codec, wm9081_eq_controls, | 1258 | snd_soc_add_controls(codec, wm9081_eq_controls, |
1273 | ARRAY_SIZE(wm9081_eq_controls)); | 1259 | ARRAY_SIZE(wm9081_eq_controls)); |
1274 | } | 1260 | } |
1275 | 1261 | ||
1276 | snd_soc_dapm_new_controls(dapm, wm9081_dapm_widgets, | ||
1277 | ARRAY_SIZE(wm9081_dapm_widgets)); | ||
1278 | snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths)); | ||
1279 | |||
1280 | return ret; | 1262 | return ret; |
1281 | } | 1263 | } |
1282 | 1264 | ||
@@ -1320,11 +1302,19 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9081 = { | |||
1320 | .remove = wm9081_remove, | 1302 | .remove = wm9081_remove, |
1321 | .suspend = wm9081_suspend, | 1303 | .suspend = wm9081_suspend, |
1322 | .resume = wm9081_resume, | 1304 | .resume = wm9081_resume, |
1305 | |||
1306 | .set_sysclk = wm9081_set_sysclk, | ||
1323 | .set_bias_level = wm9081_set_bias_level, | 1307 | .set_bias_level = wm9081_set_bias_level, |
1308 | |||
1324 | .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults), | 1309 | .reg_cache_size = ARRAY_SIZE(wm9081_reg_defaults), |
1325 | .reg_word_size = sizeof(u16), | 1310 | .reg_word_size = sizeof(u16), |
1326 | .reg_cache_default = wm9081_reg_defaults, | 1311 | .reg_cache_default = wm9081_reg_defaults, |
1327 | .volatile_register = wm9081_volatile_register, | 1312 | .volatile_register = wm9081_volatile_register, |
1313 | |||
1314 | .dapm_widgets = wm9081_dapm_widgets, | ||
1315 | .num_dapm_widgets = ARRAY_SIZE(wm9081_dapm_widgets), | ||
1316 | .dapm_routes = wm9081_audio_paths, | ||
1317 | .num_dapm_routes = ARRAY_SIZE(wm9081_audio_paths), | ||
1328 | }; | 1318 | }; |
1329 | 1319 | ||
1330 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1320 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
@@ -1343,8 +1333,8 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, | |||
1343 | wm9081->control_data = i2c; | 1333 | wm9081->control_data = i2c; |
1344 | 1334 | ||
1345 | if (dev_get_platdata(&i2c->dev)) | 1335 | if (dev_get_platdata(&i2c->dev)) |
1346 | memcpy(&wm9081->retune, dev_get_platdata(&i2c->dev), | 1336 | memcpy(&wm9081->pdata, dev_get_platdata(&i2c->dev), |
1347 | sizeof(wm9081->retune)); | 1337 | sizeof(wm9081->pdata)); |
1348 | 1338 | ||
1349 | ret = snd_soc_register_codec(&i2c->dev, | 1339 | ret = snd_soc_register_codec(&i2c->dev, |
1350 | &soc_codec_dev_wm9081, &wm9081_dai, 1); | 1340 | &soc_codec_dev_wm9081, &wm9081_dai, 1); |
@@ -1368,7 +1358,7 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); | |||
1368 | 1358 | ||
1369 | static struct i2c_driver wm9081_i2c_driver = { | 1359 | static struct i2c_driver wm9081_i2c_driver = { |
1370 | .driver = { | 1360 | .driver = { |
1371 | .name = "wm9081-codec", | 1361 | .name = "wm9081", |
1372 | .owner = THIS_MODULE, | 1362 | .owner = THIS_MODULE, |
1373 | }, | 1363 | }, |
1374 | .probe = wm9081_i2c_probe, | 1364 | .probe = wm9081_i2c_probe, |
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index a788c4297046..4de12203e611 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c | |||
@@ -144,7 +144,7 @@ struct wm9090_priv { | |||
144 | void *control_data; | 144 | void *control_data; |
145 | }; | 145 | }; |
146 | 146 | ||
147 | static int wm9090_volatile(unsigned int reg) | 147 | static int wm9090_volatile(struct snd_soc_codec *codec, unsigned int reg) |
148 | { | 148 | { |
149 | switch (reg) { | 149 | switch (reg) { |
150 | case WM9090_SOFTWARE_RESET: | 150 | case WM9090_SOFTWARE_RESET: |
@@ -518,7 +518,7 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
518 | for (i = 1; i < codec->driver->reg_cache_size; i++) { | 518 | for (i = 1; i < codec->driver->reg_cache_size; i++) { |
519 | if (reg_cache[i] == wm9090_reg_defaults[i]) | 519 | if (reg_cache[i] == wm9090_reg_defaults[i]) |
520 | continue; | 520 | continue; |
521 | if (wm9090_volatile(i)) | 521 | if (wm9090_volatile(codec, i)) |
522 | continue; | 522 | continue; |
523 | 523 | ||
524 | ret = snd_soc_write(codec, i, reg_cache[i]); | 524 | ret = snd_soc_write(codec, i, reg_cache[i]); |
@@ -551,7 +551,6 @@ static int wm9090_set_bias_level(struct snd_soc_codec *codec, | |||
551 | static int wm9090_probe(struct snd_soc_codec *codec) | 551 | static int wm9090_probe(struct snd_soc_codec *codec) |
552 | { | 552 | { |
553 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); | 553 | struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec); |
554 | u16 *reg_cache = codec->reg_cache; | ||
555 | int ret; | 554 | int ret; |
556 | 555 | ||
557 | codec->control_data = wm9090->control_data; | 556 | codec->control_data = wm9090->control_data; |
@@ -576,22 +575,30 @@ static int wm9090_probe(struct snd_soc_codec *codec) | |||
576 | /* Configure some defaults; they will be written out when we | 575 | /* Configure some defaults; they will be written out when we |
577 | * bring the bias up. | 576 | * bring the bias up. |
578 | */ | 577 | */ |
579 | reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU | 578 | snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_A_VOLUME, |
580 | | WM9090_IN1A_ZC; | 579 | WM9090_IN1_VU | WM9090_IN1A_ZC, |
581 | reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU | 580 | WM9090_IN1_VU | WM9090_IN1A_ZC); |
582 | | WM9090_IN1B_ZC; | 581 | snd_soc_update_bits(codec, WM9090_IN1_LINE_INPUT_B_VOLUME, |
583 | reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU | 582 | WM9090_IN1_VU | WM9090_IN1B_ZC, |
584 | | WM9090_IN2A_ZC; | 583 | WM9090_IN1_VU | WM9090_IN1B_ZC); |
585 | reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU | 584 | snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_A_VOLUME, |
586 | | WM9090_IN2B_ZC; | 585 | WM9090_IN2_VU | WM9090_IN2A_ZC, |
587 | reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |= | 586 | WM9090_IN2_VU | WM9090_IN2A_ZC); |
588 | WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC; | 587 | snd_soc_update_bits(codec, WM9090_IN2_LINE_INPUT_B_VOLUME, |
589 | reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |= | 588 | WM9090_IN2_VU | WM9090_IN2B_ZC, |
590 | WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC; | 589 | WM9090_IN2_VU | WM9090_IN2B_ZC); |
591 | reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |= | 590 | snd_soc_update_bits(codec, WM9090_SPEAKER_VOLUME_LEFT, |
592 | WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC; | 591 | WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC, |
593 | 592 | WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC); | |
594 | reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA; | 593 | snd_soc_update_bits(codec, WM9090_LEFT_OUTPUT_VOLUME, |
594 | WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC, | ||
595 | WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC); | ||
596 | snd_soc_update_bits(codec, WM9090_RIGHT_OUTPUT_VOLUME, | ||
597 | WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC, | ||
598 | WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC); | ||
599 | |||
600 | snd_soc_update_bits(codec, WM9090_CLOCKING_1, | ||
601 | WM9090_TOCLK_ENA, WM9090_TOCLK_ENA); | ||
595 | 602 | ||
596 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 603 | wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
597 | 604 | ||
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 516892706063..7b6b3c18e299 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -82,7 +82,8 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op) | |||
82 | } while (reg & op && count < 400); | 82 | } while (reg & op && count < 400); |
83 | 83 | ||
84 | if (reg & op) | 84 | if (reg & op) |
85 | dev_err(codec->dev, "Timed out waiting for DC Servo\n"); | 85 | dev_err(codec->dev, "Timed out waiting for DC Servo %x\n", |
86 | op); | ||
86 | } | 87 | } |
87 | 88 | ||
88 | /* | 89 | /* |
diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 9e0e565e6ed9..d0d60b8a54d4 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c | |||
@@ -658,7 +658,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
658 | return -ENODEV; | 658 | return -ENODEV; |
659 | } | 659 | } |
660 | 660 | ||
661 | ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1, | 661 | ioarea = request_mem_region(mem->start, resource_size(mem), |
662 | pdev->name); | 662 | pdev->name); |
663 | if (!ioarea) { | 663 | if (!ioarea) { |
664 | dev_err(&pdev->dev, "McBSP region already claimed\n"); | 664 | dev_err(&pdev->dev, "McBSP region already claimed\n"); |
@@ -694,20 +694,25 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
694 | } | 694 | } |
695 | clk_enable(dev->clk); | 695 | clk_enable(dev->clk); |
696 | 696 | ||
697 | dev->base = (void __iomem *)IO_ADDRESS(mem->start); | 697 | dev->base = ioremap(mem->start, resource_size(mem)); |
698 | if (!dev->base) { | ||
699 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
700 | ret = -ENOMEM; | ||
701 | goto err_release_clk; | ||
702 | } | ||
698 | 703 | ||
699 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = | 704 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].dma_addr = |
700 | (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DXR_REG); | 705 | (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); |
701 | 706 | ||
702 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = | 707 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].dma_addr = |
703 | (dma_addr_t)(io_v2p(dev->base) + DAVINCI_MCBSP_DRR_REG); | 708 | (dma_addr_t)(mem->start + DAVINCI_MCBSP_DRR_REG); |
704 | 709 | ||
705 | /* first TX, then RX */ | 710 | /* first TX, then RX */ |
706 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 711 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
707 | if (!res) { | 712 | if (!res) { |
708 | dev_err(&pdev->dev, "no DMA resource\n"); | 713 | dev_err(&pdev->dev, "no DMA resource\n"); |
709 | ret = -ENXIO; | 714 | ret = -ENXIO; |
710 | goto err_free_mem; | 715 | goto err_iounmap; |
711 | } | 716 | } |
712 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start; | 717 | dev->dma_params[SNDRV_PCM_STREAM_PLAYBACK].channel = res->start; |
713 | 718 | ||
@@ -715,7 +720,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
715 | if (!res) { | 720 | if (!res) { |
716 | dev_err(&pdev->dev, "no DMA resource\n"); | 721 | dev_err(&pdev->dev, "no DMA resource\n"); |
717 | ret = -ENXIO; | 722 | ret = -ENXIO; |
718 | goto err_free_mem; | 723 | goto err_iounmap; |
719 | } | 724 | } |
720 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; | 725 | dev->dma_params[SNDRV_PCM_STREAM_CAPTURE].channel = res->start; |
721 | dev->dev = &pdev->dev; | 726 | dev->dev = &pdev->dev; |
@@ -724,14 +729,19 @@ static int davinci_i2s_probe(struct platform_device *pdev) | |||
724 | 729 | ||
725 | ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai); | 730 | ret = snd_soc_register_dai(&pdev->dev, &davinci_i2s_dai); |
726 | if (ret != 0) | 731 | if (ret != 0) |
727 | goto err_free_mem; | 732 | goto err_iounmap; |
728 | 733 | ||
729 | return 0; | 734 | return 0; |
730 | 735 | ||
736 | err_iounmap: | ||
737 | iounmap(dev->base); | ||
738 | err_release_clk: | ||
739 | clk_disable(dev->clk); | ||
740 | clk_put(dev->clk); | ||
731 | err_free_mem: | 741 | err_free_mem: |
732 | kfree(dev); | 742 | kfree(dev); |
733 | err_release_region: | 743 | err_release_region: |
734 | release_mem_region(mem->start, (mem->end - mem->start) + 1); | 744 | release_mem_region(mem->start, resource_size(mem)); |
735 | 745 | ||
736 | return ret; | 746 | return ret; |
737 | } | 747 | } |
@@ -747,7 +757,7 @@ static int davinci_i2s_remove(struct platform_device *pdev) | |||
747 | dev->clk = NULL; | 757 | dev->clk = NULL; |
748 | kfree(dev); | 758 | kfree(dev); |
749 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 759 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
750 | release_mem_region(mem->start, (mem->end - mem->start) + 1); | 760 | release_mem_region(mem->start, resource_size(mem)); |
751 | 761 | ||
752 | return 0; | 762 | return 0; |
753 | } | 763 | } |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index fb55d2c5d704..a5af834c8ef5 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -868,7 +868,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
868 | } | 868 | } |
869 | 869 | ||
870 | ioarea = request_mem_region(mem->start, | 870 | ioarea = request_mem_region(mem->start, |
871 | (mem->end - mem->start) + 1, pdev->name); | 871 | resource_size(mem), pdev->name); |
872 | if (!ioarea) { | 872 | if (!ioarea) { |
873 | dev_err(&pdev->dev, "Audio region already claimed\n"); | 873 | dev_err(&pdev->dev, "Audio region already claimed\n"); |
874 | ret = -EBUSY; | 874 | ret = -EBUSY; |
@@ -885,7 +885,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
885 | clk_enable(dev->clk); | 885 | clk_enable(dev->clk); |
886 | dev->clk_active = 1; | 886 | dev->clk_active = 1; |
887 | 887 | ||
888 | dev->base = (void __iomem *)IO_ADDRESS(mem->start); | 888 | dev->base = ioremap(mem->start, resource_size(mem)); |
889 | if (!dev->base) { | ||
890 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
891 | ret = -ENOMEM; | ||
892 | goto err_release_clk; | ||
893 | } | ||
894 | |||
889 | dev->op_mode = pdata->op_mode; | 895 | dev->op_mode = pdata->op_mode; |
890 | dev->tdm_slots = pdata->tdm_slots; | 896 | dev->tdm_slots = pdata->tdm_slots; |
891 | dev->num_serializer = pdata->num_serializer; | 897 | dev->num_serializer = pdata->num_serializer; |
@@ -899,14 +905,14 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
899 | dma_data->asp_chan_q = pdata->asp_chan_q; | 905 | dma_data->asp_chan_q = pdata->asp_chan_q; |
900 | dma_data->ram_chan_q = pdata->ram_chan_q; | 906 | dma_data->ram_chan_q = pdata->ram_chan_q; |
901 | dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + | 907 | dma_data->dma_addr = (dma_addr_t) (pdata->tx_dma_offset + |
902 | io_v2p(dev->base)); | 908 | mem->start); |
903 | 909 | ||
904 | /* first TX, then RX */ | 910 | /* first TX, then RX */ |
905 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 911 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
906 | if (!res) { | 912 | if (!res) { |
907 | dev_err(&pdev->dev, "no DMA resource\n"); | 913 | dev_err(&pdev->dev, "no DMA resource\n"); |
908 | ret = -ENODEV; | 914 | ret = -ENODEV; |
909 | goto err_release_region; | 915 | goto err_iounmap; |
910 | } | 916 | } |
911 | 917 | ||
912 | dma_data->channel = res->start; | 918 | dma_data->channel = res->start; |
@@ -915,13 +921,13 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
915 | dma_data->asp_chan_q = pdata->asp_chan_q; | 921 | dma_data->asp_chan_q = pdata->asp_chan_q; |
916 | dma_data->ram_chan_q = pdata->ram_chan_q; | 922 | dma_data->ram_chan_q = pdata->ram_chan_q; |
917 | dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + | 923 | dma_data->dma_addr = (dma_addr_t)(pdata->rx_dma_offset + |
918 | io_v2p(dev->base)); | 924 | mem->start); |
919 | 925 | ||
920 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 926 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
921 | if (!res) { | 927 | if (!res) { |
922 | dev_err(&pdev->dev, "no DMA resource\n"); | 928 | dev_err(&pdev->dev, "no DMA resource\n"); |
923 | ret = -ENODEV; | 929 | ret = -ENODEV; |
924 | goto err_release_region; | 930 | goto err_iounmap; |
925 | } | 931 | } |
926 | 932 | ||
927 | dma_data->channel = res->start; | 933 | dma_data->channel = res->start; |
@@ -929,11 +935,16 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
929 | ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]); | 935 | ret = snd_soc_register_dai(&pdev->dev, &davinci_mcasp_dai[pdata->op_mode]); |
930 | 936 | ||
931 | if (ret != 0) | 937 | if (ret != 0) |
932 | goto err_release_region; | 938 | goto err_iounmap; |
933 | return 0; | 939 | return 0; |
934 | 940 | ||
941 | err_iounmap: | ||
942 | iounmap(dev->base); | ||
943 | err_release_clk: | ||
944 | clk_disable(dev->clk); | ||
945 | clk_put(dev->clk); | ||
935 | err_release_region: | 946 | err_release_region: |
936 | release_mem_region(mem->start, (mem->end - mem->start) + 1); | 947 | release_mem_region(mem->start, resource_size(mem)); |
937 | err_release_data: | 948 | err_release_data: |
938 | kfree(dev); | 949 | kfree(dev); |
939 | 950 | ||
@@ -951,7 +962,7 @@ static int davinci_mcasp_remove(struct platform_device *pdev) | |||
951 | dev->clk = NULL; | 962 | dev->clk = NULL; |
952 | 963 | ||
953 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 964 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
954 | release_mem_region(mem->start, (mem->end - mem->start) + 1); | 965 | release_mem_region(mem->start, resource_size(mem)); |
955 | 966 | ||
956 | kfree(dev); | 967 | kfree(dev); |
957 | 968 | ||
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig index 57429041189c..91a28de94109 100644 --- a/sound/soc/ep93xx/Kconfig +++ b/sound/soc/ep93xx/Kconfig | |||
@@ -30,3 +30,12 @@ config SND_EP93XX_SOC_SIMONE | |||
30 | help | 30 | help |
31 | Say Y or M here if you want to add support for AC97 audio on the | 31 | Say Y or M here if you want to add support for AC97 audio on the |
32 | Simplemachines Sim.One board. | 32 | Simplemachines Sim.One board. |
33 | |||
34 | config SND_EP93XX_SOC_EDB93XX | ||
35 | tristate "SoC Audio support for Cirrus Logic EDB93xx boards" | ||
36 | depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) | ||
37 | select SND_EP93XX_SOC_I2S | ||
38 | select SND_SOC_CS4271 | ||
39 | help | ||
40 | Say Y or M here if you want to add support for I2S audio on the | ||
41 | Cirrus Logic EDB93xx boards. | ||
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile index 8e7977fb6b7d..5514146cbdf0 100644 --- a/sound/soc/ep93xx/Makefile +++ b/sound/soc/ep93xx/Makefile | |||
@@ -10,6 +10,8 @@ obj-$(CONFIG_SND_EP93XX_SOC_AC97) += snd-soc-ep93xx-ac97.o | |||
10 | # EP93XX Machine Support | 10 | # EP93XX Machine Support |
11 | snd-soc-snappercl15-objs := snappercl15.o | 11 | snd-soc-snappercl15-objs := snappercl15.o |
12 | snd-soc-simone-objs := simone.o | 12 | snd-soc-simone-objs := simone.o |
13 | snd-soc-edb93xx-objs := edb93xx.o | ||
13 | 14 | ||
14 | obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o | 15 | obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15) += snd-soc-snappercl15.o |
15 | obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o | 16 | obj-$(CONFIG_SND_EP93XX_SOC_SIMONE) += snd-soc-simone.o |
17 | obj-$(CONFIG_SND_EP93XX_SOC_EDB93XX) += snd-soc-edb93xx.o | ||
diff --git a/sound/soc/ep93xx/edb93xx.c b/sound/soc/ep93xx/edb93xx.c new file mode 100644 index 000000000000..d3aa15119d26 --- /dev/null +++ b/sound/soc/ep93xx/edb93xx.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * SoC audio for EDB93xx | ||
3 | * | ||
4 | * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation; either version 2 | ||
9 | * of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * This driver support CS4271 codec being master or slave, working | ||
17 | * in control port mode, connected either via SPI or I2C. | ||
18 | * The data format accepted is I2S or left-justified. | ||
19 | * DAPM support not implemented. | ||
20 | */ | ||
21 | |||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/gpio.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | #include <mach/hardware.h> | ||
29 | #include "ep93xx-pcm.h" | ||
30 | |||
31 | #define edb93xx_has_audio() (machine_is_edb9301() || \ | ||
32 | machine_is_edb9302() || \ | ||
33 | machine_is_edb9302a() || \ | ||
34 | machine_is_edb9307a() || \ | ||
35 | machine_is_edb9315a()) | ||
36 | |||
37 | static int edb93xx_hw_params(struct snd_pcm_substream *substream, | ||
38 | struct snd_pcm_hw_params *params) | ||
39 | { | ||
40 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
41 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
42 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
43 | int err; | ||
44 | unsigned int mclk_rate; | ||
45 | unsigned int rate = params_rate(params); | ||
46 | |||
47 | /* | ||
48 | * According to CS4271 datasheet we use MCLK/LRCK=256 for | ||
49 | * rates below 50kHz and 128 for higher sample rates | ||
50 | */ | ||
51 | if (rate < 50000) | ||
52 | mclk_rate = rate * 64 * 4; | ||
53 | else | ||
54 | mclk_rate = rate * 64 * 2; | ||
55 | |||
56 | err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
57 | SND_SOC_DAIFMT_NB_IF | | ||
58 | SND_SOC_DAIFMT_CBS_CFS); | ||
59 | if (err) | ||
60 | return err; | ||
61 | |||
62 | err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
63 | SND_SOC_DAIFMT_NB_IF | | ||
64 | SND_SOC_DAIFMT_CBS_CFS); | ||
65 | if (err) | ||
66 | return err; | ||
67 | |||
68 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk_rate, | ||
69 | SND_SOC_CLOCK_IN); | ||
70 | if (err) | ||
71 | return err; | ||
72 | |||
73 | return snd_soc_dai_set_sysclk(cpu_dai, 0, mclk_rate, | ||
74 | SND_SOC_CLOCK_OUT); | ||
75 | } | ||
76 | |||
77 | static struct snd_soc_ops edb93xx_ops = { | ||
78 | .hw_params = edb93xx_hw_params, | ||
79 | }; | ||
80 | |||
81 | static struct snd_soc_dai_link edb93xx_dai = { | ||
82 | .name = "CS4271", | ||
83 | .stream_name = "CS4271 HiFi", | ||
84 | .platform_name = "ep93xx-pcm-audio", | ||
85 | .cpu_dai_name = "ep93xx-i2s", | ||
86 | .codec_name = "spi0.0", | ||
87 | .codec_dai_name = "cs4271-hifi", | ||
88 | .ops = &edb93xx_ops, | ||
89 | }; | ||
90 | |||
91 | static struct snd_soc_card snd_soc_edb93xx = { | ||
92 | .name = "EDB93XX", | ||
93 | .dai_link = &edb93xx_dai, | ||
94 | .num_links = 1, | ||
95 | }; | ||
96 | |||
97 | static struct platform_device *edb93xx_snd_device; | ||
98 | |||
99 | static int __init edb93xx_init(void) | ||
100 | { | ||
101 | int ret; | ||
102 | |||
103 | if (!edb93xx_has_audio()) | ||
104 | return -ENODEV; | ||
105 | |||
106 | ret = ep93xx_i2s_acquire(EP93XX_SYSCON_DEVCFG_I2SONAC97, | ||
107 | EP93XX_SYSCON_I2SCLKDIV_ORIDE | | ||
108 | EP93XX_SYSCON_I2SCLKDIV_SPOL); | ||
109 | if (ret) | ||
110 | return ret; | ||
111 | |||
112 | edb93xx_snd_device = platform_device_alloc("soc-audio", -1); | ||
113 | if (!edb93xx_snd_device) { | ||
114 | ret = -ENOMEM; | ||
115 | goto free_i2s; | ||
116 | } | ||
117 | |||
118 | platform_set_drvdata(edb93xx_snd_device, &snd_soc_edb93xx); | ||
119 | ret = platform_device_add(edb93xx_snd_device); | ||
120 | if (ret) | ||
121 | goto device_put; | ||
122 | |||
123 | return 0; | ||
124 | |||
125 | device_put: | ||
126 | platform_device_put(edb93xx_snd_device); | ||
127 | free_i2s: | ||
128 | ep93xx_i2s_release(); | ||
129 | return ret; | ||
130 | } | ||
131 | module_init(edb93xx_init); | ||
132 | |||
133 | static void __exit edb93xx_exit(void) | ||
134 | { | ||
135 | platform_device_unregister(edb93xx_snd_device); | ||
136 | ep93xx_i2s_release(); | ||
137 | } | ||
138 | module_exit(edb93xx_exit); | ||
139 | |||
140 | MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>"); | ||
141 | MODULE_DESCRIPTION("ALSA SoC EDB93xx"); | ||
142 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/ep93xx/ep93xx-ac97.c b/sound/soc/ep93xx/ep93xx-ac97.c index 68a0bae1208a..104e95cda0ad 100644 --- a/sound/soc/ep93xx/ep93xx-ac97.c +++ b/sound/soc/ep93xx/ep93xx-ac97.c | |||
@@ -253,7 +253,6 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream, | |||
253 | struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai); | 253 | struct ep93xx_ac97_info *info = snd_soc_dai_get_drvdata(dai); |
254 | unsigned v = 0; | 254 | unsigned v = 0; |
255 | 255 | ||
256 | |||
257 | switch (cmd) { | 256 | switch (cmd) { |
258 | case SNDRV_PCM_TRIGGER_START: | 257 | case SNDRV_PCM_TRIGGER_START: |
259 | case SNDRV_PCM_TRIGGER_RESUME: | 258 | case SNDRV_PCM_TRIGGER_RESUME: |
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c index fff579a1c134..042f4e93746f 100644 --- a/sound/soc/ep93xx/ep93xx-i2s.c +++ b/sound/soc/ep93xx/ep93xx-i2s.c | |||
@@ -242,7 +242,7 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
242 | { | 242 | { |
243 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); | 243 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); |
244 | unsigned word_len, div, sdiv, lrdiv; | 244 | unsigned word_len, div, sdiv, lrdiv; |
245 | int found = 0, err; | 245 | int err; |
246 | 246 | ||
247 | switch (params_format(params)) { | 247 | switch (params_format(params)) { |
248 | case SNDRV_PCM_FORMAT_S16_LE: | 248 | case SNDRV_PCM_FORMAT_S16_LE: |
@@ -275,15 +275,14 @@ static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
275 | * the codec uses. | 275 | * the codec uses. |
276 | */ | 276 | */ |
277 | div = clk_get_rate(info->mclk) / params_rate(params); | 277 | div = clk_get_rate(info->mclk) / params_rate(params); |
278 | for (sdiv = 2; sdiv <= 4; sdiv += 2) | 278 | sdiv = 4; |
279 | for (lrdiv = 64; lrdiv <= 128; lrdiv <<= 1) | 279 | if (div > (256 + 512) / 2) { |
280 | if (sdiv * lrdiv == div) { | 280 | lrdiv = 128; |
281 | found = 1; | 281 | } else { |
282 | goto out; | 282 | lrdiv = 64; |
283 | } | 283 | if (div < (128 + 256) / 2) |
284 | out: | 284 | sdiv = 2; |
285 | if (!found) | 285 | } |
286 | return -EINVAL; | ||
287 | 286 | ||
288 | err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv); | 287 | err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv); |
289 | if (err) | 288 | if (err) |
@@ -314,10 +313,12 @@ static int ep93xx_i2s_suspend(struct snd_soc_dai *dai) | |||
314 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); | 313 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); |
315 | 314 | ||
316 | if (!dai->active) | 315 | if (!dai->active) |
317 | return; | 316 | return 0; |
318 | 317 | ||
319 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK); | 318 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK); |
320 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE); | 319 | ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE); |
320 | |||
321 | return 0; | ||
321 | } | 322 | } |
322 | 323 | ||
323 | static int ep93xx_i2s_resume(struct snd_soc_dai *dai) | 324 | static int ep93xx_i2s_resume(struct snd_soc_dai *dai) |
@@ -325,10 +326,12 @@ static int ep93xx_i2s_resume(struct snd_soc_dai *dai) | |||
325 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); | 326 | struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai); |
326 | 327 | ||
327 | if (!dai->active) | 328 | if (!dai->active) |
328 | return; | 329 | return 0; |
329 | 330 | ||
330 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK); | 331 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK); |
331 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE); | 332 | ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE); |
333 | |||
334 | return 0; | ||
332 | } | 335 | } |
333 | #else | 336 | #else |
334 | #define ep93xx_i2s_suspend NULL | 337 | #define ep93xx_i2s_suspend NULL |
@@ -352,13 +355,13 @@ static struct snd_soc_dai_driver ep93xx_i2s_dai = { | |||
352 | .playback = { | 355 | .playback = { |
353 | .channels_min = 2, | 356 | .channels_min = 2, |
354 | .channels_max = 2, | 357 | .channels_max = 2, |
355 | .rates = SNDRV_PCM_RATE_8000_96000, | 358 | .rates = SNDRV_PCM_RATE_8000_192000, |
356 | .formats = EP93XX_I2S_FORMATS, | 359 | .formats = EP93XX_I2S_FORMATS, |
357 | }, | 360 | }, |
358 | .capture = { | 361 | .capture = { |
359 | .channels_min = 2, | 362 | .channels_min = 2, |
360 | .channels_max = 2, | 363 | .channels_max = 2, |
361 | .rates = SNDRV_PCM_RATE_8000_96000, | 364 | .rates = SNDRV_PCM_RATE_8000_192000, |
362 | .formats = EP93XX_I2S_FORMATS, | 365 | .formats = EP93XX_I2S_FORMATS, |
363 | }, | 366 | }, |
364 | .ops = &ep93xx_i2s_dai_ops, | 367 | .ops = &ep93xx_i2s_dai_ops, |
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index 06670776f649..a456e491155f 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c | |||
@@ -35,9 +35,9 @@ static const struct snd_pcm_hardware ep93xx_pcm_hardware = { | |||
35 | SNDRV_PCM_INFO_INTERLEAVED | | 35 | SNDRV_PCM_INFO_INTERLEAVED | |
36 | SNDRV_PCM_INFO_BLOCK_TRANSFER), | 36 | SNDRV_PCM_INFO_BLOCK_TRANSFER), |
37 | 37 | ||
38 | .rates = SNDRV_PCM_RATE_8000_96000, | 38 | .rates = SNDRV_PCM_RATE_8000_192000, |
39 | .rate_min = SNDRV_PCM_RATE_8000, | 39 | .rate_min = SNDRV_PCM_RATE_8000, |
40 | .rate_max = SNDRV_PCM_RATE_96000, | 40 | .rate_max = SNDRV_PCM_RATE_192000, |
41 | 41 | ||
42 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | 42 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | |
43 | SNDRV_PCM_FMTBIT_S24_LE | | 43 | SNDRV_PCM_FMTBIT_S24_LE | |
diff --git a/sound/soc/fsl/mpc8610_hpcd.c b/sound/soc/fsl/mpc8610_hpcd.c index 7d7847a1e66b..c16c6b2eff95 100644 --- a/sound/soc/fsl/mpc8610_hpcd.c +++ b/sound/soc/fsl/mpc8610_hpcd.c | |||
@@ -53,9 +53,8 @@ struct mpc8610_hpcd_data { | |||
53 | * | 53 | * |
54 | * Here we program the DMACR and PMUXCR registers. | 54 | * Here we program the DMACR and PMUXCR registers. |
55 | */ | 55 | */ |
56 | static int mpc8610_hpcd_machine_probe(struct platform_device *sound_device) | 56 | static int mpc8610_hpcd_machine_probe(struct snd_soc_card *card) |
57 | { | 57 | { |
58 | struct snd_soc_card *card = platform_get_drvdata(sound_device); | ||
59 | struct mpc8610_hpcd_data *machine_data = | 58 | struct mpc8610_hpcd_data *machine_data = |
60 | container_of(card, struct mpc8610_hpcd_data, card); | 59 | container_of(card, struct mpc8610_hpcd_data, card); |
61 | struct ccsr_guts_86xx __iomem *guts; | 60 | struct ccsr_guts_86xx __iomem *guts; |
@@ -138,9 +137,8 @@ static int mpc8610_hpcd_startup(struct snd_pcm_substream *substream) | |||
138 | * This function is called to remove the sound device for one SSI. We | 137 | * This function is called to remove the sound device for one SSI. We |
139 | * de-program the DMACR and PMUXCR register. | 138 | * de-program the DMACR and PMUXCR register. |
140 | */ | 139 | */ |
141 | static int mpc8610_hpcd_machine_remove(struct platform_device *sound_device) | 140 | static int mpc8610_hpcd_machine_remove(struct snd_soc_card *card) |
142 | { | 141 | { |
143 | struct snd_soc_card *card = platform_get_drvdata(sound_device); | ||
144 | struct mpc8610_hpcd_data *machine_data = | 142 | struct mpc8610_hpcd_data *machine_data = |
145 | container_of(card, struct mpc8610_hpcd_data, card); | 143 | container_of(card, struct mpc8610_hpcd_data, card); |
146 | struct ccsr_guts_86xx __iomem *guts; | 144 | struct ccsr_guts_86xx __iomem *guts; |
diff --git a/sound/soc/fsl/p1022_ds.c b/sound/soc/fsl/p1022_ds.c index 026b756961e0..66e0b68af147 100644 --- a/sound/soc/fsl/p1022_ds.c +++ b/sound/soc/fsl/p1022_ds.c | |||
@@ -85,9 +85,8 @@ struct machine_data { | |||
85 | * | 85 | * |
86 | * Here we program the DMACR and PMUXCR registers. | 86 | * Here we program the DMACR and PMUXCR registers. |
87 | */ | 87 | */ |
88 | static int p1022_ds_machine_probe(struct platform_device *sound_device) | 88 | static int p1022_ds_machine_probe(struct snd_soc_card *card) |
89 | { | 89 | { |
90 | struct snd_soc_card *card = platform_get_drvdata(sound_device); | ||
91 | struct machine_data *mdata = | 90 | struct machine_data *mdata = |
92 | container_of(card, struct machine_data, card); | 91 | container_of(card, struct machine_data, card); |
93 | struct ccsr_guts_85xx __iomem *guts; | 92 | struct ccsr_guts_85xx __iomem *guts; |
@@ -160,9 +159,8 @@ static int p1022_ds_startup(struct snd_pcm_substream *substream) | |||
160 | * This function is called to remove the sound device for one SSI. We | 159 | * This function is called to remove the sound device for one SSI. We |
161 | * de-program the DMACR and PMUXCR register. | 160 | * de-program the DMACR and PMUXCR register. |
162 | */ | 161 | */ |
163 | static int p1022_ds_machine_remove(struct platform_device *sound_device) | 162 | static int p1022_ds_machine_remove(struct snd_soc_card *card) |
164 | { | 163 | { |
165 | struct snd_soc_card *card = platform_get_drvdata(sound_device); | ||
166 | struct machine_data *mdata = | 164 | struct machine_data *mdata = |
167 | container_of(card, struct machine_data, card); | 165 | container_of(card, struct machine_data, card); |
168 | struct ccsr_guts_85xx __iomem *guts; | 166 | struct ccsr_guts_85xx __iomem *guts; |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index 9eeb8f0d67e9..d8f130d39dd9 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
@@ -30,6 +30,16 @@ config SND_MXC_SOC_WM1133_EV1 | |||
30 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 | 30 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 |
31 | PMIC board with WM8835x fitted. | 31 | PMIC board with WM8835x fitted. |
32 | 32 | ||
33 | config SND_SOC_MX27VIS_AIC32X4 | ||
34 | tristate "SoC audio support for Visstrim M10 boards" | ||
35 | depends on MACH_IMX27_VISSTRIM_M10 | ||
36 | select SND_SOC_TVL320AIC32X4 | ||
37 | select SND_MXC_SOC_SSI | ||
38 | select SND_MXC_SOC_MX2 | ||
39 | help | ||
40 | Say Y if you want to add support for SoC audio on Visstrim SM10 | ||
41 | board with TLV320AIC32X4 codec. | ||
42 | |||
33 | config SND_SOC_PHYCORE_AC97 | 43 | config SND_SOC_PHYCORE_AC97 |
34 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" | 44 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" |
35 | depends on MACH_PCM043 || MACH_PCA100 | 45 | depends on MACH_PCM043 || MACH_PCA100 |
diff --git a/sound/soc/imx/Makefile b/sound/soc/imx/Makefile index b67fc02a4ecc..d6d609ba7e24 100644 --- a/sound/soc/imx/Makefile +++ b/sound/soc/imx/Makefile | |||
@@ -10,8 +10,10 @@ obj-$(CONFIG_SND_MXC_SOC_MX2) += snd-soc-imx-mx2.o | |||
10 | # i.MX Machine Support | 10 | # i.MX Machine Support |
11 | snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o | 11 | snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o |
12 | snd-soc-phycore-ac97-objs := phycore-ac97.o | 12 | snd-soc-phycore-ac97-objs := phycore-ac97.o |
13 | snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o | ||
13 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o | 14 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o |
14 | 15 | ||
15 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o | 16 | obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o |
16 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o | 17 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o |
18 | obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o | ||
17 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o | 19 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o |
diff --git a/sound/soc/imx/imx-ssi.c b/sound/soc/imx/imx-ssi.c index 30894ea7f333..bc92ec620004 100644 --- a/sound/soc/imx/imx-ssi.c +++ b/sound/soc/imx/imx-ssi.c | |||
@@ -108,7 +108,7 @@ static int imx_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | |||
108 | break; | 108 | break; |
109 | case SND_SOC_DAIFMT_DSP_B: | 109 | case SND_SOC_DAIFMT_DSP_B: |
110 | /* data on rising edge of bclk, frame high with data */ | 110 | /* data on rising edge of bclk, frame high with data */ |
111 | strcr |= SSI_STCR_TFSL; | 111 | strcr |= SSI_STCR_TFSL | SSI_STCR_TXBIT0; |
112 | break; | 112 | break; |
113 | case SND_SOC_DAIFMT_DSP_A: | 113 | case SND_SOC_DAIFMT_DSP_A: |
114 | /* data on rising edge of bclk, frame high 1clk before data */ | 114 | /* data on rising edge of bclk, frame high 1clk before data */ |
@@ -656,6 +656,9 @@ static int imx_ssi_probe(struct platform_device *pdev) | |||
656 | ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; | 656 | ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; |
657 | ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; | 657 | ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; |
658 | 658 | ||
659 | ssi->dma_params_tx.burstsize = 4; | ||
660 | ssi->dma_params_rx.burstsize = 4; | ||
661 | |||
659 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); | 662 | res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); |
660 | if (res) | 663 | if (res) |
661 | ssi->dma_params_tx.dma = res->start; | 664 | ssi->dma_params_tx.dma = res->start; |
diff --git a/sound/soc/imx/mx27vis-aic32x4.c b/sound/soc/imx/mx27vis-aic32x4.c new file mode 100644 index 000000000000..054110b91d42 --- /dev/null +++ b/sound/soc/imx/mx27vis-aic32x4.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* | ||
2 | * mx27vis-aic32x4.c | ||
3 | * | ||
4 | * Copyright 2011 Vista Silicon S.L. | ||
5 | * | ||
6 | * Author: Javier Martin <javier.martin@vista-silicon.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
21 | * MA 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/device.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | ||
32 | #include <asm/mach-types.h> | ||
33 | #include <mach/audmux.h> | ||
34 | |||
35 | #include "../codecs/tlv320aic32x4.h" | ||
36 | #include "imx-ssi.h" | ||
37 | |||
38 | static int mx27vis_aic32x4_hw_params(struct snd_pcm_substream *substream, | ||
39 | struct snd_pcm_hw_params *params) | ||
40 | { | ||
41 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
42 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
43 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
44 | int ret; | ||
45 | u32 dai_format; | ||
46 | |||
47 | dai_format = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | | ||
48 | SND_SOC_DAIFMT_CBM_CFM; | ||
49 | |||
50 | /* set codec DAI configuration */ | ||
51 | snd_soc_dai_set_fmt(codec_dai, dai_format); | ||
52 | |||
53 | /* set cpu DAI configuration */ | ||
54 | snd_soc_dai_set_fmt(cpu_dai, dai_format); | ||
55 | |||
56 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, | ||
57 | 25000000, SND_SOC_CLOCK_OUT); | ||
58 | if (ret) { | ||
59 | pr_err("%s: failed setting codec sysclk\n", __func__); | ||
60 | return ret; | ||
61 | } | ||
62 | |||
63 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, | ||
64 | SND_SOC_CLOCK_IN); | ||
65 | if (ret) { | ||
66 | pr_err("can't set CPU system clock IMX_SSP_SYS_CLK\n"); | ||
67 | return ret; | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static struct snd_soc_ops mx27vis_aic32x4_snd_ops = { | ||
74 | .hw_params = mx27vis_aic32x4_hw_params, | ||
75 | }; | ||
76 | |||
77 | static struct snd_soc_dai_link mx27vis_aic32x4_dai = { | ||
78 | .name = "tlv320aic32x4", | ||
79 | .stream_name = "TLV320AIC32X4", | ||
80 | .codec_dai_name = "tlv320aic32x4-hifi", | ||
81 | .platform_name = "imx-pcm-audio.0", | ||
82 | .codec_name = "tlv320aic32x4.0-0018", | ||
83 | .cpu_dai_name = "imx-ssi.0", | ||
84 | .ops = &mx27vis_aic32x4_snd_ops, | ||
85 | }; | ||
86 | |||
87 | static struct snd_soc_card mx27vis_aic32x4 = { | ||
88 | .name = "visstrim_m10-audio", | ||
89 | .dai_link = &mx27vis_aic32x4_dai, | ||
90 | .num_links = 1, | ||
91 | }; | ||
92 | |||
93 | static struct platform_device *mx27vis_aic32x4_snd_device; | ||
94 | |||
95 | static int __init mx27vis_aic32x4_init(void) | ||
96 | { | ||
97 | int ret; | ||
98 | |||
99 | mx27vis_aic32x4_snd_device = platform_device_alloc("soc-audio", -1); | ||
100 | if (!mx27vis_aic32x4_snd_device) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | platform_set_drvdata(mx27vis_aic32x4_snd_device, &mx27vis_aic32x4); | ||
104 | ret = platform_device_add(mx27vis_aic32x4_snd_device); | ||
105 | |||
106 | if (ret) { | ||
107 | printk(KERN_ERR "ASoC: Platform device allocation failed\n"); | ||
108 | platform_device_put(mx27vis_aic32x4_snd_device); | ||
109 | } | ||
110 | |||
111 | /* Connect SSI0 as clock slave to SSI1 external pins */ | ||
112 | mxc_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, | ||
113 | MXC_AUDMUX_V1_PCR_SYN | | ||
114 | MXC_AUDMUX_V1_PCR_TFSDIR | | ||
115 | MXC_AUDMUX_V1_PCR_TCLKDIR | | ||
116 | MXC_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | | ||
117 | MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_PPCR1_SSI_PINS_1) | ||
118 | ); | ||
119 | mxc_audmux_v1_configure_port(MX27_AUDMUX_PPCR1_SSI_PINS_1, | ||
120 | MXC_AUDMUX_V1_PCR_SYN | | ||
121 | MXC_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) | ||
122 | ); | ||
123 | |||
124 | return ret; | ||
125 | } | ||
126 | |||
127 | static void __exit mx27vis_aic32x4_exit(void) | ||
128 | { | ||
129 | platform_device_unregister(mx27vis_aic32x4_snd_device); | ||
130 | } | ||
131 | |||
132 | module_init(mx27vis_aic32x4_init); | ||
133 | module_exit(mx27vis_aic32x4_exit); | ||
134 | |||
135 | MODULE_AUTHOR("Javier Martin <javier.martin@vista-silicon.com>"); | ||
136 | MODULE_DESCRIPTION("ALSA SoC AIC32X4 mx27 visstrim"); | ||
137 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/mid-x86/Kconfig b/sound/soc/mid-x86/Kconfig new file mode 100644 index 000000000000..29350428f1c2 --- /dev/null +++ b/sound/soc/mid-x86/Kconfig | |||
@@ -0,0 +1,14 @@ | |||
1 | config SND_MFLD_MACHINE | ||
2 | tristate "SOC Machine Audio driver for Intel Medfield MID platform" | ||
3 | depends on INTEL_SCU_IPC | ||
4 | depends on SND_INTEL_SST | ||
5 | select SND_SOC_SN95031 | ||
6 | select SND_SST_PLATFORM | ||
7 | help | ||
8 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform | ||
9 | used as alsa device in audio substem in Intel(R) MID devices | ||
10 | Say Y if you have such a device | ||
11 | If unsure select "N". | ||
12 | |||
13 | config SND_SST_PLATFORM | ||
14 | tristate | ||
diff --git a/sound/soc/mid-x86/Makefile b/sound/soc/mid-x86/Makefile new file mode 100644 index 000000000000..639883339465 --- /dev/null +++ b/sound/soc/mid-x86/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | snd-soc-sst-platform-objs := sst_platform.o | ||
2 | snd-soc-mfld-machine-objs := mfld_machine.o | ||
3 | |||
4 | obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o | ||
5 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o | ||
diff --git a/sound/soc/mid-x86/mfld_machine.c b/sound/soc/mid-x86/mfld_machine.c new file mode 100644 index 000000000000..429aa1be2cff --- /dev/null +++ b/sound/soc/mid-x86/mfld_machine.c | |||
@@ -0,0 +1,452 @@ | |||
1 | /* | ||
2 | * mfld_machine.c - ASoc Machine driver for Intel Medfield MID platform | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | */ | ||
24 | |||
25 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
26 | |||
27 | #include <linux/init.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/io.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include <sound/jack.h> | ||
35 | #include "../codecs/sn95031.h" | ||
36 | |||
37 | #define MID_MONO 1 | ||
38 | #define MID_STEREO 2 | ||
39 | #define MID_MAX_CAP 5 | ||
40 | #define MFLD_JACK_INSERT 0x04 | ||
41 | |||
42 | enum soc_mic_bias_zones { | ||
43 | MFLD_MV_START = 0, | ||
44 | /* mic bias volutage range for Headphones*/ | ||
45 | MFLD_MV_HP = 400, | ||
46 | /* mic bias volutage range for American Headset*/ | ||
47 | MFLD_MV_AM_HS = 650, | ||
48 | /* mic bias volutage range for Headset*/ | ||
49 | MFLD_MV_HS = 2000, | ||
50 | MFLD_MV_UNDEFINED, | ||
51 | }; | ||
52 | |||
53 | static unsigned int hs_switch; | ||
54 | static unsigned int lo_dac; | ||
55 | |||
56 | struct mfld_mc_private { | ||
57 | struct platform_device *socdev; | ||
58 | void __iomem *int_base; | ||
59 | struct snd_soc_codec *codec; | ||
60 | u8 interrupt_status; | ||
61 | }; | ||
62 | |||
63 | struct snd_soc_jack mfld_jack; | ||
64 | |||
65 | /*Headset jack detection DAPM pins */ | ||
66 | static struct snd_soc_jack_pin mfld_jack_pins[] = { | ||
67 | { | ||
68 | .pin = "Headphones", | ||
69 | .mask = SND_JACK_HEADPHONE, | ||
70 | }, | ||
71 | { | ||
72 | .pin = "AMIC1", | ||
73 | .mask = SND_JACK_MICROPHONE, | ||
74 | }, | ||
75 | }; | ||
76 | |||
77 | /* jack detection voltage zones */ | ||
78 | static struct snd_soc_jack_zone mfld_zones[] = { | ||
79 | {MFLD_MV_START, MFLD_MV_AM_HS, SND_JACK_HEADPHONE}, | ||
80 | {MFLD_MV_AM_HS, MFLD_MV_HS, SND_JACK_HEADSET}, | ||
81 | }; | ||
82 | |||
83 | /* sound card controls */ | ||
84 | static const char *headset_switch_text[] = {"Earpiece", "Headset"}; | ||
85 | |||
86 | static const char *lo_text[] = {"Vibra", "Headset", "IHF", "None"}; | ||
87 | |||
88 | static const struct soc_enum headset_enum = | ||
89 | SOC_ENUM_SINGLE_EXT(2, headset_switch_text); | ||
90 | |||
91 | static const struct soc_enum lo_enum = | ||
92 | SOC_ENUM_SINGLE_EXT(4, lo_text); | ||
93 | |||
94 | static int headset_get_switch(struct snd_kcontrol *kcontrol, | ||
95 | struct snd_ctl_elem_value *ucontrol) | ||
96 | { | ||
97 | ucontrol->value.integer.value[0] = hs_switch; | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static int headset_set_switch(struct snd_kcontrol *kcontrol, | ||
102 | struct snd_ctl_elem_value *ucontrol) | ||
103 | { | ||
104 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
105 | |||
106 | if (ucontrol->value.integer.value[0] == hs_switch) | ||
107 | return 0; | ||
108 | |||
109 | if (ucontrol->value.integer.value[0]) { | ||
110 | pr_debug("hs_set HS path\n"); | ||
111 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | ||
112 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | ||
113 | } else { | ||
114 | pr_debug("hs_set EP path\n"); | ||
115 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | ||
116 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | ||
117 | } | ||
118 | snd_soc_dapm_sync(&codec->dapm); | ||
119 | hs_switch = ucontrol->value.integer.value[0]; | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static void lo_enable_out_pins(struct snd_soc_codec *codec) | ||
125 | { | ||
126 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); | ||
127 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); | ||
128 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); | ||
129 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); | ||
130 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); | ||
131 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); | ||
132 | if (hs_switch) { | ||
133 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | ||
134 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | ||
135 | } else { | ||
136 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | ||
137 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | static int lo_get_switch(struct snd_kcontrol *kcontrol, | ||
142 | struct snd_ctl_elem_value *ucontrol) | ||
143 | { | ||
144 | ucontrol->value.integer.value[0] = lo_dac; | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int lo_set_switch(struct snd_kcontrol *kcontrol, | ||
149 | struct snd_ctl_elem_value *ucontrol) | ||
150 | { | ||
151 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
152 | |||
153 | if (ucontrol->value.integer.value[0] == lo_dac) | ||
154 | return 0; | ||
155 | |||
156 | /* we dont want to work with last state of lineout so just enable all | ||
157 | * pins and then disable pins not required | ||
158 | */ | ||
159 | lo_enable_out_pins(codec); | ||
160 | switch (ucontrol->value.integer.value[0]) { | ||
161 | case 0: | ||
162 | pr_debug("set vibra path\n"); | ||
163 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); | ||
164 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); | ||
165 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); | ||
166 | break; | ||
167 | |||
168 | case 1: | ||
169 | pr_debug("set hs path\n"); | ||
170 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | ||
171 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | ||
172 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); | ||
173 | break; | ||
174 | |||
175 | case 2: | ||
176 | pr_debug("set spkr path\n"); | ||
177 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); | ||
178 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); | ||
179 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); | ||
180 | break; | ||
181 | |||
182 | case 3: | ||
183 | pr_debug("set null path\n"); | ||
184 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); | ||
185 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); | ||
186 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); | ||
187 | break; | ||
188 | } | ||
189 | snd_soc_dapm_sync(&codec->dapm); | ||
190 | lo_dac = ucontrol->value.integer.value[0]; | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static const struct snd_kcontrol_new mfld_snd_controls[] = { | ||
195 | SOC_ENUM_EXT("Playback Switch", headset_enum, | ||
196 | headset_get_switch, headset_set_switch), | ||
197 | SOC_ENUM_EXT("Lineout Mux", lo_enum, | ||
198 | lo_get_switch, lo_set_switch), | ||
199 | }; | ||
200 | |||
201 | static const struct snd_soc_dapm_widget mfld_widgets[] = { | ||
202 | SND_SOC_DAPM_HP("Headphones", NULL), | ||
203 | SND_SOC_DAPM_MIC("Mic", NULL), | ||
204 | }; | ||
205 | |||
206 | static const struct snd_soc_dapm_route mfld_map[] = { | ||
207 | {"Headphones", NULL, "HPOUTR"}, | ||
208 | {"Headphones", NULL, "HPOUTL"}, | ||
209 | {"Mic", NULL, "AMIC1"}, | ||
210 | }; | ||
211 | |||
212 | static void mfld_jack_check(unsigned int intr_status) | ||
213 | { | ||
214 | struct mfld_jack_data jack_data; | ||
215 | |||
216 | jack_data.mfld_jack = &mfld_jack; | ||
217 | jack_data.intr_id = intr_status; | ||
218 | |||
219 | sn95031_jack_detection(&jack_data); | ||
220 | /* TODO: add american headset detection post gpiolib support */ | ||
221 | } | ||
222 | |||
223 | static int mfld_init(struct snd_soc_pcm_runtime *runtime) | ||
224 | { | ||
225 | struct snd_soc_codec *codec = runtime->codec; | ||
226 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
227 | int ret_val; | ||
228 | |||
229 | /* Add jack sense widgets */ | ||
230 | snd_soc_dapm_new_controls(dapm, mfld_widgets, ARRAY_SIZE(mfld_widgets)); | ||
231 | |||
232 | /* Set up the map */ | ||
233 | snd_soc_dapm_add_routes(dapm, mfld_map, ARRAY_SIZE(mfld_map)); | ||
234 | |||
235 | /* always connected */ | ||
236 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | ||
237 | snd_soc_dapm_enable_pin(dapm, "Mic"); | ||
238 | snd_soc_dapm_sync(dapm); | ||
239 | |||
240 | ret_val = snd_soc_add_controls(codec, mfld_snd_controls, | ||
241 | ARRAY_SIZE(mfld_snd_controls)); | ||
242 | if (ret_val) { | ||
243 | pr_err("soc_add_controls failed %d", ret_val); | ||
244 | return ret_val; | ||
245 | } | ||
246 | /* default is earpiece pin, userspace sets it explcitly */ | ||
247 | snd_soc_dapm_disable_pin(dapm, "Headphones"); | ||
248 | /* default is lineout NC, userspace sets it explcitly */ | ||
249 | snd_soc_dapm_disable_pin(dapm, "LINEOUTL"); | ||
250 | snd_soc_dapm_disable_pin(dapm, "LINEOUTR"); | ||
251 | lo_dac = 3; | ||
252 | hs_switch = 0; | ||
253 | /* we dont use linein in this so set to NC */ | ||
254 | snd_soc_dapm_disable_pin(dapm, "LINEINL"); | ||
255 | snd_soc_dapm_disable_pin(dapm, "LINEINR"); | ||
256 | snd_soc_dapm_sync(dapm); | ||
257 | |||
258 | /* Headset and button jack detection */ | ||
259 | ret_val = snd_soc_jack_new(codec, "Intel(R) MID Audio Jack", | ||
260 | SND_JACK_HEADSET | SND_JACK_BTN_0 | | ||
261 | SND_JACK_BTN_1, &mfld_jack); | ||
262 | if (ret_val) { | ||
263 | pr_err("jack creation failed\n"); | ||
264 | return ret_val; | ||
265 | } | ||
266 | |||
267 | ret_val = snd_soc_jack_add_pins(&mfld_jack, | ||
268 | ARRAY_SIZE(mfld_jack_pins), mfld_jack_pins); | ||
269 | if (ret_val) { | ||
270 | pr_err("adding jack pins failed\n"); | ||
271 | return ret_val; | ||
272 | } | ||
273 | ret_val = snd_soc_jack_add_zones(&mfld_jack, | ||
274 | ARRAY_SIZE(mfld_zones), mfld_zones); | ||
275 | if (ret_val) { | ||
276 | pr_err("adding jack zones failed\n"); | ||
277 | return ret_val; | ||
278 | } | ||
279 | |||
280 | /* we want to check if anything is inserted at boot, | ||
281 | * so send a fake event to codec and it will read adc | ||
282 | * to find if anything is there or not */ | ||
283 | mfld_jack_check(MFLD_JACK_INSERT); | ||
284 | return ret_val; | ||
285 | } | ||
286 | |||
287 | struct snd_soc_dai_link mfld_msic_dailink[] = { | ||
288 | { | ||
289 | .name = "Medfield Headset", | ||
290 | .stream_name = "Headset", | ||
291 | .cpu_dai_name = "Headset-cpu-dai", | ||
292 | .codec_dai_name = "SN95031 Headset", | ||
293 | .codec_name = "sn95031", | ||
294 | .platform_name = "sst-platform", | ||
295 | .init = mfld_init, | ||
296 | }, | ||
297 | { | ||
298 | .name = "Medfield Speaker", | ||
299 | .stream_name = "Speaker", | ||
300 | .cpu_dai_name = "Speaker-cpu-dai", | ||
301 | .codec_dai_name = "SN95031 Speaker", | ||
302 | .codec_name = "sn95031", | ||
303 | .platform_name = "sst-platform", | ||
304 | .init = NULL, | ||
305 | }, | ||
306 | { | ||
307 | .name = "Medfield Vibra", | ||
308 | .stream_name = "Vibra1", | ||
309 | .cpu_dai_name = "Vibra1-cpu-dai", | ||
310 | .codec_dai_name = "SN95031 Vibra1", | ||
311 | .codec_name = "sn95031", | ||
312 | .platform_name = "sst-platform", | ||
313 | .init = NULL, | ||
314 | }, | ||
315 | { | ||
316 | .name = "Medfield Haptics", | ||
317 | .stream_name = "Vibra2", | ||
318 | .cpu_dai_name = "Vibra2-cpu-dai", | ||
319 | .codec_dai_name = "SN95031 Vibra2", | ||
320 | .codec_name = "sn95031", | ||
321 | .platform_name = "sst-platform", | ||
322 | .init = NULL, | ||
323 | }, | ||
324 | }; | ||
325 | |||
326 | /* SoC card */ | ||
327 | static struct snd_soc_card snd_soc_card_mfld = { | ||
328 | .name = "medfield_audio", | ||
329 | .dai_link = mfld_msic_dailink, | ||
330 | .num_links = ARRAY_SIZE(mfld_msic_dailink), | ||
331 | }; | ||
332 | |||
333 | static irqreturn_t snd_mfld_jack_intr_handler(int irq, void *dev) | ||
334 | { | ||
335 | struct mfld_mc_private *mc_private = (struct mfld_mc_private *) dev; | ||
336 | |||
337 | memcpy_fromio(&mc_private->interrupt_status, | ||
338 | ((void *)(mc_private->int_base)), | ||
339 | sizeof(u8)); | ||
340 | return IRQ_WAKE_THREAD; | ||
341 | } | ||
342 | |||
343 | static irqreturn_t snd_mfld_jack_detection(int irq, void *data) | ||
344 | { | ||
345 | struct mfld_mc_private *mc_drv_ctx = (struct mfld_mc_private *) data; | ||
346 | |||
347 | if (mfld_jack.codec == NULL) | ||
348 | return IRQ_HANDLED; | ||
349 | mfld_jack_check(mc_drv_ctx->interrupt_status); | ||
350 | |||
351 | return IRQ_HANDLED; | ||
352 | } | ||
353 | |||
354 | static int __devinit snd_mfld_mc_probe(struct platform_device *pdev) | ||
355 | { | ||
356 | int ret_val = 0, irq; | ||
357 | struct mfld_mc_private *mc_drv_ctx; | ||
358 | struct resource *irq_mem; | ||
359 | |||
360 | pr_debug("snd_mfld_mc_probe called\n"); | ||
361 | |||
362 | /* retrive the irq number */ | ||
363 | irq = platform_get_irq(pdev, 0); | ||
364 | |||
365 | /* audio interrupt base of SRAM location where | ||
366 | * interrupts are stored by System FW */ | ||
367 | mc_drv_ctx = kzalloc(sizeof(*mc_drv_ctx), GFP_ATOMIC); | ||
368 | if (!mc_drv_ctx) { | ||
369 | pr_err("allocation failed\n"); | ||
370 | return -ENOMEM; | ||
371 | } | ||
372 | |||
373 | irq_mem = platform_get_resource_byname( | ||
374 | pdev, IORESOURCE_MEM, "IRQ_BASE"); | ||
375 | if (!irq_mem) { | ||
376 | pr_err("no mem resource given\n"); | ||
377 | ret_val = -ENODEV; | ||
378 | goto unalloc; | ||
379 | } | ||
380 | mc_drv_ctx->int_base = ioremap_nocache(irq_mem->start, | ||
381 | resource_size(irq_mem)); | ||
382 | if (!mc_drv_ctx->int_base) { | ||
383 | pr_err("Mapping of cache failed\n"); | ||
384 | ret_val = -ENOMEM; | ||
385 | goto unalloc; | ||
386 | } | ||
387 | /* register for interrupt */ | ||
388 | ret_val = request_threaded_irq(irq, snd_mfld_jack_intr_handler, | ||
389 | snd_mfld_jack_detection, | ||
390 | IRQF_SHARED, pdev->dev.driver->name, mc_drv_ctx); | ||
391 | if (ret_val) { | ||
392 | pr_err("cannot register IRQ\n"); | ||
393 | goto unalloc; | ||
394 | } | ||
395 | /* register the soc card */ | ||
396 | snd_soc_card_mfld.dev = &pdev->dev; | ||
397 | ret_val = snd_soc_register_card(&snd_soc_card_mfld); | ||
398 | if (ret_val) { | ||
399 | pr_debug("snd_soc_register_card failed %d\n", ret_val); | ||
400 | goto freeirq; | ||
401 | } | ||
402 | platform_set_drvdata(pdev, mc_drv_ctx); | ||
403 | pr_debug("successfully exited probe\n"); | ||
404 | return ret_val; | ||
405 | |||
406 | freeirq: | ||
407 | free_irq(irq, mc_drv_ctx); | ||
408 | unalloc: | ||
409 | kfree(mc_drv_ctx); | ||
410 | return ret_val; | ||
411 | } | ||
412 | |||
413 | static int __devexit snd_mfld_mc_remove(struct platform_device *pdev) | ||
414 | { | ||
415 | struct mfld_mc_private *mc_drv_ctx = platform_get_drvdata(pdev); | ||
416 | |||
417 | pr_debug("snd_mfld_mc_remove called\n"); | ||
418 | free_irq(platform_get_irq(pdev, 0), mc_drv_ctx); | ||
419 | snd_soc_unregister_card(&snd_soc_card_mfld); | ||
420 | kfree(mc_drv_ctx); | ||
421 | platform_set_drvdata(pdev, NULL); | ||
422 | return 0; | ||
423 | } | ||
424 | |||
425 | static struct platform_driver snd_mfld_mc_driver = { | ||
426 | .driver = { | ||
427 | .owner = THIS_MODULE, | ||
428 | .name = "msic_audio", | ||
429 | }, | ||
430 | .probe = snd_mfld_mc_probe, | ||
431 | .remove = __devexit_p(snd_mfld_mc_remove), | ||
432 | }; | ||
433 | |||
434 | static int __init snd_mfld_driver_init(void) | ||
435 | { | ||
436 | pr_debug("snd_mfld_driver_init called\n"); | ||
437 | return platform_driver_register(&snd_mfld_mc_driver); | ||
438 | } | ||
439 | module_init(snd_mfld_driver_init); | ||
440 | |||
441 | static void __exit snd_mfld_driver_exit(void) | ||
442 | { | ||
443 | pr_debug("snd_mfld_driver_exit called\n"); | ||
444 | platform_driver_unregister(&snd_mfld_mc_driver); | ||
445 | } | ||
446 | module_exit(snd_mfld_driver_exit); | ||
447 | |||
448 | MODULE_DESCRIPTION("ASoC Intel(R) MID Machine driver"); | ||
449 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
450 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
451 | MODULE_LICENSE("GPL v2"); | ||
452 | MODULE_ALIAS("platform:msic-audio"); | ||
diff --git a/sound/soc/mid-x86/sst_platform.c b/sound/soc/mid-x86/sst_platform.c new file mode 100644 index 000000000000..ee2c22475a76 --- /dev/null +++ b/sound/soc/mid-x86/sst_platform.c | |||
@@ -0,0 +1,474 @@ | |||
1 | /* | ||
2 | * sst_platform.c - Intel MID Platform driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
27 | |||
28 | #include <linux/slab.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/soc.h> | ||
34 | #include "../../../drivers/staging/intel_sst/intel_sst_ioctl.h" | ||
35 | #include "../../../drivers/staging/intel_sst/intel_sst.h" | ||
36 | #include "sst_platform.h" | ||
37 | |||
38 | static struct snd_pcm_hardware sst_platform_pcm_hw = { | ||
39 | .info = (SNDRV_PCM_INFO_INTERLEAVED | | ||
40 | SNDRV_PCM_INFO_DOUBLE | | ||
41 | SNDRV_PCM_INFO_PAUSE | | ||
42 | SNDRV_PCM_INFO_RESUME | | ||
43 | SNDRV_PCM_INFO_MMAP| | ||
44 | SNDRV_PCM_INFO_MMAP_VALID | | ||
45 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
46 | SNDRV_PCM_INFO_SYNC_START), | ||
47 | .formats = (SNDRV_PCM_FMTBIT_S16 | SNDRV_PCM_FMTBIT_U16 | | ||
48 | SNDRV_PCM_FMTBIT_S24 | SNDRV_PCM_FMTBIT_U24 | | ||
49 | SNDRV_PCM_FMTBIT_S32 | SNDRV_PCM_FMTBIT_U32), | ||
50 | .rates = (SNDRV_PCM_RATE_8000| | ||
51 | SNDRV_PCM_RATE_44100 | | ||
52 | SNDRV_PCM_RATE_48000), | ||
53 | .rate_min = SST_MIN_RATE, | ||
54 | .rate_max = SST_MAX_RATE, | ||
55 | .channels_min = SST_MIN_CHANNEL, | ||
56 | .channels_max = SST_MAX_CHANNEL, | ||
57 | .buffer_bytes_max = SST_MAX_BUFFER, | ||
58 | .period_bytes_min = SST_MIN_PERIOD_BYTES, | ||
59 | .period_bytes_max = SST_MAX_PERIOD_BYTES, | ||
60 | .periods_min = SST_MIN_PERIODS, | ||
61 | .periods_max = SST_MAX_PERIODS, | ||
62 | .fifo_size = SST_FIFO_SIZE, | ||
63 | }; | ||
64 | |||
65 | /* MFLD - MSIC */ | ||
66 | struct snd_soc_dai_driver sst_platform_dai[] = { | ||
67 | { | ||
68 | .name = "Headset-cpu-dai", | ||
69 | .id = 0, | ||
70 | .playback = { | ||
71 | .channels_min = SST_STEREO, | ||
72 | .channels_max = SST_STEREO, | ||
73 | .rates = SNDRV_PCM_RATE_48000, | ||
74 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
75 | }, | ||
76 | .capture = { | ||
77 | .channels_min = 1, | ||
78 | .channels_max = 5, | ||
79 | .rates = SNDRV_PCM_RATE_48000, | ||
80 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
81 | }, | ||
82 | }, | ||
83 | { | ||
84 | .name = "Speaker-cpu-dai", | ||
85 | .id = 1, | ||
86 | .playback = { | ||
87 | .channels_min = SST_MONO, | ||
88 | .channels_max = SST_STEREO, | ||
89 | .rates = SNDRV_PCM_RATE_48000, | ||
90 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
91 | }, | ||
92 | }, | ||
93 | { | ||
94 | .name = "Vibra1-cpu-dai", | ||
95 | .id = 2, | ||
96 | .playback = { | ||
97 | .channels_min = SST_MONO, | ||
98 | .channels_max = SST_MONO, | ||
99 | .rates = SNDRV_PCM_RATE_48000, | ||
100 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
101 | }, | ||
102 | }, | ||
103 | { | ||
104 | .name = "Vibra2-cpu-dai", | ||
105 | .id = 3, | ||
106 | .playback = { | ||
107 | .channels_min = SST_MONO, | ||
108 | .channels_max = SST_STEREO, | ||
109 | .rates = SNDRV_PCM_RATE_48000, | ||
110 | .formats = SNDRV_PCM_FMTBIT_S24_LE, | ||
111 | }, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | /* helper functions */ | ||
116 | static inline void sst_set_stream_status(struct sst_runtime_stream *stream, | ||
117 | int state) | ||
118 | { | ||
119 | spin_lock(&stream->status_lock); | ||
120 | stream->stream_status = state; | ||
121 | spin_unlock(&stream->status_lock); | ||
122 | } | ||
123 | |||
124 | static inline int sst_get_stream_status(struct sst_runtime_stream *stream) | ||
125 | { | ||
126 | int state; | ||
127 | |||
128 | spin_lock(&stream->status_lock); | ||
129 | state = stream->stream_status; | ||
130 | spin_unlock(&stream->status_lock); | ||
131 | return state; | ||
132 | } | ||
133 | |||
134 | static void sst_fill_pcm_params(struct snd_pcm_substream *substream, | ||
135 | struct snd_sst_stream_params *param) | ||
136 | { | ||
137 | |||
138 | param->uc.pcm_params.codec = SST_CODEC_TYPE_PCM; | ||
139 | param->uc.pcm_params.num_chan = (u8) substream->runtime->channels; | ||
140 | param->uc.pcm_params.pcm_wd_sz = substream->runtime->sample_bits; | ||
141 | param->uc.pcm_params.reserved = 0; | ||
142 | param->uc.pcm_params.sfreq = substream->runtime->rate; | ||
143 | param->uc.pcm_params.ring_buffer_size = | ||
144 | snd_pcm_lib_buffer_bytes(substream); | ||
145 | param->uc.pcm_params.period_count = substream->runtime->period_size; | ||
146 | param->uc.pcm_params.ring_buffer_addr = | ||
147 | virt_to_phys(substream->dma_buffer.area); | ||
148 | pr_debug("period_cnt = %d\n", param->uc.pcm_params.period_count); | ||
149 | pr_debug("sfreq= %d, wd_sz = %d\n", | ||
150 | param->uc.pcm_params.sfreq, param->uc.pcm_params.pcm_wd_sz); | ||
151 | } | ||
152 | |||
153 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream) | ||
154 | { | ||
155 | struct sst_runtime_stream *stream = | ||
156 | substream->runtime->private_data; | ||
157 | struct snd_sst_stream_params param = {{{0,},},}; | ||
158 | struct snd_sst_params str_params = {0}; | ||
159 | int ret_val; | ||
160 | |||
161 | /* set codec params and inform SST driver the same */ | ||
162 | sst_fill_pcm_params(substream, ¶m); | ||
163 | substream->runtime->dma_area = substream->dma_buffer.area; | ||
164 | str_params.sparams = param; | ||
165 | str_params.codec = param.uc.pcm_params.codec; | ||
166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
167 | str_params.ops = STREAM_OPS_PLAYBACK; | ||
168 | str_params.device_type = substream->pcm->device + 1; | ||
169 | pr_debug("Playbck stream,Device %d\n", | ||
170 | substream->pcm->device); | ||
171 | } else { | ||
172 | str_params.ops = STREAM_OPS_CAPTURE; | ||
173 | str_params.device_type = SND_SST_DEVICE_CAPTURE; | ||
174 | pr_debug("Capture stream,Device %d\n", | ||
175 | substream->pcm->device); | ||
176 | } | ||
177 | ret_val = stream->sstdrv_ops->pcm_control->open(&str_params); | ||
178 | pr_debug("SST_SND_PLAY/CAPTURE ret_val = %x\n", ret_val); | ||
179 | if (ret_val < 0) | ||
180 | return ret_val; | ||
181 | |||
182 | stream->stream_info.str_id = ret_val; | ||
183 | pr_debug("str id : %d\n", stream->stream_info.str_id); | ||
184 | return ret_val; | ||
185 | } | ||
186 | |||
187 | static void sst_period_elapsed(void *mad_substream) | ||
188 | { | ||
189 | struct snd_pcm_substream *substream = mad_substream; | ||
190 | struct sst_runtime_stream *stream; | ||
191 | int status; | ||
192 | |||
193 | if (!substream || !substream->runtime) | ||
194 | return; | ||
195 | stream = substream->runtime->private_data; | ||
196 | if (!stream) | ||
197 | return; | ||
198 | status = sst_get_stream_status(stream); | ||
199 | if (status != SST_PLATFORM_RUNNING) | ||
200 | return; | ||
201 | snd_pcm_period_elapsed(substream); | ||
202 | } | ||
203 | |||
204 | static int sst_platform_init_stream(struct snd_pcm_substream *substream) | ||
205 | { | ||
206 | struct sst_runtime_stream *stream = | ||
207 | substream->runtime->private_data; | ||
208 | int ret_val; | ||
209 | |||
210 | pr_debug("setting buffer ptr param\n"); | ||
211 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | ||
212 | stream->stream_info.period_elapsed = sst_period_elapsed; | ||
213 | stream->stream_info.mad_substream = substream; | ||
214 | stream->stream_info.buffer_ptr = 0; | ||
215 | stream->stream_info.sfreq = substream->runtime->rate; | ||
216 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
217 | SST_SND_STREAM_INIT, &stream->stream_info); | ||
218 | if (ret_val) | ||
219 | pr_err("control_set ret error %d\n", ret_val); | ||
220 | return ret_val; | ||
221 | |||
222 | } | ||
223 | /* end -- helper functions */ | ||
224 | |||
225 | static int sst_platform_open(struct snd_pcm_substream *substream) | ||
226 | { | ||
227 | struct snd_pcm_runtime *runtime; | ||
228 | struct sst_runtime_stream *stream; | ||
229 | int ret_val = 0; | ||
230 | |||
231 | pr_debug("sst_platform_open called\n"); | ||
232 | runtime = substream->runtime; | ||
233 | runtime->hw = sst_platform_pcm_hw; | ||
234 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
235 | if (!stream) | ||
236 | return -ENOMEM; | ||
237 | spin_lock_init(&stream->status_lock); | ||
238 | stream->stream_info.str_id = 0; | ||
239 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | ||
240 | stream->stream_info.mad_substream = substream; | ||
241 | /* allocate memory for SST API set */ | ||
242 | stream->sstdrv_ops = kzalloc(sizeof(*stream->sstdrv_ops), | ||
243 | GFP_KERNEL); | ||
244 | if (!stream->sstdrv_ops) { | ||
245 | pr_err("sst: mem allocation for ops fail\n"); | ||
246 | kfree(stream); | ||
247 | return -ENOMEM; | ||
248 | } | ||
249 | stream->sstdrv_ops->vendor_id = MSIC_VENDOR_ID; | ||
250 | /* registering with SST driver to get access to SST APIs to use */ | ||
251 | ret_val = register_sst_card(stream->sstdrv_ops); | ||
252 | if (ret_val) { | ||
253 | pr_err("sst: sst card registration failed\n"); | ||
254 | return ret_val; | ||
255 | } | ||
256 | runtime->private_data = stream; | ||
257 | return snd_pcm_hw_constraint_integer(runtime, | ||
258 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
259 | } | ||
260 | |||
261 | static int sst_platform_close(struct snd_pcm_substream *substream) | ||
262 | { | ||
263 | struct sst_runtime_stream *stream; | ||
264 | int ret_val = 0, str_id; | ||
265 | |||
266 | pr_debug("sst_platform_close called\n"); | ||
267 | stream = substream->runtime->private_data; | ||
268 | str_id = stream->stream_info.str_id; | ||
269 | if (str_id) | ||
270 | ret_val = stream->sstdrv_ops->pcm_control->close(str_id); | ||
271 | kfree(stream->sstdrv_ops); | ||
272 | kfree(stream); | ||
273 | return ret_val; | ||
274 | } | ||
275 | |||
276 | static int sst_platform_pcm_prepare(struct snd_pcm_substream *substream) | ||
277 | { | ||
278 | struct sst_runtime_stream *stream; | ||
279 | int ret_val = 0, str_id; | ||
280 | |||
281 | pr_debug("sst_platform_pcm_prepare called\n"); | ||
282 | stream = substream->runtime->private_data; | ||
283 | str_id = stream->stream_info.str_id; | ||
284 | if (stream->stream_info.str_id) { | ||
285 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
286 | SST_SND_DROP, &str_id); | ||
287 | return ret_val; | ||
288 | } | ||
289 | |||
290 | ret_val = sst_platform_alloc_stream(substream); | ||
291 | if (ret_val < 0) | ||
292 | return ret_val; | ||
293 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | ||
294 | "%d", stream->stream_info.str_id); | ||
295 | |||
296 | ret_val = sst_platform_init_stream(substream); | ||
297 | if (ret_val) | ||
298 | return ret_val; | ||
299 | substream->runtime->hw.info = SNDRV_PCM_INFO_BLOCK_TRANSFER; | ||
300 | return ret_val; | ||
301 | } | ||
302 | |||
303 | static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | ||
304 | int cmd) | ||
305 | { | ||
306 | int ret_val = 0, str_id; | ||
307 | struct sst_runtime_stream *stream; | ||
308 | int str_cmd, status; | ||
309 | |||
310 | pr_debug("sst_platform_pcm_trigger called\n"); | ||
311 | stream = substream->runtime->private_data; | ||
312 | str_id = stream->stream_info.str_id; | ||
313 | switch (cmd) { | ||
314 | case SNDRV_PCM_TRIGGER_START: | ||
315 | pr_debug("sst: Trigger Start\n"); | ||
316 | str_cmd = SST_SND_START; | ||
317 | status = SST_PLATFORM_RUNNING; | ||
318 | stream->stream_info.mad_substream = substream; | ||
319 | break; | ||
320 | case SNDRV_PCM_TRIGGER_STOP: | ||
321 | pr_debug("sst: in stop\n"); | ||
322 | str_cmd = SST_SND_DROP; | ||
323 | status = SST_PLATFORM_DROPPED; | ||
324 | break; | ||
325 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
326 | pr_debug("sst: in pause\n"); | ||
327 | str_cmd = SST_SND_PAUSE; | ||
328 | status = SST_PLATFORM_PAUSED; | ||
329 | break; | ||
330 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
331 | pr_debug("sst: in pause release\n"); | ||
332 | str_cmd = SST_SND_RESUME; | ||
333 | status = SST_PLATFORM_RUNNING; | ||
334 | break; | ||
335 | default: | ||
336 | return -EINVAL; | ||
337 | } | ||
338 | ret_val = stream->sstdrv_ops->pcm_control->device_control(str_cmd, | ||
339 | &str_id); | ||
340 | if (!ret_val) | ||
341 | sst_set_stream_status(stream, status); | ||
342 | |||
343 | return ret_val; | ||
344 | } | ||
345 | |||
346 | |||
347 | static snd_pcm_uframes_t sst_platform_pcm_pointer | ||
348 | (struct snd_pcm_substream *substream) | ||
349 | { | ||
350 | struct sst_runtime_stream *stream; | ||
351 | int ret_val, status; | ||
352 | struct pcm_stream_info *str_info; | ||
353 | |||
354 | stream = substream->runtime->private_data; | ||
355 | status = sst_get_stream_status(stream); | ||
356 | if (status == SST_PLATFORM_INIT) | ||
357 | return 0; | ||
358 | str_info = &stream->stream_info; | ||
359 | ret_val = stream->sstdrv_ops->pcm_control->device_control( | ||
360 | SST_SND_BUFFER_POINTER, str_info); | ||
361 | if (ret_val) { | ||
362 | pr_err("sst: error code = %d\n", ret_val); | ||
363 | return ret_val; | ||
364 | } | ||
365 | return stream->stream_info.buffer_ptr; | ||
366 | } | ||
367 | |||
368 | static int sst_platform_pcm_hw_params(struct snd_pcm_substream *substream, | ||
369 | struct snd_pcm_hw_params *params) | ||
370 | { | ||
371 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
372 | memset(substream->runtime->dma_area, 0, params_buffer_bytes(params)); | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static struct snd_pcm_ops sst_platform_ops = { | ||
378 | .open = sst_platform_open, | ||
379 | .close = sst_platform_close, | ||
380 | .ioctl = snd_pcm_lib_ioctl, | ||
381 | .prepare = sst_platform_pcm_prepare, | ||
382 | .trigger = sst_platform_pcm_trigger, | ||
383 | .pointer = sst_platform_pcm_pointer, | ||
384 | .hw_params = sst_platform_pcm_hw_params, | ||
385 | }; | ||
386 | |||
387 | static void sst_pcm_free(struct snd_pcm *pcm) | ||
388 | { | ||
389 | pr_debug("sst_pcm_free called\n"); | ||
390 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
391 | } | ||
392 | |||
393 | int sst_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | ||
394 | struct snd_pcm *pcm) | ||
395 | { | ||
396 | int retval = 0; | ||
397 | |||
398 | pr_debug("sst_pcm_new called\n"); | ||
399 | if (dai->driver->playback.channels_min || | ||
400 | dai->driver->capture.channels_min) { | ||
401 | retval = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
402 | SNDRV_DMA_TYPE_CONTINUOUS, | ||
403 | snd_dma_continuous_data(GFP_KERNEL), | ||
404 | SST_MIN_BUFFER, SST_MAX_BUFFER); | ||
405 | if (retval) { | ||
406 | pr_err("dma buffer allocationf fail\n"); | ||
407 | return retval; | ||
408 | } | ||
409 | } | ||
410 | return retval; | ||
411 | } | ||
412 | struct snd_soc_platform_driver sst_soc_platform_drv = { | ||
413 | .ops = &sst_platform_ops, | ||
414 | .pcm_new = sst_pcm_new, | ||
415 | .pcm_free = sst_pcm_free, | ||
416 | }; | ||
417 | |||
418 | static int sst_platform_probe(struct platform_device *pdev) | ||
419 | { | ||
420 | int ret; | ||
421 | |||
422 | pr_debug("sst_platform_probe called\n"); | ||
423 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | ||
424 | if (ret) { | ||
425 | pr_err("registering soc platform failed\n"); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | ret = snd_soc_register_dais(&pdev->dev, | ||
430 | sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); | ||
431 | if (ret) { | ||
432 | pr_err("registering cpu dais failed\n"); | ||
433 | snd_soc_unregister_platform(&pdev->dev); | ||
434 | } | ||
435 | return ret; | ||
436 | } | ||
437 | |||
438 | static int sst_platform_remove(struct platform_device *pdev) | ||
439 | { | ||
440 | |||
441 | snd_soc_unregister_dais(&pdev->dev, ARRAY_SIZE(sst_platform_dai)); | ||
442 | snd_soc_unregister_platform(&pdev->dev); | ||
443 | pr_debug("sst_platform_remove sucess\n"); | ||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static struct platform_driver sst_platform_driver = { | ||
448 | .driver = { | ||
449 | .name = "sst-platform", | ||
450 | .owner = THIS_MODULE, | ||
451 | }, | ||
452 | .probe = sst_platform_probe, | ||
453 | .remove = sst_platform_remove, | ||
454 | }; | ||
455 | |||
456 | static int __init sst_soc_platform_init(void) | ||
457 | { | ||
458 | pr_debug("sst_soc_platform_init called\n"); | ||
459 | return platform_driver_register(&sst_platform_driver); | ||
460 | } | ||
461 | module_init(sst_soc_platform_init); | ||
462 | |||
463 | static void __exit sst_soc_platform_exit(void) | ||
464 | { | ||
465 | platform_driver_unregister(&sst_platform_driver); | ||
466 | pr_debug("sst_soc_platform_exit sucess\n"); | ||
467 | } | ||
468 | module_exit(sst_soc_platform_exit); | ||
469 | |||
470 | MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); | ||
471 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | ||
472 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | ||
473 | MODULE_LICENSE("GPL v2"); | ||
474 | MODULE_ALIAS("platform:sst-platform"); | ||
diff --git a/sound/soc/mid-x86/sst_platform.h b/sound/soc/mid-x86/sst_platform.h new file mode 100644 index 000000000000..df370286694f --- /dev/null +++ b/sound/soc/mid-x86/sst_platform.h | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * sst_platform.h - Intel MID Platform driver header file | ||
3 | * | ||
4 | * Copyright (C) 2010 Intel Corp | ||
5 | * Author: Vinod Koul <vinod.koul@intel.com> | ||
6 | * Author: Harsha Priya <priya.harsha@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License along | ||
19 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
20 | * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. | ||
21 | * | ||
22 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
23 | * | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef __SST_PLATFORMDRV_H__ | ||
28 | #define __SST_PLATFORMDRV_H__ | ||
29 | |||
30 | #define SST_MONO 1 | ||
31 | #define SST_STEREO 2 | ||
32 | #define SST_MAX_CAP 5 | ||
33 | |||
34 | #define SST_MIN_RATE 8000 | ||
35 | #define SST_MAX_RATE 48000 | ||
36 | #define SST_MIN_CHANNEL 1 | ||
37 | #define SST_MAX_CHANNEL 5 | ||
38 | #define SST_MAX_BUFFER (800*1024) | ||
39 | #define SST_MIN_BUFFER (800*1024) | ||
40 | #define SST_MIN_PERIOD_BYTES 32 | ||
41 | #define SST_MAX_PERIOD_BYTES SST_MAX_BUFFER | ||
42 | #define SST_MIN_PERIODS 2 | ||
43 | #define SST_MAX_PERIODS (1024*2) | ||
44 | #define SST_FIFO_SIZE 0 | ||
45 | #define SST_CARD_NAMES "intel_mid_card" | ||
46 | #define MSIC_VENDOR_ID 3 | ||
47 | |||
48 | struct sst_runtime_stream { | ||
49 | int stream_status; | ||
50 | struct pcm_stream_info stream_info; | ||
51 | struct intel_sst_card_ops *sstdrv_ops; | ||
52 | spinlock_t status_lock; | ||
53 | }; | ||
54 | |||
55 | enum sst_drv_status { | ||
56 | SST_PLATFORM_INIT = 1, | ||
57 | SST_PLATFORM_STARTED, | ||
58 | SST_PLATFORM_RUNNING, | ||
59 | SST_PLATFORM_PAUSED, | ||
60 | SST_PLATFORM_DROPPED, | ||
61 | }; | ||
62 | |||
63 | #endif | ||
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index a088db6d5091..b5922984eac6 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -24,6 +24,7 @@ config SND_OMAP_SOC_RX51 | |||
24 | select OMAP_MCBSP | 24 | select OMAP_MCBSP |
25 | select SND_OMAP_SOC_MCBSP | 25 | select SND_OMAP_SOC_MCBSP |
26 | select SND_SOC_TLV320AIC3X | 26 | select SND_SOC_TLV320AIC3X |
27 | select SND_SOC_TPA6130A2 | ||
27 | help | 28 | help |
28 | Say Y if you want to add support for SoC audio on Nokia RX-51 | 29 | Say Y if you want to add support for SoC audio on Nokia RX-51 |
29 | hardware. This is also known as Nokia N900 product. | 30 | hardware. This is also known as Nokia N900 product. |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 09fb0df8d416..d0986220eff9 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <sound/soc.h> | 32 | #include <sound/soc.h> |
33 | #include <plat/mcbsp.h> | 33 | #include <plat/mcbsp.h> |
34 | #include "../codecs/tpa6130a2.h" | ||
34 | 35 | ||
35 | #include <asm/mach-types.h> | 36 | #include <asm/mach-types.h> |
36 | 37 | ||
@@ -39,6 +40,7 @@ | |||
39 | 40 | ||
40 | #define RX51_TVOUT_SEL_GPIO 40 | 41 | #define RX51_TVOUT_SEL_GPIO 40 |
41 | #define RX51_JACK_DETECT_GPIO 177 | 42 | #define RX51_JACK_DETECT_GPIO 177 |
43 | #define RX51_ECI_SW_GPIO 182 | ||
42 | /* | 44 | /* |
43 | * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This | 45 | * REVISIT: TWL4030 GPIO base in RX-51. Now statically defined to 192. This |
44 | * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c | 46 | * gpio is reserved in arch/arm/mach-omap2/board-rx51-peripherals.c |
@@ -47,7 +49,9 @@ | |||
47 | 49 | ||
48 | enum { | 50 | enum { |
49 | RX51_JACK_DISABLED, | 51 | RX51_JACK_DISABLED, |
50 | RX51_JACK_TVOUT, /* tv-out */ | 52 | RX51_JACK_TVOUT, /* tv-out with stereo output */ |
53 | RX51_JACK_HP, /* headphone: stereo output, no mic */ | ||
54 | RX51_JACK_HS, /* headset: stereo output with mic */ | ||
51 | }; | 55 | }; |
52 | 56 | ||
53 | static int rx51_spk_func; | 57 | static int rx51_spk_func; |
@@ -57,6 +61,19 @@ static int rx51_jack_func; | |||
57 | static void rx51_ext_control(struct snd_soc_codec *codec) | 61 | static void rx51_ext_control(struct snd_soc_codec *codec) |
58 | { | 62 | { |
59 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 63 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
64 | int hp = 0, hs = 0, tvout = 0; | ||
65 | |||
66 | switch (rx51_jack_func) { | ||
67 | case RX51_JACK_TVOUT: | ||
68 | tvout = 1; | ||
69 | hp = 1; | ||
70 | break; | ||
71 | case RX51_JACK_HS: | ||
72 | hs = 1; | ||
73 | case RX51_JACK_HP: | ||
74 | hp = 1; | ||
75 | break; | ||
76 | } | ||
60 | 77 | ||
61 | if (rx51_spk_func) | 78 | if (rx51_spk_func) |
62 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 79 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); |
@@ -66,9 +83,16 @@ static void rx51_ext_control(struct snd_soc_codec *codec) | |||
66 | snd_soc_dapm_enable_pin(dapm, "DMic"); | 83 | snd_soc_dapm_enable_pin(dapm, "DMic"); |
67 | else | 84 | else |
68 | snd_soc_dapm_disable_pin(dapm, "DMic"); | 85 | snd_soc_dapm_disable_pin(dapm, "DMic"); |
86 | if (hp) | ||
87 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | ||
88 | else | ||
89 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | ||
90 | if (hs) | ||
91 | snd_soc_dapm_enable_pin(dapm, "HS Mic"); | ||
92 | else | ||
93 | snd_soc_dapm_disable_pin(dapm, "HS Mic"); | ||
69 | 94 | ||
70 | gpio_set_value(RX51_TVOUT_SEL_GPIO, | 95 | gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); |
71 | rx51_jack_func == RX51_JACK_TVOUT); | ||
72 | 96 | ||
73 | snd_soc_dapm_sync(dapm); | 97 | snd_soc_dapm_sync(dapm); |
74 | } | 98 | } |
@@ -153,6 +177,19 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, | |||
153 | return 0; | 177 | return 0; |
154 | } | 178 | } |
155 | 179 | ||
180 | static int rx51_hp_event(struct snd_soc_dapm_widget *w, | ||
181 | struct snd_kcontrol *k, int event) | ||
182 | { | ||
183 | struct snd_soc_codec *codec = w->dapm->codec; | ||
184 | |||
185 | if (SND_SOC_DAPM_EVENT_ON(event)) | ||
186 | tpa6130a2_stereo_enable(codec, 1); | ||
187 | else | ||
188 | tpa6130a2_stereo_enable(codec, 0); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
156 | static int rx51_get_input(struct snd_kcontrol *kcontrol, | 193 | static int rx51_get_input(struct snd_kcontrol *kcontrol, |
157 | struct snd_ctl_elem_value *ucontrol) | 194 | struct snd_ctl_elem_value *ucontrol) |
158 | { | 195 | { |
@@ -203,7 +240,7 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { | |||
203 | { | 240 | { |
204 | .gpio = RX51_JACK_DETECT_GPIO, | 241 | .gpio = RX51_JACK_DETECT_GPIO, |
205 | .name = "avdet-gpio", | 242 | .name = "avdet-gpio", |
206 | .report = SND_JACK_VIDEOOUT, | 243 | .report = SND_JACK_HEADSET, |
207 | .invert = 1, | 244 | .invert = 1, |
208 | .debounce_time = 200, | 245 | .debounce_time = 200, |
209 | }, | 246 | }, |
@@ -212,19 +249,38 @@ static struct snd_soc_jack_gpio rx51_av_jack_gpios[] = { | |||
212 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { | 249 | static const struct snd_soc_dapm_widget aic34_dapm_widgets[] = { |
213 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), | 250 | SND_SOC_DAPM_SPK("Ext Spk", rx51_spk_event), |
214 | SND_SOC_DAPM_MIC("DMic", NULL), | 251 | SND_SOC_DAPM_MIC("DMic", NULL), |
252 | SND_SOC_DAPM_HP("Headphone Jack", rx51_hp_event), | ||
253 | SND_SOC_DAPM_MIC("HS Mic", NULL), | ||
254 | SND_SOC_DAPM_LINE("FM Transmitter", NULL), | ||
255 | }; | ||
256 | |||
257 | static const struct snd_soc_dapm_widget aic34_dapm_widgetsb[] = { | ||
258 | SND_SOC_DAPM_SPK("Earphone", NULL), | ||
215 | }; | 259 | }; |
216 | 260 | ||
217 | static const struct snd_soc_dapm_route audio_map[] = { | 261 | static const struct snd_soc_dapm_route audio_map[] = { |
218 | {"Ext Spk", NULL, "HPLOUT"}, | 262 | {"Ext Spk", NULL, "HPLOUT"}, |
219 | {"Ext Spk", NULL, "HPROUT"}, | 263 | {"Ext Spk", NULL, "HPROUT"}, |
264 | {"Headphone Jack", NULL, "LLOUT"}, | ||
265 | {"Headphone Jack", NULL, "RLOUT"}, | ||
266 | {"FM Transmitter", NULL, "LLOUT"}, | ||
267 | {"FM Transmitter", NULL, "RLOUT"}, | ||
220 | 268 | ||
221 | {"DMic Rate 64", NULL, "Mic Bias 2V"}, | 269 | {"DMic Rate 64", NULL, "Mic Bias 2V"}, |
222 | {"Mic Bias 2V", NULL, "DMic"}, | 270 | {"Mic Bias 2V", NULL, "DMic"}, |
223 | }; | 271 | }; |
224 | 272 | ||
273 | static const struct snd_soc_dapm_route audio_mapb[] = { | ||
274 | {"b LINE2R", NULL, "MONO_LOUT"}, | ||
275 | {"Earphone", NULL, "b HPLOUT"}, | ||
276 | |||
277 | {"LINE1L", NULL, "b Mic Bias 2.5V"}, | ||
278 | {"b Mic Bias 2.5V", NULL, "HS Mic"} | ||
279 | }; | ||
280 | |||
225 | static const char *spk_function[] = {"Off", "On"}; | 281 | static const char *spk_function[] = {"Off", "On"}; |
226 | static const char *input_function[] = {"ADC", "Digital Mic"}; | 282 | static const char *input_function[] = {"ADC", "Digital Mic"}; |
227 | static const char *jack_function[] = {"Off", "TV-OUT"}; | 283 | static const char *jack_function[] = {"Off", "TV-OUT", "Headphone", "Headset"}; |
228 | 284 | ||
229 | static const struct soc_enum rx51_enum[] = { | 285 | static const struct soc_enum rx51_enum[] = { |
230 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), | 286 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(spk_function), spk_function), |
@@ -239,6 +295,11 @@ static const struct snd_kcontrol_new aic34_rx51_controls[] = { | |||
239 | rx51_get_input, rx51_set_input), | 295 | rx51_get_input, rx51_set_input), |
240 | SOC_ENUM_EXT("Jack Function", rx51_enum[2], | 296 | SOC_ENUM_EXT("Jack Function", rx51_enum[2], |
241 | rx51_get_jack, rx51_set_jack), | 297 | rx51_get_jack, rx51_set_jack), |
298 | SOC_DAPM_PIN_SWITCH("FM Transmitter"), | ||
299 | }; | ||
300 | |||
301 | static const struct snd_kcontrol_new aic34_rx51_controlsb[] = { | ||
302 | SOC_DAPM_PIN_SWITCH("Earphone"), | ||
242 | }; | 303 | }; |
243 | 304 | ||
244 | static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | 305 | static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) |
@@ -265,11 +326,21 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | |||
265 | /* Set up RX-51 specific audio path audio_map */ | 326 | /* Set up RX-51 specific audio path audio_map */ |
266 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | 327 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
267 | 328 | ||
329 | err = tpa6130a2_add_controls(codec); | ||
330 | if (err < 0) | ||
331 | return err; | ||
332 | snd_soc_limit_volume(codec, "TPA6130A2 Headphone Playback Volume", 42); | ||
333 | |||
334 | err = omap_mcbsp_st_add_controls(codec, 1); | ||
335 | if (err < 0) | ||
336 | return err; | ||
337 | |||
268 | snd_soc_dapm_sync(dapm); | 338 | snd_soc_dapm_sync(dapm); |
269 | 339 | ||
270 | /* AV jack detection */ | 340 | /* AV jack detection */ |
271 | err = snd_soc_jack_new(codec, "AV Jack", | 341 | err = snd_soc_jack_new(codec, "AV Jack", |
272 | SND_JACK_VIDEOOUT, &rx51_av_jack); | 342 | SND_JACK_HEADSET | SND_JACK_VIDEOOUT, |
343 | &rx51_av_jack); | ||
273 | if (err) | 344 | if (err) |
274 | return err; | 345 | return err; |
275 | err = snd_soc_jack_add_gpios(&rx51_av_jack, | 346 | err = snd_soc_jack_add_gpios(&rx51_av_jack, |
@@ -279,6 +350,24 @@ static int rx51_aic34_init(struct snd_soc_pcm_runtime *rtd) | |||
279 | return err; | 350 | return err; |
280 | } | 351 | } |
281 | 352 | ||
353 | static int rx51_aic34b_init(struct snd_soc_dapm_context *dapm) | ||
354 | { | ||
355 | int err; | ||
356 | |||
357 | err = snd_soc_add_controls(dapm->codec, aic34_rx51_controlsb, | ||
358 | ARRAY_SIZE(aic34_rx51_controlsb)); | ||
359 | if (err < 0) | ||
360 | return err; | ||
361 | |||
362 | err = snd_soc_dapm_new_controls(dapm, aic34_dapm_widgetsb, | ||
363 | ARRAY_SIZE(aic34_dapm_widgetsb)); | ||
364 | if (err < 0) | ||
365 | return 0; | ||
366 | |||
367 | return snd_soc_dapm_add_routes(dapm, audio_mapb, | ||
368 | ARRAY_SIZE(audio_mapb)); | ||
369 | } | ||
370 | |||
282 | /* Digital audio interface glue - connects codec <--> CPU */ | 371 | /* Digital audio interface glue - connects codec <--> CPU */ |
283 | static struct snd_soc_dai_link rx51_dai[] = { | 372 | static struct snd_soc_dai_link rx51_dai[] = { |
284 | { | 373 | { |
@@ -293,11 +382,30 @@ static struct snd_soc_dai_link rx51_dai[] = { | |||
293 | }, | 382 | }, |
294 | }; | 383 | }; |
295 | 384 | ||
385 | struct snd_soc_aux_dev rx51_aux_dev[] = { | ||
386 | { | ||
387 | .name = "TLV320AIC34b", | ||
388 | .codec_name = "tlv320aic3x-codec.2-0019", | ||
389 | .init = rx51_aic34b_init, | ||
390 | }, | ||
391 | }; | ||
392 | |||
393 | static struct snd_soc_codec_conf rx51_codec_conf[] = { | ||
394 | { | ||
395 | .dev_name = "tlv320aic3x-codec.2-0019", | ||
396 | .name_prefix = "b", | ||
397 | }, | ||
398 | }; | ||
399 | |||
296 | /* Audio card */ | 400 | /* Audio card */ |
297 | static struct snd_soc_card rx51_sound_card = { | 401 | static struct snd_soc_card rx51_sound_card = { |
298 | .name = "RX-51", | 402 | .name = "RX-51", |
299 | .dai_link = rx51_dai, | 403 | .dai_link = rx51_dai, |
300 | .num_links = ARRAY_SIZE(rx51_dai), | 404 | .num_links = ARRAY_SIZE(rx51_dai), |
405 | .aux_dev = rx51_aux_dev, | ||
406 | .num_aux_devs = ARRAY_SIZE(rx51_aux_dev), | ||
407 | .codec_conf = rx51_codec_conf, | ||
408 | .num_configs = ARRAY_SIZE(rx51_codec_conf), | ||
301 | }; | 409 | }; |
302 | 410 | ||
303 | static struct platform_device *rx51_snd_device; | 411 | static struct platform_device *rx51_snd_device; |
@@ -309,10 +417,14 @@ static int __init rx51_soc_init(void) | |||
309 | if (!machine_is_nokia_rx51()) | 417 | if (!machine_is_nokia_rx51()) |
310 | return -ENODEV; | 418 | return -ENODEV; |
311 | 419 | ||
312 | err = gpio_request(RX51_TVOUT_SEL_GPIO, "tvout_sel"); | 420 | err = gpio_request_one(RX51_TVOUT_SEL_GPIO, |
421 | GPIOF_DIR_OUT | GPIOF_INIT_LOW, "tvout_sel"); | ||
313 | if (err) | 422 | if (err) |
314 | goto err_gpio_tvout_sel; | 423 | goto err_gpio_tvout_sel; |
315 | gpio_direction_output(RX51_TVOUT_SEL_GPIO, 0); | 424 | err = gpio_request_one(RX51_ECI_SW_GPIO, |
425 | GPIOF_DIR_OUT | GPIOF_INIT_HIGH, "eci_sw"); | ||
426 | if (err) | ||
427 | goto err_gpio_eci_sw; | ||
316 | 428 | ||
317 | rx51_snd_device = platform_device_alloc("soc-audio", -1); | 429 | rx51_snd_device = platform_device_alloc("soc-audio", -1); |
318 | if (!rx51_snd_device) { | 430 | if (!rx51_snd_device) { |
@@ -330,6 +442,8 @@ static int __init rx51_soc_init(void) | |||
330 | err2: | 442 | err2: |
331 | platform_device_put(rx51_snd_device); | 443 | platform_device_put(rx51_snd_device); |
332 | err1: | 444 | err1: |
445 | gpio_free(RX51_ECI_SW_GPIO); | ||
446 | err_gpio_eci_sw: | ||
333 | gpio_free(RX51_TVOUT_SEL_GPIO); | 447 | gpio_free(RX51_TVOUT_SEL_GPIO); |
334 | err_gpio_tvout_sel: | 448 | err_gpio_tvout_sel: |
335 | 449 | ||
@@ -342,6 +456,7 @@ static void __exit rx51_soc_exit(void) | |||
342 | rx51_av_jack_gpios); | 456 | rx51_av_jack_gpios); |
343 | 457 | ||
344 | platform_device_unregister(rx51_snd_device); | 458 | platform_device_unregister(rx51_snd_device); |
459 | gpio_free(RX51_ECI_SW_GPIO); | ||
345 | gpio_free(RX51_TVOUT_SEL_GPIO); | 460 | gpio_free(RX51_TVOUT_SEL_GPIO); |
346 | } | 461 | } |
347 | 462 | ||
diff --git a/sound/soc/pxa/raumfeld.c b/sound/soc/pxa/raumfeld.c index 0fd60f423036..2afabaf59491 100644 --- a/sound/soc/pxa/raumfeld.c +++ b/sound/soc/pxa/raumfeld.c | |||
@@ -151,13 +151,13 @@ static struct snd_soc_ops raumfeld_cs4270_ops = { | |||
151 | .hw_params = raumfeld_cs4270_hw_params, | 151 | .hw_params = raumfeld_cs4270_hw_params, |
152 | }; | 152 | }; |
153 | 153 | ||
154 | static int raumfeld_line_suspend(struct platform_device *pdev, pm_message_t state) | 154 | static int raumfeld_line_suspend(struct snd_soc_card *card) |
155 | { | 155 | { |
156 | raumfeld_enable_audio(false); | 156 | raumfeld_enable_audio(false); |
157 | return 0; | 157 | return 0; |
158 | } | 158 | } |
159 | 159 | ||
160 | static int raumfeld_line_resume(struct platform_device *pdev) | 160 | static int raumfeld_line_resume(struct snd_soc_card *card) |
161 | { | 161 | { |
162 | raumfeld_enable_audio(true); | 162 | raumfeld_enable_audio(true); |
163 | return 0; | 163 | return 0; |
@@ -229,19 +229,19 @@ static struct snd_soc_dai_link raumfeld_dai[] = { | |||
229 | { | 229 | { |
230 | .name = "ak4104", | 230 | .name = "ak4104", |
231 | .stream_name = "Playback", | 231 | .stream_name = "Playback", |
232 | .cpu_dai_name = "pxa-ssp-dai.1", | 232 | .cpu_dai_name = "pxa-ssp-dai.1", |
233 | .codec_dai_name = "ak4104-hifi", | 233 | .codec_dai_name = "ak4104-hifi", |
234 | .platform_name = "pxa-pcm-audio", | 234 | .platform_name = "pxa-pcm-audio", |
235 | .ops = &raumfeld_ak4104_ops, | 235 | .ops = &raumfeld_ak4104_ops, |
236 | .codec_name = "ak4104-codec.0", | 236 | .codec_name = "ak4104-codec.0", |
237 | }, | 237 | }, |
238 | { | 238 | { |
239 | .name = "CS4270", | 239 | .name = "CS4270", |
240 | .stream_name = "CS4270", | 240 | .stream_name = "CS4270", |
241 | .cpu_dai_name = "pxa-ssp-dai.0", | 241 | .cpu_dai_name = "pxa-ssp-dai.0", |
242 | .platform_name = "pxa-pcm-audio", | 242 | .platform_name = "pxa-pcm-audio", |
243 | .codec_dai_name = "cs4270-hifi", | 243 | .codec_dai_name = "cs4270-hifi", |
244 | .codec_name = "cs4270-codec.0-0048", | 244 | .codec_name = "cs4270-codec.0-0048", |
245 | .ops = &raumfeld_cs4270_ops, | 245 | .ops = &raumfeld_cs4270_ops, |
246 | },}; | 246 | },}; |
247 | 247 | ||
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index 4b6e5d608b42..9a2351366957 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -237,7 +237,7 @@ static struct snd_soc_dai_link tosa_dai[] = { | |||
237 | }, | 237 | }, |
238 | }; | 238 | }; |
239 | 239 | ||
240 | static int tosa_probe(struct platform_device *dev) | 240 | static int tosa_probe(struct snd_soc_card *card) |
241 | { | 241 | { |
242 | int ret; | 242 | int ret; |
243 | 243 | ||
@@ -251,7 +251,7 @@ static int tosa_probe(struct platform_device *dev) | |||
251 | return ret; | 251 | return ret; |
252 | } | 252 | } |
253 | 253 | ||
254 | static int tosa_remove(struct platform_device *dev) | 254 | static int tosa_remove(struct snd_soc_card *card) |
255 | { | 255 | { |
256 | gpio_free(TOSA_GPIO_L_MUTE); | 256 | gpio_free(TOSA_GPIO_L_MUTE); |
257 | return 0; | 257 | return 0; |
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c index 3ceaef68e01d..d69d9fc32233 100644 --- a/sound/soc/pxa/z2.c +++ b/sound/soc/pxa/z2.c | |||
@@ -95,6 +95,11 @@ static struct snd_soc_jack_pin hs_jack_pins[] = { | |||
95 | .pin = "Headphone Jack", | 95 | .pin = "Headphone Jack", |
96 | .mask = SND_JACK_HEADPHONE, | 96 | .mask = SND_JACK_HEADPHONE, |
97 | }, | 97 | }, |
98 | { | ||
99 | .pin = "Ext Spk", | ||
100 | .mask = SND_JACK_HEADPHONE, | ||
101 | .invert = 1 | ||
102 | }, | ||
98 | }; | 103 | }; |
99 | 104 | ||
100 | /* Headset jack detection gpios */ | 105 | /* Headset jack detection gpios */ |
@@ -147,7 +152,7 @@ static int z2_wm8750_init(struct snd_soc_pcm_runtime *rtd) | |||
147 | snd_soc_dapm_disable_pin(dapm, "LINPUT3"); | 152 | snd_soc_dapm_disable_pin(dapm, "LINPUT3"); |
148 | snd_soc_dapm_disable_pin(dapm, "RINPUT3"); | 153 | snd_soc_dapm_disable_pin(dapm, "RINPUT3"); |
149 | snd_soc_dapm_disable_pin(dapm, "OUT3"); | 154 | snd_soc_dapm_disable_pin(dapm, "OUT3"); |
150 | snd_soc_dapm_disable_pin(dapm, "MONO"); | 155 | snd_soc_dapm_disable_pin(dapm, "MONO1"); |
151 | 156 | ||
152 | /* Add z2 specific widgets */ | 157 | /* Add z2 specific widgets */ |
153 | snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, | 158 | snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets, |
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 25bba108fea3..ac577263b3e3 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
@@ -189,7 +189,7 @@ static struct snd_soc_dai_link zylonite_dai[] = { | |||
189 | }, | 189 | }, |
190 | }; | 190 | }; |
191 | 191 | ||
192 | static int zylonite_probe(struct platform_device *pdev) | 192 | static int zylonite_probe(struct snd_soc_card *card) |
193 | { | 193 | { |
194 | int ret; | 194 | int ret; |
195 | 195 | ||
@@ -216,7 +216,7 @@ static int zylonite_probe(struct platform_device *pdev) | |||
216 | return 0; | 216 | return 0; |
217 | } | 217 | } |
218 | 218 | ||
219 | static int zylonite_remove(struct platform_device *pdev) | 219 | static int zylonite_remove(struct snd_soc_card *card) |
220 | { | 220 | { |
221 | if (clk_pout) { | 221 | if (clk_pout) { |
222 | clk_disable(pout); | 222 | clk_disable(pout); |
@@ -226,8 +226,7 @@ static int zylonite_remove(struct platform_device *pdev) | |||
226 | return 0; | 226 | return 0; |
227 | } | 227 | } |
228 | 228 | ||
229 | static int zylonite_suspend_post(struct platform_device *pdev, | 229 | static int zylonite_suspend_post(struct snd_soc_card *card) |
230 | pm_message_t state) | ||
231 | { | 230 | { |
232 | if (clk_pout) | 231 | if (clk_pout) |
233 | clk_disable(pout); | 232 | clk_disable(pout); |
@@ -235,7 +234,7 @@ static int zylonite_suspend_post(struct platform_device *pdev, | |||
235 | return 0; | 234 | return 0; |
236 | } | 235 | } |
237 | 236 | ||
238 | static int zylonite_resume_pre(struct platform_device *pdev) | 237 | static int zylonite_resume_pre(struct snd_soc_card *card) |
239 | { | 238 | { |
240 | int ret = 0; | 239 | int ret = 0; |
241 | 240 | ||
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index d6713d5a90e7..a3fdfb631469 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -35,23 +35,16 @@ config SND_SAMSUNG_I2S | |||
35 | tristate | 35 | tristate |
36 | 36 | ||
37 | config SND_SOC_SAMSUNG_NEO1973_WM8753 | 37 | config SND_SOC_SAMSUNG_NEO1973_WM8753 |
38 | tristate "SoC I2S Audio support for NEO1973 - WM8753" | 38 | tristate "Audio support for Openmoko Neo1973 Smartphones (GTA01/GTA02)" |
39 | depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA01 | 39 | depends on SND_SOC_SAMSUNG && (MACH_NEO1973_GTA01 || MACH_NEO1973_GTA02) |
40 | select SND_S3C24XX_I2S | 40 | select SND_S3C24XX_I2S |
41 | select SND_SOC_WM8753 | 41 | select SND_SOC_WM8753 |
42 | select SND_SOC_LM4857 if MACH_NEO1973_GTA01 | ||
43 | select SND_SOC_DFBMCS320 | ||
42 | help | 44 | help |
43 | Say Y if you want to add support for SoC audio on smdk2440 | 45 | Say Y here to enable audio support for the Openmoko Neo1973 |
44 | with the WM8753. | 46 | Smartphones. |
45 | 47 | ||
46 | config SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753 | ||
47 | tristate "Audio support for the Openmoko Neo FreeRunner (GTA02)" | ||
48 | depends on SND_SOC_SAMSUNG && MACH_NEO1973_GTA02 | ||
49 | select SND_S3C24XX_I2S | ||
50 | select SND_SOC_WM8753 | ||
51 | help | ||
52 | This driver provides audio support for the Openmoko Neo FreeRunner | ||
53 | smartphone. | ||
54 | |||
55 | config SND_SOC_SAMSUNG_JIVE_WM8750 | 48 | config SND_SOC_SAMSUNG_JIVE_WM8750 |
56 | tristate "SoC I2S Audio support for Jive" | 49 | tristate "SoC I2S Audio support for Jive" |
57 | depends on SND_SOC_SAMSUNG && MACH_JIVE | 50 | depends on SND_SOC_SAMSUNG && MACH_JIVE |
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile index 705d4e8a6724..294dec05c26d 100644 --- a/sound/soc/samsung/Makefile +++ b/sound/soc/samsung/Makefile | |||
@@ -20,7 +20,6 @@ obj-$(CONFIG_SND_SAMSUNG_I2S) += snd-soc-i2s.o | |||
20 | # S3C24XX Machine Support | 20 | # S3C24XX Machine Support |
21 | snd-soc-jive-wm8750-objs := jive_wm8750.o | 21 | snd-soc-jive-wm8750-objs := jive_wm8750.o |
22 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o | 22 | snd-soc-neo1973-wm8753-objs := neo1973_wm8753.o |
23 | snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o | ||
24 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 23 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
25 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | 24 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o |
26 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | 25 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o |
@@ -38,7 +37,6 @@ snd-soc-smdk-spdif-objs := smdk_spdif.o | |||
38 | 37 | ||
39 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o | 38 | obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o |
40 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 39 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
41 | obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm8753.o | ||
42 | obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 40 | obj-$(CONFIG_SND_SOC_SAMSUNG_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
43 | obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | 41 | obj-$(CONFIG_SND_SOC_SAMSUNG_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o |
44 | obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o | 42 | obj-$(CONFIG_SND_SOC_SAMSUNG_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o |
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c index 4770a9550341..f97110e72e85 100644 --- a/sound/soc/samsung/ac97.c +++ b/sound/soc/samsung/ac97.c | |||
@@ -12,24 +12,24 @@ | |||
12 | * published by the Free Software Foundation. | 12 | * published by the Free Software Foundation. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/io.h> | 15 | #include <linux/io.h> |
18 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
19 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
20 | 18 | ||
21 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
22 | 20 | ||
23 | #include <plat/regs-ac97.h> | ||
24 | #include <mach/dma.h> | 21 | #include <mach/dma.h> |
22 | #include <plat/regs-ac97.h> | ||
25 | #include <plat/audio.h> | 23 | #include <plat/audio.h> |
26 | 24 | ||
27 | #include "dma.h" | 25 | #include "dma.h" |
28 | #include "ac97.h" | ||
29 | 26 | ||
30 | #define AC_CMD_ADDR(x) (x << 16) | 27 | #define AC_CMD_ADDR(x) (x << 16) |
31 | #define AC_CMD_DATA(x) (x & 0xffff) | 28 | #define AC_CMD_DATA(x) (x & 0xffff) |
32 | 29 | ||
30 | #define S3C_AC97_DAI_PCM 0 | ||
31 | #define S3C_AC97_DAI_MIC 1 | ||
32 | |||
33 | struct s3c_ac97_info { | 33 | struct s3c_ac97_info { |
34 | struct clk *ac97_clk; | 34 | struct clk *ac97_clk; |
35 | void __iomem *regs; | 35 | void __iomem *regs; |
diff --git a/sound/soc/samsung/ac97.h b/sound/soc/samsung/ac97.h deleted file mode 100644 index 0d0e1b511457..000000000000 --- a/sound/soc/samsung/ac97.h +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | /* sound/soc/samsung/ac97.h | ||
2 | * | ||
3 | * ALSA SoC Audio Layer - S3C AC97 Controller driver | ||
4 | * Evolved from s3c2443-ac97.h | ||
5 | * | ||
6 | * Copyright (c) 2010 Samsung Electronics Co. Ltd | ||
7 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | ||
8 | * Credits: Graeme Gregory, Sean Choi | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #ifndef __S3C_AC97_H_ | ||
16 | #define __S3C_AC97_H_ | ||
17 | |||
18 | #define S3C_AC97_DAI_PCM 0 | ||
19 | #define S3C_AC97_DAI_MIC 1 | ||
20 | |||
21 | #endif /* __S3C_AC97_H_ */ | ||
diff --git a/sound/soc/samsung/dma.c b/sound/soc/samsung/dma.c index 21240198c5d6..5cb3b880f0d5 100644 --- a/sound/soc/samsung/dma.c +++ b/sound/soc/samsung/dma.c | |||
@@ -14,17 +14,11 @@ | |||
14 | * option) any later version. | 14 | * option) any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/io.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
22 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
23 | 19 | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
21 | #include <sound/pcm_params.h> | ||
28 | 22 | ||
29 | #include <asm/dma.h> | 23 | #include <asm/dma.h> |
30 | #include <mach/hardware.h> | 24 | #include <mach/hardware.h> |
@@ -32,6 +26,9 @@ | |||
32 | 26 | ||
33 | #include "dma.h" | 27 | #include "dma.h" |
34 | 28 | ||
29 | #define ST_RUNNING (1<<0) | ||
30 | #define ST_OPENED (1<<1) | ||
31 | |||
35 | static const struct snd_pcm_hardware dma_hardware = { | 32 | static const struct snd_pcm_hardware dma_hardware = { |
36 | .info = SNDRV_PCM_INFO_INTERLEAVED | | 33 | .info = SNDRV_PCM_INFO_INTERLEAVED | |
37 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 34 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -313,7 +310,7 @@ dma_pointer(struct snd_pcm_substream *substream) | |||
313 | /* we seem to be getting the odd error from the pcm library due | 310 | /* we seem to be getting the odd error from the pcm library due |
314 | * to out-of-bounds pointers. this is maybe due to the dma engine | 311 | * to out-of-bounds pointers. this is maybe due to the dma engine |
315 | * not having loaded the new values for the channel before being | 312 | * not having loaded the new values for the channel before being |
316 | * callled... (todo - fix ) | 313 | * called... (todo - fix ) |
317 | */ | 314 | */ |
318 | 315 | ||
319 | if (res >= snd_pcm_lib_buffer_bytes(substream)) { | 316 | if (res >= snd_pcm_lib_buffer_bytes(substream)) { |
diff --git a/sound/soc/samsung/dma.h b/sound/soc/samsung/dma.h index f8cd2b4223af..c50659269a40 100644 --- a/sound/soc/samsung/dma.h +++ b/sound/soc/samsung/dma.h | |||
@@ -12,9 +12,6 @@ | |||
12 | #ifndef _S3C_AUDIO_H | 12 | #ifndef _S3C_AUDIO_H |
13 | #define _S3C_AUDIO_H | 13 | #define _S3C_AUDIO_H |
14 | 14 | ||
15 | #define ST_RUNNING (1<<0) | ||
16 | #define ST_OPENED (1<<1) | ||
17 | |||
18 | struct s3c_dma_params { | 15 | struct s3c_dma_params { |
19 | struct s3c2410_dma_client *client; /* stream identifier */ | 16 | struct s3c2410_dma_client *client; /* stream identifier */ |
20 | int channel; /* Channel ID */ | 17 | int channel; /* Channel ID */ |
@@ -22,9 +19,4 @@ struct s3c_dma_params { | |||
22 | int dma_size; /* Size of the DMA transfer */ | 19 | int dma_size; /* Size of the DMA transfer */ |
23 | }; | 20 | }; |
24 | 21 | ||
25 | #define S3C24XX_DAI_I2S 0 | ||
26 | |||
27 | /* platform data */ | ||
28 | extern struct snd_ac97_bus_ops s3c24xx_ac97_ops; | ||
29 | |||
30 | #endif | 22 | #endif |
diff --git a/sound/soc/samsung/goni_wm8994.c b/sound/soc/samsung/goni_wm8994.c index 34dd9ef1b9c0..f6b3a3ce5919 100644 --- a/sound/soc/samsung/goni_wm8994.c +++ b/sound/soc/samsung/goni_wm8994.c | |||
@@ -11,21 +11,13 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
19 | #include <sound/jack.h> | 15 | #include <sound/jack.h> |
16 | |||
20 | #include <asm/mach-types.h> | 17 | #include <asm/mach-types.h> |
21 | #include <mach/gpio.h> | 18 | #include <mach/gpio.h> |
22 | #include <mach/regs-clock.h> | ||
23 | 19 | ||
24 | #include <linux/mfd/wm8994/core.h> | ||
25 | #include <linux/mfd/wm8994/registers.h> | ||
26 | #include "../codecs/wm8994.h" | 20 | #include "../codecs/wm8994.h" |
27 | #include "dma.h" | ||
28 | #include "i2s.h" | ||
29 | 21 | ||
30 | #define MACHINE_NAME 0 | 22 | #define MACHINE_NAME 0 |
31 | #define CPU_VOICE_DAI 1 | 23 | #define CPU_VOICE_DAI 1 |
diff --git a/sound/soc/samsung/h1940_uda1380.c b/sound/soc/samsung/h1940_uda1380.c index c45f7ce14d61..241f55d00660 100644 --- a/sound/soc/samsung/h1940_uda1380.c +++ b/sound/soc/samsung/h1940_uda1380.c | |||
@@ -13,25 +13,16 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
21 | 17 | ||
22 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
23 | #include <sound/uda1380.h> | ||
24 | #include <sound/jack.h> | 19 | #include <sound/jack.h> |
25 | 20 | ||
26 | #include <plat/regs-iis.h> | 21 | #include <plat/regs-iis.h> |
27 | |||
28 | #include <mach/h1940-latch.h> | 22 | #include <mach/h1940-latch.h> |
29 | |||
30 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
31 | 24 | ||
32 | #include "dma.h" | ||
33 | #include "s3c24xx-i2s.h" | 25 | #include "s3c24xx-i2s.h" |
34 | #include "../codecs/uda1380.h" | ||
35 | 26 | ||
36 | static unsigned int rates[] = { | 27 | static unsigned int rates[] = { |
37 | 11025, | 28 | 11025, |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d00ac3a7102c..ffa09b3b2caa 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -15,9 +15,8 @@ | |||
15 | #include <linux/clk.h> | 15 | #include <linux/clk.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | 17 | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | #include <sound/pcm_params.h> | ||
21 | 20 | ||
22 | #include <plat/audio.h> | 21 | #include <plat/audio.h> |
23 | 22 | ||
diff --git a/sound/soc/samsung/jive_wm8750.c b/sound/soc/samsung/jive_wm8750.c index 08802520e014..3b53ad54bc33 100644 --- a/sound/soc/samsung/jive_wm8750.c +++ b/sound/soc/samsung/jive_wm8750.c | |||
@@ -11,22 +11,11 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/timer.h> | ||
17 | #include <linux/interrupt.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/clk.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
24 | 15 | ||
25 | #include <asm/mach-types.h> | 16 | #include <asm/mach-types.h> |
26 | 17 | ||
27 | #include "dma.h" | ||
28 | #include "s3c2412-i2s.h" | 18 | #include "s3c2412-i2s.h" |
29 | |||
30 | #include "../codecs/wm8750.h" | 19 | #include "../codecs/wm8750.h" |
31 | 20 | ||
32 | static const struct snd_soc_dapm_route audio_map[] = { | 21 | static const struct snd_soc_dapm_route audio_map[] = { |
diff --git a/sound/soc/samsung/lm4857.h b/sound/soc/samsung/lm4857.h deleted file mode 100644 index 0cf5b7011d6f..000000000000 --- a/sound/soc/samsung/lm4857.h +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | /* | ||
2 | * lm4857.h -- ALSA Soc Audio Layer | ||
3 | * | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
5 | * Author: Graeme Gregory | ||
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | * | ||
13 | * Revision history | ||
14 | * 18th Jun 2007 Initial version. | ||
15 | */ | ||
16 | |||
17 | #ifndef LM4857_H_ | ||
18 | #define LM4857_H_ | ||
19 | |||
20 | /* The register offsets in the cache array */ | ||
21 | #define LM4857_MVOL 0 | ||
22 | #define LM4857_LVOL 1 | ||
23 | #define LM4857_RVOL 2 | ||
24 | #define LM4857_CTRL 3 | ||
25 | |||
26 | /* the shifts required to set these bits */ | ||
27 | #define LM4857_3D 5 | ||
28 | #define LM4857_WAKEUP 5 | ||
29 | #define LM4857_EPGAIN 4 | ||
30 | |||
31 | #endif /*LM4857_H_*/ | ||
32 | |||
diff --git a/sound/soc/samsung/ln2440sbc_alc650.c b/sound/soc/samsung/ln2440sbc_alc650.c index a2bb34def740..bd91c19a6c08 100644 --- a/sound/soc/samsung/ln2440sbc_alc650.c +++ b/sound/soc/samsung/ln2440sbc_alc650.c | |||
@@ -16,15 +16,8 @@ | |||
16 | * | 16 | * |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | 19 | #include <sound/soc.h> |
24 | 20 | ||
25 | #include "dma.h" | ||
26 | #include "ac97.h" | ||
27 | |||
28 | static struct snd_soc_card ln2440sbc; | 21 | static struct snd_soc_card ln2440sbc; |
29 | 22 | ||
30 | static struct snd_soc_dai_link ln2440sbc_dai[] = { | 23 | static struct snd_soc_dai_link ln2440sbc_dai[] = { |
diff --git a/sound/soc/samsung/neo1973_gta02_wm8753.c b/sound/soc/samsung/neo1973_gta02_wm8753.c deleted file mode 100644 index 0d0ae2b9eef6..000000000000 --- a/sound/soc/samsung/neo1973_gta02_wm8753.c +++ /dev/null | |||
@@ -1,504 +0,0 @@ | |||
1 | /* | ||
2 | * neo1973_gta02_wm8753.c -- SoC audio for Openmoko Freerunner(GTA02) | ||
3 | * | ||
4 | * Copyright 2007 Openmoko Inc | ||
5 | * Author: Graeme Gregory <graeme@openmoko.org> | ||
6 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
7 | * Author: Graeme Gregory <linux@wolfsonmicro.com> | ||
8 | * Copyright 2009 Wolfson Microelectronics | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify it | ||
11 | * under the terms of the GNU General Public License as published by the | ||
12 | * Free Software Foundation; either version 2 of the License, or (at your | ||
13 | * option) any later version. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/moduleparam.h> | ||
18 | #include <linux/timer.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/soc.h> | ||
25 | |||
26 | #include <asm/mach-types.h> | ||
27 | |||
28 | #include <plat/regs-iis.h> | ||
29 | |||
30 | #include <mach/regs-clock.h> | ||
31 | #include <asm/io.h> | ||
32 | #include <mach/gta02.h> | ||
33 | #include "../codecs/wm8753.h" | ||
34 | #include "dma.h" | ||
35 | #include "s3c24xx-i2s.h" | ||
36 | |||
37 | static struct snd_soc_card neo1973_gta02; | ||
38 | |||
39 | static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, | ||
40 | struct snd_pcm_hw_params *params) | ||
41 | { | ||
42 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
43 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
44 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
45 | unsigned int pll_out = 0, bclk = 0; | ||
46 | int ret = 0; | ||
47 | unsigned long iis_clkrate; | ||
48 | |||
49 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
50 | |||
51 | switch (params_rate(params)) { | ||
52 | case 8000: | ||
53 | case 16000: | ||
54 | pll_out = 12288000; | ||
55 | break; | ||
56 | case 48000: | ||
57 | bclk = WM8753_BCLK_DIV_4; | ||
58 | pll_out = 12288000; | ||
59 | break; | ||
60 | case 96000: | ||
61 | bclk = WM8753_BCLK_DIV_2; | ||
62 | pll_out = 12288000; | ||
63 | break; | ||
64 | case 11025: | ||
65 | bclk = WM8753_BCLK_DIV_16; | ||
66 | pll_out = 11289600; | ||
67 | break; | ||
68 | case 22050: | ||
69 | bclk = WM8753_BCLK_DIV_8; | ||
70 | pll_out = 11289600; | ||
71 | break; | ||
72 | case 44100: | ||
73 | bclk = WM8753_BCLK_DIV_4; | ||
74 | pll_out = 11289600; | ||
75 | break; | ||
76 | case 88200: | ||
77 | bclk = WM8753_BCLK_DIV_2; | ||
78 | pll_out = 11289600; | ||
79 | break; | ||
80 | } | ||
81 | |||
82 | /* set codec DAI configuration */ | ||
83 | ret = snd_soc_dai_set_fmt(codec_dai, | ||
84 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
85 | SND_SOC_DAIFMT_CBM_CFM); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | |||
89 | /* set cpu DAI configuration */ | ||
90 | ret = snd_soc_dai_set_fmt(cpu_dai, | ||
91 | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
92 | SND_SOC_DAIFMT_CBM_CFM); | ||
93 | if (ret < 0) | ||
94 | return ret; | ||
95 | |||
96 | /* set the codec system clock for DAC and ADC */ | ||
97 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, pll_out, | ||
98 | SND_SOC_CLOCK_IN); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | |||
102 | /* set MCLK division for sample rate */ | ||
103 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, | ||
104 | S3C2410_IISMOD_32FS); | ||
105 | if (ret < 0) | ||
106 | return ret; | ||
107 | |||
108 | /* set codec BCLK division for sample rate */ | ||
109 | ret = snd_soc_dai_set_clkdiv(codec_dai, | ||
110 | WM8753_BCLKDIV, bclk); | ||
111 | if (ret < 0) | ||
112 | return ret; | ||
113 | |||
114 | /* set prescaler division for sample rate */ | ||
115 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | ||
116 | S3C24XX_PRESCALE(4, 4)); | ||
117 | if (ret < 0) | ||
118 | return ret; | ||
119 | |||
120 | /* codec PLL input is PCLK/4 */ | ||
121 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, | ||
122 | iis_clkrate / 4, pll_out); | ||
123 | if (ret < 0) | ||
124 | return ret; | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static int neo1973_gta02_hifi_hw_free(struct snd_pcm_substream *substream) | ||
130 | { | ||
131 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
132 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
133 | |||
134 | /* disable the PLL */ | ||
135 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Neo1973 WM8753 HiFi DAI opserations. | ||
140 | */ | ||
141 | static struct snd_soc_ops neo1973_gta02_hifi_ops = { | ||
142 | .hw_params = neo1973_gta02_hifi_hw_params, | ||
143 | .hw_free = neo1973_gta02_hifi_hw_free, | ||
144 | }; | ||
145 | |||
146 | static int neo1973_gta02_voice_hw_params( | ||
147 | struct snd_pcm_substream *substream, | ||
148 | struct snd_pcm_hw_params *params) | ||
149 | { | ||
150 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
151 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
152 | unsigned int pcmdiv = 0; | ||
153 | int ret = 0; | ||
154 | unsigned long iis_clkrate; | ||
155 | |||
156 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | ||
157 | |||
158 | if (params_rate(params) != 8000) | ||
159 | return -EINVAL; | ||
160 | if (params_channels(params) != 1) | ||
161 | return -EINVAL; | ||
162 | |||
163 | pcmdiv = WM8753_PCM_DIV_6; /* 2.048 MHz */ | ||
164 | |||
165 | /* todo: gg check mode (DSP_B) against CSR datasheet */ | ||
166 | /* set codec DAI configuration */ | ||
167 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_B | | ||
168 | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS); | ||
169 | if (ret < 0) | ||
170 | return ret; | ||
171 | |||
172 | /* set the codec system clock for DAC and ADC */ | ||
173 | ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_PCMCLK, | ||
174 | 12288000, SND_SOC_CLOCK_IN); | ||
175 | if (ret < 0) | ||
176 | return ret; | ||
177 | |||
178 | /* set codec PCM division for sample rate */ | ||
179 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8753_PCMDIV, | ||
180 | pcmdiv); | ||
181 | if (ret < 0) | ||
182 | return ret; | ||
183 | |||
184 | /* configure and enable PLL for 12.288MHz output */ | ||
185 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, | ||
186 | iis_clkrate / 4, 12288000); | ||
187 | if (ret < 0) | ||
188 | return ret; | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int neo1973_gta02_voice_hw_free(struct snd_pcm_substream *substream) | ||
194 | { | ||
195 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
196 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
197 | |||
198 | /* disable the PLL */ | ||
199 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); | ||
200 | } | ||
201 | |||
202 | static struct snd_soc_ops neo1973_gta02_voice_ops = { | ||
203 | .hw_params = neo1973_gta02_voice_hw_params, | ||
204 | .hw_free = neo1973_gta02_voice_hw_free, | ||
205 | }; | ||
206 | |||
207 | #define LM4853_AMP 1 | ||
208 | #define LM4853_SPK 2 | ||
209 | |||
210 | static u8 lm4853_state; | ||
211 | |||
212 | /* This has no effect, it exists only to maintain compatibility with | ||
213 | * existing ALSA state files. | ||
214 | */ | ||
215 | static int lm4853_set_state(struct snd_kcontrol *kcontrol, | ||
216 | struct snd_ctl_elem_value *ucontrol) | ||
217 | { | ||
218 | int val = ucontrol->value.integer.value[0]; | ||
219 | |||
220 | if (val) | ||
221 | lm4853_state |= LM4853_AMP; | ||
222 | else | ||
223 | lm4853_state &= ~LM4853_AMP; | ||
224 | |||
225 | return 0; | ||
226 | } | ||
227 | |||
228 | static int lm4853_get_state(struct snd_kcontrol *kcontrol, | ||
229 | struct snd_ctl_elem_value *ucontrol) | ||
230 | { | ||
231 | ucontrol->value.integer.value[0] = lm4853_state & LM4853_AMP; | ||
232 | |||
233 | return 0; | ||
234 | } | ||
235 | |||
236 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, | ||
237 | struct snd_ctl_elem_value *ucontrol) | ||
238 | { | ||
239 | int val = ucontrol->value.integer.value[0]; | ||
240 | |||
241 | if (val) { | ||
242 | lm4853_state |= LM4853_SPK; | ||
243 | gpio_set_value(GTA02_GPIO_HP_IN, 0); | ||
244 | } else { | ||
245 | lm4853_state &= ~LM4853_SPK; | ||
246 | gpio_set_value(GTA02_GPIO_HP_IN, 1); | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, | ||
253 | struct snd_ctl_elem_value *ucontrol) | ||
254 | { | ||
255 | ucontrol->value.integer.value[0] = (lm4853_state & LM4853_SPK) >> 1; | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int lm4853_event(struct snd_soc_dapm_widget *w, | ||
261 | struct snd_kcontrol *k, | ||
262 | int event) | ||
263 | { | ||
264 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | ||
270 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), | ||
271 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
272 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
273 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
274 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
275 | SND_SOC_DAPM_SPK("Handset Spk", NULL), | ||
276 | }; | ||
277 | |||
278 | |||
279 | /* example machine audio_mapnections */ | ||
280 | static const struct snd_soc_dapm_route audio_map[] = { | ||
281 | |||
282 | /* Connections to the lm4853 amp */ | ||
283 | {"Stereo Out", NULL, "LOUT1"}, | ||
284 | {"Stereo Out", NULL, "ROUT1"}, | ||
285 | |||
286 | /* Connections to the GSM Module */ | ||
287 | {"GSM Line Out", NULL, "MONO1"}, | ||
288 | {"GSM Line Out", NULL, "MONO2"}, | ||
289 | {"RXP", NULL, "GSM Line In"}, | ||
290 | {"RXN", NULL, "GSM Line In"}, | ||
291 | |||
292 | /* Connections to Headset */ | ||
293 | {"MIC1", NULL, "Mic Bias"}, | ||
294 | {"Mic Bias", NULL, "Headset Mic"}, | ||
295 | |||
296 | /* Call Mic */ | ||
297 | {"MIC2", NULL, "Mic Bias"}, | ||
298 | {"MIC2N", NULL, "Mic Bias"}, | ||
299 | {"Mic Bias", NULL, "Handset Mic"}, | ||
300 | |||
301 | /* Call Speaker */ | ||
302 | {"Handset Spk", NULL, "LOUT2"}, | ||
303 | {"Handset Spk", NULL, "ROUT2"}, | ||
304 | |||
305 | /* Connect the ALC pins */ | ||
306 | {"ACIN", NULL, "ACOP"}, | ||
307 | }; | ||
308 | |||
309 | static const struct snd_kcontrol_new wm8753_neo1973_gta02_controls[] = { | ||
310 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | ||
311 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), | ||
312 | SOC_DAPM_PIN_SWITCH("GSM Line In"), | ||
313 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
314 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
315 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | ||
316 | |||
317 | /* This has no effect, it exists only to maintain compatibility with | ||
318 | * existing ALSA state files. | ||
319 | */ | ||
320 | SOC_SINGLE_EXT("Amp State Switch", 6, 0, 1, 0, | ||
321 | lm4853_get_state, | ||
322 | lm4853_set_state), | ||
323 | SOC_SINGLE_EXT("Amp Spk Switch", 7, 0, 1, 0, | ||
324 | lm4853_get_spk, | ||
325 | lm4853_set_spk), | ||
326 | }; | ||
327 | |||
328 | /* | ||
329 | * This is an example machine initialisation for a wm8753 connected to a | ||
330 | * neo1973 GTA02. | ||
331 | */ | ||
332 | static int neo1973_gta02_wm8753_init(struct snd_soc_pcm_runtime *rtd) | ||
333 | { | ||
334 | struct snd_soc_codec *codec = rtd->codec; | ||
335 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
336 | int err; | ||
337 | |||
338 | /* set up NC codec pins */ | ||
339 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | ||
340 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | ||
341 | snd_soc_dapm_nc_pin(dapm, "LINE1"); | ||
342 | snd_soc_dapm_nc_pin(dapm, "LINE2"); | ||
343 | |||
344 | /* Add neo1973 gta02 specific widgets */ | ||
345 | snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, | ||
346 | ARRAY_SIZE(wm8753_dapm_widgets)); | ||
347 | |||
348 | /* add neo1973 gta02 specific controls */ | ||
349 | err = snd_soc_add_controls(codec, wm8753_neo1973_gta02_controls, | ||
350 | ARRAY_SIZE(wm8753_neo1973_gta02_controls)); | ||
351 | |||
352 | if (err < 0) | ||
353 | return err; | ||
354 | |||
355 | /* set up neo1973 gta02 specific audio path audio_map */ | ||
356 | snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); | ||
357 | |||
358 | /* set endpoints to default off mode */ | ||
359 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); | ||
360 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
361 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
362 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
363 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); | ||
364 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); | ||
365 | |||
366 | /* allow audio paths from the GSM modem to run during suspend */ | ||
367 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
368 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); | ||
369 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); | ||
370 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); | ||
371 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); | ||
372 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
373 | |||
374 | snd_soc_dapm_sync(dapm); | ||
375 | |||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * BT Codec DAI | ||
381 | */ | ||
382 | static struct snd_soc_dai_driver bt_dai = { | ||
383 | .name = "bluetooth-dai", | ||
384 | .playback = { | ||
385 | .channels_min = 1, | ||
386 | .channels_max = 1, | ||
387 | .rates = SNDRV_PCM_RATE_8000, | ||
388 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
389 | .capture = { | ||
390 | .channels_min = 1, | ||
391 | .channels_max = 1, | ||
392 | .rates = SNDRV_PCM_RATE_8000, | ||
393 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | ||
394 | }; | ||
395 | |||
396 | static struct snd_soc_dai_link neo1973_gta02_dai[] = { | ||
397 | { /* Hifi Playback - for similatious use with voice below */ | ||
398 | .name = "WM8753", | ||
399 | .stream_name = "WM8753 HiFi", | ||
400 | .cpu_dai_name = "s3c24xx-iis", | ||
401 | .codec_dai_name = "wm8753-hifi", | ||
402 | .init = neo1973_gta02_wm8753_init, | ||
403 | .platform_name = "samsung-audio", | ||
404 | .codec_name = "wm8753-codec.0-001a", | ||
405 | .ops = &neo1973_gta02_hifi_ops, | ||
406 | }, | ||
407 | { /* Voice via BT */ | ||
408 | .name = "Bluetooth", | ||
409 | .stream_name = "Voice", | ||
410 | .cpu_dai_name = "bluetooth-dai", | ||
411 | .codec_dai_name = "wm8753-voice", | ||
412 | .ops = &neo1973_gta02_voice_ops, | ||
413 | .codec_name = "wm8753-codec.0-001a", | ||
414 | .platform_name = "samsung-audio", | ||
415 | }, | ||
416 | }; | ||
417 | |||
418 | static struct snd_soc_card neo1973_gta02 = { | ||
419 | .name = "neo1973-gta02", | ||
420 | .dai_link = neo1973_gta02_dai, | ||
421 | .num_links = ARRAY_SIZE(neo1973_gta02_dai), | ||
422 | }; | ||
423 | |||
424 | static struct platform_device *neo1973_gta02_snd_device; | ||
425 | |||
426 | static int __init neo1973_gta02_init(void) | ||
427 | { | ||
428 | int ret; | ||
429 | |||
430 | if (!machine_is_neo1973_gta02()) { | ||
431 | printk(KERN_INFO | ||
432 | "Only GTA02 is supported by this ASoC driver\n"); | ||
433 | return -ENODEV; | ||
434 | } | ||
435 | |||
436 | neo1973_gta02_snd_device = platform_device_alloc("soc-audio", -1); | ||
437 | if (!neo1973_gta02_snd_device) | ||
438 | return -ENOMEM; | ||
439 | |||
440 | /* register bluetooth DAI here */ | ||
441 | ret = snd_soc_register_dai(&neo1973_gta02_snd_device->dev, &bt_dai); | ||
442 | if (ret) | ||
443 | goto err_put_device; | ||
444 | |||
445 | platform_set_drvdata(neo1973_gta02_snd_device, &neo1973_gta02); | ||
446 | ret = platform_device_add(neo1973_gta02_snd_device); | ||
447 | |||
448 | if (ret) | ||
449 | goto err_unregister_dai; | ||
450 | |||
451 | /* Initialise GPIOs used by amp */ | ||
452 | ret = gpio_request(GTA02_GPIO_HP_IN, "GTA02_HP_IN"); | ||
453 | if (ret) { | ||
454 | pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_HP_IN); | ||
455 | goto err_del_device; | ||
456 | } | ||
457 | |||
458 | ret = gpio_direction_output(GTA02_GPIO_HP_IN, 1); | ||
459 | if (ret) { | ||
460 | pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_HP_IN); | ||
461 | goto err_free_gpio_hp_in; | ||
462 | } | ||
463 | |||
464 | ret = gpio_request(GTA02_GPIO_AMP_SHUT, "GTA02_AMP_SHUT"); | ||
465 | if (ret) { | ||
466 | pr_err("gta02_wm8753: Failed to register GPIO %d\n", GTA02_GPIO_AMP_SHUT); | ||
467 | goto err_free_gpio_hp_in; | ||
468 | } | ||
469 | |||
470 | ret = gpio_direction_output(GTA02_GPIO_AMP_SHUT, 1); | ||
471 | if (ret) { | ||
472 | pr_err("gta02_wm8753: Failed to configure GPIO %d\n", GTA02_GPIO_AMP_SHUT); | ||
473 | goto err_free_gpio_amp_shut; | ||
474 | } | ||
475 | |||
476 | return 0; | ||
477 | |||
478 | err_free_gpio_amp_shut: | ||
479 | gpio_free(GTA02_GPIO_AMP_SHUT); | ||
480 | err_free_gpio_hp_in: | ||
481 | gpio_free(GTA02_GPIO_HP_IN); | ||
482 | err_del_device: | ||
483 | platform_device_del(neo1973_gta02_snd_device); | ||
484 | err_unregister_dai: | ||
485 | snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); | ||
486 | err_put_device: | ||
487 | platform_device_put(neo1973_gta02_snd_device); | ||
488 | return ret; | ||
489 | } | ||
490 | module_init(neo1973_gta02_init); | ||
491 | |||
492 | static void __exit neo1973_gta02_exit(void) | ||
493 | { | ||
494 | snd_soc_unregister_dai(&neo1973_gta02_snd_device->dev); | ||
495 | platform_device_unregister(neo1973_gta02_snd_device); | ||
496 | gpio_free(GTA02_GPIO_HP_IN); | ||
497 | gpio_free(GTA02_GPIO_AMP_SHUT); | ||
498 | } | ||
499 | module_exit(neo1973_gta02_exit); | ||
500 | |||
501 | /* Module information */ | ||
502 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org"); | ||
503 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 GTA02"); | ||
504 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/samsung/neo1973_wm8753.c b/sound/soc/samsung/neo1973_wm8753.c index d20815d5ab2e..78bfdb3f5d7e 100644 --- a/sound/soc/samsung/neo1973_wm8753.c +++ b/sound/soc/samsung/neo1973_wm8753.c | |||
@@ -1,57 +1,32 @@ | |||
1 | /* | 1 | /* |
2 | * neo1973_wm8753.c -- SoC audio for Neo1973 | 2 | * neo1973_wm8753.c -- SoC audio for Openmoko Neo1973 and Freerunner devices |
3 | * | 3 | * |
4 | * Copyright 2007 Openmoko Inc | ||
5 | * Author: Graeme Gregory <graeme@openmoko.org> | ||
4 | * Copyright 2007 Wolfson Microelectronics PLC. | 6 | * Copyright 2007 Wolfson Microelectronics PLC. |
5 | * Author: Graeme Gregory | 7 | * Author: Graeme Gregory |
6 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | 8 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com |
9 | * Copyright 2009 Wolfson Microelectronics | ||
7 | * | 10 | * |
8 | * This program is free software; you can redistribute it and/or modify it | 11 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License as published by the | 12 | * under the terms of the GNU General Public License as published by the |
10 | * Free Software Foundation; either version 2 of the License, or (at your | 13 | * Free Software Foundation; either version 2 of the License, or (at your |
11 | * option) any later version. | 14 | * option) any later version. |
12 | * | ||
13 | */ | 15 | */ |
14 | 16 | ||
15 | #include <linux/module.h> | 17 | #include <linux/module.h> |
16 | #include <linux/moduleparam.h> | ||
17 | #include <linux/timer.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
20 | #include <linux/i2c.h> | 19 | #include <linux/gpio.h> |
21 | #include <sound/core.h> | 20 | |
22 | #include <sound/pcm.h> | ||
23 | #include <sound/soc.h> | 21 | #include <sound/soc.h> |
24 | #include <sound/tlv.h> | ||
25 | 22 | ||
26 | #include <asm/mach-types.h> | 23 | #include <asm/mach-types.h> |
27 | #include <asm/hardware/scoop.h> | ||
28 | #include <mach/regs-clock.h> | ||
29 | #include <mach/regs-gpio.h> | ||
30 | #include <mach/hardware.h> | ||
31 | #include <linux/io.h> | ||
32 | #include <mach/spi-gpio.h> | ||
33 | |||
34 | #include <plat/regs-iis.h> | 24 | #include <plat/regs-iis.h> |
25 | #include <mach/gta02.h> | ||
35 | 26 | ||
36 | #include "../codecs/wm8753.h" | 27 | #include "../codecs/wm8753.h" |
37 | #include "lm4857.h" | ||
38 | #include "dma.h" | ||
39 | #include "s3c24xx-i2s.h" | 28 | #include "s3c24xx-i2s.h" |
40 | 29 | ||
41 | /* define the scenarios */ | ||
42 | #define NEO_AUDIO_OFF 0 | ||
43 | #define NEO_GSM_CALL_AUDIO_HANDSET 1 | ||
44 | #define NEO_GSM_CALL_AUDIO_HEADSET 2 | ||
45 | #define NEO_GSM_CALL_AUDIO_BLUETOOTH 3 | ||
46 | #define NEO_STEREO_TO_SPEAKERS 4 | ||
47 | #define NEO_STEREO_TO_HEADPHONES 5 | ||
48 | #define NEO_CAPTURE_HANDSET 6 | ||
49 | #define NEO_CAPTURE_HEADSET 7 | ||
50 | #define NEO_CAPTURE_BLUETOOTH 8 | ||
51 | |||
52 | static struct snd_soc_card neo1973; | ||
53 | static struct i2c_client *i2c; | ||
54 | |||
55 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | 30 | static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, |
56 | struct snd_pcm_hw_params *params) | 31 | struct snd_pcm_hw_params *params) |
57 | { | 32 | { |
@@ -62,8 +37,6 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
62 | int ret = 0; | 37 | int ret = 0; |
63 | unsigned long iis_clkrate; | 38 | unsigned long iis_clkrate; |
64 | 39 | ||
65 | pr_debug("Entered %s\n", __func__); | ||
66 | |||
67 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 40 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
68 | 41 | ||
69 | switch (params_rate(params)) { | 42 | switch (params_rate(params)) { |
@@ -148,8 +121,6 @@ static int neo1973_hifi_hw_free(struct snd_pcm_substream *substream) | |||
148 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 121 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
149 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 122 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
150 | 123 | ||
151 | pr_debug("Entered %s\n", __func__); | ||
152 | |||
153 | /* disable the PLL */ | 124 | /* disable the PLL */ |
154 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); | 125 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, 0, 0); |
155 | } | 126 | } |
@@ -171,8 +142,6 @@ static int neo1973_voice_hw_params(struct snd_pcm_substream *substream, | |||
171 | int ret = 0; | 142 | int ret = 0; |
172 | unsigned long iis_clkrate; | 143 | unsigned long iis_clkrate; |
173 | 144 | ||
174 | pr_debug("Entered %s\n", __func__); | ||
175 | |||
176 | iis_clkrate = s3c24xx_i2s_get_clockrate(); | 145 | iis_clkrate = s3c24xx_i2s_get_clockrate(); |
177 | 146 | ||
178 | if (params_rate(params) != 8000) | 147 | if (params_rate(params) != 8000) |
@@ -214,8 +183,6 @@ static int neo1973_voice_hw_free(struct snd_pcm_substream *substream) | |||
214 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 183 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
215 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 184 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
216 | 185 | ||
217 | pr_debug("Entered %s\n", __func__); | ||
218 | |||
219 | /* disable the PLL */ | 186 | /* disable the PLL */ |
220 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); | 187 | return snd_soc_dai_set_pll(codec_dai, WM8753_PLL2, 0, 0, 0); |
221 | } | 188 | } |
@@ -225,335 +192,232 @@ static struct snd_soc_ops neo1973_voice_ops = { | |||
225 | .hw_free = neo1973_voice_hw_free, | 192 | .hw_free = neo1973_voice_hw_free, |
226 | }; | 193 | }; |
227 | 194 | ||
228 | static int neo1973_scenario; | 195 | /* Shared routes and controls */ |
229 | |||
230 | static int neo1973_get_scenario(struct snd_kcontrol *kcontrol, | ||
231 | struct snd_ctl_elem_value *ucontrol) | ||
232 | { | ||
233 | ucontrol->value.integer.value[0] = neo1973_scenario; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static int set_scenario_endpoints(struct snd_soc_codec *codec, int scenario) | ||
238 | { | ||
239 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
240 | |||
241 | pr_debug("Entered %s\n", __func__); | ||
242 | |||
243 | switch (neo1973_scenario) { | ||
244 | case NEO_AUDIO_OFF: | ||
245 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
246 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
247 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
248 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
249 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
250 | break; | ||
251 | case NEO_GSM_CALL_AUDIO_HANDSET: | ||
252 | snd_soc_dapm_enable_pin(dapm, "Audio Out"); | ||
253 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); | ||
254 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); | ||
255 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
256 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); | ||
257 | break; | ||
258 | case NEO_GSM_CALL_AUDIO_HEADSET: | ||
259 | snd_soc_dapm_enable_pin(dapm, "Audio Out"); | ||
260 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); | ||
261 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); | ||
262 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | ||
263 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
264 | break; | ||
265 | case NEO_GSM_CALL_AUDIO_BLUETOOTH: | ||
266 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
267 | snd_soc_dapm_enable_pin(dapm, "GSM Line Out"); | ||
268 | snd_soc_dapm_enable_pin(dapm, "GSM Line In"); | ||
269 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
270 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
271 | break; | ||
272 | case NEO_STEREO_TO_SPEAKERS: | ||
273 | snd_soc_dapm_enable_pin(dapm, "Audio Out"); | ||
274 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
275 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
276 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
277 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
278 | break; | ||
279 | case NEO_STEREO_TO_HEADPHONES: | ||
280 | snd_soc_dapm_enable_pin(dapm, "Audio Out"); | ||
281 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
282 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
283 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
284 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
285 | break; | ||
286 | case NEO_CAPTURE_HANDSET: | ||
287 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
288 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
289 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
290 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
291 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); | ||
292 | break; | ||
293 | case NEO_CAPTURE_HEADSET: | ||
294 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
295 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
296 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
297 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | ||
298 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
299 | break; | ||
300 | case NEO_CAPTURE_BLUETOOTH: | ||
301 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
302 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
303 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
304 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
305 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
306 | break; | ||
307 | default: | ||
308 | snd_soc_dapm_disable_pin(dapm, "Audio Out"); | ||
309 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
310 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
311 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
312 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | ||
313 | } | ||
314 | 196 | ||
315 | snd_soc_dapm_sync(dapm); | 197 | static const struct snd_soc_dapm_widget neo1973_wm8753_dapm_widgets[] = { |
198 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | ||
199 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
200 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
201 | SND_SOC_DAPM_MIC("Handset Mic", NULL), | ||
202 | }; | ||
316 | 203 | ||
317 | return 0; | 204 | static const struct snd_soc_dapm_route neo1973_wm8753_routes[] = { |
318 | } | 205 | /* Connections to the GSM Module */ |
206 | {"GSM Line Out", NULL, "MONO1"}, | ||
207 | {"GSM Line Out", NULL, "MONO2"}, | ||
208 | {"RXP", NULL, "GSM Line In"}, | ||
209 | {"RXN", NULL, "GSM Line In"}, | ||
319 | 210 | ||
320 | static int neo1973_set_scenario(struct snd_kcontrol *kcontrol, | 211 | /* Connections to Headset */ |
321 | struct snd_ctl_elem_value *ucontrol) | 212 | {"MIC1", NULL, "Mic Bias"}, |
322 | { | 213 | {"Mic Bias", NULL, "Headset Mic"}, |
323 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
324 | 214 | ||
325 | pr_debug("Entered %s\n", __func__); | 215 | /* Call Mic */ |
216 | {"MIC2", NULL, "Mic Bias"}, | ||
217 | {"MIC2N", NULL, "Mic Bias"}, | ||
218 | {"Mic Bias", NULL, "Handset Mic"}, | ||
326 | 219 | ||
327 | if (neo1973_scenario == ucontrol->value.integer.value[0]) | 220 | /* Connect the ALC pins */ |
328 | return 0; | 221 | {"ACIN", NULL, "ACOP"}, |
222 | }; | ||
329 | 223 | ||
330 | neo1973_scenario = ucontrol->value.integer.value[0]; | 224 | static const struct snd_kcontrol_new neo1973_wm8753_controls[] = { |
331 | set_scenario_endpoints(codec, neo1973_scenario); | 225 | SOC_DAPM_PIN_SWITCH("GSM Line Out"), |
332 | return 1; | 226 | SOC_DAPM_PIN_SWITCH("GSM Line In"), |
333 | } | 227 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
228 | SOC_DAPM_PIN_SWITCH("Handset Mic"), | ||
229 | }; | ||
334 | 230 | ||
335 | static u8 lm4857_regs[4] = {0x00, 0x40, 0x80, 0xC0}; | 231 | /* GTA02 specific routes and controlls */ |
336 | 232 | ||
337 | static void lm4857_write_regs(void) | 233 | #ifdef CONFIG_MACH_NEO1973_GTA02 |
338 | { | ||
339 | pr_debug("Entered %s\n", __func__); | ||
340 | 234 | ||
341 | if (i2c_master_send(i2c, lm4857_regs, 4) != 4) | 235 | static int gta02_speaker_enabled; |
342 | printk(KERN_ERR "lm4857: i2c write failed\n"); | ||
343 | } | ||
344 | 236 | ||
345 | static int lm4857_get_reg(struct snd_kcontrol *kcontrol, | 237 | static int lm4853_set_spk(struct snd_kcontrol *kcontrol, |
346 | struct snd_ctl_elem_value *ucontrol) | 238 | struct snd_ctl_elem_value *ucontrol) |
347 | { | 239 | { |
348 | struct soc_mixer_control *mc = | 240 | gta02_speaker_enabled = ucontrol->value.integer.value[0]; |
349 | (struct soc_mixer_control *)kcontrol->private_value; | ||
350 | int reg = mc->reg; | ||
351 | int shift = mc->shift; | ||
352 | int mask = mc->max; | ||
353 | 241 | ||
354 | pr_debug("Entered %s\n", __func__); | 242 | gpio_set_value(GTA02_GPIO_HP_IN, !gta02_speaker_enabled); |
355 | 243 | ||
356 | ucontrol->value.integer.value[0] = (lm4857_regs[reg] >> shift) & mask; | ||
357 | return 0; | 244 | return 0; |
358 | } | 245 | } |
359 | 246 | ||
360 | static int lm4857_set_reg(struct snd_kcontrol *kcontrol, | 247 | static int lm4853_get_spk(struct snd_kcontrol *kcontrol, |
361 | struct snd_ctl_elem_value *ucontrol) | 248 | struct snd_ctl_elem_value *ucontrol) |
362 | { | 249 | { |
363 | struct soc_mixer_control *mc = | 250 | ucontrol->value.integer.value[0] = gta02_speaker_enabled; |
364 | (struct soc_mixer_control *)kcontrol->private_value; | 251 | return 0; |
365 | int reg = mc->reg; | ||
366 | int shift = mc->shift; | ||
367 | int mask = mc->max; | ||
368 | |||
369 | if (((lm4857_regs[reg] >> shift) & mask) == | ||
370 | ucontrol->value.integer.value[0]) | ||
371 | return 0; | ||
372 | |||
373 | lm4857_regs[reg] &= ~(mask << shift); | ||
374 | lm4857_regs[reg] |= ucontrol->value.integer.value[0] << shift; | ||
375 | lm4857_write_regs(); | ||
376 | return 1; | ||
377 | } | 252 | } |
378 | 253 | ||
379 | static int lm4857_get_mode(struct snd_kcontrol *kcontrol, | 254 | static int lm4853_event(struct snd_soc_dapm_widget *w, |
380 | struct snd_ctl_elem_value *ucontrol) | 255 | struct snd_kcontrol *k, int event) |
381 | { | 256 | { |
382 | u8 value = lm4857_regs[LM4857_CTRL] & 0x0F; | 257 | gpio_set_value(GTA02_GPIO_AMP_SHUT, SND_SOC_DAPM_EVENT_OFF(event)); |
383 | |||
384 | pr_debug("Entered %s\n", __func__); | ||
385 | |||
386 | if (value) | ||
387 | value -= 5; | ||
388 | 258 | ||
389 | ucontrol->value.integer.value[0] = value; | ||
390 | return 0; | 259 | return 0; |
391 | } | 260 | } |
392 | 261 | ||
393 | static int lm4857_set_mode(struct snd_kcontrol *kcontrol, | 262 | static const struct snd_soc_dapm_route neo1973_gta02_routes[] = { |
394 | struct snd_ctl_elem_value *ucontrol) | 263 | /* Connections to the amp */ |
395 | { | 264 | {"Stereo Out", NULL, "LOUT1"}, |
396 | u8 value = ucontrol->value.integer.value[0]; | 265 | {"Stereo Out", NULL, "ROUT1"}, |
397 | |||
398 | pr_debug("Entered %s\n", __func__); | ||
399 | |||
400 | if (value) | ||
401 | value += 5; | ||
402 | |||
403 | if ((lm4857_regs[LM4857_CTRL] & 0x0F) == value) | ||
404 | return 0; | ||
405 | |||
406 | lm4857_regs[LM4857_CTRL] &= 0xF0; | ||
407 | lm4857_regs[LM4857_CTRL] |= value; | ||
408 | lm4857_write_regs(); | ||
409 | return 1; | ||
410 | } | ||
411 | 266 | ||
412 | static const struct snd_soc_dapm_widget wm8753_dapm_widgets[] = { | 267 | /* Call Speaker */ |
413 | SND_SOC_DAPM_LINE("Audio Out", NULL), | 268 | {"Handset Spk", NULL, "LOUT2"}, |
414 | SND_SOC_DAPM_LINE("GSM Line Out", NULL), | 269 | {"Handset Spk", NULL, "ROUT2"}, |
415 | SND_SOC_DAPM_LINE("GSM Line In", NULL), | ||
416 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
417 | SND_SOC_DAPM_MIC("Call Mic", NULL), | ||
418 | }; | 270 | }; |
419 | 271 | ||
272 | static const struct snd_kcontrol_new neo1973_gta02_wm8753_controls[] = { | ||
273 | SOC_DAPM_PIN_SWITCH("Handset Spk"), | ||
274 | SOC_DAPM_PIN_SWITCH("Stereo Out"), | ||
420 | 275 | ||
421 | static const struct snd_soc_dapm_route dapm_routes[] = { | 276 | SOC_SINGLE_BOOL_EXT("Amp Spk Switch", 0, |
422 | 277 | lm4853_get_spk, | |
423 | /* Connections to the lm4857 amp */ | 278 | lm4853_set_spk), |
424 | {"Audio Out", NULL, "LOUT1"}, | 279 | }; |
425 | {"Audio Out", NULL, "ROUT1"}, | ||
426 | |||
427 | /* Connections to the GSM Module */ | ||
428 | {"GSM Line Out", NULL, "MONO1"}, | ||
429 | {"GSM Line Out", NULL, "MONO2"}, | ||
430 | {"RXP", NULL, "GSM Line In"}, | ||
431 | {"RXN", NULL, "GSM Line In"}, | ||
432 | 280 | ||
433 | /* Connections to Headset */ | 281 | static const struct snd_soc_dapm_widget neo1973_gta02_wm8753_dapm_widgets[] = { |
434 | {"MIC1", NULL, "Mic Bias"}, | 282 | SND_SOC_DAPM_SPK("Handset Spk", NULL), |
435 | {"Mic Bias", NULL, "Headset Mic"}, | 283 | SND_SOC_DAPM_SPK("Stereo Out", lm4853_event), |
284 | }; | ||
436 | 285 | ||
437 | /* Call Mic */ | 286 | static int neo1973_gta02_wm8753_init(struct snd_soc_codec *codec) |
438 | {"MIC2", NULL, "Mic Bias"}, | 287 | { |
439 | {"MIC2N", NULL, "Mic Bias"}, | 288 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
440 | {"Mic Bias", NULL, "Call Mic"}, | 289 | int ret; |
441 | 290 | ||
442 | /* Connect the ALC pins */ | 291 | ret = snd_soc_dapm_new_controls(dapm, neo1973_gta02_wm8753_dapm_widgets, |
443 | {"ACIN", NULL, "ACOP"}, | 292 | ARRAY_SIZE(neo1973_gta02_wm8753_dapm_widgets)); |
444 | }; | 293 | if (ret) |
294 | return ret; | ||
445 | 295 | ||
446 | static const char *lm4857_mode[] = { | 296 | ret = snd_soc_dapm_add_routes(dapm, neo1973_gta02_routes, |
447 | "Off", | 297 | ARRAY_SIZE(neo1973_gta02_routes)); |
448 | "Call Speaker", | 298 | if (ret) |
449 | "Stereo Speakers", | 299 | return ret; |
450 | "Stereo Speakers + Headphones", | ||
451 | "Headphones" | ||
452 | }; | ||
453 | 300 | ||
454 | static const struct soc_enum lm4857_mode_enum[] = { | 301 | ret = snd_soc_add_controls(codec, neo1973_gta02_wm8753_controls, |
455 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(lm4857_mode), lm4857_mode), | 302 | ARRAY_SIZE(neo1973_gta02_wm8753_controls)); |
456 | }; | 303 | if (ret) |
304 | return ret; | ||
457 | 305 | ||
458 | static const char *neo_scenarios[] = { | 306 | snd_soc_dapm_disable_pin(dapm, "Stereo Out"); |
459 | "Off", | 307 | snd_soc_dapm_disable_pin(dapm, "Handset Spk"); |
460 | "GSM Handset", | 308 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); |
461 | "GSM Headset", | 309 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); |
462 | "GSM Bluetooth", | ||
463 | "Speakers", | ||
464 | "Headphones", | ||
465 | "Capture Handset", | ||
466 | "Capture Headset", | ||
467 | "Capture Bluetooth" | ||
468 | }; | ||
469 | 310 | ||
470 | static const struct soc_enum neo_scenario_enum[] = { | 311 | return 0; |
471 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(neo_scenarios), neo_scenarios), | 312 | } |
472 | }; | ||
473 | 313 | ||
474 | static const DECLARE_TLV_DB_SCALE(stereo_tlv, -4050, 150, 0); | 314 | #else |
475 | static const DECLARE_TLV_DB_SCALE(mono_tlv, -3450, 150, 0); | 315 | static int neo1973_gta02_wm8753_init(struct snd_soc_code *codec) { return 0; } |
476 | 316 | #endif | |
477 | static const struct snd_kcontrol_new wm8753_neo1973_controls[] = { | ||
478 | SOC_SINGLE_EXT_TLV("Amp Left Playback Volume", LM4857_LVOL, 0, 31, 0, | ||
479 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), | ||
480 | SOC_SINGLE_EXT_TLV("Amp Right Playback Volume", LM4857_RVOL, 0, 31, 0, | ||
481 | lm4857_get_reg, lm4857_set_reg, stereo_tlv), | ||
482 | SOC_SINGLE_EXT_TLV("Amp Mono Playback Volume", LM4857_MVOL, 0, 31, 0, | ||
483 | lm4857_get_reg, lm4857_set_reg, mono_tlv), | ||
484 | SOC_ENUM_EXT("Amp Mode", lm4857_mode_enum[0], | ||
485 | lm4857_get_mode, lm4857_set_mode), | ||
486 | SOC_ENUM_EXT("Neo Mode", neo_scenario_enum[0], | ||
487 | neo1973_get_scenario, neo1973_set_scenario), | ||
488 | SOC_SINGLE_EXT("Amp Spk 3D Playback Switch", LM4857_LVOL, 5, 1, 0, | ||
489 | lm4857_get_reg, lm4857_set_reg), | ||
490 | SOC_SINGLE_EXT("Amp HP 3d Playback Switch", LM4857_RVOL, 5, 1, 0, | ||
491 | lm4857_get_reg, lm4857_set_reg), | ||
492 | SOC_SINGLE_EXT("Amp Fast Wakeup Playback Switch", LM4857_CTRL, 5, 1, 0, | ||
493 | lm4857_get_reg, lm4857_set_reg), | ||
494 | SOC_SINGLE_EXT("Amp Earpiece 6dB Playback Switch", LM4857_CTRL, 4, 1, 0, | ||
495 | lm4857_get_reg, lm4857_set_reg), | ||
496 | }; | ||
497 | 317 | ||
498 | /* | ||
499 | * This is an example machine initialisation for a wm8753 connected to a | ||
500 | * neo1973 II. It is missing logic to detect hp/mic insertions and logic | ||
501 | * to re-route the audio in such an event. | ||
502 | */ | ||
503 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) | 318 | static int neo1973_wm8753_init(struct snd_soc_pcm_runtime *rtd) |
504 | { | 319 | { |
505 | struct snd_soc_codec *codec = rtd->codec; | 320 | struct snd_soc_codec *codec = rtd->codec; |
506 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 321 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
507 | int err; | 322 | int ret; |
508 | |||
509 | pr_debug("Entered %s\n", __func__); | ||
510 | 323 | ||
511 | /* set up NC codec pins */ | 324 | /* set up NC codec pins */ |
512 | snd_soc_dapm_nc_pin(dapm, "LOUT2"); | 325 | if (machine_is_neo1973_gta01()) { |
513 | snd_soc_dapm_nc_pin(dapm, "ROUT2"); | 326 | snd_soc_dapm_nc_pin(dapm, "LOUT2"); |
327 | snd_soc_dapm_nc_pin(dapm, "ROUT2"); | ||
328 | } | ||
514 | snd_soc_dapm_nc_pin(dapm, "OUT3"); | 329 | snd_soc_dapm_nc_pin(dapm, "OUT3"); |
515 | snd_soc_dapm_nc_pin(dapm, "OUT4"); | 330 | snd_soc_dapm_nc_pin(dapm, "OUT4"); |
516 | snd_soc_dapm_nc_pin(dapm, "LINE1"); | 331 | snd_soc_dapm_nc_pin(dapm, "LINE1"); |
517 | snd_soc_dapm_nc_pin(dapm, "LINE2"); | 332 | snd_soc_dapm_nc_pin(dapm, "LINE2"); |
518 | 333 | ||
519 | /* Add neo1973 specific widgets */ | 334 | /* Add neo1973 specific widgets */ |
520 | snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets, | 335 | ret = snd_soc_dapm_new_controls(dapm, neo1973_wm8753_dapm_widgets, |
521 | ARRAY_SIZE(wm8753_dapm_widgets)); | 336 | ARRAY_SIZE(neo1973_wm8753_dapm_widgets)); |
522 | 337 | if (ret) | |
523 | /* set endpoints to default mode */ | 338 | return ret; |
524 | set_scenario_endpoints(codec, NEO_AUDIO_OFF); | ||
525 | 339 | ||
526 | /* add neo1973 specific controls */ | 340 | /* add neo1973 specific controls */ |
527 | err = snd_soc_add_controls(codec, wm8753_neo1973_controls, | 341 | ret = snd_soc_add_controls(codec, neo1973_wm8753_controls, |
528 | ARRAY_SIZE(8753_neo1973_controls)); | 342 | ARRAY_SIZE(neo1973_wm8753_controls)); |
529 | if (err < 0) | 343 | if (ret) |
530 | return err; | 344 | return ret; |
531 | 345 | ||
532 | /* set up neo1973 specific audio routes */ | 346 | /* set up neo1973 specific audio routes */ |
533 | err = snd_soc_dapm_add_routes(dapm, dapm_routes, | 347 | ret = snd_soc_dapm_add_routes(dapm, neo1973_wm8753_routes, |
534 | ARRAY_SIZE(dapm_routes)); | 348 | ARRAY_SIZE(neo1973_wm8753_routes)); |
349 | if (ret) | ||
350 | return ret; | ||
351 | |||
352 | /* set endpoints to default off mode */ | ||
353 | snd_soc_dapm_disable_pin(dapm, "GSM Line Out"); | ||
354 | snd_soc_dapm_disable_pin(dapm, "GSM Line In"); | ||
355 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | ||
356 | snd_soc_dapm_disable_pin(dapm, "Handset Mic"); | ||
357 | |||
358 | /* allow audio paths from the GSM modem to run during suspend */ | ||
359 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line Out"); | ||
360 | snd_soc_dapm_ignore_suspend(dapm, "GSM Line In"); | ||
361 | snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); | ||
362 | snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); | ||
363 | |||
364 | if (machine_is_neo1973_gta02()) { | ||
365 | ret = neo1973_gta02_wm8753_init(codec); | ||
366 | if (ret) | ||
367 | return ret; | ||
368 | } | ||
535 | 369 | ||
536 | snd_soc_dapm_sync(dapm); | 370 | snd_soc_dapm_sync(dapm); |
371 | |||
537 | return 0; | 372 | return 0; |
538 | } | 373 | } |
539 | 374 | ||
540 | /* | 375 | /* GTA01 specific controlls */ |
541 | * BT Codec DAI | 376 | |
542 | */ | 377 | #ifdef CONFIG_MACH_NEO1973_GTA01 |
543 | static struct snd_soc_dai bt_dai = { | 378 | |
544 | .name = "bluetooth-dai", | 379 | static const struct snd_soc_dapm_route neo1973_lm4857_routes[] = { |
545 | .playback = { | 380 | {"Amp IN", NULL, "ROUT1"}, |
546 | .channels_min = 1, | 381 | {"Amp IN", NULL, "LOUT1"}, |
547 | .channels_max = 1, | 382 | |
548 | .rates = SNDRV_PCM_RATE_8000, | 383 | {"Handset Spk", NULL, "Amp EP"}, |
549 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 384 | {"Stereo Out", NULL, "Amp LS"}, |
550 | .capture = { | 385 | {"Headphone", NULL, "Amp HP"}, |
551 | .channels_min = 1, | 386 | }; |
552 | .channels_max = 1, | 387 | |
553 | .rates = SNDRV_PCM_RATE_8000, | 388 | static const struct snd_soc_dapm_widget neo1973_lm4857_dapm_widgets[] = { |
554 | .formats = SNDRV_PCM_FMTBIT_S16_LE,}, | 389 | SND_SOC_DAPM_SPK("Handset Spk", NULL), |
390 | SND_SOC_DAPM_SPK("Stereo Out", NULL), | ||
391 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
555 | }; | 392 | }; |
556 | 393 | ||
394 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) | ||
395 | { | ||
396 | int ret; | ||
397 | |||
398 | ret = snd_soc_dapm_new_controls(dapm, neo1973_lm4857_dapm_widgets, | ||
399 | ARRAY_SIZE(neo1973_lm4857_dapm_widgets)); | ||
400 | if (ret) | ||
401 | return ret; | ||
402 | |||
403 | ret = snd_soc_dapm_add_routes(dapm, neo1973_lm4857_routes, | ||
404 | ARRAY_SIZE(neo1973_lm4857_routes)); | ||
405 | if (ret) | ||
406 | return ret; | ||
407 | |||
408 | snd_soc_dapm_ignore_suspend(dapm, "Stereo Out"); | ||
409 | snd_soc_dapm_ignore_suspend(dapm, "Handset Spk"); | ||
410 | snd_soc_dapm_ignore_suspend(dapm, "Headphone"); | ||
411 | |||
412 | snd_soc_dapm_sync(dapm); | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | #else | ||
418 | static int neo1973_lm4857_init(struct snd_soc_dapm_context *dapm) { return 0; }; | ||
419 | #endif | ||
420 | |||
557 | static struct snd_soc_dai_link neo1973_dai[] = { | 421 | static struct snd_soc_dai_link neo1973_dai[] = { |
558 | { /* Hifi Playback - for similatious use with voice below */ | 422 | { /* Hifi Playback - for similatious use with voice below */ |
559 | .name = "WM8753", | 423 | .name = "WM8753", |
@@ -569,90 +433,49 @@ static struct snd_soc_dai_link neo1973_dai[] = { | |||
569 | .name = "Bluetooth", | 433 | .name = "Bluetooth", |
570 | .stream_name = "Voice", | 434 | .stream_name = "Voice", |
571 | .platform_name = "samsung-audio", | 435 | .platform_name = "samsung-audio", |
572 | .cpu_dai_name = "bluetooth-dai", | 436 | .cpu_dai_name = "dfbmcs320-pcm", |
573 | .codec_dai_name = "wm8753-voice", | 437 | .codec_dai_name = "wm8753-voice", |
574 | .codec_name = "wm8753-codec.0-001a", | 438 | .codec_name = "wm8753-codec.0-001a", |
575 | .ops = &neo1973_voice_ops, | 439 | .ops = &neo1973_voice_ops, |
576 | }, | 440 | }, |
577 | }; | 441 | }; |
578 | 442 | ||
579 | static struct snd_soc_card neo1973 = { | 443 | static struct snd_soc_aux_dev neo1973_aux_devs[] = { |
580 | .name = "neo1973", | 444 | { |
581 | .dai_link = neo1973_dai, | 445 | .name = "dfbmcs320", |
582 | .num_links = ARRAY_SIZE(neo1973_dai), | 446 | .codec_name = "dfbmcs320.0", |
447 | }, | ||
448 | { | ||
449 | .name = "lm4857", | ||
450 | .codec_name = "lm4857.0-007c", | ||
451 | .init = neo1973_lm4857_init, | ||
452 | }, | ||
583 | }; | 453 | }; |
584 | 454 | ||
585 | static int lm4857_i2c_probe(struct i2c_client *client, | 455 | static struct snd_soc_codec_conf neo1973_codec_conf[] = { |
586 | const struct i2c_device_id *id) | 456 | { |
587 | { | 457 | .dev_name = "lm4857.0-007c", |
588 | pr_debug("Entered %s\n", __func__); | 458 | .name_prefix = "Amp", |
589 | 459 | }, | |
590 | i2c = client; | 460 | }; |
591 | |||
592 | lm4857_write_regs(); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int lm4857_i2c_remove(struct i2c_client *client) | ||
597 | { | ||
598 | pr_debug("Entered %s\n", __func__); | ||
599 | |||
600 | i2c = NULL; | ||
601 | |||
602 | return 0; | ||
603 | } | ||
604 | |||
605 | static u8 lm4857_state; | ||
606 | |||
607 | static int lm4857_suspend(struct i2c_client *dev, pm_message_t state) | ||
608 | { | ||
609 | pr_debug("Entered %s\n", __func__); | ||
610 | |||
611 | dev_dbg(&dev->dev, "lm4857_suspend\n"); | ||
612 | lm4857_state = lm4857_regs[LM4857_CTRL] & 0xf; | ||
613 | if (lm4857_state) { | ||
614 | lm4857_regs[LM4857_CTRL] &= 0xf0; | ||
615 | lm4857_write_regs(); | ||
616 | } | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | static int lm4857_resume(struct i2c_client *dev) | ||
621 | { | ||
622 | pr_debug("Entered %s\n", __func__); | ||
623 | |||
624 | if (lm4857_state) { | ||
625 | lm4857_regs[LM4857_CTRL] |= (lm4857_state & 0x0f); | ||
626 | lm4857_write_regs(); | ||
627 | } | ||
628 | return 0; | ||
629 | } | ||
630 | |||
631 | static void lm4857_shutdown(struct i2c_client *dev) | ||
632 | { | ||
633 | pr_debug("Entered %s\n", __func__); | ||
634 | |||
635 | dev_dbg(&dev->dev, "lm4857_shutdown\n"); | ||
636 | lm4857_regs[LM4857_CTRL] &= 0xf0; | ||
637 | lm4857_write_regs(); | ||
638 | } | ||
639 | 461 | ||
640 | static const struct i2c_device_id lm4857_i2c_id[] = { | 462 | #ifdef CONFIG_MACH_NEO1973_GTA02 |
641 | { "neo1973_lm4857", 0 }, | 463 | static const struct gpio neo1973_gta02_gpios[] = { |
642 | { } | 464 | { GTA02_GPIO_HP_IN, GPIOF_OUT_INIT_HIGH, "GTA02_HP_IN" }, |
465 | { GTA02_GPIO_AMP_SHUT, GPIOF_OUT_INIT_HIGH, "GTA02_AMP_SHUT" }, | ||
643 | }; | 466 | }; |
467 | #else | ||
468 | static const struct gpio neo1973_gta02_gpios[] = {}; | ||
469 | #endif | ||
644 | 470 | ||
645 | static struct i2c_driver lm4857_i2c_driver = { | 471 | static struct snd_soc_card neo1973 = { |
646 | .driver = { | 472 | .name = "neo1973", |
647 | .name = "LM4857 I2C Amp", | 473 | .dai_link = neo1973_dai, |
648 | .owner = THIS_MODULE, | 474 | .num_links = ARRAY_SIZE(neo1973_dai), |
649 | }, | 475 | .aux_dev = neo1973_aux_devs, |
650 | .suspend = lm4857_suspend, | 476 | .num_aux_devs = ARRAY_SIZE(neo1973_aux_devs), |
651 | .resume = lm4857_resume, | 477 | .codec_conf = neo1973_codec_conf, |
652 | .shutdown = lm4857_shutdown, | 478 | .num_configs = ARRAY_SIZE(neo1973_codec_conf), |
653 | .probe = lm4857_i2c_probe, | ||
654 | .remove = lm4857_i2c_remove, | ||
655 | .id_table = lm4857_i2c_id, | ||
656 | }; | 479 | }; |
657 | 480 | ||
658 | static struct platform_device *neo1973_snd_device; | 481 | static struct platform_device *neo1973_snd_device; |
@@ -661,46 +484,56 @@ static int __init neo1973_init(void) | |||
661 | { | 484 | { |
662 | int ret; | 485 | int ret; |
663 | 486 | ||
664 | pr_debug("Entered %s\n", __func__); | 487 | if (!machine_is_neo1973_gta01() && !machine_is_neo1973_gta02()) |
665 | |||
666 | if (!machine_is_neo1973_gta01()) { | ||
667 | printk(KERN_INFO | ||
668 | "Only GTA01 hardware supported by ASoC driver\n"); | ||
669 | return -ENODEV; | 488 | return -ENODEV; |
489 | |||
490 | if (machine_is_neo1973_gta02()) { | ||
491 | neo1973.name = "neo1973gta02"; | ||
492 | neo1973.num_aux_devs = 1; | ||
493 | |||
494 | ret = gpio_request_array(neo1973_gta02_gpios, | ||
495 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
496 | if (ret) | ||
497 | return ret; | ||
670 | } | 498 | } |
671 | 499 | ||
672 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); | 500 | neo1973_snd_device = platform_device_alloc("soc-audio", -1); |
673 | if (!neo1973_snd_device) | 501 | if (!neo1973_snd_device) { |
674 | return -ENOMEM; | 502 | ret = -ENOMEM; |
503 | goto err_gpio_free; | ||
504 | } | ||
675 | 505 | ||
676 | platform_set_drvdata(neo1973_snd_device, &neo1973); | 506 | platform_set_drvdata(neo1973_snd_device, &neo1973); |
677 | ret = platform_device_add(neo1973_snd_device); | 507 | ret = platform_device_add(neo1973_snd_device); |
678 | 508 | ||
679 | if (ret) { | 509 | if (ret) |
680 | platform_device_put(neo1973_snd_device); | 510 | goto err_put_device; |
681 | return ret; | ||
682 | } | ||
683 | |||
684 | ret = i2c_add_driver(&lm4857_i2c_driver); | ||
685 | 511 | ||
686 | if (ret != 0) | 512 | return 0; |
687 | platform_device_unregister(neo1973_snd_device); | ||
688 | 513 | ||
514 | err_put_device: | ||
515 | platform_device_put(neo1973_snd_device); | ||
516 | err_gpio_free: | ||
517 | if (machine_is_neo1973_gta02()) { | ||
518 | gpio_free_array(neo1973_gta02_gpios, | ||
519 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
520 | } | ||
689 | return ret; | 521 | return ret; |
690 | } | 522 | } |
523 | module_init(neo1973_init); | ||
691 | 524 | ||
692 | static void __exit neo1973_exit(void) | 525 | static void __exit neo1973_exit(void) |
693 | { | 526 | { |
694 | pr_debug("Entered %s\n", __func__); | ||
695 | |||
696 | i2c_del_driver(&lm4857_i2c_driver); | ||
697 | platform_device_unregister(neo1973_snd_device); | 527 | platform_device_unregister(neo1973_snd_device); |
698 | } | ||
699 | 528 | ||
700 | module_init(neo1973_init); | 529 | if (machine_is_neo1973_gta02()) { |
530 | gpio_free_array(neo1973_gta02_gpios, | ||
531 | ARRAY_SIZE(neo1973_gta02_gpios)); | ||
532 | } | ||
533 | } | ||
701 | module_exit(neo1973_exit); | 534 | module_exit(neo1973_exit); |
702 | 535 | ||
703 | /* Module information */ | 536 | /* Module information */ |
704 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); | 537 | MODULE_AUTHOR("Graeme Gregory, graeme@openmoko.org, www.openmoko.org"); |
705 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973"); | 538 | MODULE_DESCRIPTION("ALSA SoC WM8753 Neo1973 and Frerunner"); |
706 | MODULE_LICENSE("GPL"); | 539 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/samsung/pcm.c b/sound/soc/samsung/pcm.c index 48d0b750406b..38aac7d57a59 100644 --- a/sound/soc/samsung/pcm.c +++ b/sound/soc/samsung/pcm.c | |||
@@ -11,20 +11,11 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
19 | #include <linux/kernel.h> | ||
20 | #include <linux/gpio.h> | ||
21 | #include <linux/io.h> | 15 | #include <linux/io.h> |
22 | 16 | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
18 | #include <sound/pcm_params.h> | ||
28 | 19 | ||
29 | #include <plat/audio.h> | 20 | #include <plat/audio.h> |
30 | #include <plat/dma.h> | 21 | #include <plat/dma.h> |
@@ -32,6 +23,113 @@ | |||
32 | #include "dma.h" | 23 | #include "dma.h" |
33 | #include "pcm.h" | 24 | #include "pcm.h" |
34 | 25 | ||
26 | /*Register Offsets */ | ||
27 | #define S3C_PCM_CTL 0x00 | ||
28 | #define S3C_PCM_CLKCTL 0x04 | ||
29 | #define S3C_PCM_TXFIFO 0x08 | ||
30 | #define S3C_PCM_RXFIFO 0x0C | ||
31 | #define S3C_PCM_IRQCTL 0x10 | ||
32 | #define S3C_PCM_IRQSTAT 0x14 | ||
33 | #define S3C_PCM_FIFOSTAT 0x18 | ||
34 | #define S3C_PCM_CLRINT 0x20 | ||
35 | |||
36 | /* PCM_CTL Bit-Fields */ | ||
37 | #define S3C_PCM_CTL_TXDIPSTICK_MASK 0x3f | ||
38 | #define S3C_PCM_CTL_TXDIPSTICK_SHIFT 13 | ||
39 | #define S3C_PCM_CTL_RXDIPSTICK_MASK 0x3f | ||
40 | #define S3C_PCM_CTL_RXDIPSTICK_SHIFT 7 | ||
41 | #define S3C_PCM_CTL_TXDMA_EN (0x1 << 6) | ||
42 | #define S3C_PCM_CTL_RXDMA_EN (0x1 << 5) | ||
43 | #define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1 << 4) | ||
44 | #define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1 << 3) | ||
45 | #define S3C_PCM_CTL_TXFIFO_EN (0x1 << 2) | ||
46 | #define S3C_PCM_CTL_RXFIFO_EN (0x1 << 1) | ||
47 | #define S3C_PCM_CTL_ENABLE (0x1 << 0) | ||
48 | |||
49 | /* PCM_CLKCTL Bit-Fields */ | ||
50 | #define S3C_PCM_CLKCTL_SERCLK_EN (0x1 << 19) | ||
51 | #define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1 << 18) | ||
52 | #define S3C_PCM_CLKCTL_SCLKDIV_MASK 0x1ff | ||
53 | #define S3C_PCM_CLKCTL_SYNCDIV_MASK 0x1ff | ||
54 | #define S3C_PCM_CLKCTL_SCLKDIV_SHIFT 9 | ||
55 | #define S3C_PCM_CLKCTL_SYNCDIV_SHIFT 0 | ||
56 | |||
57 | /* PCM_TXFIFO Bit-Fields */ | ||
58 | #define S3C_PCM_TXFIFO_DVALID (0x1 << 16) | ||
59 | #define S3C_PCM_TXFIFO_DATA_MSK (0xffff << 0) | ||
60 | |||
61 | /* PCM_RXFIFO Bit-Fields */ | ||
62 | #define S3C_PCM_RXFIFO_DVALID (0x1 << 16) | ||
63 | #define S3C_PCM_RXFIFO_DATA_MSK (0xffff << 0) | ||
64 | |||
65 | /* PCM_IRQCTL Bit-Fields */ | ||
66 | #define S3C_PCM_IRQCTL_IRQEN (0x1 << 14) | ||
67 | #define S3C_PCM_IRQCTL_WRDEN (0x1 << 12) | ||
68 | #define S3C_PCM_IRQCTL_TXEMPTYEN (0x1 << 11) | ||
69 | #define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1 << 10) | ||
70 | #define S3C_PCM_IRQCTL_TXFULLEN (0x1 << 9) | ||
71 | #define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1 << 8) | ||
72 | #define S3C_PCM_IRQCTL_TXSTARVEN (0x1 << 7) | ||
73 | #define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1 << 6) | ||
74 | #define S3C_PCM_IRQCTL_RXEMPTEN (0x1 << 5) | ||
75 | #define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1 << 4) | ||
76 | #define S3C_PCM_IRQCTL_RXFULLEN (0x1 << 3) | ||
77 | #define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1 << 2) | ||
78 | #define S3C_PCM_IRQCTL_RXSTARVEN (0x1 << 1) | ||
79 | #define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1 << 0) | ||
80 | |||
81 | /* PCM_IRQSTAT Bit-Fields */ | ||
82 | #define S3C_PCM_IRQSTAT_IRQPND (0x1 << 13) | ||
83 | #define S3C_PCM_IRQSTAT_WRD_XFER (0x1 << 12) | ||
84 | #define S3C_PCM_IRQSTAT_TXEMPTY (0x1 << 11) | ||
85 | #define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1 << 10) | ||
86 | #define S3C_PCM_IRQSTAT_TXFULL (0x1 << 9) | ||
87 | #define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1 << 8) | ||
88 | #define S3C_PCM_IRQSTAT_TXSTARV (0x1 << 7) | ||
89 | #define S3C_PCM_IRQSTAT_TXERROVRFL (0x1 << 6) | ||
90 | #define S3C_PCM_IRQSTAT_RXEMPT (0x1 << 5) | ||
91 | #define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1 << 4) | ||
92 | #define S3C_PCM_IRQSTAT_RXFULL (0x1 << 3) | ||
93 | #define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1 << 2) | ||
94 | #define S3C_PCM_IRQSTAT_RXSTARV (0x1 << 1) | ||
95 | #define S3C_PCM_IRQSTAT_RXERROVRFL (0x1 << 0) | ||
96 | |||
97 | /* PCM_FIFOSTAT Bit-Fields */ | ||
98 | #define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f << 14) | ||
99 | #define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1 << 13) | ||
100 | #define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1 << 12) | ||
101 | #define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1 << 11) | ||
102 | #define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1 << 10) | ||
103 | #define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f << 4) | ||
104 | #define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1 << 3) | ||
105 | #define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1 << 2) | ||
106 | #define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1 << 1) | ||
107 | #define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1 << 0) | ||
108 | |||
109 | /** | ||
110 | * struct s3c_pcm_info - S3C PCM Controller information | ||
111 | * @dev: The parent device passed to use from the probe. | ||
112 | * @regs: The pointer to the device register block. | ||
113 | * @dma_playback: DMA information for playback channel. | ||
114 | * @dma_capture: DMA information for capture channel. | ||
115 | */ | ||
116 | struct s3c_pcm_info { | ||
117 | spinlock_t lock; | ||
118 | struct device *dev; | ||
119 | void __iomem *regs; | ||
120 | |||
121 | unsigned int sclk_per_fs; | ||
122 | |||
123 | /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */ | ||
124 | unsigned int idleclk; | ||
125 | |||
126 | struct clk *pclk; | ||
127 | struct clk *cclk; | ||
128 | |||
129 | struct s3c_dma_params *dma_playback; | ||
130 | struct s3c_dma_params *dma_capture; | ||
131 | }; | ||
132 | |||
35 | static struct s3c2410_dma_client s3c_pcm_dma_client_out = { | 133 | static struct s3c2410_dma_client s3c_pcm_dma_client_out = { |
36 | .name = "PCM Stereo out" | 134 | .name = "PCM Stereo out" |
37 | }; | 135 | }; |
diff --git a/sound/soc/samsung/pcm.h b/sound/soc/samsung/pcm.h index 03393dcf852d..726baf814613 100644 --- a/sound/soc/samsung/pcm.h +++ b/sound/soc/samsung/pcm.h | |||
@@ -9,116 +9,9 @@ | |||
9 | #ifndef __S3C_PCM_H | 9 | #ifndef __S3C_PCM_H |
10 | #define __S3C_PCM_H __FILE__ | 10 | #define __S3C_PCM_H __FILE__ |
11 | 11 | ||
12 | /*Register Offsets */ | ||
13 | #define S3C_PCM_CTL (0x00) | ||
14 | #define S3C_PCM_CLKCTL (0x04) | ||
15 | #define S3C_PCM_TXFIFO (0x08) | ||
16 | #define S3C_PCM_RXFIFO (0x0C) | ||
17 | #define S3C_PCM_IRQCTL (0x10) | ||
18 | #define S3C_PCM_IRQSTAT (0x14) | ||
19 | #define S3C_PCM_FIFOSTAT (0x18) | ||
20 | #define S3C_PCM_CLRINT (0x20) | ||
21 | |||
22 | /* PCM_CTL Bit-Fields */ | ||
23 | #define S3C_PCM_CTL_TXDIPSTICK_MASK (0x3f) | ||
24 | #define S3C_PCM_CTL_TXDIPSTICK_SHIFT (13) | ||
25 | #define S3C_PCM_CTL_RXDIPSTICK_MASK (0x3f) | ||
26 | #define S3C_PCM_CTL_RXDIPSTICK_SHIFT (7) | ||
27 | #define S3C_PCM_CTL_TXDMA_EN (0x1<<6) | ||
28 | #define S3C_PCM_CTL_RXDMA_EN (0x1<<5) | ||
29 | #define S3C_PCM_CTL_TXMSB_AFTER_FSYNC (0x1<<4) | ||
30 | #define S3C_PCM_CTL_RXMSB_AFTER_FSYNC (0x1<<3) | ||
31 | #define S3C_PCM_CTL_TXFIFO_EN (0x1<<2) | ||
32 | #define S3C_PCM_CTL_RXFIFO_EN (0x1<<1) | ||
33 | #define S3C_PCM_CTL_ENABLE (0x1<<0) | ||
34 | |||
35 | /* PCM_CLKCTL Bit-Fields */ | ||
36 | #define S3C_PCM_CLKCTL_SERCLK_EN (0x1<<19) | ||
37 | #define S3C_PCM_CLKCTL_SERCLKSEL_PCLK (0x1<<18) | ||
38 | #define S3C_PCM_CLKCTL_SCLKDIV_MASK (0x1ff) | ||
39 | #define S3C_PCM_CLKCTL_SYNCDIV_MASK (0x1ff) | ||
40 | #define S3C_PCM_CLKCTL_SCLKDIV_SHIFT (9) | ||
41 | #define S3C_PCM_CLKCTL_SYNCDIV_SHIFT (0) | ||
42 | |||
43 | /* PCM_TXFIFO Bit-Fields */ | ||
44 | #define S3C_PCM_TXFIFO_DVALID (0x1<<16) | ||
45 | #define S3C_PCM_TXFIFO_DATA_MSK (0xffff<<0) | ||
46 | |||
47 | /* PCM_RXFIFO Bit-Fields */ | ||
48 | #define S3C_PCM_RXFIFO_DVALID (0x1<<16) | ||
49 | #define S3C_PCM_RXFIFO_DATA_MSK (0xffff<<0) | ||
50 | |||
51 | /* PCM_IRQCTL Bit-Fields */ | ||
52 | #define S3C_PCM_IRQCTL_IRQEN (0x1<<14) | ||
53 | #define S3C_PCM_IRQCTL_WRDEN (0x1<<12) | ||
54 | #define S3C_PCM_IRQCTL_TXEMPTYEN (0x1<<11) | ||
55 | #define S3C_PCM_IRQCTL_TXALMSTEMPTYEN (0x1<<10) | ||
56 | #define S3C_PCM_IRQCTL_TXFULLEN (0x1<<9) | ||
57 | #define S3C_PCM_IRQCTL_TXALMSTFULLEN (0x1<<8) | ||
58 | #define S3C_PCM_IRQCTL_TXSTARVEN (0x1<<7) | ||
59 | #define S3C_PCM_IRQCTL_TXERROVRFLEN (0x1<<6) | ||
60 | #define S3C_PCM_IRQCTL_RXEMPTEN (0x1<<5) | ||
61 | #define S3C_PCM_IRQCTL_RXALMSTEMPTEN (0x1<<4) | ||
62 | #define S3C_PCM_IRQCTL_RXFULLEN (0x1<<3) | ||
63 | #define S3C_PCM_IRQCTL_RXALMSTFULLEN (0x1<<2) | ||
64 | #define S3C_PCM_IRQCTL_RXSTARVEN (0x1<<1) | ||
65 | #define S3C_PCM_IRQCTL_RXERROVRFLEN (0x1<<0) | ||
66 | |||
67 | /* PCM_IRQSTAT Bit-Fields */ | ||
68 | #define S3C_PCM_IRQSTAT_IRQPND (0x1<<13) | ||
69 | #define S3C_PCM_IRQSTAT_WRD_XFER (0x1<<12) | ||
70 | #define S3C_PCM_IRQSTAT_TXEMPTY (0x1<<11) | ||
71 | #define S3C_PCM_IRQSTAT_TXALMSTEMPTY (0x1<<10) | ||
72 | #define S3C_PCM_IRQSTAT_TXFULL (0x1<<9) | ||
73 | #define S3C_PCM_IRQSTAT_TXALMSTFULL (0x1<<8) | ||
74 | #define S3C_PCM_IRQSTAT_TXSTARV (0x1<<7) | ||
75 | #define S3C_PCM_IRQSTAT_TXERROVRFL (0x1<<6) | ||
76 | #define S3C_PCM_IRQSTAT_RXEMPT (0x1<<5) | ||
77 | #define S3C_PCM_IRQSTAT_RXALMSTEMPT (0x1<<4) | ||
78 | #define S3C_PCM_IRQSTAT_RXFULL (0x1<<3) | ||
79 | #define S3C_PCM_IRQSTAT_RXALMSTFULL (0x1<<2) | ||
80 | #define S3C_PCM_IRQSTAT_RXSTARV (0x1<<1) | ||
81 | #define S3C_PCM_IRQSTAT_RXERROVRFL (0x1<<0) | ||
82 | |||
83 | /* PCM_FIFOSTAT Bit-Fields */ | ||
84 | #define S3C_PCM_FIFOSTAT_TXCNT_MSK (0x3f<<14) | ||
85 | #define S3C_PCM_FIFOSTAT_TXFIFOEMPTY (0x1<<13) | ||
86 | #define S3C_PCM_FIFOSTAT_TXFIFOALMSTEMPTY (0x1<<12) | ||
87 | #define S3C_PCM_FIFOSTAT_TXFIFOFULL (0x1<<11) | ||
88 | #define S3C_PCM_FIFOSTAT_TXFIFOALMSTFULL (0x1<<10) | ||
89 | #define S3C_PCM_FIFOSTAT_RXCNT_MSK (0x3f<<4) | ||
90 | #define S3C_PCM_FIFOSTAT_RXFIFOEMPTY (0x1<<3) | ||
91 | #define S3C_PCM_FIFOSTAT_RXFIFOALMSTEMPTY (0x1<<2) | ||
92 | #define S3C_PCM_FIFOSTAT_RXFIFOFULL (0x1<<1) | ||
93 | #define S3C_PCM_FIFOSTAT_RXFIFOALMSTFULL (0x1<<0) | ||
94 | |||
95 | #define S3C_PCM_CLKSRC_PCLK 0 | 12 | #define S3C_PCM_CLKSRC_PCLK 0 |
96 | #define S3C_PCM_CLKSRC_MUX 1 | 13 | #define S3C_PCM_CLKSRC_MUX 1 |
97 | 14 | ||
98 | #define S3C_PCM_SCLK_PER_FS 0 | 15 | #define S3C_PCM_SCLK_PER_FS 0 |
99 | 16 | ||
100 | /** | ||
101 | * struct s3c_pcm_info - S3C PCM Controller information | ||
102 | * @dev: The parent device passed to use from the probe. | ||
103 | * @regs: The pointer to the device register block. | ||
104 | * @dma_playback: DMA information for playback channel. | ||
105 | * @dma_capture: DMA information for capture channel. | ||
106 | */ | ||
107 | struct s3c_pcm_info { | ||
108 | spinlock_t lock; | ||
109 | struct device *dev; | ||
110 | void __iomem *regs; | ||
111 | |||
112 | unsigned int sclk_per_fs; | ||
113 | |||
114 | /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */ | ||
115 | unsigned int idleclk; | ||
116 | |||
117 | struct clk *pclk; | ||
118 | struct clk *cclk; | ||
119 | |||
120 | struct s3c_dma_params *dma_playback; | ||
121 | struct s3c_dma_params *dma_capture; | ||
122 | }; | ||
123 | |||
124 | #endif /* __S3C_PCM_H */ | 17 | #endif /* __S3C_PCM_H */ |
diff --git a/sound/soc/samsung/rx1950_uda1380.c b/sound/soc/samsung/rx1950_uda1380.c index f40027445dda..1e574a5d440d 100644 --- a/sound/soc/samsung/rx1950_uda1380.c +++ b/sound/soc/samsung/rx1950_uda1380.c | |||
@@ -17,26 +17,15 @@ | |||
17 | * | 17 | * |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/moduleparam.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
25 | #include <linux/clk.h> | ||
26 | 21 | ||
27 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
28 | #include <sound/uda1380.h> | ||
29 | #include <sound/jack.h> | 23 | #include <sound/jack.h> |
30 | 24 | ||
31 | #include <plat/regs-iis.h> | 25 | #include <plat/regs-iis.h> |
32 | |||
33 | #include <mach/regs-clock.h> | ||
34 | |||
35 | #include <asm/mach-types.h> | 26 | #include <asm/mach-types.h> |
36 | 27 | ||
37 | #include "dma.h" | ||
38 | #include "s3c24xx-i2s.h" | 28 | #include "s3c24xx-i2s.h" |
39 | #include "../codecs/uda1380.h" | ||
40 | 29 | ||
41 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); | 30 | static int rx1950_uda1380_init(struct snd_soc_pcm_runtime *rtd); |
42 | static int rx1950_startup(struct snd_pcm_substream *substream); | 31 | static int rx1950_startup(struct snd_pcm_substream *substream); |
diff --git a/sound/soc/samsung/s3c-i2s-v2.c b/sound/soc/samsung/s3c-i2s-v2.c index 094f36e41e83..52074a2b0696 100644 --- a/sound/soc/samsung/s3c-i2s-v2.c +++ b/sound/soc/samsung/s3c-i2s-v2.c | |||
@@ -20,9 +20,8 @@ | |||
20 | #include <linux/clk.h> | 20 | #include <linux/clk.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | 22 | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pcm_params.h> | ||
26 | 25 | ||
27 | #include <mach/dma.h> | 26 | #include <mach/dma.h> |
28 | 27 | ||
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 7ea837867124..841ab14c1100 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c | |||
@@ -16,21 +16,13 @@ | |||
16 | * option) any later version. | 16 | * option) any later version. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | #include <linux/init.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
23 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
24 | #include <linux/clk.h> | 21 | #include <linux/clk.h> |
25 | #include <linux/kernel.h> | ||
26 | #include <linux/io.h> | 22 | #include <linux/io.h> |
27 | 23 | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
33 | #include <mach/hardware.h> | 25 | #include <sound/pcm_params.h> |
34 | 26 | ||
35 | #include <mach/regs-gpio.h> | 27 | #include <mach/regs-gpio.h> |
36 | #include <mach/dma.h> | 28 | #include <mach/dma.h> |
@@ -39,8 +31,6 @@ | |||
39 | #include "regs-i2s-v2.h" | 31 | #include "regs-i2s-v2.h" |
40 | #include "s3c2412-i2s.h" | 32 | #include "s3c2412-i2s.h" |
41 | 33 | ||
42 | #define S3C2412_I2S_DEBUG 0 | ||
43 | |||
44 | static struct s3c2410_dma_client s3c2412_dma_client_out = { | 34 | static struct s3c2410_dma_client s3c2412_dma_client_out = { |
45 | .name = "I2S PCM Stereo out" | 35 | .name = "I2S PCM Stereo out" |
46 | }; | 36 | }; |
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index 13e41ed8e22b..63d8849d80bd 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c | |||
@@ -14,28 +14,16 @@ | |||
14 | * option) any later version. | 14 | * option) any later version. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
21 | #include <linux/clk.h> | 18 | #include <linux/clk.h> |
22 | #include <linux/jiffies.h> | ||
23 | #include <linux/io.h> | 19 | #include <linux/io.h> |
24 | #include <linux/gpio.h> | 20 | #include <linux/gpio.h> |
25 | 21 | ||
26 | #include <sound/core.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include <sound/initval.h> | ||
30 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
23 | #include <sound/pcm_params.h> | ||
31 | 24 | ||
32 | #include <mach/hardware.h> | ||
33 | #include <mach/regs-gpio.h> | 25 | #include <mach/regs-gpio.h> |
34 | #include <mach/regs-clock.h> | ||
35 | |||
36 | #include <asm/dma.h> | ||
37 | #include <mach/dma.h> | 26 | #include <mach/dma.h> |
38 | |||
39 | #include <plat/regs-iis.h> | 27 | #include <plat/regs-iis.h> |
40 | 28 | ||
41 | #include "dma.h" | 29 | #include "dma.h" |
diff --git a/sound/soc/samsung/s3c24xx_simtec.c b/sound/soc/samsung/s3c24xx_simtec.c index a434032d1832..349566f0686b 100644 --- a/sound/soc/samsung/s3c24xx_simtec.c +++ b/sound/soc/samsung/s3c24xx_simtec.c | |||
@@ -7,20 +7,13 @@ | |||
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/gpio.h> | 10 | #include <linux/gpio.h> |
14 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
15 | #include <linux/i2c.h> | ||
16 | 12 | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | 13 | #include <sound/soc.h> |
20 | 14 | ||
21 | #include <plat/audio-simtec.h> | 15 | #include <plat/audio-simtec.h> |
22 | 16 | ||
23 | #include "dma.h" | ||
24 | #include "s3c24xx-i2s.h" | 17 | #include "s3c24xx-i2s.h" |
25 | #include "s3c24xx_simtec.h" | 18 | #include "s3c24xx_simtec.h" |
26 | 19 | ||
diff --git a/sound/soc/samsung/s3c24xx_simtec_hermes.c b/sound/soc/samsung/s3c24xx_simtec_hermes.c index 08fcaaa66907..ce6aef604179 100644 --- a/sound/soc/samsung/s3c24xx_simtec_hermes.c +++ b/sound/soc/samsung/s3c24xx_simtec_hermes.c | |||
@@ -7,18 +7,8 @@ | |||
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | 10 | #include <sound/soc.h> |
17 | 11 | ||
18 | #include <plat/audio-simtec.h> | ||
19 | |||
20 | #include "dma.h" | ||
21 | #include "s3c24xx-i2s.h" | ||
22 | #include "s3c24xx_simtec.h" | 12 | #include "s3c24xx_simtec.h" |
23 | 13 | ||
24 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | 14 | static const struct snd_soc_dapm_widget dapm_widgets[] = { |
diff --git a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c index 116e3e670167..a7ef7db54687 100644 --- a/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c +++ b/sound/soc/samsung/s3c24xx_simtec_tlv320aic23.c | |||
@@ -7,22 +7,10 @@ | |||
7 | * published by the Free Software Foundation. | 7 | * published by the Free Software Foundation. |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | 10 | #include <sound/soc.h> |
17 | 11 | ||
18 | #include <plat/audio-simtec.h> | ||
19 | |||
20 | #include "dma.h" | ||
21 | #include "s3c24xx-i2s.h" | ||
22 | #include "s3c24xx_simtec.h" | 12 | #include "s3c24xx_simtec.h" |
23 | 13 | ||
24 | #include "../codecs/tlv320aic23.h" | ||
25 | |||
26 | /* supported machines: | 14 | /* supported machines: |
27 | * | 15 | * |
28 | * Machine Connections AMP | 16 | * Machine Connections AMP |
diff --git a/sound/soc/samsung/s3c24xx_uda134x.c b/sound/soc/samsung/s3c24xx_uda134x.c index 2c09e93dd566..3cb700751078 100644 --- a/sound/soc/samsung/s3c24xx_uda134x.c +++ b/sound/soc/samsung/s3c24xx_uda134x.c | |||
@@ -11,22 +11,15 @@ | |||
11 | * published by the Free Software Foundation. | 11 | * published by the Free Software Foundation. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/clk.h> | 14 | #include <linux/clk.h> |
16 | #include <linux/mutex.h> | ||
17 | #include <linux/gpio.h> | 15 | #include <linux/gpio.h> |
18 | #include <sound/pcm.h> | 16 | |
19 | #include <sound/pcm_params.h> | ||
20 | #include <sound/soc.h> | 17 | #include <sound/soc.h> |
21 | #include <sound/s3c24xx_uda134x.h> | 18 | #include <sound/s3c24xx_uda134x.h> |
22 | #include <sound/uda134x.h> | ||
23 | 19 | ||
24 | #include <plat/regs-iis.h> | 20 | #include <plat/regs-iis.h> |
25 | 21 | ||
26 | #include "dma.h" | ||
27 | #include "s3c24xx-i2s.h" | 22 | #include "s3c24xx-i2s.h" |
28 | #include "../codecs/uda134x.h" | ||
29 | |||
30 | 23 | ||
31 | /* #define ENFORCE_RATES 1 */ | 24 | /* #define ENFORCE_RATES 1 */ |
32 | /* | 25 | /* |
diff --git a/sound/soc/samsung/smartq_wm8987.c b/sound/soc/samsung/smartq_wm8987.c index 61e2b5219d42..0a2c4f223038 100644 --- a/sound/soc/samsung/smartq_wm8987.c +++ b/sound/soc/samsung/smartq_wm8987.c | |||
@@ -13,20 +13,14 @@ | |||
13 | * | 13 | * |
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/gpio.h> | 16 | #include <linux/gpio.h> |
19 | 17 | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/pcm_params.h> | ||
22 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
23 | #include <sound/jack.h> | 19 | #include <sound/jack.h> |
24 | 20 | ||
25 | #include <asm/mach-types.h> | 21 | #include <asm/mach-types.h> |
26 | 22 | ||
27 | #include "dma.h" | ||
28 | #include "i2s.h" | 23 | #include "i2s.h" |
29 | |||
30 | #include "../codecs/wm8750.h" | 24 | #include "../codecs/wm8750.h" |
31 | 25 | ||
32 | /* | 26 | /* |
diff --git a/sound/soc/samsung/smdk2443_wm9710.c b/sound/soc/samsung/smdk2443_wm9710.c index 3be7e7e92d6e..3a0dbfc793f0 100644 --- a/sound/soc/samsung/smdk2443_wm9710.c +++ b/sound/soc/samsung/smdk2443_wm9710.c | |||
@@ -12,15 +12,8 @@ | |||
12 | * | 12 | * |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | 15 | #include <sound/soc.h> |
20 | 16 | ||
21 | #include "dma.h" | ||
22 | #include "ac97.h" | ||
23 | |||
24 | static struct snd_soc_card smdk2443; | 17 | static struct snd_soc_card smdk2443; |
25 | 18 | ||
26 | static struct snd_soc_dai_link smdk2443_dai[] = { | 19 | static struct snd_soc_dai_link smdk2443_dai[] = { |
diff --git a/sound/soc/samsung/smdk_spdif.c b/sound/soc/samsung/smdk_spdif.c index b5c3fad01bb8..e8ac961c6ba1 100644 --- a/sound/soc/samsung/smdk_spdif.c +++ b/sound/soc/samsung/smdk_spdif.c | |||
@@ -10,15 +10,10 @@ | |||
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
16 | 14 | ||
17 | #include <plat/devs.h> | ||
18 | |||
19 | #include <sound/soc.h> | 15 | #include <sound/soc.h> |
20 | 16 | ||
21 | #include "dma.h" | ||
22 | #include "spdif.h" | 17 | #include "spdif.h" |
23 | 18 | ||
24 | /* Audio clock settings are belonged to board specific part. Every | 19 | /* Audio clock settings are belonged to board specific part. Every |
diff --git a/sound/soc/samsung/smdk_wm8580.c b/sound/soc/samsung/smdk_wm8580.c index b2cff1a44aed..8aacf23d6f3a 100644 --- a/sound/soc/samsung/smdk_wm8580.c +++ b/sound/soc/samsung/smdk_wm8580.c | |||
@@ -10,17 +10,12 @@ | |||
10 | * option) any later version. | 10 | * option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | 13 | #include <sound/soc.h> |
14 | #include <sound/pcm_params.h> | ||
19 | 15 | ||
20 | #include <asm/mach-types.h> | 16 | #include <asm/mach-types.h> |
21 | 17 | ||
22 | #include "../codecs/wm8580.h" | 18 | #include "../codecs/wm8580.h" |
23 | #include "dma.h" | ||
24 | #include "i2s.h" | 19 | #include "i2s.h" |
25 | 20 | ||
26 | /* | 21 | /* |
diff --git a/sound/soc/samsung/smdk_wm9713.c b/sound/soc/samsung/smdk_wm9713.c index ae5fed6f772f..fffe3c1dd1bd 100644 --- a/sound/soc/samsung/smdk_wm9713.c +++ b/sound/soc/samsung/smdk_wm9713.c | |||
@@ -11,13 +11,8 @@ | |||
11 | * | 11 | * |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <sound/soc.h> | 14 | #include <sound/soc.h> |
17 | 15 | ||
18 | #include "dma.h" | ||
19 | #include "ac97.h" | ||
20 | |||
21 | static struct snd_soc_card smdk; | 16 | static struct snd_soc_card smdk; |
22 | 17 | ||
23 | /* | 18 | /* |
diff --git a/sound/soc/samsung/spdif.c b/sound/soc/samsung/spdif.c index f0816404ea3e..28c491dacf7a 100644 --- a/sound/soc/samsung/spdif.c +++ b/sound/soc/samsung/spdif.c | |||
@@ -13,9 +13,8 @@ | |||
13 | #include <linux/clk.h> | 13 | #include <linux/clk.h> |
14 | #include <linux/io.h> | 14 | #include <linux/io.h> |
15 | 15 | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | #include <sound/pcm_params.h> | ||
19 | 18 | ||
20 | #include <plat/audio.h> | 19 | #include <plat/audio.h> |
21 | #include <mach/dma.h> | 20 | #include <mach/dma.h> |
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c index a14820ac9665..d6f4703b3c07 100644 --- a/sound/soc/sh/fsi-ak4642.c +++ b/sound/soc/sh/fsi-ak4642.c | |||
@@ -18,18 +18,26 @@ struct fsi_ak4642_data { | |||
18 | const char *cpu_dai; | 18 | const char *cpu_dai; |
19 | const char *codec; | 19 | const char *codec; |
20 | const char *platform; | 20 | const char *platform; |
21 | int id; | ||
21 | }; | 22 | }; |
22 | 23 | ||
23 | static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd) | 24 | static int fsi_ak4642_dai_init(struct snd_soc_pcm_runtime *rtd) |
24 | { | 25 | { |
25 | struct snd_soc_dai *dai = rtd->codec_dai; | 26 | struct snd_soc_dai *codec = rtd->codec_dai; |
27 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
26 | int ret; | 28 | int ret; |
27 | 29 | ||
28 | ret = snd_soc_dai_set_fmt(dai, SND_SOC_DAIFMT_CBM_CFM); | 30 | ret = snd_soc_dai_set_fmt(codec, SND_SOC_DAIFMT_LEFT_J | |
31 | SND_SOC_DAIFMT_CBM_CFM); | ||
29 | if (ret < 0) | 32 | if (ret < 0) |
30 | return ret; | 33 | return ret; |
31 | 34 | ||
32 | ret = snd_soc_dai_set_sysclk(dai, 0, 11289600, 0); | 35 | ret = snd_soc_dai_set_sysclk(codec, 0, 11289600, 0); |
36 | if (ret < 0) | ||
37 | return ret; | ||
38 | |||
39 | ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_LEFT_J | | ||
40 | SND_SOC_DAIFMT_CBS_CFS); | ||
33 | 41 | ||
34 | return ret; | 42 | return ret; |
35 | } | 43 | } |
@@ -60,7 +68,7 @@ static int fsi_ak4642_probe(struct platform_device *pdev) | |||
60 | 68 | ||
61 | pdata = (struct fsi_ak4642_data *)id_entry->driver_data; | 69 | pdata = (struct fsi_ak4642_data *)id_entry->driver_data; |
62 | 70 | ||
63 | fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_A); | 71 | fsi_snd_device = platform_device_alloc("soc-audio", pdata->id); |
64 | if (!fsi_snd_device) | 72 | if (!fsi_snd_device) |
65 | goto out; | 73 | goto out; |
66 | 74 | ||
@@ -93,6 +101,7 @@ static struct fsi_ak4642_data fsi_a_ak4642 = { | |||
93 | .cpu_dai = "fsia-dai", | 101 | .cpu_dai = "fsia-dai", |
94 | .codec = "ak4642-codec.0-0012", | 102 | .codec = "ak4642-codec.0-0012", |
95 | .platform = "sh_fsi.0", | 103 | .platform = "sh_fsi.0", |
104 | .id = FSI_PORT_A, | ||
96 | }; | 105 | }; |
97 | 106 | ||
98 | static struct fsi_ak4642_data fsi_b_ak4642 = { | 107 | static struct fsi_ak4642_data fsi_b_ak4642 = { |
@@ -101,6 +110,7 @@ static struct fsi_ak4642_data fsi_b_ak4642 = { | |||
101 | .cpu_dai = "fsib-dai", | 110 | .cpu_dai = "fsib-dai", |
102 | .codec = "ak4642-codec.0-0012", | 111 | .codec = "ak4642-codec.0-0012", |
103 | .platform = "sh_fsi.0", | 112 | .platform = "sh_fsi.0", |
113 | .id = FSI_PORT_B, | ||
104 | }; | 114 | }; |
105 | 115 | ||
106 | static struct fsi_ak4642_data fsi_a_ak4643 = { | 116 | static struct fsi_ak4642_data fsi_a_ak4643 = { |
@@ -109,6 +119,7 @@ static struct fsi_ak4642_data fsi_a_ak4643 = { | |||
109 | .cpu_dai = "fsia-dai", | 119 | .cpu_dai = "fsia-dai", |
110 | .codec = "ak4642-codec.0-0013", | 120 | .codec = "ak4642-codec.0-0013", |
111 | .platform = "sh_fsi.0", | 121 | .platform = "sh_fsi.0", |
122 | .id = FSI_PORT_A, | ||
112 | }; | 123 | }; |
113 | 124 | ||
114 | static struct fsi_ak4642_data fsi_b_ak4643 = { | 125 | static struct fsi_ak4642_data fsi_b_ak4643 = { |
@@ -117,6 +128,7 @@ static struct fsi_ak4642_data fsi_b_ak4643 = { | |||
117 | .cpu_dai = "fsib-dai", | 128 | .cpu_dai = "fsib-dai", |
118 | .codec = "ak4642-codec.0-0013", | 129 | .codec = "ak4642-codec.0-0013", |
119 | .platform = "sh_fsi.0", | 130 | .platform = "sh_fsi.0", |
131 | .id = FSI_PORT_B, | ||
120 | }; | 132 | }; |
121 | 133 | ||
122 | static struct fsi_ak4642_data fsi2_a_ak4642 = { | 134 | static struct fsi_ak4642_data fsi2_a_ak4642 = { |
@@ -125,6 +137,7 @@ static struct fsi_ak4642_data fsi2_a_ak4642 = { | |||
125 | .cpu_dai = "fsia-dai", | 137 | .cpu_dai = "fsia-dai", |
126 | .codec = "ak4642-codec.0-0012", | 138 | .codec = "ak4642-codec.0-0012", |
127 | .platform = "sh_fsi2", | 139 | .platform = "sh_fsi2", |
140 | .id = FSI_PORT_A, | ||
128 | }; | 141 | }; |
129 | 142 | ||
130 | static struct fsi_ak4642_data fsi2_b_ak4642 = { | 143 | static struct fsi_ak4642_data fsi2_b_ak4642 = { |
@@ -133,6 +146,7 @@ static struct fsi_ak4642_data fsi2_b_ak4642 = { | |||
133 | .cpu_dai = "fsib-dai", | 146 | .cpu_dai = "fsib-dai", |
134 | .codec = "ak4642-codec.0-0012", | 147 | .codec = "ak4642-codec.0-0012", |
135 | .platform = "sh_fsi2", | 148 | .platform = "sh_fsi2", |
149 | .id = FSI_PORT_B, | ||
136 | }; | 150 | }; |
137 | 151 | ||
138 | static struct fsi_ak4642_data fsi2_a_ak4643 = { | 152 | static struct fsi_ak4642_data fsi2_a_ak4643 = { |
@@ -141,6 +155,7 @@ static struct fsi_ak4642_data fsi2_a_ak4643 = { | |||
141 | .cpu_dai = "fsia-dai", | 155 | .cpu_dai = "fsia-dai", |
142 | .codec = "ak4642-codec.0-0013", | 156 | .codec = "ak4642-codec.0-0013", |
143 | .platform = "sh_fsi2", | 157 | .platform = "sh_fsi2", |
158 | .id = FSI_PORT_A, | ||
144 | }; | 159 | }; |
145 | 160 | ||
146 | static struct fsi_ak4642_data fsi2_b_ak4643 = { | 161 | static struct fsi_ak4642_data fsi2_b_ak4643 = { |
@@ -149,6 +164,7 @@ static struct fsi_ak4642_data fsi2_b_ak4643 = { | |||
149 | .cpu_dai = "fsib-dai", | 164 | .cpu_dai = "fsib-dai", |
150 | .codec = "ak4642-codec.0-0013", | 165 | .codec = "ak4642-codec.0-0013", |
151 | .platform = "sh_fsi2", | 166 | .platform = "sh_fsi2", |
167 | .id = FSI_PORT_B, | ||
152 | }; | 168 | }; |
153 | 169 | ||
154 | static struct platform_device_id fsi_id_table[] = { | 170 | static struct platform_device_id fsi_id_table[] = { |
diff --git a/sound/soc/sh/fsi-da7210.c b/sound/soc/sh/fsi-da7210.c index e8df9da92f71..dbafd7ac5590 100644 --- a/sound/soc/sh/fsi-da7210.c +++ b/sound/soc/sh/fsi-da7210.c | |||
@@ -15,11 +15,20 @@ | |||
15 | 15 | ||
16 | static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd) | 16 | static int fsi_da7210_init(struct snd_soc_pcm_runtime *rtd) |
17 | { | 17 | { |
18 | struct snd_soc_dai *dai = rtd->codec_dai; | 18 | struct snd_soc_dai *codec = rtd->codec_dai; |
19 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
20 | int ret; | ||
19 | 21 | ||
20 | return snd_soc_dai_set_fmt(dai, | 22 | ret = snd_soc_dai_set_fmt(codec, |
21 | SND_SOC_DAIFMT_I2S | | 23 | SND_SOC_DAIFMT_I2S | |
22 | SND_SOC_DAIFMT_CBM_CFM); | 24 | SND_SOC_DAIFMT_CBM_CFM); |
25 | if (ret < 0) | ||
26 | return ret; | ||
27 | |||
28 | ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_I2S | | ||
29 | SND_SOC_DAIFMT_CBS_CFS); | ||
30 | |||
31 | return ret; | ||
23 | } | 32 | } |
24 | 33 | ||
25 | static struct snd_soc_dai_link fsi_da7210_dai = { | 34 | static struct snd_soc_dai_link fsi_da7210_dai = { |
diff --git a/sound/soc/sh/fsi-hdmi.c b/sound/soc/sh/fsi-hdmi.c index a52dd8ec71d3..9719985eb82d 100644 --- a/sound/soc/sh/fsi-hdmi.c +++ b/sound/soc/sh/fsi-hdmi.c | |||
@@ -12,31 +12,59 @@ | |||
12 | #include <linux/platform_device.h> | 12 | #include <linux/platform_device.h> |
13 | #include <sound/sh_fsi.h> | 13 | #include <sound/sh_fsi.h> |
14 | 14 | ||
15 | struct fsi_hdmi_data { | ||
16 | const char *cpu_dai; | ||
17 | const char *card; | ||
18 | int id; | ||
19 | }; | ||
20 | |||
21 | static int fsi_hdmi_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
22 | { | ||
23 | struct snd_soc_dai *cpu = rtd->cpu_dai; | ||
24 | int ret; | ||
25 | |||
26 | ret = snd_soc_dai_set_fmt(cpu, SND_SOC_DAIFMT_CBM_CFM); | ||
27 | |||
28 | return ret; | ||
29 | } | ||
30 | |||
15 | static struct snd_soc_dai_link fsi_dai_link = { | 31 | static struct snd_soc_dai_link fsi_dai_link = { |
16 | .name = "HDMI", | 32 | .name = "HDMI", |
17 | .stream_name = "HDMI", | 33 | .stream_name = "HDMI", |
18 | .cpu_dai_name = "fsib-dai", /* fsi B */ | ||
19 | .codec_dai_name = "sh_mobile_hdmi-hifi", | 34 | .codec_dai_name = "sh_mobile_hdmi-hifi", |
20 | .platform_name = "sh_fsi2", | 35 | .platform_name = "sh_fsi2", |
21 | .codec_name = "sh-mobile-hdmi", | 36 | .codec_name = "sh-mobile-hdmi", |
37 | .init = fsi_hdmi_dai_init, | ||
22 | }; | 38 | }; |
23 | 39 | ||
24 | static struct snd_soc_card fsi_soc_card = { | 40 | static struct snd_soc_card fsi_soc_card = { |
25 | .name = "FSI (SH MOBILE HDMI)", | ||
26 | .dai_link = &fsi_dai_link, | 41 | .dai_link = &fsi_dai_link, |
27 | .num_links = 1, | 42 | .num_links = 1, |
28 | }; | 43 | }; |
29 | 44 | ||
30 | static struct platform_device *fsi_snd_device; | 45 | static struct platform_device *fsi_snd_device; |
31 | 46 | ||
32 | static int __init fsi_hdmi_init(void) | 47 | static int fsi_hdmi_probe(struct platform_device *pdev) |
33 | { | 48 | { |
34 | int ret = -ENOMEM; | 49 | int ret = -ENOMEM; |
50 | const struct platform_device_id *id_entry; | ||
51 | struct fsi_hdmi_data *pdata; | ||
52 | |||
53 | id_entry = pdev->id_entry; | ||
54 | if (!id_entry) { | ||
55 | dev_err(&pdev->dev, "unknown fsi hdmi\n"); | ||
56 | return -ENODEV; | ||
57 | } | ||
35 | 58 | ||
36 | fsi_snd_device = platform_device_alloc("soc-audio", FSI_PORT_B); | 59 | pdata = (struct fsi_hdmi_data *)id_entry->driver_data; |
60 | |||
61 | fsi_snd_device = platform_device_alloc("soc-audio", pdata->id); | ||
37 | if (!fsi_snd_device) | 62 | if (!fsi_snd_device) |
38 | goto out; | 63 | goto out; |
39 | 64 | ||
65 | fsi_dai_link.cpu_dai_name = pdata->cpu_dai; | ||
66 | fsi_soc_card.name = pdata->card; | ||
67 | |||
40 | platform_set_drvdata(fsi_snd_device, &fsi_soc_card); | 68 | platform_set_drvdata(fsi_snd_device, &fsi_soc_card); |
41 | ret = platform_device_add(fsi_snd_device); | 69 | ret = platform_device_add(fsi_snd_device); |
42 | 70 | ||
@@ -47,9 +75,48 @@ out: | |||
47 | return ret; | 75 | return ret; |
48 | } | 76 | } |
49 | 77 | ||
50 | static void __exit fsi_hdmi_exit(void) | 78 | static int fsi_hdmi_remove(struct platform_device *pdev) |
51 | { | 79 | { |
52 | platform_device_unregister(fsi_snd_device); | 80 | platform_device_unregister(fsi_snd_device); |
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static struct fsi_hdmi_data fsi2_a_hdmi = { | ||
85 | .cpu_dai = "fsia-dai", | ||
86 | .card = "FSI2A (SH MOBILE HDMI)", | ||
87 | .id = FSI_PORT_A, | ||
88 | }; | ||
89 | |||
90 | static struct fsi_hdmi_data fsi2_b_hdmi = { | ||
91 | .cpu_dai = "fsib-dai", | ||
92 | .card = "FSI2B (SH MOBILE HDMI)", | ||
93 | .id = FSI_PORT_B, | ||
94 | }; | ||
95 | |||
96 | static struct platform_device_id fsi_id_table[] = { | ||
97 | /* FSI 2 */ | ||
98 | { "sh_fsi2_a_hdmi", (kernel_ulong_t)&fsi2_a_hdmi }, | ||
99 | { "sh_fsi2_b_hdmi", (kernel_ulong_t)&fsi2_b_hdmi }, | ||
100 | {}, | ||
101 | }; | ||
102 | |||
103 | static struct platform_driver fsi_hdmi = { | ||
104 | .driver = { | ||
105 | .name = "fsi-hdmi-audio", | ||
106 | }, | ||
107 | .probe = fsi_hdmi_probe, | ||
108 | .remove = fsi_hdmi_remove, | ||
109 | .id_table = fsi_id_table, | ||
110 | }; | ||
111 | |||
112 | static int __init fsi_hdmi_init(void) | ||
113 | { | ||
114 | return platform_driver_register(&fsi_hdmi); | ||
115 | } | ||
116 | |||
117 | static void __exit fsi_hdmi_exit(void) | ||
118 | { | ||
119 | platform_driver_unregister(&fsi_hdmi); | ||
53 | } | 120 | } |
54 | 121 | ||
55 | module_init(fsi_hdmi_init); | 122 | module_init(fsi_hdmi_init); |
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 2b06402801ef..0c9997e2d8c0 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -78,6 +78,8 @@ | |||
78 | /* CKG1 */ | 78 | /* CKG1 */ |
79 | #define ACKMD_MASK 0x00007000 | 79 | #define ACKMD_MASK 0x00007000 |
80 | #define BPFMD_MASK 0x00000700 | 80 | #define BPFMD_MASK 0x00000700 |
81 | #define DIMD (1 << 4) | ||
82 | #define DOMD (1 << 0) | ||
81 | 83 | ||
82 | /* A/B MST_CTLR */ | 84 | /* A/B MST_CTLR */ |
83 | #define BP (1 << 4) /* Fix the signal of Biphase output */ | 85 | #define BP (1 << 4) /* Fix the signal of Biphase output */ |
@@ -111,6 +113,8 @@ | |||
111 | 113 | ||
112 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | 114 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
113 | 115 | ||
116 | typedef int (*set_rate_func)(struct device *dev, int is_porta, int rate, int enable); | ||
117 | |||
114 | /* | 118 | /* |
115 | * FSI driver use below type name for variable | 119 | * FSI driver use below type name for variable |
116 | * | 120 | * |
@@ -128,7 +132,6 @@ struct fsi_stream { | |||
128 | struct snd_pcm_substream *substream; | 132 | struct snd_pcm_substream *substream; |
129 | 133 | ||
130 | int fifo_max_num; | 134 | int fifo_max_num; |
131 | int chan_num; | ||
132 | 135 | ||
133 | int buff_offset; | 136 | int buff_offset; |
134 | int buff_len; | 137 | int buff_len; |
@@ -143,6 +146,7 @@ struct fsi_priv { | |||
143 | void __iomem *base; | 146 | void __iomem *base; |
144 | struct fsi_master *master; | 147 | struct fsi_master *master; |
145 | 148 | ||
149 | int chan_num; | ||
146 | struct fsi_stream playback; | 150 | struct fsi_stream playback; |
147 | struct fsi_stream capture; | 151 | struct fsi_stream capture; |
148 | 152 | ||
@@ -252,9 +256,8 @@ static struct snd_soc_dai *fsi_get_dai(struct snd_pcm_substream *substream) | |||
252 | return rtd->cpu_dai; | 256 | return rtd->cpu_dai; |
253 | } | 257 | } |
254 | 258 | ||
255 | static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | 259 | static struct fsi_priv *fsi_get_priv_frm_dai(struct snd_soc_dai *dai) |
256 | { | 260 | { |
257 | struct snd_soc_dai *dai = fsi_get_dai(substream); | ||
258 | struct fsi_master *master = snd_soc_dai_get_drvdata(dai); | 261 | struct fsi_master *master = snd_soc_dai_get_drvdata(dai); |
259 | 262 | ||
260 | if (dai->id == 0) | 263 | if (dai->id == 0) |
@@ -263,11 +266,27 @@ static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | |||
263 | return &master->fsib; | 266 | return &master->fsib; |
264 | } | 267 | } |
265 | 268 | ||
269 | static struct fsi_priv *fsi_get_priv(struct snd_pcm_substream *substream) | ||
270 | { | ||
271 | return fsi_get_priv_frm_dai(fsi_get_dai(substream)); | ||
272 | } | ||
273 | |||
274 | static set_rate_func fsi_get_info_set_rate(struct fsi_master *master) | ||
275 | { | ||
276 | if (!master->info) | ||
277 | return NULL; | ||
278 | |||
279 | return master->info->set_rate; | ||
280 | } | ||
281 | |||
266 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) | 282 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) |
267 | { | 283 | { |
268 | int is_porta = fsi_is_port_a(fsi); | 284 | int is_porta = fsi_is_port_a(fsi); |
269 | struct fsi_master *master = fsi_get_master(fsi); | 285 | struct fsi_master *master = fsi_get_master(fsi); |
270 | 286 | ||
287 | if (!master->info) | ||
288 | return 0; | ||
289 | |||
271 | return is_porta ? master->info->porta_flags : | 290 | return is_porta ? master->info->porta_flags : |
272 | master->info->portb_flags; | 291 | master->info->portb_flags; |
273 | } | 292 | } |
@@ -288,21 +307,6 @@ static inline struct fsi_stream *fsi_get_stream(struct fsi_priv *fsi, | |||
288 | return is_play ? &fsi->playback : &fsi->capture; | 307 | return is_play ? &fsi->playback : &fsi->capture; |
289 | } | 308 | } |
290 | 309 | ||
291 | static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) | ||
292 | { | ||
293 | u32 mode; | ||
294 | u32 flags = fsi_get_info_flags(fsi); | ||
295 | |||
296 | mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE; | ||
297 | |||
298 | /* return | ||
299 | * 1 : master mode | ||
300 | * 0 : slave mode | ||
301 | */ | ||
302 | |||
303 | return (mode & flags) != mode; | ||
304 | } | ||
305 | |||
306 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) | 310 | static u32 fsi_get_port_shift(struct fsi_priv *fsi, int is_play) |
307 | { | 311 | { |
308 | int is_porta = fsi_is_port_a(fsi); | 312 | int is_porta = fsi_is_port_a(fsi); |
@@ -357,7 +361,6 @@ static void fsi_stream_pop(struct fsi_priv *fsi, int is_play) | |||
357 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | 361 | static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) |
358 | { | 362 | { |
359 | u32 status; | 363 | u32 status; |
360 | struct fsi_stream *io = fsi_get_stream(fsi, is_play); | ||
361 | int data_num; | 364 | int data_num; |
362 | 365 | ||
363 | status = is_play ? | 366 | status = is_play ? |
@@ -365,7 +368,7 @@ static int fsi_get_fifo_data_num(struct fsi_priv *fsi, int is_play) | |||
365 | fsi_reg_read(fsi, DIFF_ST); | 368 | fsi_reg_read(fsi, DIFF_ST); |
366 | 369 | ||
367 | data_num = 0x1ff & (status >> 8); | 370 | data_num = 0x1ff & (status >> 8); |
368 | data_num *= io->chan_num; | 371 | data_num *= fsi->chan_num; |
369 | 372 | ||
370 | return data_num; | 373 | return data_num; |
371 | } | 374 | } |
@@ -387,7 +390,7 @@ static int fsi_get_frame_width(struct fsi_priv *fsi, int is_play) | |||
387 | struct snd_pcm_substream *substream = io->substream; | 390 | struct snd_pcm_substream *substream = io->substream; |
388 | struct snd_pcm_runtime *runtime = substream->runtime; | 391 | struct snd_pcm_runtime *runtime = substream->runtime; |
389 | 392 | ||
390 | return frames_to_bytes(runtime, 1) / io->chan_num; | 393 | return frames_to_bytes(runtime, 1) / fsi->chan_num; |
391 | } | 394 | } |
392 | 395 | ||
393 | static void fsi_count_fifo_err(struct fsi_priv *fsi) | 396 | static void fsi_count_fifo_err(struct fsi_priv *fsi) |
@@ -580,10 +583,10 @@ static void fsi_fifo_init(struct fsi_priv *fsi, | |||
580 | * 7 channels: 32 ( 32 x 7 = 224) | 583 | * 7 channels: 32 ( 32 x 7 = 224) |
581 | * 8 channels: 32 ( 32 x 8 = 256) | 584 | * 8 channels: 32 ( 32 x 8 = 256) |
582 | */ | 585 | */ |
583 | for (i = 1; i < io->chan_num; i <<= 1) | 586 | for (i = 1; i < fsi->chan_num; i <<= 1) |
584 | io->fifo_max_num >>= 1; | 587 | io->fifo_max_num >>= 1; |
585 | dev_dbg(dai->dev, "%d channel %d store\n", | 588 | dev_dbg(dai->dev, "%d channel %d store\n", |
586 | io->chan_num, io->fifo_max_num); | 589 | fsi->chan_num, io->fifo_max_num); |
587 | 590 | ||
588 | /* | 591 | /* |
589 | * set interrupt generation factor | 592 | * set interrupt generation factor |
@@ -659,7 +662,7 @@ static int fsi_fifo_data_ctrl(struct fsi_priv *fsi, int stream) | |||
659 | * data_num_max : number of FSI fifo free space | 662 | * data_num_max : number of FSI fifo free space |
660 | * data_num : number of ALSA residue data | 663 | * data_num : number of ALSA residue data |
661 | */ | 664 | */ |
662 | data_num_max = io->fifo_max_num * io->chan_num; | 665 | data_num_max = io->fifo_max_num * fsi->chan_num; |
663 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); | 666 | data_num_max -= fsi_get_fifo_data_num(fsi, is_play); |
664 | 667 | ||
665 | data_num = data_residue_num; | 668 | data_num = data_residue_num; |
@@ -754,25 +757,12 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
754 | struct snd_soc_dai *dai) | 757 | struct snd_soc_dai *dai) |
755 | { | 758 | { |
756 | struct fsi_priv *fsi = fsi_get_priv(substream); | 759 | struct fsi_priv *fsi = fsi_get_priv(substream); |
757 | struct fsi_master *master = fsi_get_master(fsi); | ||
758 | struct fsi_stream *io; | ||
759 | u32 flags = fsi_get_info_flags(fsi); | 760 | u32 flags = fsi_get_info_flags(fsi); |
760 | u32 fmt; | ||
761 | u32 data; | 761 | u32 data; |
762 | int is_play = fsi_is_play(substream); | 762 | int is_play = fsi_is_play(substream); |
763 | int is_master; | ||
764 | |||
765 | io = fsi_get_stream(fsi, is_play); | ||
766 | 763 | ||
767 | pm_runtime_get_sync(dai->dev); | 764 | pm_runtime_get_sync(dai->dev); |
768 | 765 | ||
769 | /* CKG1 */ | ||
770 | data = is_play ? (1 << 0) : (1 << 4); | ||
771 | is_master = fsi_is_master_mode(fsi, is_play); | ||
772 | if (is_master) | ||
773 | fsi_reg_mask_set(fsi, CKG1, data, data); | ||
774 | else | ||
775 | fsi_reg_mask_set(fsi, CKG1, data, 0); | ||
776 | 766 | ||
777 | /* clock inversion (CKG2) */ | 767 | /* clock inversion (CKG2) */ |
778 | data = 0; | 768 | data = 0; |
@@ -787,54 +777,6 @@ static int fsi_dai_startup(struct snd_pcm_substream *substream, | |||
787 | 777 | ||
788 | fsi_reg_write(fsi, CKG2, data); | 778 | fsi_reg_write(fsi, CKG2, data); |
789 | 779 | ||
790 | /* do fmt, di fmt */ | ||
791 | data = 0; | ||
792 | fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); | ||
793 | switch (fmt) { | ||
794 | case SH_FSI_FMT_MONO: | ||
795 | data = CR_MONO; | ||
796 | io->chan_num = 1; | ||
797 | break; | ||
798 | case SH_FSI_FMT_MONO_DELAY: | ||
799 | data = CR_MONO_D; | ||
800 | io->chan_num = 1; | ||
801 | break; | ||
802 | case SH_FSI_FMT_PCM: | ||
803 | data = CR_PCM; | ||
804 | io->chan_num = 2; | ||
805 | break; | ||
806 | case SH_FSI_FMT_I2S: | ||
807 | data = CR_I2S; | ||
808 | io->chan_num = 2; | ||
809 | break; | ||
810 | case SH_FSI_FMT_TDM: | ||
811 | io->chan_num = is_play ? | ||
812 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
813 | data = CR_TDM | (io->chan_num - 1); | ||
814 | break; | ||
815 | case SH_FSI_FMT_TDM_DELAY: | ||
816 | io->chan_num = is_play ? | ||
817 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
818 | data = CR_TDM_D | (io->chan_num - 1); | ||
819 | break; | ||
820 | case SH_FSI_FMT_SPDIF: | ||
821 | if (master->core->ver < 2) { | ||
822 | dev_err(dai->dev, "This FSI can not use SPDIF\n"); | ||
823 | return -EINVAL; | ||
824 | } | ||
825 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | ||
826 | io->chan_num = 2; | ||
827 | fsi_spdif_clk_ctrl(fsi, 1); | ||
828 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
829 | break; | ||
830 | default: | ||
831 | dev_err(dai->dev, "unknown format.\n"); | ||
832 | return -EINVAL; | ||
833 | } | ||
834 | is_play ? | ||
835 | fsi_reg_write(fsi, DO_FMT, data) : | ||
836 | fsi_reg_write(fsi, DI_FMT, data); | ||
837 | |||
838 | /* irq clear */ | 780 | /* irq clear */ |
839 | fsi_irq_disable(fsi, is_play); | 781 | fsi_irq_disable(fsi, is_play); |
840 | fsi_irq_clear_status(fsi); | 782 | fsi_irq_clear_status(fsi); |
@@ -851,12 +793,12 @@ static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | |||
851 | struct fsi_priv *fsi = fsi_get_priv(substream); | 793 | struct fsi_priv *fsi = fsi_get_priv(substream); |
852 | int is_play = fsi_is_play(substream); | 794 | int is_play = fsi_is_play(substream); |
853 | struct fsi_master *master = fsi_get_master(fsi); | 795 | struct fsi_master *master = fsi_get_master(fsi); |
854 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); | 796 | set_rate_func set_rate; |
855 | 797 | ||
856 | fsi_irq_disable(fsi, is_play); | 798 | fsi_irq_disable(fsi, is_play); |
857 | fsi_clk_ctrl(fsi, 0); | 799 | fsi_clk_ctrl(fsi, 0); |
858 | 800 | ||
859 | set_rate = master->info->set_rate; | 801 | set_rate = fsi_get_info_set_rate(master); |
860 | if (set_rate && fsi->rate) | 802 | if (set_rate && fsi->rate) |
861 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); | 803 | set_rate(dai->dev, fsi_is_port_a(fsi), fsi->rate, 0); |
862 | fsi->rate = 0; | 804 | fsi->rate = 0; |
@@ -889,18 +831,100 @@ static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
889 | return ret; | 831 | return ret; |
890 | } | 832 | } |
891 | 833 | ||
834 | static int fsi_set_fmt_dai(struct fsi_priv *fsi, unsigned int fmt) | ||
835 | { | ||
836 | u32 data = 0; | ||
837 | |||
838 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
839 | case SND_SOC_DAIFMT_I2S: | ||
840 | data = CR_I2S; | ||
841 | fsi->chan_num = 2; | ||
842 | break; | ||
843 | case SND_SOC_DAIFMT_LEFT_J: | ||
844 | data = CR_PCM; | ||
845 | fsi->chan_num = 2; | ||
846 | break; | ||
847 | default: | ||
848 | return -EINVAL; | ||
849 | } | ||
850 | |||
851 | fsi_reg_write(fsi, DO_FMT, data); | ||
852 | fsi_reg_write(fsi, DI_FMT, data); | ||
853 | |||
854 | return 0; | ||
855 | } | ||
856 | |||
857 | static int fsi_set_fmt_spdif(struct fsi_priv *fsi) | ||
858 | { | ||
859 | struct fsi_master *master = fsi_get_master(fsi); | ||
860 | u32 data = 0; | ||
861 | |||
862 | if (master->core->ver < 2) | ||
863 | return -EINVAL; | ||
864 | |||
865 | data = CR_BWS_16 | CR_DTMD_SPDIF_PCM | CR_PCM; | ||
866 | fsi->chan_num = 2; | ||
867 | fsi_spdif_clk_ctrl(fsi, 1); | ||
868 | fsi_reg_mask_set(fsi, OUT_SEL, DMMD, DMMD); | ||
869 | |||
870 | fsi_reg_write(fsi, DO_FMT, data); | ||
871 | fsi_reg_write(fsi, DI_FMT, data); | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int fsi_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
877 | { | ||
878 | struct fsi_priv *fsi = fsi_get_priv_frm_dai(dai); | ||
879 | u32 flags = fsi_get_info_flags(fsi); | ||
880 | u32 data = 0; | ||
881 | int ret; | ||
882 | |||
883 | pm_runtime_get_sync(dai->dev); | ||
884 | |||
885 | /* set master/slave audio interface */ | ||
886 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
887 | case SND_SOC_DAIFMT_CBM_CFM: | ||
888 | data = DIMD | DOMD; | ||
889 | break; | ||
890 | case SND_SOC_DAIFMT_CBS_CFS: | ||
891 | break; | ||
892 | default: | ||
893 | ret = -EINVAL; | ||
894 | goto set_fmt_exit; | ||
895 | } | ||
896 | fsi_reg_mask_set(fsi, CKG1, (DIMD | DOMD), data); | ||
897 | |||
898 | /* set format */ | ||
899 | switch (flags & SH_FSI_FMT_MASK) { | ||
900 | case SH_FSI_FMT_DAI: | ||
901 | ret = fsi_set_fmt_dai(fsi, fmt & SND_SOC_DAIFMT_FORMAT_MASK); | ||
902 | break; | ||
903 | case SH_FSI_FMT_SPDIF: | ||
904 | ret = fsi_set_fmt_spdif(fsi); | ||
905 | break; | ||
906 | default: | ||
907 | ret = -EINVAL; | ||
908 | } | ||
909 | |||
910 | set_fmt_exit: | ||
911 | pm_runtime_put_sync(dai->dev); | ||
912 | |||
913 | return ret; | ||
914 | } | ||
915 | |||
892 | static int fsi_dai_hw_params(struct snd_pcm_substream *substream, | 916 | static int fsi_dai_hw_params(struct snd_pcm_substream *substream, |
893 | struct snd_pcm_hw_params *params, | 917 | struct snd_pcm_hw_params *params, |
894 | struct snd_soc_dai *dai) | 918 | struct snd_soc_dai *dai) |
895 | { | 919 | { |
896 | struct fsi_priv *fsi = fsi_get_priv(substream); | 920 | struct fsi_priv *fsi = fsi_get_priv(substream); |
897 | struct fsi_master *master = fsi_get_master(fsi); | 921 | struct fsi_master *master = fsi_get_master(fsi); |
898 | int (*set_rate)(struct device *dev, int is_porta, int rate, int enable); | 922 | set_rate_func set_rate; |
899 | int fsi_ver = master->core->ver; | 923 | int fsi_ver = master->core->ver; |
900 | long rate = params_rate(params); | 924 | long rate = params_rate(params); |
901 | int ret; | 925 | int ret; |
902 | 926 | ||
903 | set_rate = master->info->set_rate; | 927 | set_rate = fsi_get_info_set_rate(master); |
904 | if (!set_rate) | 928 | if (!set_rate) |
905 | return 0; | 929 | return 0; |
906 | 930 | ||
@@ -975,6 +999,7 @@ static struct snd_soc_dai_ops fsi_dai_ops = { | |||
975 | .startup = fsi_dai_startup, | 999 | .startup = fsi_dai_startup, |
976 | .shutdown = fsi_dai_shutdown, | 1000 | .shutdown = fsi_dai_shutdown, |
977 | .trigger = fsi_dai_trigger, | 1001 | .trigger = fsi_dai_trigger, |
1002 | .set_fmt = fsi_dai_set_fmt, | ||
978 | .hw_params = fsi_dai_hw_params, | 1003 | .hw_params = fsi_dai_hw_params, |
979 | }; | 1004 | }; |
980 | 1005 | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 8c2a21a978ac..5d76da43b14c 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/bitmap.h> | 18 | #include <linux/bitmap.h> |
19 | #include <linux/rbtree.h> | 19 | #include <linux/rbtree.h> |
20 | 20 | ||
21 | #include <trace/events/asoc.h> | ||
22 | |||
21 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | 23 | static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, |
22 | unsigned int reg) | 24 | unsigned int reg) |
23 | { | 25 | { |
@@ -25,7 +27,8 @@ static unsigned int snd_soc_4_12_read(struct snd_soc_codec *codec, | |||
25 | unsigned int val; | 27 | unsigned int val; |
26 | 28 | ||
27 | if (reg >= codec->driver->reg_cache_size || | 29 | if (reg >= codec->driver->reg_cache_size || |
28 | snd_soc_codec_volatile_register(codec, reg)) { | 30 | snd_soc_codec_volatile_register(codec, reg) || |
31 | codec->cache_bypass) { | ||
29 | if (codec->cache_only) | 32 | if (codec->cache_only) |
30 | return -1; | 33 | return -1; |
31 | 34 | ||
@@ -49,7 +52,8 @@ static int snd_soc_4_12_write(struct snd_soc_codec *codec, unsigned int reg, | |||
49 | data[1] = value & 0x00ff; | 52 | data[1] = value & 0x00ff; |
50 | 53 | ||
51 | if (!snd_soc_codec_volatile_register(codec, reg) && | 54 | if (!snd_soc_codec_volatile_register(codec, reg) && |
52 | reg < codec->driver->reg_cache_size) { | 55 | reg < codec->driver->reg_cache_size && |
56 | !codec->cache_bypass) { | ||
53 | ret = snd_soc_cache_write(codec, reg, value); | 57 | ret = snd_soc_cache_write(codec, reg, value); |
54 | if (ret < 0) | 58 | if (ret < 0) |
55 | return -1; | 59 | return -1; |
@@ -106,7 +110,8 @@ static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, | |||
106 | unsigned int val; | 110 | unsigned int val; |
107 | 111 | ||
108 | if (reg >= codec->driver->reg_cache_size || | 112 | if (reg >= codec->driver->reg_cache_size || |
109 | snd_soc_codec_volatile_register(codec, reg)) { | 113 | snd_soc_codec_volatile_register(codec, reg) || |
114 | codec->cache_bypass) { | ||
110 | if (codec->cache_only) | 115 | if (codec->cache_only) |
111 | return -1; | 116 | return -1; |
112 | 117 | ||
@@ -130,7 +135,8 @@ static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, | |||
130 | data[1] = value & 0x00ff; | 135 | data[1] = value & 0x00ff; |
131 | 136 | ||
132 | if (!snd_soc_codec_volatile_register(codec, reg) && | 137 | if (!snd_soc_codec_volatile_register(codec, reg) && |
133 | reg < codec->driver->reg_cache_size) { | 138 | reg < codec->driver->reg_cache_size && |
139 | !codec->cache_bypass) { | ||
134 | ret = snd_soc_cache_write(codec, reg, value); | 140 | ret = snd_soc_cache_write(codec, reg, value); |
135 | if (ret < 0) | 141 | if (ret < 0) |
136 | return -1; | 142 | return -1; |
@@ -191,7 +197,8 @@ static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | |||
191 | data[1] = value & 0xff; | 197 | data[1] = value & 0xff; |
192 | 198 | ||
193 | if (!snd_soc_codec_volatile_register(codec, reg) && | 199 | if (!snd_soc_codec_volatile_register(codec, reg) && |
194 | reg < codec->driver->reg_cache_size) { | 200 | reg < codec->driver->reg_cache_size && |
201 | !codec->cache_bypass) { | ||
195 | ret = snd_soc_cache_write(codec, reg, value); | 202 | ret = snd_soc_cache_write(codec, reg, value); |
196 | if (ret < 0) | 203 | if (ret < 0) |
197 | return -1; | 204 | return -1; |
@@ -216,7 +223,8 @@ static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | |||
216 | 223 | ||
217 | reg &= 0xff; | 224 | reg &= 0xff; |
218 | if (reg >= codec->driver->reg_cache_size || | 225 | if (reg >= codec->driver->reg_cache_size || |
219 | snd_soc_codec_volatile_register(codec, reg)) { | 226 | snd_soc_codec_volatile_register(codec, reg) || |
227 | codec->cache_bypass) { | ||
220 | if (codec->cache_only) | 228 | if (codec->cache_only) |
221 | return -1; | 229 | return -1; |
222 | 230 | ||
@@ -271,7 +279,8 @@ static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | |||
271 | data[2] = value & 0xff; | 279 | data[2] = value & 0xff; |
272 | 280 | ||
273 | if (!snd_soc_codec_volatile_register(codec, reg) && | 281 | if (!snd_soc_codec_volatile_register(codec, reg) && |
274 | reg < codec->driver->reg_cache_size) { | 282 | reg < codec->driver->reg_cache_size && |
283 | !codec->cache_bypass) { | ||
275 | ret = snd_soc_cache_write(codec, reg, value); | 284 | ret = snd_soc_cache_write(codec, reg, value); |
276 | if (ret < 0) | 285 | if (ret < 0) |
277 | return -1; | 286 | return -1; |
@@ -295,7 +304,8 @@ static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, | |||
295 | unsigned int val; | 304 | unsigned int val; |
296 | 305 | ||
297 | if (reg >= codec->driver->reg_cache_size || | 306 | if (reg >= codec->driver->reg_cache_size || |
298 | snd_soc_codec_volatile_register(codec, reg)) { | 307 | snd_soc_codec_volatile_register(codec, reg) || |
308 | codec->cache_bypass) { | ||
299 | if (codec->cache_only) | 309 | if (codec->cache_only) |
300 | return -1; | 310 | return -1; |
301 | 311 | ||
@@ -450,7 +460,8 @@ static unsigned int snd_soc_16_8_read(struct snd_soc_codec *codec, | |||
450 | 460 | ||
451 | reg &= 0xff; | 461 | reg &= 0xff; |
452 | if (reg >= codec->driver->reg_cache_size || | 462 | if (reg >= codec->driver->reg_cache_size || |
453 | snd_soc_codec_volatile_register(codec, reg)) { | 463 | snd_soc_codec_volatile_register(codec, reg) || |
464 | codec->cache_bypass) { | ||
454 | if (codec->cache_only) | 465 | if (codec->cache_only) |
455 | return -1; | 466 | return -1; |
456 | 467 | ||
@@ -476,7 +487,8 @@ static int snd_soc_16_8_write(struct snd_soc_codec *codec, unsigned int reg, | |||
476 | 487 | ||
477 | reg &= 0xff; | 488 | reg &= 0xff; |
478 | if (!snd_soc_codec_volatile_register(codec, reg) && | 489 | if (!snd_soc_codec_volatile_register(codec, reg) && |
479 | reg < codec->driver->reg_cache_size) { | 490 | reg < codec->driver->reg_cache_size && |
491 | !codec->cache_bypass) { | ||
480 | ret = snd_soc_cache_write(codec, reg, value); | 492 | ret = snd_soc_cache_write(codec, reg, value); |
481 | if (ret < 0) | 493 | if (ret < 0) |
482 | return -1; | 494 | return -1; |
@@ -568,7 +580,8 @@ static unsigned int snd_soc_16_16_read(struct snd_soc_codec *codec, | |||
568 | unsigned int val; | 580 | unsigned int val; |
569 | 581 | ||
570 | if (reg >= codec->driver->reg_cache_size || | 582 | if (reg >= codec->driver->reg_cache_size || |
571 | snd_soc_codec_volatile_register(codec, reg)) { | 583 | snd_soc_codec_volatile_register(codec, reg) || |
584 | codec->cache_bypass) { | ||
572 | if (codec->cache_only) | 585 | if (codec->cache_only) |
573 | return -1; | 586 | return -1; |
574 | 587 | ||
@@ -595,7 +608,8 @@ static int snd_soc_16_16_write(struct snd_soc_codec *codec, unsigned int reg, | |||
595 | data[3] = value & 0xff; | 608 | data[3] = value & 0xff; |
596 | 609 | ||
597 | if (!snd_soc_codec_volatile_register(codec, reg) && | 610 | if (!snd_soc_codec_volatile_register(codec, reg) && |
598 | reg < codec->driver->reg_cache_size) { | 611 | reg < codec->driver->reg_cache_size && |
612 | !codec->cache_bypass) { | ||
599 | ret = snd_soc_cache_write(codec, reg, value); | 613 | ret = snd_soc_cache_write(codec, reg, value); |
600 | if (ret < 0) | 614 | if (ret < 0) |
601 | return -1; | 615 | return -1; |
@@ -761,6 +775,49 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | |||
761 | } | 775 | } |
762 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); | 776 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); |
763 | 777 | ||
778 | static bool snd_soc_set_cache_val(void *base, unsigned int idx, | ||
779 | unsigned int val, unsigned int word_size) | ||
780 | { | ||
781 | switch (word_size) { | ||
782 | case 1: { | ||
783 | u8 *cache = base; | ||
784 | if (cache[idx] == val) | ||
785 | return true; | ||
786 | cache[idx] = val; | ||
787 | break; | ||
788 | } | ||
789 | case 2: { | ||
790 | u16 *cache = base; | ||
791 | if (cache[idx] == val) | ||
792 | return true; | ||
793 | cache[idx] = val; | ||
794 | break; | ||
795 | } | ||
796 | default: | ||
797 | BUG(); | ||
798 | } | ||
799 | return false; | ||
800 | } | ||
801 | |||
802 | static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx, | ||
803 | unsigned int word_size) | ||
804 | { | ||
805 | switch (word_size) { | ||
806 | case 1: { | ||
807 | const u8 *cache = base; | ||
808 | return cache[idx]; | ||
809 | } | ||
810 | case 2: { | ||
811 | const u16 *cache = base; | ||
812 | return cache[idx]; | ||
813 | } | ||
814 | default: | ||
815 | BUG(); | ||
816 | } | ||
817 | /* unreachable */ | ||
818 | return -1; | ||
819 | } | ||
820 | |||
764 | struct snd_soc_rbtree_node { | 821 | struct snd_soc_rbtree_node { |
765 | struct rb_node node; | 822 | struct rb_node node; |
766 | unsigned int reg; | 823 | unsigned int reg; |
@@ -835,7 +892,9 @@ static int snd_soc_rbtree_cache_sync(struct snd_soc_codec *codec) | |||
835 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); | 892 | ret = snd_soc_cache_read(codec, rbnode->reg, &val); |
836 | if (ret) | 893 | if (ret) |
837 | return ret; | 894 | return ret; |
895 | codec->cache_bypass = 1; | ||
838 | ret = snd_soc_write(codec, rbnode->reg, val); | 896 | ret = snd_soc_write(codec, rbnode->reg, val); |
897 | codec->cache_bypass = 0; | ||
839 | if (ret) | 898 | if (ret) |
840 | return ret; | 899 | return ret; |
841 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | 900 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
@@ -924,7 +983,12 @@ static int snd_soc_rbtree_cache_exit(struct snd_soc_codec *codec) | |||
924 | 983 | ||
925 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | 984 | static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) |
926 | { | 985 | { |
986 | struct snd_soc_rbtree_node *rbtree_node; | ||
927 | struct snd_soc_rbtree_ctx *rbtree_ctx; | 987 | struct snd_soc_rbtree_ctx *rbtree_ctx; |
988 | unsigned int val; | ||
989 | unsigned int word_size; | ||
990 | int i; | ||
991 | int ret; | ||
928 | 992 | ||
929 | codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); | 993 | codec->reg_cache = kmalloc(sizeof *rbtree_ctx, GFP_KERNEL); |
930 | if (!codec->reg_cache) | 994 | if (!codec->reg_cache) |
@@ -936,53 +1000,25 @@ static int snd_soc_rbtree_cache_init(struct snd_soc_codec *codec) | |||
936 | if (!codec->reg_def_copy) | 1000 | if (!codec->reg_def_copy) |
937 | return 0; | 1001 | return 0; |
938 | 1002 | ||
939 | /* | 1003 | /* |
940 | * populate the rbtree with the initialized registers. All other | 1004 | * populate the rbtree with the initialized registers. All other |
941 | * registers will be inserted into the tree when they are first written. | 1005 | * registers will be inserted when they are first modified. |
942 | * | 1006 | */ |
943 | * The reasoning behind this, is that we need to step through and | 1007 | word_size = codec->driver->reg_word_size; |
944 | * dereference the cache in u8/u16 increments without sacrificing | 1008 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { |
945 | * portability. This could also be done using memcpy() but that would | 1009 | val = snd_soc_get_cache_val(codec->reg_def_copy, i, word_size); |
946 | * be slightly more cryptic. | 1010 | if (!val) |
947 | */ | 1011 | continue; |
948 | #define snd_soc_rbtree_populate(cache) \ | 1012 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); |
949 | ({ \ | 1013 | if (!rbtree_node) { |
950 | int ret, i; \ | 1014 | ret = -ENOMEM; |
951 | struct snd_soc_rbtree_node *rbtree_node; \ | 1015 | snd_soc_cache_exit(codec); |
952 | \ | 1016 | break; |
953 | ret = 0; \ | 1017 | } |
954 | cache = codec->reg_def_copy; \ | 1018 | rbtree_node->reg = i; |
955 | for (i = 0; i < codec->driver->reg_cache_size; ++i) { \ | 1019 | rbtree_node->value = val; |
956 | if (!cache[i]) \ | 1020 | rbtree_node->defval = val; |
957 | continue; \ | 1021 | snd_soc_rbtree_insert(&rbtree_ctx->root, rbtree_node); |
958 | rbtree_node = kzalloc(sizeof *rbtree_node, GFP_KERNEL); \ | ||
959 | if (!rbtree_node) { \ | ||
960 | ret = -ENOMEM; \ | ||
961 | snd_soc_cache_exit(codec); \ | ||
962 | break; \ | ||
963 | } \ | ||
964 | rbtree_node->reg = i; \ | ||
965 | rbtree_node->value = cache[i]; \ | ||
966 | rbtree_node->defval = cache[i]; \ | ||
967 | snd_soc_rbtree_insert(&rbtree_ctx->root, \ | ||
968 | rbtree_node); \ | ||
969 | } \ | ||
970 | ret; \ | ||
971 | }) | ||
972 | |||
973 | switch (codec->driver->reg_word_size) { | ||
974 | case 1: { | ||
975 | const u8 *cache; | ||
976 | |||
977 | return snd_soc_rbtree_populate(cache); | ||
978 | } | ||
979 | case 2: { | ||
980 | const u16 *cache; | ||
981 | |||
982 | return snd_soc_rbtree_populate(cache); | ||
983 | } | ||
984 | default: | ||
985 | BUG(); | ||
986 | } | 1022 | } |
987 | 1023 | ||
988 | return 0; | 1024 | return 0; |
@@ -1080,34 +1116,28 @@ static inline int snd_soc_lzo_get_blkindex(struct snd_soc_codec *codec, | |||
1080 | unsigned int reg) | 1116 | unsigned int reg) |
1081 | { | 1117 | { |
1082 | const struct snd_soc_codec_driver *codec_drv; | 1118 | const struct snd_soc_codec_driver *codec_drv; |
1083 | size_t reg_size; | ||
1084 | 1119 | ||
1085 | codec_drv = codec->driver; | 1120 | codec_drv = codec->driver; |
1086 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1087 | return (reg * codec_drv->reg_word_size) / | 1121 | return (reg * codec_drv->reg_word_size) / |
1088 | DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()); | 1122 | DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
1089 | } | 1123 | } |
1090 | 1124 | ||
1091 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, | 1125 | static inline int snd_soc_lzo_get_blkpos(struct snd_soc_codec *codec, |
1092 | unsigned int reg) | 1126 | unsigned int reg) |
1093 | { | 1127 | { |
1094 | const struct snd_soc_codec_driver *codec_drv; | 1128 | const struct snd_soc_codec_driver *codec_drv; |
1095 | size_t reg_size; | ||
1096 | 1129 | ||
1097 | codec_drv = codec->driver; | 1130 | codec_drv = codec->driver; |
1098 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | 1131 | return reg % (DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()) / |
1099 | return reg % (DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()) / | ||
1100 | codec_drv->reg_word_size); | 1132 | codec_drv->reg_word_size); |
1101 | } | 1133 | } |
1102 | 1134 | ||
1103 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) | 1135 | static inline int snd_soc_lzo_get_blksize(struct snd_soc_codec *codec) |
1104 | { | 1136 | { |
1105 | const struct snd_soc_codec_driver *codec_drv; | 1137 | const struct snd_soc_codec_driver *codec_drv; |
1106 | size_t reg_size; | ||
1107 | 1138 | ||
1108 | codec_drv = codec->driver; | 1139 | codec_drv = codec->driver; |
1109 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | 1140 | return DIV_ROUND_UP(codec->reg_size, snd_soc_lzo_block_count()); |
1110 | return DIV_ROUND_UP(reg_size, snd_soc_lzo_block_count()); | ||
1111 | } | 1141 | } |
1112 | 1142 | ||
1113 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | 1143 | static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) |
@@ -1122,7 +1152,9 @@ static int snd_soc_lzo_cache_sync(struct snd_soc_codec *codec) | |||
1122 | ret = snd_soc_cache_read(codec, i, &val); | 1152 | ret = snd_soc_cache_read(codec, i, &val); |
1123 | if (ret) | 1153 | if (ret) |
1124 | return ret; | 1154 | return ret; |
1155 | codec->cache_bypass = 1; | ||
1125 | ret = snd_soc_write(codec, i, val); | 1156 | ret = snd_soc_write(codec, i, val); |
1157 | codec->cache_bypass = 0; | ||
1126 | if (ret) | 1158 | if (ret) |
1127 | return ret; | 1159 | return ret; |
1128 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", | 1160 | dev_dbg(codec->dev, "Synced register %#x, value = %#x\n", |
@@ -1165,29 +1197,10 @@ static int snd_soc_lzo_cache_write(struct snd_soc_codec *codec, | |||
1165 | } | 1197 | } |
1166 | 1198 | ||
1167 | /* write the new value to the cache */ | 1199 | /* write the new value to the cache */ |
1168 | switch (codec->driver->reg_word_size) { | 1200 | if (snd_soc_set_cache_val(lzo_block->dst, blkpos, value, |
1169 | case 1: { | 1201 | codec->driver->reg_word_size)) { |
1170 | u8 *cache; | 1202 | kfree(lzo_block->dst); |
1171 | cache = lzo_block->dst; | 1203 | goto out; |
1172 | if (cache[blkpos] == value) { | ||
1173 | kfree(lzo_block->dst); | ||
1174 | goto out; | ||
1175 | } | ||
1176 | cache[blkpos] = value; | ||
1177 | } | ||
1178 | break; | ||
1179 | case 2: { | ||
1180 | u16 *cache; | ||
1181 | cache = lzo_block->dst; | ||
1182 | if (cache[blkpos] == value) { | ||
1183 | kfree(lzo_block->dst); | ||
1184 | goto out; | ||
1185 | } | ||
1186 | cache[blkpos] = value; | ||
1187 | } | ||
1188 | break; | ||
1189 | default: | ||
1190 | BUG(); | ||
1191 | } | 1204 | } |
1192 | 1205 | ||
1193 | /* prepare the source to be the decompressed block */ | 1206 | /* prepare the source to be the decompressed block */ |
@@ -1241,25 +1254,10 @@ static int snd_soc_lzo_cache_read(struct snd_soc_codec *codec, | |||
1241 | 1254 | ||
1242 | /* decompress the block */ | 1255 | /* decompress the block */ |
1243 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); | 1256 | ret = snd_soc_lzo_decompress_cache_block(codec, lzo_block); |
1244 | if (ret >= 0) { | 1257 | if (ret >= 0) |
1245 | /* fetch the value from the cache */ | 1258 | /* fetch the value from the cache */ |
1246 | switch (codec->driver->reg_word_size) { | 1259 | *value = snd_soc_get_cache_val(lzo_block->dst, blkpos, |
1247 | case 1: { | 1260 | codec->driver->reg_word_size); |
1248 | u8 *cache; | ||
1249 | cache = lzo_block->dst; | ||
1250 | *value = cache[blkpos]; | ||
1251 | } | ||
1252 | break; | ||
1253 | case 2: { | ||
1254 | u16 *cache; | ||
1255 | cache = lzo_block->dst; | ||
1256 | *value = cache[blkpos]; | ||
1257 | } | ||
1258 | break; | ||
1259 | default: | ||
1260 | BUG(); | ||
1261 | } | ||
1262 | } | ||
1263 | 1261 | ||
1264 | kfree(lzo_block->dst); | 1262 | kfree(lzo_block->dst); |
1265 | /* restore the pointer and length of the compressed block */ | 1263 | /* restore the pointer and length of the compressed block */ |
@@ -1301,7 +1299,7 @@ static int snd_soc_lzo_cache_exit(struct snd_soc_codec *codec) | |||
1301 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | 1299 | static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) |
1302 | { | 1300 | { |
1303 | struct snd_soc_lzo_ctx **lzo_blocks; | 1301 | struct snd_soc_lzo_ctx **lzo_blocks; |
1304 | size_t reg_size, bmp_size; | 1302 | size_t bmp_size; |
1305 | const struct snd_soc_codec_driver *codec_drv; | 1303 | const struct snd_soc_codec_driver *codec_drv; |
1306 | int ret, tofree, i, blksize, blkcount; | 1304 | int ret, tofree, i, blksize, blkcount; |
1307 | const char *p, *end; | 1305 | const char *p, *end; |
@@ -1309,7 +1307,6 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1309 | 1307 | ||
1310 | ret = 0; | 1308 | ret = 0; |
1311 | codec_drv = codec->driver; | 1309 | codec_drv = codec->driver; |
1312 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1313 | 1310 | ||
1314 | /* | 1311 | /* |
1315 | * If we have not been given a default register cache | 1312 | * If we have not been given a default register cache |
@@ -1321,8 +1318,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1321 | tofree = 1; | 1318 | tofree = 1; |
1322 | 1319 | ||
1323 | if (!codec->reg_def_copy) { | 1320 | if (!codec->reg_def_copy) { |
1324 | codec->reg_def_copy = kzalloc(reg_size, | 1321 | codec->reg_def_copy = kzalloc(codec->reg_size, GFP_KERNEL); |
1325 | GFP_KERNEL); | ||
1326 | if (!codec->reg_def_copy) | 1322 | if (!codec->reg_def_copy) |
1327 | return -ENOMEM; | 1323 | return -ENOMEM; |
1328 | } | 1324 | } |
@@ -1370,7 +1366,7 @@ static int snd_soc_lzo_cache_init(struct snd_soc_codec *codec) | |||
1370 | 1366 | ||
1371 | blksize = snd_soc_lzo_get_blksize(codec); | 1367 | blksize = snd_soc_lzo_get_blksize(codec); |
1372 | p = codec->reg_def_copy; | 1368 | p = codec->reg_def_copy; |
1373 | end = codec->reg_def_copy + reg_size; | 1369 | end = codec->reg_def_copy + codec->reg_size; |
1374 | /* compress the register map and fill the lzo blocks */ | 1370 | /* compress the register map and fill the lzo blocks */ |
1375 | for (i = 0; i < blkcount; ++i, p += blksize) { | 1371 | for (i = 0; i < blkcount; ++i, p += blksize) { |
1376 | lzo_blocks[i]->src = p; | 1372 | lzo_blocks[i]->src = p; |
@@ -1414,28 +1410,10 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | |||
1414 | ret = snd_soc_cache_read(codec, i, &val); | 1410 | ret = snd_soc_cache_read(codec, i, &val); |
1415 | if (ret) | 1411 | if (ret) |
1416 | return ret; | 1412 | return ret; |
1417 | if (codec_drv->reg_cache_default) { | 1413 | if (codec->reg_def_copy) |
1418 | switch (codec_drv->reg_word_size) { | 1414 | if (snd_soc_get_cache_val(codec->reg_def_copy, |
1419 | case 1: { | 1415 | i, codec_drv->reg_word_size) == val) |
1420 | const u8 *cache; | 1416 | continue; |
1421 | |||
1422 | cache = codec_drv->reg_cache_default; | ||
1423 | if (cache[i] == val) | ||
1424 | continue; | ||
1425 | } | ||
1426 | break; | ||
1427 | case 2: { | ||
1428 | const u16 *cache; | ||
1429 | |||
1430 | cache = codec_drv->reg_cache_default; | ||
1431 | if (cache[i] == val) | ||
1432 | continue; | ||
1433 | } | ||
1434 | break; | ||
1435 | default: | ||
1436 | BUG(); | ||
1437 | } | ||
1438 | } | ||
1439 | ret = snd_soc_write(codec, i, val); | 1417 | ret = snd_soc_write(codec, i, val); |
1440 | if (ret) | 1418 | if (ret) |
1441 | return ret; | 1419 | return ret; |
@@ -1448,50 +1426,16 @@ static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec) | |||
1448 | static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, | 1426 | static int snd_soc_flat_cache_write(struct snd_soc_codec *codec, |
1449 | unsigned int reg, unsigned int value) | 1427 | unsigned int reg, unsigned int value) |
1450 | { | 1428 | { |
1451 | switch (codec->driver->reg_word_size) { | 1429 | snd_soc_set_cache_val(codec->reg_cache, reg, value, |
1452 | case 1: { | 1430 | codec->driver->reg_word_size); |
1453 | u8 *cache; | ||
1454 | |||
1455 | cache = codec->reg_cache; | ||
1456 | cache[reg] = value; | ||
1457 | } | ||
1458 | break; | ||
1459 | case 2: { | ||
1460 | u16 *cache; | ||
1461 | |||
1462 | cache = codec->reg_cache; | ||
1463 | cache[reg] = value; | ||
1464 | } | ||
1465 | break; | ||
1466 | default: | ||
1467 | BUG(); | ||
1468 | } | ||
1469 | |||
1470 | return 0; | 1431 | return 0; |
1471 | } | 1432 | } |
1472 | 1433 | ||
1473 | static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, | 1434 | static int snd_soc_flat_cache_read(struct snd_soc_codec *codec, |
1474 | unsigned int reg, unsigned int *value) | 1435 | unsigned int reg, unsigned int *value) |
1475 | { | 1436 | { |
1476 | switch (codec->driver->reg_word_size) { | 1437 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
1477 | case 1: { | 1438 | codec->driver->reg_word_size); |
1478 | u8 *cache; | ||
1479 | |||
1480 | cache = codec->reg_cache; | ||
1481 | *value = cache[reg]; | ||
1482 | } | ||
1483 | break; | ||
1484 | case 2: { | ||
1485 | u16 *cache; | ||
1486 | |||
1487 | cache = codec->reg_cache; | ||
1488 | *value = cache[reg]; | ||
1489 | } | ||
1490 | break; | ||
1491 | default: | ||
1492 | BUG(); | ||
1493 | } | ||
1494 | |||
1495 | return 0; | 1439 | return 0; |
1496 | } | 1440 | } |
1497 | 1441 | ||
@@ -1507,24 +1451,14 @@ static int snd_soc_flat_cache_exit(struct snd_soc_codec *codec) | |||
1507 | static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) | 1451 | static int snd_soc_flat_cache_init(struct snd_soc_codec *codec) |
1508 | { | 1452 | { |
1509 | const struct snd_soc_codec_driver *codec_drv; | 1453 | const struct snd_soc_codec_driver *codec_drv; |
1510 | size_t reg_size; | ||
1511 | 1454 | ||
1512 | codec_drv = codec->driver; | 1455 | codec_drv = codec->driver; |
1513 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | ||
1514 | 1456 | ||
1515 | /* | 1457 | if (codec->reg_def_copy) |
1516 | * for flat compression, we don't need to keep a copy of the | 1458 | codec->reg_cache = kmemdup(codec->reg_def_copy, |
1517 | * original defaults register cache as it will definitely not | 1459 | codec->reg_size, GFP_KERNEL); |
1518 | * be marked as __devinitconst | ||
1519 | */ | ||
1520 | kfree(codec->reg_def_copy); | ||
1521 | codec->reg_def_copy = NULL; | ||
1522 | |||
1523 | if (codec_drv->reg_cache_default) | ||
1524 | codec->reg_cache = kmemdup(codec_drv->reg_cache_default, | ||
1525 | reg_size, GFP_KERNEL); | ||
1526 | else | 1460 | else |
1527 | codec->reg_cache = kzalloc(reg_size, GFP_KERNEL); | 1461 | codec->reg_cache = kzalloc(codec->reg_size, GFP_KERNEL); |
1528 | if (!codec->reg_cache) | 1462 | if (!codec->reg_cache) |
1529 | return -ENOMEM; | 1463 | return -ENOMEM; |
1530 | 1464 | ||
@@ -1669,21 +1603,77 @@ EXPORT_SYMBOL_GPL(snd_soc_cache_write); | |||
1669 | int snd_soc_cache_sync(struct snd_soc_codec *codec) | 1603 | int snd_soc_cache_sync(struct snd_soc_codec *codec) |
1670 | { | 1604 | { |
1671 | int ret; | 1605 | int ret; |
1606 | const char *name; | ||
1672 | 1607 | ||
1673 | if (!codec->cache_sync) { | 1608 | if (!codec->cache_sync) { |
1674 | return 0; | 1609 | return 0; |
1675 | } | 1610 | } |
1676 | 1611 | ||
1677 | if (codec->cache_ops && codec->cache_ops->sync) { | 1612 | if (!codec->cache_ops || !codec->cache_ops->sync) |
1678 | if (codec->cache_ops->name) | 1613 | return -EINVAL; |
1679 | dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", | ||
1680 | codec->cache_ops->name, codec->name); | ||
1681 | ret = codec->cache_ops->sync(codec); | ||
1682 | if (!ret) | ||
1683 | codec->cache_sync = 0; | ||
1684 | return ret; | ||
1685 | } | ||
1686 | 1614 | ||
1687 | return -EINVAL; | 1615 | if (codec->cache_ops->name) |
1616 | name = codec->cache_ops->name; | ||
1617 | else | ||
1618 | name = "unknown"; | ||
1619 | |||
1620 | if (codec->cache_ops->name) | ||
1621 | dev_dbg(codec->dev, "Syncing %s cache for %s codec\n", | ||
1622 | codec->cache_ops->name, codec->name); | ||
1623 | trace_snd_soc_cache_sync(codec, name, "start"); | ||
1624 | ret = codec->cache_ops->sync(codec); | ||
1625 | if (!ret) | ||
1626 | codec->cache_sync = 0; | ||
1627 | trace_snd_soc_cache_sync(codec, name, "end"); | ||
1628 | return ret; | ||
1688 | } | 1629 | } |
1689 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); | 1630 | EXPORT_SYMBOL_GPL(snd_soc_cache_sync); |
1631 | |||
1632 | static int snd_soc_get_reg_access_index(struct snd_soc_codec *codec, | ||
1633 | unsigned int reg) | ||
1634 | { | ||
1635 | const struct snd_soc_codec_driver *codec_drv; | ||
1636 | unsigned int min, max, index; | ||
1637 | |||
1638 | codec_drv = codec->driver; | ||
1639 | min = 0; | ||
1640 | max = codec_drv->reg_access_size - 1; | ||
1641 | do { | ||
1642 | index = (min + max) / 2; | ||
1643 | if (codec_drv->reg_access_default[index].reg == reg) | ||
1644 | return index; | ||
1645 | if (codec_drv->reg_access_default[index].reg < reg) | ||
1646 | min = index + 1; | ||
1647 | else | ||
1648 | max = index; | ||
1649 | } while (min <= max); | ||
1650 | return -1; | ||
1651 | } | ||
1652 | |||
1653 | int snd_soc_default_volatile_register(struct snd_soc_codec *codec, | ||
1654 | unsigned int reg) | ||
1655 | { | ||
1656 | int index; | ||
1657 | |||
1658 | if (reg >= codec->driver->reg_cache_size) | ||
1659 | return 1; | ||
1660 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1661 | if (index < 0) | ||
1662 | return 0; | ||
1663 | return codec->driver->reg_access_default[index].vol; | ||
1664 | } | ||
1665 | EXPORT_SYMBOL_GPL(snd_soc_default_volatile_register); | ||
1666 | |||
1667 | int snd_soc_default_readable_register(struct snd_soc_codec *codec, | ||
1668 | unsigned int reg) | ||
1669 | { | ||
1670 | int index; | ||
1671 | |||
1672 | if (reg >= codec->driver->reg_cache_size) | ||
1673 | return 1; | ||
1674 | index = snd_soc_get_reg_access_index(codec, reg); | ||
1675 | if (index < 0) | ||
1676 | return 0; | ||
1677 | return codec->driver->reg_access_default[index].read; | ||
1678 | } | ||
1679 | EXPORT_SYMBOL_GPL(snd_soc_default_readable_register); | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index c3f6f1e72790..17efacdb248a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -48,7 +48,8 @@ static DEFINE_MUTEX(pcm_mutex); | |||
48 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); | 48 | static DECLARE_WAIT_QUEUE_HEAD(soc_pm_waitq); |
49 | 49 | ||
50 | #ifdef CONFIG_DEBUG_FS | 50 | #ifdef CONFIG_DEBUG_FS |
51 | static struct dentry *debugfs_root; | 51 | struct dentry *snd_soc_debugfs_root; |
52 | EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | ||
52 | #endif | 53 | #endif |
53 | 54 | ||
54 | static DEFINE_MUTEX(client_mutex); | 55 | static DEFINE_MUTEX(client_mutex); |
@@ -57,8 +58,6 @@ static LIST_HEAD(dai_list); | |||
57 | static LIST_HEAD(platform_list); | 58 | static LIST_HEAD(platform_list); |
58 | static LIST_HEAD(codec_list); | 59 | static LIST_HEAD(codec_list); |
59 | 60 | ||
60 | static int snd_soc_register_card(struct snd_soc_card *card); | ||
61 | static int snd_soc_unregister_card(struct snd_soc_card *card); | ||
62 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); | 61 | static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num); |
63 | 62 | ||
64 | /* | 63 | /* |
@@ -70,10 +69,73 @@ static int pmdown_time = 5000; | |||
70 | module_param(pmdown_time, int, 0); | 69 | module_param(pmdown_time, int, 0); |
71 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); | 70 | MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); |
72 | 71 | ||
72 | /* returns the minimum number of bytes needed to represent | ||
73 | * a particular given value */ | ||
74 | static int min_bytes_needed(unsigned long val) | ||
75 | { | ||
76 | int c = 0; | ||
77 | int i; | ||
78 | |||
79 | for (i = (sizeof val * 8) - 1; i >= 0; --i, ++c) | ||
80 | if (val & (1UL << i)) | ||
81 | break; | ||
82 | c = (sizeof val * 8) - c; | ||
83 | if (!c || (c % 8)) | ||
84 | c = (c + 8) / 8; | ||
85 | else | ||
86 | c /= 8; | ||
87 | return c; | ||
88 | } | ||
89 | |||
90 | /* fill buf which is 'len' bytes with a formatted | ||
91 | * string of the form 'reg: value\n' */ | ||
92 | static int format_register_str(struct snd_soc_codec *codec, | ||
93 | unsigned int reg, char *buf, size_t len) | ||
94 | { | ||
95 | int wordsize = codec->driver->reg_word_size * 2; | ||
96 | int regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; | ||
97 | int ret; | ||
98 | char tmpbuf[len + 1]; | ||
99 | char regbuf[regsize + 1]; | ||
100 | |||
101 | /* since tmpbuf is allocated on the stack, warn the callers if they | ||
102 | * try to abuse this function */ | ||
103 | WARN_ON(len > 63); | ||
104 | |||
105 | /* +2 for ': ' and + 1 for '\n' */ | ||
106 | if (wordsize + regsize + 2 + 1 != len) | ||
107 | return -EINVAL; | ||
108 | |||
109 | ret = snd_soc_read(codec , reg); | ||
110 | if (ret < 0) { | ||
111 | memset(regbuf, 'X', regsize); | ||
112 | regbuf[regsize] = '\0'; | ||
113 | } else { | ||
114 | snprintf(regbuf, regsize + 1, "%.*x", regsize, ret); | ||
115 | } | ||
116 | |||
117 | /* prepare the buffer */ | ||
118 | snprintf(tmpbuf, len + 1, "%.*x: %s\n", wordsize, reg, regbuf); | ||
119 | /* copy it back to the caller without the '\0' */ | ||
120 | memcpy(buf, tmpbuf, len); | ||
121 | |||
122 | return 0; | ||
123 | } | ||
124 | |||
73 | /* codec register dump */ | 125 | /* codec register dump */ |
74 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | 126 | static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf, |
127 | size_t count, loff_t pos) | ||
75 | { | 128 | { |
76 | int ret, i, step = 1, count = 0; | 129 | int i, step = 1; |
130 | int wordsize, regsize; | ||
131 | int len; | ||
132 | size_t total = 0; | ||
133 | loff_t p = 0; | ||
134 | |||
135 | wordsize = codec->driver->reg_word_size * 2; | ||
136 | regsize = min_bytes_needed(codec->driver->reg_cache_size) * 2; | ||
137 | |||
138 | len = wordsize + regsize + 2 + 1; | ||
77 | 139 | ||
78 | if (!codec->driver->reg_cache_size) | 140 | if (!codec->driver->reg_cache_size) |
79 | return 0; | 141 | return 0; |
@@ -81,55 +143,37 @@ static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) | |||
81 | if (codec->driver->reg_cache_step) | 143 | if (codec->driver->reg_cache_step) |
82 | step = codec->driver->reg_cache_step; | 144 | step = codec->driver->reg_cache_step; |
83 | 145 | ||
84 | count += sprintf(buf, "%s registers\n", codec->name); | ||
85 | for (i = 0; i < codec->driver->reg_cache_size; i += step) { | 146 | for (i = 0; i < codec->driver->reg_cache_size; i += step) { |
86 | if (codec->driver->readable_register && !codec->driver->readable_register(i)) | 147 | if (codec->readable_register && !codec->readable_register(codec, i)) |
87 | continue; | 148 | continue; |
88 | |||
89 | count += sprintf(buf + count, "%2x: ", i); | ||
90 | if (count >= PAGE_SIZE - 1) | ||
91 | break; | ||
92 | |||
93 | if (codec->driver->display_register) { | 149 | if (codec->driver->display_register) { |
94 | count += codec->driver->display_register(codec, buf + count, | 150 | count += codec->driver->display_register(codec, buf + count, |
95 | PAGE_SIZE - count, i); | 151 | PAGE_SIZE - count, i); |
96 | } else { | 152 | } else { |
97 | /* If the read fails it's almost certainly due to | 153 | /* only support larger than PAGE_SIZE bytes debugfs |
98 | * the register being volatile and the device being | 154 | * entries for the default case */ |
99 | * powered off. | 155 | if (p >= pos) { |
100 | */ | 156 | if (total + len >= count - 1) |
101 | ret = snd_soc_read(codec, i); | 157 | break; |
102 | if (ret >= 0) | 158 | format_register_str(codec, i, buf + total, len); |
103 | count += snprintf(buf + count, | 159 | total += len; |
104 | PAGE_SIZE - count, | 160 | } |
105 | "%4x", ret); | 161 | p += len; |
106 | else | ||
107 | count += snprintf(buf + count, | ||
108 | PAGE_SIZE - count, | ||
109 | "<no data: %d>", ret); | ||
110 | } | 162 | } |
111 | |||
112 | if (count >= PAGE_SIZE - 1) | ||
113 | break; | ||
114 | |||
115 | count += snprintf(buf + count, PAGE_SIZE - count, "\n"); | ||
116 | if (count >= PAGE_SIZE - 1) | ||
117 | break; | ||
118 | } | 163 | } |
119 | 164 | ||
120 | /* Truncate count; min() would cause a warning */ | 165 | total = min(total, count - 1); |
121 | if (count >= PAGE_SIZE) | ||
122 | count = PAGE_SIZE - 1; | ||
123 | 166 | ||
124 | return count; | 167 | return total; |
125 | } | 168 | } |
169 | |||
126 | static ssize_t codec_reg_show(struct device *dev, | 170 | static ssize_t codec_reg_show(struct device *dev, |
127 | struct device_attribute *attr, char *buf) | 171 | struct device_attribute *attr, char *buf) |
128 | { | 172 | { |
129 | struct snd_soc_pcm_runtime *rtd = | 173 | struct snd_soc_pcm_runtime *rtd = |
130 | container_of(dev, struct snd_soc_pcm_runtime, dev); | 174 | container_of(dev, struct snd_soc_pcm_runtime, dev); |
131 | 175 | ||
132 | return soc_codec_reg_show(rtd->codec, buf); | 176 | return soc_codec_reg_show(rtd->codec, buf, PAGE_SIZE, 0); |
133 | } | 177 | } |
134 | 178 | ||
135 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); | 179 | static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); |
@@ -168,16 +212,28 @@ static int codec_reg_open_file(struct inode *inode, struct file *file) | |||
168 | } | 212 | } |
169 | 213 | ||
170 | static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, | 214 | static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, |
171 | size_t count, loff_t *ppos) | 215 | size_t count, loff_t *ppos) |
172 | { | 216 | { |
173 | ssize_t ret; | 217 | ssize_t ret; |
174 | struct snd_soc_codec *codec = file->private_data; | 218 | struct snd_soc_codec *codec = file->private_data; |
175 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 219 | char *buf; |
220 | |||
221 | if (*ppos < 0 || !count) | ||
222 | return -EINVAL; | ||
223 | |||
224 | buf = kmalloc(count, GFP_KERNEL); | ||
176 | if (!buf) | 225 | if (!buf) |
177 | return -ENOMEM; | 226 | return -ENOMEM; |
178 | ret = soc_codec_reg_show(codec, buf); | 227 | |
179 | if (ret >= 0) | 228 | ret = soc_codec_reg_show(codec, buf, count, *ppos); |
180 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | 229 | if (ret >= 0) { |
230 | if (copy_to_user(user_buf, buf, ret)) { | ||
231 | kfree(buf); | ||
232 | return -EFAULT; | ||
233 | } | ||
234 | *ppos += ret; | ||
235 | } | ||
236 | |||
181 | kfree(buf); | 237 | kfree(buf); |
182 | return ret; | 238 | return ret; |
183 | } | 239 | } |
@@ -209,6 +265,10 @@ static ssize_t codec_reg_write_file(struct file *file, | |||
209 | start++; | 265 | start++; |
210 | if (strict_strtoul(start, 16, &value)) | 266 | if (strict_strtoul(start, 16, &value)) |
211 | return -EINVAL; | 267 | return -EINVAL; |
268 | |||
269 | /* Userspace has been fiddling around behind the kernel's back */ | ||
270 | add_taint(TAINT_USER); | ||
271 | |||
212 | snd_soc_write(codec, reg, value); | 272 | snd_soc_write(codec, reg, value); |
213 | return buf_size; | 273 | return buf_size; |
214 | } | 274 | } |
@@ -232,6 +292,11 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
232 | return; | 292 | return; |
233 | } | 293 | } |
234 | 294 | ||
295 | debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, | ||
296 | &codec->cache_sync); | ||
297 | debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, | ||
298 | &codec->cache_only); | ||
299 | |||
235 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 300 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
236 | codec->debugfs_codec_root, | 301 | codec->debugfs_codec_root, |
237 | codec, &codec_reg_fops); | 302 | codec, &codec_reg_fops); |
@@ -356,7 +421,7 @@ static const struct file_operations platform_list_fops = { | |||
356 | static void soc_init_card_debugfs(struct snd_soc_card *card) | 421 | static void soc_init_card_debugfs(struct snd_soc_card *card) |
357 | { | 422 | { |
358 | card->debugfs_card_root = debugfs_create_dir(card->name, | 423 | card->debugfs_card_root = debugfs_create_dir(card->name, |
359 | debugfs_root); | 424 | snd_soc_debugfs_root); |
360 | if (!card->debugfs_card_root) { | 425 | if (!card->debugfs_card_root) { |
361 | dev_warn(card->dev, | 426 | dev_warn(card->dev, |
362 | "ASoC: Failed to create codec debugfs directory\n"); | 427 | "ASoC: Failed to create codec debugfs directory\n"); |
@@ -435,20 +500,30 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream) | |||
435 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 500 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
436 | int ret; | 501 | int ret; |
437 | 502 | ||
438 | if (codec_dai->driver->symmetric_rates || cpu_dai->driver->symmetric_rates || | 503 | if (!codec_dai->driver->symmetric_rates && |
439 | rtd->dai_link->symmetric_rates) { | 504 | !cpu_dai->driver->symmetric_rates && |
440 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", | 505 | !rtd->dai_link->symmetric_rates) |
441 | rtd->rate); | 506 | return 0; |
442 | 507 | ||
443 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | 508 | /* This can happen if multiple streams are starting simultaneously - |
444 | SNDRV_PCM_HW_PARAM_RATE, | 509 | * the second can need to get its constraints before the first has |
445 | rtd->rate, | 510 | * picked a rate. Complain and allow the application to carry on. |
446 | rtd->rate); | 511 | */ |
447 | if (ret < 0) { | 512 | if (!rtd->rate) { |
448 | dev_err(&rtd->dev, | 513 | dev_warn(&rtd->dev, |
449 | "Unable to apply rate symmetry constraint: %d\n", ret); | 514 | "Not enforcing symmetric_rates due to race\n"); |
450 | return ret; | 515 | return 0; |
451 | } | 516 | } |
517 | |||
518 | dev_dbg(&rtd->dev, "Symmetry forces %dHz rate\n", rtd->rate); | ||
519 | |||
520 | ret = snd_pcm_hw_constraint_minmax(substream->runtime, | ||
521 | SNDRV_PCM_HW_PARAM_RATE, | ||
522 | rtd->rate, rtd->rate); | ||
523 | if (ret < 0) { | ||
524 | dev_err(&rtd->dev, | ||
525 | "Unable to apply rate symmetry constraint: %d\n", ret); | ||
526 | return ret; | ||
452 | } | 527 | } |
453 | 528 | ||
454 | return 0; | 529 | return 0; |
@@ -962,12 +1037,11 @@ static struct snd_pcm_ops soc_pcm_ops = { | |||
962 | .pointer = soc_pcm_pointer, | 1037 | .pointer = soc_pcm_pointer, |
963 | }; | 1038 | }; |
964 | 1039 | ||
965 | #ifdef CONFIG_PM | 1040 | #ifdef CONFIG_PM_SLEEP |
966 | /* powers down audio subsystem for suspend */ | 1041 | /* powers down audio subsystem for suspend */ |
967 | static int soc_suspend(struct device *dev) | 1042 | int snd_soc_suspend(struct device *dev) |
968 | { | 1043 | { |
969 | struct platform_device *pdev = to_platform_device(dev); | 1044 | struct snd_soc_card *card = dev_get_drvdata(dev); |
970 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
971 | struct snd_soc_codec *codec; | 1045 | struct snd_soc_codec *codec; |
972 | int i; | 1046 | int i; |
973 | 1047 | ||
@@ -1008,7 +1082,7 @@ static int soc_suspend(struct device *dev) | |||
1008 | } | 1082 | } |
1009 | 1083 | ||
1010 | if (card->suspend_pre) | 1084 | if (card->suspend_pre) |
1011 | card->suspend_pre(pdev, PMSG_SUSPEND); | 1085 | card->suspend_pre(card); |
1012 | 1086 | ||
1013 | for (i = 0; i < card->num_rtd; i++) { | 1087 | for (i = 0; i < card->num_rtd; i++) { |
1014 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; | 1088 | struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; |
@@ -1075,10 +1149,11 @@ static int soc_suspend(struct device *dev) | |||
1075 | } | 1149 | } |
1076 | 1150 | ||
1077 | if (card->suspend_post) | 1151 | if (card->suspend_post) |
1078 | card->suspend_post(pdev, PMSG_SUSPEND); | 1152 | card->suspend_post(card); |
1079 | 1153 | ||
1080 | return 0; | 1154 | return 0; |
1081 | } | 1155 | } |
1156 | EXPORT_SYMBOL_GPL(snd_soc_suspend); | ||
1082 | 1157 | ||
1083 | /* deferred resume work, so resume can complete before we finished | 1158 | /* deferred resume work, so resume can complete before we finished |
1084 | * setting our codec back up, which can be very slow on I2C | 1159 | * setting our codec back up, which can be very slow on I2C |
@@ -1087,7 +1162,6 @@ static void soc_resume_deferred(struct work_struct *work) | |||
1087 | { | 1162 | { |
1088 | struct snd_soc_card *card = | 1163 | struct snd_soc_card *card = |
1089 | container_of(work, struct snd_soc_card, deferred_resume_work); | 1164 | container_of(work, struct snd_soc_card, deferred_resume_work); |
1090 | struct platform_device *pdev = to_platform_device(card->dev); | ||
1091 | struct snd_soc_codec *codec; | 1165 | struct snd_soc_codec *codec; |
1092 | int i; | 1166 | int i; |
1093 | 1167 | ||
@@ -1101,7 +1175,7 @@ static void soc_resume_deferred(struct work_struct *work) | |||
1101 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); | 1175 | snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D2); |
1102 | 1176 | ||
1103 | if (card->resume_pre) | 1177 | if (card->resume_pre) |
1104 | card->resume_pre(pdev); | 1178 | card->resume_pre(card); |
1105 | 1179 | ||
1106 | /* resume AC97 DAIs */ | 1180 | /* resume AC97 DAIs */ |
1107 | for (i = 0; i < card->num_rtd; i++) { | 1181 | for (i = 0; i < card->num_rtd; i++) { |
@@ -1176,7 +1250,7 @@ static void soc_resume_deferred(struct work_struct *work) | |||
1176 | } | 1250 | } |
1177 | 1251 | ||
1178 | if (card->resume_post) | 1252 | if (card->resume_post) |
1179 | card->resume_post(pdev); | 1253 | card->resume_post(card); |
1180 | 1254 | ||
1181 | dev_dbg(card->dev, "resume work completed\n"); | 1255 | dev_dbg(card->dev, "resume work completed\n"); |
1182 | 1256 | ||
@@ -1185,10 +1259,9 @@ static void soc_resume_deferred(struct work_struct *work) | |||
1185 | } | 1259 | } |
1186 | 1260 | ||
1187 | /* powers up audio subsystem after a suspend */ | 1261 | /* powers up audio subsystem after a suspend */ |
1188 | static int soc_resume(struct device *dev) | 1262 | int snd_soc_resume(struct device *dev) |
1189 | { | 1263 | { |
1190 | struct platform_device *pdev = to_platform_device(dev); | 1264 | struct snd_soc_card *card = dev_get_drvdata(dev); |
1191 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1192 | int i; | 1265 | int i; |
1193 | 1266 | ||
1194 | /* AC97 devices might have other drivers hanging off them so | 1267 | /* AC97 devices might have other drivers hanging off them so |
@@ -1210,9 +1283,10 @@ static int soc_resume(struct device *dev) | |||
1210 | 1283 | ||
1211 | return 0; | 1284 | return 0; |
1212 | } | 1285 | } |
1286 | EXPORT_SYMBOL_GPL(snd_soc_resume); | ||
1213 | #else | 1287 | #else |
1214 | #define soc_suspend NULL | 1288 | #define snd_soc_suspend NULL |
1215 | #define soc_resume NULL | 1289 | #define snd_soc_resume NULL |
1216 | #endif | 1290 | #endif |
1217 | 1291 | ||
1218 | static struct snd_soc_dai_ops null_dai_ops = { | 1292 | static struct snd_soc_dai_ops null_dai_ops = { |
@@ -1400,31 +1474,44 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1400 | struct snd_soc_codec *codec) | 1474 | struct snd_soc_codec *codec) |
1401 | { | 1475 | { |
1402 | int ret = 0; | 1476 | int ret = 0; |
1477 | const struct snd_soc_codec_driver *driver = codec->driver; | ||
1403 | 1478 | ||
1404 | codec->card = card; | 1479 | codec->card = card; |
1405 | codec->dapm.card = card; | 1480 | codec->dapm.card = card; |
1406 | soc_set_name_prefix(card, codec); | 1481 | soc_set_name_prefix(card, codec); |
1407 | 1482 | ||
1408 | if (codec->driver->probe) { | 1483 | if (!try_module_get(codec->dev->driver->owner)) |
1409 | ret = codec->driver->probe(codec); | 1484 | return -ENODEV; |
1485 | |||
1486 | if (driver->probe) { | ||
1487 | ret = driver->probe(codec); | ||
1410 | if (ret < 0) { | 1488 | if (ret < 0) { |
1411 | dev_err(codec->dev, | 1489 | dev_err(codec->dev, |
1412 | "asoc: failed to probe CODEC %s: %d\n", | 1490 | "asoc: failed to probe CODEC %s: %d\n", |
1413 | codec->name, ret); | 1491 | codec->name, ret); |
1414 | return ret; | 1492 | goto err_probe; |
1415 | } | 1493 | } |
1416 | } | 1494 | } |
1417 | 1495 | ||
1496 | if (driver->dapm_widgets) | ||
1497 | snd_soc_dapm_new_controls(&codec->dapm, driver->dapm_widgets, | ||
1498 | driver->num_dapm_widgets); | ||
1499 | if (driver->dapm_routes) | ||
1500 | snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, | ||
1501 | driver->num_dapm_routes); | ||
1502 | |||
1418 | soc_init_codec_debugfs(codec); | 1503 | soc_init_codec_debugfs(codec); |
1419 | 1504 | ||
1420 | /* mark codec as probed and add to card codec list */ | 1505 | /* mark codec as probed and add to card codec list */ |
1421 | if (!try_module_get(codec->dev->driver->owner)) | ||
1422 | return -ENODEV; | ||
1423 | |||
1424 | codec->probed = 1; | 1506 | codec->probed = 1; |
1425 | list_add(&codec->card_list, &card->codec_dev_list); | 1507 | list_add(&codec->card_list, &card->codec_dev_list); |
1426 | list_add(&codec->dapm.list, &card->dapm_list); | 1508 | list_add(&codec->dapm.list, &card->dapm_list); |
1427 | 1509 | ||
1510 | return 0; | ||
1511 | |||
1512 | err_probe: | ||
1513 | module_put(codec->dev->driver->owner); | ||
1514 | |||
1428 | return ret; | 1515 | return ret; |
1429 | } | 1516 | } |
1430 | 1517 | ||
@@ -1468,7 +1555,6 @@ static int soc_post_component_init(struct snd_soc_card *card, | |||
1468 | 1555 | ||
1469 | /* Make sure all DAPM widgets are instantiated */ | 1556 | /* Make sure all DAPM widgets are instantiated */ |
1470 | snd_soc_dapm_new_widgets(&codec->dapm); | 1557 | snd_soc_dapm_new_widgets(&codec->dapm); |
1471 | snd_soc_dapm_sync(&codec->dapm); | ||
1472 | 1558 | ||
1473 | /* register the rtd device */ | 1559 | /* register the rtd device */ |
1474 | rtd->codec = codec; | 1560 | rtd->codec = codec; |
@@ -1543,19 +1629,19 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num) | |||
1543 | 1629 | ||
1544 | /* probe the platform */ | 1630 | /* probe the platform */ |
1545 | if (!platform->probed) { | 1631 | if (!platform->probed) { |
1632 | if (!try_module_get(platform->dev->driver->owner)) | ||
1633 | return -ENODEV; | ||
1634 | |||
1546 | if (platform->driver->probe) { | 1635 | if (platform->driver->probe) { |
1547 | ret = platform->driver->probe(platform); | 1636 | ret = platform->driver->probe(platform); |
1548 | if (ret < 0) { | 1637 | if (ret < 0) { |
1549 | printk(KERN_ERR "asoc: failed to probe platform %s\n", | 1638 | printk(KERN_ERR "asoc: failed to probe platform %s\n", |
1550 | platform->name); | 1639 | platform->name); |
1640 | module_put(platform->dev->driver->owner); | ||
1551 | return ret; | 1641 | return ret; |
1552 | } | 1642 | } |
1553 | } | 1643 | } |
1554 | /* mark platform as probed and add to card platform list */ | 1644 | /* mark platform as probed and add to card platform list */ |
1555 | |||
1556 | if (!try_module_get(platform->dev->driver->owner)) | ||
1557 | return -ENODEV; | ||
1558 | |||
1559 | platform->probed = 1; | 1645 | platform->probed = 1; |
1560 | list_add(&platform->card_list, &card->platform_dev_list); | 1646 | list_add(&platform->card_list, &card->platform_dev_list); |
1561 | } | 1647 | } |
@@ -1713,7 +1799,6 @@ static int snd_soc_init_codec_cache(struct snd_soc_codec *codec, | |||
1713 | 1799 | ||
1714 | static void snd_soc_instantiate_card(struct snd_soc_card *card) | 1800 | static void snd_soc_instantiate_card(struct snd_soc_card *card) |
1715 | { | 1801 | { |
1716 | struct platform_device *pdev = to_platform_device(card->dev); | ||
1717 | struct snd_soc_codec *codec; | 1802 | struct snd_soc_codec *codec; |
1718 | struct snd_soc_codec_conf *codec_conf; | 1803 | struct snd_soc_codec_conf *codec_conf; |
1719 | enum snd_soc_compress_type compress_type; | 1804 | enum snd_soc_compress_type compress_type; |
@@ -1740,6 +1825,8 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1740 | list_for_each_entry(codec, &codec_list, list) { | 1825 | list_for_each_entry(codec, &codec_list, list) { |
1741 | if (codec->cache_init) | 1826 | if (codec->cache_init) |
1742 | continue; | 1827 | continue; |
1828 | /* by default we don't override the compress_type */ | ||
1829 | compress_type = 0; | ||
1743 | /* check to see if we need to override the compress_type */ | 1830 | /* check to see if we need to override the compress_type */ |
1744 | for (i = 0; i < card->num_configs; ++i) { | 1831 | for (i = 0; i < card->num_configs; ++i) { |
1745 | codec_conf = &card->codec_conf[i]; | 1832 | codec_conf = &card->codec_conf[i]; |
@@ -1750,18 +1837,6 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1750 | break; | 1837 | break; |
1751 | } | 1838 | } |
1752 | } | 1839 | } |
1753 | if (i == card->num_configs) { | ||
1754 | /* no need to override the compress_type so | ||
1755 | * go ahead and do the standard thing */ | ||
1756 | ret = snd_soc_init_codec_cache(codec, 0); | ||
1757 | if (ret < 0) { | ||
1758 | mutex_unlock(&card->mutex); | ||
1759 | return; | ||
1760 | } | ||
1761 | continue; | ||
1762 | } | ||
1763 | /* override the compress_type with the one supplied in | ||
1764 | * the machine driver */ | ||
1765 | ret = snd_soc_init_codec_cache(codec, compress_type); | 1840 | ret = snd_soc_init_codec_cache(codec, compress_type); |
1766 | if (ret < 0) { | 1841 | if (ret < 0) { |
1767 | mutex_unlock(&card->mutex); | 1842 | mutex_unlock(&card->mutex); |
@@ -1780,14 +1855,19 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1780 | } | 1855 | } |
1781 | card->snd_card->dev = card->dev; | 1856 | card->snd_card->dev = card->dev; |
1782 | 1857 | ||
1783 | #ifdef CONFIG_PM | 1858 | card->dapm.bias_level = SND_SOC_BIAS_OFF; |
1859 | card->dapm.dev = card->dev; | ||
1860 | card->dapm.card = card; | ||
1861 | list_add(&card->dapm.list, &card->dapm_list); | ||
1862 | |||
1863 | #ifdef CONFIG_PM_SLEEP | ||
1784 | /* deferred resume work */ | 1864 | /* deferred resume work */ |
1785 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); | 1865 | INIT_WORK(&card->deferred_resume_work, soc_resume_deferred); |
1786 | #endif | 1866 | #endif |
1787 | 1867 | ||
1788 | /* initialise the sound card only once */ | 1868 | /* initialise the sound card only once */ |
1789 | if (card->probe) { | 1869 | if (card->probe) { |
1790 | ret = card->probe(pdev); | 1870 | ret = card->probe(card); |
1791 | if (ret < 0) | 1871 | if (ret < 0) |
1792 | goto card_probe_error; | 1872 | goto card_probe_error; |
1793 | } | 1873 | } |
@@ -1810,11 +1890,37 @@ static void snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1810 | } | 1890 | } |
1811 | } | 1891 | } |
1812 | 1892 | ||
1893 | if (card->dapm_widgets) | ||
1894 | snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets, | ||
1895 | card->num_dapm_widgets); | ||
1896 | if (card->dapm_routes) | ||
1897 | snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes, | ||
1898 | card->num_dapm_routes); | ||
1899 | |||
1900 | #ifdef CONFIG_DEBUG_FS | ||
1901 | card->dapm.debugfs_dapm = debugfs_create_dir("dapm", | ||
1902 | card->debugfs_card_root); | ||
1903 | if (!card->dapm.debugfs_dapm) | ||
1904 | printk(KERN_WARNING | ||
1905 | "Failed to create card DAPM debugfs directory\n"); | ||
1906 | |||
1907 | snd_soc_dapm_debugfs_init(&card->dapm); | ||
1908 | #endif | ||
1909 | |||
1813 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), | 1910 | snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname), |
1814 | "%s", card->name); | 1911 | "%s", card->name); |
1815 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), | 1912 | snprintf(card->snd_card->longname, sizeof(card->snd_card->longname), |
1816 | "%s", card->name); | 1913 | "%s", card->name); |
1817 | 1914 | ||
1915 | if (card->late_probe) { | ||
1916 | ret = card->late_probe(card); | ||
1917 | if (ret < 0) { | ||
1918 | dev_err(card->dev, "%s late_probe() failed: %d\n", | ||
1919 | card->name, ret); | ||
1920 | goto probe_aux_dev_err; | ||
1921 | } | ||
1922 | } | ||
1923 | |||
1818 | ret = snd_card_register(card->snd_card); | 1924 | ret = snd_card_register(card->snd_card); |
1819 | if (ret < 0) { | 1925 | if (ret < 0) { |
1820 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); | 1926 | printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name); |
@@ -1848,7 +1954,7 @@ probe_dai_err: | |||
1848 | 1954 | ||
1849 | card_probe_error: | 1955 | card_probe_error: |
1850 | if (card->remove) | 1956 | if (card->remove) |
1851 | card->remove(pdev); | 1957 | card->remove(card); |
1852 | 1958 | ||
1853 | snd_card_free(card->snd_card); | 1959 | snd_card_free(card->snd_card); |
1854 | 1960 | ||
@@ -1872,16 +1978,15 @@ static int soc_probe(struct platform_device *pdev) | |||
1872 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 1978 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
1873 | int ret = 0; | 1979 | int ret = 0; |
1874 | 1980 | ||
1981 | /* | ||
1982 | * no card, so machine driver should be registering card | ||
1983 | * we should not be here in that case so ret error | ||
1984 | */ | ||
1985 | if (!card) | ||
1986 | return -EINVAL; | ||
1987 | |||
1875 | /* Bodge while we unpick instantiation */ | 1988 | /* Bodge while we unpick instantiation */ |
1876 | card->dev = &pdev->dev; | 1989 | card->dev = &pdev->dev; |
1877 | INIT_LIST_HEAD(&card->dai_dev_list); | ||
1878 | INIT_LIST_HEAD(&card->codec_dev_list); | ||
1879 | INIT_LIST_HEAD(&card->platform_dev_list); | ||
1880 | INIT_LIST_HEAD(&card->widgets); | ||
1881 | INIT_LIST_HEAD(&card->paths); | ||
1882 | INIT_LIST_HEAD(&card->dapm_list); | ||
1883 | |||
1884 | soc_init_card_debugfs(card); | ||
1885 | 1990 | ||
1886 | ret = snd_soc_register_card(card); | 1991 | ret = snd_soc_register_card(card); |
1887 | if (ret != 0) { | 1992 | if (ret != 0) { |
@@ -1892,45 +1997,48 @@ static int soc_probe(struct platform_device *pdev) | |||
1892 | return 0; | 1997 | return 0; |
1893 | } | 1998 | } |
1894 | 1999 | ||
1895 | /* removes a socdev */ | 2000 | static int soc_cleanup_card_resources(struct snd_soc_card *card) |
1896 | static int soc_remove(struct platform_device *pdev) | ||
1897 | { | 2001 | { |
1898 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1899 | int i; | 2002 | int i; |
1900 | 2003 | ||
1901 | if (card->instantiated) { | 2004 | /* make sure any delayed work runs */ |
2005 | for (i = 0; i < card->num_rtd; i++) { | ||
2006 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | ||
2007 | flush_delayed_work_sync(&rtd->delayed_work); | ||
2008 | } | ||
1902 | 2009 | ||
1903 | /* make sure any delayed work runs */ | 2010 | /* remove auxiliary devices */ |
1904 | for (i = 0; i < card->num_rtd; i++) { | 2011 | for (i = 0; i < card->num_aux_devs; i++) |
1905 | struct snd_soc_pcm_runtime *rtd = &card->rtd[i]; | 2012 | soc_remove_aux_dev(card, i); |
1906 | flush_delayed_work_sync(&rtd->delayed_work); | ||
1907 | } | ||
1908 | 2013 | ||
1909 | /* remove auxiliary devices */ | 2014 | /* remove and free each DAI */ |
1910 | for (i = 0; i < card->num_aux_devs; i++) | 2015 | for (i = 0; i < card->num_rtd; i++) |
1911 | soc_remove_aux_dev(card, i); | 2016 | soc_remove_dai_link(card, i); |
1912 | 2017 | ||
1913 | /* remove and free each DAI */ | 2018 | soc_cleanup_card_debugfs(card); |
1914 | for (i = 0; i < card->num_rtd; i++) | ||
1915 | soc_remove_dai_link(card, i); | ||
1916 | 2019 | ||
1917 | soc_cleanup_card_debugfs(card); | 2020 | /* remove the card */ |
2021 | if (card->remove) | ||
2022 | card->remove(card); | ||
2023 | |||
2024 | kfree(card->rtd); | ||
2025 | snd_card_free(card->snd_card); | ||
2026 | return 0; | ||
1918 | 2027 | ||
1919 | /* remove the card */ | 2028 | } |
1920 | if (card->remove) | 2029 | |
1921 | card->remove(pdev); | 2030 | /* removes a socdev */ |
2031 | static int soc_remove(struct platform_device *pdev) | ||
2032 | { | ||
2033 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1922 | 2034 | ||
1923 | kfree(card->rtd); | ||
1924 | snd_card_free(card->snd_card); | ||
1925 | } | ||
1926 | snd_soc_unregister_card(card); | 2035 | snd_soc_unregister_card(card); |
1927 | return 0; | 2036 | return 0; |
1928 | } | 2037 | } |
1929 | 2038 | ||
1930 | static int soc_poweroff(struct device *dev) | 2039 | int snd_soc_poweroff(struct device *dev) |
1931 | { | 2040 | { |
1932 | struct platform_device *pdev = to_platform_device(dev); | 2041 | struct snd_soc_card *card = dev_get_drvdata(dev); |
1933 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
1934 | int i; | 2042 | int i; |
1935 | 2043 | ||
1936 | if (!card->instantiated) | 2044 | if (!card->instantiated) |
@@ -1947,11 +2055,12 @@ static int soc_poweroff(struct device *dev) | |||
1947 | 2055 | ||
1948 | return 0; | 2056 | return 0; |
1949 | } | 2057 | } |
2058 | EXPORT_SYMBOL_GPL(snd_soc_poweroff); | ||
1950 | 2059 | ||
1951 | static const struct dev_pm_ops soc_pm_ops = { | 2060 | const struct dev_pm_ops snd_soc_pm_ops = { |
1952 | .suspend = soc_suspend, | 2061 | .suspend = snd_soc_suspend, |
1953 | .resume = soc_resume, | 2062 | .resume = snd_soc_resume, |
1954 | .poweroff = soc_poweroff, | 2063 | .poweroff = snd_soc_poweroff, |
1955 | }; | 2064 | }; |
1956 | 2065 | ||
1957 | /* ASoC platform driver */ | 2066 | /* ASoC platform driver */ |
@@ -1959,7 +2068,7 @@ static struct platform_driver soc_driver = { | |||
1959 | .driver = { | 2068 | .driver = { |
1960 | .name = "soc-audio", | 2069 | .name = "soc-audio", |
1961 | .owner = THIS_MODULE, | 2070 | .owner = THIS_MODULE, |
1962 | .pm = &soc_pm_ops, | 2071 | .pm = &snd_soc_pm_ops, |
1963 | }, | 2072 | }, |
1964 | .probe = soc_probe, | 2073 | .probe = soc_probe, |
1965 | .remove = soc_remove, | 2074 | .remove = soc_remove, |
@@ -2029,10 +2138,11 @@ static int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2029 | * | 2138 | * |
2030 | * Boolean function indiciating if a CODEC register is volatile. | 2139 | * Boolean function indiciating if a CODEC register is volatile. |
2031 | */ | 2140 | */ |
2032 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg) | 2141 | int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, |
2142 | unsigned int reg) | ||
2033 | { | 2143 | { |
2034 | if (codec->driver->volatile_register) | 2144 | if (codec->volatile_register) |
2035 | return codec->driver->volatile_register(reg); | 2145 | return codec->volatile_register(codec, reg); |
2036 | else | 2146 | else |
2037 | return 0; | 2147 | return 0; |
2038 | } | 2148 | } |
@@ -2129,19 +2239,27 @@ EXPORT_SYMBOL_GPL(snd_soc_write); | |||
2129 | * | 2239 | * |
2130 | * Writes new register value. | 2240 | * Writes new register value. |
2131 | * | 2241 | * |
2132 | * Returns 1 for change else 0. | 2242 | * Returns 1 for change, 0 for no change, or negative error code. |
2133 | */ | 2243 | */ |
2134 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, | 2244 | int snd_soc_update_bits(struct snd_soc_codec *codec, unsigned short reg, |
2135 | unsigned int mask, unsigned int value) | 2245 | unsigned int mask, unsigned int value) |
2136 | { | 2246 | { |
2137 | int change; | 2247 | int change; |
2138 | unsigned int old, new; | 2248 | unsigned int old, new; |
2249 | int ret; | ||
2139 | 2250 | ||
2140 | old = snd_soc_read(codec, reg); | 2251 | ret = snd_soc_read(codec, reg); |
2252 | if (ret < 0) | ||
2253 | return ret; | ||
2254 | |||
2255 | old = ret; | ||
2141 | new = (old & ~mask) | value; | 2256 | new = (old & ~mask) | value; |
2142 | change = old != new; | 2257 | change = old != new; |
2143 | if (change) | 2258 | if (change) { |
2144 | snd_soc_write(codec, reg, new); | 2259 | ret = snd_soc_write(codec, reg, new); |
2260 | if (ret < 0) | ||
2261 | return ret; | ||
2262 | } | ||
2145 | 2263 | ||
2146 | return change; | 2264 | return change; |
2147 | } | 2265 | } |
@@ -2226,22 +2344,45 @@ EXPORT_SYMBOL_GPL(snd_soc_set_runtime_hwparams); | |||
2226 | * @_template: control template | 2344 | * @_template: control template |
2227 | * @data: control private data | 2345 | * @data: control private data |
2228 | * @long_name: control long name | 2346 | * @long_name: control long name |
2347 | * @prefix: control name prefix | ||
2229 | * | 2348 | * |
2230 | * Create a new mixer control from a template control. | 2349 | * Create a new mixer control from a template control. |
2231 | * | 2350 | * |
2232 | * Returns 0 for success, else error. | 2351 | * Returns 0 for success, else error. |
2233 | */ | 2352 | */ |
2234 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, | 2353 | struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, |
2235 | void *data, char *long_name) | 2354 | void *data, char *long_name, |
2355 | const char *prefix) | ||
2236 | { | 2356 | { |
2237 | struct snd_kcontrol_new template; | 2357 | struct snd_kcontrol_new template; |
2358 | struct snd_kcontrol *kcontrol; | ||
2359 | char *name = NULL; | ||
2360 | int name_len; | ||
2238 | 2361 | ||
2239 | memcpy(&template, _template, sizeof(template)); | 2362 | memcpy(&template, _template, sizeof(template)); |
2240 | if (long_name) | ||
2241 | template.name = long_name; | ||
2242 | template.index = 0; | 2363 | template.index = 0; |
2243 | 2364 | ||
2244 | return snd_ctl_new1(&template, data); | 2365 | if (!long_name) |
2366 | long_name = template.name; | ||
2367 | |||
2368 | if (prefix) { | ||
2369 | name_len = strlen(long_name) + strlen(prefix) + 2; | ||
2370 | name = kmalloc(name_len, GFP_ATOMIC); | ||
2371 | if (!name) | ||
2372 | return NULL; | ||
2373 | |||
2374 | snprintf(name, name_len, "%s %s", prefix, long_name); | ||
2375 | |||
2376 | template.name = name; | ||
2377 | } else { | ||
2378 | template.name = long_name; | ||
2379 | } | ||
2380 | |||
2381 | kcontrol = snd_ctl_new1(&template, data); | ||
2382 | |||
2383 | kfree(name); | ||
2384 | |||
2385 | return kcontrol; | ||
2245 | } | 2386 | } |
2246 | EXPORT_SYMBOL_GPL(snd_soc_cnew); | 2387 | EXPORT_SYMBOL_GPL(snd_soc_cnew); |
2247 | 2388 | ||
@@ -2260,22 +2401,16 @@ int snd_soc_add_controls(struct snd_soc_codec *codec, | |||
2260 | const struct snd_kcontrol_new *controls, int num_controls) | 2401 | const struct snd_kcontrol_new *controls, int num_controls) |
2261 | { | 2402 | { |
2262 | struct snd_card *card = codec->card->snd_card; | 2403 | struct snd_card *card = codec->card->snd_card; |
2263 | char prefixed_name[44], *name; | ||
2264 | int err, i; | 2404 | int err, i; |
2265 | 2405 | ||
2266 | for (i = 0; i < num_controls; i++) { | 2406 | for (i = 0; i < num_controls; i++) { |
2267 | const struct snd_kcontrol_new *control = &controls[i]; | 2407 | const struct snd_kcontrol_new *control = &controls[i]; |
2268 | if (codec->name_prefix) { | 2408 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, |
2269 | snprintf(prefixed_name, sizeof(prefixed_name), "%s %s", | 2409 | control->name, |
2270 | codec->name_prefix, control->name); | 2410 | codec->name_prefix)); |
2271 | name = prefixed_name; | ||
2272 | } else { | ||
2273 | name = control->name; | ||
2274 | } | ||
2275 | err = snd_ctl_add(card, snd_soc_cnew(control, codec, name)); | ||
2276 | if (err < 0) { | 2411 | if (err < 0) { |
2277 | dev_err(codec->dev, "%s: Failed to add %s: %d\n", | 2412 | dev_err(codec->dev, "%s: Failed to add %s: %d\n", |
2278 | codec->name, name, err); | 2413 | codec->name, control->name, err); |
2279 | return err; | 2414 | return err; |
2280 | } | 2415 | } |
2281 | } | 2416 | } |
@@ -2956,12 +3091,34 @@ int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
2956 | { | 3091 | { |
2957 | if (dai->driver && dai->driver->ops->set_sysclk) | 3092 | if (dai->driver && dai->driver->ops->set_sysclk) |
2958 | return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); | 3093 | return dai->driver->ops->set_sysclk(dai, clk_id, freq, dir); |
3094 | else if (dai->codec && dai->codec->driver->set_sysclk) | ||
3095 | return dai->codec->driver->set_sysclk(dai->codec, clk_id, | ||
3096 | freq, dir); | ||
2959 | else | 3097 | else |
2960 | return -EINVAL; | 3098 | return -EINVAL; |
2961 | } | 3099 | } |
2962 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); | 3100 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); |
2963 | 3101 | ||
2964 | /** | 3102 | /** |
3103 | * snd_soc_codec_set_sysclk - configure CODEC system or master clock. | ||
3104 | * @codec: CODEC | ||
3105 | * @clk_id: DAI specific clock ID | ||
3106 | * @freq: new clock frequency in Hz | ||
3107 | * @dir: new clock direction - input/output. | ||
3108 | * | ||
3109 | * Configures the CODEC master (MCLK) or system (SYSCLK) clocking. | ||
3110 | */ | ||
3111 | int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id, | ||
3112 | unsigned int freq, int dir) | ||
3113 | { | ||
3114 | if (codec->driver->set_sysclk) | ||
3115 | return codec->driver->set_sysclk(codec, clk_id, freq, dir); | ||
3116 | else | ||
3117 | return -EINVAL; | ||
3118 | } | ||
3119 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_sysclk); | ||
3120 | |||
3121 | /** | ||
2965 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. | 3122 | * snd_soc_dai_set_clkdiv - configure DAI clock dividers. |
2966 | * @dai: DAI | 3123 | * @dai: DAI |
2967 | * @div_id: DAI specific clock divider ID | 3124 | * @div_id: DAI specific clock divider ID |
@@ -2997,11 +3154,35 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, | |||
2997 | if (dai->driver && dai->driver->ops->set_pll) | 3154 | if (dai->driver && dai->driver->ops->set_pll) |
2998 | return dai->driver->ops->set_pll(dai, pll_id, source, | 3155 | return dai->driver->ops->set_pll(dai, pll_id, source, |
2999 | freq_in, freq_out); | 3156 | freq_in, freq_out); |
3157 | else if (dai->codec && dai->codec->driver->set_pll) | ||
3158 | return dai->codec->driver->set_pll(dai->codec, pll_id, source, | ||
3159 | freq_in, freq_out); | ||
3000 | else | 3160 | else |
3001 | return -EINVAL; | 3161 | return -EINVAL; |
3002 | } | 3162 | } |
3003 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); | 3163 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); |
3004 | 3164 | ||
3165 | /* | ||
3166 | * snd_soc_codec_set_pll - configure codec PLL. | ||
3167 | * @codec: CODEC | ||
3168 | * @pll_id: DAI specific PLL ID | ||
3169 | * @source: DAI specific source for the PLL | ||
3170 | * @freq_in: PLL input clock frequency in Hz | ||
3171 | * @freq_out: requested PLL output clock frequency in Hz | ||
3172 | * | ||
3173 | * Configures and enables PLL to generate output clock based on input clock. | ||
3174 | */ | ||
3175 | int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source, | ||
3176 | unsigned int freq_in, unsigned int freq_out) | ||
3177 | { | ||
3178 | if (codec->driver->set_pll) | ||
3179 | return codec->driver->set_pll(codec, pll_id, source, | ||
3180 | freq_in, freq_out); | ||
3181 | else | ||
3182 | return -EINVAL; | ||
3183 | } | ||
3184 | EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); | ||
3185 | |||
3005 | /** | 3186 | /** |
3006 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. | 3187 | * snd_soc_dai_set_fmt - configure DAI hardware audio format. |
3007 | * @dai: DAI | 3188 | * @dai: DAI |
@@ -3101,17 +3282,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_digital_mute); | |||
3101 | * | 3282 | * |
3102 | * @card: Card to register | 3283 | * @card: Card to register |
3103 | * | 3284 | * |
3104 | * Note that currently this is an internal only function: it will be | ||
3105 | * exposed to machine drivers after further backporting of ASoC v2 | ||
3106 | * registration APIs. | ||
3107 | */ | 3285 | */ |
3108 | static int snd_soc_register_card(struct snd_soc_card *card) | 3286 | int snd_soc_register_card(struct snd_soc_card *card) |
3109 | { | 3287 | { |
3110 | int i; | 3288 | int i; |
3111 | 3289 | ||
3112 | if (!card->name || !card->dev) | 3290 | if (!card->name || !card->dev) |
3113 | return -EINVAL; | 3291 | return -EINVAL; |
3114 | 3292 | ||
3293 | snd_soc_initialize_card_lists(card); | ||
3294 | |||
3295 | soc_init_card_debugfs(card); | ||
3296 | |||
3115 | card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * | 3297 | card->rtd = kzalloc(sizeof(struct snd_soc_pcm_runtime) * |
3116 | (card->num_links + card->num_aux_devs), | 3298 | (card->num_links + card->num_aux_devs), |
3117 | GFP_KERNEL); | 3299 | GFP_KERNEL); |
@@ -3135,18 +3317,18 @@ static int snd_soc_register_card(struct snd_soc_card *card) | |||
3135 | 3317 | ||
3136 | return 0; | 3318 | return 0; |
3137 | } | 3319 | } |
3320 | EXPORT_SYMBOL_GPL(snd_soc_register_card); | ||
3138 | 3321 | ||
3139 | /** | 3322 | /** |
3140 | * snd_soc_unregister_card - Unregister a card with the ASoC core | 3323 | * snd_soc_unregister_card - Unregister a card with the ASoC core |
3141 | * | 3324 | * |
3142 | * @card: Card to unregister | 3325 | * @card: Card to unregister |
3143 | * | 3326 | * |
3144 | * Note that currently this is an internal only function: it will be | ||
3145 | * exposed to machine drivers after further backporting of ASoC v2 | ||
3146 | * registration APIs. | ||
3147 | */ | 3327 | */ |
3148 | static int snd_soc_unregister_card(struct snd_soc_card *card) | 3328 | int snd_soc_unregister_card(struct snd_soc_card *card) |
3149 | { | 3329 | { |
3330 | if (card->instantiated) | ||
3331 | soc_cleanup_card_resources(card); | ||
3150 | mutex_lock(&client_mutex); | 3332 | mutex_lock(&client_mutex); |
3151 | list_del(&card->list); | 3333 | list_del(&card->list); |
3152 | mutex_unlock(&client_mutex); | 3334 | mutex_unlock(&client_mutex); |
@@ -3154,6 +3336,7 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) | |||
3154 | 3336 | ||
3155 | return 0; | 3337 | return 0; |
3156 | } | 3338 | } |
3339 | EXPORT_SYMBOL_GPL(snd_soc_unregister_card); | ||
3157 | 3340 | ||
3158 | /* | 3341 | /* |
3159 | * Simplify DAI link configuration by removing ".-1" from device names | 3342 | * Simplify DAI link configuration by removing ".-1" from device names |
@@ -3483,9 +3666,12 @@ int snd_soc_register_codec(struct device *dev, | |||
3483 | 3666 | ||
3484 | codec->write = codec_drv->write; | 3667 | codec->write = codec_drv->write; |
3485 | codec->read = codec_drv->read; | 3668 | codec->read = codec_drv->read; |
3669 | codec->volatile_register = codec_drv->volatile_register; | ||
3670 | codec->readable_register = codec_drv->readable_register; | ||
3486 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 3671 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
3487 | codec->dapm.dev = dev; | 3672 | codec->dapm.dev = dev; |
3488 | codec->dapm.codec = codec; | 3673 | codec->dapm.codec = codec; |
3674 | codec->dapm.seq_notifier = codec_drv->seq_notifier; | ||
3489 | codec->dev = dev; | 3675 | codec->dev = dev; |
3490 | codec->driver = codec_drv; | 3676 | codec->driver = codec_drv; |
3491 | codec->num_dai = num_dai; | 3677 | codec->num_dai = num_dai; |
@@ -3494,20 +3680,30 @@ int snd_soc_register_codec(struct device *dev, | |||
3494 | /* allocate CODEC register cache */ | 3680 | /* allocate CODEC register cache */ |
3495 | if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { | 3681 | if (codec_drv->reg_cache_size && codec_drv->reg_word_size) { |
3496 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; | 3682 | reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size; |
3683 | codec->reg_size = reg_size; | ||
3497 | /* it is necessary to make a copy of the default register cache | 3684 | /* it is necessary to make a copy of the default register cache |
3498 | * because in the case of using a compression type that requires | 3685 | * because in the case of using a compression type that requires |
3499 | * the default register cache to be marked as __devinitconst the | 3686 | * the default register cache to be marked as __devinitconst the |
3500 | * kernel might have freed the array by the time we initialize | 3687 | * kernel might have freed the array by the time we initialize |
3501 | * the cache. | 3688 | * the cache. |
3502 | */ | 3689 | */ |
3503 | codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, | 3690 | if (codec_drv->reg_cache_default) { |
3504 | reg_size, GFP_KERNEL); | 3691 | codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default, |
3505 | if (!codec->reg_def_copy) { | 3692 | reg_size, GFP_KERNEL); |
3506 | ret = -ENOMEM; | 3693 | if (!codec->reg_def_copy) { |
3507 | goto fail; | 3694 | ret = -ENOMEM; |
3695 | goto fail; | ||
3696 | } | ||
3508 | } | 3697 | } |
3509 | } | 3698 | } |
3510 | 3699 | ||
3700 | if (codec_drv->reg_access_size && codec_drv->reg_access_default) { | ||
3701 | if (!codec->volatile_register) | ||
3702 | codec->volatile_register = snd_soc_default_volatile_register; | ||
3703 | if (!codec->readable_register) | ||
3704 | codec->readable_register = snd_soc_default_readable_register; | ||
3705 | } | ||
3706 | |||
3511 | for (i = 0; i < num_dai; i++) { | 3707 | for (i = 0; i < num_dai; i++) { |
3512 | fixup_codec_formats(&dai_drv[i].playback); | 3708 | fixup_codec_formats(&dai_drv[i].playback); |
3513 | fixup_codec_formats(&dai_drv[i].capture); | 3709 | fixup_codec_formats(&dai_drv[i].capture); |
@@ -3574,22 +3770,22 @@ EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); | |||
3574 | static int __init snd_soc_init(void) | 3770 | static int __init snd_soc_init(void) |
3575 | { | 3771 | { |
3576 | #ifdef CONFIG_DEBUG_FS | 3772 | #ifdef CONFIG_DEBUG_FS |
3577 | debugfs_root = debugfs_create_dir("asoc", NULL); | 3773 | snd_soc_debugfs_root = debugfs_create_dir("asoc", NULL); |
3578 | if (IS_ERR(debugfs_root) || !debugfs_root) { | 3774 | if (IS_ERR(snd_soc_debugfs_root) || !snd_soc_debugfs_root) { |
3579 | printk(KERN_WARNING | 3775 | printk(KERN_WARNING |
3580 | "ASoC: Failed to create debugfs directory\n"); | 3776 | "ASoC: Failed to create debugfs directory\n"); |
3581 | debugfs_root = NULL; | 3777 | snd_soc_debugfs_root = NULL; |
3582 | } | 3778 | } |
3583 | 3779 | ||
3584 | if (!debugfs_create_file("codecs", 0444, debugfs_root, NULL, | 3780 | if (!debugfs_create_file("codecs", 0444, snd_soc_debugfs_root, NULL, |
3585 | &codec_list_fops)) | 3781 | &codec_list_fops)) |
3586 | pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); | 3782 | pr_warn("ASoC: Failed to create CODEC list debugfs file\n"); |
3587 | 3783 | ||
3588 | if (!debugfs_create_file("dais", 0444, debugfs_root, NULL, | 3784 | if (!debugfs_create_file("dais", 0444, snd_soc_debugfs_root, NULL, |
3589 | &dai_list_fops)) | 3785 | &dai_list_fops)) |
3590 | pr_warn("ASoC: Failed to create DAI list debugfs file\n"); | 3786 | pr_warn("ASoC: Failed to create DAI list debugfs file\n"); |
3591 | 3787 | ||
3592 | if (!debugfs_create_file("platforms", 0444, debugfs_root, NULL, | 3788 | if (!debugfs_create_file("platforms", 0444, snd_soc_debugfs_root, NULL, |
3593 | &platform_list_fops)) | 3789 | &platform_list_fops)) |
3594 | pr_warn("ASoC: Failed to create platform list debugfs file\n"); | 3790 | pr_warn("ASoC: Failed to create platform list debugfs file\n"); |
3595 | #endif | 3791 | #endif |
@@ -3601,7 +3797,7 @@ module_init(snd_soc_init); | |||
3601 | static void __exit snd_soc_exit(void) | 3797 | static void __exit snd_soc_exit(void) |
3602 | { | 3798 | { |
3603 | #ifdef CONFIG_DEBUG_FS | 3799 | #ifdef CONFIG_DEBUG_FS |
3604 | debugfs_remove_recursive(debugfs_root); | 3800 | debugfs_remove_recursive(snd_soc_debugfs_root); |
3605 | #endif | 3801 | #endif |
3606 | platform_driver_unregister(&soc_driver); | 3802 | platform_driver_unregister(&soc_driver); |
3607 | } | 3803 | } |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 1790f83ee665..81c4052c127c 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/moduleparam.h> | 33 | #include <linux/moduleparam.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/async.h> | ||
35 | #include <linux/delay.h> | 36 | #include <linux/delay.h> |
36 | #include <linux/pm.h> | 37 | #include <linux/pm.h> |
37 | #include <linux/bitops.h> | 38 | #include <linux/bitops.h> |
@@ -125,17 +126,17 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( | |||
125 | 126 | ||
126 | /** | 127 | /** |
127 | * snd_soc_dapm_set_bias_level - set the bias level for the system | 128 | * snd_soc_dapm_set_bias_level - set the bias level for the system |
128 | * @card: audio device | 129 | * @dapm: DAPM context |
129 | * @level: level to configure | 130 | * @level: level to configure |
130 | * | 131 | * |
131 | * Configure the bias (power) levels for the SoC audio device. | 132 | * Configure the bias (power) levels for the SoC audio device. |
132 | * | 133 | * |
133 | * Returns 0 for success else error. | 134 | * Returns 0 for success else error. |
134 | */ | 135 | */ |
135 | static int snd_soc_dapm_set_bias_level(struct snd_soc_card *card, | 136 | static int snd_soc_dapm_set_bias_level(struct snd_soc_dapm_context *dapm, |
136 | struct snd_soc_dapm_context *dapm, | ||
137 | enum snd_soc_bias_level level) | 137 | enum snd_soc_bias_level level) |
138 | { | 138 | { |
139 | struct snd_soc_card *card = dapm->card; | ||
139 | int ret = 0; | 140 | int ret = 0; |
140 | 141 | ||
141 | switch (level) { | 142 | switch (level) { |
@@ -365,9 +366,20 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
365 | struct snd_soc_dapm_widget *w) | 366 | struct snd_soc_dapm_widget *w) |
366 | { | 367 | { |
367 | int i, ret = 0; | 368 | int i, ret = 0; |
368 | size_t name_len; | 369 | size_t name_len, prefix_len; |
369 | struct snd_soc_dapm_path *path; | 370 | struct snd_soc_dapm_path *path; |
370 | struct snd_card *card = dapm->codec->card->snd_card; | 371 | struct snd_card *card = dapm->card->snd_card; |
372 | const char *prefix; | ||
373 | |||
374 | if (dapm->codec) | ||
375 | prefix = dapm->codec->name_prefix; | ||
376 | else | ||
377 | prefix = NULL; | ||
378 | |||
379 | if (prefix) | ||
380 | prefix_len = strlen(prefix) + 1; | ||
381 | else | ||
382 | prefix_len = 0; | ||
371 | 383 | ||
372 | /* add kcontrol */ | 384 | /* add kcontrol */ |
373 | for (i = 0; i < w->num_kcontrols; i++) { | 385 | for (i = 0; i < w->num_kcontrols; i++) { |
@@ -396,8 +408,15 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
396 | 408 | ||
397 | switch (w->id) { | 409 | switch (w->id) { |
398 | default: | 410 | default: |
411 | /* The control will get a prefix from | ||
412 | * the control creation process but | ||
413 | * we're also using the same prefix | ||
414 | * for widgets so cut the prefix off | ||
415 | * the front of the widget name. | ||
416 | */ | ||
399 | snprintf(path->long_name, name_len, "%s %s", | 417 | snprintf(path->long_name, name_len, "%s %s", |
400 | w->name, w->kcontrols[i].name); | 418 | w->name + prefix_len, |
419 | w->kcontrols[i].name); | ||
401 | break; | 420 | break; |
402 | case snd_soc_dapm_mixer_named_ctl: | 421 | case snd_soc_dapm_mixer_named_ctl: |
403 | snprintf(path->long_name, name_len, "%s", | 422 | snprintf(path->long_name, name_len, "%s", |
@@ -408,7 +427,7 @@ static int dapm_new_mixer(struct snd_soc_dapm_context *dapm, | |||
408 | path->long_name[name_len - 1] = '\0'; | 427 | path->long_name[name_len - 1] = '\0'; |
409 | 428 | ||
410 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, | 429 | path->kcontrol = snd_soc_cnew(&w->kcontrols[i], w, |
411 | path->long_name); | 430 | path->long_name, prefix); |
412 | ret = snd_ctl_add(card, path->kcontrol); | 431 | ret = snd_ctl_add(card, path->kcontrol); |
413 | if (ret < 0) { | 432 | if (ret < 0) { |
414 | dev_err(dapm->dev, | 433 | dev_err(dapm->dev, |
@@ -429,7 +448,9 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, | |||
429 | { | 448 | { |
430 | struct snd_soc_dapm_path *path = NULL; | 449 | struct snd_soc_dapm_path *path = NULL; |
431 | struct snd_kcontrol *kcontrol; | 450 | struct snd_kcontrol *kcontrol; |
432 | struct snd_card *card = dapm->codec->card->snd_card; | 451 | struct snd_card *card = dapm->card->snd_card; |
452 | const char *prefix; | ||
453 | size_t prefix_len; | ||
433 | int ret = 0; | 454 | int ret = 0; |
434 | 455 | ||
435 | if (!w->num_kcontrols) { | 456 | if (!w->num_kcontrols) { |
@@ -437,7 +458,22 @@ static int dapm_new_mux(struct snd_soc_dapm_context *dapm, | |||
437 | return -EINVAL; | 458 | return -EINVAL; |
438 | } | 459 | } |
439 | 460 | ||
440 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name); | 461 | if (dapm->codec) |
462 | prefix = dapm->codec->name_prefix; | ||
463 | else | ||
464 | prefix = NULL; | ||
465 | |||
466 | if (prefix) | ||
467 | prefix_len = strlen(prefix) + 1; | ||
468 | else | ||
469 | prefix_len = 0; | ||
470 | |||
471 | /* The control will get a prefix from the control creation | ||
472 | * process but we're also using the same prefix for widgets so | ||
473 | * cut the prefix off the front of the widget name. | ||
474 | */ | ||
475 | kcontrol = snd_soc_cnew(&w->kcontrols[0], w, w->name + prefix_len, | ||
476 | prefix); | ||
441 | ret = snd_ctl_add(card, kcontrol); | 477 | ret = snd_ctl_add(card, kcontrol); |
442 | 478 | ||
443 | if (ret < 0) | 479 | if (ret < 0) |
@@ -479,7 +515,7 @@ static inline void dapm_clear_walk(struct snd_soc_dapm_context *dapm) | |||
479 | */ | 515 | */ |
480 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) | 516 | static int snd_soc_dapm_suspend_check(struct snd_soc_dapm_widget *widget) |
481 | { | 517 | { |
482 | int level = snd_power_get_state(widget->dapm->codec->card->snd_card); | 518 | int level = snd_power_get_state(widget->dapm->card->snd_card); |
483 | 519 | ||
484 | switch (level) { | 520 | switch (level) { |
485 | case SNDRV_CTL_POWER_D3hot: | 521 | case SNDRV_CTL_POWER_D3hot: |
@@ -734,10 +770,23 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
734 | 770 | ||
735 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | 771 | static int dapm_seq_compare(struct snd_soc_dapm_widget *a, |
736 | struct snd_soc_dapm_widget *b, | 772 | struct snd_soc_dapm_widget *b, |
737 | int sort[]) | 773 | bool power_up) |
738 | { | 774 | { |
775 | int *sort; | ||
776 | |||
777 | if (power_up) | ||
778 | sort = dapm_up_seq; | ||
779 | else | ||
780 | sort = dapm_down_seq; | ||
781 | |||
739 | if (sort[a->id] != sort[b->id]) | 782 | if (sort[a->id] != sort[b->id]) |
740 | return sort[a->id] - sort[b->id]; | 783 | return sort[a->id] - sort[b->id]; |
784 | if (a->subseq != b->subseq) { | ||
785 | if (power_up) | ||
786 | return a->subseq - b->subseq; | ||
787 | else | ||
788 | return b->subseq - a->subseq; | ||
789 | } | ||
741 | if (a->reg != b->reg) | 790 | if (a->reg != b->reg) |
742 | return a->reg - b->reg; | 791 | return a->reg - b->reg; |
743 | if (a->dapm != b->dapm) | 792 | if (a->dapm != b->dapm) |
@@ -749,12 +798,12 @@ static int dapm_seq_compare(struct snd_soc_dapm_widget *a, | |||
749 | /* Insert a widget in order into a DAPM power sequence. */ | 798 | /* Insert a widget in order into a DAPM power sequence. */ |
750 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, | 799 | static void dapm_seq_insert(struct snd_soc_dapm_widget *new_widget, |
751 | struct list_head *list, | 800 | struct list_head *list, |
752 | int sort[]) | 801 | bool power_up) |
753 | { | 802 | { |
754 | struct snd_soc_dapm_widget *w; | 803 | struct snd_soc_dapm_widget *w; |
755 | 804 | ||
756 | list_for_each_entry(w, list, power_list) | 805 | list_for_each_entry(w, list, power_list) |
757 | if (dapm_seq_compare(new_widget, w, sort) < 0) { | 806 | if (dapm_seq_compare(new_widget, w, power_up) < 0) { |
758 | list_add_tail(&new_widget->power_list, &w->power_list); | 807 | list_add_tail(&new_widget->power_list, &w->power_list); |
759 | return; | 808 | return; |
760 | } | 809 | } |
@@ -865,26 +914,42 @@ static void dapm_seq_run_coalesced(struct snd_soc_dapm_context *dapm, | |||
865 | * handled. | 914 | * handled. |
866 | */ | 915 | */ |
867 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | 916 | static void dapm_seq_run(struct snd_soc_dapm_context *dapm, |
868 | struct list_head *list, int event, int sort[]) | 917 | struct list_head *list, int event, bool power_up) |
869 | { | 918 | { |
870 | struct snd_soc_dapm_widget *w, *n; | 919 | struct snd_soc_dapm_widget *w, *n; |
871 | LIST_HEAD(pending); | 920 | LIST_HEAD(pending); |
872 | int cur_sort = -1; | 921 | int cur_sort = -1; |
922 | int cur_subseq = -1; | ||
873 | int cur_reg = SND_SOC_NOPM; | 923 | int cur_reg = SND_SOC_NOPM; |
874 | struct snd_soc_dapm_context *cur_dapm = NULL; | 924 | struct snd_soc_dapm_context *cur_dapm = NULL; |
875 | int ret; | 925 | int ret, i; |
926 | int *sort; | ||
927 | |||
928 | if (power_up) | ||
929 | sort = dapm_up_seq; | ||
930 | else | ||
931 | sort = dapm_down_seq; | ||
876 | 932 | ||
877 | list_for_each_entry_safe(w, n, list, power_list) { | 933 | list_for_each_entry_safe(w, n, list, power_list) { |
878 | ret = 0; | 934 | ret = 0; |
879 | 935 | ||
880 | /* Do we need to apply any queued changes? */ | 936 | /* Do we need to apply any queued changes? */ |
881 | if (sort[w->id] != cur_sort || w->reg != cur_reg || | 937 | if (sort[w->id] != cur_sort || w->reg != cur_reg || |
882 | w->dapm != cur_dapm) { | 938 | w->dapm != cur_dapm || w->subseq != cur_subseq) { |
883 | if (!list_empty(&pending)) | 939 | if (!list_empty(&pending)) |
884 | dapm_seq_run_coalesced(cur_dapm, &pending); | 940 | dapm_seq_run_coalesced(cur_dapm, &pending); |
885 | 941 | ||
942 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
943 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
944 | if (sort[i] == cur_sort) | ||
945 | cur_dapm->seq_notifier(cur_dapm, | ||
946 | i, | ||
947 | cur_subseq); | ||
948 | } | ||
949 | |||
886 | INIT_LIST_HEAD(&pending); | 950 | INIT_LIST_HEAD(&pending); |
887 | cur_sort = -1; | 951 | cur_sort = -1; |
952 | cur_subseq = -1; | ||
888 | cur_reg = SND_SOC_NOPM; | 953 | cur_reg = SND_SOC_NOPM; |
889 | cur_dapm = NULL; | 954 | cur_dapm = NULL; |
890 | } | 955 | } |
@@ -929,6 +994,7 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
929 | default: | 994 | default: |
930 | /* Queue it up for application */ | 995 | /* Queue it up for application */ |
931 | cur_sort = sort[w->id]; | 996 | cur_sort = sort[w->id]; |
997 | cur_subseq = w->subseq; | ||
932 | cur_reg = w->reg; | 998 | cur_reg = w->reg; |
933 | cur_dapm = w->dapm; | 999 | cur_dapm = w->dapm; |
934 | list_move(&w->power_list, &pending); | 1000 | list_move(&w->power_list, &pending); |
@@ -942,6 +1008,13 @@ static void dapm_seq_run(struct snd_soc_dapm_context *dapm, | |||
942 | 1008 | ||
943 | if (!list_empty(&pending)) | 1009 | if (!list_empty(&pending)) |
944 | dapm_seq_run_coalesced(cur_dapm, &pending); | 1010 | dapm_seq_run_coalesced(cur_dapm, &pending); |
1011 | |||
1012 | if (cur_dapm && cur_dapm->seq_notifier) { | ||
1013 | for (i = 0; i < ARRAY_SIZE(dapm_up_seq); i++) | ||
1014 | if (sort[i] == cur_sort) | ||
1015 | cur_dapm->seq_notifier(cur_dapm, | ||
1016 | i, cur_subseq); | ||
1017 | } | ||
945 | } | 1018 | } |
946 | 1019 | ||
947 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | 1020 | static void dapm_widget_update(struct snd_soc_dapm_context *dapm) |
@@ -977,7 +1050,62 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | |||
977 | } | 1050 | } |
978 | } | 1051 | } |
979 | 1052 | ||
1053 | /* Async callback run prior to DAPM sequences - brings to _PREPARE if | ||
1054 | * they're changing state. | ||
1055 | */ | ||
1056 | static void dapm_pre_sequence_async(void *data, async_cookie_t cookie) | ||
1057 | { | ||
1058 | struct snd_soc_dapm_context *d = data; | ||
1059 | int ret; | ||
980 | 1060 | ||
1061 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | ||
1062 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1063 | if (ret != 0) | ||
1064 | dev_err(d->dev, | ||
1065 | "Failed to turn on bias: %d\n", ret); | ||
1066 | } | ||
1067 | |||
1068 | /* If we're changing to all on or all off then prepare */ | ||
1069 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | ||
1070 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1071 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_PREPARE); | ||
1072 | if (ret != 0) | ||
1073 | dev_err(d->dev, | ||
1074 | "Failed to prepare bias: %d\n", ret); | ||
1075 | } | ||
1076 | } | ||
1077 | |||
1078 | /* Async callback run prior to DAPM sequences - brings to their final | ||
1079 | * state. | ||
1080 | */ | ||
1081 | static void dapm_post_sequence_async(void *data, async_cookie_t cookie) | ||
1082 | { | ||
1083 | struct snd_soc_dapm_context *d = data; | ||
1084 | int ret; | ||
1085 | |||
1086 | /* If we just powered the last thing off drop to standby bias */ | ||
1087 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | ||
1088 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_STANDBY); | ||
1089 | if (ret != 0) | ||
1090 | dev_err(d->dev, "Failed to apply standby bias: %d\n", | ||
1091 | ret); | ||
1092 | } | ||
1093 | |||
1094 | /* If we're in standby and can support bias off then do that */ | ||
1095 | if (d->bias_level == SND_SOC_BIAS_STANDBY && d->idle_bias_off) { | ||
1096 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_OFF); | ||
1097 | if (ret != 0) | ||
1098 | dev_err(d->dev, "Failed to turn off bias: %d\n", ret); | ||
1099 | } | ||
1100 | |||
1101 | /* If we just powered up then move to active bias */ | ||
1102 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | ||
1103 | ret = snd_soc_dapm_set_bias_level(d, SND_SOC_BIAS_ON); | ||
1104 | if (ret != 0) | ||
1105 | dev_err(d->dev, "Failed to apply active bias: %d\n", | ||
1106 | ret); | ||
1107 | } | ||
1108 | } | ||
981 | 1109 | ||
982 | /* | 1110 | /* |
983 | * Scan each dapm widget for complete audio path. | 1111 | * Scan each dapm widget for complete audio path. |
@@ -990,12 +1118,12 @@ static void dapm_widget_update(struct snd_soc_dapm_context *dapm) | |||
990 | */ | 1118 | */ |
991 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | 1119 | static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) |
992 | { | 1120 | { |
993 | struct snd_soc_card *card = dapm->codec->card; | 1121 | struct snd_soc_card *card = dapm->card; |
994 | struct snd_soc_dapm_widget *w; | 1122 | struct snd_soc_dapm_widget *w; |
995 | struct snd_soc_dapm_context *d; | 1123 | struct snd_soc_dapm_context *d; |
996 | LIST_HEAD(up_list); | 1124 | LIST_HEAD(up_list); |
997 | LIST_HEAD(down_list); | 1125 | LIST_HEAD(down_list); |
998 | int ret = 0; | 1126 | LIST_HEAD(async_domain); |
999 | int power; | 1127 | int power; |
1000 | 1128 | ||
1001 | trace_snd_soc_dapm_start(card); | 1129 | trace_snd_soc_dapm_start(card); |
@@ -1010,10 +1138,10 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1010 | list_for_each_entry(w, &card->widgets, list) { | 1138 | list_for_each_entry(w, &card->widgets, list) { |
1011 | switch (w->id) { | 1139 | switch (w->id) { |
1012 | case snd_soc_dapm_pre: | 1140 | case snd_soc_dapm_pre: |
1013 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1141 | dapm_seq_insert(w, &down_list, false); |
1014 | break; | 1142 | break; |
1015 | case snd_soc_dapm_post: | 1143 | case snd_soc_dapm_post: |
1016 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1144 | dapm_seq_insert(w, &up_list, true); |
1017 | break; | 1145 | break; |
1018 | 1146 | ||
1019 | default: | 1147 | default: |
@@ -1033,9 +1161,9 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1033 | trace_snd_soc_dapm_widget_power(w, power); | 1161 | trace_snd_soc_dapm_widget_power(w, power); |
1034 | 1162 | ||
1035 | if (power) | 1163 | if (power) |
1036 | dapm_seq_insert(w, &up_list, dapm_up_seq); | 1164 | dapm_seq_insert(w, &up_list, true); |
1037 | else | 1165 | else |
1038 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 1166 | dapm_seq_insert(w, &down_list, false); |
1039 | 1167 | ||
1040 | w->power = power; | 1168 | w->power = power; |
1041 | break; | 1169 | break; |
@@ -1073,65 +1201,25 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1073 | } | 1201 | } |
1074 | } | 1202 | } |
1075 | 1203 | ||
1076 | list_for_each_entry(d, &dapm->card->dapm_list, list) { | 1204 | /* Run all the bias changes in parallel */ |
1077 | if (d->dev_power && d->bias_level == SND_SOC_BIAS_OFF) { | 1205 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
1078 | ret = snd_soc_dapm_set_bias_level(card, d, | 1206 | async_schedule_domain(dapm_pre_sequence_async, d, |
1079 | SND_SOC_BIAS_STANDBY); | 1207 | &async_domain); |
1080 | if (ret != 0) | 1208 | async_synchronize_full_domain(&async_domain); |
1081 | dev_err(d->dev, | ||
1082 | "Failed to turn on bias: %d\n", ret); | ||
1083 | } | ||
1084 | |||
1085 | /* If we're changing to all on or all off then prepare */ | ||
1086 | if ((d->dev_power && d->bias_level == SND_SOC_BIAS_STANDBY) || | ||
1087 | (!d->dev_power && d->bias_level == SND_SOC_BIAS_ON)) { | ||
1088 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1089 | SND_SOC_BIAS_PREPARE); | ||
1090 | if (ret != 0) | ||
1091 | dev_err(d->dev, | ||
1092 | "Failed to prepare bias: %d\n", ret); | ||
1093 | } | ||
1094 | } | ||
1095 | 1209 | ||
1096 | /* Power down widgets first; try to avoid amplifying pops. */ | 1210 | /* Power down widgets first; try to avoid amplifying pops. */ |
1097 | dapm_seq_run(dapm, &down_list, event, dapm_down_seq); | 1211 | dapm_seq_run(dapm, &down_list, event, false); |
1098 | 1212 | ||
1099 | dapm_widget_update(dapm); | 1213 | dapm_widget_update(dapm); |
1100 | 1214 | ||
1101 | /* Now power up. */ | 1215 | /* Now power up. */ |
1102 | dapm_seq_run(dapm, &up_list, event, dapm_up_seq); | 1216 | dapm_seq_run(dapm, &up_list, event, true); |
1103 | |||
1104 | list_for_each_entry(d, &dapm->card->dapm_list, list) { | ||
1105 | /* If we just powered the last thing off drop to standby bias */ | ||
1106 | if (d->bias_level == SND_SOC_BIAS_PREPARE && !d->dev_power) { | ||
1107 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1108 | SND_SOC_BIAS_STANDBY); | ||
1109 | if (ret != 0) | ||
1110 | dev_err(d->dev, | ||
1111 | "Failed to apply standby bias: %d\n", | ||
1112 | ret); | ||
1113 | } | ||
1114 | 1217 | ||
1115 | /* If we're in standby and can support bias off then do that */ | 1218 | /* Run all the bias changes in parallel */ |
1116 | if (d->bias_level == SND_SOC_BIAS_STANDBY && | 1219 | list_for_each_entry(d, &dapm->card->dapm_list, list) |
1117 | d->idle_bias_off) { | 1220 | async_schedule_domain(dapm_post_sequence_async, d, |
1118 | ret = snd_soc_dapm_set_bias_level(card, d, | 1221 | &async_domain); |
1119 | SND_SOC_BIAS_OFF); | 1222 | async_synchronize_full_domain(&async_domain); |
1120 | if (ret != 0) | ||
1121 | dev_err(d->dev, | ||
1122 | "Failed to turn off bias: %d\n", ret); | ||
1123 | } | ||
1124 | |||
1125 | /* If we just powered up then move to active bias */ | ||
1126 | if (d->bias_level == SND_SOC_BIAS_PREPARE && d->dev_power) { | ||
1127 | ret = snd_soc_dapm_set_bias_level(card, d, | ||
1128 | SND_SOC_BIAS_ON); | ||
1129 | if (ret != 0) | ||
1130 | dev_err(d->dev, | ||
1131 | "Failed to apply active bias: %d\n", | ||
1132 | ret); | ||
1133 | } | ||
1134 | } | ||
1135 | 1223 | ||
1136 | pop_dbg(dapm->dev, card->pop_time, | 1224 | pop_dbg(dapm->dev, card->pop_time, |
1137 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); | 1225 | "DAPM sequencing finished, waiting %dms\n", card->pop_time); |
@@ -1189,7 +1277,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1189 | 1277 | ||
1190 | if (p->connect) | 1278 | if (p->connect) |
1191 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1279 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1192 | " in %s %s\n", | 1280 | " in \"%s\" \"%s\"\n", |
1193 | p->name ? p->name : "static", | 1281 | p->name ? p->name : "static", |
1194 | p->source->name); | 1282 | p->source->name); |
1195 | } | 1283 | } |
@@ -1199,7 +1287,7 @@ static ssize_t dapm_widget_power_read_file(struct file *file, | |||
1199 | 1287 | ||
1200 | if (p->connect) | 1288 | if (p->connect) |
1201 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | 1289 | ret += snprintf(buf + ret, PAGE_SIZE - ret, |
1202 | " out %s %s\n", | 1290 | " out \"%s\" \"%s\"\n", |
1203 | p->name ? p->name : "static", | 1291 | p->name ? p->name : "static", |
1204 | p->sink->name); | 1292 | p->sink->name); |
1205 | } | 1293 | } |
@@ -1464,7 +1552,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
1464 | char prefixed_source[80]; | 1552 | char prefixed_source[80]; |
1465 | int ret = 0; | 1553 | int ret = 0; |
1466 | 1554 | ||
1467 | if (dapm->codec->name_prefix) { | 1555 | if (dapm->codec && dapm->codec->name_prefix) { |
1468 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | 1556 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", |
1469 | dapm->codec->name_prefix, route->sink); | 1557 | dapm->codec->name_prefix, route->sink); |
1470 | sink = prefixed_sink; | 1558 | sink = prefixed_sink; |
@@ -2114,14 +2202,14 @@ int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2114 | return -ENOMEM; | 2202 | return -ENOMEM; |
2115 | 2203 | ||
2116 | name_len = strlen(widget->name) + 1; | 2204 | name_len = strlen(widget->name) + 1; |
2117 | if (dapm->codec->name_prefix) | 2205 | if (dapm->codec && dapm->codec->name_prefix) |
2118 | name_len += 1 + strlen(dapm->codec->name_prefix); | 2206 | name_len += 1 + strlen(dapm->codec->name_prefix); |
2119 | w->name = kmalloc(name_len, GFP_KERNEL); | 2207 | w->name = kmalloc(name_len, GFP_KERNEL); |
2120 | if (w->name == NULL) { | 2208 | if (w->name == NULL) { |
2121 | kfree(w); | 2209 | kfree(w); |
2122 | return -ENOMEM; | 2210 | return -ENOMEM; |
2123 | } | 2211 | } |
2124 | if (dapm->codec->name_prefix) | 2212 | if (dapm->codec && dapm->codec->name_prefix) |
2125 | snprintf(w->name, name_len, "%s %s", | 2213 | snprintf(w->name, name_len, "%s %s", |
2126 | dapm->codec->name_prefix, widget->name); | 2214 | dapm->codec->name_prefix, widget->name); |
2127 | else | 2215 | else |
@@ -2226,7 +2314,6 @@ int snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, | |||
2226 | mutex_unlock(&codec->mutex); | 2314 | mutex_unlock(&codec->mutex); |
2227 | return 0; | 2315 | return 0; |
2228 | } | 2316 | } |
2229 | EXPORT_SYMBOL_GPL(snd_soc_dapm_stream_event); | ||
2230 | 2317 | ||
2231 | /** | 2318 | /** |
2232 | * snd_soc_dapm_enable_pin - enable pin. | 2319 | * snd_soc_dapm_enable_pin - enable pin. |
@@ -2393,7 +2480,7 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
2393 | if (w->dapm != dapm) | 2480 | if (w->dapm != dapm) |
2394 | continue; | 2481 | continue; |
2395 | if (w->power) { | 2482 | if (w->power) { |
2396 | dapm_seq_insert(w, &down_list, dapm_down_seq); | 2483 | dapm_seq_insert(w, &down_list, false); |
2397 | w->power = 0; | 2484 | w->power = 0; |
2398 | powerdown = 1; | 2485 | powerdown = 1; |
2399 | } | 2486 | } |
@@ -2403,9 +2490,9 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
2403 | * standby. | 2490 | * standby. |
2404 | */ | 2491 | */ |
2405 | if (powerdown) { | 2492 | if (powerdown) { |
2406 | snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_PREPARE); | 2493 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_PREPARE); |
2407 | dapm_seq_run(dapm, &down_list, 0, dapm_down_seq); | 2494 | dapm_seq_run(dapm, &down_list, 0, false); |
2408 | snd_soc_dapm_set_bias_level(NULL, dapm, SND_SOC_BIAS_STANDBY); | 2495 | snd_soc_dapm_set_bias_level(dapm, SND_SOC_BIAS_STANDBY); |
2409 | } | 2496 | } |
2410 | } | 2497 | } |
2411 | 2498 | ||
@@ -2418,7 +2505,7 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card) | |||
2418 | 2505 | ||
2419 | list_for_each_entry(codec, &card->codec_dev_list, list) { | 2506 | list_for_each_entry(codec, &card->codec_dev_list, list) { |
2420 | soc_dapm_shutdown_codec(&codec->dapm); | 2507 | soc_dapm_shutdown_codec(&codec->dapm); |
2421 | snd_soc_dapm_set_bias_level(card, &codec->dapm, SND_SOC_BIAS_OFF); | 2508 | snd_soc_dapm_set_bias_level(&codec->dapm, SND_SOC_BIAS_OFF); |
2422 | } | 2509 | } |
2423 | } | 2510 | } |
2424 | 2511 | ||
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c index ac5a5bc7375a..fcab80b36a37 100644 --- a/sound/soc/soc-jack.c +++ b/sound/soc/soc-jack.c | |||
@@ -37,6 +37,7 @@ int snd_soc_jack_new(struct snd_soc_codec *codec, const char *id, int type, | |||
37 | { | 37 | { |
38 | jack->codec = codec; | 38 | jack->codec = codec; |
39 | INIT_LIST_HEAD(&jack->pins); | 39 | INIT_LIST_HEAD(&jack->pins); |
40 | INIT_LIST_HEAD(&jack->jack_zones); | ||
40 | BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); | 41 | BLOCKING_INIT_NOTIFIER_HEAD(&jack->notifier); |
41 | 42 | ||
42 | return snd_jack_new(codec->card->snd_card, id, type, &jack->jack); | 43 | return snd_jack_new(codec->card->snd_card, id, type, &jack->jack); |
@@ -100,7 +101,7 @@ void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask) | |||
100 | } | 101 | } |
101 | 102 | ||
102 | /* Report before the DAPM sync to help users updating micbias status */ | 103 | /* Report before the DAPM sync to help users updating micbias status */ |
103 | blocking_notifier_call_chain(&jack->notifier, status, NULL); | 104 | blocking_notifier_call_chain(&jack->notifier, status, jack); |
104 | 105 | ||
105 | snd_soc_dapm_sync(dapm); | 106 | snd_soc_dapm_sync(dapm); |
106 | 107 | ||
@@ -112,6 +113,51 @@ out: | |||
112 | EXPORT_SYMBOL_GPL(snd_soc_jack_report); | 113 | EXPORT_SYMBOL_GPL(snd_soc_jack_report); |
113 | 114 | ||
114 | /** | 115 | /** |
116 | * snd_soc_jack_add_zones - Associate voltage zones with jack | ||
117 | * | ||
118 | * @jack: ASoC jack | ||
119 | * @count: Number of zones | ||
120 | * @zone: Array of zones | ||
121 | * | ||
122 | * After this function has been called the zones specified in the | ||
123 | * array will be associated with the jack. | ||
124 | */ | ||
125 | int snd_soc_jack_add_zones(struct snd_soc_jack *jack, int count, | ||
126 | struct snd_soc_jack_zone *zones) | ||
127 | { | ||
128 | int i; | ||
129 | |||
130 | for (i = 0; i < count; i++) { | ||
131 | INIT_LIST_HEAD(&zones[i].list); | ||
132 | list_add(&(zones[i].list), &jack->jack_zones); | ||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | EXPORT_SYMBOL_GPL(snd_soc_jack_add_zones); | ||
137 | |||
138 | /** | ||
139 | * snd_soc_jack_get_type - Based on the mic bias value, this function returns | ||
140 | * the type of jack from the zones delcared in the jack type | ||
141 | * | ||
142 | * @micbias_voltage: mic bias voltage at adc channel when jack is plugged in | ||
143 | * | ||
144 | * Based on the mic bias value passed, this function helps identify | ||
145 | * the type of jack from the already delcared jack zones | ||
146 | */ | ||
147 | int snd_soc_jack_get_type(struct snd_soc_jack *jack, int micbias_voltage) | ||
148 | { | ||
149 | struct snd_soc_jack_zone *zone; | ||
150 | |||
151 | list_for_each_entry(zone, &jack->jack_zones, list) { | ||
152 | if (micbias_voltage >= zone->min_mv && | ||
153 | micbias_voltage < zone->max_mv) | ||
154 | return zone->jack_type; | ||
155 | } | ||
156 | return 0; | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(snd_soc_jack_get_type); | ||
159 | |||
160 | /** | ||
115 | * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack | 161 | * snd_soc_jack_add_pins - Associate DAPM pins with an ASoC jack |
116 | * | 162 | * |
117 | * @jack: ASoC jack | 163 | * @jack: ASoC jack |
@@ -194,7 +240,7 @@ static void snd_soc_jack_gpio_detect(struct snd_soc_jack_gpio *gpio) | |||
194 | int enable; | 240 | int enable; |
195 | int report; | 241 | int report; |
196 | 242 | ||
197 | enable = gpio_get_value(gpio->gpio); | 243 | enable = gpio_get_value_cansleep(gpio->gpio); |
198 | if (gpio->invert) | 244 | if (gpio->invert) |
199 | enable = !enable; | 245 | enable = !enable; |
200 | 246 | ||
@@ -284,6 +330,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count, | |||
284 | if (ret) | 330 | if (ret) |
285 | goto err; | 331 | goto err; |
286 | 332 | ||
333 | if (gpios[i].wake) { | ||
334 | ret = set_irq_wake(gpio_to_irq(gpios[i].gpio), 1); | ||
335 | if (ret != 0) | ||
336 | printk(KERN_ERR | ||
337 | "Failed to mark GPIO %d as wake source: %d\n", | ||
338 | gpios[i].gpio, ret); | ||
339 | } | ||
340 | |||
287 | #ifdef CONFIG_GPIO_SYSFS | 341 | #ifdef CONFIG_GPIO_SYSFS |
288 | /* Expose GPIO value over sysfs for diagnostic purposes */ | 342 | /* Expose GPIO value over sysfs for diagnostic purposes */ |
289 | gpio_export(gpios[i].gpio, false); | 343 | gpio_export(gpios[i].gpio, false); |
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index 1d07b931f3d8..3f45e6a439bf 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c | |||
@@ -28,26 +28,9 @@ int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params) | |||
28 | { | 28 | { |
29 | int sample_size; | 29 | int sample_size; |
30 | 30 | ||
31 | switch (params_format(params)) { | 31 | sample_size = snd_pcm_format_width(params_format(params)); |
32 | case SNDRV_PCM_FORMAT_S16_LE: | 32 | if (sample_size < 0) |
33 | case SNDRV_PCM_FORMAT_S16_BE: | 33 | return sample_size; |
34 | sample_size = 16; | ||
35 | break; | ||
36 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
37 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
38 | sample_size = 20; | ||
39 | break; | ||
40 | case SNDRV_PCM_FORMAT_S24_LE: | ||
41 | case SNDRV_PCM_FORMAT_S24_BE: | ||
42 | sample_size = 24; | ||
43 | break; | ||
44 | case SNDRV_PCM_FORMAT_S32_LE: | ||
45 | case SNDRV_PCM_FORMAT_S32_BE: | ||
46 | sample_size = 32; | ||
47 | break; | ||
48 | default: | ||
49 | return -ENOTSUPP; | ||
50 | } | ||
51 | 34 | ||
52 | return snd_soc_calc_frame_size(sample_size, params_channels(params), | 35 | return snd_soc_calc_frame_size(sample_size, params_channels(params), |
53 | 1); | 36 | 1); |
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig new file mode 100644 index 000000000000..66b504f06c23 --- /dev/null +++ b/sound/soc/tegra/Kconfig | |||
@@ -0,0 +1,26 @@ | |||
1 | config SND_TEGRA_SOC | ||
2 | tristate "SoC Audio for the Tegra System-on-Chip" | ||
3 | depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA | ||
4 | default m | ||
5 | help | ||
6 | Say Y or M here if you want support for SoC audio on Tegra. | ||
7 | |||
8 | config SND_TEGRA_SOC_I2S | ||
9 | tristate | ||
10 | depends on SND_TEGRA_SOC | ||
11 | default m | ||
12 | help | ||
13 | Say Y or M if you want to add support for codecs attached to the | ||
14 | Tegra I2S interface. You will also need to select the individual | ||
15 | machine drivers to support below. | ||
16 | |||
17 | config SND_TEGRA_SOC_HARMONY | ||
18 | tristate "SoC Audio support for Tegra Harmony reference board" | ||
19 | depends on SND_TEGRA_SOC && MACH_HARMONY && I2C | ||
20 | default m | ||
21 | select SND_TEGRA_SOC_I2S | ||
22 | select SND_SOC_WM8903 | ||
23 | help | ||
24 | Say Y or M here if you want to add support for SoC audio on the | ||
25 | Tegra Harmony reference board. | ||
26 | |||
diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile new file mode 100644 index 000000000000..fd183d3ab4f1 --- /dev/null +++ b/sound/soc/tegra/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | # Tegra platform Support | ||
2 | snd-soc-tegra-das-objs := tegra_das.o | ||
3 | snd-soc-tegra-pcm-objs := tegra_pcm.o | ||
4 | snd-soc-tegra-i2s-objs := tegra_i2s.o | ||
5 | snd-soc-tegra-utils-objs += tegra_asoc_utils.o | ||
6 | |||
7 | obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-utils.o | ||
8 | obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-das.o | ||
9 | obj-$(CONFIG_SND_TEGRA_SOC) += snd-soc-tegra-pcm.o | ||
10 | obj-$(CONFIG_SND_TEGRA_SOC_I2S) += snd-soc-tegra-i2s.o | ||
11 | |||
12 | # Tegra machine Support | ||
13 | snd-soc-tegra-harmony-objs := harmony.o | ||
14 | |||
15 | obj-$(CONFIG_SND_TEGRA_SOC_HARMONY) += snd-soc-tegra-harmony.o | ||
diff --git a/sound/soc/tegra/harmony.c b/sound/soc/tegra/harmony.c new file mode 100644 index 000000000000..8585957477eb --- /dev/null +++ b/sound/soc/tegra/harmony.c | |||
@@ -0,0 +1,393 @@ | |||
1 | /* | ||
2 | * harmony.c - Harmony machine ASoC driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010-2011 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * (c) 2009, 2010 Nvidia Graphics Pvt. Ltd. | ||
10 | * | ||
11 | * Copyright 2007 Wolfson Microelectronics PLC. | ||
12 | * Author: Graeme Gregory | ||
13 | * graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include <linux/module.h> | ||
34 | #include <linux/platform_device.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/gpio.h> | ||
37 | |||
38 | #include <mach/harmony_audio.h> | ||
39 | |||
40 | #include <sound/core.h> | ||
41 | #include <sound/jack.h> | ||
42 | #include <sound/pcm.h> | ||
43 | #include <sound/pcm_params.h> | ||
44 | #include <sound/soc.h> | ||
45 | |||
46 | #include "../codecs/wm8903.h" | ||
47 | |||
48 | #include "tegra_das.h" | ||
49 | #include "tegra_i2s.h" | ||
50 | #include "tegra_pcm.h" | ||
51 | #include "tegra_asoc_utils.h" | ||
52 | |||
53 | #define DRV_NAME "tegra-snd-harmony" | ||
54 | |||
55 | #define GPIO_SPKR_EN BIT(0) | ||
56 | #define GPIO_INT_MIC_EN BIT(1) | ||
57 | #define GPIO_EXT_MIC_EN BIT(2) | ||
58 | |||
59 | struct tegra_harmony { | ||
60 | struct tegra_asoc_utils_data util_data; | ||
61 | struct harmony_audio_platform_data *pdata; | ||
62 | int gpio_requested; | ||
63 | }; | ||
64 | |||
65 | static int harmony_asoc_hw_params(struct snd_pcm_substream *substream, | ||
66 | struct snd_pcm_hw_params *params) | ||
67 | { | ||
68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
69 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
70 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
71 | struct snd_soc_codec *codec = rtd->codec; | ||
72 | struct snd_soc_card *card = codec->card; | ||
73 | struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); | ||
74 | int srate, mclk, mclk_change; | ||
75 | int err; | ||
76 | |||
77 | srate = params_rate(params); | ||
78 | switch (srate) { | ||
79 | case 64000: | ||
80 | case 88200: | ||
81 | case 96000: | ||
82 | mclk = 128 * srate; | ||
83 | break; | ||
84 | default: | ||
85 | mclk = 256 * srate; | ||
86 | break; | ||
87 | } | ||
88 | /* FIXME: Codec only requires >= 3MHz if OSR==0 */ | ||
89 | while (mclk < 6000000) | ||
90 | mclk *= 2; | ||
91 | |||
92 | err = tegra_asoc_utils_set_rate(&harmony->util_data, srate, mclk, | ||
93 | &mclk_change); | ||
94 | if (err < 0) { | ||
95 | dev_err(card->dev, "Can't configure clocks\n"); | ||
96 | return err; | ||
97 | } | ||
98 | |||
99 | err = snd_soc_dai_set_fmt(codec_dai, | ||
100 | SND_SOC_DAIFMT_I2S | | ||
101 | SND_SOC_DAIFMT_NB_NF | | ||
102 | SND_SOC_DAIFMT_CBS_CFS); | ||
103 | if (err < 0) { | ||
104 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
105 | return err; | ||
106 | } | ||
107 | |||
108 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
109 | SND_SOC_DAIFMT_I2S | | ||
110 | SND_SOC_DAIFMT_NB_NF | | ||
111 | SND_SOC_DAIFMT_CBS_CFS); | ||
112 | if (err < 0) { | ||
113 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | if (mclk_change) { | ||
118 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | ||
119 | SND_SOC_CLOCK_IN); | ||
120 | if (err < 0) { | ||
121 | dev_err(card->dev, "codec_dai clock not set\n"); | ||
122 | return err; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static struct snd_soc_ops harmony_asoc_ops = { | ||
130 | .hw_params = harmony_asoc_hw_params, | ||
131 | }; | ||
132 | |||
133 | static struct snd_soc_jack harmony_hp_jack; | ||
134 | |||
135 | static struct snd_soc_jack_pin harmony_hp_jack_pins[] = { | ||
136 | { | ||
137 | .pin = "Headphone Jack", | ||
138 | .mask = SND_JACK_HEADPHONE, | ||
139 | }, | ||
140 | }; | ||
141 | |||
142 | static struct snd_soc_jack_gpio harmony_hp_jack_gpios[] = { | ||
143 | { | ||
144 | .name = "headphone detect", | ||
145 | .report = SND_JACK_HEADPHONE, | ||
146 | .debounce_time = 150, | ||
147 | .invert = 1, | ||
148 | } | ||
149 | }; | ||
150 | |||
151 | static struct snd_soc_jack harmony_mic_jack; | ||
152 | |||
153 | static struct snd_soc_jack_pin harmony_mic_jack_pins[] = { | ||
154 | { | ||
155 | .pin = "Mic Jack", | ||
156 | .mask = SND_JACK_MICROPHONE, | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | static int harmony_event_int_spk(struct snd_soc_dapm_widget *w, | ||
161 | struct snd_kcontrol *k, int event) | ||
162 | { | ||
163 | struct snd_soc_codec *codec = w->codec; | ||
164 | struct snd_soc_card *card = codec->card; | ||
165 | struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); | ||
166 | struct harmony_audio_platform_data *pdata = harmony->pdata; | ||
167 | |||
168 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | ||
169 | SND_SOC_DAPM_EVENT_ON(event)); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct snd_soc_dapm_widget harmony_dapm_widgets[] = { | ||
175 | SND_SOC_DAPM_SPK("Int Spk", harmony_event_int_spk), | ||
176 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
177 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
178 | }; | ||
179 | |||
180 | static const struct snd_soc_dapm_route harmony_audio_map[] = { | ||
181 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
182 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
183 | {"Int Spk", NULL, "ROP"}, | ||
184 | {"Int Spk", NULL, "RON"}, | ||
185 | {"Int Spk", NULL, "LOP"}, | ||
186 | {"Int Spk", NULL, "LON"}, | ||
187 | {"Mic Bias", NULL, "Mic Jack"}, | ||
188 | {"IN1L", NULL, "Mic Bias"}, | ||
189 | }; | ||
190 | |||
191 | static const struct snd_kcontrol_new harmony_controls[] = { | ||
192 | SOC_DAPM_PIN_SWITCH("Int Spk"), | ||
193 | }; | ||
194 | |||
195 | static int harmony_asoc_init(struct snd_soc_pcm_runtime *rtd) | ||
196 | { | ||
197 | struct snd_soc_codec *codec = rtd->codec; | ||
198 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
199 | struct snd_soc_card *card = codec->card; | ||
200 | struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); | ||
201 | struct harmony_audio_platform_data *pdata = harmony->pdata; | ||
202 | int ret; | ||
203 | |||
204 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
205 | if (ret) { | ||
206 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
207 | return ret; | ||
208 | } | ||
209 | harmony->gpio_requested |= GPIO_SPKR_EN; | ||
210 | |||
211 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
212 | |||
213 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
214 | if (ret) { | ||
215 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
216 | return ret; | ||
217 | } | ||
218 | harmony->gpio_requested |= GPIO_INT_MIC_EN; | ||
219 | |||
220 | /* Disable int mic; enable signal is active-high */ | ||
221 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
222 | |||
223 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
224 | if (ret) { | ||
225 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
226 | return ret; | ||
227 | } | ||
228 | harmony->gpio_requested |= GPIO_EXT_MIC_EN; | ||
229 | |||
230 | /* Enable ext mic; enable signal is active-low */ | ||
231 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
232 | |||
233 | ret = snd_soc_add_controls(codec, harmony_controls, | ||
234 | ARRAY_SIZE(harmony_controls)); | ||
235 | if (ret < 0) | ||
236 | return ret; | ||
237 | |||
238 | snd_soc_dapm_new_controls(dapm, harmony_dapm_widgets, | ||
239 | ARRAY_SIZE(harmony_dapm_widgets)); | ||
240 | |||
241 | snd_soc_dapm_add_routes(dapm, harmony_audio_map, | ||
242 | ARRAY_SIZE(harmony_audio_map)); | ||
243 | |||
244 | harmony_hp_jack_gpios[0].gpio = pdata->gpio_hp_det; | ||
245 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE, | ||
246 | &harmony_hp_jack); | ||
247 | snd_soc_jack_add_pins(&harmony_hp_jack, | ||
248 | ARRAY_SIZE(harmony_hp_jack_pins), | ||
249 | harmony_hp_jack_pins); | ||
250 | snd_soc_jack_add_gpios(&harmony_hp_jack, | ||
251 | ARRAY_SIZE(harmony_hp_jack_gpios), | ||
252 | harmony_hp_jack_gpios); | ||
253 | |||
254 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | ||
255 | &harmony_mic_jack); | ||
256 | snd_soc_jack_add_pins(&harmony_mic_jack, | ||
257 | ARRAY_SIZE(harmony_mic_jack_pins), | ||
258 | harmony_mic_jack_pins); | ||
259 | wm8903_mic_detect(codec, &harmony_mic_jack, SND_JACK_MICROPHONE, 0); | ||
260 | |||
261 | snd_soc_dapm_force_enable_pin(dapm, "Mic Bias"); | ||
262 | |||
263 | snd_soc_dapm_nc_pin(dapm, "IN3L"); | ||
264 | snd_soc_dapm_nc_pin(dapm, "IN3R"); | ||
265 | snd_soc_dapm_nc_pin(dapm, "LINEOUTL"); | ||
266 | snd_soc_dapm_nc_pin(dapm, "LINEOUTR"); | ||
267 | |||
268 | snd_soc_dapm_sync(dapm); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static struct snd_soc_dai_link harmony_wm8903_dai = { | ||
274 | .name = "WM8903", | ||
275 | .stream_name = "WM8903 PCM", | ||
276 | .codec_name = "wm8903.0-001a", | ||
277 | .platform_name = "tegra-pcm-audio", | ||
278 | .cpu_dai_name = "tegra-i2s.0", | ||
279 | .codec_dai_name = "wm8903-hifi", | ||
280 | .init = harmony_asoc_init, | ||
281 | .ops = &harmony_asoc_ops, | ||
282 | }; | ||
283 | |||
284 | static struct snd_soc_card snd_soc_harmony = { | ||
285 | .name = "tegra-harmony", | ||
286 | .dai_link = &harmony_wm8903_dai, | ||
287 | .num_links = 1, | ||
288 | }; | ||
289 | |||
290 | static __devinit int tegra_snd_harmony_probe(struct platform_device *pdev) | ||
291 | { | ||
292 | struct snd_soc_card *card = &snd_soc_harmony; | ||
293 | struct tegra_harmony *harmony; | ||
294 | struct harmony_audio_platform_data *pdata; | ||
295 | int ret; | ||
296 | |||
297 | if (!machine_is_harmony()) { | ||
298 | dev_err(&pdev->dev, "Not running on Tegra Harmony!\n"); | ||
299 | return -ENODEV; | ||
300 | } | ||
301 | |||
302 | pdata = pdev->dev.platform_data; | ||
303 | if (!pdata) { | ||
304 | dev_err(&pdev->dev, "no platform data supplied\n"); | ||
305 | return -EINVAL; | ||
306 | } | ||
307 | |||
308 | harmony = kzalloc(sizeof(struct tegra_harmony), GFP_KERNEL); | ||
309 | if (!harmony) { | ||
310 | dev_err(&pdev->dev, "Can't allocate tegra_harmony\n"); | ||
311 | return -ENOMEM; | ||
312 | } | ||
313 | |||
314 | harmony->pdata = pdata; | ||
315 | |||
316 | ret = tegra_asoc_utils_init(&harmony->util_data, &pdev->dev); | ||
317 | if (ret) | ||
318 | goto err_free_harmony; | ||
319 | |||
320 | card->dev = &pdev->dev; | ||
321 | platform_set_drvdata(pdev, card); | ||
322 | snd_soc_card_set_drvdata(card, harmony); | ||
323 | |||
324 | ret = snd_soc_register_card(card); | ||
325 | if (ret) { | ||
326 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", | ||
327 | ret); | ||
328 | goto err_clear_drvdata; | ||
329 | } | ||
330 | |||
331 | return 0; | ||
332 | |||
333 | err_clear_drvdata: | ||
334 | snd_soc_card_set_drvdata(card, NULL); | ||
335 | platform_set_drvdata(pdev, NULL); | ||
336 | card->dev = NULL; | ||
337 | tegra_asoc_utils_fini(&harmony->util_data); | ||
338 | err_free_harmony: | ||
339 | kfree(harmony); | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | static int __devexit tegra_snd_harmony_remove(struct platform_device *pdev) | ||
344 | { | ||
345 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
346 | struct tegra_harmony *harmony = snd_soc_card_get_drvdata(card); | ||
347 | struct harmony_audio_platform_data *pdata = harmony->pdata; | ||
348 | |||
349 | snd_soc_unregister_card(card); | ||
350 | |||
351 | snd_soc_card_set_drvdata(card, NULL); | ||
352 | platform_set_drvdata(pdev, NULL); | ||
353 | card->dev = NULL; | ||
354 | |||
355 | tegra_asoc_utils_fini(&harmony->util_data); | ||
356 | |||
357 | if (harmony->gpio_requested & GPIO_EXT_MIC_EN) | ||
358 | gpio_free(pdata->gpio_ext_mic_en); | ||
359 | if (harmony->gpio_requested & GPIO_INT_MIC_EN) | ||
360 | gpio_free(pdata->gpio_int_mic_en); | ||
361 | if (harmony->gpio_requested & GPIO_SPKR_EN) | ||
362 | gpio_free(pdata->gpio_spkr_en); | ||
363 | |||
364 | kfree(harmony); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | static struct platform_driver tegra_snd_harmony_driver = { | ||
370 | .driver = { | ||
371 | .name = DRV_NAME, | ||
372 | .owner = THIS_MODULE, | ||
373 | }, | ||
374 | .probe = tegra_snd_harmony_probe, | ||
375 | .remove = __devexit_p(tegra_snd_harmony_remove), | ||
376 | }; | ||
377 | |||
378 | static int __init snd_tegra_harmony_init(void) | ||
379 | { | ||
380 | return platform_driver_register(&tegra_snd_harmony_driver); | ||
381 | } | ||
382 | module_init(snd_tegra_harmony_init); | ||
383 | |||
384 | static void __exit snd_tegra_harmony_exit(void) | ||
385 | { | ||
386 | platform_driver_unregister(&tegra_snd_harmony_driver); | ||
387 | } | ||
388 | module_exit(snd_tegra_harmony_exit); | ||
389 | |||
390 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
391 | MODULE_DESCRIPTION("Harmony machine ASoC driver"); | ||
392 | MODULE_LICENSE("GPL"); | ||
393 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_asoc_utils.c b/sound/soc/tegra/tegra_asoc_utils.c new file mode 100644 index 000000000000..52f0a3f9ce40 --- /dev/null +++ b/sound/soc/tegra/tegra_asoc_utils.c | |||
@@ -0,0 +1,155 @@ | |||
1 | /* | ||
2 | * tegra_asoc_utils.c - Harmony machine ASoC driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/clk.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/kernel.h> | ||
27 | |||
28 | #include "tegra_asoc_utils.h" | ||
29 | |||
30 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | ||
31 | int mclk, int *mclk_change) | ||
32 | { | ||
33 | int new_baseclock; | ||
34 | int err; | ||
35 | |||
36 | switch (srate) { | ||
37 | case 11025: | ||
38 | case 22050: | ||
39 | case 44100: | ||
40 | case 88200: | ||
41 | new_baseclock = 56448000; | ||
42 | break; | ||
43 | case 8000: | ||
44 | case 16000: | ||
45 | case 32000: | ||
46 | case 48000: | ||
47 | case 64000: | ||
48 | case 96000: | ||
49 | new_baseclock = 73728000; | ||
50 | break; | ||
51 | default: | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | *mclk_change = ((new_baseclock != data->set_baseclock) || | ||
56 | (mclk != data->set_mclk)); | ||
57 | if (!*mclk_change) | ||
58 | return 0; | ||
59 | |||
60 | data->set_baseclock = 0; | ||
61 | data->set_mclk = 0; | ||
62 | |||
63 | clk_disable(data->clk_cdev1); | ||
64 | clk_disable(data->clk_pll_a_out0); | ||
65 | clk_disable(data->clk_pll_a); | ||
66 | |||
67 | err = clk_set_rate(data->clk_pll_a, new_baseclock); | ||
68 | if (err) { | ||
69 | dev_err(data->dev, "Can't set pll_a rate: %d\n", err); | ||
70 | return err; | ||
71 | } | ||
72 | |||
73 | err = clk_set_rate(data->clk_pll_a_out0, mclk); | ||
74 | if (err) { | ||
75 | dev_err(data->dev, "Can't set pll_a_out0 rate: %d\n", err); | ||
76 | return err; | ||
77 | } | ||
78 | |||
79 | /* Don't set cdev1 rate; its locked to pll_a_out0 */ | ||
80 | |||
81 | err = clk_enable(data->clk_pll_a); | ||
82 | if (err) { | ||
83 | dev_err(data->dev, "Can't enable pll_a: %d\n", err); | ||
84 | return err; | ||
85 | } | ||
86 | |||
87 | err = clk_enable(data->clk_pll_a_out0); | ||
88 | if (err) { | ||
89 | dev_err(data->dev, "Can't enable pll_a_out0: %d\n", err); | ||
90 | return err; | ||
91 | } | ||
92 | |||
93 | err = clk_enable(data->clk_cdev1); | ||
94 | if (err) { | ||
95 | dev_err(data->dev, "Can't enable cdev1: %d\n", err); | ||
96 | return err; | ||
97 | } | ||
98 | |||
99 | data->set_baseclock = new_baseclock; | ||
100 | data->set_mclk = mclk; | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_set_rate); | ||
105 | |||
106 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, | ||
107 | struct device *dev) | ||
108 | { | ||
109 | int ret; | ||
110 | |||
111 | data->dev = dev; | ||
112 | |||
113 | data->clk_pll_a = clk_get_sys(NULL, "pll_a"); | ||
114 | if (IS_ERR(data->clk_pll_a)) { | ||
115 | dev_err(data->dev, "Can't retrieve clk pll_a\n"); | ||
116 | ret = PTR_ERR(data->clk_pll_a); | ||
117 | goto err; | ||
118 | } | ||
119 | |||
120 | data->clk_pll_a_out0 = clk_get_sys(NULL, "pll_a_out0"); | ||
121 | if (IS_ERR(data->clk_pll_a_out0)) { | ||
122 | dev_err(data->dev, "Can't retrieve clk pll_a_out0\n"); | ||
123 | ret = PTR_ERR(data->clk_pll_a_out0); | ||
124 | goto err_put_pll_a; | ||
125 | } | ||
126 | |||
127 | data->clk_cdev1 = clk_get_sys(NULL, "cdev1"); | ||
128 | if (IS_ERR(data->clk_cdev1)) { | ||
129 | dev_err(data->dev, "Can't retrieve clk cdev1\n"); | ||
130 | ret = PTR_ERR(data->clk_cdev1); | ||
131 | goto err_put_pll_a_out0; | ||
132 | } | ||
133 | |||
134 | return 0; | ||
135 | |||
136 | err_put_pll_a_out0: | ||
137 | clk_put(data->clk_pll_a_out0); | ||
138 | err_put_pll_a: | ||
139 | clk_put(data->clk_pll_a); | ||
140 | err: | ||
141 | return ret; | ||
142 | } | ||
143 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_init); | ||
144 | |||
145 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data) | ||
146 | { | ||
147 | clk_put(data->clk_cdev1); | ||
148 | clk_put(data->clk_pll_a_out0); | ||
149 | clk_put(data->clk_pll_a); | ||
150 | } | ||
151 | EXPORT_SYMBOL_GPL(tegra_asoc_utils_fini); | ||
152 | |||
153 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
154 | MODULE_DESCRIPTION("Tegra ASoC utility code"); | ||
155 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h new file mode 100644 index 000000000000..bbba7afdfc2c --- /dev/null +++ b/sound/soc/tegra/tegra_asoc_utils.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * tegra_asoc_utils.h - Definitions for Tegra DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __TEGRA_ASOC_UTILS_H__ | ||
24 | #define __TEGRA_ASOC_UTILS_H_ | ||
25 | |||
26 | struct clk; | ||
27 | struct device; | ||
28 | |||
29 | struct tegra_asoc_utils_data { | ||
30 | struct device *dev; | ||
31 | struct clk *clk_pll_a; | ||
32 | struct clk *clk_pll_a_out0; | ||
33 | struct clk *clk_cdev1; | ||
34 | int set_baseclock; | ||
35 | int set_mclk; | ||
36 | }; | ||
37 | |||
38 | int tegra_asoc_utils_set_rate(struct tegra_asoc_utils_data *data, int srate, | ||
39 | int mclk, int *mclk_change); | ||
40 | int tegra_asoc_utils_init(struct tegra_asoc_utils_data *data, | ||
41 | struct device *dev); | ||
42 | void tegra_asoc_utils_fini(struct tegra_asoc_utils_data *data); | ||
43 | |||
44 | #endif | ||
45 | |||
diff --git a/sound/soc/tegra/tegra_das.c b/sound/soc/tegra/tegra_das.c new file mode 100644 index 000000000000..9f24ef73f2cb --- /dev/null +++ b/sound/soc/tegra/tegra_das.c | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * tegra_das.c - Tegra DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/debugfs.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/seq_file.h> | ||
28 | #include <linux/slab.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <mach/iomap.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include "tegra_das.h" | ||
33 | |||
34 | #define DRV_NAME "tegra-das" | ||
35 | |||
36 | static struct tegra_das *das; | ||
37 | |||
38 | static inline void tegra_das_write(u32 reg, u32 val) | ||
39 | { | ||
40 | __raw_writel(val, das->regs + reg); | ||
41 | } | ||
42 | |||
43 | static inline u32 tegra_das_read(u32 reg) | ||
44 | { | ||
45 | return __raw_readl(das->regs + reg); | ||
46 | } | ||
47 | |||
48 | int tegra_das_connect_dap_to_dac(int dap, int dac) | ||
49 | { | ||
50 | u32 addr; | ||
51 | u32 reg; | ||
52 | |||
53 | if (!das) | ||
54 | return -ENODEV; | ||
55 | |||
56 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
57 | (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
58 | reg = dac << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P; | ||
59 | |||
60 | tegra_das_write(addr, reg); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dac); | ||
65 | |||
66 | int tegra_das_connect_dap_to_dap(int dap, int otherdap, int master, | ||
67 | int sdata1rx, int sdata2rx) | ||
68 | { | ||
69 | u32 addr; | ||
70 | u32 reg; | ||
71 | |||
72 | if (!das) | ||
73 | return -ENODEV; | ||
74 | |||
75 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
76 | (dap * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
77 | reg = otherdap << TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P | | ||
78 | !!sdata2rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P | | ||
79 | !!sdata1rx << TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P | | ||
80 | !!master << TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P; | ||
81 | |||
82 | tegra_das_write(addr, reg); | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | EXPORT_SYMBOL_GPL(tegra_das_connect_dap_to_dap); | ||
87 | |||
88 | int tegra_das_connect_dac_to_dap(int dac, int dap) | ||
89 | { | ||
90 | u32 addr; | ||
91 | u32 reg; | ||
92 | |||
93 | if (!das) | ||
94 | return -ENODEV; | ||
95 | |||
96 | addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
97 | (dac * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
98 | reg = dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P | | ||
99 | dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P | | ||
100 | dap << TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P; | ||
101 | |||
102 | tegra_das_write(addr, reg); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(tegra_das_connect_dac_to_dap); | ||
107 | |||
108 | #ifdef CONFIG_DEBUG_FS | ||
109 | static int tegra_das_show(struct seq_file *s, void *unused) | ||
110 | { | ||
111 | int i; | ||
112 | u32 addr; | ||
113 | u32 reg; | ||
114 | |||
115 | for (i = 0; i < TEGRA_DAS_DAP_CTRL_SEL_COUNT; i++) { | ||
116 | addr = TEGRA_DAS_DAP_CTRL_SEL + | ||
117 | (i * TEGRA_DAS_DAP_CTRL_SEL_STRIDE); | ||
118 | reg = tegra_das_read(addr); | ||
119 | seq_printf(s, "TEGRA_DAS_DAP_CTRL_SEL[%d] = %08x\n", i, reg); | ||
120 | } | ||
121 | |||
122 | for (i = 0; i < TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT; i++) { | ||
123 | addr = TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL + | ||
124 | (i * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE); | ||
125 | reg = tegra_das_read(addr); | ||
126 | seq_printf(s, "TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL[%d] = %08x\n", | ||
127 | i, reg); | ||
128 | } | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int tegra_das_debug_open(struct inode *inode, struct file *file) | ||
134 | { | ||
135 | return single_open(file, tegra_das_show, inode->i_private); | ||
136 | } | ||
137 | |||
138 | static const struct file_operations tegra_das_debug_fops = { | ||
139 | .open = tegra_das_debug_open, | ||
140 | .read = seq_read, | ||
141 | .llseek = seq_lseek, | ||
142 | .release = single_release, | ||
143 | }; | ||
144 | |||
145 | static void tegra_das_debug_add(struct tegra_das *das) | ||
146 | { | ||
147 | das->debug = debugfs_create_file(DRV_NAME, S_IRUGO, | ||
148 | snd_soc_debugfs_root, das, | ||
149 | &tegra_das_debug_fops); | ||
150 | } | ||
151 | |||
152 | static void tegra_das_debug_remove(struct tegra_das *das) | ||
153 | { | ||
154 | if (das->debug) | ||
155 | debugfs_remove(das->debug); | ||
156 | } | ||
157 | #else | ||
158 | static inline void tegra_das_debug_add(struct tegra_das *das) | ||
159 | { | ||
160 | } | ||
161 | |||
162 | static inline void tegra_das_debug_remove(struct tegra_das *das) | ||
163 | { | ||
164 | } | ||
165 | #endif | ||
166 | |||
167 | static int __devinit tegra_das_probe(struct platform_device *pdev) | ||
168 | { | ||
169 | struct resource *res, *region; | ||
170 | int ret = 0; | ||
171 | |||
172 | if (das) | ||
173 | return -ENODEV; | ||
174 | |||
175 | das = kzalloc(sizeof(struct tegra_das), GFP_KERNEL); | ||
176 | if (!das) { | ||
177 | dev_err(&pdev->dev, "Can't allocate tegra_das\n"); | ||
178 | ret = -ENOMEM; | ||
179 | goto exit; | ||
180 | } | ||
181 | das->dev = &pdev->dev; | ||
182 | |||
183 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
184 | if (!res) { | ||
185 | dev_err(&pdev->dev, "No memory resource\n"); | ||
186 | ret = -ENODEV; | ||
187 | goto err_free; | ||
188 | } | ||
189 | |||
190 | region = request_mem_region(res->start, resource_size(res), | ||
191 | pdev->name); | ||
192 | if (!region) { | ||
193 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
194 | ret = -EBUSY; | ||
195 | goto err_free; | ||
196 | } | ||
197 | |||
198 | das->regs = ioremap(res->start, resource_size(res)); | ||
199 | if (!das->regs) { | ||
200 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
201 | ret = -ENOMEM; | ||
202 | goto err_release; | ||
203 | } | ||
204 | |||
205 | tegra_das_debug_add(das); | ||
206 | |||
207 | platform_set_drvdata(pdev, das); | ||
208 | |||
209 | return 0; | ||
210 | |||
211 | err_release: | ||
212 | release_mem_region(res->start, resource_size(res)); | ||
213 | err_free: | ||
214 | kfree(das); | ||
215 | das = 0; | ||
216 | exit: | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static int __devexit tegra_das_remove(struct platform_device *pdev) | ||
221 | { | ||
222 | struct resource *res; | ||
223 | |||
224 | if (!das) | ||
225 | return -ENODEV; | ||
226 | |||
227 | platform_set_drvdata(pdev, NULL); | ||
228 | |||
229 | tegra_das_debug_remove(das); | ||
230 | |||
231 | iounmap(das->regs); | ||
232 | |||
233 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
234 | release_mem_region(res->start, resource_size(res)); | ||
235 | |||
236 | kfree(das); | ||
237 | das = 0; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static struct platform_driver tegra_das_driver = { | ||
243 | .probe = tegra_das_probe, | ||
244 | .remove = __devexit_p(tegra_das_remove), | ||
245 | .driver = { | ||
246 | .name = DRV_NAME, | ||
247 | }, | ||
248 | }; | ||
249 | |||
250 | static int __init tegra_das_modinit(void) | ||
251 | { | ||
252 | return platform_driver_register(&tegra_das_driver); | ||
253 | } | ||
254 | module_init(tegra_das_modinit); | ||
255 | |||
256 | static void __exit tegra_das_modexit(void) | ||
257 | { | ||
258 | platform_driver_unregister(&tegra_das_driver); | ||
259 | } | ||
260 | module_exit(tegra_das_modexit); | ||
261 | |||
262 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
263 | MODULE_DESCRIPTION("Tegra DAS driver"); | ||
264 | MODULE_LICENSE("GPL"); | ||
265 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_das.h b/sound/soc/tegra/tegra_das.h new file mode 100644 index 000000000000..2c96c7b3c459 --- /dev/null +++ b/sound/soc/tegra/tegra_das.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * tegra_das.h - Definitions for Tegra DAS driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
19 | * 02110-1301 USA | ||
20 | * | ||
21 | */ | ||
22 | |||
23 | #ifndef __TEGRA_DAS_H__ | ||
24 | #define __TEGRA_DAS_H__ | ||
25 | |||
26 | /* Register TEGRA_DAS_DAP_CTRL_SEL */ | ||
27 | #define TEGRA_DAS_DAP_CTRL_SEL 0x00 | ||
28 | #define TEGRA_DAS_DAP_CTRL_SEL_COUNT 5 | ||
29 | #define TEGRA_DAS_DAP_CTRL_SEL_STRIDE 4 | ||
30 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_P 31 | ||
31 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_MS_SEL_S 1 | ||
32 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_P 30 | ||
33 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA1_TX_RX_S 1 | ||
34 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_P 29 | ||
35 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_SDATA2_TX_RX_S 1 | ||
36 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_P 0 | ||
37 | #define TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL_S 5 | ||
38 | |||
39 | /* Values for field TEGRA_DAS_DAP_CTRL_SEL_DAP_CTRL_SEL */ | ||
40 | #define TEGRA_DAS_DAP_SEL_DAC1 0 | ||
41 | #define TEGRA_DAS_DAP_SEL_DAC2 1 | ||
42 | #define TEGRA_DAS_DAP_SEL_DAC3 2 | ||
43 | #define TEGRA_DAS_DAP_SEL_DAP1 16 | ||
44 | #define TEGRA_DAS_DAP_SEL_DAP2 17 | ||
45 | #define TEGRA_DAS_DAP_SEL_DAP3 18 | ||
46 | #define TEGRA_DAS_DAP_SEL_DAP4 19 | ||
47 | #define TEGRA_DAS_DAP_SEL_DAP5 20 | ||
48 | |||
49 | /* Register TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL */ | ||
50 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL 0x40 | ||
51 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_COUNT 3 | ||
52 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_STRIDE 4 | ||
53 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_P 28 | ||
54 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL_S 4 | ||
55 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_P 24 | ||
56 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL_S 4 | ||
57 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_P 0 | ||
58 | #define TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL_S 4 | ||
59 | |||
60 | /* | ||
61 | * Values for: | ||
62 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA2_SEL | ||
63 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_SDATA1_SEL | ||
64 | * TEGRA_DAS_DAC_INPUT_DATA_CLK_SEL_DAC_CLK_SEL | ||
65 | */ | ||
66 | #define TEGRA_DAS_DAC_SEL_DAP1 0 | ||
67 | #define TEGRA_DAS_DAC_SEL_DAP2 1 | ||
68 | #define TEGRA_DAS_DAC_SEL_DAP3 2 | ||
69 | #define TEGRA_DAS_DAC_SEL_DAP4 3 | ||
70 | #define TEGRA_DAS_DAC_SEL_DAP5 4 | ||
71 | |||
72 | /* | ||
73 | * Names/IDs of the DACs/DAPs. | ||
74 | */ | ||
75 | |||
76 | #define TEGRA_DAS_DAP_ID_1 0 | ||
77 | #define TEGRA_DAS_DAP_ID_2 1 | ||
78 | #define TEGRA_DAS_DAP_ID_3 2 | ||
79 | #define TEGRA_DAS_DAP_ID_4 3 | ||
80 | #define TEGRA_DAS_DAP_ID_5 4 | ||
81 | |||
82 | #define TEGRA_DAS_DAC_ID_1 0 | ||
83 | #define TEGRA_DAS_DAC_ID_2 1 | ||
84 | #define TEGRA_DAS_DAC_ID_3 2 | ||
85 | |||
86 | struct tegra_das { | ||
87 | struct device *dev; | ||
88 | void __iomem *regs; | ||
89 | struct dentry *debug; | ||
90 | }; | ||
91 | |||
92 | /* | ||
93 | * Terminology: | ||
94 | * DAS: Digital audio switch (HW module controlled by this driver) | ||
95 | * DAP: Digital audio port (port/pins on Tegra device) | ||
96 | * DAC: Digital audio controller (e.g. I2S or AC97 controller elsewhere) | ||
97 | * | ||
98 | * The Tegra DAS is a mux/cross-bar which can connect each DAP to a specific | ||
99 | * DAC, or another DAP. When DAPs are connected, one must be the master and | ||
100 | * one the slave. Each DAC allows selection of a specific DAP for input, to | ||
101 | * cater for the case where N DAPs are connected to 1 DAC for broadcast | ||
102 | * output. | ||
103 | * | ||
104 | * This driver is dumb; no attempt is made to ensure that a valid routing | ||
105 | * configuration is programmed. | ||
106 | */ | ||
107 | |||
108 | /* | ||
109 | * Connect a DAP to to a DAC | ||
110 | * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_* | ||
111 | * dac_sel: DAC to connect to: TEGRA_DAS_DAP_SEL_DAC* | ||
112 | */ | ||
113 | extern int tegra_das_connect_dap_to_dac(int dap_id, int dac_sel); | ||
114 | |||
115 | /* | ||
116 | * Connect a DAP to to another DAP | ||
117 | * dap_id: DAP to connect: TEGRA_DAS_DAP_ID_* | ||
118 | * other_dap_sel: DAP to connect to: TEGRA_DAS_DAP_SEL_DAP* | ||
119 | * master: Is this DAP the master (1) or slave (0) | ||
120 | * sdata1rx: Is this DAP's SDATA1 pin RX (1) or TX (0) | ||
121 | * sdata2rx: Is this DAP's SDATA2 pin RX (1) or TX (0) | ||
122 | */ | ||
123 | extern int tegra_das_connect_dap_to_dap(int dap_id, int other_dap_sel, | ||
124 | int master, int sdata1rx, | ||
125 | int sdata2rx); | ||
126 | |||
127 | /* | ||
128 | * Connect a DAC's input to a DAP | ||
129 | * (DAC outputs are selected by the DAP) | ||
130 | * dac_id: DAC ID to connect: TEGRA_DAS_DAC_ID_* | ||
131 | * dap_sel: DAP to receive input from: TEGRA_DAS_DAC_SEL_DAP* | ||
132 | */ | ||
133 | extern int tegra_das_connect_dac_to_dap(int dac_id, int dap_sel); | ||
134 | |||
135 | #endif | ||
diff --git a/sound/soc/tegra/tegra_i2s.c b/sound/soc/tegra/tegra_i2s.c new file mode 100644 index 000000000000..4f5e2c90b020 --- /dev/null +++ b/sound/soc/tegra/tegra_i2s.c | |||
@@ -0,0 +1,503 @@ | |||
1 | /* | ||
2 | * tegra_i2s.c - Tegra I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * | ||
12 | * Copyright (C) 2010 Google, Inc. | ||
13 | * Iliyan Malchev <malchev@google.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #include <linux/clk.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | #include <linux/device.h> | ||
35 | #include <linux/platform_device.h> | ||
36 | #include <linux/seq_file.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/io.h> | ||
39 | #include <mach/iomap.h> | ||
40 | #include <sound/core.h> | ||
41 | #include <sound/pcm.h> | ||
42 | #include <sound/pcm_params.h> | ||
43 | #include <sound/soc.h> | ||
44 | |||
45 | #include "tegra_das.h" | ||
46 | #include "tegra_i2s.h" | ||
47 | |||
48 | #define DRV_NAME "tegra-i2s" | ||
49 | |||
50 | static inline void tegra_i2s_write(struct tegra_i2s *i2s, u32 reg, u32 val) | ||
51 | { | ||
52 | __raw_writel(val, i2s->regs + reg); | ||
53 | } | ||
54 | |||
55 | static inline u32 tegra_i2s_read(struct tegra_i2s *i2s, u32 reg) | ||
56 | { | ||
57 | return __raw_readl(i2s->regs + reg); | ||
58 | } | ||
59 | |||
60 | #ifdef CONFIG_DEBUG_FS | ||
61 | static int tegra_i2s_show(struct seq_file *s, void *unused) | ||
62 | { | ||
63 | #define REG(r) { r, #r } | ||
64 | static const struct { | ||
65 | int offset; | ||
66 | const char *name; | ||
67 | } regs[] = { | ||
68 | REG(TEGRA_I2S_CTRL), | ||
69 | REG(TEGRA_I2S_STATUS), | ||
70 | REG(TEGRA_I2S_TIMING), | ||
71 | REG(TEGRA_I2S_FIFO_SCR), | ||
72 | REG(TEGRA_I2S_PCM_CTRL), | ||
73 | REG(TEGRA_I2S_NW_CTRL), | ||
74 | REG(TEGRA_I2S_TDM_CTRL), | ||
75 | REG(TEGRA_I2S_TDM_TX_RX_CTRL), | ||
76 | }; | ||
77 | #undef REG | ||
78 | |||
79 | struct tegra_i2s *i2s = s->private; | ||
80 | int i; | ||
81 | |||
82 | for (i = 0; i < ARRAY_SIZE(regs); i++) { | ||
83 | u32 val = tegra_i2s_read(i2s, regs[i].offset); | ||
84 | seq_printf(s, "%s = %08x\n", regs[i].name, val); | ||
85 | } | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static int tegra_i2s_debug_open(struct inode *inode, struct file *file) | ||
91 | { | ||
92 | return single_open(file, tegra_i2s_show, inode->i_private); | ||
93 | } | ||
94 | |||
95 | static const struct file_operations tegra_i2s_debug_fops = { | ||
96 | .open = tegra_i2s_debug_open, | ||
97 | .read = seq_read, | ||
98 | .llseek = seq_lseek, | ||
99 | .release = single_release, | ||
100 | }; | ||
101 | |||
102 | static void tegra_i2s_debug_add(struct tegra_i2s *i2s, int id) | ||
103 | { | ||
104 | char name[] = DRV_NAME ".0"; | ||
105 | |||
106 | snprintf(name, sizeof(name), DRV_NAME".%1d", id); | ||
107 | i2s->debug = debugfs_create_file(name, S_IRUGO, snd_soc_debugfs_root, | ||
108 | i2s, &tegra_i2s_debug_fops); | ||
109 | } | ||
110 | |||
111 | static void tegra_i2s_debug_remove(struct tegra_i2s *i2s) | ||
112 | { | ||
113 | if (i2s->debug) | ||
114 | debugfs_remove(i2s->debug); | ||
115 | } | ||
116 | #else | ||
117 | static inline void tegra_i2s_debug_add(struct tegra_i2s *i2s) | ||
118 | { | ||
119 | } | ||
120 | |||
121 | static inline void tegra_i2s_debug_remove(struct tegra_i2s *i2s) | ||
122 | { | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | static int tegra_i2s_set_fmt(struct snd_soc_dai *dai, | ||
127 | unsigned int fmt) | ||
128 | { | ||
129 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
130 | |||
131 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
132 | case SND_SOC_DAIFMT_NB_NF: | ||
133 | break; | ||
134 | default: | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_MASTER_ENABLE; | ||
139 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
140 | case SND_SOC_DAIFMT_CBS_CFS: | ||
141 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_MASTER_ENABLE; | ||
142 | break; | ||
143 | case SND_SOC_DAIFMT_CBM_CFM: | ||
144 | break; | ||
145 | default: | ||
146 | return -EINVAL; | ||
147 | } | ||
148 | |||
149 | i2s->reg_ctrl &= ~(TEGRA_I2S_CTRL_BIT_FORMAT_MASK | | ||
150 | TEGRA_I2S_CTRL_LRCK_MASK); | ||
151 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
152 | case SND_SOC_DAIFMT_DSP_A: | ||
153 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; | ||
154 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
155 | break; | ||
156 | case SND_SOC_DAIFMT_DSP_B: | ||
157 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_DSP; | ||
158 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_R_LOW; | ||
159 | break; | ||
160 | case SND_SOC_DAIFMT_I2S: | ||
161 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_I2S; | ||
162 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
163 | break; | ||
164 | case SND_SOC_DAIFMT_RIGHT_J: | ||
165 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_RJM; | ||
166 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
167 | break; | ||
168 | case SND_SOC_DAIFMT_LEFT_J: | ||
169 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_FORMAT_LJM; | ||
170 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_LRCK_L_LOW; | ||
171 | break; | ||
172 | default: | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int tegra_i2s_hw_params(struct snd_pcm_substream *substream, | ||
180 | struct snd_pcm_hw_params *params, | ||
181 | struct snd_soc_dai *dai) | ||
182 | { | ||
183 | struct device *dev = substream->pcm->card->dev; | ||
184 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
185 | u32 reg; | ||
186 | int ret, sample_size, srate, i2sclock, bitcnt; | ||
187 | |||
188 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_BIT_SIZE_MASK; | ||
189 | switch (params_format(params)) { | ||
190 | case SNDRV_PCM_FORMAT_S16_LE: | ||
191 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_16; | ||
192 | sample_size = 16; | ||
193 | break; | ||
194 | case SNDRV_PCM_FORMAT_S24_LE: | ||
195 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_24; | ||
196 | sample_size = 24; | ||
197 | break; | ||
198 | case SNDRV_PCM_FORMAT_S32_LE: | ||
199 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_BIT_SIZE_32; | ||
200 | sample_size = 32; | ||
201 | break; | ||
202 | default: | ||
203 | return -EINVAL; | ||
204 | } | ||
205 | |||
206 | srate = params_rate(params); | ||
207 | |||
208 | /* Final "* 2" required by Tegra hardware */ | ||
209 | i2sclock = srate * params_channels(params) * sample_size * 2; | ||
210 | |||
211 | ret = clk_set_rate(i2s->clk_i2s, i2sclock); | ||
212 | if (ret) { | ||
213 | dev_err(dev, "Can't set I2S clock rate: %d\n", ret); | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | bitcnt = (i2sclock / (2 * srate)) - 1; | ||
218 | if (bitcnt < 0 || bitcnt > TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) | ||
219 | return -EINVAL; | ||
220 | reg = bitcnt << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | ||
221 | |||
222 | if (i2sclock % (2 * srate)) | ||
223 | reg |= TEGRA_I2S_TIMING_NON_SYM_ENABLE; | ||
224 | |||
225 | tegra_i2s_write(i2s, TEGRA_I2S_TIMING, reg); | ||
226 | |||
227 | tegra_i2s_write(i2s, TEGRA_I2S_FIFO_SCR, | ||
228 | TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | | ||
229 | TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); | ||
230 | |||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | static void tegra_i2s_start_playback(struct tegra_i2s *i2s) | ||
235 | { | ||
236 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO1_ENABLE; | ||
237 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
238 | } | ||
239 | |||
240 | static void tegra_i2s_stop_playback(struct tegra_i2s *i2s) | ||
241 | { | ||
242 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO1_ENABLE; | ||
243 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
244 | } | ||
245 | |||
246 | static void tegra_i2s_start_capture(struct tegra_i2s *i2s) | ||
247 | { | ||
248 | i2s->reg_ctrl |= TEGRA_I2S_CTRL_FIFO2_ENABLE; | ||
249 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
250 | } | ||
251 | |||
252 | static void tegra_i2s_stop_capture(struct tegra_i2s *i2s) | ||
253 | { | ||
254 | i2s->reg_ctrl &= ~TEGRA_I2S_CTRL_FIFO2_ENABLE; | ||
255 | tegra_i2s_write(i2s, TEGRA_I2S_CTRL, i2s->reg_ctrl); | ||
256 | } | ||
257 | |||
258 | static int tegra_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | ||
259 | struct snd_soc_dai *dai) | ||
260 | { | ||
261 | struct tegra_i2s *i2s = snd_soc_dai_get_drvdata(dai); | ||
262 | |||
263 | switch (cmd) { | ||
264 | case SNDRV_PCM_TRIGGER_START: | ||
265 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
266 | case SNDRV_PCM_TRIGGER_RESUME: | ||
267 | if (!i2s->clk_refs) | ||
268 | clk_enable(i2s->clk_i2s); | ||
269 | i2s->clk_refs++; | ||
270 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
271 | tegra_i2s_start_playback(i2s); | ||
272 | else | ||
273 | tegra_i2s_start_capture(i2s); | ||
274 | break; | ||
275 | case SNDRV_PCM_TRIGGER_STOP: | ||
276 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
277 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
278 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
279 | tegra_i2s_stop_playback(i2s); | ||
280 | else | ||
281 | tegra_i2s_stop_capture(i2s); | ||
282 | i2s->clk_refs--; | ||
283 | if (!i2s->clk_refs) | ||
284 | clk_disable(i2s->clk_i2s); | ||
285 | break; | ||
286 | default: | ||
287 | return -EINVAL; | ||
288 | } | ||
289 | |||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | static int tegra_i2s_probe(struct snd_soc_dai *dai) | ||
294 | { | ||
295 | struct tegra_i2s * i2s = snd_soc_dai_get_drvdata(dai); | ||
296 | |||
297 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
298 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static struct snd_soc_dai_ops tegra_i2s_dai_ops = { | ||
304 | .set_fmt = tegra_i2s_set_fmt, | ||
305 | .hw_params = tegra_i2s_hw_params, | ||
306 | .trigger = tegra_i2s_trigger, | ||
307 | }; | ||
308 | |||
309 | struct snd_soc_dai_driver tegra_i2s_dai[] = { | ||
310 | { | ||
311 | .name = DRV_NAME ".0", | ||
312 | .probe = tegra_i2s_probe, | ||
313 | .playback = { | ||
314 | .channels_min = 2, | ||
315 | .channels_max = 2, | ||
316 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
317 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
318 | }, | ||
319 | .capture = { | ||
320 | .channels_min = 2, | ||
321 | .channels_max = 2, | ||
322 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
323 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
324 | }, | ||
325 | .ops = &tegra_i2s_dai_ops, | ||
326 | .symmetric_rates = 1, | ||
327 | }, | ||
328 | { | ||
329 | .name = DRV_NAME ".1", | ||
330 | .probe = tegra_i2s_probe, | ||
331 | .playback = { | ||
332 | .channels_min = 2, | ||
333 | .channels_max = 2, | ||
334 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
335 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
336 | }, | ||
337 | .capture = { | ||
338 | .channels_min = 2, | ||
339 | .channels_max = 2, | ||
340 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
341 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
342 | }, | ||
343 | .ops = &tegra_i2s_dai_ops, | ||
344 | .symmetric_rates = 1, | ||
345 | }, | ||
346 | }; | ||
347 | |||
348 | static __devinit int tegra_i2s_platform_probe(struct platform_device *pdev) | ||
349 | { | ||
350 | struct tegra_i2s * i2s; | ||
351 | char clk_name[12]; /* tegra-i2s.0 */ | ||
352 | struct resource *mem, *memregion, *dmareq; | ||
353 | int ret; | ||
354 | |||
355 | if ((pdev->id < 0) || | ||
356 | (pdev->id >= ARRAY_SIZE(tegra_i2s_dai))) { | ||
357 | dev_err(&pdev->dev, "ID %d out of range\n", pdev->id); | ||
358 | return -EINVAL; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * FIXME: Until a codec driver exists for the tegra DAS, hard-code a | ||
363 | * 1:1 mapping between audio controllers and audio ports. | ||
364 | */ | ||
365 | ret = tegra_das_connect_dap_to_dac(TEGRA_DAS_DAP_ID_1 + pdev->id, | ||
366 | TEGRA_DAS_DAP_SEL_DAC1 + pdev->id); | ||
367 | if (ret) { | ||
368 | dev_err(&pdev->dev, "Can't set up DAP connection\n"); | ||
369 | return ret; | ||
370 | } | ||
371 | ret = tegra_das_connect_dac_to_dap(TEGRA_DAS_DAC_ID_1 + pdev->id, | ||
372 | TEGRA_DAS_DAC_SEL_DAP1 + pdev->id); | ||
373 | if (ret) { | ||
374 | dev_err(&pdev->dev, "Can't set up DAC connection\n"); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | i2s = kzalloc(sizeof(struct tegra_i2s), GFP_KERNEL); | ||
379 | if (!i2s) { | ||
380 | dev_err(&pdev->dev, "Can't allocate tegra_i2s\n"); | ||
381 | ret = -ENOMEM; | ||
382 | goto exit; | ||
383 | } | ||
384 | dev_set_drvdata(&pdev->dev, i2s); | ||
385 | |||
386 | snprintf(clk_name, sizeof(clk_name), DRV_NAME ".%d", pdev->id); | ||
387 | i2s->clk_i2s = clk_get_sys(clk_name, NULL); | ||
388 | if (IS_ERR(i2s->clk_i2s)) { | ||
389 | dev_err(&pdev->dev, "Can't retrieve i2s clock\n"); | ||
390 | ret = PTR_ERR(i2s->clk_i2s); | ||
391 | goto err_free; | ||
392 | } | ||
393 | |||
394 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
395 | if (!mem) { | ||
396 | dev_err(&pdev->dev, "No memory resource\n"); | ||
397 | ret = -ENODEV; | ||
398 | goto err_clk_put; | ||
399 | } | ||
400 | |||
401 | dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
402 | if (!dmareq) { | ||
403 | dev_err(&pdev->dev, "No DMA resource\n"); | ||
404 | ret = -ENODEV; | ||
405 | goto err_clk_put; | ||
406 | } | ||
407 | |||
408 | memregion = request_mem_region(mem->start, resource_size(mem), | ||
409 | DRV_NAME); | ||
410 | if (!memregion) { | ||
411 | dev_err(&pdev->dev, "Memory region already claimed\n"); | ||
412 | ret = -EBUSY; | ||
413 | goto err_clk_put; | ||
414 | } | ||
415 | |||
416 | i2s->regs = ioremap(mem->start, resource_size(mem)); | ||
417 | if (!i2s->regs) { | ||
418 | dev_err(&pdev->dev, "ioremap failed\n"); | ||
419 | ret = -ENOMEM; | ||
420 | goto err_release; | ||
421 | } | ||
422 | |||
423 | i2s->capture_dma_data.addr = mem->start + TEGRA_I2S_FIFO2; | ||
424 | i2s->capture_dma_data.wrap = 4; | ||
425 | i2s->capture_dma_data.width = 32; | ||
426 | i2s->capture_dma_data.req_sel = dmareq->start; | ||
427 | |||
428 | i2s->playback_dma_data.addr = mem->start + TEGRA_I2S_FIFO1; | ||
429 | i2s->playback_dma_data.wrap = 4; | ||
430 | i2s->playback_dma_data.width = 32; | ||
431 | i2s->playback_dma_data.req_sel = dmareq->start; | ||
432 | |||
433 | i2s->reg_ctrl = TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED; | ||
434 | |||
435 | ret = snd_soc_register_dai(&pdev->dev, &tegra_i2s_dai[pdev->id]); | ||
436 | if (ret) { | ||
437 | dev_err(&pdev->dev, "Could not register DAI: %d\n", ret); | ||
438 | ret = -ENOMEM; | ||
439 | goto err_unmap; | ||
440 | } | ||
441 | |||
442 | tegra_i2s_debug_add(i2s, pdev->id); | ||
443 | |||
444 | return 0; | ||
445 | |||
446 | err_unmap: | ||
447 | iounmap(i2s->regs); | ||
448 | err_release: | ||
449 | release_mem_region(mem->start, resource_size(mem)); | ||
450 | err_clk_put: | ||
451 | clk_put(i2s->clk_i2s); | ||
452 | err_free: | ||
453 | kfree(i2s); | ||
454 | exit: | ||
455 | return ret; | ||
456 | } | ||
457 | |||
458 | static int __devexit tegra_i2s_platform_remove(struct platform_device *pdev) | ||
459 | { | ||
460 | struct tegra_i2s *i2s = dev_get_drvdata(&pdev->dev); | ||
461 | struct resource *res; | ||
462 | |||
463 | snd_soc_unregister_dai(&pdev->dev); | ||
464 | |||
465 | tegra_i2s_debug_remove(i2s); | ||
466 | |||
467 | iounmap(i2s->regs); | ||
468 | |||
469 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
470 | release_mem_region(res->start, resource_size(res)); | ||
471 | |||
472 | clk_put(i2s->clk_i2s); | ||
473 | |||
474 | kfree(i2s); | ||
475 | |||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static struct platform_driver tegra_i2s_driver = { | ||
480 | .driver = { | ||
481 | .name = DRV_NAME, | ||
482 | .owner = THIS_MODULE, | ||
483 | }, | ||
484 | .probe = tegra_i2s_platform_probe, | ||
485 | .remove = __devexit_p(tegra_i2s_platform_remove), | ||
486 | }; | ||
487 | |||
488 | static int __init snd_tegra_i2s_init(void) | ||
489 | { | ||
490 | return platform_driver_register(&tegra_i2s_driver); | ||
491 | } | ||
492 | module_init(snd_tegra_i2s_init); | ||
493 | |||
494 | static void __exit snd_tegra_i2s_exit(void) | ||
495 | { | ||
496 | platform_driver_unregister(&tegra_i2s_driver); | ||
497 | } | ||
498 | module_exit(snd_tegra_i2s_exit); | ||
499 | |||
500 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
501 | MODULE_DESCRIPTION("Tegra I2S ASoC driver"); | ||
502 | MODULE_LICENSE("GPL"); | ||
503 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_i2s.h b/sound/soc/tegra/tegra_i2s.h new file mode 100644 index 000000000000..2b38a096f46c --- /dev/null +++ b/sound/soc/tegra/tegra_i2s.h | |||
@@ -0,0 +1,165 @@ | |||
1 | /* | ||
2 | * tegra_i2s.h - Definitions for Tegra I2S driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * | ||
12 | * Copyright (C) 2010 Google, Inc. | ||
13 | * Iliyan Malchev <malchev@google.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef __TEGRA_I2S_H__ | ||
32 | #define __TEGRA_I2S_H__ | ||
33 | |||
34 | #include "tegra_pcm.h" | ||
35 | |||
36 | /* Register offsets from TEGRA_I2S1_BASE and TEGRA_I2S2_BASE */ | ||
37 | |||
38 | #define TEGRA_I2S_CTRL 0x00 | ||
39 | #define TEGRA_I2S_STATUS 0x04 | ||
40 | #define TEGRA_I2S_TIMING 0x08 | ||
41 | #define TEGRA_I2S_FIFO_SCR 0x0c | ||
42 | #define TEGRA_I2S_PCM_CTRL 0x10 | ||
43 | #define TEGRA_I2S_NW_CTRL 0x14 | ||
44 | #define TEGRA_I2S_TDM_CTRL 0x20 | ||
45 | #define TEGRA_I2S_TDM_TX_RX_CTRL 0x24 | ||
46 | #define TEGRA_I2S_FIFO1 0x40 | ||
47 | #define TEGRA_I2S_FIFO2 0x80 | ||
48 | |||
49 | /* Fields in TEGRA_I2S_CTRL */ | ||
50 | |||
51 | #define TEGRA_I2S_CTRL_FIFO2_TX_ENABLE (1 << 30) | ||
52 | #define TEGRA_I2S_CTRL_FIFO1_ENABLE (1 << 29) | ||
53 | #define TEGRA_I2S_CTRL_FIFO2_ENABLE (1 << 28) | ||
54 | #define TEGRA_I2S_CTRL_FIFO1_RX_ENABLE (1 << 27) | ||
55 | #define TEGRA_I2S_CTRL_FIFO_LPBK_ENABLE (1 << 26) | ||
56 | #define TEGRA_I2S_CTRL_MASTER_ENABLE (1 << 25) | ||
57 | |||
58 | #define TEGRA_I2S_LRCK_LEFT_LOW 0 | ||
59 | #define TEGRA_I2S_LRCK_RIGHT_LOW 1 | ||
60 | |||
61 | #define TEGRA_I2S_CTRL_LRCK_SHIFT 24 | ||
62 | #define TEGRA_I2S_CTRL_LRCK_MASK (1 << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
63 | #define TEGRA_I2S_CTRL_LRCK_L_LOW (TEGRA_I2S_LRCK_LEFT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
64 | #define TEGRA_I2S_CTRL_LRCK_R_LOW (TEGRA_I2S_LRCK_RIGHT_LOW << TEGRA_I2S_CTRL_LRCK_SHIFT) | ||
65 | |||
66 | #define TEGRA_I2S_BIT_FORMAT_I2S 0 | ||
67 | #define TEGRA_I2S_BIT_FORMAT_RJM 1 | ||
68 | #define TEGRA_I2S_BIT_FORMAT_LJM 2 | ||
69 | #define TEGRA_I2S_BIT_FORMAT_DSP 3 | ||
70 | |||
71 | #define TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT 10 | ||
72 | #define TEGRA_I2S_CTRL_BIT_FORMAT_MASK (3 << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
73 | #define TEGRA_I2S_CTRL_BIT_FORMAT_I2S (TEGRA_I2S_BIT_FORMAT_I2S << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
74 | #define TEGRA_I2S_CTRL_BIT_FORMAT_RJM (TEGRA_I2S_BIT_FORMAT_RJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
75 | #define TEGRA_I2S_CTRL_BIT_FORMAT_LJM (TEGRA_I2S_BIT_FORMAT_LJM << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
76 | #define TEGRA_I2S_CTRL_BIT_FORMAT_DSP (TEGRA_I2S_BIT_FORMAT_DSP << TEGRA_I2S_CTRL_BIT_FORMAT_SHIFT) | ||
77 | |||
78 | #define TEGRA_I2S_BIT_SIZE_16 0 | ||
79 | #define TEGRA_I2S_BIT_SIZE_20 1 | ||
80 | #define TEGRA_I2S_BIT_SIZE_24 2 | ||
81 | #define TEGRA_I2S_BIT_SIZE_32 3 | ||
82 | |||
83 | #define TEGRA_I2S_CTRL_BIT_SIZE_SHIFT 8 | ||
84 | #define TEGRA_I2S_CTRL_BIT_SIZE_MASK (3 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
85 | #define TEGRA_I2S_CTRL_BIT_SIZE_16 (TEGRA_I2S_BIT_SIZE_16 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
86 | #define TEGRA_I2S_CTRL_BIT_SIZE_20 (TEGRA_I2S_BIT_SIZE_20 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
87 | #define TEGRA_I2S_CTRL_BIT_SIZE_24 (TEGRA_I2S_BIT_SIZE_24 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
88 | #define TEGRA_I2S_CTRL_BIT_SIZE_32 (TEGRA_I2S_BIT_SIZE_32 << TEGRA_I2S_CTRL_BIT_SIZE_SHIFT) | ||
89 | |||
90 | #define TEGRA_I2S_FIFO_16_LSB 0 | ||
91 | #define TEGRA_I2S_FIFO_20_LSB 1 | ||
92 | #define TEGRA_I2S_FIFO_24_LSB 2 | ||
93 | #define TEGRA_I2S_FIFO_32 3 | ||
94 | #define TEGRA_I2S_FIFO_PACKED 7 | ||
95 | |||
96 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT 4 | ||
97 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_MASK (7 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
98 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_16_LSB (TEGRA_I2S_FIFO_16_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
99 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_20_LSB (TEGRA_I2S_FIFO_20_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
100 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_24_LSB (TEGRA_I2S_FIFO_24_LSB << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
101 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_32 (TEGRA_I2S_FIFO_32 << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
102 | #define TEGRA_I2S_CTRL_FIFO_FORMAT_PACKED (TEGRA_I2S_FIFO_PACKED << TEGRA_I2S_CTRL_FIFO_FORMAT_SHIFT) | ||
103 | |||
104 | #define TEGRA_I2S_CTRL_IE_FIFO1_ERR (1 << 3) | ||
105 | #define TEGRA_I2S_CTRL_IE_FIFO2_ERR (1 << 2) | ||
106 | #define TEGRA_I2S_CTRL_QE_FIFO1 (1 << 1) | ||
107 | #define TEGRA_I2S_CTRL_QE_FIFO2 (1 << 0) | ||
108 | |||
109 | /* Fields in TEGRA_I2S_STATUS */ | ||
110 | |||
111 | #define TEGRA_I2S_STATUS_FIFO1_RDY (1 << 31) | ||
112 | #define TEGRA_I2S_STATUS_FIFO2_RDY (1 << 30) | ||
113 | #define TEGRA_I2S_STATUS_FIFO1_BSY (1 << 29) | ||
114 | #define TEGRA_I2S_STATUS_FIFO2_BSY (1 << 28) | ||
115 | #define TEGRA_I2S_STATUS_FIFO1_ERR (1 << 3) | ||
116 | #define TEGRA_I2S_STATUS_FIFO2_ERR (1 << 2) | ||
117 | #define TEGRA_I2S_STATUS_QS_FIFO1 (1 << 1) | ||
118 | #define TEGRA_I2S_STATUS_QS_FIFO2 (1 << 0) | ||
119 | |||
120 | /* Fields in TEGRA_I2S_TIMING */ | ||
121 | |||
122 | #define TEGRA_I2S_TIMING_NON_SYM_ENABLE (1 << 12) | ||
123 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT 0 | ||
124 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US 0x7fff | ||
125 | #define TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK (TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US << TEGRA_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT) | ||
126 | |||
127 | /* Fields in TEGRA_I2S_FIFO_SCR */ | ||
128 | |||
129 | #define TEGRA_I2S_FIFO_SCR_FIFO2_FULL_EMPTY_COUNT_SHIFT 24 | ||
130 | #define TEGRA_I2S_FIFO_SCR_FIFO1_FULL_EMPTY_COUNT_SHIFT 16 | ||
131 | #define TEGRA_I2S_FIFO_SCR_FIFO_FULL_EMPTY_COUNT_MASK 0x3f | ||
132 | |||
133 | #define TEGRA_I2S_FIFO_SCR_FIFO2_CLR (1 << 12) | ||
134 | #define TEGRA_I2S_FIFO_SCR_FIFO1_CLR (1 << 8) | ||
135 | |||
136 | #define TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT 0 | ||
137 | #define TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS 1 | ||
138 | #define TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS 2 | ||
139 | #define TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS 3 | ||
140 | |||
141 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT 4 | ||
142 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
143 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
144 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
145 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
146 | #define TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO2_ATN_LVL_SHIFT) | ||
147 | |||
148 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT 0 | ||
149 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_MASK (3 << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
150 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_ONE_SLOT (TEGRA_I2S_FIFO_ATN_LVL_ONE_SLOT << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
151 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_FOUR_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
152 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_EIGHT_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_EIGHT_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
153 | #define TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_TWELVE_SLOTS (TEGRA_I2S_FIFO_ATN_LVL_TWELVE_SLOTS << TEGRA_I2S_FIFO_SCR_FIFO1_ATN_LVL_SHIFT) | ||
154 | |||
155 | struct tegra_i2s { | ||
156 | struct clk *clk_i2s; | ||
157 | int clk_refs; | ||
158 | struct tegra_pcm_dma_params capture_dma_data; | ||
159 | struct tegra_pcm_dma_params playback_dma_data; | ||
160 | void __iomem *regs; | ||
161 | struct dentry *debug; | ||
162 | u32 reg_ctrl; | ||
163 | }; | ||
164 | |||
165 | #endif | ||
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c new file mode 100644 index 000000000000..3c271f953582 --- /dev/null +++ b/sound/soc/tegra/tegra_pcm.c | |||
@@ -0,0 +1,404 @@ | |||
1 | /* | ||
2 | * tegra_pcm.c - Tegra PCM driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * Vijay Mali <vmali@nvidia.com> | ||
12 | * | ||
13 | * Copyright (C) 2010 Google, Inc. | ||
14 | * Iliyan Malchev <malchev@google.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License | ||
18 | * version 2 as published by the Free Software Foundation. | ||
19 | * | ||
20 | * This program is distributed in the hope that it will be useful, but | ||
21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
23 | * General Public License for more details. | ||
24 | * | ||
25 | * You should have received a copy of the GNU General Public License | ||
26 | * along with this program; if not, write to the Free Software | ||
27 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
28 | * 02110-1301 USA | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include <linux/module.h> | ||
33 | #include <linux/dma-mapping.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <sound/core.h> | ||
36 | #include <sound/pcm.h> | ||
37 | #include <sound/pcm_params.h> | ||
38 | #include <sound/soc.h> | ||
39 | |||
40 | #include "tegra_pcm.h" | ||
41 | |||
42 | #define DRV_NAME "tegra-pcm-audio" | ||
43 | |||
44 | static const struct snd_pcm_hardware tegra_pcm_hardware = { | ||
45 | .info = SNDRV_PCM_INFO_MMAP | | ||
46 | SNDRV_PCM_INFO_MMAP_VALID | | ||
47 | SNDRV_PCM_INFO_PAUSE | | ||
48 | SNDRV_PCM_INFO_RESUME | | ||
49 | SNDRV_PCM_INFO_INTERLEAVED, | ||
50 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
51 | .channels_min = 2, | ||
52 | .channels_max = 2, | ||
53 | .period_bytes_min = 1024, | ||
54 | .period_bytes_max = PAGE_SIZE, | ||
55 | .periods_min = 2, | ||
56 | .periods_max = 8, | ||
57 | .buffer_bytes_max = PAGE_SIZE * 8, | ||
58 | .fifo_size = 4, | ||
59 | }; | ||
60 | |||
61 | static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) | ||
62 | { | ||
63 | struct snd_pcm_substream *substream = prtd->substream; | ||
64 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
65 | struct tegra_dma_req *dma_req; | ||
66 | unsigned long addr; | ||
67 | |||
68 | dma_req = &prtd->dma_req[prtd->dma_req_idx]; | ||
69 | prtd->dma_req_idx = 1 - prtd->dma_req_idx; | ||
70 | |||
71 | addr = buf->addr + prtd->dma_pos; | ||
72 | prtd->dma_pos += dma_req->size; | ||
73 | if (prtd->dma_pos >= prtd->dma_pos_end) | ||
74 | prtd->dma_pos = 0; | ||
75 | |||
76 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
77 | dma_req->source_addr = addr; | ||
78 | else | ||
79 | dma_req->dest_addr = addr; | ||
80 | |||
81 | tegra_dma_enqueue_req(prtd->dma_chan, dma_req); | ||
82 | } | ||
83 | |||
84 | static void dma_complete_callback(struct tegra_dma_req *req) | ||
85 | { | ||
86 | struct tegra_runtime_data *prtd = (struct tegra_runtime_data *)req->dev; | ||
87 | struct snd_pcm_substream *substream = prtd->substream; | ||
88 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
89 | |||
90 | spin_lock(&prtd->lock); | ||
91 | |||
92 | if (!prtd->running) { | ||
93 | spin_unlock(&prtd->lock); | ||
94 | return; | ||
95 | } | ||
96 | |||
97 | if (++prtd->period_index >= runtime->periods) | ||
98 | prtd->period_index = 0; | ||
99 | |||
100 | tegra_pcm_queue_dma(prtd); | ||
101 | |||
102 | spin_unlock(&prtd->lock); | ||
103 | |||
104 | snd_pcm_period_elapsed(substream); | ||
105 | } | ||
106 | |||
107 | static void setup_dma_tx_request(struct tegra_dma_req *req, | ||
108 | struct tegra_pcm_dma_params * dmap) | ||
109 | { | ||
110 | req->complete = dma_complete_callback; | ||
111 | req->to_memory = false; | ||
112 | req->dest_addr = dmap->addr; | ||
113 | req->dest_wrap = dmap->wrap; | ||
114 | req->source_bus_width = 32; | ||
115 | req->source_wrap = 0; | ||
116 | req->dest_bus_width = dmap->width; | ||
117 | req->req_sel = dmap->req_sel; | ||
118 | } | ||
119 | |||
120 | static void setup_dma_rx_request(struct tegra_dma_req *req, | ||
121 | struct tegra_pcm_dma_params * dmap) | ||
122 | { | ||
123 | req->complete = dma_complete_callback; | ||
124 | req->to_memory = true; | ||
125 | req->source_addr = dmap->addr; | ||
126 | req->dest_wrap = 0; | ||
127 | req->source_bus_width = dmap->width; | ||
128 | req->source_wrap = dmap->wrap; | ||
129 | req->dest_bus_width = 32; | ||
130 | req->req_sel = dmap->req_sel; | ||
131 | } | ||
132 | |||
133 | static int tegra_pcm_open(struct snd_pcm_substream *substream) | ||
134 | { | ||
135 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
136 | struct tegra_runtime_data *prtd; | ||
137 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
138 | struct tegra_pcm_dma_params * dmap; | ||
139 | int ret = 0; | ||
140 | |||
141 | prtd = kzalloc(sizeof(struct tegra_runtime_data), GFP_KERNEL); | ||
142 | if (prtd == NULL) | ||
143 | return -ENOMEM; | ||
144 | |||
145 | runtime->private_data = prtd; | ||
146 | prtd->substream = substream; | ||
147 | |||
148 | spin_lock_init(&prtd->lock); | ||
149 | |||
150 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
151 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
152 | setup_dma_tx_request(&prtd->dma_req[0], dmap); | ||
153 | setup_dma_tx_request(&prtd->dma_req[1], dmap); | ||
154 | } else { | ||
155 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
156 | setup_dma_rx_request(&prtd->dma_req[0], dmap); | ||
157 | setup_dma_rx_request(&prtd->dma_req[1], dmap); | ||
158 | } | ||
159 | |||
160 | prtd->dma_req[0].dev = prtd; | ||
161 | prtd->dma_req[1].dev = prtd; | ||
162 | |||
163 | prtd->dma_chan = tegra_dma_allocate_channel(TEGRA_DMA_MODE_ONESHOT); | ||
164 | if (prtd->dma_chan == NULL) { | ||
165 | ret = -ENOMEM; | ||
166 | goto err; | ||
167 | } | ||
168 | |||
169 | /* Set HW params now that initialization is complete */ | ||
170 | snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); | ||
171 | |||
172 | /* Ensure that buffer size is a multiple of period size */ | ||
173 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
174 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
175 | if (ret < 0) | ||
176 | goto err; | ||
177 | |||
178 | return 0; | ||
179 | |||
180 | err: | ||
181 | if (prtd->dma_chan) { | ||
182 | tegra_dma_free_channel(prtd->dma_chan); | ||
183 | } | ||
184 | |||
185 | kfree(prtd); | ||
186 | |||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int tegra_pcm_close(struct snd_pcm_substream *substream) | ||
191 | { | ||
192 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
193 | struct tegra_runtime_data *prtd = runtime->private_data; | ||
194 | |||
195 | tegra_dma_free_channel(prtd->dma_chan); | ||
196 | |||
197 | kfree(prtd); | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, | ||
203 | struct snd_pcm_hw_params *params) | ||
204 | { | ||
205 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
206 | struct tegra_runtime_data *prtd = runtime->private_data; | ||
207 | |||
208 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
209 | |||
210 | prtd->dma_req[0].size = params_period_bytes(params); | ||
211 | prtd->dma_req[1].size = prtd->dma_req[0].size; | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) | ||
217 | { | ||
218 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
224 | { | ||
225 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
226 | struct tegra_runtime_data *prtd = runtime->private_data; | ||
227 | unsigned long flags; | ||
228 | |||
229 | switch (cmd) { | ||
230 | case SNDRV_PCM_TRIGGER_START: | ||
231 | prtd->dma_pos = 0; | ||
232 | prtd->dma_pos_end = frames_to_bytes(runtime, runtime->periods * runtime->period_size); | ||
233 | prtd->period_index = 0; | ||
234 | prtd->dma_req_idx = 0; | ||
235 | /* Fall-through */ | ||
236 | case SNDRV_PCM_TRIGGER_RESUME: | ||
237 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
238 | spin_lock_irqsave(&prtd->lock, flags); | ||
239 | prtd->running = 1; | ||
240 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
241 | tegra_pcm_queue_dma(prtd); | ||
242 | tegra_pcm_queue_dma(prtd); | ||
243 | break; | ||
244 | case SNDRV_PCM_TRIGGER_STOP: | ||
245 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
246 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
247 | spin_lock_irqsave(&prtd->lock, flags); | ||
248 | prtd->running = 0; | ||
249 | spin_unlock_irqrestore(&prtd->lock, flags); | ||
250 | tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[0]); | ||
251 | tegra_dma_dequeue_req(prtd->dma_chan, &prtd->dma_req[1]); | ||
252 | break; | ||
253 | default: | ||
254 | return -EINVAL; | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static snd_pcm_uframes_t tegra_pcm_pointer(struct snd_pcm_substream *substream) | ||
261 | { | ||
262 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
263 | struct tegra_runtime_data *prtd = runtime->private_data; | ||
264 | |||
265 | return prtd->period_index * runtime->period_size; | ||
266 | } | ||
267 | |||
268 | |||
269 | static int tegra_pcm_mmap(struct snd_pcm_substream *substream, | ||
270 | struct vm_area_struct *vma) | ||
271 | { | ||
272 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
273 | |||
274 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
275 | runtime->dma_area, | ||
276 | runtime->dma_addr, | ||
277 | runtime->dma_bytes); | ||
278 | } | ||
279 | |||
280 | static struct snd_pcm_ops tegra_pcm_ops = { | ||
281 | .open = tegra_pcm_open, | ||
282 | .close = tegra_pcm_close, | ||
283 | .ioctl = snd_pcm_lib_ioctl, | ||
284 | .hw_params = tegra_pcm_hw_params, | ||
285 | .hw_free = tegra_pcm_hw_free, | ||
286 | .trigger = tegra_pcm_trigger, | ||
287 | .pointer = tegra_pcm_pointer, | ||
288 | .mmap = tegra_pcm_mmap, | ||
289 | }; | ||
290 | |||
291 | static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
292 | { | ||
293 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
294 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
295 | size_t size = tegra_pcm_hardware.buffer_bytes_max; | ||
296 | |||
297 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
298 | &buf->addr, GFP_KERNEL); | ||
299 | if (!buf->area) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
303 | buf->dev.dev = pcm->card->dev; | ||
304 | buf->private_data = NULL; | ||
305 | buf->bytes = size; | ||
306 | |||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream) | ||
311 | { | ||
312 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
313 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
314 | |||
315 | if (!buf->area) | ||
316 | return; | ||
317 | |||
318 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
319 | buf->area, buf->addr); | ||
320 | buf->area = NULL; | ||
321 | } | ||
322 | |||
323 | static u64 tegra_dma_mask = DMA_BIT_MASK(32); | ||
324 | |||
325 | static int tegra_pcm_new(struct snd_card *card, | ||
326 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
327 | { | ||
328 | int ret = 0; | ||
329 | |||
330 | if (!card->dev->dma_mask) | ||
331 | card->dev->dma_mask = &tegra_dma_mask; | ||
332 | if (!card->dev->coherent_dma_mask) | ||
333 | card->dev->coherent_dma_mask = 0xffffffff; | ||
334 | |||
335 | if (dai->driver->playback.channels_min) { | ||
336 | ret = tegra_pcm_preallocate_dma_buffer(pcm, | ||
337 | SNDRV_PCM_STREAM_PLAYBACK); | ||
338 | if (ret) | ||
339 | goto err; | ||
340 | } | ||
341 | |||
342 | if (dai->driver->capture.channels_min) { | ||
343 | ret = tegra_pcm_preallocate_dma_buffer(pcm, | ||
344 | SNDRV_PCM_STREAM_CAPTURE); | ||
345 | if (ret) | ||
346 | goto err_free_play; | ||
347 | } | ||
348 | |||
349 | return 0; | ||
350 | |||
351 | err_free_play: | ||
352 | tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
353 | err: | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | static void tegra_pcm_free(struct snd_pcm *pcm) | ||
358 | { | ||
359 | tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE); | ||
360 | tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK); | ||
361 | } | ||
362 | |||
363 | struct snd_soc_platform_driver tegra_pcm_platform = { | ||
364 | .ops = &tegra_pcm_ops, | ||
365 | .pcm_new = tegra_pcm_new, | ||
366 | .pcm_free = tegra_pcm_free, | ||
367 | }; | ||
368 | |||
369 | static int __devinit tegra_pcm_platform_probe(struct platform_device *pdev) | ||
370 | { | ||
371 | return snd_soc_register_platform(&pdev->dev, &tegra_pcm_platform); | ||
372 | } | ||
373 | |||
374 | static int __devexit tegra_pcm_platform_remove(struct platform_device *pdev) | ||
375 | { | ||
376 | snd_soc_unregister_platform(&pdev->dev); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static struct platform_driver tegra_pcm_driver = { | ||
381 | .driver = { | ||
382 | .name = DRV_NAME, | ||
383 | .owner = THIS_MODULE, | ||
384 | }, | ||
385 | .probe = tegra_pcm_platform_probe, | ||
386 | .remove = __devexit_p(tegra_pcm_platform_remove), | ||
387 | }; | ||
388 | |||
389 | static int __init snd_tegra_pcm_init(void) | ||
390 | { | ||
391 | return platform_driver_register(&tegra_pcm_driver); | ||
392 | } | ||
393 | module_init(snd_tegra_pcm_init); | ||
394 | |||
395 | static void __exit snd_tegra_pcm_exit(void) | ||
396 | { | ||
397 | platform_driver_unregister(&tegra_pcm_driver); | ||
398 | } | ||
399 | module_exit(snd_tegra_pcm_exit); | ||
400 | |||
401 | MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>"); | ||
402 | MODULE_DESCRIPTION("Tegra PCM ASoC driver"); | ||
403 | MODULE_LICENSE("GPL"); | ||
404 | MODULE_ALIAS("platform:" DRV_NAME); | ||
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h new file mode 100644 index 000000000000..dbb90339fe0d --- /dev/null +++ b/sound/soc/tegra/tegra_pcm.h | |||
@@ -0,0 +1,55 @@ | |||
1 | /* | ||
2 | * tegra_pcm.h - Definitions for Tegra PCM driver | ||
3 | * | ||
4 | * Author: Stephen Warren <swarren@nvidia.com> | ||
5 | * Copyright (C) 2010 - NVIDIA, Inc. | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * | ||
9 | * Copyright (c) 2009-2010, NVIDIA Corporation. | ||
10 | * Scott Peterson <speterson@nvidia.com> | ||
11 | * | ||
12 | * Copyright (C) 2010 Google, Inc. | ||
13 | * Iliyan Malchev <malchev@google.com> | ||
14 | * | ||
15 | * This program is free software; you can redistribute it and/or | ||
16 | * modify it under the terms of the GNU General Public License | ||
17 | * version 2 as published by the Free Software Foundation. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, but | ||
20 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
22 | * General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, write to the Free Software | ||
26 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
27 | * 02110-1301 USA | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef __TEGRA_PCM_H__ | ||
32 | #define __TEGRA_PCM_H__ | ||
33 | |||
34 | #include <mach/dma.h> | ||
35 | |||
36 | struct tegra_pcm_dma_params { | ||
37 | unsigned long addr; | ||
38 | unsigned long wrap; | ||
39 | unsigned long width; | ||
40 | unsigned long req_sel; | ||
41 | }; | ||
42 | |||
43 | struct tegra_runtime_data { | ||
44 | struct snd_pcm_substream *substream; | ||
45 | spinlock_t lock; | ||
46 | int running; | ||
47 | int dma_pos; | ||
48 | int dma_pos_end; | ||
49 | int period_index; | ||
50 | int dma_req_idx; | ||
51 | struct tegra_dma_req dma_req[2]; | ||
52 | struct tegra_dma_channel *dma_chan; | ||
53 | }; | ||
54 | |||
55 | #endif | ||