diff options
author | Paul Mundt <lethal@linux-sh.org> | 2010-08-16 00:32:24 -0400 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2010-08-16 00:32:24 -0400 |
commit | bbcf6e8b66ab2fb5ddab4d0fe40c2e6a5ebe5301 (patch) | |
tree | 071fa9f86dc04a16570be367d04cff3b00c694ad /sound/soc/codecs | |
parent | 57682827b9a5edb52e33af0be9082b51bffcd5c7 (diff) | |
parent | da5cabf80e2433131bf0ed8993abc0f7ea618c73 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
arch/sh/include/asm/Kbuild
drivers/Makefile
Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Diffstat (limited to 'sound/soc/codecs')
41 files changed, 3155 insertions, 370 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 5da30eb6ad00..83f5c67d3c41 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -22,9 +22,11 @@ config SND_SOC_ALL_CODECS | |||
22 | select SND_SOC_AK4642 if I2C | 22 | select SND_SOC_AK4642 if I2C |
23 | select SND_SOC_AK4671 if I2C | 23 | select SND_SOC_AK4671 if I2C |
24 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 24 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
25 | select SND_SOC_CS42L51 if I2C | ||
25 | select SND_SOC_CS4270 if I2C | 26 | select SND_SOC_CS4270 if I2C |
26 | select SND_SOC_MAX9877 if I2C | ||
27 | select SND_SOC_DA7210 if I2C | 27 | select SND_SOC_DA7210 if I2C |
28 | select SND_SOC_JZ4740 if SOC_JZ4740 | ||
29 | select SND_SOC_MAX9877 if I2C | ||
28 | select SND_SOC_PCM3008 | 30 | select SND_SOC_PCM3008 |
29 | select SND_SOC_SPDIF | 31 | select SND_SOC_SPDIF |
30 | select SND_SOC_SSM2602 if I2C | 32 | select SND_SOC_SSM2602 if I2C |
@@ -48,6 +50,7 @@ config SND_SOC_ALL_CODECS | |||
48 | select SND_SOC_WM8727 | 50 | select SND_SOC_WM8727 |
49 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI | 51 | select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI |
50 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI | 52 | select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI |
53 | select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI | ||
51 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI | 54 | select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI |
52 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI | 55 | select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI |
53 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI | 56 | select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI |
@@ -120,13 +123,13 @@ config SND_SOC_AK4671 | |||
120 | config SND_SOC_CQ0093VC | 123 | config SND_SOC_CQ0093VC |
121 | tristate | 124 | tristate |
122 | 125 | ||
126 | config SND_SOC_CS42L51 | ||
127 | tristate | ||
128 | |||
123 | # Cirrus Logic CS4270 Codec | 129 | # Cirrus Logic CS4270 Codec |
124 | config SND_SOC_CS4270 | 130 | config SND_SOC_CS4270 |
125 | tristate | 131 | tristate |
126 | 132 | ||
127 | config SND_SOC_DA7210 | ||
128 | tristate | ||
129 | |||
130 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 133 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
131 | # Select if you are affected by the errata where the part will not function | 134 | # Select if you are affected by the errata where the part will not function |
132 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will | 135 | # if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will |
@@ -138,9 +141,15 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
138 | config SND_SOC_CX20442 | 141 | config SND_SOC_CX20442 |
139 | tristate | 142 | tristate |
140 | 143 | ||
144 | config SND_SOC_JZ4740_CODEC | ||
145 | tristate | ||
146 | |||
141 | config SND_SOC_L3 | 147 | config SND_SOC_L3 |
142 | tristate | 148 | tristate |
143 | 149 | ||
150 | config SND_SOC_DA7210 | ||
151 | tristate | ||
152 | |||
144 | config SND_SOC_PCM3008 | 153 | config SND_SOC_PCM3008 |
145 | tristate | 154 | tristate |
146 | 155 | ||
@@ -206,6 +215,9 @@ config SND_SOC_WM8728 | |||
206 | config SND_SOC_WM8731 | 215 | config SND_SOC_WM8731 |
207 | tristate | 216 | tristate |
208 | 217 | ||
218 | config SND_SOC_WM8741 | ||
219 | tristate | ||
220 | |||
209 | config SND_SOC_WM8750 | 221 | config SND_SOC_WM8750 |
210 | tristate | 222 | tristate |
211 | 223 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 91429eab0707..53524095759c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o | |||
9 | snd-soc-ak4642-objs := ak4642.o | 9 | snd-soc-ak4642-objs := ak4642.o |
10 | snd-soc-ak4671-objs := ak4671.o | 10 | snd-soc-ak4671-objs := ak4671.o |
11 | snd-soc-cq93vc-objs := cq93vc.o | 11 | snd-soc-cq93vc-objs := cq93vc.o |
12 | snd-soc-cs42l51-objs := cs42l51.o | ||
12 | snd-soc-cs4270-objs := cs4270.o | 13 | snd-soc-cs4270-objs := cs4270.o |
13 | snd-soc-cx20442-objs := cx20442.o | 14 | snd-soc-cx20442-objs := cx20442.o |
14 | snd-soc-da7210-objs := da7210.o | 15 | snd-soc-da7210-objs := da7210.o |
@@ -34,6 +35,7 @@ snd-soc-wm8711-objs := wm8711.o | |||
34 | snd-soc-wm8727-objs := wm8727.o | 35 | snd-soc-wm8727-objs := wm8727.o |
35 | snd-soc-wm8728-objs := wm8728.o | 36 | snd-soc-wm8728-objs := wm8728.o |
36 | snd-soc-wm8731-objs := wm8731.o | 37 | snd-soc-wm8731-objs := wm8731.o |
38 | snd-soc-wm8741-objs := wm8741.o | ||
37 | snd-soc-wm8750-objs := wm8750.o | 39 | snd-soc-wm8750-objs := wm8750.o |
38 | snd-soc-wm8753-objs := wm8753.o | 40 | snd-soc-wm8753-objs := wm8753.o |
39 | snd-soc-wm8776-objs := wm8776.o | 41 | snd-soc-wm8776-objs := wm8776.o |
@@ -56,6 +58,7 @@ snd-soc-wm9705-objs := wm9705.o | |||
56 | snd-soc-wm9712-objs := wm9712.o | 58 | snd-soc-wm9712-objs := wm9712.o |
57 | snd-soc-wm9713-objs := wm9713.o | 59 | snd-soc-wm9713-objs := wm9713.o |
58 | snd-soc-wm-hubs-objs := wm_hubs.o | 60 | snd-soc-wm-hubs-objs := wm_hubs.o |
61 | snd-soc-jz4740-codec-objs := jz4740.o | ||
59 | 62 | ||
60 | # Amp | 63 | # Amp |
61 | snd-soc-max9877-objs := max9877.o | 64 | snd-soc-max9877-objs := max9877.o |
@@ -74,10 +77,12 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | |||
74 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | 77 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o |
75 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 78 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
76 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 79 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
80 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | ||
77 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 81 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
78 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 82 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
79 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | 83 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o |
80 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 84 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
85 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | ||
81 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 86 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
82 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 87 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o |
83 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 88 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
@@ -99,6 +104,7 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o | |||
99 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o | 104 | obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o |
100 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o | 105 | obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o |
101 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o | 106 | obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o |
107 | obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o | ||
102 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o | 108 | obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o |
103 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o | 109 | obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o |
104 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o | 110 | obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 217538423225..a01006c8c606 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -272,6 +272,7 @@ static int ad1836_register(struct ad1836_priv *ad1836) | |||
272 | 272 | ||
273 | if (ad1836_codec) { | 273 | if (ad1836_codec) { |
274 | dev_err(codec->dev, "Another ad1836 is registered\n"); | 274 | dev_err(codec->dev, "Another ad1836 is registered\n"); |
275 | kfree(ad1836); | ||
275 | return -EINVAL; | 276 | return -EINVAL; |
276 | } | 277 | } |
277 | 278 | ||
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index c8ca1142b2f4..1def75e4862f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -24,6 +24,7 @@ | |||
24 | 24 | ||
25 | /* codec private data */ | 25 | /* codec private data */ |
26 | struct ad193x_priv { | 26 | struct ad193x_priv { |
27 | unsigned int sysclk; | ||
27 | struct snd_soc_codec codec; | 28 | struct snd_soc_codec codec; |
28 | u8 reg_cache[AD193X_NUM_REGS]; | 29 | u8 reg_cache[AD193X_NUM_REGS]; |
29 | }; | 30 | }; |
@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
251 | return 0; | 252 | return 0; |
252 | } | 253 | } |
253 | 254 | ||
255 | static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
256 | int clk_id, unsigned int freq, int dir) | ||
257 | { | ||
258 | struct snd_soc_codec *codec = codec_dai->codec; | ||
259 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | ||
260 | switch (freq) { | ||
261 | case 12288000: | ||
262 | case 18432000: | ||
263 | case 24576000: | ||
264 | case 36864000: | ||
265 | ad193x->sysclk = freq; | ||
266 | return 0; | ||
267 | } | ||
268 | return -EINVAL; | ||
269 | } | ||
270 | |||
254 | static int ad193x_hw_params(struct snd_pcm_substream *substream, | 271 | static int ad193x_hw_params(struct snd_pcm_substream *substream, |
255 | struct snd_pcm_hw_params *params, | 272 | struct snd_pcm_hw_params *params, |
256 | struct snd_soc_dai *dai) | 273 | struct snd_soc_dai *dai) |
257 | { | 274 | { |
258 | int word_len = 0, reg = 0; | 275 | int word_len = 0, reg = 0, master_rate = 0; |
259 | 276 | ||
260 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 277 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
261 | struct snd_soc_device *socdev = rtd->socdev; | 278 | struct snd_soc_device *socdev = rtd->socdev; |
262 | struct snd_soc_codec *codec = socdev->card->codec; | 279 | struct snd_soc_codec *codec = socdev->card->codec; |
280 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | ||
263 | 281 | ||
264 | /* bit size */ | 282 | /* bit size */ |
265 | switch (params_format(params)) { | 283 | switch (params_format(params)) { |
@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream, | |||
275 | break; | 293 | break; |
276 | } | 294 | } |
277 | 295 | ||
296 | switch (ad193x->sysclk) { | ||
297 | case 12288000: | ||
298 | master_rate = AD193X_PLL_INPUT_256; | ||
299 | break; | ||
300 | case 18432000: | ||
301 | master_rate = AD193X_PLL_INPUT_384; | ||
302 | break; | ||
303 | case 24576000: | ||
304 | master_rate = AD193X_PLL_INPUT_512; | ||
305 | break; | ||
306 | case 36864000: | ||
307 | master_rate = AD193X_PLL_INPUT_768; | ||
308 | break; | ||
309 | } | ||
310 | |||
311 | reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0); | ||
312 | reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate; | ||
313 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg); | ||
314 | |||
278 | reg = snd_soc_read(codec, AD193X_DAC_CTRL2); | 315 | reg = snd_soc_read(codec, AD193X_DAC_CTRL2); |
279 | reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; | 316 | reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len; |
280 | snd_soc_write(codec, AD193X_DAC_CTRL2, reg); | 317 | snd_soc_write(codec, AD193X_DAC_CTRL2, reg); |
@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type) | |||
348 | /* pll input: mclki/xi */ | 385 | /* pll input: mclki/xi */ |
349 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ | 386 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */ |
350 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); | 387 | snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04); |
388 | ad193x->sysclk = 12288000; | ||
351 | 389 | ||
352 | ret = snd_soc_register_codec(codec); | 390 | ret = snd_soc_register_codec(codec); |
353 | if (ret != 0) { | 391 | if (ret != 0) { |
@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = { | |||
383 | .hw_params = ad193x_hw_params, | 421 | .hw_params = ad193x_hw_params, |
384 | .digital_mute = ad193x_mute, | 422 | .digital_mute = ad193x_mute, |
385 | .set_tdm_slot = ad193x_set_tdm_slot, | 423 | .set_tdm_slot = ad193x_set_tdm_slot, |
424 | .set_sysclk = ad193x_set_dai_sysclk, | ||
386 | .set_fmt = ad193x_set_dai_fmt, | 425 | .set_fmt = ad193x_set_dai_fmt, |
387 | }; | 426 | }; |
388 | 427 | ||
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index a03c880d52f9..654ba64ae04c 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h | |||
@@ -11,6 +11,11 @@ | |||
11 | 11 | ||
12 | #define AD193X_PLL_CLK_CTRL0 0x800 | 12 | #define AD193X_PLL_CLK_CTRL0 0x800 |
13 | #define AD193X_PLL_POWERDOWN 0x01 | 13 | #define AD193X_PLL_POWERDOWN 0x01 |
14 | #define AD193X_PLL_INPUT_MASK (~0x6) | ||
15 | #define AD193X_PLL_INPUT_256 (0 << 1) | ||
16 | #define AD193X_PLL_INPUT_384 (1 << 1) | ||
17 | #define AD193X_PLL_INPUT_512 (2 << 1) | ||
18 | #define AD193X_PLL_INPUT_768 (3 << 1) | ||
14 | #define AD193X_PLL_CLK_CTRL1 0x801 | 19 | #define AD193X_PLL_CLK_CTRL1 0x801 |
15 | #define AD193X_DAC_CTRL0 0x802 | 20 | #define AD193X_DAC_CTRL0 0x802 |
16 | #define AD193X_DAC_POWERDOWN 0x01 | 21 | #define AD193X_DAC_POWERDOWN 0x01 |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 042072738cdc..70cfaec3be2c 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -11,6 +11,14 @@ | |||
11 | * option) any later version. | 11 | * option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* | ||
15 | * WARNING: | ||
16 | * | ||
17 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
18 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
19 | * by ADI now. | ||
20 | */ | ||
21 | |||
14 | #include <linux/init.h> | 22 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
16 | #include <linux/module.h> | 24 | #include <linux/module.h> |
@@ -298,6 +306,6 @@ struct snd_soc_codec_device soc_codec_dev_ad1980 = { | |||
298 | }; | 306 | }; |
299 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); | 307 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1980); |
300 | 308 | ||
301 | MODULE_DESCRIPTION("ASoC ad1980 driver"); | 309 | MODULE_DESCRIPTION("ASoC ad1980 driver (Obsolete)"); |
302 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); | 310 | MODULE_AUTHOR("Roy Huang, Cliff Cai"); |
303 | MODULE_LICENSE("GPL"); | 311 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h index db6c8500d66b..538f37c90806 100644 --- a/sound/soc/codecs/ad1980.h +++ b/sound/soc/codecs/ad1980.h | |||
@@ -1,5 +1,11 @@ | |||
1 | /* | 1 | /* |
2 | * ad1980.h -- ad1980 Soc Audio driver | 2 | * ad1980.h -- ad1980 Soc Audio driver |
3 | * | ||
4 | * WARNING: | ||
5 | * | ||
6 | * Because Analog Devices Inc. discontinued the ad1980 sound chip since | ||
7 | * Sep. 2009, this ad1980 driver is not maintained, tested and supported | ||
8 | * by ADI now. | ||
3 | */ | 9 | */ |
4 | 10 | ||
5 | #ifndef _AD1980_H | 11 | #ifndef _AD1980_H |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7528a54102b5..3d7dc55305ec 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c | |||
@@ -22,20 +22,13 @@ | |||
22 | * AK4643 is tested. | 22 | * AK4643 is tested. |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | 25 | #include <linux/delay.h> |
29 | #include <linux/pm.h> | ||
30 | #include <linux/i2c.h> | 26 | #include <linux/i2c.h> |
31 | #include <linux/platform_device.h> | 27 | #include <linux/platform_device.h> |
32 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
33 | #include <sound/core.h> | ||
34 | #include <sound/pcm.h> | ||
35 | #include <sound/pcm_params.h> | ||
36 | #include <sound/soc.h> | ||
37 | #include <sound/soc-dapm.h> | 29 | #include <sound/soc-dapm.h> |
38 | #include <sound/initval.h> | 30 | #include <sound/initval.h> |
31 | #include <sound/tlv.h> | ||
39 | 32 | ||
40 | #include "ak4642.h" | 33 | #include "ak4642.h" |
41 | 34 | ||
@@ -111,6 +104,23 @@ | |||
111 | 104 | ||
112 | struct snd_soc_codec_device soc_codec_dev_ak4642; | 105 | struct snd_soc_codec_device soc_codec_dev_ak4642; |
113 | 106 | ||
107 | /* | ||
108 | * Playback Volume (table 39) | ||
109 | * | ||
110 | * max : 0x00 : +12.0 dB | ||
111 | * ( 0.5 dB step ) | ||
112 | * min : 0xFE : -115.0 dB | ||
113 | * mute: 0xFF | ||
114 | */ | ||
115 | static const DECLARE_TLV_DB_SCALE(out_tlv, -11500, 50, 1); | ||
116 | |||
117 | static const struct snd_kcontrol_new ak4642_snd_controls[] = { | ||
118 | |||
119 | SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, | ||
120 | 0, 0xFF, 1, out_tlv), | ||
121 | }; | ||
122 | |||
123 | |||
114 | /* codec private data */ | 124 | /* codec private data */ |
115 | struct ak4642_priv { | 125 | struct ak4642_priv { |
116 | struct snd_soc_codec codec; | 126 | struct snd_soc_codec codec; |
@@ -204,7 +214,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, | |||
204 | * | 214 | * |
205 | * PLL, Master Mode | 215 | * PLL, Master Mode |
206 | * Audio I/F Format :MSB justified (ADC & DAC) | 216 | * Audio I/F Format :MSB justified (ADC & DAC) |
207 | * Digital Volume: -8dB | ||
208 | * Bass Boost Level : Middle | 217 | * Bass Boost Level : Middle |
209 | * | 218 | * |
210 | * This operation came from example code of | 219 | * This operation came from example code of |
@@ -214,8 +223,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream, | |||
214 | ak4642_write(codec, 0x0e, 0x19); | 223 | ak4642_write(codec, 0x0e, 0x19); |
215 | ak4642_write(codec, 0x09, 0x91); | 224 | ak4642_write(codec, 0x09, 0x91); |
216 | ak4642_write(codec, 0x0c, 0x91); | 225 | ak4642_write(codec, 0x0c, 0x91); |
217 | ak4642_write(codec, 0x0a, 0x28); | ||
218 | ak4642_write(codec, 0x0d, 0x28); | ||
219 | ak4642_write(codec, 0x00, 0x64); | 226 | ak4642_write(codec, 0x00, 0x64); |
220 | snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); | 227 | snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); |
221 | snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); | 228 | snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN); |
@@ -491,8 +498,10 @@ static int ak4642_i2c_probe(struct i2c_client *i2c, | |||
491 | codec->control_data = i2c; | 498 | codec->control_data = i2c; |
492 | 499 | ||
493 | ret = ak4642_init(ak4642); | 500 | ret = ak4642_init(ak4642); |
494 | if (ret < 0) | 501 | if (ret < 0) { |
495 | printk(KERN_ERR "failed to initialise AK4642\n"); | 502 | printk(KERN_ERR "failed to initialise AK4642\n"); |
503 | kfree(ak4642); | ||
504 | } | ||
496 | 505 | ||
497 | return ret; | 506 | return ret; |
498 | } | 507 | } |
@@ -548,6 +557,9 @@ static int ak4642_probe(struct platform_device *pdev) | |||
548 | goto pcm_err; | 557 | goto pcm_err; |
549 | } | 558 | } |
550 | 559 | ||
560 | snd_soc_add_controls(ak4642_codec, ak4642_snd_controls, | ||
561 | ARRAY_SIZE(ak4642_snd_controls)); | ||
562 | |||
551 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); | 563 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); |
552 | return ret; | 564 | return ret; |
553 | 565 | ||
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c new file mode 100644 index 000000000000..dd9b8550c402 --- /dev/null +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -0,0 +1,763 @@ | |||
1 | /* | ||
2 | * cs42l51.c | ||
3 | * | ||
4 | * ASoC Driver for Cirrus Logic CS42L51 codecs | ||
5 | * | ||
6 | * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
7 | * | ||
8 | * Based on cs4270.c - Copyright (c) Freescale Semiconductor | ||
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 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * For now: | ||
20 | * - Only I2C is support. Not SPI | ||
21 | * - master mode *NOT* supported | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <sound/core.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | #include <sound/tlv.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include <sound/pcm_params.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <linux/i2c.h> | ||
35 | |||
36 | #include "cs42l51.h" | ||
37 | |||
38 | enum master_slave_mode { | ||
39 | MODE_SLAVE, | ||
40 | MODE_SLAVE_AUTO, | ||
41 | MODE_MASTER, | ||
42 | }; | ||
43 | |||
44 | struct cs42l51_private { | ||
45 | unsigned int mclk; | ||
46 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ | ||
47 | enum master_slave_mode func; | ||
48 | struct snd_soc_codec codec; | ||
49 | u8 reg_cache[CS42L51_NUMREGS]; | ||
50 | }; | ||
51 | |||
52 | static struct snd_soc_codec *cs42l51_codec; | ||
53 | |||
54 | #define CS42L51_FORMATS ( \ | ||
55 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ | ||
56 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ | ||
57 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | ||
58 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | ||
59 | |||
60 | static int cs42l51_fill_cache(struct snd_soc_codec *codec) | ||
61 | { | ||
62 | u8 *cache = codec->reg_cache + 1; | ||
63 | struct i2c_client *i2c_client = codec->control_data; | ||
64 | s32 length; | ||
65 | |||
66 | length = i2c_smbus_read_i2c_block_data(i2c_client, | ||
67 | CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); | ||
68 | if (length != CS42L51_NUMREGS) { | ||
69 | dev_err(&i2c_client->dev, | ||
70 | "I2C read failure, addr=0x%x (ret=%d vs %d)\n", | ||
71 | i2c_client->addr, length, CS42L51_NUMREGS); | ||
72 | return -EIO; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, | ||
79 | const struct i2c_device_id *id) | ||
80 | { | ||
81 | struct snd_soc_codec *codec; | ||
82 | struct cs42l51_private *cs42l51; | ||
83 | int ret = 0; | ||
84 | int reg; | ||
85 | |||
86 | if (cs42l51_codec) | ||
87 | return -EBUSY; | ||
88 | |||
89 | /* Verify that we have a CS42L51 */ | ||
90 | ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); | ||
91 | if (ret < 0) { | ||
92 | dev_err(&i2c_client->dev, "failed to read I2C\n"); | ||
93 | goto error; | ||
94 | } | ||
95 | |||
96 | if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && | ||
97 | (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { | ||
98 | dev_err(&i2c_client->dev, "Invalid chip id\n"); | ||
99 | ret = -ENODEV; | ||
100 | goto error; | ||
101 | } | ||
102 | |||
103 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", | ||
104 | ret & 7); | ||
105 | |||
106 | cs42l51 = kzalloc(sizeof(struct cs42l51_private), GFP_KERNEL); | ||
107 | if (!cs42l51) { | ||
108 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
109 | return -ENOMEM; | ||
110 | } | ||
111 | codec = &cs42l51->codec; | ||
112 | |||
113 | mutex_init(&codec->mutex); | ||
114 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
115 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
116 | |||
117 | codec->dev = &i2c_client->dev; | ||
118 | codec->name = "CS42L51"; | ||
119 | codec->owner = THIS_MODULE; | ||
120 | codec->dai = &cs42l51_dai; | ||
121 | codec->num_dai = 1; | ||
122 | snd_soc_codec_set_drvdata(codec, cs42l51); | ||
123 | |||
124 | codec->control_data = i2c_client; | ||
125 | codec->reg_cache = cs42l51->reg_cache; | ||
126 | codec->reg_cache_size = CS42L51_NUMREGS; | ||
127 | i2c_set_clientdata(i2c_client, codec); | ||
128 | |||
129 | ret = cs42l51_fill_cache(codec); | ||
130 | if (ret < 0) { | ||
131 | dev_err(&i2c_client->dev, "failed to fill register cache\n"); | ||
132 | goto error_alloc; | ||
133 | } | ||
134 | |||
135 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_I2C); | ||
136 | if (ret < 0) { | ||
137 | dev_err(&i2c_client->dev, "Failed to set cache I/O: %d\n", ret); | ||
138 | goto error_alloc; | ||
139 | } | ||
140 | |||
141 | /* | ||
142 | * DAC configuration | ||
143 | * - Use signal processor | ||
144 | * - auto mute | ||
145 | * - vol changes immediate | ||
146 | * - no de-emphasize | ||
147 | */ | ||
148 | reg = CS42L51_DAC_CTL_DATA_SEL(1) | ||
149 | | CS42L51_DAC_CTL_AMUTE | CS42L51_DAC_CTL_DACSZ(0); | ||
150 | ret = snd_soc_write(codec, CS42L51_DAC_CTL, reg); | ||
151 | if (ret < 0) | ||
152 | goto error_alloc; | ||
153 | |||
154 | cs42l51_dai.dev = codec->dev; | ||
155 | cs42l51_codec = codec; | ||
156 | |||
157 | ret = snd_soc_register_codec(codec); | ||
158 | if (ret != 0) { | ||
159 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
160 | goto error_alloc; | ||
161 | } | ||
162 | |||
163 | ret = snd_soc_register_dai(&cs42l51_dai); | ||
164 | if (ret < 0) { | ||
165 | dev_err(&i2c_client->dev, "failed to register DAIe\n"); | ||
166 | goto error_reg; | ||
167 | } | ||
168 | |||
169 | return 0; | ||
170 | |||
171 | error_reg: | ||
172 | snd_soc_unregister_codec(codec); | ||
173 | error_alloc: | ||
174 | kfree(cs42l51); | ||
175 | error: | ||
176 | return ret; | ||
177 | } | ||
178 | |||
179 | static int cs42l51_i2c_remove(struct i2c_client *client) | ||
180 | { | ||
181 | struct cs42l51_private *cs42l51 = i2c_get_clientdata(client); | ||
182 | snd_soc_unregister_dai(&cs42l51_dai); | ||
183 | snd_soc_unregister_codec(cs42l51_codec); | ||
184 | cs42l51_codec = NULL; | ||
185 | kfree(cs42l51); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | |||
190 | static const struct i2c_device_id cs42l51_id[] = { | ||
191 | {"cs42l51", 0}, | ||
192 | {} | ||
193 | }; | ||
194 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); | ||
195 | |||
196 | static struct i2c_driver cs42l51_i2c_driver = { | ||
197 | .driver = { | ||
198 | .name = "CS42L51 I2C", | ||
199 | .owner = THIS_MODULE, | ||
200 | }, | ||
201 | .id_table = cs42l51_id, | ||
202 | .probe = cs42l51_i2c_probe, | ||
203 | .remove = cs42l51_i2c_remove, | ||
204 | }; | ||
205 | |||
206 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, | ||
207 | struct snd_ctl_elem_value *ucontrol) | ||
208 | { | ||
209 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
210 | unsigned long value = snd_soc_read(codec, CS42L51_PCM_MIXER)&3; | ||
211 | |||
212 | switch (value) { | ||
213 | default: | ||
214 | case 0: | ||
215 | ucontrol->value.integer.value[0] = 0; | ||
216 | break; | ||
217 | /* same value : (L+R)/2 and (R+L)/2 */ | ||
218 | case 1: | ||
219 | case 2: | ||
220 | ucontrol->value.integer.value[0] = 1; | ||
221 | break; | ||
222 | case 3: | ||
223 | ucontrol->value.integer.value[0] = 2; | ||
224 | break; | ||
225 | } | ||
226 | |||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | #define CHAN_MIX_NORMAL 0x00 | ||
231 | #define CHAN_MIX_BOTH 0x55 | ||
232 | #define CHAN_MIX_SWAP 0xFF | ||
233 | |||
234 | static int cs42l51_set_chan_mix(struct snd_kcontrol *kcontrol, | ||
235 | struct snd_ctl_elem_value *ucontrol) | ||
236 | { | ||
237 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
238 | unsigned char val; | ||
239 | |||
240 | switch (ucontrol->value.integer.value[0]) { | ||
241 | default: | ||
242 | case 0: | ||
243 | val = CHAN_MIX_NORMAL; | ||
244 | break; | ||
245 | case 1: | ||
246 | val = CHAN_MIX_BOTH; | ||
247 | break; | ||
248 | case 2: | ||
249 | val = CHAN_MIX_SWAP; | ||
250 | break; | ||
251 | } | ||
252 | |||
253 | snd_soc_write(codec, CS42L51_PCM_MIXER, val); | ||
254 | |||
255 | return 1; | ||
256 | } | ||
257 | |||
258 | static const DECLARE_TLV_DB_SCALE(adc_pcm_tlv, -5150, 50, 0); | ||
259 | static const DECLARE_TLV_DB_SCALE(tone_tlv, -1050, 150, 0); | ||
260 | /* This is a lie. after -102 db, it stays at -102 */ | ||
261 | /* maybe a range would be better */ | ||
262 | static const DECLARE_TLV_DB_SCALE(aout_tlv, -11550, 50, 0); | ||
263 | |||
264 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 1600, 1600, 0); | ||
265 | static const char *chan_mix[] = { | ||
266 | "L R", | ||
267 | "L+R", | ||
268 | "R L", | ||
269 | }; | ||
270 | |||
271 | static const struct soc_enum cs42l51_chan_mix = | ||
272 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(chan_mix), chan_mix); | ||
273 | |||
274 | static const struct snd_kcontrol_new cs42l51_snd_controls[] = { | ||
275 | SOC_DOUBLE_R_SX_TLV("PCM Playback Volume", | ||
276 | CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, | ||
277 | 7, 0xffffff99, 0x18, adc_pcm_tlv), | ||
278 | SOC_DOUBLE_R("PCM Playback Switch", | ||
279 | CS42L51_PCMA_VOL, CS42L51_PCMB_VOL, 7, 1, 1), | ||
280 | SOC_DOUBLE_R_SX_TLV("Analog Playback Volume", | ||
281 | CS42L51_AOUTA_VOL, CS42L51_AOUTB_VOL, | ||
282 | 8, 0xffffff19, 0x18, aout_tlv), | ||
283 | SOC_DOUBLE_R_SX_TLV("ADC Mixer Volume", | ||
284 | CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, | ||
285 | 7, 0xffffff99, 0x18, adc_pcm_tlv), | ||
286 | SOC_DOUBLE_R("ADC Mixer Switch", | ||
287 | CS42L51_ADCA_VOL, CS42L51_ADCB_VOL, 7, 1, 1), | ||
288 | SOC_SINGLE("Playback Deemphasis Switch", CS42L51_DAC_CTL, 3, 1, 0), | ||
289 | SOC_SINGLE("Auto-Mute Switch", CS42L51_DAC_CTL, 2, 1, 0), | ||
290 | SOC_SINGLE("Soft Ramp Switch", CS42L51_DAC_CTL, 1, 1, 0), | ||
291 | SOC_SINGLE("Zero Cross Switch", CS42L51_DAC_CTL, 0, 0, 0), | ||
292 | SOC_DOUBLE_TLV("Mic Boost Volume", | ||
293 | CS42L51_MIC_CTL, 0, 1, 1, 0, boost_tlv), | ||
294 | SOC_SINGLE_TLV("Bass Volume", CS42L51_TONE_CTL, 0, 0xf, 1, tone_tlv), | ||
295 | SOC_SINGLE_TLV("Treble Volume", CS42L51_TONE_CTL, 4, 0xf, 1, tone_tlv), | ||
296 | SOC_ENUM_EXT("PCM channel mixer", | ||
297 | cs42l51_chan_mix, | ||
298 | cs42l51_get_chan_mix, cs42l51_set_chan_mix), | ||
299 | }; | ||
300 | |||
301 | /* | ||
302 | * to power down, one must: | ||
303 | * 1.) Enable the PDN bit | ||
304 | * 2.) enable power-down for the select channels | ||
305 | * 3.) disable the PDN bit. | ||
306 | */ | ||
307 | static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w, | ||
308 | struct snd_kcontrol *kcontrol, int event) | ||
309 | { | ||
310 | unsigned long value; | ||
311 | |||
312 | value = snd_soc_read(w->codec, CS42L51_POWER_CTL1); | ||
313 | value &= ~CS42L51_POWER_CTL1_PDN; | ||
314 | |||
315 | switch (event) { | ||
316 | case SND_SOC_DAPM_PRE_PMD: | ||
317 | value |= CS42L51_POWER_CTL1_PDN; | ||
318 | break; | ||
319 | default: | ||
320 | case SND_SOC_DAPM_POST_PMD: | ||
321 | break; | ||
322 | } | ||
323 | snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1, | ||
324 | CS42L51_POWER_CTL1_PDN, value); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static const char *cs42l51_dac_names[] = {"Direct PCM", | ||
330 | "DSP PCM", "ADC"}; | ||
331 | static const struct soc_enum cs42l51_dac_mux_enum = | ||
332 | SOC_ENUM_SINGLE(CS42L51_DAC_CTL, 6, 3, cs42l51_dac_names); | ||
333 | static const struct snd_kcontrol_new cs42l51_dac_mux_controls = | ||
334 | SOC_DAPM_ENUM("Route", cs42l51_dac_mux_enum); | ||
335 | |||
336 | static const char *cs42l51_adcl_names[] = {"AIN1 Left", "AIN2 Left", | ||
337 | "MIC Left", "MIC+preamp Left"}; | ||
338 | static const struct soc_enum cs42l51_adcl_mux_enum = | ||
339 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 4, 4, cs42l51_adcl_names); | ||
340 | static const struct snd_kcontrol_new cs42l51_adcl_mux_controls = | ||
341 | SOC_DAPM_ENUM("Route", cs42l51_adcl_mux_enum); | ||
342 | |||
343 | static const char *cs42l51_adcr_names[] = {"AIN1 Right", "AIN2 Right", | ||
344 | "MIC Right", "MIC+preamp Right"}; | ||
345 | static const struct soc_enum cs42l51_adcr_mux_enum = | ||
346 | SOC_ENUM_SINGLE(CS42L51_ADC_INPUT, 6, 4, cs42l51_adcr_names); | ||
347 | static const struct snd_kcontrol_new cs42l51_adcr_mux_controls = | ||
348 | SOC_DAPM_ENUM("Route", cs42l51_adcr_mux_enum); | ||
349 | |||
350 | static const struct snd_soc_dapm_widget cs42l51_dapm_widgets[] = { | ||
351 | SND_SOC_DAPM_MICBIAS("Mic Bias", CS42L51_MIC_POWER_CTL, 1, 1), | ||
352 | SND_SOC_DAPM_PGA_E("Left PGA", CS42L51_POWER_CTL1, 3, 1, NULL, 0, | ||
353 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
354 | SND_SOC_DAPM_PGA_E("Right PGA", CS42L51_POWER_CTL1, 4, 1, NULL, 0, | ||
355 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
356 | SND_SOC_DAPM_ADC_E("Left ADC", "Left HiFi Capture", | ||
357 | CS42L51_POWER_CTL1, 1, 1, | ||
358 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
359 | SND_SOC_DAPM_ADC_E("Right ADC", "Right HiFi Capture", | ||
360 | CS42L51_POWER_CTL1, 2, 1, | ||
361 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
362 | SND_SOC_DAPM_DAC_E("Left DAC", "Left HiFi Playback", | ||
363 | CS42L51_POWER_CTL1, 5, 1, | ||
364 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
365 | SND_SOC_DAPM_DAC_E("Right DAC", "Right HiFi Playback", | ||
366 | CS42L51_POWER_CTL1, 6, 1, | ||
367 | cs42l51_pdn_event, SND_SOC_DAPM_PRE_POST_PMD), | ||
368 | |||
369 | /* analog/mic */ | ||
370 | SND_SOC_DAPM_INPUT("AIN1L"), | ||
371 | SND_SOC_DAPM_INPUT("AIN1R"), | ||
372 | SND_SOC_DAPM_INPUT("AIN2L"), | ||
373 | SND_SOC_DAPM_INPUT("AIN2R"), | ||
374 | SND_SOC_DAPM_INPUT("MICL"), | ||
375 | SND_SOC_DAPM_INPUT("MICR"), | ||
376 | |||
377 | SND_SOC_DAPM_MIXER("Mic Preamp Left", | ||
378 | CS42L51_MIC_POWER_CTL, 2, 1, NULL, 0), | ||
379 | SND_SOC_DAPM_MIXER("Mic Preamp Right", | ||
380 | CS42L51_MIC_POWER_CTL, 3, 1, NULL, 0), | ||
381 | |||
382 | /* HP */ | ||
383 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
384 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
385 | |||
386 | /* mux */ | ||
387 | SND_SOC_DAPM_MUX("DAC Mux", SND_SOC_NOPM, 0, 0, | ||
388 | &cs42l51_dac_mux_controls), | ||
389 | SND_SOC_DAPM_MUX("PGA-ADC Mux Left", SND_SOC_NOPM, 0, 0, | ||
390 | &cs42l51_adcl_mux_controls), | ||
391 | SND_SOC_DAPM_MUX("PGA-ADC Mux Right", SND_SOC_NOPM, 0, 0, | ||
392 | &cs42l51_adcr_mux_controls), | ||
393 | }; | ||
394 | |||
395 | static const struct snd_soc_dapm_route cs42l51_routes[] = { | ||
396 | {"HPL", NULL, "Left DAC"}, | ||
397 | {"HPR", NULL, "Right DAC"}, | ||
398 | |||
399 | {"Left ADC", NULL, "Left PGA"}, | ||
400 | {"Right ADC", NULL, "Right PGA"}, | ||
401 | |||
402 | {"Mic Preamp Left", NULL, "MICL"}, | ||
403 | {"Mic Preamp Right", NULL, "MICR"}, | ||
404 | |||
405 | {"PGA-ADC Mux Left", "AIN1 Left", "AIN1L" }, | ||
406 | {"PGA-ADC Mux Left", "AIN2 Left", "AIN2L" }, | ||
407 | {"PGA-ADC Mux Left", "MIC Left", "MICL" }, | ||
408 | {"PGA-ADC Mux Left", "MIC+preamp Left", "Mic Preamp Left" }, | ||
409 | {"PGA-ADC Mux Right", "AIN1 Right", "AIN1R" }, | ||
410 | {"PGA-ADC Mux Right", "AIN2 Right", "AIN2R" }, | ||
411 | {"PGA-ADC Mux Right", "MIC Right", "MICR" }, | ||
412 | {"PGA-ADC Mux Right", "MIC+preamp Right", "Mic Preamp Right" }, | ||
413 | |||
414 | {"Left PGA", NULL, "PGA-ADC Mux Left"}, | ||
415 | {"Right PGA", NULL, "PGA-ADC Mux Right"}, | ||
416 | }; | ||
417 | |||
418 | static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
419 | unsigned int format) | ||
420 | { | ||
421 | struct snd_soc_codec *codec = codec_dai->codec; | ||
422 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
423 | int ret = 0; | ||
424 | |||
425 | switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
426 | case SND_SOC_DAIFMT_I2S: | ||
427 | case SND_SOC_DAIFMT_LEFT_J: | ||
428 | case SND_SOC_DAIFMT_RIGHT_J: | ||
429 | cs42l51->audio_mode = format & SND_SOC_DAIFMT_FORMAT_MASK; | ||
430 | break; | ||
431 | default: | ||
432 | dev_err(codec->dev, "invalid DAI format\n"); | ||
433 | ret = -EINVAL; | ||
434 | } | ||
435 | |||
436 | switch (format & SND_SOC_DAIFMT_MASTER_MASK) { | ||
437 | case SND_SOC_DAIFMT_CBM_CFM: | ||
438 | cs42l51->func = MODE_MASTER; | ||
439 | break; | ||
440 | case SND_SOC_DAIFMT_CBS_CFS: | ||
441 | cs42l51->func = MODE_SLAVE_AUTO; | ||
442 | break; | ||
443 | default: | ||
444 | ret = -EINVAL; | ||
445 | break; | ||
446 | } | ||
447 | |||
448 | return ret; | ||
449 | } | ||
450 | |||
451 | struct cs42l51_ratios { | ||
452 | unsigned int ratio; | ||
453 | unsigned char speed_mode; | ||
454 | unsigned char mclk; | ||
455 | }; | ||
456 | |||
457 | static struct cs42l51_ratios slave_ratios[] = { | ||
458 | { 512, CS42L51_QSM_MODE, 0 }, { 768, CS42L51_QSM_MODE, 0 }, | ||
459 | { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, | ||
460 | { 2048, CS42L51_QSM_MODE, 0 }, { 3072, CS42L51_QSM_MODE, 0 }, | ||
461 | { 256, CS42L51_HSM_MODE, 0 }, { 384, CS42L51_HSM_MODE, 0 }, | ||
462 | { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, | ||
463 | { 1024, CS42L51_HSM_MODE, 0 }, { 1536, CS42L51_HSM_MODE, 0 }, | ||
464 | { 128, CS42L51_SSM_MODE, 0 }, { 192, CS42L51_SSM_MODE, 0 }, | ||
465 | { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, | ||
466 | { 512, CS42L51_SSM_MODE, 0 }, { 768, CS42L51_SSM_MODE, 0 }, | ||
467 | { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, | ||
468 | { 256, CS42L51_DSM_MODE, 0 }, { 384, CS42L51_DSM_MODE, 0 }, | ||
469 | }; | ||
470 | |||
471 | static struct cs42l51_ratios slave_auto_ratios[] = { | ||
472 | { 1024, CS42L51_QSM_MODE, 0 }, { 1536, CS42L51_QSM_MODE, 0 }, | ||
473 | { 2048, CS42L51_QSM_MODE, 1 }, { 3072, CS42L51_QSM_MODE, 1 }, | ||
474 | { 512, CS42L51_HSM_MODE, 0 }, { 768, CS42L51_HSM_MODE, 0 }, | ||
475 | { 1024, CS42L51_HSM_MODE, 1 }, { 1536, CS42L51_HSM_MODE, 1 }, | ||
476 | { 256, CS42L51_SSM_MODE, 0 }, { 384, CS42L51_SSM_MODE, 0 }, | ||
477 | { 512, CS42L51_SSM_MODE, 1 }, { 768, CS42L51_SSM_MODE, 1 }, | ||
478 | { 128, CS42L51_DSM_MODE, 0 }, { 192, CS42L51_DSM_MODE, 0 }, | ||
479 | { 256, CS42L51_DSM_MODE, 1 }, { 384, CS42L51_DSM_MODE, 1 }, | ||
480 | }; | ||
481 | |||
482 | static int cs42l51_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
483 | int clk_id, unsigned int freq, int dir) | ||
484 | { | ||
485 | struct snd_soc_codec *codec = codec_dai->codec; | ||
486 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
487 | struct cs42l51_ratios *ratios = NULL; | ||
488 | int nr_ratios = 0; | ||
489 | unsigned int rates = 0; | ||
490 | unsigned int rate_min = -1; | ||
491 | unsigned int rate_max = 0; | ||
492 | int i; | ||
493 | |||
494 | cs42l51->mclk = freq; | ||
495 | |||
496 | switch (cs42l51->func) { | ||
497 | case MODE_MASTER: | ||
498 | return -EINVAL; | ||
499 | case MODE_SLAVE: | ||
500 | ratios = slave_ratios; | ||
501 | nr_ratios = ARRAY_SIZE(slave_ratios); | ||
502 | break; | ||
503 | case MODE_SLAVE_AUTO: | ||
504 | ratios = slave_auto_ratios; | ||
505 | nr_ratios = ARRAY_SIZE(slave_auto_ratios); | ||
506 | break; | ||
507 | } | ||
508 | |||
509 | for (i = 0; i < nr_ratios; i++) { | ||
510 | unsigned int rate = freq / ratios[i].ratio; | ||
511 | rates |= snd_pcm_rate_to_rate_bit(rate); | ||
512 | if (rate < rate_min) | ||
513 | rate_min = rate; | ||
514 | if (rate > rate_max) | ||
515 | rate_max = rate; | ||
516 | } | ||
517 | rates &= ~SNDRV_PCM_RATE_KNOT; | ||
518 | |||
519 | if (!rates) { | ||
520 | dev_err(codec->dev, "could not find a valid sample rate\n"); | ||
521 | return -EINVAL; | ||
522 | } | ||
523 | |||
524 | codec_dai->playback.rates = rates; | ||
525 | codec_dai->playback.rate_min = rate_min; | ||
526 | codec_dai->playback.rate_max = rate_max; | ||
527 | |||
528 | codec_dai->capture.rates = rates; | ||
529 | codec_dai->capture.rate_min = rate_min; | ||
530 | codec_dai->capture.rate_max = rate_max; | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int cs42l51_hw_params(struct snd_pcm_substream *substream, | ||
536 | struct snd_pcm_hw_params *params, | ||
537 | struct snd_soc_dai *dai) | ||
538 | { | ||
539 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
540 | struct snd_soc_device *socdev = rtd->socdev; | ||
541 | struct snd_soc_codec *codec = socdev->card->codec; | ||
542 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
543 | int ret; | ||
544 | unsigned int i; | ||
545 | unsigned int rate; | ||
546 | unsigned int ratio; | ||
547 | struct cs42l51_ratios *ratios = NULL; | ||
548 | int nr_ratios = 0; | ||
549 | int intf_ctl, power_ctl, fmt; | ||
550 | |||
551 | switch (cs42l51->func) { | ||
552 | case MODE_MASTER: | ||
553 | return -EINVAL; | ||
554 | case MODE_SLAVE: | ||
555 | ratios = slave_ratios; | ||
556 | nr_ratios = ARRAY_SIZE(slave_ratios); | ||
557 | break; | ||
558 | case MODE_SLAVE_AUTO: | ||
559 | ratios = slave_auto_ratios; | ||
560 | nr_ratios = ARRAY_SIZE(slave_auto_ratios); | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | /* Figure out which MCLK/LRCK ratio to use */ | ||
565 | rate = params_rate(params); /* Sampling rate, in Hz */ | ||
566 | ratio = cs42l51->mclk / rate; /* MCLK/LRCK ratio */ | ||
567 | for (i = 0; i < nr_ratios; i++) { | ||
568 | if (ratios[i].ratio == ratio) | ||
569 | break; | ||
570 | } | ||
571 | |||
572 | if (i == nr_ratios) { | ||
573 | /* We did not find a matching ratio */ | ||
574 | dev_err(codec->dev, "could not find matching ratio\n"); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | intf_ctl = snd_soc_read(codec, CS42L51_INTF_CTL); | ||
579 | power_ctl = snd_soc_read(codec, CS42L51_MIC_POWER_CTL); | ||
580 | |||
581 | intf_ctl &= ~(CS42L51_INTF_CTL_MASTER | CS42L51_INTF_CTL_ADC_I2S | ||
582 | | CS42L51_INTF_CTL_DAC_FORMAT(7)); | ||
583 | power_ctl &= ~(CS42L51_MIC_POWER_CTL_SPEED(3) | ||
584 | | CS42L51_MIC_POWER_CTL_MCLK_DIV2); | ||
585 | |||
586 | switch (cs42l51->func) { | ||
587 | case MODE_MASTER: | ||
588 | intf_ctl |= CS42L51_INTF_CTL_MASTER; | ||
589 | power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); | ||
590 | break; | ||
591 | case MODE_SLAVE: | ||
592 | power_ctl |= CS42L51_MIC_POWER_CTL_SPEED(ratios[i].speed_mode); | ||
593 | break; | ||
594 | case MODE_SLAVE_AUTO: | ||
595 | power_ctl |= CS42L51_MIC_POWER_CTL_AUTO; | ||
596 | break; | ||
597 | } | ||
598 | |||
599 | switch (cs42l51->audio_mode) { | ||
600 | case SND_SOC_DAIFMT_I2S: | ||
601 | intf_ctl |= CS42L51_INTF_CTL_ADC_I2S; | ||
602 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_I2S); | ||
603 | break; | ||
604 | case SND_SOC_DAIFMT_LEFT_J: | ||
605 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(CS42L51_DAC_DIF_LJ24); | ||
606 | break; | ||
607 | case SND_SOC_DAIFMT_RIGHT_J: | ||
608 | switch (params_format(params)) { | ||
609 | case SNDRV_PCM_FORMAT_S16_LE: | ||
610 | case SNDRV_PCM_FORMAT_S16_BE: | ||
611 | fmt = CS42L51_DAC_DIF_RJ16; | ||
612 | break; | ||
613 | case SNDRV_PCM_FORMAT_S18_3LE: | ||
614 | case SNDRV_PCM_FORMAT_S18_3BE: | ||
615 | fmt = CS42L51_DAC_DIF_RJ18; | ||
616 | break; | ||
617 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
618 | case SNDRV_PCM_FORMAT_S20_3BE: | ||
619 | fmt = CS42L51_DAC_DIF_RJ20; | ||
620 | break; | ||
621 | case SNDRV_PCM_FORMAT_S24_LE: | ||
622 | case SNDRV_PCM_FORMAT_S24_BE: | ||
623 | fmt = CS42L51_DAC_DIF_RJ24; | ||
624 | break; | ||
625 | default: | ||
626 | dev_err(codec->dev, "unknown format\n"); | ||
627 | return -EINVAL; | ||
628 | } | ||
629 | intf_ctl |= CS42L51_INTF_CTL_DAC_FORMAT(fmt); | ||
630 | break; | ||
631 | default: | ||
632 | dev_err(codec->dev, "unknown format\n"); | ||
633 | return -EINVAL; | ||
634 | } | ||
635 | |||
636 | if (ratios[i].mclk) | ||
637 | power_ctl |= CS42L51_MIC_POWER_CTL_MCLK_DIV2; | ||
638 | |||
639 | ret = snd_soc_write(codec, CS42L51_INTF_CTL, intf_ctl); | ||
640 | if (ret < 0) | ||
641 | return ret; | ||
642 | |||
643 | ret = snd_soc_write(codec, CS42L51_MIC_POWER_CTL, power_ctl); | ||
644 | if (ret < 0) | ||
645 | return ret; | ||
646 | |||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static int cs42l51_dai_mute(struct snd_soc_dai *dai, int mute) | ||
651 | { | ||
652 | struct snd_soc_codec *codec = dai->codec; | ||
653 | int reg; | ||
654 | int mask = CS42L51_DAC_OUT_CTL_DACA_MUTE|CS42L51_DAC_OUT_CTL_DACB_MUTE; | ||
655 | |||
656 | reg = snd_soc_read(codec, CS42L51_DAC_OUT_CTL); | ||
657 | |||
658 | if (mute) | ||
659 | reg |= mask; | ||
660 | else | ||
661 | reg &= ~mask; | ||
662 | |||
663 | return snd_soc_write(codec, CS42L51_DAC_OUT_CTL, reg); | ||
664 | } | ||
665 | |||
666 | static struct snd_soc_dai_ops cs42l51_dai_ops = { | ||
667 | .hw_params = cs42l51_hw_params, | ||
668 | .set_sysclk = cs42l51_set_dai_sysclk, | ||
669 | .set_fmt = cs42l51_set_dai_fmt, | ||
670 | .digital_mute = cs42l51_dai_mute, | ||
671 | }; | ||
672 | |||
673 | struct snd_soc_dai cs42l51_dai = { | ||
674 | .name = "CS42L51 HiFi", | ||
675 | .playback = { | ||
676 | .stream_name = "Playback", | ||
677 | .channels_min = 1, | ||
678 | .channels_max = 2, | ||
679 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
680 | .formats = CS42L51_FORMATS, | ||
681 | }, | ||
682 | .capture = { | ||
683 | .stream_name = "Capture", | ||
684 | .channels_min = 1, | ||
685 | .channels_max = 2, | ||
686 | .rates = SNDRV_PCM_RATE_8000_96000, | ||
687 | .formats = CS42L51_FORMATS, | ||
688 | }, | ||
689 | .ops = &cs42l51_dai_ops, | ||
690 | }; | ||
691 | EXPORT_SYMBOL_GPL(cs42l51_dai); | ||
692 | |||
693 | |||
694 | static int cs42l51_probe(struct platform_device *pdev) | ||
695 | { | ||
696 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
697 | struct snd_soc_codec *codec; | ||
698 | int ret = 0; | ||
699 | |||
700 | if (!cs42l51_codec) { | ||
701 | dev_err(&pdev->dev, "CS42L51 codec not yet registered\n"); | ||
702 | return -EINVAL; | ||
703 | } | ||
704 | |||
705 | socdev->card->codec = cs42l51_codec; | ||
706 | codec = socdev->card->codec; | ||
707 | |||
708 | /* Register PCMs */ | ||
709 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
710 | if (ret < 0) { | ||
711 | dev_err(&pdev->dev, "failed to create PCMs\n"); | ||
712 | return ret; | ||
713 | } | ||
714 | |||
715 | snd_soc_add_controls(codec, cs42l51_snd_controls, | ||
716 | ARRAY_SIZE(cs42l51_snd_controls)); | ||
717 | snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets, | ||
718 | ARRAY_SIZE(cs42l51_dapm_widgets)); | ||
719 | snd_soc_dapm_add_routes(codec, cs42l51_routes, | ||
720 | ARRAY_SIZE(cs42l51_routes)); | ||
721 | |||
722 | return 0; | ||
723 | } | ||
724 | |||
725 | |||
726 | static int cs42l51_remove(struct platform_device *pdev) | ||
727 | { | ||
728 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
729 | |||
730 | snd_soc_free_pcms(socdev); | ||
731 | snd_soc_dapm_free(socdev); | ||
732 | |||
733 | return 0; | ||
734 | } | ||
735 | |||
736 | struct snd_soc_codec_device soc_codec_device_cs42l51 = { | ||
737 | .probe = cs42l51_probe, | ||
738 | .remove = cs42l51_remove | ||
739 | }; | ||
740 | EXPORT_SYMBOL_GPL(soc_codec_device_cs42l51); | ||
741 | |||
742 | static int __init cs42l51_init(void) | ||
743 | { | ||
744 | int ret; | ||
745 | |||
746 | ret = i2c_add_driver(&cs42l51_i2c_driver); | ||
747 | if (ret != 0) { | ||
748 | printk(KERN_ERR "%s: can't add i2c driver\n", __func__); | ||
749 | return ret; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | module_init(cs42l51_init); | ||
754 | |||
755 | static void __exit cs42l51_exit(void) | ||
756 | { | ||
757 | i2c_del_driver(&cs42l51_i2c_driver); | ||
758 | } | ||
759 | module_exit(cs42l51_exit); | ||
760 | |||
761 | MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>"); | ||
762 | MODULE_DESCRIPTION("Cirrus Logic CS42L51 ALSA SoC Codec Driver"); | ||
763 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs42l51.h b/sound/soc/codecs/cs42l51.h new file mode 100644 index 000000000000..8f0bd9786ad2 --- /dev/null +++ b/sound/soc/codecs/cs42l51.h | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * cs42l51.h | ||
3 | * | ||
4 | * ASoC Driver for Cirrus Logic CS42L51 codecs | ||
5 | * | ||
6 | * Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your 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 | #ifndef _CS42L51_H | ||
19 | #define _CS42L51_H | ||
20 | |||
21 | #define CS42L51_CHIP_ID 0x1B | ||
22 | #define CS42L51_CHIP_REV_A 0x00 | ||
23 | #define CS42L51_CHIP_REV_B 0x01 | ||
24 | |||
25 | #define CS42L51_CHIP_REV_ID 0x01 | ||
26 | #define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b)) | ||
27 | |||
28 | #define CS42L51_POWER_CTL1 0x02 | ||
29 | #define CS42L51_POWER_CTL1_PDN_DACB (1<<6) | ||
30 | #define CS42L51_POWER_CTL1_PDN_DACA (1<<5) | ||
31 | #define CS42L51_POWER_CTL1_PDN_PGAB (1<<4) | ||
32 | #define CS42L51_POWER_CTL1_PDN_PGAA (1<<3) | ||
33 | #define CS42L51_POWER_CTL1_PDN_ADCB (1<<2) | ||
34 | #define CS42L51_POWER_CTL1_PDN_ADCA (1<<1) | ||
35 | #define CS42L51_POWER_CTL1_PDN (1<<0) | ||
36 | |||
37 | #define CS42L51_MIC_POWER_CTL 0x03 | ||
38 | #define CS42L51_MIC_POWER_CTL_AUTO (1<<7) | ||
39 | #define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5) | ||
40 | #define CS42L51_QSM_MODE 3 | ||
41 | #define CS42L51_HSM_MODE 2 | ||
42 | #define CS42L51_SSM_MODE 1 | ||
43 | #define CS42L51_DSM_MODE 0 | ||
44 | #define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4) | ||
45 | #define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3) | ||
46 | #define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2) | ||
47 | #define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1) | ||
48 | #define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0) | ||
49 | |||
50 | #define CS42L51_INTF_CTL 0x04 | ||
51 | #define CS42L51_INTF_CTL_LOOPBACK (1<<7) | ||
52 | #define CS42L51_INTF_CTL_MASTER (1<<6) | ||
53 | #define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3) | ||
54 | #define CS42L51_DAC_DIF_LJ24 0x00 | ||
55 | #define CS42L51_DAC_DIF_I2S 0x01 | ||
56 | #define CS42L51_DAC_DIF_RJ24 0x02 | ||
57 | #define CS42L51_DAC_DIF_RJ20 0x03 | ||
58 | #define CS42L51_DAC_DIF_RJ18 0x04 | ||
59 | #define CS42L51_DAC_DIF_RJ16 0x05 | ||
60 | #define CS42L51_INTF_CTL_ADC_I2S (1<<2) | ||
61 | #define CS42L51_INTF_CTL_DIGMIX (1<<1) | ||
62 | #define CS42L51_INTF_CTL_MICMIX (1<<0) | ||
63 | |||
64 | #define CS42L51_MIC_CTL 0x05 | ||
65 | #define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7) | ||
66 | #define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6) | ||
67 | #define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5) | ||
68 | #define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4) | ||
69 | #define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2) | ||
70 | #define CS42L51_MIC_CTL_MICB_BOOST (1<<1) | ||
71 | #define CS42L51_MIC_CTL_MICA_BOOST (1<<0) | ||
72 | |||
73 | #define CS42L51_ADC_CTL 0x06 | ||
74 | #define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7) | ||
75 | #define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6) | ||
76 | #define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5) | ||
77 | #define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4) | ||
78 | #define CS42L51_ADC_CTL_SOFTB (1<<3) | ||
79 | #define CS42L51_ADC_CTL_ZCROSSB (1<<2) | ||
80 | #define CS42L51_ADC_CTL_SOFTA (1<<1) | ||
81 | #define CS42L51_ADC_CTL_ZCROSSA (1<<0) | ||
82 | |||
83 | #define CS42L51_ADC_INPUT 0x07 | ||
84 | #define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6) | ||
85 | #define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4) | ||
86 | #define CS42L51_ADC_INPUT_INV_ADCB (1<<3) | ||
87 | #define CS42L51_ADC_INPUT_INV_ADCA (1<<2) | ||
88 | #define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1) | ||
89 | #define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0) | ||
90 | |||
91 | #define CS42L51_DAC_OUT_CTL 0x08 | ||
92 | #define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5) | ||
93 | #define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4) | ||
94 | #define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3) | ||
95 | #define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2) | ||
96 | #define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1) | ||
97 | #define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0) | ||
98 | |||
99 | #define CS42L51_DAC_CTL 0x09 | ||
100 | #define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6) | ||
101 | #define CS42L51_DAC_CTL_FREEZE (1<<5) | ||
102 | #define CS42L51_DAC_CTL_DEEMPH (1<<3) | ||
103 | #define CS42L51_DAC_CTL_AMUTE (1<<2) | ||
104 | #define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0) | ||
105 | |||
106 | #define CS42L51_ALC_PGA_CTL 0x0A | ||
107 | #define CS42L51_ALC_PGB_CTL 0x0B | ||
108 | #define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7) | ||
109 | #define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6) | ||
110 | #define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0) | ||
111 | |||
112 | #define CS42L51_ADCA_ATT 0x0C | ||
113 | #define CS42L51_ADCB_ATT 0x0D | ||
114 | |||
115 | #define CS42L51_ADCA_VOL 0x0E | ||
116 | #define CS42L51_ADCB_VOL 0x0F | ||
117 | #define CS42L51_PCMA_VOL 0x10 | ||
118 | #define CS42L51_PCMB_VOL 0x11 | ||
119 | #define CS42L51_MIX_MUTE_ADCMIX (1<<7) | ||
120 | #define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0) | ||
121 | |||
122 | #define CS42L51_BEEP_FREQ 0x12 | ||
123 | #define CS42L51_BEEP_VOL 0x13 | ||
124 | #define CS42L51_BEEP_CONF 0x14 | ||
125 | |||
126 | #define CS42L51_TONE_CTL 0x15 | ||
127 | #define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4) | ||
128 | #define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0) | ||
129 | |||
130 | #define CS42L51_AOUTA_VOL 0x16 | ||
131 | #define CS42L51_AOUTB_VOL 0x17 | ||
132 | #define CS42L51_PCM_MIXER 0x18 | ||
133 | #define CS42L51_LIMIT_THRES_DIS 0x19 | ||
134 | #define CS42L51_LIMIT_REL 0x1A | ||
135 | #define CS42L51_LIMIT_ATT 0x1B | ||
136 | #define CS42L51_ALC_EN 0x1C | ||
137 | #define CS42L51_ALC_REL 0x1D | ||
138 | #define CS42L51_ALC_THRES 0x1E | ||
139 | #define CS42L51_NOISE_CONF 0x1F | ||
140 | |||
141 | #define CS42L51_STATUS 0x20 | ||
142 | #define CS42L51_STATUS_SP_CLKERR (1<<6) | ||
143 | #define CS42L51_STATUS_SPEA_OVFL (1<<5) | ||
144 | #define CS42L51_STATUS_SPEB_OVFL (1<<4) | ||
145 | #define CS42L51_STATUS_PCMA_OVFL (1<<3) | ||
146 | #define CS42L51_STATUS_PCMB_OVFL (1<<2) | ||
147 | #define CS42L51_STATUS_ADCA_OVFL (1<<1) | ||
148 | #define CS42L51_STATUS_ADCB_OVFL (1<<0) | ||
149 | |||
150 | #define CS42L51_CHARGE_FREQ 0x21 | ||
151 | |||
152 | #define CS42L51_FIRSTREG 0x01 | ||
153 | /* | ||
154 | * Hack: with register 0x21, it makes 33 registers. Looks like someone in the | ||
155 | * i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using | ||
156 | * 32 regs | ||
157 | */ | ||
158 | #define CS42L51_LASTREG 0x20 | ||
159 | #define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1) | ||
160 | |||
161 | extern struct snd_soc_dai cs42l51_dai; | ||
162 | extern struct snd_soc_codec_device soc_codec_device_cs42l51; | ||
163 | #endif | ||
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 75af2d6e0e78..3c51d6a57523 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c | |||
@@ -15,23 +15,15 @@ | |||
15 | * option) any later version. | 15 | * option) any later version. |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
23 | #include <linux/pm.h> | ||
24 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
25 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
26 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
27 | #include <sound/core.h> | ||
28 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
29 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
30 | #include <sound/soc.h> | ||
31 | #include <sound/soc-dapm.h> | 24 | #include <sound/soc-dapm.h> |
32 | #include <sound/tlv.h> | ||
33 | #include <sound/initval.h> | 25 | #include <sound/initval.h> |
34 | #include <asm/div64.h> | 26 | #include <sound/tlv.h> |
35 | 27 | ||
36 | #include "da7210.h" | 28 | #include "da7210.h" |
37 | 29 | ||
@@ -145,6 +137,29 @@ | |||
145 | 137 | ||
146 | #define DA7210_VERSION "0.0.1" | 138 | #define DA7210_VERSION "0.0.1" |
147 | 139 | ||
140 | /* | ||
141 | * Playback Volume | ||
142 | * | ||
143 | * max : 0x3F (+15.0 dB) | ||
144 | * (1.5 dB step) | ||
145 | * min : 0x11 (-54.0 dB) | ||
146 | * mute : 0x10 | ||
147 | * reserved : 0x00 - 0x0F | ||
148 | * | ||
149 | * ** FIXME ** | ||
150 | * | ||
151 | * Reserved area are considered as "mute". | ||
152 | * -> min = -79.5 dB | ||
153 | */ | ||
154 | static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1); | ||
155 | |||
156 | static const struct snd_kcontrol_new da7210_snd_controls[] = { | ||
157 | |||
158 | SOC_DOUBLE_R_TLV("HeadPhone Playback Volume", | ||
159 | DA7210_HP_L_VOL, DA7210_HP_R_VOL, | ||
160 | 0, 0x3F, 0, hp_out_tlv), | ||
161 | }; | ||
162 | |||
148 | /* Codec private data */ | 163 | /* Codec private data */ |
149 | struct da7210_priv { | 164 | struct da7210_priv { |
150 | struct snd_soc_codec codec; | 165 | struct snd_soc_codec codec; |
@@ -227,10 +242,6 @@ static int da7210_startup(struct snd_pcm_substream *substream, | |||
227 | struct snd_soc_codec *codec = dai->codec; | 242 | struct snd_soc_codec *codec = dai->codec; |
228 | 243 | ||
229 | if (is_play) { | 244 | if (is_play) { |
230 | /* PlayBack Volume 40 */ | ||
231 | snd_soc_update_bits(codec, DA7210_HP_L_VOL, 0x3F, 40); | ||
232 | snd_soc_update_bits(codec, DA7210_HP_R_VOL, 0x3F, 40); | ||
233 | |||
234 | /* Enable Out */ | 245 | /* Enable Out */ |
235 | snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); | 246 | snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10); |
236 | snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); | 247 | snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10); |
@@ -488,7 +499,7 @@ static int da7210_init(struct da7210_priv *da7210) | |||
488 | ret = snd_soc_register_dai(&da7210_dai); | 499 | ret = snd_soc_register_dai(&da7210_dai); |
489 | if (ret) { | 500 | if (ret) { |
490 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 501 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
491 | goto init_err; | 502 | goto codec_err; |
492 | } | 503 | } |
493 | 504 | ||
494 | /* FIXME | 505 | /* FIXME |
@@ -574,6 +585,8 @@ static int da7210_init(struct da7210_priv *da7210) | |||
574 | 585 | ||
575 | return ret; | 586 | return ret; |
576 | 587 | ||
588 | codec_err: | ||
589 | snd_soc_unregister_codec(codec); | ||
577 | init_err: | 590 | init_err: |
578 | kfree(codec->reg_cache); | 591 | kfree(codec->reg_cache); |
579 | codec->reg_cache = NULL; | 592 | codec->reg_cache = NULL; |
@@ -601,8 +614,10 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c, | |||
601 | codec->control_data = i2c; | 614 | codec->control_data = i2c; |
602 | 615 | ||
603 | ret = da7210_init(da7210); | 616 | ret = da7210_init(da7210); |
604 | if (ret < 0) | 617 | if (ret < 0) { |
605 | pr_err("Failed to initialise da7210 audio codec\n"); | 618 | pr_err("Failed to initialise da7210 audio codec\n"); |
619 | kfree(da7210); | ||
620 | } | ||
606 | 621 | ||
607 | return ret; | 622 | return ret; |
608 | } | 623 | } |
@@ -656,6 +671,9 @@ static int da7210_probe(struct platform_device *pdev) | |||
656 | if (ret < 0) | 671 | if (ret < 0) |
657 | goto pcm_err; | 672 | goto pcm_err; |
658 | 673 | ||
674 | snd_soc_add_controls(da7210_codec, da7210_snd_controls, | ||
675 | ARRAY_SIZE(da7210_snd_controls)); | ||
676 | |||
659 | dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); | 677 | dev_info(&pdev->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); |
660 | 678 | ||
661 | pcm_err: | 679 | pcm_err: |
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c new file mode 100644 index 000000000000..66557de1e4fe --- /dev/null +++ b/sound/soc/codecs/jz4740.c | |||
@@ -0,0 +1,511 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009-2010, Lars-Peter Clausen <lars@metafoo.de> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
9 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
10 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/slab.h> | ||
18 | |||
19 | #include <linux/delay.h> | ||
20 | |||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/soc.h> | ||
27 | |||
28 | #define JZ4740_REG_CODEC_1 0x0 | ||
29 | #define JZ4740_REG_CODEC_2 0x1 | ||
30 | |||
31 | #define JZ4740_CODEC_1_LINE_ENABLE BIT(29) | ||
32 | #define JZ4740_CODEC_1_MIC_ENABLE BIT(28) | ||
33 | #define JZ4740_CODEC_1_SW1_ENABLE BIT(27) | ||
34 | #define JZ4740_CODEC_1_ADC_ENABLE BIT(26) | ||
35 | #define JZ4740_CODEC_1_SW2_ENABLE BIT(25) | ||
36 | #define JZ4740_CODEC_1_DAC_ENABLE BIT(24) | ||
37 | #define JZ4740_CODEC_1_VREF_DISABLE BIT(20) | ||
38 | #define JZ4740_CODEC_1_VREF_AMP_DISABLE BIT(19) | ||
39 | #define JZ4740_CODEC_1_VREF_PULLDOWN BIT(18) | ||
40 | #define JZ4740_CODEC_1_VREF_LOW_CURRENT BIT(17) | ||
41 | #define JZ4740_CODEC_1_VREF_HIGH_CURRENT BIT(16) | ||
42 | #define JZ4740_CODEC_1_HEADPHONE_DISABLE BIT(14) | ||
43 | #define JZ4740_CODEC_1_HEADPHONE_AMP_CHANGE_ANY BIT(13) | ||
44 | #define JZ4740_CODEC_1_HEADPHONE_CHARGE BIT(12) | ||
45 | #define JZ4740_CODEC_1_HEADPHONE_PULLDOWN (BIT(11) | BIT(10)) | ||
46 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M BIT(9) | ||
47 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN BIT(8) | ||
48 | #define JZ4740_CODEC_1_SUSPEND BIT(1) | ||
49 | #define JZ4740_CODEC_1_RESET BIT(0) | ||
50 | |||
51 | #define JZ4740_CODEC_1_LINE_ENABLE_OFFSET 29 | ||
52 | #define JZ4740_CODEC_1_MIC_ENABLE_OFFSET 28 | ||
53 | #define JZ4740_CODEC_1_SW1_ENABLE_OFFSET 27 | ||
54 | #define JZ4740_CODEC_1_ADC_ENABLE_OFFSET 26 | ||
55 | #define JZ4740_CODEC_1_SW2_ENABLE_OFFSET 25 | ||
56 | #define JZ4740_CODEC_1_DAC_ENABLE_OFFSET 24 | ||
57 | #define JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET 14 | ||
58 | #define JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET 8 | ||
59 | |||
60 | #define JZ4740_CODEC_2_INPUT_VOLUME_MASK 0x1f0000 | ||
61 | #define JZ4740_CODEC_2_SAMPLE_RATE_MASK 0x000f00 | ||
62 | #define JZ4740_CODEC_2_MIC_BOOST_GAIN_MASK 0x000030 | ||
63 | #define JZ4740_CODEC_2_HEADPHONE_VOLUME_MASK 0x000003 | ||
64 | |||
65 | #define JZ4740_CODEC_2_INPUT_VOLUME_OFFSET 16 | ||
66 | #define JZ4740_CODEC_2_SAMPLE_RATE_OFFSET 8 | ||
67 | #define JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET 4 | ||
68 | #define JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET 0 | ||
69 | |||
70 | static const uint32_t jz4740_codec_regs[] = { | ||
71 | 0x021b2302, 0x00170803, | ||
72 | }; | ||
73 | |||
74 | struct jz4740_codec { | ||
75 | void __iomem *base; | ||
76 | struct resource *mem; | ||
77 | |||
78 | uint32_t reg_cache[2]; | ||
79 | struct snd_soc_codec codec; | ||
80 | }; | ||
81 | |||
82 | static inline struct jz4740_codec *codec_to_jz4740(struct snd_soc_codec *codec) | ||
83 | { | ||
84 | return container_of(codec, struct jz4740_codec, codec); | ||
85 | } | ||
86 | |||
87 | static unsigned int jz4740_codec_read(struct snd_soc_codec *codec, | ||
88 | unsigned int reg) | ||
89 | { | ||
90 | struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec); | ||
91 | return readl(jz4740_codec->base + (reg << 2)); | ||
92 | } | ||
93 | |||
94 | static int jz4740_codec_write(struct snd_soc_codec *codec, unsigned int reg, | ||
95 | unsigned int val) | ||
96 | { | ||
97 | struct jz4740_codec *jz4740_codec = codec_to_jz4740(codec); | ||
98 | |||
99 | jz4740_codec->reg_cache[reg] = val; | ||
100 | writel(val, jz4740_codec->base + (reg << 2)); | ||
101 | |||
102 | return 0; | ||
103 | } | ||
104 | |||
105 | static const struct snd_kcontrol_new jz4740_codec_controls[] = { | ||
106 | SOC_SINGLE("Master Playback Volume", JZ4740_REG_CODEC_2, | ||
107 | JZ4740_CODEC_2_HEADPHONE_VOLUME_OFFSET, 3, 0), | ||
108 | SOC_SINGLE("Master Capture Volume", JZ4740_REG_CODEC_2, | ||
109 | JZ4740_CODEC_2_INPUT_VOLUME_OFFSET, 31, 0), | ||
110 | SOC_SINGLE("Master Playback Switch", JZ4740_REG_CODEC_1, | ||
111 | JZ4740_CODEC_1_HEADPHONE_DISABLE_OFFSET, 1, 1), | ||
112 | SOC_SINGLE("Mic Capture Volume", JZ4740_REG_CODEC_2, | ||
113 | JZ4740_CODEC_2_MIC_BOOST_GAIN_OFFSET, 3, 0), | ||
114 | }; | ||
115 | |||
116 | static const struct snd_kcontrol_new jz4740_codec_output_controls[] = { | ||
117 | SOC_DAPM_SINGLE("Bypass Switch", JZ4740_REG_CODEC_1, | ||
118 | JZ4740_CODEC_1_SW1_ENABLE_OFFSET, 1, 0), | ||
119 | SOC_DAPM_SINGLE("DAC Switch", JZ4740_REG_CODEC_1, | ||
120 | JZ4740_CODEC_1_SW2_ENABLE_OFFSET, 1, 0), | ||
121 | }; | ||
122 | |||
123 | static const struct snd_kcontrol_new jz4740_codec_input_controls[] = { | ||
124 | SOC_DAPM_SINGLE("Line Capture Switch", JZ4740_REG_CODEC_1, | ||
125 | JZ4740_CODEC_1_LINE_ENABLE_OFFSET, 1, 0), | ||
126 | SOC_DAPM_SINGLE("Mic Capture Switch", JZ4740_REG_CODEC_1, | ||
127 | JZ4740_CODEC_1_MIC_ENABLE_OFFSET, 1, 0), | ||
128 | }; | ||
129 | |||
130 | static const struct snd_soc_dapm_widget jz4740_codec_dapm_widgets[] = { | ||
131 | SND_SOC_DAPM_ADC("ADC", "Capture", JZ4740_REG_CODEC_1, | ||
132 | JZ4740_CODEC_1_ADC_ENABLE_OFFSET, 0), | ||
133 | SND_SOC_DAPM_DAC("DAC", "Playback", JZ4740_REG_CODEC_1, | ||
134 | JZ4740_CODEC_1_DAC_ENABLE_OFFSET, 0), | ||
135 | |||
136 | SND_SOC_DAPM_MIXER("Output Mixer", JZ4740_REG_CODEC_1, | ||
137 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_OFFSET, 1, | ||
138 | jz4740_codec_output_controls, | ||
139 | ARRAY_SIZE(jz4740_codec_output_controls)), | ||
140 | |||
141 | SND_SOC_DAPM_MIXER_NAMED_CTL("Input Mixer", SND_SOC_NOPM, 0, 0, | ||
142 | jz4740_codec_input_controls, | ||
143 | ARRAY_SIZE(jz4740_codec_input_controls)), | ||
144 | SND_SOC_DAPM_MIXER("Line Input", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
145 | |||
146 | SND_SOC_DAPM_OUTPUT("LOUT"), | ||
147 | SND_SOC_DAPM_OUTPUT("ROUT"), | ||
148 | |||
149 | SND_SOC_DAPM_INPUT("MIC"), | ||
150 | SND_SOC_DAPM_INPUT("LIN"), | ||
151 | SND_SOC_DAPM_INPUT("RIN"), | ||
152 | }; | ||
153 | |||
154 | static const struct snd_soc_dapm_route jz4740_codec_dapm_routes[] = { | ||
155 | {"Line Input", NULL, "LIN"}, | ||
156 | {"Line Input", NULL, "RIN"}, | ||
157 | |||
158 | {"Input Mixer", "Line Capture Switch", "Line Input"}, | ||
159 | {"Input Mixer", "Mic Capture Switch", "MIC"}, | ||
160 | |||
161 | {"ADC", NULL, "Input Mixer"}, | ||
162 | |||
163 | {"Output Mixer", "Bypass Switch", "Input Mixer"}, | ||
164 | {"Output Mixer", "DAC Switch", "DAC"}, | ||
165 | |||
166 | {"LOUT", NULL, "Output Mixer"}, | ||
167 | {"ROUT", NULL, "Output Mixer"}, | ||
168 | }; | ||
169 | |||
170 | static int jz4740_codec_hw_params(struct snd_pcm_substream *substream, | ||
171 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
172 | { | ||
173 | uint32_t val; | ||
174 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
175 | struct snd_soc_device *socdev = rtd->socdev; | ||
176 | struct snd_soc_codec *codec = socdev->card->codec; | ||
177 | |||
178 | switch (params_rate(params)) { | ||
179 | case 8000: | ||
180 | val = 0; | ||
181 | break; | ||
182 | case 11025: | ||
183 | val = 1; | ||
184 | break; | ||
185 | case 12000: | ||
186 | val = 2; | ||
187 | break; | ||
188 | case 16000: | ||
189 | val = 3; | ||
190 | break; | ||
191 | case 22050: | ||
192 | val = 4; | ||
193 | break; | ||
194 | case 24000: | ||
195 | val = 5; | ||
196 | break; | ||
197 | case 32000: | ||
198 | val = 6; | ||
199 | break; | ||
200 | case 44100: | ||
201 | val = 7; | ||
202 | break; | ||
203 | case 48000: | ||
204 | val = 8; | ||
205 | break; | ||
206 | default: | ||
207 | return -EINVAL; | ||
208 | } | ||
209 | |||
210 | val <<= JZ4740_CODEC_2_SAMPLE_RATE_OFFSET; | ||
211 | |||
212 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_2, | ||
213 | JZ4740_CODEC_2_SAMPLE_RATE_MASK, val); | ||
214 | |||
215 | return 0; | ||
216 | } | ||
217 | |||
218 | static struct snd_soc_dai_ops jz4740_codec_dai_ops = { | ||
219 | .hw_params = jz4740_codec_hw_params, | ||
220 | }; | ||
221 | |||
222 | struct snd_soc_dai jz4740_codec_dai = { | ||
223 | .name = "jz4740", | ||
224 | .playback = { | ||
225 | .stream_name = "Playback", | ||
226 | .channels_min = 2, | ||
227 | .channels_max = 2, | ||
228 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
229 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, | ||
230 | }, | ||
231 | .capture = { | ||
232 | .stream_name = "Capture", | ||
233 | .channels_min = 2, | ||
234 | .channels_max = 2, | ||
235 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
236 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8, | ||
237 | }, | ||
238 | .ops = &jz4740_codec_dai_ops, | ||
239 | .symmetric_rates = 1, | ||
240 | }; | ||
241 | EXPORT_SYMBOL_GPL(jz4740_codec_dai); | ||
242 | |||
243 | static void jz4740_codec_wakeup(struct snd_soc_codec *codec) | ||
244 | { | ||
245 | int i; | ||
246 | uint32_t *cache = codec->reg_cache; | ||
247 | |||
248 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
249 | JZ4740_CODEC_1_RESET, JZ4740_CODEC_1_RESET); | ||
250 | udelay(2); | ||
251 | |||
252 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
253 | JZ4740_CODEC_1_SUSPEND | JZ4740_CODEC_1_RESET, 0); | ||
254 | |||
255 | for (i = 0; i < ARRAY_SIZE(jz4740_codec_regs); ++i) | ||
256 | jz4740_codec_write(codec, i, cache[i]); | ||
257 | } | ||
258 | |||
259 | static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec, | ||
260 | enum snd_soc_bias_level level) | ||
261 | { | ||
262 | unsigned int mask; | ||
263 | unsigned int value; | ||
264 | |||
265 | switch (level) { | ||
266 | case SND_SOC_BIAS_ON: | ||
267 | break; | ||
268 | case SND_SOC_BIAS_PREPARE: | ||
269 | mask = JZ4740_CODEC_1_VREF_DISABLE | | ||
270 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
271 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
272 | value = 0; | ||
273 | |||
274 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
275 | break; | ||
276 | case SND_SOC_BIAS_STANDBY: | ||
277 | /* The only way to clear the suspend flag is to reset the codec */ | ||
278 | if (codec->bias_level == SND_SOC_BIAS_OFF) | ||
279 | jz4740_codec_wakeup(codec); | ||
280 | |||
281 | mask = JZ4740_CODEC_1_VREF_DISABLE | | ||
282 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
283 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
284 | value = JZ4740_CODEC_1_VREF_DISABLE | | ||
285 | JZ4740_CODEC_1_VREF_AMP_DISABLE | | ||
286 | JZ4740_CODEC_1_HEADPHONE_POWERDOWN_M; | ||
287 | |||
288 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
289 | break; | ||
290 | case SND_SOC_BIAS_OFF: | ||
291 | mask = JZ4740_CODEC_1_SUSPEND; | ||
292 | value = JZ4740_CODEC_1_SUSPEND; | ||
293 | |||
294 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, mask, value); | ||
295 | break; | ||
296 | default: | ||
297 | break; | ||
298 | } | ||
299 | |||
300 | codec->bias_level = level; | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static struct snd_soc_codec *jz4740_codec_codec; | ||
306 | |||
307 | static int jz4740_codec_dev_probe(struct platform_device *pdev) | ||
308 | { | ||
309 | int ret; | ||
310 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
311 | struct snd_soc_codec *codec = jz4740_codec_codec; | ||
312 | |||
313 | BUG_ON(!codec); | ||
314 | |||
315 | socdev->card->codec = codec; | ||
316 | |||
317 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
318 | if (ret) { | ||
319 | dev_err(&pdev->dev, "Failed to create pcms: %d\n", ret); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | snd_soc_add_controls(codec, jz4740_codec_controls, | ||
324 | ARRAY_SIZE(jz4740_codec_controls)); | ||
325 | |||
326 | snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets, | ||
327 | ARRAY_SIZE(jz4740_codec_dapm_widgets)); | ||
328 | |||
329 | snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes, | ||
330 | ARRAY_SIZE(jz4740_codec_dapm_routes)); | ||
331 | |||
332 | snd_soc_dapm_new_widgets(codec); | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int jz4740_codec_dev_remove(struct platform_device *pdev) | ||
338 | { | ||
339 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
340 | |||
341 | snd_soc_free_pcms(socdev); | ||
342 | snd_soc_dapm_free(socdev); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | #ifdef CONFIG_PM_SLEEP | ||
348 | |||
349 | static int jz4740_codec_suspend(struct platform_device *pdev, pm_message_t state) | ||
350 | { | ||
351 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
352 | struct snd_soc_codec *codec = socdev->card->codec; | ||
353 | |||
354 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
355 | } | ||
356 | |||
357 | static int jz4740_codec_resume(struct platform_device *pdev) | ||
358 | { | ||
359 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
360 | struct snd_soc_codec *codec = socdev->card->codec; | ||
361 | |||
362 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
363 | } | ||
364 | |||
365 | #else | ||
366 | #define jz4740_codec_suspend NULL | ||
367 | #define jz4740_codec_resume NULL | ||
368 | #endif | ||
369 | |||
370 | struct snd_soc_codec_device soc_codec_dev_jz4740_codec = { | ||
371 | .probe = jz4740_codec_dev_probe, | ||
372 | .remove = jz4740_codec_dev_remove, | ||
373 | .suspend = jz4740_codec_suspend, | ||
374 | .resume = jz4740_codec_resume, | ||
375 | }; | ||
376 | EXPORT_SYMBOL_GPL(soc_codec_dev_jz4740_codec); | ||
377 | |||
378 | static int __devinit jz4740_codec_probe(struct platform_device *pdev) | ||
379 | { | ||
380 | int ret; | ||
381 | struct jz4740_codec *jz4740_codec; | ||
382 | struct snd_soc_codec *codec; | ||
383 | struct resource *mem; | ||
384 | |||
385 | jz4740_codec = kzalloc(sizeof(*jz4740_codec), GFP_KERNEL); | ||
386 | if (!jz4740_codec) | ||
387 | return -ENOMEM; | ||
388 | |||
389 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
390 | if (!mem) { | ||
391 | dev_err(&pdev->dev, "Failed to get mmio memory resource\n"); | ||
392 | ret = -ENOENT; | ||
393 | goto err_free_codec; | ||
394 | } | ||
395 | |||
396 | mem = request_mem_region(mem->start, resource_size(mem), pdev->name); | ||
397 | if (!mem) { | ||
398 | dev_err(&pdev->dev, "Failed to request mmio memory region\n"); | ||
399 | ret = -EBUSY; | ||
400 | goto err_free_codec; | ||
401 | } | ||
402 | |||
403 | jz4740_codec->base = ioremap(mem->start, resource_size(mem)); | ||
404 | if (!jz4740_codec->base) { | ||
405 | dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); | ||
406 | ret = -EBUSY; | ||
407 | goto err_release_mem_region; | ||
408 | } | ||
409 | jz4740_codec->mem = mem; | ||
410 | |||
411 | jz4740_codec_dai.dev = &pdev->dev; | ||
412 | |||
413 | codec = &jz4740_codec->codec; | ||
414 | |||
415 | codec->dev = &pdev->dev; | ||
416 | codec->name = "jz4740"; | ||
417 | codec->owner = THIS_MODULE; | ||
418 | |||
419 | codec->read = jz4740_codec_read; | ||
420 | codec->write = jz4740_codec_write; | ||
421 | codec->set_bias_level = jz4740_codec_set_bias_level; | ||
422 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
423 | |||
424 | codec->dai = &jz4740_codec_dai; | ||
425 | codec->num_dai = 1; | ||
426 | |||
427 | codec->reg_cache = jz4740_codec->reg_cache; | ||
428 | codec->reg_cache_size = 2; | ||
429 | memcpy(codec->reg_cache, jz4740_codec_regs, sizeof(jz4740_codec_regs)); | ||
430 | |||
431 | mutex_init(&codec->mutex); | ||
432 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
433 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
434 | |||
435 | jz4740_codec_codec = codec; | ||
436 | |||
437 | snd_soc_update_bits(codec, JZ4740_REG_CODEC_1, | ||
438 | JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); | ||
439 | |||
440 | platform_set_drvdata(pdev, jz4740_codec); | ||
441 | |||
442 | ret = snd_soc_register_codec(codec); | ||
443 | if (ret) { | ||
444 | dev_err(&pdev->dev, "Failed to register codec\n"); | ||
445 | goto err_iounmap; | ||
446 | } | ||
447 | |||
448 | ret = snd_soc_register_dai(&jz4740_codec_dai); | ||
449 | if (ret) { | ||
450 | dev_err(&pdev->dev, "Failed to register codec dai\n"); | ||
451 | goto err_unregister_codec; | ||
452 | } | ||
453 | |||
454 | jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
455 | |||
456 | return 0; | ||
457 | |||
458 | err_unregister_codec: | ||
459 | snd_soc_unregister_codec(codec); | ||
460 | err_iounmap: | ||
461 | iounmap(jz4740_codec->base); | ||
462 | err_release_mem_region: | ||
463 | release_mem_region(mem->start, resource_size(mem)); | ||
464 | err_free_codec: | ||
465 | kfree(jz4740_codec); | ||
466 | |||
467 | return ret; | ||
468 | } | ||
469 | |||
470 | static int __devexit jz4740_codec_remove(struct platform_device *pdev) | ||
471 | { | ||
472 | struct jz4740_codec *jz4740_codec = platform_get_drvdata(pdev); | ||
473 | struct resource *mem = jz4740_codec->mem; | ||
474 | |||
475 | snd_soc_unregister_dai(&jz4740_codec_dai); | ||
476 | snd_soc_unregister_codec(&jz4740_codec->codec); | ||
477 | |||
478 | iounmap(jz4740_codec->base); | ||
479 | release_mem_region(mem->start, resource_size(mem)); | ||
480 | |||
481 | platform_set_drvdata(pdev, NULL); | ||
482 | kfree(jz4740_codec); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | static struct platform_driver jz4740_codec_driver = { | ||
488 | .probe = jz4740_codec_probe, | ||
489 | .remove = __devexit_p(jz4740_codec_remove), | ||
490 | .driver = { | ||
491 | .name = "jz4740-codec", | ||
492 | .owner = THIS_MODULE, | ||
493 | }, | ||
494 | }; | ||
495 | |||
496 | static int __init jz4740_codec_init(void) | ||
497 | { | ||
498 | return platform_driver_register(&jz4740_codec_driver); | ||
499 | } | ||
500 | module_init(jz4740_codec_init); | ||
501 | |||
502 | static void __exit jz4740_codec_exit(void) | ||
503 | { | ||
504 | platform_driver_unregister(&jz4740_codec_driver); | ||
505 | } | ||
506 | module_exit(jz4740_codec_exit); | ||
507 | |||
508 | MODULE_DESCRIPTION("JZ4740 SoC internal codec driver"); | ||
509 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
510 | MODULE_LICENSE("GPL v2"); | ||
511 | MODULE_ALIAS("platform:jz4740-codec"); | ||
diff --git a/sound/soc/codecs/jz4740.h b/sound/soc/codecs/jz4740.h new file mode 100644 index 000000000000..b5a0691be763 --- /dev/null +++ b/sound/soc/codecs/jz4740.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, Lars-Peter Clausen <lars@metafoo.de> | ||
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 | * You should have received a copy of the GNU General Public License along | ||
9 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
10 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __SND_SOC_CODECS_JZ4740_CODEC_H__ | ||
15 | #define __SND_SOC_CODECS_JZ4740_CODEC_H__ | ||
16 | |||
17 | extern struct snd_soc_dai jz4740_codec_dai; | ||
18 | extern struct snd_soc_codec_device soc_codec_dev_jz4740_codec; | ||
19 | |||
20 | #endif | ||
diff --git a/sound/soc/codecs/spdif_transciever.c b/sound/soc/codecs/spdif_transciever.c index a63191141052..9119836051a4 100644 --- a/sound/soc/codecs/spdif_transciever.c +++ b/sound/soc/codecs/spdif_transciever.c | |||
@@ -16,8 +16,10 @@ | |||
16 | 16 | ||
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/moduleparam.h> | 18 | #include <linux/moduleparam.h> |
19 | #include <linux/slab.h> | ||
19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
20 | #include <sound/pcm.h> | 21 | #include <sound/pcm.h> |
22 | #include <sound/initval.h> | ||
21 | 23 | ||
22 | #include "spdif_transciever.h" | 24 | #include "spdif_transciever.h" |
23 | 25 | ||
@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL"); | |||
26 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 | 28 | #define STUB_RATES SNDRV_PCM_RATE_8000_96000 |
27 | #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE | 29 | #define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE |
28 | 30 | ||
31 | static struct snd_soc_codec *spdif_dit_codec; | ||
32 | |||
33 | static int spdif_dit_codec_probe(struct platform_device *pdev) | ||
34 | { | ||
35 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
36 | struct snd_soc_codec *codec; | ||
37 | int ret; | ||
38 | |||
39 | if (spdif_dit_codec == NULL) { | ||
40 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
41 | return -ENODEV; | ||
42 | } | ||
43 | |||
44 | socdev->card->codec = spdif_dit_codec; | ||
45 | codec = spdif_dit_codec; | ||
46 | |||
47 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
48 | if (ret < 0) { | ||
49 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
50 | goto err_create_pcms; | ||
51 | } | ||
52 | |||
53 | return 0; | ||
54 | |||
55 | err_create_pcms: | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | static int spdif_dit_codec_remove(struct platform_device *pdev) | ||
60 | { | ||
61 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
62 | |||
63 | snd_soc_free_pcms(socdev); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | struct snd_soc_codec_device soc_codec_dev_spdif_dit = { | ||
69 | .probe = spdif_dit_codec_probe, | ||
70 | .remove = spdif_dit_codec_remove, | ||
71 | }; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit); | ||
72 | |||
29 | struct snd_soc_dai dit_stub_dai = { | 73 | struct snd_soc_dai dit_stub_dai = { |
30 | .name = "DIT", | 74 | .name = "DIT", |
31 | .playback = { | 75 | .playback = { |
@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai); | |||
40 | 84 | ||
41 | static int spdif_dit_probe(struct platform_device *pdev) | 85 | static int spdif_dit_probe(struct platform_device *pdev) |
42 | { | 86 | { |
87 | struct snd_soc_codec *codec; | ||
88 | int ret; | ||
89 | |||
90 | if (spdif_dit_codec) { | ||
91 | dev_err(&pdev->dev, "Another Codec is registered\n"); | ||
92 | ret = -EINVAL; | ||
93 | goto err_reg_codec; | ||
94 | } | ||
95 | |||
96 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
97 | if (codec == NULL) | ||
98 | return -ENOMEM; | ||
99 | |||
100 | codec->dev = &pdev->dev; | ||
101 | |||
102 | mutex_init(&codec->mutex); | ||
103 | |||
104 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
105 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
106 | |||
107 | codec->name = "spdif-dit"; | ||
108 | codec->owner = THIS_MODULE; | ||
109 | codec->dai = &dit_stub_dai; | ||
110 | codec->num_dai = 1; | ||
111 | |||
112 | spdif_dit_codec = codec; | ||
113 | |||
114 | ret = snd_soc_register_codec(codec); | ||
115 | if (ret < 0) { | ||
116 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
117 | goto err_reg_codec; | ||
118 | } | ||
119 | |||
43 | dit_stub_dai.dev = &pdev->dev; | 120 | dit_stub_dai.dev = &pdev->dev; |
44 | return snd_soc_register_dai(&dit_stub_dai); | 121 | ret = snd_soc_register_dai(&dit_stub_dai); |
122 | if (ret < 0) { | ||
123 | dev_err(codec->dev, "Failed to register dai: %d\n", ret); | ||
124 | goto err_reg_dai; | ||
125 | } | ||
126 | |||
127 | return 0; | ||
128 | |||
129 | err_reg_dai: | ||
130 | snd_soc_unregister_codec(codec); | ||
131 | err_reg_codec: | ||
132 | kfree(spdif_dit_codec); | ||
133 | return ret; | ||
45 | } | 134 | } |
46 | 135 | ||
47 | static int spdif_dit_remove(struct platform_device *pdev) | 136 | static int spdif_dit_remove(struct platform_device *pdev) |
48 | { | 137 | { |
49 | snd_soc_unregister_dai(&dit_stub_dai); | 138 | snd_soc_unregister_dai(&dit_stub_dai); |
139 | snd_soc_unregister_codec(spdif_dit_codec); | ||
140 | kfree(spdif_dit_codec); | ||
141 | spdif_dit_codec = NULL; | ||
50 | return 0; | 142 | return 0; |
51 | } | 143 | } |
52 | 144 | ||
diff --git a/sound/soc/codecs/spdif_transciever.h b/sound/soc/codecs/spdif_transciever.h index 296f2eb6c4ef..1e102124f546 100644 --- a/sound/soc/codecs/spdif_transciever.h +++ b/sound/soc/codecs/spdif_transciever.h | |||
@@ -12,6 +12,7 @@ | |||
12 | #ifndef CODEC_STUBS_H | 12 | #ifndef CODEC_STUBS_H |
13 | #define CODEC_STUBS_H | 13 | #define CODEC_STUBS_H |
14 | 14 | ||
15 | extern struct snd_soc_codec_device soc_codec_dev_spdif_dit; | ||
15 | extern struct snd_soc_dai dit_stub_dai; | 16 | extern struct snd_soc_dai dit_stub_dai; |
16 | 17 | ||
17 | #endif /* CODEC_STUBS_H */ | 18 | #endif /* CODEC_STUBS_H */ |
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index b0bae3508b29..0a4b0fef3355 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -560,13 +560,16 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, | |||
560 | switch (level) { | 560 | switch (level) { |
561 | case SND_SOC_BIAS_ON: | 561 | case SND_SOC_BIAS_ON: |
562 | /* vref/mid, osc on, dac unmute */ | 562 | /* vref/mid, osc on, dac unmute */ |
563 | reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \ | ||
564 | TLV320AIC23_DAC_OFF); | ||
563 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); | 565 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg); |
564 | break; | 566 | break; |
565 | case SND_SOC_BIAS_PREPARE: | 567 | case SND_SOC_BIAS_PREPARE: |
566 | break; | 568 | break; |
567 | case SND_SOC_BIAS_STANDBY: | 569 | case SND_SOC_BIAS_STANDBY: |
568 | /* everything off except vref/vmid, */ | 570 | /* everything off except vref/vmid, */ |
569 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | 0x0040); | 571 | tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \ |
572 | TLV320AIC23_CLK_OFF); | ||
570 | break; | 573 | break; |
571 | case SND_SOC_BIAS_OFF: | 574 | case SND_SOC_BIAS_OFF: |
572 | /* everything off, dac mute, inactive */ | 575 | /* everything off, dac mute, inactive */ |
@@ -615,7 +618,6 @@ static int tlv320aic23_suspend(struct platform_device *pdev, | |||
615 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 618 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
616 | struct snd_soc_codec *codec = socdev->card->codec; | 619 | struct snd_soc_codec *codec = socdev->card->codec; |
617 | 620 | ||
618 | tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); | ||
619 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); | 621 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF); |
620 | 622 | ||
621 | return 0; | 623 | return 0; |
@@ -632,7 +634,6 @@ static int tlv320aic23_resume(struct platform_device *pdev) | |||
632 | u16 val = tlv320aic23_read_reg_cache(codec, reg); | 634 | u16 val = tlv320aic23_read_reg_cache(codec, reg); |
633 | tlv320aic23_write(codec, reg, val); | 635 | tlv320aic23_write(codec, reg, val); |
634 | } | 636 | } |
635 | |||
636 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 637 | tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
637 | 638 | ||
638 | return 0; | 639 | return 0; |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 65adc77eada1..8651b01ed223 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -49,8 +49,6 @@ | |||
49 | 49 | ||
50 | #define NSAMPLE_MAX 5700 | 50 | #define NSAMPLE_MAX 5700 |
51 | 51 | ||
52 | #define LATENCY_TIME_MS 20 | ||
53 | |||
54 | #define MODE7_LTHR 10 | 52 | #define MODE7_LTHR 10 |
55 | #define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) | 53 | #define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10) |
56 | 54 | ||
@@ -62,6 +60,9 @@ | |||
62 | #define US_TO_SAMPLES(rate, us) \ | 60 | #define US_TO_SAMPLES(rate, us) \ |
63 | (rate / (1000000 / us)) | 61 | (rate / (1000000 / us)) |
64 | 62 | ||
63 | #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ | ||
64 | ((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) | ||
65 | |||
65 | static void dac33_calculate_times(struct snd_pcm_substream *substream); | 66 | static void dac33_calculate_times(struct snd_pcm_substream *substream); |
66 | static int dac33_prepare_chip(struct snd_pcm_substream *substream); | 67 | static int dac33_prepare_chip(struct snd_pcm_substream *substream); |
67 | 68 | ||
@@ -107,6 +108,10 @@ struct tlv320dac33_priv { | |||
107 | * this */ | 108 | * this */ |
108 | enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ | 109 | enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */ |
109 | unsigned int nsample; /* burst read amount from host */ | 110 | unsigned int nsample; /* burst read amount from host */ |
111 | int mode1_latency; /* latency caused by the i2c writes in | ||
112 | * us */ | ||
113 | int auto_fifo_config; /* Configure the FIFO based on the | ||
114 | * period size */ | ||
110 | u8 burst_bclkdiv; /* BCLK divider value in burst mode */ | 115 | u8 burst_bclkdiv; /* BCLK divider value in burst mode */ |
111 | unsigned int burst_rate; /* Interface speed in Burst modes */ | 116 | unsigned int burst_rate; /* Interface speed in Burst modes */ |
112 | 117 | ||
@@ -120,6 +125,8 @@ struct tlv320dac33_priv { | |||
120 | * samples */ | 125 | * samples */ |
121 | unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ | 126 | unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */ |
122 | 127 | ||
128 | unsigned int uthr; | ||
129 | |||
123 | enum dac33_state state; | 130 | enum dac33_state state; |
124 | }; | 131 | }; |
125 | 132 | ||
@@ -442,6 +449,39 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol, | |||
442 | return ret; | 449 | return ret; |
443 | } | 450 | } |
444 | 451 | ||
452 | static int dac33_get_uthr(struct snd_kcontrol *kcontrol, | ||
453 | struct snd_ctl_elem_value *ucontrol) | ||
454 | { | ||
455 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
456 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
457 | |||
458 | ucontrol->value.integer.value[0] = dac33->uthr; | ||
459 | |||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | static int dac33_set_uthr(struct snd_kcontrol *kcontrol, | ||
464 | struct snd_ctl_elem_value *ucontrol) | ||
465 | { | ||
466 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
467 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | ||
468 | int ret = 0; | ||
469 | |||
470 | if (dac33->substream) | ||
471 | return -EBUSY; | ||
472 | |||
473 | if (dac33->uthr == ucontrol->value.integer.value[0]) | ||
474 | return 0; | ||
475 | |||
476 | if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) || | ||
477 | ucontrol->value.integer.value[0] > MODE7_UTHR) | ||
478 | ret = -EINVAL; | ||
479 | else | ||
480 | dac33->uthr = ucontrol->value.integer.value[0]; | ||
481 | |||
482 | return ret; | ||
483 | } | ||
484 | |||
445 | static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, | 485 | static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol, |
446 | struct snd_ctl_elem_value *ucontrol) | 486 | struct snd_ctl_elem_value *ucontrol) |
447 | { | 487 | { |
@@ -503,13 +543,18 @@ static const struct snd_kcontrol_new dac33_snd_controls[] = { | |||
503 | DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), | 543 | DAC33_LINEL_TO_LLO_VOL, DAC33_LINER_TO_RLO_VOL, 0, 127, 1), |
504 | }; | 544 | }; |
505 | 545 | ||
506 | static const struct snd_kcontrol_new dac33_nsample_snd_controls[] = { | 546 | static const struct snd_kcontrol_new dac33_mode_snd_controls[] = { |
507 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, | ||
508 | dac33_get_nsample, dac33_set_nsample), | ||
509 | SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, | 547 | SOC_ENUM_EXT("FIFO Mode", dac33_fifo_mode_enum, |
510 | dac33_get_fifo_mode, dac33_set_fifo_mode), | 548 | dac33_get_fifo_mode, dac33_set_fifo_mode), |
511 | }; | 549 | }; |
512 | 550 | ||
551 | static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = { | ||
552 | SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0, | ||
553 | dac33_get_nsample, dac33_set_nsample), | ||
554 | SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0, | ||
555 | dac33_get_uthr, dac33_set_uthr), | ||
556 | }; | ||
557 | |||
513 | /* Analog bypass */ | 558 | /* Analog bypass */ |
514 | static const struct snd_kcontrol_new dac33_dapm_abypassl_control = | 559 | static const struct snd_kcontrol_new dac33_dapm_abypassl_control = |
515 | SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); | 560 | SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1); |
@@ -612,7 +657,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33) | |||
612 | switch (dac33->fifo_mode) { | 657 | switch (dac33->fifo_mode) { |
613 | case DAC33_FIFO_MODE1: | 658 | case DAC33_FIFO_MODE1: |
614 | dac33_write16(codec, DAC33_NSAMPLE_MSB, | 659 | dac33_write16(codec, DAC33_NSAMPLE_MSB, |
615 | DAC33_THRREG(dac33->nsample + dac33->alarm_threshold)); | 660 | DAC33_THRREG(dac33->nsample)); |
616 | 661 | ||
617 | /* Take the timestamps */ | 662 | /* Take the timestamps */ |
618 | spin_lock_irq(&dac33->lock); | 663 | spin_lock_irq(&dac33->lock); |
@@ -761,6 +806,10 @@ static void dac33_shutdown(struct snd_pcm_substream *substream, | |||
761 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 806 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
762 | 807 | ||
763 | dac33->substream = NULL; | 808 | dac33->substream = NULL; |
809 | |||
810 | /* Reset the nSample restrictions */ | ||
811 | dac33->nsample_min = 0; | ||
812 | dac33->nsample_max = NSAMPLE_MAX; | ||
764 | } | 813 | } |
765 | 814 | ||
766 | static int dac33_hw_params(struct snd_pcm_substream *substream, | 815 | static int dac33_hw_params(struct snd_pcm_substream *substream, |
@@ -985,7 +1034,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) | |||
985 | * Configure the threshold levels, and leave 10 sample space | 1034 | * Configure the threshold levels, and leave 10 sample space |
986 | * at the bottom, and also at the top of the FIFO | 1035 | * at the bottom, and also at the top of the FIFO |
987 | */ | 1036 | */ |
988 | dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR)); | 1037 | dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr)); |
989 | dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); | 1038 | dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR)); |
990 | break; | 1039 | break; |
991 | default: | 1040 | default: |
@@ -1003,57 +1052,71 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream) | |||
1003 | struct snd_soc_device *socdev = rtd->socdev; | 1052 | struct snd_soc_device *socdev = rtd->socdev; |
1004 | struct snd_soc_codec *codec = socdev->card->codec; | 1053 | struct snd_soc_codec *codec = socdev->card->codec; |
1005 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1054 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1055 | unsigned int period_size = substream->runtime->period_size; | ||
1056 | unsigned int rate = substream->runtime->rate; | ||
1006 | unsigned int nsample_limit; | 1057 | unsigned int nsample_limit; |
1007 | 1058 | ||
1008 | /* In bypass mode we don't need to calculate */ | 1059 | /* In bypass mode we don't need to calculate */ |
1009 | if (!dac33->fifo_mode) | 1060 | if (!dac33->fifo_mode) |
1010 | return; | 1061 | return; |
1011 | 1062 | ||
1012 | /* Number of samples (16bit, stereo) in one period */ | ||
1013 | dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4; | ||
1014 | |||
1015 | /* Number of samples (16bit, stereo) in ALSA buffer */ | ||
1016 | dac33->nsample_max = snd_pcm_lib_buffer_bytes(substream) / 4; | ||
1017 | /* Subtract one period from the total */ | ||
1018 | dac33->nsample_max -= dac33->nsample_min; | ||
1019 | |||
1020 | /* Number of samples for LATENCY_TIME_MS / 2 */ | ||
1021 | dac33->alarm_threshold = substream->runtime->rate / | ||
1022 | (1000 / (LATENCY_TIME_MS / 2)); | ||
1023 | |||
1024 | /* Find and fix up the lowest nsmaple limit */ | ||
1025 | nsample_limit = substream->runtime->rate / (1000 / LATENCY_TIME_MS); | ||
1026 | |||
1027 | if (dac33->nsample_min < nsample_limit) | ||
1028 | dac33->nsample_min = nsample_limit; | ||
1029 | |||
1030 | if (dac33->nsample < dac33->nsample_min) | ||
1031 | dac33->nsample = dac33->nsample_min; | ||
1032 | |||
1033 | /* | ||
1034 | * Find and fix up the highest nsmaple limit | ||
1035 | * In order to not overflow the DAC33 buffer substract the | ||
1036 | * alarm_threshold value from the size of the DAC33 buffer | ||
1037 | */ | ||
1038 | nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - dac33->alarm_threshold; | ||
1039 | |||
1040 | if (dac33->nsample_max > nsample_limit) | ||
1041 | dac33->nsample_max = nsample_limit; | ||
1042 | |||
1043 | if (dac33->nsample > dac33->nsample_max) | ||
1044 | dac33->nsample = dac33->nsample_max; | ||
1045 | |||
1046 | switch (dac33->fifo_mode) { | 1063 | switch (dac33->fifo_mode) { |
1047 | case DAC33_FIFO_MODE1: | 1064 | case DAC33_FIFO_MODE1: |
1065 | /* Number of samples under i2c latency */ | ||
1066 | dac33->alarm_threshold = US_TO_SAMPLES(rate, | ||
1067 | dac33->mode1_latency); | ||
1068 | if (dac33->auto_fifo_config) { | ||
1069 | if (period_size <= dac33->alarm_threshold) | ||
1070 | /* | ||
1071 | * Configure nSamaple to number of periods, | ||
1072 | * which covers the latency requironment. | ||
1073 | */ | ||
1074 | dac33->nsample = period_size * | ||
1075 | ((dac33->alarm_threshold / period_size) + | ||
1076 | (dac33->alarm_threshold % period_size ? | ||
1077 | 1 : 0)); | ||
1078 | else | ||
1079 | dac33->nsample = period_size; | ||
1080 | } else { | ||
1081 | /* nSample time shall not be shorter than i2c latency */ | ||
1082 | dac33->nsample_min = dac33->alarm_threshold; | ||
1083 | /* | ||
1084 | * nSample should not be bigger than alsa buffer minus | ||
1085 | * size of one period to avoid overruns | ||
1086 | */ | ||
1087 | dac33->nsample_max = substream->runtime->buffer_size - | ||
1088 | period_size; | ||
1089 | nsample_limit = DAC33_BUFFER_SIZE_SAMPLES - | ||
1090 | dac33->alarm_threshold; | ||
1091 | if (dac33->nsample_max > nsample_limit) | ||
1092 | dac33->nsample_max = nsample_limit; | ||
1093 | |||
1094 | /* Correct the nSample if it is outside of the ranges */ | ||
1095 | if (dac33->nsample < dac33->nsample_min) | ||
1096 | dac33->nsample = dac33->nsample_min; | ||
1097 | if (dac33->nsample > dac33->nsample_max) | ||
1098 | dac33->nsample = dac33->nsample_max; | ||
1099 | } | ||
1100 | |||
1048 | dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, | 1101 | dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate, |
1049 | dac33->nsample); | 1102 | dac33->nsample); |
1050 | dac33->t_stamp1 = 0; | 1103 | dac33->t_stamp1 = 0; |
1051 | dac33->t_stamp2 = 0; | 1104 | dac33->t_stamp2 = 0; |
1052 | break; | 1105 | break; |
1053 | case DAC33_FIFO_MODE7: | 1106 | case DAC33_FIFO_MODE7: |
1107 | if (dac33->auto_fifo_config) { | ||
1108 | dac33->uthr = UTHR_FROM_PERIOD_SIZE( | ||
1109 | period_size, | ||
1110 | rate, | ||
1111 | dac33->burst_rate) + 9; | ||
1112 | if (dac33->uthr > MODE7_UTHR) | ||
1113 | dac33->uthr = MODE7_UTHR; | ||
1114 | if (dac33->uthr < (MODE7_LTHR + 10)) | ||
1115 | dac33->uthr = (MODE7_LTHR + 10); | ||
1116 | } | ||
1054 | dac33->mode7_us_to_lthr = | 1117 | dac33->mode7_us_to_lthr = |
1055 | SAMPLES_TO_US(substream->runtime->rate, | 1118 | SAMPLES_TO_US(substream->runtime->rate, |
1056 | MODE7_UTHR - MODE7_LTHR + 1); | 1119 | dac33->uthr - MODE7_LTHR + 1); |
1057 | dac33->t_stamp1 = 0; | 1120 | dac33->t_stamp1 = 0; |
1058 | break; | 1121 | break; |
1059 | default: | 1122 | default: |
@@ -1104,7 +1167,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1104 | struct snd_soc_codec *codec = socdev->card->codec; | 1167 | struct snd_soc_codec *codec = socdev->card->codec; |
1105 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); | 1168 | struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec); |
1106 | unsigned long long t0, t1, t_now; | 1169 | unsigned long long t0, t1, t_now; |
1107 | unsigned int time_delta; | 1170 | unsigned int time_delta, uthr; |
1108 | int samples_out, samples_in, samples; | 1171 | int samples_out, samples_in, samples; |
1109 | snd_pcm_sframes_t delay = 0; | 1172 | snd_pcm_sframes_t delay = 0; |
1110 | 1173 | ||
@@ -1182,6 +1245,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1182 | case DAC33_FIFO_MODE7: | 1245 | case DAC33_FIFO_MODE7: |
1183 | spin_lock(&dac33->lock); | 1246 | spin_lock(&dac33->lock); |
1184 | t0 = dac33->t_stamp1; | 1247 | t0 = dac33->t_stamp1; |
1248 | uthr = dac33->uthr; | ||
1185 | spin_unlock(&dac33->lock); | 1249 | spin_unlock(&dac33->lock); |
1186 | t_now = ktime_to_us(ktime_get()); | 1250 | t_now = ktime_to_us(ktime_get()); |
1187 | 1251 | ||
@@ -1194,7 +1258,7 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1194 | * Either the timestamps are messed or equal. Report | 1258 | * Either the timestamps are messed or equal. Report |
1195 | * maximum delay | 1259 | * maximum delay |
1196 | */ | 1260 | */ |
1197 | delay = MODE7_UTHR; | 1261 | delay = uthr; |
1198 | goto out; | 1262 | goto out; |
1199 | } | 1263 | } |
1200 | 1264 | ||
@@ -1208,8 +1272,8 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1208 | substream->runtime->rate, | 1272 | substream->runtime->rate, |
1209 | time_delta); | 1273 | time_delta); |
1210 | 1274 | ||
1211 | if (likely(MODE7_UTHR > samples_out)) | 1275 | if (likely(uthr > samples_out)) |
1212 | delay = MODE7_UTHR - samples_out; | 1276 | delay = uthr - samples_out; |
1213 | else | 1277 | else |
1214 | delay = 0; | 1278 | delay = 0; |
1215 | } else { | 1279 | } else { |
@@ -1227,8 +1291,8 @@ static snd_pcm_sframes_t dac33_dai_delay( | |||
1227 | time_delta); | 1291 | time_delta); |
1228 | delay = MODE7_LTHR + samples_in - samples_out; | 1292 | delay = MODE7_LTHR + samples_in - samples_out; |
1229 | 1293 | ||
1230 | if (unlikely(delay > MODE7_UTHR)) | 1294 | if (unlikely(delay > uthr)) |
1231 | delay = MODE7_UTHR; | 1295 | delay = uthr; |
1232 | } | 1296 | } |
1233 | break; | 1297 | break; |
1234 | default: | 1298 | default: |
@@ -1347,10 +1411,15 @@ static int dac33_soc_probe(struct platform_device *pdev) | |||
1347 | 1411 | ||
1348 | snd_soc_add_controls(codec, dac33_snd_controls, | 1412 | snd_soc_add_controls(codec, dac33_snd_controls, |
1349 | ARRAY_SIZE(dac33_snd_controls)); | 1413 | ARRAY_SIZE(dac33_snd_controls)); |
1350 | /* Only add the nSample controls, if we have valid IRQ number */ | 1414 | /* Only add the FIFO controls, if we have valid IRQ number */ |
1351 | if (dac33->irq >= 0) | 1415 | if (dac33->irq >= 0) { |
1352 | snd_soc_add_controls(codec, dac33_nsample_snd_controls, | 1416 | snd_soc_add_controls(codec, dac33_mode_snd_controls, |
1353 | ARRAY_SIZE(dac33_nsample_snd_controls)); | 1417 | ARRAY_SIZE(dac33_mode_snd_controls)); |
1418 | /* FIFO usage controls only, if autoio config is not selected */ | ||
1419 | if (!dac33->auto_fifo_config) | ||
1420 | snd_soc_add_controls(codec, dac33_fifo_snd_controls, | ||
1421 | ARRAY_SIZE(dac33_fifo_snd_controls)); | ||
1422 | } | ||
1354 | 1423 | ||
1355 | dac33_add_widgets(codec); | 1424 | dac33_add_widgets(codec); |
1356 | 1425 | ||
@@ -1481,9 +1550,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client, | |||
1481 | /* Pre calculate the burst rate */ | 1550 | /* Pre calculate the burst rate */ |
1482 | dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; | 1551 | dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32; |
1483 | dac33->keep_bclk = pdata->keep_bclk; | 1552 | dac33->keep_bclk = pdata->keep_bclk; |
1553 | dac33->auto_fifo_config = pdata->auto_fifo_config; | ||
1554 | dac33->mode1_latency = pdata->mode1_latency; | ||
1555 | if (!dac33->mode1_latency) | ||
1556 | dac33->mode1_latency = 10000; /* 10ms */ | ||
1484 | dac33->irq = client->irq; | 1557 | dac33->irq = client->irq; |
1485 | dac33->nsample = NSAMPLE_MAX; | 1558 | dac33->nsample = NSAMPLE_MAX; |
1486 | dac33->nsample_max = NSAMPLE_MAX; | 1559 | dac33->nsample_max = NSAMPLE_MAX; |
1560 | dac33->uthr = MODE7_UTHR; | ||
1487 | /* Disable FIFO use by default */ | 1561 | /* Disable FIFO use by default */ |
1488 | dac33->fifo_mode = DAC33_FIFO_BYPASS; | 1562 | dac33->fifo_mode = DAC33_FIFO_BYPASS; |
1489 | 1563 | ||
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index b4fcdb01fc49..7b618bbff884 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -43,37 +43,37 @@ | |||
43 | */ | 43 | */ |
44 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | 44 | static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { |
45 | 0x00, /* this register not used */ | 45 | 0x00, /* this register not used */ |
46 | 0x91, /* REG_CODEC_MODE (0x1) */ | 46 | 0x00, /* REG_CODEC_MODE (0x1) */ |
47 | 0xc3, /* REG_OPTION (0x2) */ | 47 | 0x00, /* REG_OPTION (0x2) */ |
48 | 0x00, /* REG_UNKNOWN (0x3) */ | 48 | 0x00, /* REG_UNKNOWN (0x3) */ |
49 | 0x00, /* REG_MICBIAS_CTL (0x4) */ | 49 | 0x00, /* REG_MICBIAS_CTL (0x4) */ |
50 | 0x20, /* REG_ANAMICL (0x5) */ | 50 | 0x00, /* REG_ANAMICL (0x5) */ |
51 | 0x00, /* REG_ANAMICR (0x6) */ | 51 | 0x00, /* REG_ANAMICR (0x6) */ |
52 | 0x00, /* REG_AVADC_CTL (0x7) */ | 52 | 0x00, /* REG_AVADC_CTL (0x7) */ |
53 | 0x00, /* REG_ADCMICSEL (0x8) */ | 53 | 0x00, /* REG_ADCMICSEL (0x8) */ |
54 | 0x00, /* REG_DIGMIXING (0x9) */ | 54 | 0x00, /* REG_DIGMIXING (0x9) */ |
55 | 0x0c, /* REG_ATXL1PGA (0xA) */ | 55 | 0x0f, /* REG_ATXL1PGA (0xA) */ |
56 | 0x0c, /* REG_ATXR1PGA (0xB) */ | 56 | 0x0f, /* REG_ATXR1PGA (0xB) */ |
57 | 0x00, /* REG_AVTXL2PGA (0xC) */ | 57 | 0x0f, /* REG_AVTXL2PGA (0xC) */ |
58 | 0x00, /* REG_AVTXR2PGA (0xD) */ | 58 | 0x0f, /* REG_AVTXR2PGA (0xD) */ |
59 | 0x00, /* REG_AUDIO_IF (0xE) */ | 59 | 0x00, /* REG_AUDIO_IF (0xE) */ |
60 | 0x00, /* REG_VOICE_IF (0xF) */ | 60 | 0x00, /* REG_VOICE_IF (0xF) */ |
61 | 0x00, /* REG_ARXR1PGA (0x10) */ | 61 | 0x3f, /* REG_ARXR1PGA (0x10) */ |
62 | 0x00, /* REG_ARXL1PGA (0x11) */ | 62 | 0x3f, /* REG_ARXL1PGA (0x11) */ |
63 | 0x6c, /* REG_ARXR2PGA (0x12) */ | 63 | 0x3f, /* REG_ARXR2PGA (0x12) */ |
64 | 0x6c, /* REG_ARXL2PGA (0x13) */ | 64 | 0x3f, /* REG_ARXL2PGA (0x13) */ |
65 | 0x00, /* REG_VRXPGA (0x14) */ | 65 | 0x25, /* REG_VRXPGA (0x14) */ |
66 | 0x00, /* REG_VSTPGA (0x15) */ | 66 | 0x00, /* REG_VSTPGA (0x15) */ |
67 | 0x00, /* REG_VRX2ARXPGA (0x16) */ | 67 | 0x00, /* REG_VRX2ARXPGA (0x16) */ |
68 | 0x00, /* REG_AVDAC_CTL (0x17) */ | 68 | 0x00, /* REG_AVDAC_CTL (0x17) */ |
69 | 0x00, /* REG_ARX2VTXPGA (0x18) */ | 69 | 0x00, /* REG_ARX2VTXPGA (0x18) */ |
70 | 0x00, /* REG_ARXL1_APGA_CTL (0x19) */ | 70 | 0x32, /* REG_ARXL1_APGA_CTL (0x19) */ |
71 | 0x00, /* REG_ARXR1_APGA_CTL (0x1A) */ | 71 | 0x32, /* REG_ARXR1_APGA_CTL (0x1A) */ |
72 | 0x4a, /* REG_ARXL2_APGA_CTL (0x1B) */ | 72 | 0x32, /* REG_ARXL2_APGA_CTL (0x1B) */ |
73 | 0x4a, /* REG_ARXR2_APGA_CTL (0x1C) */ | 73 | 0x32, /* REG_ARXR2_APGA_CTL (0x1C) */ |
74 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ | 74 | 0x00, /* REG_ATX2ARXPGA (0x1D) */ |
75 | 0x00, /* REG_BT_IF (0x1E) */ | 75 | 0x00, /* REG_BT_IF (0x1E) */ |
76 | 0x00, /* REG_BTPGA (0x1F) */ | 76 | 0x55, /* REG_BTPGA (0x1F) */ |
77 | 0x00, /* REG_BTSTPGA (0x20) */ | 77 | 0x00, /* REG_BTSTPGA (0x20) */ |
78 | 0x00, /* REG_EAR_CTL (0x21) */ | 78 | 0x00, /* REG_EAR_CTL (0x21) */ |
79 | 0x00, /* REG_HS_SEL (0x22) */ | 79 | 0x00, /* REG_HS_SEL (0x22) */ |
@@ -85,32 +85,32 @@ static const u8 twl4030_reg[TWL4030_CACHEREGNUM] = { | |||
85 | 0x00, /* REG_PRECKR_CTL (0x28) */ | 85 | 0x00, /* REG_PRECKR_CTL (0x28) */ |
86 | 0x00, /* REG_HFL_CTL (0x29) */ | 86 | 0x00, /* REG_HFL_CTL (0x29) */ |
87 | 0x00, /* REG_HFR_CTL (0x2A) */ | 87 | 0x00, /* REG_HFR_CTL (0x2A) */ |
88 | 0x00, /* REG_ALC_CTL (0x2B) */ | 88 | 0x05, /* REG_ALC_CTL (0x2B) */ |
89 | 0x00, /* REG_ALC_SET1 (0x2C) */ | 89 | 0x00, /* REG_ALC_SET1 (0x2C) */ |
90 | 0x00, /* REG_ALC_SET2 (0x2D) */ | 90 | 0x00, /* REG_ALC_SET2 (0x2D) */ |
91 | 0x00, /* REG_BOOST_CTL (0x2E) */ | 91 | 0x00, /* REG_BOOST_CTL (0x2E) */ |
92 | 0x00, /* REG_SOFTVOL_CTL (0x2F) */ | 92 | 0x00, /* REG_SOFTVOL_CTL (0x2F) */ |
93 | 0x00, /* REG_DTMF_FREQSEL (0x30) */ | 93 | 0x13, /* REG_DTMF_FREQSEL (0x30) */ |
94 | 0x00, /* REG_DTMF_TONEXT1H (0x31) */ | 94 | 0x00, /* REG_DTMF_TONEXT1H (0x31) */ |
95 | 0x00, /* REG_DTMF_TONEXT1L (0x32) */ | 95 | 0x00, /* REG_DTMF_TONEXT1L (0x32) */ |
96 | 0x00, /* REG_DTMF_TONEXT2H (0x33) */ | 96 | 0x00, /* REG_DTMF_TONEXT2H (0x33) */ |
97 | 0x00, /* REG_DTMF_TONEXT2L (0x34) */ | 97 | 0x00, /* REG_DTMF_TONEXT2L (0x34) */ |
98 | 0x00, /* REG_DTMF_TONOFF (0x35) */ | 98 | 0x79, /* REG_DTMF_TONOFF (0x35) */ |
99 | 0x00, /* REG_DTMF_WANONOFF (0x36) */ | 99 | 0x11, /* REG_DTMF_WANONOFF (0x36) */ |
100 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ | 100 | 0x00, /* REG_I2S_RX_SCRAMBLE_H (0x37) */ |
101 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ | 101 | 0x00, /* REG_I2S_RX_SCRAMBLE_M (0x38) */ |
102 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ | 102 | 0x00, /* REG_I2S_RX_SCRAMBLE_L (0x39) */ |
103 | 0x06, /* REG_APLL_CTL (0x3A) */ | 103 | 0x06, /* REG_APLL_CTL (0x3A) */ |
104 | 0x00, /* REG_DTMF_CTL (0x3B) */ | 104 | 0x00, /* REG_DTMF_CTL (0x3B) */ |
105 | 0x00, /* REG_DTMF_PGA_CTL2 (0x3C) */ | 105 | 0x44, /* REG_DTMF_PGA_CTL2 (0x3C) */ |
106 | 0x00, /* REG_DTMF_PGA_CTL1 (0x3D) */ | 106 | 0x69, /* REG_DTMF_PGA_CTL1 (0x3D) */ |
107 | 0x00, /* REG_MISC_SET_1 (0x3E) */ | 107 | 0x00, /* REG_MISC_SET_1 (0x3E) */ |
108 | 0x00, /* REG_PCMBTMUX (0x3F) */ | 108 | 0x00, /* REG_PCMBTMUX (0x3F) */ |
109 | 0x00, /* not used (0x40) */ | 109 | 0x00, /* not used (0x40) */ |
110 | 0x00, /* not used (0x41) */ | 110 | 0x00, /* not used (0x41) */ |
111 | 0x00, /* not used (0x42) */ | 111 | 0x00, /* not used (0x42) */ |
112 | 0x00, /* REG_RX_PATH_SEL (0x43) */ | 112 | 0x00, /* REG_RX_PATH_SEL (0x43) */ |
113 | 0x00, /* REG_VDL_APGA_CTL (0x44) */ | 113 | 0x32, /* REG_VDL_APGA_CTL (0x44) */ |
114 | 0x00, /* REG_VIBRA_CTL (0x45) */ | 114 | 0x00, /* REG_VIBRA_CTL (0x45) */ |
115 | 0x00, /* REG_VIBRA_SET (0x46) */ | 115 | 0x00, /* REG_VIBRA_SET (0x46) */ |
116 | 0x00, /* REG_VIBRA_PWM_SET (0x47) */ | 116 | 0x00, /* REG_VIBRA_PWM_SET (0x47) */ |
@@ -143,6 +143,9 @@ struct twl4030_priv { | |||
143 | u8 earpiece_enabled; | 143 | u8 earpiece_enabled; |
144 | u8 predrivel_enabled, predriver_enabled; | 144 | u8 predrivel_enabled, predriver_enabled; |
145 | u8 carkitl_enabled, carkitr_enabled; | 145 | u8 carkitl_enabled, carkitr_enabled; |
146 | |||
147 | /* Delay needed after enabling the digimic interface */ | ||
148 | unsigned int digimic_delay; | ||
146 | }; | 149 | }; |
147 | 150 | ||
148 | /* | 151 | /* |
@@ -244,58 +247,95 @@ static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable) | |||
244 | udelay(10); | 247 | udelay(10); |
245 | } | 248 | } |
246 | 249 | ||
247 | static void twl4030_init_chip(struct snd_soc_codec *codec) | 250 | static inline void twl4030_check_defaults(struct snd_soc_codec *codec) |
248 | { | 251 | { |
249 | u8 *cache = codec->reg_cache; | 252 | int i, difference = 0; |
250 | int i; | 253 | u8 val; |
254 | |||
255 | dev_dbg(codec->dev, "Checking TWL audio default configuration\n"); | ||
256 | for (i = 1; i <= TWL4030_REG_MISC_SET_2; i++) { | ||
257 | twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &val, i); | ||
258 | if (val != twl4030_reg[i]) { | ||
259 | difference++; | ||
260 | dev_dbg(codec->dev, | ||
261 | "Reg 0x%02x: chip: 0x%02x driver: 0x%02x\n", | ||
262 | i, val, twl4030_reg[i]); | ||
263 | } | ||
264 | } | ||
265 | dev_dbg(codec->dev, "Found %d non maching registers. %s\n", | ||
266 | difference, difference ? "Not OK" : "OK"); | ||
267 | } | ||
251 | 268 | ||
252 | /* clear CODECPDZ prior to setting register defaults */ | 269 | static inline void twl4030_reset_registers(struct snd_soc_codec *codec) |
253 | twl4030_codec_enable(codec, 0); | 270 | { |
271 | int i; | ||
254 | 272 | ||
255 | /* set all audio section registers to reasonable defaults */ | 273 | /* set all audio section registers to reasonable defaults */ |
256 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) | 274 | for (i = TWL4030_REG_OPTION; i <= TWL4030_REG_MISC_SET_2; i++) |
257 | if (i != TWL4030_REG_APLL_CTL) | 275 | if (i != TWL4030_REG_APLL_CTL) |
258 | twl4030_write(codec, i, cache[i]); | 276 | twl4030_write(codec, i, twl4030_reg[i]); |
259 | 277 | ||
260 | } | 278 | } |
261 | 279 | ||
262 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) | 280 | static void twl4030_init_chip(struct platform_device *pdev) |
263 | { | 281 | { |
282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
283 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
284 | struct snd_soc_codec *codec = socdev->card->codec; | ||
264 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 285 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
265 | int status = -1; | 286 | u8 reg, byte; |
287 | int i = 0; | ||
266 | 288 | ||
267 | if (enable) { | 289 | /* Check defaults, if instructed before anything else */ |
268 | twl4030->apll_enabled++; | 290 | if (setup && setup->check_defaults) |
269 | if (twl4030->apll_enabled == 1) | 291 | twl4030_check_defaults(codec); |
270 | status = twl4030_codec_enable_resource( | ||
271 | TWL4030_CODEC_RES_APLL); | ||
272 | } else { | ||
273 | twl4030->apll_enabled--; | ||
274 | if (!twl4030->apll_enabled) | ||
275 | status = twl4030_codec_disable_resource( | ||
276 | TWL4030_CODEC_RES_APLL); | ||
277 | } | ||
278 | 292 | ||
279 | if (status >= 0) | 293 | /* Reset registers, if no setup data or if instructed to do so */ |
280 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); | 294 | if (!setup || (setup && setup->reset_registers)) |
281 | } | 295 | twl4030_reset_registers(codec); |
282 | 296 | ||
283 | static void twl4030_power_up(struct snd_soc_codec *codec) | 297 | /* Refresh APLL_CTL register from HW */ |
284 | { | 298 | twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, |
285 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 299 | TWL4030_REG_APLL_CTL); |
286 | u8 anamicl, regmisc1, byte; | 300 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, byte); |
287 | int i = 0; | 301 | |
302 | /* anti-pop when changing analog gain */ | ||
303 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
304 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
305 | reg | TWL4030_SMOOTH_ANAVOL_EN); | ||
288 | 306 | ||
289 | if (twl4030->codec_powered) | 307 | twl4030_write(codec, TWL4030_REG_OPTION, |
308 | TWL4030_ATXL1_EN | TWL4030_ATXR1_EN | | ||
309 | TWL4030_ARXL2_EN | TWL4030_ARXR2_EN); | ||
310 | |||
311 | /* REG_ARXR2_APGA_CTL reset according to the TRM: 0dB, DA_EN */ | ||
312 | twl4030_write(codec, TWL4030_REG_ARXR2_APGA_CTL, 0x32); | ||
313 | |||
314 | /* Machine dependent setup */ | ||
315 | if (!setup) | ||
290 | return; | 316 | return; |
291 | 317 | ||
292 | /* set CODECPDZ to turn on codec */ | 318 | twl4030->digimic_delay = setup->digimic_delay; |
293 | twl4030_codec_enable(codec, 1); | 319 | |
320 | /* Configuration for headset ramp delay from setup data */ | ||
321 | if (setup->sysclk != twl4030->sysclk) | ||
322 | dev_warn(codec->dev, | ||
323 | "Mismatch in APLL mclk: %u (configured: %u)\n", | ||
324 | setup->sysclk, twl4030->sysclk); | ||
325 | |||
326 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
327 | reg &= ~TWL4030_RAMP_DELAY; | ||
328 | reg |= (setup->ramp_delay_value << 2); | ||
329 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, reg); | ||
294 | 330 | ||
295 | /* initiate offset cancellation */ | 331 | /* initiate offset cancellation */ |
296 | anamicl = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | 332 | twl4030_codec_enable(codec, 1); |
333 | |||
334 | reg = twl4030_read_reg_cache(codec, TWL4030_REG_ANAMICL); | ||
335 | reg &= ~TWL4030_OFFSET_CNCL_SEL; | ||
336 | reg |= setup->offset_cncl_path; | ||
297 | twl4030_write(codec, TWL4030_REG_ANAMICL, | 337 | twl4030_write(codec, TWL4030_REG_ANAMICL, |
298 | anamicl | TWL4030_CNCL_OFFSET_START); | 338 | reg | TWL4030_CNCL_OFFSET_START); |
299 | 339 | ||
300 | /* wait for offset cancellation to complete */ | 340 | /* wait for offset cancellation to complete */ |
301 | do { | 341 | do { |
@@ -310,23 +350,28 @@ static void twl4030_power_up(struct snd_soc_codec *codec) | |||
310 | /* Make sure that the reg_cache has the same value as the HW */ | 350 | /* Make sure that the reg_cache has the same value as the HW */ |
311 | twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); | 351 | twl4030_write_reg_cache(codec, TWL4030_REG_ANAMICL, byte); |
312 | 352 | ||
313 | /* anti-pop when changing analog gain */ | ||
314 | regmisc1 = twl4030_read_reg_cache(codec, TWL4030_REG_MISC_SET_1); | ||
315 | twl4030_write(codec, TWL4030_REG_MISC_SET_1, | ||
316 | regmisc1 | TWL4030_SMOOTH_ANAVOL_EN); | ||
317 | |||
318 | /* toggle CODECPDZ as per TRM */ | ||
319 | twl4030_codec_enable(codec, 0); | 353 | twl4030_codec_enable(codec, 0); |
320 | twl4030_codec_enable(codec, 1); | ||
321 | } | 354 | } |
322 | 355 | ||
323 | /* | 356 | static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable) |
324 | * Unconditional power down | ||
325 | */ | ||
326 | static void twl4030_power_down(struct snd_soc_codec *codec) | ||
327 | { | 357 | { |
328 | /* power down */ | 358 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
329 | twl4030_codec_enable(codec, 0); | 359 | int status = -1; |
360 | |||
361 | if (enable) { | ||
362 | twl4030->apll_enabled++; | ||
363 | if (twl4030->apll_enabled == 1) | ||
364 | status = twl4030_codec_enable_resource( | ||
365 | TWL4030_CODEC_RES_APLL); | ||
366 | } else { | ||
367 | twl4030->apll_enabled--; | ||
368 | if (!twl4030->apll_enabled) | ||
369 | status = twl4030_codec_disable_resource( | ||
370 | TWL4030_CODEC_RES_APLL); | ||
371 | } | ||
372 | |||
373 | if (status >= 0) | ||
374 | twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status); | ||
330 | } | 375 | } |
331 | 376 | ||
332 | /* Earpiece */ | 377 | /* Earpiece */ |
@@ -500,10 +545,11 @@ static const struct snd_kcontrol_new twl4030_dapm_abypassl2_control = | |||
500 | static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = | 545 | static const struct snd_kcontrol_new twl4030_dapm_abypassv_control = |
501 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); | 546 | SOC_DAPM_SINGLE("Switch", TWL4030_REG_VDL_APGA_CTL, 2, 1, 0); |
502 | 547 | ||
503 | /* Digital bypass gain, 0 mutes the bypass */ | 548 | /* Digital bypass gain, mute instead of -30dB */ |
504 | static const unsigned int twl4030_dapm_dbypass_tlv[] = { | 549 | static const unsigned int twl4030_dapm_dbypass_tlv[] = { |
505 | TLV_DB_RANGE_HEAD(2), | 550 | TLV_DB_RANGE_HEAD(3), |
506 | 0, 3, TLV_DB_SCALE_ITEM(-2400, 0, 1), | 551 | 0, 1, TLV_DB_SCALE_ITEM(-3000, 600, 1), |
552 | 2, 3, TLV_DB_SCALE_ITEM(-2400, 0, 0), | ||
507 | 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), | 553 | 4, 7, TLV_DB_SCALE_ITEM(-1800, 600, 0), |
508 | }; | 554 | }; |
509 | 555 | ||
@@ -531,36 +577,6 @@ static const struct snd_kcontrol_new twl4030_dapm_dbypassv_control = | |||
531 | TWL4030_REG_VSTPGA, 0, 0x29, 0, | 577 | TWL4030_REG_VSTPGA, 0, 0x29, 0, |
532 | twl4030_dapm_dbypassv_tlv); | 578 | twl4030_dapm_dbypassv_tlv); |
533 | 579 | ||
534 | static int micpath_event(struct snd_soc_dapm_widget *w, | ||
535 | struct snd_kcontrol *kcontrol, int event) | ||
536 | { | ||
537 | struct soc_enum *e = (struct soc_enum *)w->kcontrols->private_value; | ||
538 | unsigned char adcmicsel, micbias_ctl; | ||
539 | |||
540 | adcmicsel = twl4030_read_reg_cache(w->codec, TWL4030_REG_ADCMICSEL); | ||
541 | micbias_ctl = twl4030_read_reg_cache(w->codec, TWL4030_REG_MICBIAS_CTL); | ||
542 | /* Prepare the bits for the given TX path: | ||
543 | * shift_l == 0: TX1 microphone path | ||
544 | * shift_l == 2: TX2 microphone path */ | ||
545 | if (e->shift_l) { | ||
546 | /* TX2 microphone path */ | ||
547 | if (adcmicsel & TWL4030_TX2IN_SEL) | ||
548 | micbias_ctl |= TWL4030_MICBIAS2_CTL; /* digimic */ | ||
549 | else | ||
550 | micbias_ctl &= ~TWL4030_MICBIAS2_CTL; | ||
551 | } else { | ||
552 | /* TX1 microphone path */ | ||
553 | if (adcmicsel & TWL4030_TX1IN_SEL) | ||
554 | micbias_ctl |= TWL4030_MICBIAS1_CTL; /* digimic */ | ||
555 | else | ||
556 | micbias_ctl &= ~TWL4030_MICBIAS1_CTL; | ||
557 | } | ||
558 | |||
559 | twl4030_write(w->codec, TWL4030_REG_MICBIAS_CTL, micbias_ctl); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | /* | 580 | /* |
565 | * Output PGA builder: | 581 | * Output PGA builder: |
566 | * Handle the muting and unmuting of the given output (turning off the | 582 | * Handle the muting and unmuting of the given output (turning off the |
@@ -814,6 +830,16 @@ static int headsetrpga_event(struct snd_soc_dapm_widget *w, | |||
814 | return 0; | 830 | return 0; |
815 | } | 831 | } |
816 | 832 | ||
833 | static int digimic_event(struct snd_soc_dapm_widget *w, | ||
834 | struct snd_kcontrol *kcontrol, int event) | ||
835 | { | ||
836 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); | ||
837 | |||
838 | if (twl4030->digimic_delay) | ||
839 | mdelay(twl4030->digimic_delay); | ||
840 | return 0; | ||
841 | } | ||
842 | |||
817 | /* | 843 | /* |
818 | * Some of the gain controls in TWL (mostly those which are associated with | 844 | * Some of the gain controls in TWL (mostly those which are associated with |
819 | * the outputs) are implemented in an interesting way: | 845 | * the outputs) are implemented in an interesting way: |
@@ -1374,14 +1400,10 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1374 | /* Analog/Digital mic path selection. | 1400 | /* Analog/Digital mic path selection. |
1375 | TX1 Left/Right: either analog Left/Right or Digimic0 | 1401 | TX1 Left/Right: either analog Left/Right or Digimic0 |
1376 | TX2 Left/Right: either analog Left/Right or Digimic1 */ | 1402 | TX2 Left/Right: either analog Left/Right or Digimic1 */ |
1377 | SND_SOC_DAPM_MUX_E("TX1 Capture Route", SND_SOC_NOPM, 0, 0, | 1403 | SND_SOC_DAPM_MUX("TX1 Capture Route", SND_SOC_NOPM, 0, 0, |
1378 | &twl4030_dapm_micpathtx1_control, micpath_event, | 1404 | &twl4030_dapm_micpathtx1_control), |
1379 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| | 1405 | SND_SOC_DAPM_MUX("TX2 Capture Route", SND_SOC_NOPM, 0, 0, |
1380 | SND_SOC_DAPM_POST_REG), | 1406 | &twl4030_dapm_micpathtx2_control), |
1381 | SND_SOC_DAPM_MUX_E("TX2 Capture Route", SND_SOC_NOPM, 0, 0, | ||
1382 | &twl4030_dapm_micpathtx2_control, micpath_event, | ||
1383 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD| | ||
1384 | SND_SOC_DAPM_POST_REG), | ||
1385 | 1407 | ||
1386 | /* Analog input mixers for the capture amplifiers */ | 1408 | /* Analog input mixers for the capture amplifiers */ |
1387 | SND_SOC_DAPM_MIXER("Analog Left", | 1409 | SND_SOC_DAPM_MIXER("Analog Left", |
@@ -1398,10 +1420,17 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = { | |||
1398 | SND_SOC_DAPM_PGA("ADC Physical Right", | 1420 | SND_SOC_DAPM_PGA("ADC Physical Right", |
1399 | TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), | 1421 | TWL4030_REG_AVADC_CTL, 1, 0, NULL, 0), |
1400 | 1422 | ||
1401 | SND_SOC_DAPM_PGA("Digimic0 Enable", | 1423 | SND_SOC_DAPM_PGA_E("Digimic0 Enable", |
1402 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0), | 1424 | TWL4030_REG_ADCMICSEL, 1, 0, NULL, 0, |
1403 | SND_SOC_DAPM_PGA("Digimic1 Enable", | 1425 | digimic_event, SND_SOC_DAPM_POST_PMU), |
1404 | TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0), | 1426 | SND_SOC_DAPM_PGA_E("Digimic1 Enable", |
1427 | TWL4030_REG_ADCMICSEL, 3, 0, NULL, 0, | ||
1428 | digimic_event, SND_SOC_DAPM_POST_PMU), | ||
1429 | |||
1430 | SND_SOC_DAPM_SUPPLY("micbias1 select", TWL4030_REG_MICBIAS_CTL, 5, 0, | ||
1431 | NULL, 0), | ||
1432 | SND_SOC_DAPM_SUPPLY("micbias2 select", TWL4030_REG_MICBIAS_CTL, 6, 0, | ||
1433 | NULL, 0), | ||
1405 | 1434 | ||
1406 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), | 1435 | SND_SOC_DAPM_MICBIAS("Mic Bias 1", TWL4030_REG_MICBIAS_CTL, 0, 0), |
1407 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), | 1436 | SND_SOC_DAPM_MICBIAS("Mic Bias 2", TWL4030_REG_MICBIAS_CTL, 1, 0), |
@@ -1419,8 +1448,11 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1419 | /* Supply for the digital part (APLL) */ | 1448 | /* Supply for the digital part (APLL) */ |
1420 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, | 1449 | {"Digital Voice Playback Mixer", NULL, "APLL Enable"}, |
1421 | 1450 | ||
1422 | {"Digital R1 Playback Mixer", NULL, "AIF Enable"}, | 1451 | {"DAC Left1", NULL, "AIF Enable"}, |
1423 | {"Digital L1 Playback Mixer", NULL, "AIF Enable"}, | 1452 | {"DAC Right1", NULL, "AIF Enable"}, |
1453 | {"DAC Left2", NULL, "AIF Enable"}, | ||
1454 | {"DAC Right1", NULL, "AIF Enable"}, | ||
1455 | |||
1424 | {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, | 1456 | {"Digital R2 Playback Mixer", NULL, "AIF Enable"}, |
1425 | {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, | 1457 | {"Digital L2 Playback Mixer", NULL, "AIF Enable"}, |
1426 | 1458 | ||
@@ -1491,10 +1523,10 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1491 | 1523 | ||
1492 | /* outputs */ | 1524 | /* outputs */ |
1493 | /* Must be always connected (for AIF and APLL) */ | 1525 | /* Must be always connected (for AIF and APLL) */ |
1494 | {"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"}, | 1526 | {"Virtual HiFi OUT", NULL, "DAC Left1"}, |
1495 | {"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"}, | 1527 | {"Virtual HiFi OUT", NULL, "DAC Right1"}, |
1496 | {"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"}, | 1528 | {"Virtual HiFi OUT", NULL, "DAC Left2"}, |
1497 | {"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"}, | 1529 | {"Virtual HiFi OUT", NULL, "DAC Right2"}, |
1498 | /* Must be always connected (for APLL) */ | 1530 | /* Must be always connected (for APLL) */ |
1499 | {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, | 1531 | {"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"}, |
1500 | /* Physical outputs */ | 1532 | /* Physical outputs */ |
@@ -1531,6 +1563,9 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
1531 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, | 1563 | {"Digimic0 Enable", NULL, "DIGIMIC0"}, |
1532 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, | 1564 | {"Digimic1 Enable", NULL, "DIGIMIC1"}, |
1533 | 1565 | ||
1566 | {"DIGIMIC0", NULL, "micbias1 select"}, | ||
1567 | {"DIGIMIC1", NULL, "micbias2 select"}, | ||
1568 | |||
1534 | /* TX1 Left capture path */ | 1569 | /* TX1 Left capture path */ |
1535 | {"TX1 Capture Route", "Analog", "ADC Physical Left"}, | 1570 | {"TX1 Capture Route", "Analog", "ADC Physical Left"}, |
1536 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, | 1571 | {"TX1 Capture Route", "Digimic0", "Digimic0 Enable"}, |
@@ -1605,10 +1640,10 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec, | |||
1605 | break; | 1640 | break; |
1606 | case SND_SOC_BIAS_STANDBY: | 1641 | case SND_SOC_BIAS_STANDBY: |
1607 | if (codec->bias_level == SND_SOC_BIAS_OFF) | 1642 | if (codec->bias_level == SND_SOC_BIAS_OFF) |
1608 | twl4030_power_up(codec); | 1643 | twl4030_codec_enable(codec, 1); |
1609 | break; | 1644 | break; |
1610 | case SND_SOC_BIAS_OFF: | 1645 | case SND_SOC_BIAS_OFF: |
1611 | twl4030_power_down(codec); | 1646 | twl4030_codec_enable(codec, 0); |
1612 | break; | 1647 | break; |
1613 | } | 1648 | } |
1614 | codec->bias_level = level; | 1649 | codec->bias_level = level; |
@@ -1794,13 +1829,6 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1794 | return -EINVAL; | 1829 | return -EINVAL; |
1795 | } | 1830 | } |
1796 | 1831 | ||
1797 | if (mode != old_mode) { | ||
1798 | /* change rate and set CODECPDZ */ | ||
1799 | twl4030_codec_enable(codec, 0); | ||
1800 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
1801 | twl4030_codec_enable(codec, 1); | ||
1802 | } | ||
1803 | |||
1804 | /* sample size */ | 1832 | /* sample size */ |
1805 | old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); | 1833 | old_format = twl4030_read_reg_cache(codec, TWL4030_REG_AUDIO_IF); |
1806 | format = old_format; | 1834 | format = old_format; |
@@ -1818,16 +1846,20 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream, | |||
1818 | return -EINVAL; | 1846 | return -EINVAL; |
1819 | } | 1847 | } |
1820 | 1848 | ||
1821 | if (format != old_format) { | 1849 | if (format != old_format || mode != old_mode) { |
1822 | 1850 | if (twl4030->codec_powered) { | |
1823 | /* clear CODECPDZ before changing format (codec requirement) */ | 1851 | /* |
1824 | twl4030_codec_enable(codec, 0); | 1852 | * If the codec is powered, than we need to toggle the |
1825 | 1853 | * codec power. | |
1826 | /* change format */ | 1854 | */ |
1827 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1855 | twl4030_codec_enable(codec, 0); |
1828 | 1856 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | |
1829 | /* set CODECPDZ afterwards */ | 1857 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); |
1830 | twl4030_codec_enable(codec, 1); | 1858 | twl4030_codec_enable(codec, 1); |
1859 | } else { | ||
1860 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
1861 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | ||
1862 | } | ||
1831 | } | 1863 | } |
1832 | 1864 | ||
1833 | /* Store the important parameters for the DAI configuration and set | 1865 | /* Store the important parameters for the DAI configuration and set |
@@ -1877,6 +1909,7 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1877 | unsigned int fmt) | 1909 | unsigned int fmt) |
1878 | { | 1910 | { |
1879 | struct snd_soc_codec *codec = codec_dai->codec; | 1911 | struct snd_soc_codec *codec = codec_dai->codec; |
1912 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
1880 | u8 old_format, format; | 1913 | u8 old_format, format; |
1881 | 1914 | ||
1882 | /* get format */ | 1915 | /* get format */ |
@@ -1911,15 +1944,17 @@ static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
1911 | } | 1944 | } |
1912 | 1945 | ||
1913 | if (format != old_format) { | 1946 | if (format != old_format) { |
1914 | 1947 | if (twl4030->codec_powered) { | |
1915 | /* clear CODECPDZ before changing format (codec requirement) */ | 1948 | /* |
1916 | twl4030_codec_enable(codec, 0); | 1949 | * If the codec is powered, than we need to toggle the |
1917 | 1950 | * codec power. | |
1918 | /* change format */ | 1951 | */ |
1919 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | 1952 | twl4030_codec_enable(codec, 0); |
1920 | 1953 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | |
1921 | /* set CODECPDZ afterwards */ | 1954 | twl4030_codec_enable(codec, 1); |
1922 | twl4030_codec_enable(codec, 1); | 1955 | } else { |
1956 | twl4030_write(codec, TWL4030_REG_AUDIO_IF, format); | ||
1957 | } | ||
1923 | } | 1958 | } |
1924 | 1959 | ||
1925 | return 0; | 1960 | return 0; |
@@ -2011,6 +2046,7 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, | |||
2011 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 2046 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
2012 | struct snd_soc_device *socdev = rtd->socdev; | 2047 | struct snd_soc_device *socdev = rtd->socdev; |
2013 | struct snd_soc_codec *codec = socdev->card->codec; | 2048 | struct snd_soc_codec *codec = socdev->card->codec; |
2049 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2014 | u8 old_mode, mode; | 2050 | u8 old_mode, mode; |
2015 | 2051 | ||
2016 | /* Enable voice digital filters */ | 2052 | /* Enable voice digital filters */ |
@@ -2035,10 +2071,17 @@ static int twl4030_voice_hw_params(struct snd_pcm_substream *substream, | |||
2035 | } | 2071 | } |
2036 | 2072 | ||
2037 | if (mode != old_mode) { | 2073 | if (mode != old_mode) { |
2038 | /* change rate and set CODECPDZ */ | 2074 | if (twl4030->codec_powered) { |
2039 | twl4030_codec_enable(codec, 0); | 2075 | /* |
2040 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | 2076 | * If the codec is powered, than we need to toggle the |
2041 | twl4030_codec_enable(codec, 1); | 2077 | * codec power. |
2078 | */ | ||
2079 | twl4030_codec_enable(codec, 0); | ||
2080 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
2081 | twl4030_codec_enable(codec, 1); | ||
2082 | } else { | ||
2083 | twl4030_write(codec, TWL4030_REG_CODEC_MODE, mode); | ||
2084 | } | ||
2042 | } | 2085 | } |
2043 | 2086 | ||
2044 | return 0; | 2087 | return 0; |
@@ -2068,6 +2111,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
2068 | unsigned int fmt) | 2111 | unsigned int fmt) |
2069 | { | 2112 | { |
2070 | struct snd_soc_codec *codec = codec_dai->codec; | 2113 | struct snd_soc_codec *codec = codec_dai->codec; |
2114 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2071 | u8 old_format, format; | 2115 | u8 old_format, format; |
2072 | 2116 | ||
2073 | /* get format */ | 2117 | /* get format */ |
@@ -2099,10 +2143,17 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
2099 | } | 2143 | } |
2100 | 2144 | ||
2101 | if (format != old_format) { | 2145 | if (format != old_format) { |
2102 | /* change format and set CODECPDZ */ | 2146 | if (twl4030->codec_powered) { |
2103 | twl4030_codec_enable(codec, 0); | 2147 | /* |
2104 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | 2148 | * If the codec is powered, than we need to toggle the |
2105 | twl4030_codec_enable(codec, 1); | 2149 | * codec power. |
2150 | */ | ||
2151 | twl4030_codec_enable(codec, 0); | ||
2152 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | ||
2153 | twl4030_codec_enable(codec, 1); | ||
2154 | } else { | ||
2155 | twl4030_write(codec, TWL4030_REG_VOICE_IF, format); | ||
2156 | } | ||
2106 | } | 2157 | } |
2107 | 2158 | ||
2108 | return 0; | 2159 | return 0; |
@@ -2202,31 +2253,15 @@ static struct snd_soc_codec *twl4030_codec; | |||
2202 | static int twl4030_soc_probe(struct platform_device *pdev) | 2253 | static int twl4030_soc_probe(struct platform_device *pdev) |
2203 | { | 2254 | { |
2204 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 2255 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
2205 | struct twl4030_setup_data *setup = socdev->codec_data; | ||
2206 | struct snd_soc_codec *codec; | 2256 | struct snd_soc_codec *codec; |
2207 | struct twl4030_priv *twl4030; | ||
2208 | int ret; | 2257 | int ret; |
2209 | 2258 | ||
2210 | BUG_ON(!twl4030_codec); | 2259 | BUG_ON(!twl4030_codec); |
2211 | 2260 | ||
2212 | codec = twl4030_codec; | 2261 | codec = twl4030_codec; |
2213 | twl4030 = snd_soc_codec_get_drvdata(codec); | ||
2214 | socdev->card->codec = codec; | 2262 | socdev->card->codec = codec; |
2215 | 2263 | ||
2216 | /* Configuration for headset ramp delay from setup data */ | 2264 | twl4030_init_chip(pdev); |
2217 | if (setup) { | ||
2218 | unsigned char hs_pop; | ||
2219 | |||
2220 | if (setup->sysclk != twl4030->sysclk) | ||
2221 | dev_warn(&pdev->dev, | ||
2222 | "Mismatch in APLL mclk: %u (configured: %u)\n", | ||
2223 | setup->sysclk, twl4030->sysclk); | ||
2224 | |||
2225 | hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET); | ||
2226 | hs_pop &= ~TWL4030_RAMP_DELAY; | ||
2227 | hs_pop |= (setup->ramp_delay_value << 2); | ||
2228 | twl4030_write_reg_cache(codec, TWL4030_REG_HS_POPN_SET, hs_pop); | ||
2229 | } | ||
2230 | 2265 | ||
2231 | /* register pcms */ | 2266 | /* register pcms */ |
2232 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 2267 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
@@ -2247,6 +2282,8 @@ static int twl4030_soc_remove(struct platform_device *pdev) | |||
2247 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 2282 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
2248 | struct snd_soc_codec *codec = socdev->card->codec; | 2283 | struct snd_soc_codec *codec = socdev->card->codec; |
2249 | 2284 | ||
2285 | /* Reset registers to their chip default before leaving */ | ||
2286 | twl4030_reset_registers(codec); | ||
2250 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); | 2287 | twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2251 | snd_soc_free_pcms(socdev); | 2288 | snd_soc_free_pcms(socdev); |
2252 | snd_soc_dapm_free(socdev); | 2289 | snd_soc_dapm_free(socdev); |
@@ -2287,6 +2324,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2287 | codec->read = twl4030_read_reg_cache; | 2324 | codec->read = twl4030_read_reg_cache; |
2288 | codec->write = twl4030_write; | 2325 | codec->write = twl4030_write; |
2289 | codec->set_bias_level = twl4030_set_bias_level; | 2326 | codec->set_bias_level = twl4030_set_bias_level; |
2327 | codec->idle_bias_off = 1; | ||
2290 | codec->dai = twl4030_dai; | 2328 | codec->dai = twl4030_dai; |
2291 | codec->num_dai = ARRAY_SIZE(twl4030_dai); | 2329 | codec->num_dai = ARRAY_SIZE(twl4030_dai); |
2292 | codec->reg_cache_size = sizeof(twl4030_reg); | 2330 | codec->reg_cache_size = sizeof(twl4030_reg); |
@@ -2302,9 +2340,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2302 | 2340 | ||
2303 | /* Set the defaults, and power up the codec */ | 2341 | /* Set the defaults, and power up the codec */ |
2304 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; | 2342 | twl4030->sysclk = twl4030_codec_get_mclk() / 1000; |
2305 | twl4030_init_chip(codec); | ||
2306 | codec->bias_level = SND_SOC_BIAS_OFF; | 2343 | codec->bias_level = SND_SOC_BIAS_OFF; |
2307 | twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2308 | 2344 | ||
2309 | ret = snd_soc_register_codec(codec); | 2345 | ret = snd_soc_register_codec(codec); |
2310 | if (ret != 0) { | 2346 | if (ret != 0) { |
@@ -2322,7 +2358,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev) | |||
2322 | return 0; | 2358 | return 0; |
2323 | 2359 | ||
2324 | error_codec: | 2360 | error_codec: |
2325 | twl4030_power_down(codec); | 2361 | twl4030_codec_enable(codec, 0); |
2326 | kfree(codec->reg_cache); | 2362 | kfree(codec->reg_cache); |
2327 | error_cache: | 2363 | error_cache: |
2328 | kfree(twl4030); | 2364 | kfree(twl4030); |
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h index f206d242ca31..6c57430f6e24 100644 --- a/sound/soc/codecs/twl4030.h +++ b/sound/soc/codecs/twl4030.h | |||
@@ -41,7 +41,11 @@ extern struct snd_soc_codec_device soc_codec_dev_twl4030; | |||
41 | 41 | ||
42 | struct twl4030_setup_data { | 42 | struct twl4030_setup_data { |
43 | unsigned int ramp_delay_value; | 43 | unsigned int ramp_delay_value; |
44 | unsigned int digimic_delay; /* in ms */ | ||
44 | unsigned int sysclk; | 45 | unsigned int sysclk; |
46 | unsigned int offset_cncl_path; | ||
47 | unsigned int check_defaults:1; | ||
48 | unsigned int reset_registers:1; | ||
45 | unsigned int hs_extmute:1; | 49 | unsigned int hs_extmute:1; |
46 | void (*set_hs_extmute)(int mute); | 50 | void (*set_hs_extmute)(int mute); |
47 | }; | 51 | }; |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index af36346ff336..64a807f1a8a1 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -360,6 +360,13 @@ static int headset_power_mode(struct snd_soc_codec *codec, int high_perf) | |||
360 | return 0; | 360 | return 0; |
361 | } | 361 | } |
362 | 362 | ||
363 | static int twl6040_hs_dac_event(struct snd_soc_dapm_widget *w, | ||
364 | struct snd_kcontrol *kcontrol, int event) | ||
365 | { | ||
366 | msleep(1); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
363 | static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | 370 | static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, |
364 | struct snd_kcontrol *kcontrol, int event) | 371 | struct snd_kcontrol *kcontrol, int event) |
365 | { | 372 | { |
@@ -371,6 +378,8 @@ static int twl6040_power_mode_event(struct snd_soc_dapm_widget *w, | |||
371 | else | 378 | else |
372 | priv->non_lp--; | 379 | priv->non_lp--; |
373 | 380 | ||
381 | msleep(1); | ||
382 | |||
374 | return 0; | 383 | return 0; |
375 | } | 384 | } |
376 | 385 | ||
@@ -471,20 +480,6 @@ static const struct snd_kcontrol_new hfdacl_switch_controls = | |||
471 | static const struct snd_kcontrol_new hfdacr_switch_controls = | 480 | static const struct snd_kcontrol_new hfdacr_switch_controls = |
472 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0); | 481 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 2, 1, 0); |
473 | 482 | ||
474 | /* Headset driver switches */ | ||
475 | static const struct snd_kcontrol_new hsl_driver_switch_controls = | ||
476 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSLCTL, 2, 1, 0); | ||
477 | |||
478 | static const struct snd_kcontrol_new hsr_driver_switch_controls = | ||
479 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HSRCTL, 2, 1, 0); | ||
480 | |||
481 | /* Handsfree driver switches */ | ||
482 | static const struct snd_kcontrol_new hfl_driver_switch_controls = | ||
483 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFLCTL, 4, 1, 0); | ||
484 | |||
485 | static const struct snd_kcontrol_new hfr_driver_switch_controls = | ||
486 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_HFRCTL, 4, 1, 0); | ||
487 | |||
488 | static const struct snd_kcontrol_new ep_driver_switch_controls = | 483 | static const struct snd_kcontrol_new ep_driver_switch_controls = |
489 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); | 484 | SOC_DAPM_SINGLE("Switch", TWL6040_REG_EARCTL, 0, 1, 0); |
490 | 485 | ||
@@ -548,10 +543,14 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { | |||
548 | TWL6040_REG_DMICBCTL, 4, 0), | 543 | TWL6040_REG_DMICBCTL, 4, 0), |
549 | 544 | ||
550 | /* DACs */ | 545 | /* DACs */ |
551 | SND_SOC_DAPM_DAC("HSDAC Left", "Headset Playback", | 546 | SND_SOC_DAPM_DAC_E("HSDAC Left", "Headset Playback", |
552 | TWL6040_REG_HSLCTL, 0, 0), | 547 | TWL6040_REG_HSLCTL, 0, 0, |
553 | SND_SOC_DAPM_DAC("HSDAC Right", "Headset Playback", | 548 | twl6040_hs_dac_event, |
554 | TWL6040_REG_HSRCTL, 0, 0), | 549 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
550 | SND_SOC_DAPM_DAC_E("HSDAC Right", "Headset Playback", | ||
551 | TWL6040_REG_HSRCTL, 0, 0, | ||
552 | twl6040_hs_dac_event, | ||
553 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
555 | SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", | 554 | SND_SOC_DAPM_DAC_E("HFDAC Left", "Handsfree Playback", |
556 | TWL6040_REG_HFLCTL, 0, 0, | 555 | TWL6040_REG_HFLCTL, 0, 0, |
557 | twl6040_power_mode_event, | 556 | twl6040_power_mode_event, |
@@ -571,18 +570,19 @@ static const struct snd_soc_dapm_widget twl6040_dapm_widgets[] = { | |||
571 | SND_SOC_DAPM_SWITCH("HFDAC Right Playback", | 570 | SND_SOC_DAPM_SWITCH("HFDAC Right Playback", |
572 | SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls), | 571 | SND_SOC_NOPM, 0, 0, &hfdacr_switch_controls), |
573 | 572 | ||
574 | SND_SOC_DAPM_SWITCH("Headset Left Driver", | 573 | /* Analog playback drivers */ |
575 | SND_SOC_NOPM, 0, 0, &hsl_driver_switch_controls), | 574 | SND_SOC_DAPM_PGA_E("Handsfree Left Driver", |
576 | SND_SOC_DAPM_SWITCH("Headset Right Driver", | 575 | TWL6040_REG_HFLCTL, 4, 0, NULL, 0, |
577 | SND_SOC_NOPM, 0, 0, &hsr_driver_switch_controls), | ||
578 | SND_SOC_DAPM_SWITCH_E("Handsfree Left Driver", | ||
579 | SND_SOC_NOPM, 0, 0, &hfl_driver_switch_controls, | ||
580 | twl6040_power_mode_event, | 576 | twl6040_power_mode_event, |
581 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 577 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
582 | SND_SOC_DAPM_SWITCH_E("Handsfree Right Driver", | 578 | SND_SOC_DAPM_PGA_E("Handsfree Right Driver", |
583 | SND_SOC_NOPM, 0, 0, &hfr_driver_switch_controls, | 579 | TWL6040_REG_HFRCTL, 4, 0, NULL, 0, |
584 | twl6040_power_mode_event, | 580 | twl6040_power_mode_event, |
585 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | 581 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), |
582 | SND_SOC_DAPM_PGA("Headset Left Driver", | ||
583 | TWL6040_REG_HSLCTL, 2, 0, NULL, 0), | ||
584 | SND_SOC_DAPM_PGA("Headset Right Driver", | ||
585 | TWL6040_REG_HSRCTL, 2, 0, NULL, 0), | ||
586 | SND_SOC_DAPM_SWITCH_E("Earphone Driver", | 586 | SND_SOC_DAPM_SWITCH_E("Earphone Driver", |
587 | SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, | 587 | SND_SOC_NOPM, 0, 0, &ep_driver_switch_controls, |
588 | twl6040_power_mode_event, | 588 | twl6040_power_mode_event, |
@@ -616,8 +616,8 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
616 | {"HSDAC Left Playback", "Switch", "HSDAC Left"}, | 616 | {"HSDAC Left Playback", "Switch", "HSDAC Left"}, |
617 | {"HSDAC Right Playback", "Switch", "HSDAC Right"}, | 617 | {"HSDAC Right Playback", "Switch", "HSDAC Right"}, |
618 | 618 | ||
619 | {"Headset Left Driver", "Switch", "HSDAC Left Playback"}, | 619 | {"Headset Left Driver", NULL, "HSDAC Left Playback"}, |
620 | {"Headset Right Driver", "Switch", "HSDAC Right Playback"}, | 620 | {"Headset Right Driver", NULL, "HSDAC Right Playback"}, |
621 | 621 | ||
622 | {"HSOL", NULL, "Headset Left Driver"}, | 622 | {"HSOL", NULL, "Headset Left Driver"}, |
623 | {"HSOR", NULL, "Headset Right Driver"}, | 623 | {"HSOR", NULL, "Headset Right Driver"}, |
@@ -928,7 +928,7 @@ static int twl6040_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
928 | case 19200000: | 928 | case 19200000: |
929 | /* mclk input, pll disabled */ | 929 | /* mclk input, pll disabled */ |
930 | hppllctl |= TWL6040_MCLK_19200KHZ | | 930 | hppllctl |= TWL6040_MCLK_19200KHZ | |
931 | TWL6040_HPLLSQRBP | | 931 | TWL6040_HPLLSQRENA | |
932 | TWL6040_HPLLBP; | 932 | TWL6040_HPLLBP; |
933 | break; | 933 | break; |
934 | case 26000000: | 934 | case 26000000: |
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 28aac53c97bb..f3b4c1d6a82d 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c | |||
@@ -28,19 +28,6 @@ | |||
28 | #include "uda134x.h" | 28 | #include "uda134x.h" |
29 | 29 | ||
30 | 30 | ||
31 | #define POWER_OFF_ON_STANDBY 1 | ||
32 | /* | ||
33 | ALSA SOC usually puts the device in standby mode when it's not used | ||
34 | for sometime. If you define POWER_OFF_ON_STANDBY the driver will | ||
35 | turn off the ADC/DAC when this callback is invoked and turn it back | ||
36 | on when needed. Unfortunately this will result in a very light bump | ||
37 | (it can be audible only with good earphones). If this bothers you | ||
38 | just comment this line, you will have slightly higher power | ||
39 | consumption . Please note that sending the L3 command for ADC is | ||
40 | enough to make the bump, so it doesn't make difference if you | ||
41 | completely take off power from the codec. | ||
42 | */ | ||
43 | |||
44 | #define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 | 31 | #define UDA134X_RATES SNDRV_PCM_RATE_8000_48000 |
45 | #define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ | 32 | #define UDA134X_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ |
46 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) | 33 | SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S20_3LE) |
@@ -58,7 +45,7 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = { | |||
58 | /* Extended address registers */ | 45 | /* Extended address registers */ |
59 | 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, | 46 | 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, |
60 | /* Status, data regs */ | 47 | /* Status, data regs */ |
61 | 0x00, 0x83, 0x00, 0x40, 0x80, 0x00, | 48 | 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00, |
62 | }; | 49 | }; |
63 | 50 | ||
64 | /* | 51 | /* |
@@ -117,6 +104,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, | |||
117 | case UDA134X_DATA000: | 104 | case UDA134X_DATA000: |
118 | case UDA134X_DATA001: | 105 | case UDA134X_DATA001: |
119 | case UDA134X_DATA010: | 106 | case UDA134X_DATA010: |
107 | case UDA134X_DATA011: | ||
120 | addr = UDA134X_DATA0_ADDR; | 108 | addr = UDA134X_DATA0_ADDR; |
121 | break; | 109 | break; |
122 | case UDA134X_DATA1: | 110 | case UDA134X_DATA1: |
@@ -353,8 +341,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
353 | switch (level) { | 341 | switch (level) { |
354 | case SND_SOC_BIAS_ON: | 342 | case SND_SOC_BIAS_ON: |
355 | /* ADC, DAC on */ | 343 | /* ADC, DAC on */ |
356 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | 344 | switch (pd->model) { |
357 | uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); | 345 | case UDA134X_UDA1340: |
346 | case UDA134X_UDA1344: | ||
347 | case UDA134X_UDA1345: | ||
348 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
349 | uda134x_write(codec, UDA134X_DATA011, reg | 0x03); | ||
350 | break; | ||
351 | case UDA134X_UDA1341: | ||
352 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
353 | uda134x_write(codec, UDA134X_STATUS1, reg | 0x03); | ||
354 | break; | ||
355 | default: | ||
356 | printk(KERN_ERR "UDA134X SoC codec: " | ||
357 | "unsupported model %d\n", pd->model); | ||
358 | return -EINVAL; | ||
359 | } | ||
358 | break; | 360 | break; |
359 | case SND_SOC_BIAS_PREPARE: | 361 | case SND_SOC_BIAS_PREPARE: |
360 | /* power on */ | 362 | /* power on */ |
@@ -367,8 +369,22 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, | |||
367 | break; | 369 | break; |
368 | case SND_SOC_BIAS_STANDBY: | 370 | case SND_SOC_BIAS_STANDBY: |
369 | /* ADC, DAC power off */ | 371 | /* ADC, DAC power off */ |
370 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | 372 | switch (pd->model) { |
371 | uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); | 373 | case UDA134X_UDA1340: |
374 | case UDA134X_UDA1344: | ||
375 | case UDA134X_UDA1345: | ||
376 | reg = uda134x_read_reg_cache(codec, UDA134X_DATA011); | ||
377 | uda134x_write(codec, UDA134X_DATA011, reg & ~(0x03)); | ||
378 | break; | ||
379 | case UDA134X_UDA1341: | ||
380 | reg = uda134x_read_reg_cache(codec, UDA134X_STATUS1); | ||
381 | uda134x_write(codec, UDA134X_STATUS1, reg & ~(0x03)); | ||
382 | break; | ||
383 | default: | ||
384 | printk(KERN_ERR "UDA134X SoC codec: " | ||
385 | "unsupported model %d\n", pd->model); | ||
386 | return -EINVAL; | ||
387 | } | ||
372 | break; | 388 | break; |
373 | case SND_SOC_BIAS_OFF: | 389 | case SND_SOC_BIAS_OFF: |
374 | /* power off */ | 390 | /* power off */ |
@@ -531,9 +547,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
531 | codec->num_dai = 1; | 547 | codec->num_dai = 1; |
532 | codec->read = uda134x_read_reg_cache; | 548 | codec->read = uda134x_read_reg_cache; |
533 | codec->write = uda134x_write; | 549 | codec->write = uda134x_write; |
534 | #ifdef POWER_OFF_ON_STANDBY | 550 | |
535 | codec->set_bias_level = uda134x_set_bias_level; | ||
536 | #endif | ||
537 | INIT_LIST_HEAD(&codec->dapm_widgets); | 551 | INIT_LIST_HEAD(&codec->dapm_widgets); |
538 | INIT_LIST_HEAD(&codec->dapm_paths); | 552 | INIT_LIST_HEAD(&codec->dapm_paths); |
539 | 553 | ||
@@ -544,6 +558,14 @@ static int uda134x_soc_probe(struct platform_device *pdev) | |||
544 | 558 | ||
545 | uda134x_reset(codec); | 559 | uda134x_reset(codec); |
546 | 560 | ||
561 | if (pd->is_powered_on_standby) { | ||
562 | codec->set_bias_level = NULL; | ||
563 | uda134x_set_bias_level(codec, SND_SOC_BIAS_ON); | ||
564 | } else { | ||
565 | codec->set_bias_level = uda134x_set_bias_level; | ||
566 | uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
567 | } | ||
568 | |||
547 | /* register pcms */ | 569 | /* register pcms */ |
548 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | 570 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
549 | if (ret < 0) { | 571 | if (ret < 0) { |
diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h index 94f440490b31..205f03b3eaf8 100644 --- a/sound/soc/codecs/uda134x.h +++ b/sound/soc/codecs/uda134x.h | |||
@@ -23,9 +23,10 @@ | |||
23 | #define UDA134X_DATA000 10 | 23 | #define UDA134X_DATA000 10 |
24 | #define UDA134X_DATA001 11 | 24 | #define UDA134X_DATA001 11 |
25 | #define UDA134X_DATA010 12 | 25 | #define UDA134X_DATA010 12 |
26 | #define UDA134X_DATA1 13 | 26 | #define UDA134X_DATA011 13 |
27 | #define UDA134X_DATA1 14 | ||
27 | 28 | ||
28 | #define UDA134X_REGS_NUM 14 | 29 | #define UDA134X_REGS_NUM 15 |
29 | 30 | ||
30 | #define STATUS0_DAIFMT_MASK (~(7<<1)) | 31 | #define STATUS0_DAIFMT_MASK (~(7<<1)) |
31 | #define STATUS0_SYSCLK_MASK (~(3<<4)) | 32 | #define STATUS0_SYSCLK_MASK (~(3<<4)) |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 002e289d1255..4bcd168794e1 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -795,6 +795,8 @@ static int __devinit wm2000_i2c_probe(struct i2c_client *i2c, | |||
795 | 795 | ||
796 | dev_set_drvdata(&i2c->dev, wm2000); | 796 | dev_set_drvdata(&i2c->dev, wm2000); |
797 | wm2000->anc_eng_ena = 1; | 797 | wm2000->anc_eng_ena = 1; |
798 | wm2000->anc_active = 1; | ||
799 | wm2000->spk_ena = 1; | ||
798 | wm2000->i2c = i2c; | 800 | wm2000->i2c = i2c; |
799 | 801 | ||
800 | wm2000_reset(wm2000); | 802 | wm2000_reset(wm2000); |
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 37242a7d3077..0ad039b4adf5 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c | |||
@@ -482,7 +482,8 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
482 | 482 | ||
483 | if (wm8523_codec) { | 483 | if (wm8523_codec) { |
484 | dev_err(codec->dev, "Another WM8523 is registered\n"); | 484 | dev_err(codec->dev, "Another WM8523 is registered\n"); |
485 | return -EINVAL; | 485 | ret = -EINVAL; |
486 | goto err; | ||
486 | } | 487 | } |
487 | 488 | ||
488 | mutex_init(&codec->mutex); | 489 | mutex_init(&codec->mutex); |
@@ -570,18 +571,19 @@ static int wm8523_register(struct wm8523_priv *wm8523, | |||
570 | ret = snd_soc_register_codec(codec); | 571 | ret = snd_soc_register_codec(codec); |
571 | if (ret != 0) { | 572 | if (ret != 0) { |
572 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 573 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
573 | return ret; | 574 | goto err_enable; |
574 | } | 575 | } |
575 | 576 | ||
576 | ret = snd_soc_register_dai(&wm8523_dai); | 577 | ret = snd_soc_register_dai(&wm8523_dai); |
577 | if (ret != 0) { | 578 | if (ret != 0) { |
578 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 579 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
579 | snd_soc_unregister_codec(codec); | 580 | goto err_codec; |
580 | return ret; | ||
581 | } | 581 | } |
582 | 582 | ||
583 | return 0; | 583 | return 0; |
584 | 584 | ||
585 | err_codec: | ||
586 | snd_soc_unregister_codec(codec); | ||
585 | err_enable: | 587 | err_enable: |
586 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); | 588 | regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies); |
587 | err_get: | 589 | err_get: |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index c3571ee5c11b..72deeabef4fe 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -269,9 +269,9 @@ SOC_DOUBLE("DAC2 Invert Switch", WM8580_DAC_CONTROL4, 2, 3, 1, 0), | |||
269 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), | 269 | SOC_DOUBLE("DAC3 Invert Switch", WM8580_DAC_CONTROL4, 4, 5, 1, 0), |
270 | 270 | ||
271 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), | 271 | SOC_SINGLE("DAC ZC Switch", WM8580_DAC_CONTROL5, 5, 1, 0), |
272 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 0), | 272 | SOC_SINGLE("DAC1 Switch", WM8580_DAC_CONTROL5, 0, 1, 1), |
273 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 0), | 273 | SOC_SINGLE("DAC2 Switch", WM8580_DAC_CONTROL5, 1, 1, 1), |
274 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 0), | 274 | SOC_SINGLE("DAC3 Switch", WM8580_DAC_CONTROL5, 2, 1, 1), |
275 | 275 | ||
276 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), | 276 | SOC_DOUBLE("ADC Mute Switch", WM8580_ADC_CONTROL1, 0, 1, 1, 0), |
277 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), | 277 | SOC_SINGLE("ADC High-Pass Filter Switch", WM8580_ADC_CONTROL1, 4, 1, 0), |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index effb14eee7d4..e2dba07f0260 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -439,7 +439,8 @@ static int wm8711_register(struct wm8711_priv *wm8711, | |||
439 | 439 | ||
440 | if (wm8711_codec) { | 440 | if (wm8711_codec) { |
441 | dev_err(codec->dev, "Another WM8711 is registered\n"); | 441 | dev_err(codec->dev, "Another WM8711 is registered\n"); |
442 | return -EINVAL; | 442 | ret = -EINVAL; |
443 | goto err; | ||
443 | } | 444 | } |
444 | 445 | ||
445 | mutex_init(&codec->mutex); | 446 | mutex_init(&codec->mutex); |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c new file mode 100644 index 000000000000..b9ea8904ad4b --- /dev/null +++ b/sound/soc/codecs/wm8741.c | |||
@@ -0,0 +1,579 @@ | |||
1 | /* | ||
2 | * wm8741.c -- WM8741 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2010 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/pm.h> | ||
19 | #include <linux/i2c.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dapm.h> | ||
28 | #include <sound/initval.h> | ||
29 | #include <sound/tlv.h> | ||
30 | |||
31 | #include "wm8741.h" | ||
32 | |||
33 | static struct snd_soc_codec *wm8741_codec; | ||
34 | struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
35 | |||
36 | #define WM8741_NUM_SUPPLIES 2 | ||
37 | static const char *wm8741_supply_names[WM8741_NUM_SUPPLIES] = { | ||
38 | "AVDD", | ||
39 | "DVDD", | ||
40 | }; | ||
41 | |||
42 | #define WM8741_NUM_RATES 4 | ||
43 | |||
44 | /* codec private data */ | ||
45 | struct wm8741_priv { | ||
46 | struct snd_soc_codec codec; | ||
47 | u16 reg_cache[WM8741_REGISTER_COUNT]; | ||
48 | struct regulator_bulk_data supplies[WM8741_NUM_SUPPLIES]; | ||
49 | unsigned int sysclk; | ||
50 | unsigned int rate_constraint_list[WM8741_NUM_RATES]; | ||
51 | struct snd_pcm_hw_constraint_list rate_constraint; | ||
52 | }; | ||
53 | |||
54 | static const u16 wm8741_reg_defaults[WM8741_REGISTER_COUNT] = { | ||
55 | 0x0000, /* R0 - DACLLSB Attenuation */ | ||
56 | 0x0000, /* R1 - DACLMSB Attenuation */ | ||
57 | 0x0000, /* R2 - DACRLSB Attenuation */ | ||
58 | 0x0000, /* R3 - DACRMSB Attenuation */ | ||
59 | 0x0000, /* R4 - Volume Control */ | ||
60 | 0x000A, /* R5 - Format Control */ | ||
61 | 0x0000, /* R6 - Filter Control */ | ||
62 | 0x0000, /* R7 - Mode Control 1 */ | ||
63 | 0x0002, /* R8 - Mode Control 2 */ | ||
64 | 0x0000, /* R9 - Reset */ | ||
65 | 0x0002, /* R32 - ADDITONAL_CONTROL_1 */ | ||
66 | }; | ||
67 | |||
68 | |||
69 | static int wm8741_reset(struct snd_soc_codec *codec) | ||
70 | { | ||
71 | return snd_soc_write(codec, WM8741_RESET, 0); | ||
72 | } | ||
73 | |||
74 | static const DECLARE_TLV_DB_SCALE(dac_tlv_fine, -12700, 13, 0); | ||
75 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 400, 0); | ||
76 | |||
77 | static const struct snd_kcontrol_new wm8741_snd_controls[] = { | ||
78 | SOC_DOUBLE_R_TLV("Fine Playback Volume", WM8741_DACLLSB_ATTENUATION, | ||
79 | WM8741_DACRLSB_ATTENUATION, 1, 255, 1, dac_tlv_fine), | ||
80 | SOC_DOUBLE_R_TLV("Playback Volume", WM8741_DACLMSB_ATTENUATION, | ||
81 | WM8741_DACRMSB_ATTENUATION, 0, 511, 1, dac_tlv), | ||
82 | }; | ||
83 | |||
84 | static const struct snd_soc_dapm_widget wm8741_dapm_widgets[] = { | ||
85 | SND_SOC_DAPM_DAC("DACL", "Playback", SND_SOC_NOPM, 0, 0), | ||
86 | SND_SOC_DAPM_DAC("DACR", "Playback", SND_SOC_NOPM, 0, 0), | ||
87 | SND_SOC_DAPM_OUTPUT("VOUTLP"), | ||
88 | SND_SOC_DAPM_OUTPUT("VOUTLN"), | ||
89 | SND_SOC_DAPM_OUTPUT("VOUTRP"), | ||
90 | SND_SOC_DAPM_OUTPUT("VOUTRN"), | ||
91 | }; | ||
92 | |||
93 | static const struct snd_soc_dapm_route intercon[] = { | ||
94 | { "VOUTLP", NULL, "DACL" }, | ||
95 | { "VOUTLN", NULL, "DACL" }, | ||
96 | { "VOUTRP", NULL, "DACR" }, | ||
97 | { "VOUTRN", NULL, "DACR" }, | ||
98 | }; | ||
99 | |||
100 | static int wm8741_add_widgets(struct snd_soc_codec *codec) | ||
101 | { | ||
102 | snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets, | ||
103 | ARRAY_SIZE(wm8741_dapm_widgets)); | ||
104 | |||
105 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
106 | |||
107 | return 0; | ||
108 | } | ||
109 | |||
110 | static struct { | ||
111 | int value; | ||
112 | int ratio; | ||
113 | } lrclk_ratios[WM8741_NUM_RATES] = { | ||
114 | { 1, 256 }, | ||
115 | { 2, 384 }, | ||
116 | { 3, 512 }, | ||
117 | { 4, 768 }, | ||
118 | }; | ||
119 | |||
120 | |||
121 | static int wm8741_startup(struct snd_pcm_substream *substream, | ||
122 | struct snd_soc_dai *dai) | ||
123 | { | ||
124 | struct snd_soc_codec *codec = dai->codec; | ||
125 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
126 | |||
127 | /* The set of sample rates that can be supported depends on the | ||
128 | * MCLK supplied to the CODEC - enforce this. | ||
129 | */ | ||
130 | if (!wm8741->sysclk) { | ||
131 | dev_err(codec->dev, | ||
132 | "No MCLK configured, call set_sysclk() on init\n"); | ||
133 | return -EINVAL; | ||
134 | } | ||
135 | |||
136 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
137 | SNDRV_PCM_HW_PARAM_RATE, | ||
138 | &wm8741->rate_constraint); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static int wm8741_hw_params(struct snd_pcm_substream *substream, | ||
144 | struct snd_pcm_hw_params *params, | ||
145 | struct snd_soc_dai *dai) | ||
146 | { | ||
147 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
148 | struct snd_soc_device *socdev = rtd->socdev; | ||
149 | struct snd_soc_codec *codec = socdev->card->codec; | ||
150 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
151 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1FC; | ||
152 | int i; | ||
153 | |||
154 | /* Find a supported LRCLK ratio */ | ||
155 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
156 | if (wm8741->sysclk / params_rate(params) == | ||
157 | lrclk_ratios[i].ratio) | ||
158 | break; | ||
159 | } | ||
160 | |||
161 | /* Should never happen, should be handled by constraints */ | ||
162 | if (i == ARRAY_SIZE(lrclk_ratios)) { | ||
163 | dev_err(codec->dev, "MCLK/fs ratio %d unsupported\n", | ||
164 | wm8741->sysclk / params_rate(params)); | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
168 | /* bit size */ | ||
169 | switch (params_format(params)) { | ||
170 | case SNDRV_PCM_FORMAT_S16_LE: | ||
171 | break; | ||
172 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
173 | iface |= 0x0001; | ||
174 | break; | ||
175 | case SNDRV_PCM_FORMAT_S24_LE: | ||
176 | iface |= 0x0002; | ||
177 | break; | ||
178 | case SNDRV_PCM_FORMAT_S32_LE: | ||
179 | iface |= 0x0003; | ||
180 | break; | ||
181 | default: | ||
182 | dev_dbg(codec->dev, "wm8741_hw_params: Unsupported bit size param = %d", | ||
183 | params_format(params)); | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | |||
187 | dev_dbg(codec->dev, "wm8741_hw_params: bit size param = %d", | ||
188 | params_format(params)); | ||
189 | |||
190 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int wm8741_set_dai_sysclk(struct snd_soc_dai *codec_dai, | ||
195 | int clk_id, unsigned int freq, int dir) | ||
196 | { | ||
197 | struct snd_soc_codec *codec = codec_dai->codec; | ||
198 | struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec); | ||
199 | unsigned int val; | ||
200 | int i; | ||
201 | |||
202 | dev_dbg(codec->dev, "wm8741_set_dai_sysclk info: freq=%dHz\n", freq); | ||
203 | |||
204 | wm8741->sysclk = freq; | ||
205 | |||
206 | wm8741->rate_constraint.count = 0; | ||
207 | |||
208 | for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { | ||
209 | dev_dbg(codec->dev, "index = %d, ratio = %d, freq = %d", | ||
210 | i, lrclk_ratios[i].ratio, freq); | ||
211 | |||
212 | val = freq / lrclk_ratios[i].ratio; | ||
213 | /* Check that it's a standard rate since core can't | ||
214 | * cope with others and having the odd rates confuses | ||
215 | * constraint matching. | ||
216 | */ | ||
217 | switch (val) { | ||
218 | case 32000: | ||
219 | case 44100: | ||
220 | case 48000: | ||
221 | case 64000: | ||
222 | case 88200: | ||
223 | case 96000: | ||
224 | dev_dbg(codec->dev, "Supported sample rate: %dHz\n", | ||
225 | val); | ||
226 | wm8741->rate_constraint_list[i] = val; | ||
227 | wm8741->rate_constraint.count++; | ||
228 | break; | ||
229 | default: | ||
230 | dev_dbg(codec->dev, "Skipping sample rate: %dHz\n", | ||
231 | val); | ||
232 | } | ||
233 | } | ||
234 | |||
235 | /* Need at least one supported rate... */ | ||
236 | if (wm8741->rate_constraint.count == 0) | ||
237 | return -EINVAL; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
243 | unsigned int fmt) | ||
244 | { | ||
245 | struct snd_soc_codec *codec = codec_dai->codec; | ||
246 | u16 iface = snd_soc_read(codec, WM8741_FORMAT_CONTROL) & 0x1C3; | ||
247 | |||
248 | /* check master/slave audio interface */ | ||
249 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
250 | case SND_SOC_DAIFMT_CBS_CFS: | ||
251 | break; | ||
252 | default: | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | |||
256 | /* interface format */ | ||
257 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
258 | case SND_SOC_DAIFMT_I2S: | ||
259 | iface |= 0x0008; | ||
260 | break; | ||
261 | case SND_SOC_DAIFMT_RIGHT_J: | ||
262 | break; | ||
263 | case SND_SOC_DAIFMT_LEFT_J: | ||
264 | iface |= 0x0004; | ||
265 | break; | ||
266 | case SND_SOC_DAIFMT_DSP_A: | ||
267 | iface |= 0x0003; | ||
268 | break; | ||
269 | case SND_SOC_DAIFMT_DSP_B: | ||
270 | iface |= 0x0013; | ||
271 | break; | ||
272 | default: | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | /* clock inversion */ | ||
277 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
278 | case SND_SOC_DAIFMT_NB_NF: | ||
279 | break; | ||
280 | case SND_SOC_DAIFMT_IB_IF: | ||
281 | iface |= 0x0010; | ||
282 | break; | ||
283 | case SND_SOC_DAIFMT_IB_NF: | ||
284 | iface |= 0x0020; | ||
285 | break; | ||
286 | case SND_SOC_DAIFMT_NB_IF: | ||
287 | iface |= 0x0030; | ||
288 | break; | ||
289 | default: | ||
290 | return -EINVAL; | ||
291 | } | ||
292 | |||
293 | |||
294 | dev_dbg(codec->dev, "wm8741_set_dai_fmt: Format=%x, Clock Inv=%x\n", | ||
295 | fmt & SND_SOC_DAIFMT_FORMAT_MASK, | ||
296 | ((fmt & SND_SOC_DAIFMT_INV_MASK))); | ||
297 | |||
298 | snd_soc_write(codec, WM8741_FORMAT_CONTROL, iface); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | #define WM8741_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
303 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \ | ||
304 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 | \ | ||
305 | SNDRV_PCM_RATE_192000) | ||
306 | |||
307 | #define WM8741_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
308 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
309 | |||
310 | static struct snd_soc_dai_ops wm8741_dai_ops = { | ||
311 | .startup = wm8741_startup, | ||
312 | .hw_params = wm8741_hw_params, | ||
313 | .set_sysclk = wm8741_set_dai_sysclk, | ||
314 | .set_fmt = wm8741_set_dai_fmt, | ||
315 | }; | ||
316 | |||
317 | struct snd_soc_dai wm8741_dai = { | ||
318 | .name = "WM8741", | ||
319 | .playback = { | ||
320 | .stream_name = "Playback", | ||
321 | .channels_min = 2, /* Mono modes not yet supported */ | ||
322 | .channels_max = 2, | ||
323 | .rates = WM8741_RATES, | ||
324 | .formats = WM8741_FORMATS, | ||
325 | }, | ||
326 | .ops = &wm8741_dai_ops, | ||
327 | }; | ||
328 | EXPORT_SYMBOL_GPL(wm8741_dai); | ||
329 | |||
330 | #ifdef CONFIG_PM | ||
331 | static int wm8741_resume(struct platform_device *pdev) | ||
332 | { | ||
333 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
334 | struct snd_soc_codec *codec = socdev->card->codec; | ||
335 | u16 *cache = codec->reg_cache; | ||
336 | int i; | ||
337 | |||
338 | /* RESTORE REG Cache */ | ||
339 | for (i = 0; i < WM8741_REGISTER_COUNT; i++) { | ||
340 | if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i) | ||
341 | continue; | ||
342 | snd_soc_write(codec, i, cache[i]); | ||
343 | } | ||
344 | return 0; | ||
345 | } | ||
346 | #else | ||
347 | #define wm8741_suspend NULL | ||
348 | #define wm8741_resume NULL | ||
349 | #endif | ||
350 | |||
351 | static int wm8741_probe(struct platform_device *pdev) | ||
352 | { | ||
353 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
354 | struct snd_soc_codec *codec; | ||
355 | int ret = 0; | ||
356 | |||
357 | if (wm8741_codec == NULL) { | ||
358 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
359 | return -ENODEV; | ||
360 | } | ||
361 | |||
362 | socdev->card->codec = wm8741_codec; | ||
363 | codec = wm8741_codec; | ||
364 | |||
365 | /* register pcms */ | ||
366 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
367 | if (ret < 0) { | ||
368 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
369 | goto pcm_err; | ||
370 | } | ||
371 | |||
372 | snd_soc_add_controls(codec, wm8741_snd_controls, | ||
373 | ARRAY_SIZE(wm8741_snd_controls)); | ||
374 | wm8741_add_widgets(codec); | ||
375 | |||
376 | return ret; | ||
377 | |||
378 | pcm_err: | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | static int wm8741_remove(struct platform_device *pdev) | ||
383 | { | ||
384 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
385 | |||
386 | snd_soc_free_pcms(socdev); | ||
387 | snd_soc_dapm_free(socdev); | ||
388 | |||
389 | return 0; | ||
390 | } | ||
391 | |||
392 | struct snd_soc_codec_device soc_codec_dev_wm8741 = { | ||
393 | .probe = wm8741_probe, | ||
394 | .remove = wm8741_remove, | ||
395 | .resume = wm8741_resume, | ||
396 | }; | ||
397 | EXPORT_SYMBOL_GPL(soc_codec_dev_wm8741); | ||
398 | |||
399 | static int wm8741_register(struct wm8741_priv *wm8741, | ||
400 | enum snd_soc_control_type control) | ||
401 | { | ||
402 | int ret; | ||
403 | struct snd_soc_codec *codec = &wm8741->codec; | ||
404 | int i; | ||
405 | |||
406 | if (wm8741_codec) { | ||
407 | dev_err(codec->dev, "Another WM8741 is registered\n"); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | |||
411 | mutex_init(&codec->mutex); | ||
412 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
413 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
414 | |||
415 | snd_soc_codec_set_drvdata(codec, wm8741); | ||
416 | codec->name = "WM8741"; | ||
417 | codec->owner = THIS_MODULE; | ||
418 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
419 | codec->set_bias_level = NULL; | ||
420 | codec->dai = &wm8741_dai; | ||
421 | codec->num_dai = 1; | ||
422 | codec->reg_cache_size = WM8741_REGISTER_COUNT; | ||
423 | codec->reg_cache = &wm8741->reg_cache; | ||
424 | |||
425 | wm8741->rate_constraint.list = &wm8741->rate_constraint_list[0]; | ||
426 | wm8741->rate_constraint.count = | ||
427 | ARRAY_SIZE(wm8741->rate_constraint_list); | ||
428 | |||
429 | memcpy(codec->reg_cache, wm8741_reg_defaults, | ||
430 | sizeof(wm8741->reg_cache)); | ||
431 | |||
432 | ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); | ||
433 | if (ret != 0) { | ||
434 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
435 | goto err; | ||
436 | } | ||
437 | |||
438 | for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++) | ||
439 | wm8741->supplies[i].supply = wm8741_supply_names[i]; | ||
440 | |||
441 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies), | ||
442 | wm8741->supplies); | ||
443 | if (ret != 0) { | ||
444 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
445 | goto err; | ||
446 | } | ||
447 | |||
448 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies), | ||
449 | wm8741->supplies); | ||
450 | if (ret != 0) { | ||
451 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
452 | goto err_get; | ||
453 | } | ||
454 | |||
455 | ret = wm8741_reset(codec); | ||
456 | if (ret < 0) { | ||
457 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
458 | goto err_enable; | ||
459 | } | ||
460 | |||
461 | wm8741_dai.dev = codec->dev; | ||
462 | |||
463 | /* Change some default settings - latch VU */ | ||
464 | wm8741->reg_cache[WM8741_DACLLSB_ATTENUATION] |= WM8741_UPDATELL; | ||
465 | wm8741->reg_cache[WM8741_DACLMSB_ATTENUATION] |= WM8741_UPDATELM; | ||
466 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERL; | ||
467 | wm8741->reg_cache[WM8741_DACRLSB_ATTENUATION] |= WM8741_UPDATERM; | ||
468 | |||
469 | wm8741_codec = codec; | ||
470 | |||
471 | ret = snd_soc_register_codec(codec); | ||
472 | if (ret != 0) { | ||
473 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
474 | return ret; | ||
475 | } | ||
476 | |||
477 | ret = snd_soc_register_dai(&wm8741_dai); | ||
478 | if (ret != 0) { | ||
479 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
480 | snd_soc_unregister_codec(codec); | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | dev_dbg(codec->dev, "Successful registration\n"); | ||
485 | return 0; | ||
486 | |||
487 | err_enable: | ||
488 | regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
489 | |||
490 | err_get: | ||
491 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
492 | |||
493 | err: | ||
494 | kfree(wm8741); | ||
495 | return ret; | ||
496 | } | ||
497 | |||
498 | static void wm8741_unregister(struct wm8741_priv *wm8741) | ||
499 | { | ||
500 | regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies); | ||
501 | |||
502 | snd_soc_unregister_dai(&wm8741_dai); | ||
503 | snd_soc_unregister_codec(&wm8741->codec); | ||
504 | kfree(wm8741); | ||
505 | wm8741_codec = NULL; | ||
506 | } | ||
507 | |||
508 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
509 | static __devinit int wm8741_i2c_probe(struct i2c_client *i2c, | ||
510 | const struct i2c_device_id *id) | ||
511 | { | ||
512 | struct wm8741_priv *wm8741; | ||
513 | struct snd_soc_codec *codec; | ||
514 | |||
515 | wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL); | ||
516 | if (wm8741 == NULL) | ||
517 | return -ENOMEM; | ||
518 | |||
519 | codec = &wm8741->codec; | ||
520 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
521 | |||
522 | i2c_set_clientdata(i2c, wm8741); | ||
523 | codec->control_data = i2c; | ||
524 | |||
525 | codec->dev = &i2c->dev; | ||
526 | |||
527 | return wm8741_register(wm8741, SND_SOC_I2C); | ||
528 | } | ||
529 | |||
530 | static __devexit int wm8741_i2c_remove(struct i2c_client *client) | ||
531 | { | ||
532 | struct wm8741_priv *wm8741 = i2c_get_clientdata(client); | ||
533 | wm8741_unregister(wm8741); | ||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static const struct i2c_device_id wm8741_i2c_id[] = { | ||
538 | { "wm8741", 0 }, | ||
539 | { } | ||
540 | }; | ||
541 | MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); | ||
542 | |||
543 | |||
544 | static struct i2c_driver wm8741_i2c_driver = { | ||
545 | .driver = { | ||
546 | .name = "WM8741", | ||
547 | .owner = THIS_MODULE, | ||
548 | }, | ||
549 | .probe = wm8741_i2c_probe, | ||
550 | .remove = __devexit_p(wm8741_i2c_remove), | ||
551 | .id_table = wm8741_i2c_id, | ||
552 | }; | ||
553 | #endif | ||
554 | |||
555 | static int __init wm8741_modinit(void) | ||
556 | { | ||
557 | int ret; | ||
558 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
559 | ret = i2c_add_driver(&wm8741_i2c_driver); | ||
560 | if (ret != 0) { | ||
561 | printk(KERN_ERR "Failed to register WM8741 I2C driver: %d\n", | ||
562 | ret); | ||
563 | } | ||
564 | #endif | ||
565 | return 0; | ||
566 | } | ||
567 | module_init(wm8741_modinit); | ||
568 | |||
569 | static void __exit wm8741_exit(void) | ||
570 | { | ||
571 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
572 | i2c_del_driver(&wm8741_i2c_driver); | ||
573 | #endif | ||
574 | } | ||
575 | module_exit(wm8741_exit); | ||
576 | |||
577 | MODULE_DESCRIPTION("ASoC WM8741 driver"); | ||
578 | MODULE_AUTHOR("Ian Lartey <ian@opensource.wolfsonmicro.com>"); | ||
579 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/wm8741.h b/sound/soc/codecs/wm8741.h new file mode 100644 index 000000000000..fdef6ecd1f6f --- /dev/null +++ b/sound/soc/codecs/wm8741.h | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * wm8741.h -- WM8423 ASoC driver | ||
3 | * | ||
4 | * Copyright 2010 Wolfson Microelectronics, plc | ||
5 | * | ||
6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * Based on wm8753.h | ||
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 _WM8741_H | ||
16 | #define _WM8741_H | ||
17 | |||
18 | /* | ||
19 | * Register values. | ||
20 | */ | ||
21 | #define WM8741_DACLLSB_ATTENUATION 0x00 | ||
22 | #define WM8741_DACLMSB_ATTENUATION 0x01 | ||
23 | #define WM8741_DACRLSB_ATTENUATION 0x02 | ||
24 | #define WM8741_DACRMSB_ATTENUATION 0x03 | ||
25 | #define WM8741_VOLUME_CONTROL 0x04 | ||
26 | #define WM8741_FORMAT_CONTROL 0x05 | ||
27 | #define WM8741_FILTER_CONTROL 0x06 | ||
28 | #define WM8741_MODE_CONTROL_1 0x07 | ||
29 | #define WM8741_MODE_CONTROL_2 0x08 | ||
30 | #define WM8741_RESET 0x09 | ||
31 | #define WM8741_ADDITIONAL_CONTROL_1 0x20 | ||
32 | |||
33 | #define WM8741_REGISTER_COUNT 11 | ||
34 | #define WM8741_MAX_REGISTER 0x20 | ||
35 | |||
36 | /* | ||
37 | * Field Definitions. | ||
38 | */ | ||
39 | |||
40 | /* | ||
41 | * R0 (0x00) - DACLLSB_ATTENUATION | ||
42 | */ | ||
43 | #define WM8741_UPDATELL 0x0020 /* UPDATELL */ | ||
44 | #define WM8741_UPDATELL_MASK 0x0020 /* UPDATELL */ | ||
45 | #define WM8741_UPDATELL_SHIFT 5 /* UPDATELL */ | ||
46 | #define WM8741_UPDATELL_WIDTH 1 /* UPDATELL */ | ||
47 | #define WM8741_LAT_4_0_MASK 0x001F /* LAT[4:0] - [4:0] */ | ||
48 | #define WM8741_LAT_4_0_SHIFT 0 /* LAT[4:0] - [4:0] */ | ||
49 | #define WM8741_LAT_4_0_WIDTH 5 /* LAT[4:0] - [4:0] */ | ||
50 | |||
51 | /* | ||
52 | * R1 (0x01) - DACLMSB_ATTENUATION | ||
53 | */ | ||
54 | #define WM8741_UPDATELM 0x0020 /* UPDATELM */ | ||
55 | #define WM8741_UPDATELM_MASK 0x0020 /* UPDATELM */ | ||
56 | #define WM8741_UPDATELM_SHIFT 5 /* UPDATELM */ | ||
57 | #define WM8741_UPDATELM_WIDTH 1 /* UPDATELM */ | ||
58 | #define WM8741_LAT_9_5_0_MASK 0x001F /* LAT[9:5] - [4:0] */ | ||
59 | #define WM8741_LAT_9_5_0_SHIFT 0 /* LAT[9:5] - [4:0] */ | ||
60 | #define WM8741_LAT_9_5_0_WIDTH 5 /* LAT[9:5] - [4:0] */ | ||
61 | |||
62 | /* | ||
63 | * R2 (0x02) - DACRLSB_ATTENUATION | ||
64 | */ | ||
65 | #define WM8741_UPDATERL 0x0020 /* UPDATERL */ | ||
66 | #define WM8741_UPDATERL_MASK 0x0020 /* UPDATERL */ | ||
67 | #define WM8741_UPDATERL_SHIFT 5 /* UPDATERL */ | ||
68 | #define WM8741_UPDATERL_WIDTH 1 /* UPDATERL */ | ||
69 | #define WM8741_RAT_4_0_MASK 0x001F /* RAT[4:0] - [4:0] */ | ||
70 | #define WM8741_RAT_4_0_SHIFT 0 /* RAT[4:0] - [4:0] */ | ||
71 | #define WM8741_RAT_4_0_WIDTH 5 /* RAT[4:0] - [4:0] */ | ||
72 | |||
73 | /* | ||
74 | * R3 (0x03) - DACRMSB_ATTENUATION | ||
75 | */ | ||
76 | #define WM8741_UPDATERM 0x0020 /* UPDATERM */ | ||
77 | #define WM8741_UPDATERM_MASK 0x0020 /* UPDATERM */ | ||
78 | #define WM8741_UPDATERM_SHIFT 5 /* UPDATERM */ | ||
79 | #define WM8741_UPDATERM_WIDTH 1 /* UPDATERM */ | ||
80 | #define WM8741_RAT_9_5_0_MASK 0x001F /* RAT[9:5] - [4:0] */ | ||
81 | #define WM8741_RAT_9_5_0_SHIFT 0 /* RAT[9:5] - [4:0] */ | ||
82 | #define WM8741_RAT_9_5_0_WIDTH 5 /* RAT[9:5] - [4:0] */ | ||
83 | |||
84 | /* | ||
85 | * R4 (0x04) - VOLUME_CONTROL | ||
86 | */ | ||
87 | #define WM8741_AMUTE 0x0080 /* AMUTE */ | ||
88 | #define WM8741_AMUTE_MASK 0x0080 /* AMUTE */ | ||
89 | #define WM8741_AMUTE_SHIFT 7 /* AMUTE */ | ||
90 | #define WM8741_AMUTE_WIDTH 1 /* AMUTE */ | ||
91 | #define WM8741_ZFLAG_MASK 0x0060 /* ZFLAG - [6:5] */ | ||
92 | #define WM8741_ZFLAG_SHIFT 5 /* ZFLAG - [6:5] */ | ||
93 | #define WM8741_ZFLAG_WIDTH 2 /* ZFLAG - [6:5] */ | ||
94 | #define WM8741_IZD 0x0010 /* IZD */ | ||
95 | #define WM8741_IZD_MASK 0x0010 /* IZD */ | ||
96 | #define WM8741_IZD_SHIFT 4 /* IZD */ | ||
97 | #define WM8741_IZD_WIDTH 1 /* IZD */ | ||
98 | #define WM8741_SOFT 0x0008 /* SOFT MUTE */ | ||
99 | #define WM8741_SOFT_MASK 0x0008 /* SOFT MUTE */ | ||
100 | #define WM8741_SOFT_SHIFT 3 /* SOFT MUTE */ | ||
101 | #define WM8741_SOFT_WIDTH 1 /* SOFT MUTE */ | ||
102 | #define WM8741_ATC 0x0004 /* ATC */ | ||
103 | #define WM8741_ATC_MASK 0x0004 /* ATC */ | ||
104 | #define WM8741_ATC_SHIFT 2 /* ATC */ | ||
105 | #define WM8741_ATC_WIDTH 1 /* ATC */ | ||
106 | #define WM8741_ATT2DB 0x0002 /* ATT2DB */ | ||
107 | #define WM8741_ATT2DB_MASK 0x0002 /* ATT2DB */ | ||
108 | #define WM8741_ATT2DB_SHIFT 1 /* ATT2DB */ | ||
109 | #define WM8741_ATT2DB_WIDTH 1 /* ATT2DB */ | ||
110 | #define WM8741_VOL_RAMP 0x0001 /* VOL_RAMP */ | ||
111 | #define WM8741_VOL_RAMP_MASK 0x0001 /* VOL_RAMP */ | ||
112 | #define WM8741_VOL_RAMP_SHIFT 0 /* VOL_RAMP */ | ||
113 | #define WM8741_VOL_RAMP_WIDTH 1 /* VOL_RAMP */ | ||
114 | |||
115 | /* | ||
116 | * R5 (0x05) - FORMAT_CONTROL | ||
117 | */ | ||
118 | #define WM8741_PWDN 0x0080 /* PWDN */ | ||
119 | #define WM8741_PWDN_MASK 0x0080 /* PWDN */ | ||
120 | #define WM8741_PWDN_SHIFT 7 /* PWDN */ | ||
121 | #define WM8741_PWDN_WIDTH 1 /* PWDN */ | ||
122 | #define WM8741_REV 0x0040 /* REV */ | ||
123 | #define WM8741_REV_MASK 0x0040 /* REV */ | ||
124 | #define WM8741_REV_SHIFT 6 /* REV */ | ||
125 | #define WM8741_REV_WIDTH 1 /* REV */ | ||
126 | #define WM8741_BCP 0x0020 /* BCP */ | ||
127 | #define WM8741_BCP_MASK 0x0020 /* BCP */ | ||
128 | #define WM8741_BCP_SHIFT 5 /* BCP */ | ||
129 | #define WM8741_BCP_WIDTH 1 /* BCP */ | ||
130 | #define WM8741_LRP 0x0010 /* LRP */ | ||
131 | #define WM8741_LRP_MASK 0x0010 /* LRP */ | ||
132 | #define WM8741_LRP_SHIFT 4 /* LRP */ | ||
133 | #define WM8741_LRP_WIDTH 1 /* LRP */ | ||
134 | #define WM8741_FMT_MASK 0x000C /* FMT - [3:2] */ | ||
135 | #define WM8741_FMT_SHIFT 2 /* FMT - [3:2] */ | ||
136 | #define WM8741_FMT_WIDTH 2 /* FMT - [3:2] */ | ||
137 | #define WM8741_IWL_MASK 0x0003 /* IWL - [1:0] */ | ||
138 | #define WM8741_IWL_SHIFT 0 /* IWL - [1:0] */ | ||
139 | #define WM8741_IWL_WIDTH 2 /* IWL - [1:0] */ | ||
140 | |||
141 | /* | ||
142 | * R6 (0x06) - FILTER_CONTROL | ||
143 | */ | ||
144 | #define WM8741_ZFLAG_HI 0x0080 /* ZFLAG_HI */ | ||
145 | #define WM8741_ZFLAG_HI_MASK 0x0080 /* ZFLAG_HI */ | ||
146 | #define WM8741_ZFLAG_HI_SHIFT 7 /* ZFLAG_HI */ | ||
147 | #define WM8741_ZFLAG_HI_WIDTH 1 /* ZFLAG_HI */ | ||
148 | #define WM8741_DEEMPH_MASK 0x0060 /* DEEMPH - [6:5] */ | ||
149 | #define WM8741_DEEMPH_SHIFT 5 /* DEEMPH - [6:5] */ | ||
150 | #define WM8741_DEEMPH_WIDTH 2 /* DEEMPH - [6:5] */ | ||
151 | #define WM8741_DSDFILT_MASK 0x0018 /* DSDFILT - [4:3] */ | ||
152 | #define WM8741_DSDFILT_SHIFT 3 /* DSDFILT - [4:3] */ | ||
153 | #define WM8741_DSDFILT_WIDTH 2 /* DSDFILT - [4:3] */ | ||
154 | #define WM8741_FIRSEL_MASK 0x0007 /* FIRSEL - [2:0] */ | ||
155 | #define WM8741_FIRSEL_SHIFT 0 /* FIRSEL - [2:0] */ | ||
156 | #define WM8741_FIRSEL_WIDTH 3 /* FIRSEL - [2:0] */ | ||
157 | |||
158 | /* | ||
159 | * R7 (0x07) - MODE_CONTROL_1 | ||
160 | */ | ||
161 | #define WM8741_MODE8X 0x0080 /* MODE8X */ | ||
162 | #define WM8741_MODE8X_MASK 0x0080 /* MODE8X */ | ||
163 | #define WM8741_MODE8X_SHIFT 7 /* MODE8X */ | ||
164 | #define WM8741_MODE8X_WIDTH 1 /* MODE8X */ | ||
165 | #define WM8741_OSR_MASK 0x0060 /* OSR - [6:5] */ | ||
166 | #define WM8741_OSR_SHIFT 5 /* OSR - [6:5] */ | ||
167 | #define WM8741_OSR_WIDTH 2 /* OSR - [6:5] */ | ||
168 | #define WM8741_SR_MASK 0x001C /* SR - [4:2] */ | ||
169 | #define WM8741_SR_SHIFT 2 /* SR - [4:2] */ | ||
170 | #define WM8741_SR_WIDTH 3 /* SR - [4:2] */ | ||
171 | #define WM8741_MODESEL_MASK 0x0003 /* MODESEL - [1:0] */ | ||
172 | #define WM8741_MODESEL_SHIFT 0 /* MODESEL - [1:0] */ | ||
173 | #define WM8741_MODESEL_WIDTH 2 /* MODESEL - [1:0] */ | ||
174 | |||
175 | /* | ||
176 | * R8 (0x08) - MODE_CONTROL_2 | ||
177 | */ | ||
178 | #define WM8741_DSD_GAIN 0x0040 /* DSD_GAIN */ | ||
179 | #define WM8741_DSD_GAIN_MASK 0x0040 /* DSD_GAIN */ | ||
180 | #define WM8741_DSD_GAIN_SHIFT 6 /* DSD_GAIN */ | ||
181 | #define WM8741_DSD_GAIN_WIDTH 1 /* DSD_GAIN */ | ||
182 | #define WM8741_SDOUT 0x0020 /* SDOUT */ | ||
183 | #define WM8741_SDOUT_MASK 0x0020 /* SDOUT */ | ||
184 | #define WM8741_SDOUT_SHIFT 5 /* SDOUT */ | ||
185 | #define WM8741_SDOUT_WIDTH 1 /* SDOUT */ | ||
186 | #define WM8741_DOUT 0x0010 /* DOUT */ | ||
187 | #define WM8741_DOUT_MASK 0x0010 /* DOUT */ | ||
188 | #define WM8741_DOUT_SHIFT 4 /* DOUT */ | ||
189 | #define WM8741_DOUT_WIDTH 1 /* DOUT */ | ||
190 | #define WM8741_DIFF_MASK 0x000C /* DIFF - [3:2] */ | ||
191 | #define WM8741_DIFF_SHIFT 2 /* DIFF - [3:2] */ | ||
192 | #define WM8741_DIFF_WIDTH 2 /* DIFF - [3:2] */ | ||
193 | #define WM8741_DITHER_MASK 0x0003 /* DITHER - [1:0] */ | ||
194 | #define WM8741_DITHER_SHIFT 0 /* DITHER - [1:0] */ | ||
195 | #define WM8741_DITHER_WIDTH 2 /* DITHER - [1:0] */ | ||
196 | |||
197 | /* | ||
198 | * R32 (0x20) - ADDITONAL_CONTROL_1 | ||
199 | */ | ||
200 | #define WM8741_DSD_LEVEL 0x0002 /* DSD_LEVEL */ | ||
201 | #define WM8741_DSD_LEVEL_MASK 0x0002 /* DSD_LEVEL */ | ||
202 | #define WM8741_DSD_LEVEL_SHIFT 1 /* DSD_LEVEL */ | ||
203 | #define WM8741_DSD_LEVEL_WIDTH 1 /* DSD_LEVEL */ | ||
204 | #define WM8741_DSD_NO_NOTCH 0x0001 /* DSD_NO_NOTCH */ | ||
205 | #define WM8741_DSD_NO_NOTCH_MASK 0x0001 /* DSD_NO_NOTCH */ | ||
206 | #define WM8741_DSD_NO_NOTCH_SHIFT 0 /* DSD_NO_NOTCH */ | ||
207 | #define WM8741_DSD_NO_NOTCH_WIDTH 1 /* DSD_NO_NOTCH */ | ||
208 | |||
209 | #define WM8741_SYSCLK 0 | ||
210 | |||
211 | extern struct snd_soc_dai wm8741_dai; | ||
212 | extern struct snd_soc_codec_device soc_codec_dev_wm8741; | ||
213 | |||
214 | #endif | ||
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 9407e193fcc3..e2c05e3e323a 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c | |||
@@ -884,6 +884,7 @@ static int wm8750_i2c_remove(struct i2c_client *client) | |||
884 | 884 | ||
885 | static const struct i2c_device_id wm8750_i2c_id[] = { | 885 | static const struct i2c_device_id wm8750_i2c_id[] = { |
886 | { "wm8750", 0 }, | 886 | { "wm8750", 0 }, |
887 | { "wm8987", 0 }, /* WM8987 is register compatible with WM8750 */ | ||
887 | { } | 888 | { } |
888 | }; | 889 | }; |
889 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); | 890 | MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); |
@@ -925,14 +926,22 @@ static int __devexit wm8750_spi_remove(struct spi_device *spi) | |||
925 | return 0; | 926 | return 0; |
926 | } | 927 | } |
927 | 928 | ||
929 | static const struct spi_device_id wm8750_spi_id[] = { | ||
930 | { "wm8750", 0 }, | ||
931 | { "wm8987", 0 }, | ||
932 | { } | ||
933 | }; | ||
934 | MODULE_DEVICE_TABLE(spi, wm8750_spi_id); | ||
935 | |||
928 | static struct spi_driver wm8750_spi_driver = { | 936 | static struct spi_driver wm8750_spi_driver = { |
929 | .driver = { | 937 | .driver = { |
930 | .name = "wm8750", | 938 | .name = "WM8750 SPI Codec", |
931 | .bus = &spi_bus_type, | 939 | .bus = &spi_bus_type, |
932 | .owner = THIS_MODULE, | 940 | .owner = THIS_MODULE, |
933 | }, | 941 | }, |
934 | .probe = wm8750_spi_probe, | 942 | .probe = wm8750_spi_probe, |
935 | .remove = __devexit_p(wm8750_spi_remove), | 943 | .remove = __devexit_p(wm8750_spi_remove), |
944 | .id_table = wm8750_spi_id, | ||
936 | }; | 945 | }; |
937 | #endif | 946 | #endif |
938 | 947 | ||
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 87f14f8675fa..f7dcabf6283c 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -2433,7 +2433,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2433 | 2433 | ||
2434 | if (wm8904_codec) { | 2434 | if (wm8904_codec) { |
2435 | dev_err(codec->dev, "Another WM8904 is registered\n"); | 2435 | dev_err(codec->dev, "Another WM8904 is registered\n"); |
2436 | return -EINVAL; | 2436 | ret = -EINVAL; |
2437 | goto err; | ||
2437 | } | 2438 | } |
2438 | 2439 | ||
2439 | mutex_init(&codec->mutex); | 2440 | mutex_init(&codec->mutex); |
@@ -2462,7 +2463,8 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2462 | default: | 2463 | default: |
2463 | dev_err(codec->dev, "Unknown device type %d\n", | 2464 | dev_err(codec->dev, "Unknown device type %d\n", |
2464 | wm8904->devtype); | 2465 | wm8904->devtype); |
2465 | return -EINVAL; | 2466 | ret = -EINVAL; |
2467 | goto err; | ||
2466 | } | 2468 | } |
2467 | 2469 | ||
2468 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); | 2470 | memcpy(codec->reg_cache, wm8904_reg, sizeof(wm8904_reg)); |
@@ -2566,18 +2568,19 @@ static int wm8904_register(struct wm8904_priv *wm8904, | |||
2566 | ret = snd_soc_register_codec(codec); | 2568 | ret = snd_soc_register_codec(codec); |
2567 | if (ret != 0) { | 2569 | if (ret != 0) { |
2568 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 2570 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
2569 | return ret; | 2571 | goto err_enable; |
2570 | } | 2572 | } |
2571 | 2573 | ||
2572 | ret = snd_soc_register_dai(&wm8904_dai); | 2574 | ret = snd_soc_register_dai(&wm8904_dai); |
2573 | if (ret != 0) { | 2575 | if (ret != 0) { |
2574 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 2576 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
2575 | snd_soc_unregister_codec(codec); | 2577 | goto err_codec; |
2576 | return ret; | ||
2577 | } | 2578 | } |
2578 | 2579 | ||
2579 | return 0; | 2580 | return 0; |
2580 | 2581 | ||
2582 | err_codec: | ||
2583 | snd_soc_unregister_codec(codec); | ||
2581 | err_enable: | 2584 | err_enable: |
2582 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | 2585 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); |
2583 | err_get: | 2586 | err_get: |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index e3c4bbfaae27..f0c11138e610 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -845,6 +845,7 @@ static void wm8940_unregister(struct wm8940_priv *wm8940) | |||
845 | static int wm8940_i2c_probe(struct i2c_client *i2c, | 845 | static int wm8940_i2c_probe(struct i2c_client *i2c, |
846 | const struct i2c_device_id *id) | 846 | const struct i2c_device_id *id) |
847 | { | 847 | { |
848 | int ret; | ||
848 | struct wm8940_priv *wm8940; | 849 | struct wm8940_priv *wm8940; |
849 | struct snd_soc_codec *codec; | 850 | struct snd_soc_codec *codec; |
850 | 851 | ||
@@ -858,7 +859,11 @@ static int wm8940_i2c_probe(struct i2c_client *i2c, | |||
858 | codec->control_data = i2c; | 859 | codec->control_data = i2c; |
859 | codec->dev = &i2c->dev; | 860 | codec->dev = &i2c->dev; |
860 | 861 | ||
861 | return wm8940_register(wm8940, SND_SOC_I2C); | 862 | ret = wm8940_register(wm8940, SND_SOC_I2C); |
863 | if (ret < 0) | ||
864 | kfree(wm8940); | ||
865 | |||
866 | return ret; | ||
862 | } | 867 | } |
863 | 868 | ||
864 | static int __devexit wm8940_i2c_remove(struct i2c_client *client) | 869 | static int __devexit wm8940_i2c_remove(struct i2c_client *client) |
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index fedb76452f1b..5f025593d84d 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c | |||
@@ -964,7 +964,8 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
964 | 964 | ||
965 | if (wm8955_codec) { | 965 | if (wm8955_codec) { |
966 | dev_err(codec->dev, "Another WM8955 is registered\n"); | 966 | dev_err(codec->dev, "Another WM8955 is registered\n"); |
967 | return -EINVAL; | 967 | ret = -EINVAL; |
968 | goto err; | ||
968 | } | 969 | } |
969 | 970 | ||
970 | mutex_init(&codec->mutex); | 971 | mutex_init(&codec->mutex); |
@@ -1047,18 +1048,19 @@ static int wm8955_register(struct wm8955_priv *wm8955, | |||
1047 | ret = snd_soc_register_codec(codec); | 1048 | ret = snd_soc_register_codec(codec); |
1048 | if (ret != 0) { | 1049 | if (ret != 0) { |
1049 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1050 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1050 | return ret; | 1051 | goto err_enable; |
1051 | } | 1052 | } |
1052 | 1053 | ||
1053 | ret = snd_soc_register_dai(&wm8955_dai); | 1054 | ret = snd_soc_register_dai(&wm8955_dai); |
1054 | if (ret != 0) { | 1055 | if (ret != 0) { |
1055 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1056 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1056 | snd_soc_unregister_codec(codec); | 1057 | goto err_codec; |
1057 | return ret; | ||
1058 | } | 1058 | } |
1059 | 1059 | ||
1060 | return 0; | 1060 | return 0; |
1061 | 1061 | ||
1062 | err_codec: | ||
1063 | snd_soc_unregister_codec(codec); | ||
1062 | err_enable: | 1064 | err_enable: |
1063 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); | 1065 | regulator_bulk_disable(ARRAY_SIZE(wm8955->supplies), wm8955->supplies); |
1064 | err_get: | 1066 | err_get: |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 7233cc68435a..3c6ee61f6c95 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -79,12 +79,13 @@ struct wm8960_priv { | |||
79 | struct snd_soc_dapm_widget *lout1; | 79 | struct snd_soc_dapm_widget *lout1; |
80 | struct snd_soc_dapm_widget *rout1; | 80 | struct snd_soc_dapm_widget *rout1; |
81 | struct snd_soc_dapm_widget *out3; | 81 | struct snd_soc_dapm_widget *out3; |
82 | bool deemph; | ||
83 | int playback_fs; | ||
82 | }; | 84 | }; |
83 | 85 | ||
84 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) | 86 | #define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) |
85 | 87 | ||
86 | /* enumerated controls */ | 88 | /* enumerated controls */ |
87 | static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | ||
88 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", | 89 | static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted", |
89 | "Right Inverted", "Stereo Inversion"}; | 90 | "Right Inverted", "Stereo Inversion"}; |
90 | static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; | 91 | static const char *wm8960_3d_upper_cutoff[] = {"High", "Low"}; |
@@ -93,7 +94,6 @@ static const char *wm8960_alcfunc[] = {"Off", "Right", "Left", "Stereo"}; | |||
93 | static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; | 94 | static const char *wm8960_alcmode[] = {"ALC", "Limiter"}; |
94 | 95 | ||
95 | static const struct soc_enum wm8960_enum[] = { | 96 | static const struct soc_enum wm8960_enum[] = { |
96 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 1, 4, wm8960_deemph), | ||
97 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), | 97 | SOC_ENUM_SINGLE(WM8960_DACCTL1, 5, 4, wm8960_polarity), |
98 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), | 98 | SOC_ENUM_SINGLE(WM8960_DACCTL2, 5, 4, wm8960_polarity), |
99 | SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), | 99 | SOC_ENUM_SINGLE(WM8960_3D, 6, 2, wm8960_3d_upper_cutoff), |
@@ -102,6 +102,59 @@ static const struct soc_enum wm8960_enum[] = { | |||
102 | SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), | 102 | SOC_ENUM_SINGLE(WM8960_ALC3, 8, 2, wm8960_alcmode), |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
106 | |||
107 | static int wm8960_set_deemph(struct snd_soc_codec *codec) | ||
108 | { | ||
109 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
110 | int val, i, best; | ||
111 | |||
112 | /* If we're using deemphasis select the nearest available sample | ||
113 | * rate. | ||
114 | */ | ||
115 | if (wm8960->deemph) { | ||
116 | best = 1; | ||
117 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
118 | if (abs(deemph_settings[i] - wm8960->playback_fs) < | ||
119 | abs(deemph_settings[best] - wm8960->playback_fs)) | ||
120 | best = i; | ||
121 | } | ||
122 | |||
123 | val = best << 1; | ||
124 | } else { | ||
125 | val = 0; | ||
126 | } | ||
127 | |||
128 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
129 | |||
130 | return snd_soc_update_bits(codec, WM8960_DACCTL1, | ||
131 | 0x6, val); | ||
132 | } | ||
133 | |||
134 | static int wm8960_get_deemph(struct snd_kcontrol *kcontrol, | ||
135 | struct snd_ctl_elem_value *ucontrol) | ||
136 | { | ||
137 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
138 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
139 | |||
140 | return wm8960->deemph; | ||
141 | } | ||
142 | |||
143 | static int wm8960_put_deemph(struct snd_kcontrol *kcontrol, | ||
144 | struct snd_ctl_elem_value *ucontrol) | ||
145 | { | ||
146 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
147 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
148 | int deemph = ucontrol->value.enumerated.item[0]; | ||
149 | |||
150 | if (deemph > 1) | ||
151 | return -EINVAL; | ||
152 | |||
153 | wm8960->deemph = deemph; | ||
154 | |||
155 | return wm8960_set_deemph(codec); | ||
156 | } | ||
157 | |||
105 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); | 158 | static const DECLARE_TLV_DB_SCALE(adc_tlv, -9700, 50, 0); |
106 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); | 159 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -12700, 50, 1); |
107 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); | 160 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -2100, 300, 0); |
@@ -131,23 +184,24 @@ SOC_SINGLE("Speaker DC Volume", WM8960_CLASSD3, 3, 5, 0), | |||
131 | SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), | 184 | SOC_SINGLE("Speaker AC Volume", WM8960_CLASSD3, 0, 5, 0), |
132 | 185 | ||
133 | SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), | 186 | SOC_SINGLE("PCM Playback -6dB Switch", WM8960_DACCTL1, 7, 1, 0), |
134 | SOC_ENUM("ADC Polarity", wm8960_enum[1]), | 187 | SOC_ENUM("ADC Polarity", wm8960_enum[0]), |
135 | SOC_ENUM("Playback De-emphasis", wm8960_enum[0]), | ||
136 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), | 188 | SOC_SINGLE("ADC High Pass Filter Switch", WM8960_DACCTL1, 0, 1, 0), |
137 | 189 | ||
138 | SOC_ENUM("DAC Polarity", wm8960_enum[2]), | 190 | SOC_ENUM("DAC Polarity", wm8960_enum[2]), |
191 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
192 | wm8960_get_deemph, wm8960_put_deemph), | ||
139 | 193 | ||
140 | SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[3]), | 194 | SOC_ENUM("3D Filter Upper Cut-Off", wm8960_enum[2]), |
141 | SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[4]), | 195 | SOC_ENUM("3D Filter Lower Cut-Off", wm8960_enum[3]), |
142 | SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), | 196 | SOC_SINGLE("3D Volume", WM8960_3D, 1, 15, 0), |
143 | SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), | 197 | SOC_SINGLE("3D Switch", WM8960_3D, 0, 1, 0), |
144 | 198 | ||
145 | SOC_ENUM("ALC Function", wm8960_enum[5]), | 199 | SOC_ENUM("ALC Function", wm8960_enum[4]), |
146 | SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), | 200 | SOC_SINGLE("ALC Max Gain", WM8960_ALC1, 4, 7, 0), |
147 | SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), | 201 | SOC_SINGLE("ALC Target", WM8960_ALC1, 0, 15, 1), |
148 | SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), | 202 | SOC_SINGLE("ALC Min Gain", WM8960_ALC2, 4, 7, 0), |
149 | SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), | 203 | SOC_SINGLE("ALC Hold Time", WM8960_ALC2, 0, 15, 0), |
150 | SOC_ENUM("ALC Mode", wm8960_enum[6]), | 204 | SOC_ENUM("ALC Mode", wm8960_enum[5]), |
151 | SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), | 205 | SOC_SINGLE("ALC Decay", WM8960_ALC3, 4, 15, 0), |
152 | SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), | 206 | SOC_SINGLE("ALC Attack", WM8960_ALC3, 0, 15, 0), |
153 | 207 | ||
@@ -433,6 +487,21 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
433 | return 0; | 487 | return 0; |
434 | } | 488 | } |
435 | 489 | ||
490 | static struct { | ||
491 | int rate; | ||
492 | unsigned int val; | ||
493 | } alc_rates[] = { | ||
494 | { 48000, 0 }, | ||
495 | { 44100, 0 }, | ||
496 | { 32000, 1 }, | ||
497 | { 22050, 2 }, | ||
498 | { 24000, 2 }, | ||
499 | { 16000, 3 }, | ||
500 | { 11250, 4 }, | ||
501 | { 12000, 4 }, | ||
502 | { 8000, 5 }, | ||
503 | }; | ||
504 | |||
436 | static int wm8960_hw_params(struct snd_pcm_substream *substream, | 505 | static int wm8960_hw_params(struct snd_pcm_substream *substream, |
437 | struct snd_pcm_hw_params *params, | 506 | struct snd_pcm_hw_params *params, |
438 | struct snd_soc_dai *dai) | 507 | struct snd_soc_dai *dai) |
@@ -440,7 +509,9 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
440 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 509 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
441 | struct snd_soc_device *socdev = rtd->socdev; | 510 | struct snd_soc_device *socdev = rtd->socdev; |
442 | struct snd_soc_codec *codec = socdev->card->codec; | 511 | struct snd_soc_codec *codec = socdev->card->codec; |
512 | struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); | ||
443 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; | 513 | u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; |
514 | int i; | ||
444 | 515 | ||
445 | /* bit size */ | 516 | /* bit size */ |
446 | switch (params_format(params)) { | 517 | switch (params_format(params)) { |
@@ -454,6 +525,18 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, | |||
454 | break; | 525 | break; |
455 | } | 526 | } |
456 | 527 | ||
528 | /* Update filters for the new rate */ | ||
529 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
530 | wm8960->playback_fs = params_rate(params); | ||
531 | wm8960_set_deemph(codec); | ||
532 | } else { | ||
533 | for (i = 0; i < ARRAY_SIZE(alc_rates); i++) | ||
534 | if (alc_rates[i].rate == params_rate(params)) | ||
535 | snd_soc_update_bits(codec, | ||
536 | WM8960_ADDCTL3, 0x7, | ||
537 | alc_rates[i].val); | ||
538 | } | ||
539 | |||
457 | /* set iface */ | 540 | /* set iface */ |
458 | snd_soc_write(codec, WM8960_IFACE1, iface); | 541 | snd_soc_write(codec, WM8960_IFACE1, iface); |
459 | return 0; | 542 | return 0; |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 5b9a756242f1..2549d3a297ab 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -1102,7 +1102,7 @@ static int wm8961_register(struct wm8961_priv *wm8961) | |||
1102 | ret = wm8961_reset(codec); | 1102 | ret = wm8961_reset(codec); |
1103 | if (ret < 0) { | 1103 | if (ret < 0) { |
1104 | dev_err(codec->dev, "Failed to issue reset\n"); | 1104 | dev_err(codec->dev, "Failed to issue reset\n"); |
1105 | return ret; | 1105 | goto err; |
1106 | } | 1106 | } |
1107 | 1107 | ||
1108 | /* Enable class W */ | 1108 | /* Enable class W */ |
@@ -1147,18 +1147,19 @@ static int wm8961_register(struct wm8961_priv *wm8961) | |||
1147 | ret = snd_soc_register_codec(codec); | 1147 | ret = snd_soc_register_codec(codec); |
1148 | if (ret != 0) { | 1148 | if (ret != 0) { |
1149 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1149 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1150 | return ret; | 1150 | goto err; |
1151 | } | 1151 | } |
1152 | 1152 | ||
1153 | ret = snd_soc_register_dai(&wm8961_dai); | 1153 | ret = snd_soc_register_dai(&wm8961_dai); |
1154 | if (ret != 0) { | 1154 | if (ret != 0) { |
1155 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1155 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1156 | snd_soc_unregister_codec(codec); | 1156 | goto err_codec; |
1157 | return ret; | ||
1158 | } | 1157 | } |
1159 | 1158 | ||
1160 | return 0; | 1159 | return 0; |
1161 | 1160 | ||
1161 | err_codec: | ||
1162 | snd_soc_unregister_codec(codec); | ||
1162 | err: | 1163 | err: |
1163 | kfree(wm8961); | 1164 | kfree(wm8961); |
1164 | return ret; | 1165 | return ret; |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index a2c4b2f37cca..1468fe10cbbe 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c | |||
@@ -670,7 +670,8 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974) | |||
670 | 670 | ||
671 | if (wm8974_codec) { | 671 | if (wm8974_codec) { |
672 | dev_err(codec->dev, "Another WM8974 is registered\n"); | 672 | dev_err(codec->dev, "Another WM8974 is registered\n"); |
673 | return -EINVAL; | 673 | ret = -EINVAL; |
674 | goto err; | ||
674 | } | 675 | } |
675 | 676 | ||
676 | mutex_init(&codec->mutex); | 677 | mutex_init(&codec->mutex); |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 51d5f433215c..8a1ad778e7e3 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -1076,7 +1076,6 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978) | |||
1076 | err_codec: | 1076 | err_codec: |
1077 | snd_soc_unregister_codec(codec); | 1077 | snd_soc_unregister_codec(codec); |
1078 | err: | 1078 | err: |
1079 | kfree(wm8978); | ||
1080 | return ret; | 1079 | return ret; |
1081 | } | 1080 | } |
1082 | 1081 | ||
@@ -1085,13 +1084,13 @@ static __devexit void wm8978_unregister(struct wm8978_priv *wm8978) | |||
1085 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); | 1084 | wm8978_set_bias_level(&wm8978->codec, SND_SOC_BIAS_OFF); |
1086 | snd_soc_unregister_dai(&wm8978_dai); | 1085 | snd_soc_unregister_dai(&wm8978_dai); |
1087 | snd_soc_unregister_codec(&wm8978->codec); | 1086 | snd_soc_unregister_codec(&wm8978->codec); |
1088 | kfree(wm8978); | ||
1089 | wm8978_codec = NULL; | 1087 | wm8978_codec = NULL; |
1090 | } | 1088 | } |
1091 | 1089 | ||
1092 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | 1090 | static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, |
1093 | const struct i2c_device_id *id) | 1091 | const struct i2c_device_id *id) |
1094 | { | 1092 | { |
1093 | int ret; | ||
1095 | struct wm8978_priv *wm8978; | 1094 | struct wm8978_priv *wm8978; |
1096 | struct snd_soc_codec *codec; | 1095 | struct snd_soc_codec *codec; |
1097 | 1096 | ||
@@ -1107,13 +1106,18 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c, | |||
1107 | 1106 | ||
1108 | codec->dev = &i2c->dev; | 1107 | codec->dev = &i2c->dev; |
1109 | 1108 | ||
1110 | return wm8978_register(wm8978); | 1109 | ret = wm8978_register(wm8978); |
1110 | if (ret < 0) | ||
1111 | kfree(wm8978); | ||
1112 | |||
1113 | return ret; | ||
1111 | } | 1114 | } |
1112 | 1115 | ||
1113 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) | 1116 | static __devexit int wm8978_i2c_remove(struct i2c_client *client) |
1114 | { | 1117 | { |
1115 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); | 1118 | struct wm8978_priv *wm8978 = i2c_get_clientdata(client); |
1116 | wm8978_unregister(wm8978); | 1119 | wm8978_unregister(wm8978); |
1120 | kfree(wm8978); | ||
1117 | return 0; | 1121 | return 0; |
1118 | } | 1122 | } |
1119 | 1123 | ||
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index c018772cc430..dd8d909788c1 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -30,8 +30,6 @@ | |||
30 | 30 | ||
31 | #include "wm8990.h" | 31 | #include "wm8990.h" |
32 | 32 | ||
33 | #define WM8990_VERSION "0.2" | ||
34 | |||
35 | /* codec private data */ | 33 | /* codec private data */ |
36 | struct wm8990_priv { | 34 | struct wm8990_priv { |
37 | unsigned int sysclk; | 35 | unsigned int sysclk; |
@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev) | |||
1511 | struct wm8990_priv *wm8990; | 1509 | struct wm8990_priv *wm8990; |
1512 | int ret; | 1510 | int ret; |
1513 | 1511 | ||
1514 | pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION); | ||
1515 | |||
1516 | setup = socdev->codec_data; | 1512 | setup = socdev->codec_data; |
1517 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | 1513 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); |
1518 | if (codec == NULL) | 1514 | if (codec == NULL) |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index e84a1177f350..522249d5c2b4 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -95,6 +95,7 @@ struct wm8994_priv { | |||
95 | 95 | ||
96 | struct wm8994_micdet micdet[2]; | 96 | struct wm8994_micdet micdet[2]; |
97 | 97 | ||
98 | int revision; | ||
98 | struct wm8994_pdata *pdata; | 99 | struct wm8994_pdata *pdata; |
99 | }; | 100 | }; |
100 | 101 | ||
@@ -1677,6 +1678,26 @@ static struct { | |||
1677 | 1678 | ||
1678 | static int wm8994_readable(unsigned int reg) | 1679 | static int wm8994_readable(unsigned int reg) |
1679 | { | 1680 | { |
1681 | switch (reg) { | ||
1682 | case WM8994_GPIO_1: | ||
1683 | case WM8994_GPIO_2: | ||
1684 | case WM8994_GPIO_3: | ||
1685 | case WM8994_GPIO_4: | ||
1686 | case WM8994_GPIO_5: | ||
1687 | case WM8994_GPIO_6: | ||
1688 | case WM8994_GPIO_7: | ||
1689 | case WM8994_GPIO_8: | ||
1690 | case WM8994_GPIO_9: | ||
1691 | case WM8994_GPIO_10: | ||
1692 | case WM8994_GPIO_11: | ||
1693 | case WM8994_INTERRUPT_STATUS_1: | ||
1694 | case WM8994_INTERRUPT_STATUS_2: | ||
1695 | case WM8994_INTERRUPT_RAW_STATUS_2: | ||
1696 | return 1; | ||
1697 | default: | ||
1698 | break; | ||
1699 | } | ||
1700 | |||
1680 | if (reg >= ARRAY_SIZE(access_masks)) | 1701 | if (reg >= ARRAY_SIZE(access_masks)) |
1681 | return 0; | 1702 | return 0; |
1682 | return access_masks[reg].readable != 0; | 1703 | return access_masks[reg].readable != 0; |
@@ -2341,6 +2362,20 @@ SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC1_RIGHT_MIXER_ROUTING, | |||
2341 | 0, 1, 0), | 2362 | 0, 1, 0), |
2342 | }; | 2363 | }; |
2343 | 2364 | ||
2365 | static const struct snd_kcontrol_new aif1adc2l_mix[] = { | ||
2366 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2367 | 1, 1, 0), | ||
2368 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_LEFT_MIXER_ROUTING, | ||
2369 | 0, 1, 0), | ||
2370 | }; | ||
2371 | |||
2372 | static const struct snd_kcontrol_new aif1adc2r_mix[] = { | ||
2373 | SOC_DAPM_SINGLE("DMIC Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2374 | 1, 1, 0), | ||
2375 | SOC_DAPM_SINGLE("AIF2 Switch", WM8994_AIF1_ADC2_RIGHT_MIXER_ROUTING, | ||
2376 | 0, 1, 0), | ||
2377 | }; | ||
2378 | |||
2344 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { | 2379 | static const struct snd_kcontrol_new aif2dac2l_mix[] = { |
2345 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, | 2380 | SOC_DAPM_SINGLE("Right Sidetone Switch", WM8994_DAC2_LEFT_MIXER_ROUTING, |
2346 | 5, 1, 0), | 2381 | 5, 1, 0), |
@@ -2472,6 +2507,7 @@ static const struct snd_kcontrol_new aif3adc_mux = | |||
2472 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { | 2507 | static const struct snd_soc_dapm_widget wm8994_dapm_widgets[] = { |
2473 | SND_SOC_DAPM_INPUT("DMIC1DAT"), | 2508 | SND_SOC_DAPM_INPUT("DMIC1DAT"), |
2474 | SND_SOC_DAPM_INPUT("DMIC2DAT"), | 2509 | SND_SOC_DAPM_INPUT("DMIC2DAT"), |
2510 | SND_SOC_DAPM_INPUT("Clock"), | ||
2475 | 2511 | ||
2476 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, | 2512 | SND_SOC_DAPM_SUPPLY("CLK_SYS", SND_SOC_NOPM, 0, 0, clk_sys_event, |
2477 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), | 2513 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), |
@@ -2506,6 +2542,11 @@ SND_SOC_DAPM_MIXER("AIF1ADC1L Mixer", SND_SOC_NOPM, 0, 0, | |||
2506 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, | 2542 | SND_SOC_DAPM_MIXER("AIF1ADC1R Mixer", SND_SOC_NOPM, 0, 0, |
2507 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), | 2543 | aif1adc1r_mix, ARRAY_SIZE(aif1adc1r_mix)), |
2508 | 2544 | ||
2545 | SND_SOC_DAPM_MIXER("AIF1ADC2L Mixer", SND_SOC_NOPM, 0, 0, | ||
2546 | aif1adc2l_mix, ARRAY_SIZE(aif1adc2l_mix)), | ||
2547 | SND_SOC_DAPM_MIXER("AIF1ADC2R Mixer", SND_SOC_NOPM, 0, 0, | ||
2548 | aif1adc2r_mix, ARRAY_SIZE(aif1adc2r_mix)), | ||
2549 | |||
2509 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, | 2550 | SND_SOC_DAPM_MIXER("AIF2DAC2L Mixer", SND_SOC_NOPM, 0, 0, |
2510 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), | 2551 | aif2dac2l_mix, ARRAY_SIZE(aif2dac2l_mix)), |
2511 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, | 2552 | SND_SOC_DAPM_MIXER("AIF2DAC2R Mixer", SND_SOC_NOPM, 0, 0, |
@@ -2668,6 +2709,14 @@ static const struct snd_soc_dapm_route intercon[] = { | |||
2668 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, | 2709 | { "AIF1ADC1R Mixer", "ADC/DMIC Switch", "ADCR Mux" }, |
2669 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, | 2710 | { "AIF1ADC1R Mixer", "AIF2 Switch", "AIF2DACR" }, |
2670 | 2711 | ||
2712 | { "AIF1ADC2L", NULL, "AIF1ADC2L Mixer" }, | ||
2713 | { "AIF1ADC2L Mixer", "DMIC Switch", "DMIC2L" }, | ||
2714 | { "AIF1ADC2L Mixer", "AIF2 Switch", "AIF2DACL" }, | ||
2715 | |||
2716 | { "AIF1ADC2R", NULL, "AIF1ADC2R Mixer" }, | ||
2717 | { "AIF1ADC2R Mixer", "DMIC Switch", "DMIC2R" }, | ||
2718 | { "AIF1ADC2R Mixer", "AIF2 Switch", "AIF2DACR" }, | ||
2719 | |||
2671 | /* Pin level routing for AIF3 */ | 2720 | /* Pin level routing for AIF3 */ |
2672 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, | 2721 | { "AIF1DAC1L", NULL, "AIF1DAC Mux" }, |
2673 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, | 2722 | { "AIF1DAC1R", NULL, "AIF1DAC Mux" }, |
@@ -2946,11 +2995,14 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src, | |||
2946 | return 0; | 2995 | return 0; |
2947 | } | 2996 | } |
2948 | 2997 | ||
2998 | static int opclk_divs[] = { 10, 20, 30, 40, 55, 60, 80, 120, 160 }; | ||
2999 | |||
2949 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | 3000 | static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, |
2950 | int clk_id, unsigned int freq, int dir) | 3001 | int clk_id, unsigned int freq, int dir) |
2951 | { | 3002 | { |
2952 | struct snd_soc_codec *codec = dai->codec; | 3003 | struct snd_soc_codec *codec = dai->codec; |
2953 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 3004 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
3005 | int i; | ||
2954 | 3006 | ||
2955 | switch (dai->id) { | 3007 | switch (dai->id) { |
2956 | case 1: | 3008 | case 1: |
@@ -2988,6 +3040,25 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | |||
2988 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); | 3040 | dev_dbg(dai->dev, "AIF%d using FLL2\n", dai->id); |
2989 | break; | 3041 | break; |
2990 | 3042 | ||
3043 | case WM8994_SYSCLK_OPCLK: | ||
3044 | /* Special case - a division (times 10) is given and | ||
3045 | * no effect on main clocking. | ||
3046 | */ | ||
3047 | if (freq) { | ||
3048 | for (i = 0; i < ARRAY_SIZE(opclk_divs); i++) | ||
3049 | if (opclk_divs[i] == freq) | ||
3050 | break; | ||
3051 | if (i == ARRAY_SIZE(opclk_divs)) | ||
3052 | return -EINVAL; | ||
3053 | snd_soc_update_bits(codec, WM8994_CLOCKING_2, | ||
3054 | WM8994_OPCLK_DIV_MASK, i); | ||
3055 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3056 | WM8994_OPCLK_ENA, WM8994_OPCLK_ENA); | ||
3057 | } else { | ||
3058 | snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_2, | ||
3059 | WM8994_OPCLK_ENA, 0); | ||
3060 | } | ||
3061 | |||
2991 | default: | 3062 | default: |
2992 | return -EINVAL; | 3063 | return -EINVAL; |
2993 | } | 3064 | } |
@@ -3000,6 +3071,8 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai, | |||
3000 | static int wm8994_set_bias_level(struct snd_soc_codec *codec, | 3071 | static int wm8994_set_bias_level(struct snd_soc_codec *codec, |
3001 | enum snd_soc_bias_level level) | 3072 | enum snd_soc_bias_level level) |
3002 | { | 3073 | { |
3074 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | ||
3075 | |||
3003 | switch (level) { | 3076 | switch (level) { |
3004 | case SND_SOC_BIAS_ON: | 3077 | case SND_SOC_BIAS_ON: |
3005 | break; | 3078 | break; |
@@ -3012,11 +3085,16 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
3012 | 3085 | ||
3013 | case SND_SOC_BIAS_STANDBY: | 3086 | case SND_SOC_BIAS_STANDBY: |
3014 | if (codec->bias_level == SND_SOC_BIAS_OFF) { | 3087 | if (codec->bias_level == SND_SOC_BIAS_OFF) { |
3015 | /* Tweak DC servo configuration for improved | 3088 | /* Tweak DC servo and DSP configuration for |
3016 | * performance. */ | 3089 | * improved performance. */ |
3017 | snd_soc_write(codec, 0x102, 0x3); | 3090 | if (wm8994->revision < 4) { |
3018 | snd_soc_write(codec, 0x56, 0x3); | 3091 | /* Tweak DC servo and DSP configuration for |
3019 | snd_soc_write(codec, 0x102, 0); | 3092 | * improved performance. */ |
3093 | snd_soc_write(codec, 0x102, 0x3); | ||
3094 | snd_soc_write(codec, 0x56, 0x3); | ||
3095 | snd_soc_write(codec, 0x817, 0); | ||
3096 | snd_soc_write(codec, 0x102, 0); | ||
3097 | } | ||
3020 | 3098 | ||
3021 | /* Discharge LINEOUT1 & 2 */ | 3099 | /* Discharge LINEOUT1 & 2 */ |
3022 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, | 3100 | snd_soc_update_bits(codec, WM8994_ANTIPOP_1, |
@@ -3849,7 +3927,6 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
3849 | struct wm8994_priv *wm8994; | 3927 | struct wm8994_priv *wm8994; |
3850 | struct snd_soc_codec *codec; | 3928 | struct snd_soc_codec *codec; |
3851 | int i; | 3929 | int i; |
3852 | u16 rev; | ||
3853 | 3930 | ||
3854 | if (wm8994_codec) { | 3931 | if (wm8994_codec) { |
3855 | dev_err(&pdev->dev, "Another WM8994 is registered\n"); | 3932 | dev_err(&pdev->dev, "Another WM8994 is registered\n"); |
@@ -3903,8 +3980,8 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
3903 | wm8994->reg_cache[i] = 0; | 3980 | wm8994->reg_cache[i] = 0; |
3904 | 3981 | ||
3905 | /* Set revision-specific configuration */ | 3982 | /* Set revision-specific configuration */ |
3906 | rev = snd_soc_read(codec, WM8994_CHIP_REVISION); | 3983 | wm8994->revision = snd_soc_read(codec, WM8994_CHIP_REVISION); |
3907 | switch (rev) { | 3984 | switch (wm8994->revision) { |
3908 | case 2: | 3985 | case 2: |
3909 | case 3: | 3986 | case 3: |
3910 | wm8994->hubs.dcs_codes = -5; | 3987 | wm8994->hubs.dcs_codes = -5; |
@@ -4004,6 +4081,11 @@ static int wm8994_codec_probe(struct platform_device *pdev) | |||
4004 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, | 4081 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT, |
4005 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); | 4082 | 1 << WM8994_AIF2DAC_3D_GAIN_SHIFT); |
4006 | 4083 | ||
4084 | /* Unconditionally enable AIF1 ADC TDM mode; it only affects | ||
4085 | * behaviour on idle TDM clock cycles. */ | ||
4086 | snd_soc_update_bits(codec, WM8994_AIF1_CONTROL_1, | ||
4087 | WM8994_AIF1ADC_TDM, WM8994_AIF1ADC_TDM); | ||
4088 | |||
4007 | wm8994_update_class_w(codec); | 4089 | wm8994_update_class_w(codec); |
4008 | 4090 | ||
4009 | ret = snd_soc_register_codec(codec); | 4091 | ret = snd_soc_register_codec(codec); |
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h index 7072dc539354..2e0ca67a8df7 100644 --- a/sound/soc/codecs/wm8994.h +++ b/sound/soc/codecs/wm8994.h | |||
@@ -20,6 +20,9 @@ extern struct snd_soc_dai wm8994_dai[]; | |||
20 | #define WM8994_SYSCLK_FLL1 3 | 20 | #define WM8994_SYSCLK_FLL1 3 |
21 | #define WM8994_SYSCLK_FLL2 4 | 21 | #define WM8994_SYSCLK_FLL2 4 |
22 | 22 | ||
23 | /* OPCLK is also configured with set_dai_sysclk, specify division*10 as rate. */ | ||
24 | #define WM8994_SYSCLK_OPCLK 5 | ||
25 | |||
23 | #define WM8994_FLL1 1 | 26 | #define WM8994_FLL1 1 |
24 | #define WM8994_FLL2 2 | 27 | #define WM8994_FLL2 2 |
25 | 28 | ||
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 13186fb4dcb4..76b37ff6c264 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -1356,7 +1356,7 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); | 1356 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); |
1357 | if (ret != 0) { | 1357 | if (ret != 0) { |
1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 1358 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
1359 | return ret; | 1359 | goto err; |
1360 | } | 1360 | } |
1361 | 1361 | ||
1362 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); | 1362 | reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); |
@@ -1369,7 +1369,7 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1369 | ret = wm9081_reset(codec); | 1369 | ret = wm9081_reset(codec); |
1370 | if (ret < 0) { | 1370 | if (ret < 0) { |
1371 | dev_err(codec->dev, "Failed to issue reset\n"); | 1371 | dev_err(codec->dev, "Failed to issue reset\n"); |
1372 | return ret; | 1372 | goto err; |
1373 | } | 1373 | } |
1374 | 1374 | ||
1375 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1375 | wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -1388,18 +1388,19 @@ static int wm9081_register(struct wm9081_priv *wm9081, | |||
1388 | ret = snd_soc_register_codec(codec); | 1388 | ret = snd_soc_register_codec(codec); |
1389 | if (ret != 0) { | 1389 | if (ret != 0) { |
1390 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | 1390 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); |
1391 | return ret; | 1391 | goto err; |
1392 | } | 1392 | } |
1393 | 1393 | ||
1394 | ret = snd_soc_register_dai(&wm9081_dai); | 1394 | ret = snd_soc_register_dai(&wm9081_dai); |
1395 | if (ret != 0) { | 1395 | if (ret != 0) { |
1396 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | 1396 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); |
1397 | snd_soc_unregister_codec(codec); | 1397 | goto err_codec; |
1398 | return ret; | ||
1399 | } | 1398 | } |
1400 | 1399 | ||
1401 | return 0; | 1400 | return 0; |
1402 | 1401 | ||
1402 | err_codec: | ||
1403 | snd_soc_unregister_codec(codec); | ||
1403 | err: | 1404 | err: |
1404 | kfree(wm9081); | 1405 | kfree(wm9081); |
1405 | return ret; | 1406 | return ret; |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 16f1a57da08a..2cb81538cd91 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -410,6 +410,8 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
410 | WM8993_HPOUT1L_DLY | | 410 | WM8993_HPOUT1L_DLY | |
411 | WM8993_HPOUT1R_DLY, 0); | 411 | WM8993_HPOUT1R_DLY, 0); |
412 | 412 | ||
413 | snd_soc_write(codec, WM8993_DC_SERVO_0, 0); | ||
414 | |||
413 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 415 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
414 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, | 416 | WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA, |
415 | 0); | 417 | 0); |