diff options
author | Takashi Iwai <tiwai@suse.de> | 2012-07-19 02:03:20 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2012-07-19 02:03:20 -0400 |
commit | 4609ed6b1f0ab9f11a9d0361573b53d9d057c440 (patch) | |
tree | 802119cc6ddea286bc03d56431286ac52166352e /sound | |
parent | 639aa4bd58582f3015ae5621b7e9e754dcb58e6b (diff) | |
parent | 409b78cc17a4a3d07a541037575da648ced99437 (diff) |
Merge tag 'asoc-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: Updates for 3.6
This has been a pretty quiet release - very little activity in framework
terms, mostly just a few new drivers and updates:
- Added the ability to add and remove DAPM paths dynamically, mostly for
reparenting on clock changes.
- New machine drivers for Marvell Brownstone, ST-Ericsson Ux500
reference platform and ttc-dkp.
- New CPU drivers for Blackfin BF6xx SPORTs in I2S mode, Marvell MMP,
Synopsis Designware I2S controllers, and SPEAr DMA and S/PDIF
- New CODEC drivers for Dialog DA732x, ST STA529, ST-Ericsson AB8500, TI
Isabelle and Wolfson Microelectronics WM5102 and WM5110
Diffstat (limited to 'sound')
113 files changed, 16392 insertions, 1339 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 40b2ad1bb1cd..c5de0a84566f 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -33,6 +33,7 @@ source "sound/soc/atmel/Kconfig" | |||
33 | source "sound/soc/au1x/Kconfig" | 33 | source "sound/soc/au1x/Kconfig" |
34 | source "sound/soc/blackfin/Kconfig" | 34 | source "sound/soc/blackfin/Kconfig" |
35 | source "sound/soc/davinci/Kconfig" | 35 | source "sound/soc/davinci/Kconfig" |
36 | source "sound/soc/dwc/Kconfig" | ||
36 | source "sound/soc/ep93xx/Kconfig" | 37 | source "sound/soc/ep93xx/Kconfig" |
37 | source "sound/soc/fsl/Kconfig" | 38 | source "sound/soc/fsl/Kconfig" |
38 | source "sound/soc/jz4740/Kconfig" | 39 | source "sound/soc/jz4740/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 70990f4017f4..00a555a743b6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_SND_SOC) += atmel/ | |||
11 | obj-$(CONFIG_SND_SOC) += au1x/ | 11 | obj-$(CONFIG_SND_SOC) += au1x/ |
12 | obj-$(CONFIG_SND_SOC) += blackfin/ | 12 | obj-$(CONFIG_SND_SOC) += blackfin/ |
13 | obj-$(CONFIG_SND_SOC) += davinci/ | 13 | obj-$(CONFIG_SND_SOC) += davinci/ |
14 | obj-$(CONFIG_SND_SOC) += dwc/ | ||
14 | obj-$(CONFIG_SND_SOC) += ep93xx/ | 15 | obj-$(CONFIG_SND_SOC) += ep93xx/ |
15 | obj-$(CONFIG_SND_SOC) += fsl/ | 16 | obj-$(CONFIG_SND_SOC) += fsl/ |
16 | obj-$(CONFIG_SND_SOC) += jz4740/ | 17 | obj-$(CONFIG_SND_SOC) += jz4740/ |
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 9f6bc55fc399..16b88f5c26e2 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -1,7 +1,8 @@ | |||
1 | config SND_BF5XX_I2S | 1 | config SND_BF5XX_I2S |
2 | tristate "SoC I2S Audio for the ADI BF5xx chip" | 2 | tristate "SoC I2S Audio for the ADI Blackfin chip" |
3 | depends on BLACKFIN | 3 | depends on BLACKFIN |
4 | select SND_BF5XX_SOC_SPORT | 4 | select SND_BF5XX_SOC_SPORT if !BF60x |
5 | select SND_BF6XX_SOC_SPORT if BF60x | ||
5 | help | 6 | help |
6 | Say Y or M if you want to add support for codecs attached to | 7 | Say Y or M if you want to add support for codecs attached to |
7 | the Blackfin SPORT (synchronous serial ports) interface in I2S | 8 | the Blackfin SPORT (synchronous serial ports) interface in I2S |
@@ -9,12 +10,14 @@ config SND_BF5XX_I2S | |||
9 | You will also need to select the audio interfaces to support below. | 10 | You will also need to select the audio interfaces to support below. |
10 | 11 | ||
11 | config SND_BF5XX_SOC_SSM2602 | 12 | config SND_BF5XX_SOC_SSM2602 |
12 | tristate "SoC SSM2602 Audio support for BF52x ezkit" | 13 | tristate "SoC SSM2602 Audio Codec Add-On Card support" |
13 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) | 14 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) |
14 | select SND_BF5XX_SOC_I2S | 15 | select SND_BF5XX_SOC_I2S if !BF60x |
16 | select SND_BF6XX_SOC_I2S if BF60x | ||
15 | select SND_SOC_SSM2602 | 17 | select SND_SOC_SSM2602 |
16 | help | 18 | help |
17 | Say Y if you want to add support for SoC audio on BF527-EZKIT. | 19 | Say Y if you want to add support for the Analog Devices |
20 | SSM2602 Audio Codec Add-On Card. | ||
18 | 21 | ||
19 | config SND_SOC_BFIN_EVAL_ADAU1701 | 22 | config SND_SOC_BFIN_EVAL_ADAU1701 |
20 | tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" | 23 | tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" |
@@ -162,9 +165,15 @@ config SND_BF5XX_SOC_AD1980 | |||
162 | config SND_BF5XX_SOC_SPORT | 165 | config SND_BF5XX_SOC_SPORT |
163 | tristate | 166 | tristate |
164 | 167 | ||
168 | config SND_BF6XX_SOC_SPORT | ||
169 | tristate | ||
170 | |||
165 | config SND_BF5XX_SOC_I2S | 171 | config SND_BF5XX_SOC_I2S |
166 | tristate | 172 | tristate |
167 | 173 | ||
174 | config SND_BF6XX_SOC_I2S | ||
175 | tristate | ||
176 | |||
168 | config SND_BF5XX_SOC_TDM | 177 | config SND_BF5XX_SOC_TDM |
169 | tristate | 178 | tristate |
170 | 179 | ||
@@ -173,7 +182,7 @@ config SND_BF5XX_SOC_AC97 | |||
173 | 182 | ||
174 | config SND_BF5XX_SPORT_NUM | 183 | config SND_BF5XX_SPORT_NUM |
175 | int "Set a SPORT for Sound chip" | 184 | int "Set a SPORT for Sound chip" |
176 | depends on (SND_BF5XX_I2S || SND_BF5XX_AC97 || SND_BF5XX_TDM) | 185 | depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT) |
177 | range 0 3 if BF54x | 186 | range 0 3 if BF54x |
178 | range 0 1 if !BF54x | 187 | range 0 1 if !BF54x |
179 | default 0 | 188 | default 0 |
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index 1bf86ccaa8de..6fea1f4cbee2 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile | |||
@@ -3,16 +3,20 @@ snd-bf5xx-ac97-objs := bf5xx-ac97-pcm.o | |||
3 | snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o | 3 | snd-bf5xx-i2s-objs := bf5xx-i2s-pcm.o |
4 | snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o | 4 | snd-bf5xx-tdm-objs := bf5xx-tdm-pcm.o |
5 | snd-soc-bf5xx-sport-objs := bf5xx-sport.o | 5 | snd-soc-bf5xx-sport-objs := bf5xx-sport.o |
6 | snd-soc-bf6xx-sport-objs := bf6xx-sport.o | ||
6 | snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o | 7 | snd-soc-bf5xx-ac97-objs := bf5xx-ac97.o |
7 | snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o | 8 | snd-soc-bf5xx-i2s-objs := bf5xx-i2s.o |
9 | snd-soc-bf6xx-i2s-objs := bf6xx-i2s.o | ||
8 | snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o | 10 | snd-soc-bf5xx-tdm-objs := bf5xx-tdm.o |
9 | 11 | ||
10 | obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o | 12 | obj-$(CONFIG_SND_BF5XX_AC97) += snd-bf5xx-ac97.o |
11 | obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o | 13 | obj-$(CONFIG_SND_BF5XX_I2S) += snd-bf5xx-i2s.o |
12 | obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o | 14 | obj-$(CONFIG_SND_BF5XX_TDM) += snd-bf5xx-tdm.o |
13 | obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o | 15 | obj-$(CONFIG_SND_BF5XX_SOC_SPORT) += snd-soc-bf5xx-sport.o |
16 | obj-$(CONFIG_SND_BF6XX_SOC_SPORT) += snd-soc-bf6xx-sport.o | ||
14 | obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o | 17 | obj-$(CONFIG_SND_BF5XX_SOC_AC97) += snd-soc-bf5xx-ac97.o |
15 | obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o | 18 | obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o |
19 | obj-$(CONFIG_SND_BF6XX_SOC_I2S) += snd-soc-bf6xx-i2s.o | ||
16 | obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o | 20 | obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o |
17 | 21 | ||
18 | # Blackfin Machine Support | 22 | # Blackfin Machine Support |
diff --git a/sound/soc/blackfin/bf6xx-i2s.c b/sound/soc/blackfin/bf6xx-i2s.c new file mode 100644 index 000000000000..c3c2466d3a42 --- /dev/null +++ b/sound/soc/blackfin/bf6xx-i2s.c | |||
@@ -0,0 +1,234 @@ | |||
1 | /* | ||
2 | * bf6xx-i2s.c - Analog Devices BF6XX i2s interface driver | ||
3 | * | ||
4 | * Copyright (c) 2012 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/device.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/soc-dai.h> | ||
28 | |||
29 | #include "bf6xx-sport.h" | ||
30 | |||
31 | struct sport_params param; | ||
32 | |||
33 | static int bfin_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
34 | unsigned int fmt) | ||
35 | { | ||
36 | struct sport_device *sport = snd_soc_dai_get_drvdata(cpu_dai); | ||
37 | struct device *dev = &sport->pdev->dev; | ||
38 | int ret = 0; | ||
39 | |||
40 | param.spctl &= ~(SPORT_CTL_OPMODE | SPORT_CTL_CKRE | SPORT_CTL_FSR | ||
41 | | SPORT_CTL_LFS | SPORT_CTL_LAFS); | ||
42 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
43 | case SND_SOC_DAIFMT_I2S: | ||
44 | param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_CKRE | ||
45 | | SPORT_CTL_LFS; | ||
46 | break; | ||
47 | case SND_SOC_DAIFMT_DSP_A: | ||
48 | param.spctl |= SPORT_CTL_FSR; | ||
49 | break; | ||
50 | case SND_SOC_DAIFMT_LEFT_J: | ||
51 | param.spctl |= SPORT_CTL_OPMODE | SPORT_CTL_LFS | ||
52 | | SPORT_CTL_LAFS; | ||
53 | break; | ||
54 | default: | ||
55 | dev_err(dev, "%s: Unknown DAI format type\n", __func__); | ||
56 | ret = -EINVAL; | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | param.spctl &= ~(SPORT_CTL_ICLK | SPORT_CTL_IFS); | ||
61 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
62 | case SND_SOC_DAIFMT_CBM_CFM: | ||
63 | break; | ||
64 | case SND_SOC_DAIFMT_CBS_CFS: | ||
65 | case SND_SOC_DAIFMT_CBM_CFS: | ||
66 | case SND_SOC_DAIFMT_CBS_CFM: | ||
67 | ret = -EINVAL; | ||
68 | break; | ||
69 | default: | ||
70 | dev_err(dev, "%s: Unknown DAI master type\n", __func__); | ||
71 | ret = -EINVAL; | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static int bfin_i2s_hw_params(struct snd_pcm_substream *substream, | ||
79 | struct snd_pcm_hw_params *params, | ||
80 | struct snd_soc_dai *dai) | ||
81 | { | ||
82 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | ||
83 | struct device *dev = &sport->pdev->dev; | ||
84 | int ret = 0; | ||
85 | |||
86 | param.spctl &= ~SPORT_CTL_SLEN; | ||
87 | switch (params_format(params)) { | ||
88 | case SNDRV_PCM_FORMAT_S8: | ||
89 | param.spctl |= 0x70; | ||
90 | sport->wdsize = 1; | ||
91 | case SNDRV_PCM_FORMAT_S16_LE: | ||
92 | param.spctl |= 0xf0; | ||
93 | sport->wdsize = 2; | ||
94 | break; | ||
95 | case SNDRV_PCM_FORMAT_S24_LE: | ||
96 | param.spctl |= 0x170; | ||
97 | sport->wdsize = 3; | ||
98 | break; | ||
99 | case SNDRV_PCM_FORMAT_S32_LE: | ||
100 | param.spctl |= 0x1f0; | ||
101 | sport->wdsize = 4; | ||
102 | break; | ||
103 | } | ||
104 | |||
105 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
106 | ret = sport_set_tx_params(sport, ¶m); | ||
107 | if (ret) { | ||
108 | dev_err(dev, "SPORT tx is busy!\n"); | ||
109 | return ret; | ||
110 | } | ||
111 | } else { | ||
112 | ret = sport_set_rx_params(sport, ¶m); | ||
113 | if (ret) { | ||
114 | dev_err(dev, "SPORT rx is busy!\n"); | ||
115 | return ret; | ||
116 | } | ||
117 | } | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | #ifdef CONFIG_PM | ||
122 | static int bfin_i2s_suspend(struct snd_soc_dai *dai) | ||
123 | { | ||
124 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | ||
125 | |||
126 | if (dai->capture_active) | ||
127 | sport_rx_stop(sport); | ||
128 | if (dai->playback_active) | ||
129 | sport_tx_stop(sport); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int bfin_i2s_resume(struct snd_soc_dai *dai) | ||
134 | { | ||
135 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | ||
136 | struct device *dev = &sport->pdev->dev; | ||
137 | int ret; | ||
138 | |||
139 | ret = sport_set_tx_params(sport, ¶m); | ||
140 | if (ret) { | ||
141 | dev_err(dev, "SPORT tx is busy!\n"); | ||
142 | return ret; | ||
143 | } | ||
144 | ret = sport_set_rx_params(sport, ¶m); | ||
145 | if (ret) { | ||
146 | dev_err(dev, "SPORT rx is busy!\n"); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | #else | ||
154 | #define bfin_i2s_suspend NULL | ||
155 | #define bfin_i2s_resume NULL | ||
156 | #endif | ||
157 | |||
158 | #define BFIN_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
159 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \ | ||
160 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ | ||
161 | SNDRV_PCM_RATE_96000) | ||
162 | |||
163 | #define BFIN_I2S_FORMATS (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
164 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
165 | |||
166 | static struct snd_soc_dai_ops bfin_i2s_dai_ops = { | ||
167 | .hw_params = bfin_i2s_hw_params, | ||
168 | .set_fmt = bfin_i2s_set_dai_fmt, | ||
169 | }; | ||
170 | |||
171 | static struct snd_soc_dai_driver bfin_i2s_dai = { | ||
172 | .suspend = bfin_i2s_suspend, | ||
173 | .resume = bfin_i2s_resume, | ||
174 | .playback = { | ||
175 | .channels_min = 1, | ||
176 | .channels_max = 2, | ||
177 | .rates = BFIN_I2S_RATES, | ||
178 | .formats = BFIN_I2S_FORMATS, | ||
179 | }, | ||
180 | .capture = { | ||
181 | .channels_min = 1, | ||
182 | .channels_max = 2, | ||
183 | .rates = BFIN_I2S_RATES, | ||
184 | .formats = BFIN_I2S_FORMATS, | ||
185 | }, | ||
186 | .ops = &bfin_i2s_dai_ops, | ||
187 | }; | ||
188 | |||
189 | static int __devinit bfin_i2s_probe(struct platform_device *pdev) | ||
190 | { | ||
191 | struct sport_device *sport; | ||
192 | struct device *dev = &pdev->dev; | ||
193 | int ret; | ||
194 | |||
195 | sport = sport_create(pdev); | ||
196 | if (!sport) | ||
197 | return -ENODEV; | ||
198 | |||
199 | /* register with the ASoC layers */ | ||
200 | ret = snd_soc_register_dai(dev, &bfin_i2s_dai); | ||
201 | if (ret) { | ||
202 | dev_err(dev, "Failed to register DAI: %d\n", ret); | ||
203 | sport_delete(sport); | ||
204 | return ret; | ||
205 | } | ||
206 | platform_set_drvdata(pdev, sport); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int __devexit bfin_i2s_remove(struct platform_device *pdev) | ||
212 | { | ||
213 | struct sport_device *sport = platform_get_drvdata(pdev); | ||
214 | |||
215 | snd_soc_unregister_dai(&pdev->dev); | ||
216 | sport_delete(sport); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static struct platform_driver bfin_i2s_driver = { | ||
222 | .probe = bfin_i2s_probe, | ||
223 | .remove = __devexit_p(bfin_i2s_remove), | ||
224 | .driver = { | ||
225 | .name = "bfin-i2s", | ||
226 | .owner = THIS_MODULE, | ||
227 | }, | ||
228 | }; | ||
229 | |||
230 | module_platform_driver(bfin_i2s_driver); | ||
231 | |||
232 | MODULE_DESCRIPTION("Analog Devices BF6XX i2s interface driver"); | ||
233 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
234 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/blackfin/bf6xx-sport.c b/sound/soc/blackfin/bf6xx-sport.c new file mode 100644 index 000000000000..318c5ba5360f --- /dev/null +++ b/sound/soc/blackfin/bf6xx-sport.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * bf6xx_sport.c Analog Devices BF6XX SPORT driver | ||
3 | * | ||
4 | * Copyright (c) 2012 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #include <linux/device.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | #include <asm/blackfin.h> | ||
28 | #include <asm/dma.h> | ||
29 | #include <asm/portmux.h> | ||
30 | |||
31 | #include "bf6xx-sport.h" | ||
32 | |||
33 | int sport_set_tx_params(struct sport_device *sport, | ||
34 | struct sport_params *params) | ||
35 | { | ||
36 | if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI) | ||
37 | return -EBUSY; | ||
38 | sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN; | ||
39 | sport->tx_regs->div = params->div; | ||
40 | SSYNC(); | ||
41 | return 0; | ||
42 | } | ||
43 | EXPORT_SYMBOL(sport_set_tx_params); | ||
44 | |||
45 | int sport_set_rx_params(struct sport_device *sport, | ||
46 | struct sport_params *params) | ||
47 | { | ||
48 | if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI) | ||
49 | return -EBUSY; | ||
50 | sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN; | ||
51 | sport->rx_regs->div = params->div; | ||
52 | SSYNC(); | ||
53 | return 0; | ||
54 | } | ||
55 | EXPORT_SYMBOL(sport_set_rx_params); | ||
56 | |||
57 | static int compute_wdsize(size_t wdsize) | ||
58 | { | ||
59 | switch (wdsize) { | ||
60 | case 1: | ||
61 | return WDSIZE_8 | PSIZE_8; | ||
62 | case 2: | ||
63 | return WDSIZE_16 | PSIZE_16; | ||
64 | default: | ||
65 | return WDSIZE_32 | PSIZE_32; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | void sport_tx_start(struct sport_device *sport) | ||
70 | { | ||
71 | set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc); | ||
72 | set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN | ||
73 | | compute_wdsize(sport->wdsize) | NDSIZE_6); | ||
74 | enable_dma(sport->tx_dma_chan); | ||
75 | sport->tx_regs->spctl |= SPORT_CTL_SPENPRI; | ||
76 | SSYNC(); | ||
77 | } | ||
78 | EXPORT_SYMBOL(sport_tx_start); | ||
79 | |||
80 | void sport_rx_start(struct sport_device *sport) | ||
81 | { | ||
82 | set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc); | ||
83 | set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR | ||
84 | | compute_wdsize(sport->wdsize) | NDSIZE_6); | ||
85 | enable_dma(sport->rx_dma_chan); | ||
86 | sport->rx_regs->spctl |= SPORT_CTL_SPENPRI; | ||
87 | SSYNC(); | ||
88 | } | ||
89 | EXPORT_SYMBOL(sport_rx_start); | ||
90 | |||
91 | void sport_tx_stop(struct sport_device *sport) | ||
92 | { | ||
93 | sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI; | ||
94 | SSYNC(); | ||
95 | disable_dma(sport->tx_dma_chan); | ||
96 | } | ||
97 | EXPORT_SYMBOL(sport_tx_stop); | ||
98 | |||
99 | void sport_rx_stop(struct sport_device *sport) | ||
100 | { | ||
101 | sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI; | ||
102 | SSYNC(); | ||
103 | disable_dma(sport->rx_dma_chan); | ||
104 | } | ||
105 | EXPORT_SYMBOL(sport_rx_stop); | ||
106 | |||
107 | void sport_set_tx_callback(struct sport_device *sport, | ||
108 | void (*tx_callback)(void *), void *tx_data) | ||
109 | { | ||
110 | sport->tx_callback = tx_callback; | ||
111 | sport->tx_data = tx_data; | ||
112 | } | ||
113 | EXPORT_SYMBOL(sport_set_tx_callback); | ||
114 | |||
115 | void sport_set_rx_callback(struct sport_device *sport, | ||
116 | void (*rx_callback)(void *), void *rx_data) | ||
117 | { | ||
118 | sport->rx_callback = rx_callback; | ||
119 | sport->rx_data = rx_data; | ||
120 | } | ||
121 | EXPORT_SYMBOL(sport_set_rx_callback); | ||
122 | |||
123 | static void setup_desc(struct dmasg *desc, void *buf, int fragcount, | ||
124 | size_t fragsize, unsigned int cfg, | ||
125 | unsigned int count, size_t wdsize) | ||
126 | { | ||
127 | |||
128 | int i; | ||
129 | |||
130 | for (i = 0; i < fragcount; ++i) { | ||
131 | desc[i].next_desc_addr = &(desc[i + 1]); | ||
132 | desc[i].start_addr = (unsigned long)buf + i*fragsize; | ||
133 | desc[i].cfg = cfg; | ||
134 | desc[i].x_count = count; | ||
135 | desc[i].x_modify = wdsize; | ||
136 | desc[i].y_count = 0; | ||
137 | desc[i].y_modify = 0; | ||
138 | } | ||
139 | |||
140 | /* make circular */ | ||
141 | desc[fragcount-1].next_desc_addr = desc; | ||
142 | } | ||
143 | |||
144 | int sport_config_tx_dma(struct sport_device *sport, void *buf, | ||
145 | int fragcount, size_t fragsize) | ||
146 | { | ||
147 | unsigned int count; | ||
148 | unsigned int cfg; | ||
149 | dma_addr_t addr; | ||
150 | |||
151 | count = fragsize/sport->wdsize; | ||
152 | |||
153 | if (sport->tx_desc) | ||
154 | dma_free_coherent(NULL, sport->tx_desc_size, | ||
155 | sport->tx_desc, 0); | ||
156 | |||
157 | sport->tx_desc = dma_alloc_coherent(NULL, | ||
158 | fragcount * sizeof(struct dmasg), &addr, 0); | ||
159 | sport->tx_desc_size = fragcount * sizeof(struct dmasg); | ||
160 | if (!sport->tx_desc) | ||
161 | return -ENOMEM; | ||
162 | |||
163 | sport->tx_buf = buf; | ||
164 | sport->tx_fragsize = fragsize; | ||
165 | sport->tx_frags = fragcount; | ||
166 | cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6; | ||
167 | |||
168 | setup_desc(sport->tx_desc, buf, fragcount, fragsize, | ||
169 | cfg|DMAEN, count, sport->wdsize); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | EXPORT_SYMBOL(sport_config_tx_dma); | ||
174 | |||
175 | int sport_config_rx_dma(struct sport_device *sport, void *buf, | ||
176 | int fragcount, size_t fragsize) | ||
177 | { | ||
178 | unsigned int count; | ||
179 | unsigned int cfg; | ||
180 | dma_addr_t addr; | ||
181 | |||
182 | count = fragsize/sport->wdsize; | ||
183 | |||
184 | if (sport->rx_desc) | ||
185 | dma_free_coherent(NULL, sport->rx_desc_size, | ||
186 | sport->rx_desc, 0); | ||
187 | |||
188 | sport->rx_desc = dma_alloc_coherent(NULL, | ||
189 | fragcount * sizeof(struct dmasg), &addr, 0); | ||
190 | sport->rx_desc_size = fragcount * sizeof(struct dmasg); | ||
191 | if (!sport->rx_desc) | ||
192 | return -ENOMEM; | ||
193 | |||
194 | sport->rx_buf = buf; | ||
195 | sport->rx_fragsize = fragsize; | ||
196 | sport->rx_frags = fragcount; | ||
197 | cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | ||
198 | | WNR | NDSIZE_6; | ||
199 | |||
200 | setup_desc(sport->rx_desc, buf, fragcount, fragsize, | ||
201 | cfg|DMAEN, count, sport->wdsize); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | EXPORT_SYMBOL(sport_config_rx_dma); | ||
206 | |||
207 | unsigned long sport_curr_offset_tx(struct sport_device *sport) | ||
208 | { | ||
209 | unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan); | ||
210 | |||
211 | return (unsigned char *)curr - sport->tx_buf; | ||
212 | } | ||
213 | EXPORT_SYMBOL(sport_curr_offset_tx); | ||
214 | |||
215 | unsigned long sport_curr_offset_rx(struct sport_device *sport) | ||
216 | { | ||
217 | unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan); | ||
218 | |||
219 | return (unsigned char *)curr - sport->rx_buf; | ||
220 | } | ||
221 | EXPORT_SYMBOL(sport_curr_offset_rx); | ||
222 | |||
223 | static irqreturn_t sport_tx_irq(int irq, void *dev_id) | ||
224 | { | ||
225 | struct sport_device *sport = dev_id; | ||
226 | static unsigned long status; | ||
227 | |||
228 | status = get_dma_curr_irqstat(sport->tx_dma_chan); | ||
229 | if (status & (DMA_DONE|DMA_ERR)) { | ||
230 | clear_dma_irqstat(sport->tx_dma_chan); | ||
231 | SSYNC(); | ||
232 | } | ||
233 | if (sport->tx_callback) | ||
234 | sport->tx_callback(sport->tx_data); | ||
235 | return IRQ_HANDLED; | ||
236 | } | ||
237 | |||
238 | static irqreturn_t sport_rx_irq(int irq, void *dev_id) | ||
239 | { | ||
240 | struct sport_device *sport = dev_id; | ||
241 | unsigned long status; | ||
242 | |||
243 | status = get_dma_curr_irqstat(sport->rx_dma_chan); | ||
244 | if (status & (DMA_DONE|DMA_ERR)) { | ||
245 | clear_dma_irqstat(sport->rx_dma_chan); | ||
246 | SSYNC(); | ||
247 | } | ||
248 | if (sport->rx_callback) | ||
249 | sport->rx_callback(sport->rx_data); | ||
250 | return IRQ_HANDLED; | ||
251 | } | ||
252 | |||
253 | static irqreturn_t sport_err_irq(int irq, void *dev_id) | ||
254 | { | ||
255 | struct sport_device *sport = dev_id; | ||
256 | struct device *dev = &sport->pdev->dev; | ||
257 | |||
258 | if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI) | ||
259 | dev_err(dev, "sport error: TUVF\n"); | ||
260 | if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI) | ||
261 | dev_err(dev, "sport error: ROVF\n"); | ||
262 | |||
263 | return IRQ_HANDLED; | ||
264 | } | ||
265 | |||
266 | static int sport_get_resource(struct sport_device *sport) | ||
267 | { | ||
268 | struct platform_device *pdev = sport->pdev; | ||
269 | struct device *dev = &pdev->dev; | ||
270 | struct bfin_snd_platform_data *pdata = dev->platform_data; | ||
271 | struct resource *res; | ||
272 | |||
273 | if (!pdata) { | ||
274 | dev_err(dev, "No platform data\n"); | ||
275 | return -ENODEV; | ||
276 | } | ||
277 | sport->pin_req = pdata->pin_req; | ||
278 | |||
279 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
280 | if (!res) { | ||
281 | dev_err(dev, "No tx MEM resource\n"); | ||
282 | return -ENODEV; | ||
283 | } | ||
284 | sport->tx_regs = (struct sport_register *)res->start; | ||
285 | |||
286 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
287 | if (!res) { | ||
288 | dev_err(dev, "No rx MEM resource\n"); | ||
289 | return -ENODEV; | ||
290 | } | ||
291 | sport->rx_regs = (struct sport_register *)res->start; | ||
292 | |||
293 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
294 | if (!res) { | ||
295 | dev_err(dev, "No tx DMA resource\n"); | ||
296 | return -ENODEV; | ||
297 | } | ||
298 | sport->tx_dma_chan = res->start; | ||
299 | |||
300 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
301 | if (!res) { | ||
302 | dev_err(dev, "No rx DMA resource\n"); | ||
303 | return -ENODEV; | ||
304 | } | ||
305 | sport->rx_dma_chan = res->start; | ||
306 | |||
307 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | ||
308 | if (!res) { | ||
309 | dev_err(dev, "No tx error irq resource\n"); | ||
310 | return -ENODEV; | ||
311 | } | ||
312 | sport->tx_err_irq = res->start; | ||
313 | |||
314 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); | ||
315 | if (!res) { | ||
316 | dev_err(dev, "No rx error irq resource\n"); | ||
317 | return -ENODEV; | ||
318 | } | ||
319 | sport->rx_err_irq = res->start; | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int sport_request_resource(struct sport_device *sport) | ||
325 | { | ||
326 | struct device *dev = &sport->pdev->dev; | ||
327 | int ret; | ||
328 | |||
329 | ret = peripheral_request_list(sport->pin_req, "soc-audio"); | ||
330 | if (ret) { | ||
331 | dev_err(dev, "Unable to request sport pin\n"); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | ret = request_dma(sport->tx_dma_chan, "SPORT TX Data"); | ||
336 | if (ret) { | ||
337 | dev_err(dev, "Unable to allocate DMA channel for sport tx\n"); | ||
338 | goto err_tx_dma; | ||
339 | } | ||
340 | set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport); | ||
341 | |||
342 | ret = request_dma(sport->rx_dma_chan, "SPORT RX Data"); | ||
343 | if (ret) { | ||
344 | dev_err(dev, "Unable to allocate DMA channel for sport rx\n"); | ||
345 | goto err_rx_dma; | ||
346 | } | ||
347 | set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport); | ||
348 | |||
349 | ret = request_irq(sport->tx_err_irq, sport_err_irq, | ||
350 | 0, "SPORT TX ERROR", sport); | ||
351 | if (ret) { | ||
352 | dev_err(dev, "Unable to allocate tx error IRQ for sport\n"); | ||
353 | goto err_tx_irq; | ||
354 | } | ||
355 | |||
356 | ret = request_irq(sport->rx_err_irq, sport_err_irq, | ||
357 | 0, "SPORT RX ERROR", sport); | ||
358 | if (ret) { | ||
359 | dev_err(dev, "Unable to allocate rx error IRQ for sport\n"); | ||
360 | goto err_rx_irq; | ||
361 | } | ||
362 | |||
363 | return 0; | ||
364 | err_rx_irq: | ||
365 | free_irq(sport->tx_err_irq, sport); | ||
366 | err_tx_irq: | ||
367 | free_dma(sport->rx_dma_chan); | ||
368 | err_rx_dma: | ||
369 | free_dma(sport->tx_dma_chan); | ||
370 | err_tx_dma: | ||
371 | peripheral_free_list(sport->pin_req); | ||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static void sport_free_resource(struct sport_device *sport) | ||
376 | { | ||
377 | free_irq(sport->rx_err_irq, sport); | ||
378 | free_irq(sport->tx_err_irq, sport); | ||
379 | free_dma(sport->rx_dma_chan); | ||
380 | free_dma(sport->tx_dma_chan); | ||
381 | peripheral_free_list(sport->pin_req); | ||
382 | } | ||
383 | |||
384 | struct sport_device *sport_create(struct platform_device *pdev) | ||
385 | { | ||
386 | struct device *dev = &pdev->dev; | ||
387 | struct sport_device *sport; | ||
388 | int ret; | ||
389 | |||
390 | sport = kzalloc(sizeof(*sport), GFP_KERNEL); | ||
391 | if (!sport) { | ||
392 | dev_err(dev, "Unable to allocate memory for sport device\n"); | ||
393 | return NULL; | ||
394 | } | ||
395 | sport->pdev = pdev; | ||
396 | |||
397 | ret = sport_get_resource(sport); | ||
398 | if (ret) { | ||
399 | kfree(sport); | ||
400 | return NULL; | ||
401 | } | ||
402 | |||
403 | ret = sport_request_resource(sport); | ||
404 | if (ret) { | ||
405 | kfree(sport); | ||
406 | return NULL; | ||
407 | } | ||
408 | |||
409 | dev_dbg(dev, "SPORT create success\n"); | ||
410 | return sport; | ||
411 | } | ||
412 | EXPORT_SYMBOL(sport_create); | ||
413 | |||
414 | void sport_delete(struct sport_device *sport) | ||
415 | { | ||
416 | sport_free_resource(sport); | ||
417 | } | ||
418 | EXPORT_SYMBOL(sport_delete); | ||
419 | |||
420 | MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver"); | ||
421 | MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); | ||
422 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/blackfin/bf6xx-sport.h b/sound/soc/blackfin/bf6xx-sport.h new file mode 100644 index 000000000000..307d193cfcef --- /dev/null +++ b/sound/soc/blackfin/bf6xx-sport.h | |||
@@ -0,0 +1,82 @@ | |||
1 | /* | ||
2 | * bf6xx_sport - Analog Devices BF6XX SPORT driver | ||
3 | * | ||
4 | * Copyright (c) 2012 Analog Devices Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _BF6XX_SPORT_H_ | ||
21 | #define _BF6XX_SPORT_H_ | ||
22 | |||
23 | #include <linux/platform_device.h> | ||
24 | #include <asm/bfin_sport3.h> | ||
25 | |||
26 | struct sport_device { | ||
27 | struct platform_device *pdev; | ||
28 | const unsigned short *pin_req; | ||
29 | struct sport_register *tx_regs; | ||
30 | struct sport_register *rx_regs; | ||
31 | int tx_dma_chan; | ||
32 | int rx_dma_chan; | ||
33 | int tx_err_irq; | ||
34 | int rx_err_irq; | ||
35 | |||
36 | void (*tx_callback)(void *data); | ||
37 | void *tx_data; | ||
38 | void (*rx_callback)(void *data); | ||
39 | void *rx_data; | ||
40 | |||
41 | struct dmasg *tx_desc; | ||
42 | struct dmasg *rx_desc; | ||
43 | unsigned int tx_desc_size; | ||
44 | unsigned int rx_desc_size; | ||
45 | unsigned char *tx_buf; | ||
46 | unsigned char *rx_buf; | ||
47 | unsigned int tx_fragsize; | ||
48 | unsigned int rx_fragsize; | ||
49 | unsigned int tx_frags; | ||
50 | unsigned int rx_frags; | ||
51 | unsigned int wdsize; | ||
52 | }; | ||
53 | |||
54 | struct sport_params { | ||
55 | u32 spctl; | ||
56 | u32 div; | ||
57 | }; | ||
58 | |||
59 | struct sport_device *sport_create(struct platform_device *pdev); | ||
60 | void sport_delete(struct sport_device *sport); | ||
61 | int sport_set_tx_params(struct sport_device *sport, | ||
62 | struct sport_params *params); | ||
63 | int sport_set_rx_params(struct sport_device *sport, | ||
64 | struct sport_params *params); | ||
65 | void sport_tx_start(struct sport_device *sport); | ||
66 | void sport_rx_start(struct sport_device *sport); | ||
67 | void sport_tx_stop(struct sport_device *sport); | ||
68 | void sport_rx_stop(struct sport_device *sport); | ||
69 | void sport_set_tx_callback(struct sport_device *sport, | ||
70 | void (*tx_callback)(void *), void *tx_data); | ||
71 | void sport_set_rx_callback(struct sport_device *sport, | ||
72 | void (*rx_callback)(void *), void *rx_data); | ||
73 | int sport_config_tx_dma(struct sport_device *sport, void *buf, | ||
74 | int fragcount, size_t fragsize); | ||
75 | int sport_config_rx_dma(struct sport_device *sport, void *buf, | ||
76 | int fragcount, size_t fragsize); | ||
77 | unsigned long sport_curr_offset_tx(struct sport_device *sport); | ||
78 | unsigned long sport_curr_offset_rx(struct sport_device *sport); | ||
79 | |||
80 | |||
81 | |||
82 | #endif | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 1e1613a438dd..9f8e8594aeb9 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -12,6 +12,7 @@ config SND_SOC_ALL_CODECS | |||
12 | tristate "Build all ASoC CODEC drivers" | 12 | tristate "Build all ASoC CODEC drivers" |
13 | select SND_SOC_88PM860X if MFD_88PM860X | 13 | select SND_SOC_88PM860X if MFD_88PM860X |
14 | select SND_SOC_L3 | 14 | select SND_SOC_L3 |
15 | select SND_SOC_AB8500_CODEC if ABX500_CORE | ||
15 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 16 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS |
16 | select SND_SOC_AD1836 if SPI_MASTER | 17 | select SND_SOC_AD1836 if SPI_MASTER |
17 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI | 18 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI |
@@ -35,7 +36,9 @@ config SND_SOC_ALL_CODECS | |||
35 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI | 36 | select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI |
36 | select SND_SOC_CX20442 | 37 | select SND_SOC_CX20442 |
37 | select SND_SOC_DA7210 if I2C | 38 | select SND_SOC_DA7210 if I2C |
39 | select SND_SOC_DA732X if I2C | ||
38 | select SND_SOC_DFBMCS320 | 40 | select SND_SOC_DFBMCS320 |
41 | select SND_SOC_ISABELLE if I2C | ||
39 | select SND_SOC_JZ4740_CODEC | 42 | select SND_SOC_JZ4740_CODEC |
40 | select SND_SOC_LM4857 if I2C | 43 | select SND_SOC_LM4857 if I2C |
41 | select SND_SOC_LM49453 if I2C | 44 | select SND_SOC_LM49453 if I2C |
@@ -54,6 +57,7 @@ config SND_SOC_ALL_CODECS | |||
54 | select SND_SOC_SPDIF | 57 | select SND_SOC_SPDIF |
55 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI | 58 | select SND_SOC_SSM2602 if SND_SOC_I2C_AND_SPI |
56 | select SND_SOC_STA32X if I2C | 59 | select SND_SOC_STA32X if I2C |
60 | select SND_SOC_STA529 if I2C | ||
57 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 61 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
58 | select SND_SOC_TLV320AIC23 if I2C | 62 | select SND_SOC_TLV320AIC23 if I2C |
59 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 63 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
@@ -70,6 +74,8 @@ config SND_SOC_ALL_CODECS | |||
70 | select SND_SOC_WM2000 if I2C | 74 | select SND_SOC_WM2000 if I2C |
71 | select SND_SOC_WM2200 if I2C | 75 | select SND_SOC_WM2200 if I2C |
72 | select SND_SOC_WM5100 if I2C | 76 | select SND_SOC_WM5100 if I2C |
77 | select SND_SOC_WM5102 if MFD_WM5102 | ||
78 | select SND_SOC_WM5110 if MFD_WM5110 | ||
73 | select SND_SOC_WM8350 if MFD_WM8350 | 79 | select SND_SOC_WM8350 if MFD_WM8350 |
74 | select SND_SOC_WM8400 if MFD_WM8400 | 80 | select SND_SOC_WM8400 if MFD_WM8400 |
75 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI | 81 | select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI |
@@ -126,11 +132,21 @@ config SND_SOC_ALL_CODECS | |||
126 | config SND_SOC_88PM860X | 132 | config SND_SOC_88PM860X |
127 | tristate | 133 | tristate |
128 | 134 | ||
135 | config SND_SOC_ARIZONA | ||
136 | tristate | ||
137 | default y if SND_SOC_WM5102=y | ||
138 | default y if SND_SOC_WM5110=y | ||
139 | default m if SND_SOC_WM5102=m | ||
140 | default m if SND_SOC_WM5110=m | ||
141 | |||
129 | config SND_SOC_WM_HUBS | 142 | config SND_SOC_WM_HUBS |
130 | tristate | 143 | tristate |
131 | default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y | 144 | default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y |
132 | default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m | 145 | default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m |
133 | 146 | ||
147 | config SND_SOC_AB8500_CODEC | ||
148 | tristate | ||
149 | |||
134 | config SND_SOC_AC97_CODEC | 150 | config SND_SOC_AC97_CODEC |
135 | tristate | 151 | tristate |
136 | select SND_AC97_CODEC | 152 | select SND_AC97_CODEC |
@@ -219,12 +235,18 @@ config SND_SOC_L3 | |||
219 | config SND_SOC_DA7210 | 235 | config SND_SOC_DA7210 |
220 | tristate | 236 | tristate |
221 | 237 | ||
238 | config SND_SOC_DA732X | ||
239 | tristate | ||
240 | |||
222 | config SND_SOC_DFBMCS320 | 241 | config SND_SOC_DFBMCS320 |
223 | tristate | 242 | tristate |
224 | 243 | ||
225 | config SND_SOC_DMIC | 244 | config SND_SOC_DMIC |
226 | tristate | 245 | tristate |
227 | 246 | ||
247 | config SND_SOC_ISABELLE | ||
248 | tristate | ||
249 | |||
228 | config SND_SOC_LM49453 | 250 | config SND_SOC_LM49453 |
229 | tristate | 251 | tristate |
230 | 252 | ||
@@ -266,6 +288,9 @@ config SND_SOC_SSM2602 | |||
266 | config SND_SOC_STA32X | 288 | config SND_SOC_STA32X |
267 | tristate | 289 | tristate |
268 | 290 | ||
291 | config SND_SOC_STA529 | ||
292 | tristate | ||
293 | |||
269 | config SND_SOC_STAC9766 | 294 | config SND_SOC_STAC9766 |
270 | tristate | 295 | tristate |
271 | 296 | ||
@@ -313,6 +338,12 @@ config SND_SOC_WM2200 | |||
313 | config SND_SOC_WM5100 | 338 | config SND_SOC_WM5100 |
314 | tristate | 339 | tristate |
315 | 340 | ||
341 | config SND_SOC_WM5102 | ||
342 | tristate | ||
343 | |||
344 | config SND_SOC_WM5110 | ||
345 | tristate | ||
346 | |||
316 | config SND_SOC_WM8350 | 347 | config SND_SOC_WM8350 |
317 | tristate | 348 | tristate |
318 | 349 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fc27fec39487..34148bb59c68 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | snd-soc-88pm860x-objs := 88pm860x-codec.o | 1 | snd-soc-88pm860x-objs := 88pm860x-codec.o |
2 | snd-soc-ab8500-codec-objs := ab8500-codec.o | ||
2 | snd-soc-ac97-objs := ac97.o | 3 | snd-soc-ac97-objs := ac97.o |
3 | snd-soc-ad1836-objs := ad1836.o | 4 | snd-soc-ad1836-objs := ad1836.o |
4 | snd-soc-ad193x-objs := ad193x.o | 5 | snd-soc-ad193x-objs := ad193x.o |
@@ -13,6 +14,7 @@ snd-soc-ak4535-objs := ak4535.o | |||
13 | snd-soc-ak4641-objs := ak4641.o | 14 | snd-soc-ak4641-objs := ak4641.o |
14 | snd-soc-ak4642-objs := ak4642.o | 15 | snd-soc-ak4642-objs := ak4642.o |
15 | snd-soc-ak4671-objs := ak4671.o | 16 | snd-soc-ak4671-objs := ak4671.o |
17 | snd-soc-arizona-objs := arizona.o | ||
16 | snd-soc-cq93vc-objs := cq93vc.o | 18 | snd-soc-cq93vc-objs := cq93vc.o |
17 | snd-soc-cs42l51-objs := cs42l51.o | 19 | snd-soc-cs42l51-objs := cs42l51.o |
18 | snd-soc-cs42l52-objs := cs42l52.o | 20 | snd-soc-cs42l52-objs := cs42l52.o |
@@ -21,8 +23,10 @@ snd-soc-cs4270-objs := cs4270.o | |||
21 | snd-soc-cs4271-objs := cs4271.o | 23 | snd-soc-cs4271-objs := cs4271.o |
22 | snd-soc-cx20442-objs := cx20442.o | 24 | snd-soc-cx20442-objs := cx20442.o |
23 | snd-soc-da7210-objs := da7210.o | 25 | snd-soc-da7210-objs := da7210.o |
26 | snd-soc-da732x-objs := da732x.o | ||
24 | snd-soc-dfbmcs320-objs := dfbmcs320.o | 27 | snd-soc-dfbmcs320-objs := dfbmcs320.o |
25 | snd-soc-dmic-objs := dmic.o | 28 | snd-soc-dmic-objs := dmic.o |
29 | snd-soc-isabelle-objs := isabelle.o | ||
26 | snd-soc-jz4740-codec-objs := jz4740.o | 30 | snd-soc-jz4740-codec-objs := jz4740.o |
27 | snd-soc-l3-objs := l3.o | 31 | snd-soc-l3-objs := l3.o |
28 | snd-soc-lm4857-objs := lm4857.o | 32 | snd-soc-lm4857-objs := lm4857.o |
@@ -41,9 +45,11 @@ snd-soc-alc5623-objs := alc5623.o | |||
41 | snd-soc-alc5632-objs := alc5632.o | 45 | snd-soc-alc5632-objs := alc5632.o |
42 | snd-soc-sigmadsp-objs := sigmadsp.o | 46 | snd-soc-sigmadsp-objs := sigmadsp.o |
43 | snd-soc-sn95031-objs := sn95031.o | 47 | snd-soc-sn95031-objs := sn95031.o |
44 | snd-soc-spdif-objs := spdif_transciever.o | 48 | snd-soc-spdif-tx-objs := spdif_transciever.o |
49 | snd-soc-spdif-rx-objs := spdif_receiver.o | ||
45 | snd-soc-ssm2602-objs := ssm2602.o | 50 | snd-soc-ssm2602-objs := ssm2602.o |
46 | snd-soc-sta32x-objs := sta32x.o | 51 | snd-soc-sta32x-objs := sta32x.o |
52 | snd-soc-sta529-objs := sta529.o | ||
47 | snd-soc-stac9766-objs := stac9766.o | 53 | snd-soc-stac9766-objs := stac9766.o |
48 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 54 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
49 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 55 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
@@ -59,6 +65,8 @@ snd-soc-wm1250-ev1-objs := wm1250-ev1.o | |||
59 | snd-soc-wm2000-objs := wm2000.o | 65 | snd-soc-wm2000-objs := wm2000.o |
60 | snd-soc-wm2200-objs := wm2200.o | 66 | snd-soc-wm2200-objs := wm2200.o |
61 | snd-soc-wm5100-objs := wm5100.o wm5100-tables.o | 67 | snd-soc-wm5100-objs := wm5100.o wm5100-tables.o |
68 | snd-soc-wm5102-objs := wm5102.o | ||
69 | snd-soc-wm5110-objs := wm5110.o | ||
62 | snd-soc-wm8350-objs := wm8350.o | 70 | snd-soc-wm8350-objs := wm8350.o |
63 | snd-soc-wm8400-objs := wm8400.o | 71 | snd-soc-wm8400-objs := wm8400.o |
64 | snd-soc-wm8510-objs := wm8510.o | 72 | snd-soc-wm8510-objs := wm8510.o |
@@ -108,6 +116,7 @@ snd-soc-max9877-objs := max9877.o | |||
108 | snd-soc-tpa6130a2-objs := tpa6130a2.o | 116 | snd-soc-tpa6130a2-objs := tpa6130a2.o |
109 | 117 | ||
110 | obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o | 118 | obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o |
119 | obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o | ||
111 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 120 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
112 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o | 121 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o |
113 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o | 122 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o |
@@ -124,6 +133,7 @@ obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | |||
124 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | 133 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o |
125 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | 134 | obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o |
126 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o | 135 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o |
136 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o | ||
127 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 137 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
128 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 138 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
129 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o | 139 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o |
@@ -132,8 +142,10 @@ obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | |||
132 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o | 142 | obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o |
133 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 143 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
134 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o | 144 | obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o |
145 | obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o | ||
135 | obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o | 146 | obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o |
136 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o | 147 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o |
148 | obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o | ||
137 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | 149 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o |
138 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 150 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
139 | obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o | 151 | obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o |
@@ -150,9 +162,10 @@ obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | |||
150 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 162 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
151 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o | 163 | obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o |
152 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o | 164 | obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o |
153 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o | 165 | obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o |
154 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 166 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
155 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | 167 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o |
168 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | ||
156 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 169 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
157 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 170 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
158 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 171 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
@@ -168,6 +181,8 @@ obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o | |||
168 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o | 181 | obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o |
169 | obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o | 182 | obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o |
170 | obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o | 183 | obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o |
184 | obj-$(CONFIG_SND_SOC_WM5102) += snd-soc-wm5102.o | ||
185 | obj-$(CONFIG_SND_SOC_WM5110) += snd-soc-wm5110.o | ||
171 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o | 186 | obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o |
172 | obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o | 187 | obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o |
173 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o | 188 | obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c new file mode 100644 index 000000000000..3c795921c5f6 --- /dev/null +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -0,0 +1,2522 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | ||
5 | * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>, | ||
6 | * Roger Nilsson <roger.xr.nilsson@stericsson.com>, | ||
7 | * for ST-Ericsson. | ||
8 | * | ||
9 | * Based on the early work done by: | ||
10 | * Mikko J. Lehto <mikko.lehto@symbio.com>, | ||
11 | * Mikko Sarmanne <mikko.sarmanne@symbio.com>, | ||
12 | * Jarmo K. Kuronen <jarmo.kuronen@symbio.com>, | ||
13 | * for ST-Ericsson. | ||
14 | * | ||
15 | * License terms: | ||
16 | * | ||
17 | * This program is free software; you can redistribute it and/or modify it | ||
18 | * under the terms of the GNU General Public License version 2 as published | ||
19 | * by the Free Software Foundation. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/device.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/pm.h> | ||
30 | #include <linux/platform_device.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <linux/mfd/abx500/ab8500.h> | ||
33 | #include <linux/mfd/abx500.h> | ||
34 | #include <linux/mfd/abx500/ab8500-sysctrl.h> | ||
35 | #include <linux/mfd/abx500/ab8500-codec.h> | ||
36 | #include <linux/regulator/consumer.h> | ||
37 | |||
38 | #include <sound/core.h> | ||
39 | #include <sound/pcm.h> | ||
40 | #include <sound/pcm_params.h> | ||
41 | #include <sound/initval.h> | ||
42 | #include <sound/soc.h> | ||
43 | #include <sound/soc-dapm.h> | ||
44 | #include <sound/tlv.h> | ||
45 | |||
46 | #include "ab8500-codec.h" | ||
47 | |||
48 | /* Macrocell value definitions */ | ||
49 | #define CLK_32K_OUT2_DISABLE 0x01 | ||
50 | #define INACTIVE_RESET_AUDIO 0x02 | ||
51 | #define ENABLE_AUDIO_CLK_TO_AUDIO_BLK 0x10 | ||
52 | #define ENABLE_VINTCORE12_SUPPLY 0x04 | ||
53 | #define GPIO27_DIR_OUTPUT 0x04 | ||
54 | #define GPIO29_DIR_OUTPUT 0x10 | ||
55 | #define GPIO31_DIR_OUTPUT 0x40 | ||
56 | |||
57 | /* Macrocell register definitions */ | ||
58 | #define AB8500_CTRL3_REG 0x0200 | ||
59 | #define AB8500_GPIO_DIR4_REG 0x1013 | ||
60 | |||
61 | /* Nr of FIR/IIR-coeff banks in ANC-block */ | ||
62 | #define AB8500_NR_OF_ANC_COEFF_BANKS 2 | ||
63 | |||
64 | /* Minimum duration to keep ANC IIR Init bit high or | ||
65 | low before proceeding with the configuration sequence */ | ||
66 | #define AB8500_ANC_SM_DELAY 2000 | ||
67 | |||
68 | #define AB8500_FILTER_CONTROL(xname, xcount, xmin, xmax) \ | ||
69 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ | ||
70 | .info = filter_control_info, \ | ||
71 | .get = filter_control_get, .put = filter_control_put, \ | ||
72 | .private_value = (unsigned long)&(struct filter_control) \ | ||
73 | {.count = xcount, .min = xmin, .max = xmax} } | ||
74 | |||
75 | struct filter_control { | ||
76 | long min, max; | ||
77 | unsigned int count; | ||
78 | long value[128]; | ||
79 | }; | ||
80 | |||
81 | /* Sidetone states */ | ||
82 | static const char * const enum_sid_state[] = { | ||
83 | "Unconfigured", | ||
84 | "Apply FIR", | ||
85 | "FIR is configured", | ||
86 | }; | ||
87 | enum sid_state { | ||
88 | SID_UNCONFIGURED = 0, | ||
89 | SID_APPLY_FIR = 1, | ||
90 | SID_FIR_CONFIGURED = 2, | ||
91 | }; | ||
92 | |||
93 | static const char * const enum_anc_state[] = { | ||
94 | "Unconfigured", | ||
95 | "Apply FIR and IIR", | ||
96 | "FIR and IIR are configured", | ||
97 | "Apply FIR", | ||
98 | "FIR is configured", | ||
99 | "Apply IIR", | ||
100 | "IIR is configured" | ||
101 | }; | ||
102 | enum anc_state { | ||
103 | ANC_UNCONFIGURED = 0, | ||
104 | ANC_APPLY_FIR_IIR = 1, | ||
105 | ANC_FIR_IIR_CONFIGURED = 2, | ||
106 | ANC_APPLY_FIR = 3, | ||
107 | ANC_FIR_CONFIGURED = 4, | ||
108 | ANC_APPLY_IIR = 5, | ||
109 | ANC_IIR_CONFIGURED = 6 | ||
110 | }; | ||
111 | |||
112 | /* Analog microphones */ | ||
113 | enum amic_idx { | ||
114 | AMIC_IDX_1A, | ||
115 | AMIC_IDX_1B, | ||
116 | AMIC_IDX_2 | ||
117 | }; | ||
118 | |||
119 | struct ab8500_codec_drvdata_dbg { | ||
120 | struct regulator *vaud; | ||
121 | struct regulator *vamic1; | ||
122 | struct regulator *vamic2; | ||
123 | struct regulator *vdmic; | ||
124 | }; | ||
125 | |||
126 | /* Private data for AB8500 device-driver */ | ||
127 | struct ab8500_codec_drvdata { | ||
128 | /* Sidetone */ | ||
129 | long *sid_fir_values; | ||
130 | enum sid_state sid_status; | ||
131 | |||
132 | /* ANC */ | ||
133 | struct mutex anc_lock; | ||
134 | long *anc_fir_values; | ||
135 | long *anc_iir_values; | ||
136 | enum anc_state anc_status; | ||
137 | }; | ||
138 | |||
139 | static inline const char *amic_micbias_str(enum amic_micbias micbias) | ||
140 | { | ||
141 | switch (micbias) { | ||
142 | case AMIC_MICBIAS_VAMIC1: | ||
143 | return "VAMIC1"; | ||
144 | case AMIC_MICBIAS_VAMIC2: | ||
145 | return "VAMIC2"; | ||
146 | default: | ||
147 | return "Unknown"; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | static inline const char *amic_type_str(enum amic_type type) | ||
152 | { | ||
153 | switch (type) { | ||
154 | case AMIC_TYPE_DIFFERENTIAL: | ||
155 | return "DIFFERENTIAL"; | ||
156 | case AMIC_TYPE_SINGLE_ENDED: | ||
157 | return "SINGLE ENDED"; | ||
158 | default: | ||
159 | return "Unknown"; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Read'n'write functions | ||
165 | */ | ||
166 | |||
167 | /* Read a register from the audio-bank of AB8500 */ | ||
168 | static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, | ||
169 | unsigned int reg) | ||
170 | { | ||
171 | int status; | ||
172 | unsigned int value = 0; | ||
173 | |||
174 | u8 value8; | ||
175 | status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, | ||
176 | reg, &value8); | ||
177 | if (status < 0) { | ||
178 | dev_err(codec->dev, | ||
179 | "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", | ||
180 | __func__, (u8)AB8500_AUDIO, (u8)reg, status); | ||
181 | } else { | ||
182 | dev_dbg(codec->dev, | ||
183 | "%s: Read 0x%02x from register 0x%02x:0x%02x\n", | ||
184 | __func__, value8, (u8)AB8500_AUDIO, (u8)reg); | ||
185 | value = (unsigned int)value8; | ||
186 | } | ||
187 | |||
188 | return value; | ||
189 | } | ||
190 | |||
191 | /* Write to a register in the audio-bank of AB8500 */ | ||
192 | static int ab8500_codec_write_reg(struct snd_soc_codec *codec, | ||
193 | unsigned int reg, unsigned int value) | ||
194 | { | ||
195 | int status; | ||
196 | |||
197 | status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, | ||
198 | reg, value); | ||
199 | if (status < 0) | ||
200 | dev_err(codec->dev, | ||
201 | "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", | ||
202 | __func__, (u8)AB8500_AUDIO, (u8)reg, status); | ||
203 | else | ||
204 | dev_dbg(codec->dev, | ||
205 | "%s: Wrote 0x%02x into register %02x:%02x\n", | ||
206 | __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); | ||
207 | |||
208 | return status; | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Controls - DAPM | ||
213 | */ | ||
214 | |||
215 | /* Earpiece */ | ||
216 | |||
217 | /* Earpiece source selector */ | ||
218 | static const char * const enum_ear_lineout_source[] = {"Headset Left", | ||
219 | "Speaker Left"}; | ||
220 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ear_lineout_source, AB8500_DMICFILTCONF, | ||
221 | AB8500_DMICFILTCONF_DA3TOEAR, enum_ear_lineout_source); | ||
222 | static const struct snd_kcontrol_new dapm_ear_lineout_source = | ||
223 | SOC_DAPM_ENUM("Earpiece or LineOut Mono Source", | ||
224 | dapm_enum_ear_lineout_source); | ||
225 | |||
226 | /* LineOut */ | ||
227 | |||
228 | /* LineOut source selector */ | ||
229 | static const char * const enum_lineout_source[] = {"Mono Path", "Stereo Path"}; | ||
230 | static SOC_ENUM_DOUBLE_DECL(dapm_enum_lineout_source, AB8500_ANACONF5, | ||
231 | AB8500_ANACONF5_HSLDACTOLOL, | ||
232 | AB8500_ANACONF5_HSRDACTOLOR, enum_lineout_source); | ||
233 | static const struct snd_kcontrol_new dapm_lineout_source[] = { | ||
234 | SOC_DAPM_ENUM("LineOut Source", dapm_enum_lineout_source), | ||
235 | }; | ||
236 | |||
237 | /* Handsfree */ | ||
238 | |||
239 | /* Speaker Left - ANC selector */ | ||
240 | static const char * const enum_HFx_sel[] = {"Audio Path", "ANC"}; | ||
241 | static SOC_ENUM_SINGLE_DECL(dapm_enum_HFl_sel, AB8500_DIGMULTCONF2, | ||
242 | AB8500_DIGMULTCONF2_HFLSEL, enum_HFx_sel); | ||
243 | static const struct snd_kcontrol_new dapm_HFl_select[] = { | ||
244 | SOC_DAPM_ENUM("Speaker Left Source", dapm_enum_HFl_sel), | ||
245 | }; | ||
246 | |||
247 | /* Speaker Right - ANC selector */ | ||
248 | static SOC_ENUM_SINGLE_DECL(dapm_enum_HFr_sel, AB8500_DIGMULTCONF2, | ||
249 | AB8500_DIGMULTCONF2_HFRSEL, enum_HFx_sel); | ||
250 | static const struct snd_kcontrol_new dapm_HFr_select[] = { | ||
251 | SOC_DAPM_ENUM("Speaker Right Source", dapm_enum_HFr_sel), | ||
252 | }; | ||
253 | |||
254 | /* Mic 1 */ | ||
255 | |||
256 | /* Mic 1 - Mic 1a or 1b selector */ | ||
257 | static const char * const enum_mic1ab_sel[] = {"Mic 1b", "Mic 1a"}; | ||
258 | static SOC_ENUM_SINGLE_DECL(dapm_enum_mic1ab_sel, AB8500_ANACONF3, | ||
259 | AB8500_ANACONF3_MIC1SEL, enum_mic1ab_sel); | ||
260 | static const struct snd_kcontrol_new dapm_mic1ab_mux[] = { | ||
261 | SOC_DAPM_ENUM("Mic 1a or 1b Select", dapm_enum_mic1ab_sel), | ||
262 | }; | ||
263 | |||
264 | /* Mic 1 - AD3 - Mic 1 or DMic 3 selector */ | ||
265 | static const char * const enum_ad3_sel[] = {"Mic 1", "DMic 3"}; | ||
266 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ad3_sel, AB8500_DIGMULTCONF1, | ||
267 | AB8500_DIGMULTCONF1_AD3SEL, enum_ad3_sel); | ||
268 | static const struct snd_kcontrol_new dapm_ad3_select[] = { | ||
269 | SOC_DAPM_ENUM("AD3 Source Select", dapm_enum_ad3_sel), | ||
270 | }; | ||
271 | |||
272 | /* Mic 1 - AD6 - Mic 1 or DMic 6 selector */ | ||
273 | static const char * const enum_ad6_sel[] = {"Mic 1", "DMic 6"}; | ||
274 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ad6_sel, AB8500_DIGMULTCONF1, | ||
275 | AB8500_DIGMULTCONF1_AD6SEL, enum_ad6_sel); | ||
276 | static const struct snd_kcontrol_new dapm_ad6_select[] = { | ||
277 | SOC_DAPM_ENUM("AD6 Source Select", dapm_enum_ad6_sel), | ||
278 | }; | ||
279 | |||
280 | /* Mic 2 */ | ||
281 | |||
282 | /* Mic 2 - AD5 - Mic 2 or DMic 5 selector */ | ||
283 | static const char * const enum_ad5_sel[] = {"Mic 2", "DMic 5"}; | ||
284 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ad5_sel, AB8500_DIGMULTCONF1, | ||
285 | AB8500_DIGMULTCONF1_AD5SEL, enum_ad5_sel); | ||
286 | static const struct snd_kcontrol_new dapm_ad5_select[] = { | ||
287 | SOC_DAPM_ENUM("AD5 Source Select", dapm_enum_ad5_sel), | ||
288 | }; | ||
289 | |||
290 | /* LineIn */ | ||
291 | |||
292 | /* LineIn left - AD1 - LineIn Left or DMic 1 selector */ | ||
293 | static const char * const enum_ad1_sel[] = {"LineIn Left", "DMic 1"}; | ||
294 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ad1_sel, AB8500_DIGMULTCONF1, | ||
295 | AB8500_DIGMULTCONF1_AD1SEL, enum_ad1_sel); | ||
296 | static const struct snd_kcontrol_new dapm_ad1_select[] = { | ||
297 | SOC_DAPM_ENUM("AD1 Source Select", dapm_enum_ad1_sel), | ||
298 | }; | ||
299 | |||
300 | /* LineIn right - Mic 2 or LineIn Right selector */ | ||
301 | static const char * const enum_mic2lr_sel[] = {"Mic 2", "LineIn Right"}; | ||
302 | static SOC_ENUM_SINGLE_DECL(dapm_enum_mic2lr_sel, AB8500_ANACONF3, | ||
303 | AB8500_ANACONF3_LINRSEL, enum_mic2lr_sel); | ||
304 | static const struct snd_kcontrol_new dapm_mic2lr_select[] = { | ||
305 | SOC_DAPM_ENUM("Mic 2 or LINR Select", dapm_enum_mic2lr_sel), | ||
306 | }; | ||
307 | |||
308 | /* LineIn right - AD2 - LineIn Right or DMic2 selector */ | ||
309 | static const char * const enum_ad2_sel[] = {"LineIn Right", "DMic 2"}; | ||
310 | static SOC_ENUM_SINGLE_DECL(dapm_enum_ad2_sel, AB8500_DIGMULTCONF1, | ||
311 | AB8500_DIGMULTCONF1_AD2SEL, enum_ad2_sel); | ||
312 | static const struct snd_kcontrol_new dapm_ad2_select[] = { | ||
313 | SOC_DAPM_ENUM("AD2 Source Select", dapm_enum_ad2_sel), | ||
314 | }; | ||
315 | |||
316 | |||
317 | /* ANC */ | ||
318 | |||
319 | static const char * const enum_anc_in_sel[] = {"Mic 1 / DMic 6", | ||
320 | "Mic 2 / DMic 5"}; | ||
321 | static SOC_ENUM_SINGLE_DECL(dapm_enum_anc_in_sel, AB8500_DMICFILTCONF, | ||
322 | AB8500_DMICFILTCONF_ANCINSEL, enum_anc_in_sel); | ||
323 | static const struct snd_kcontrol_new dapm_anc_in_select[] = { | ||
324 | SOC_DAPM_ENUM("ANC Source", dapm_enum_anc_in_sel), | ||
325 | }; | ||
326 | |||
327 | /* ANC - Enable/Disable */ | ||
328 | static const struct snd_kcontrol_new dapm_anc_enable[] = { | ||
329 | SOC_DAPM_SINGLE("Switch", AB8500_ANCCONF1, | ||
330 | AB8500_ANCCONF1_ENANC, 0, 0), | ||
331 | }; | ||
332 | |||
333 | /* ANC to Earpiece - Mute */ | ||
334 | static const struct snd_kcontrol_new dapm_anc_ear_mute[] = { | ||
335 | SOC_DAPM_SINGLE("Switch", AB8500_DIGMULTCONF1, | ||
336 | AB8500_DIGMULTCONF1_ANCSEL, 1, 0), | ||
337 | }; | ||
338 | |||
339 | |||
340 | |||
341 | /* Sidetone left */ | ||
342 | |||
343 | /* Sidetone left - Input selector */ | ||
344 | static const char * const enum_stfir1_in_sel[] = { | ||
345 | "LineIn Left", "LineIn Right", "Mic 1", "Headset Left" | ||
346 | }; | ||
347 | static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir1_in_sel, AB8500_DIGMULTCONF2, | ||
348 | AB8500_DIGMULTCONF2_FIRSID1SEL, enum_stfir1_in_sel); | ||
349 | static const struct snd_kcontrol_new dapm_stfir1_in_select[] = { | ||
350 | SOC_DAPM_ENUM("Sidetone Left Source", dapm_enum_stfir1_in_sel), | ||
351 | }; | ||
352 | |||
353 | /* Sidetone right path */ | ||
354 | |||
355 | /* Sidetone right - Input selector */ | ||
356 | static const char * const enum_stfir2_in_sel[] = { | ||
357 | "LineIn Right", "Mic 1", "DMic 4", "Headset Right" | ||
358 | }; | ||
359 | static SOC_ENUM_SINGLE_DECL(dapm_enum_stfir2_in_sel, AB8500_DIGMULTCONF2, | ||
360 | AB8500_DIGMULTCONF2_FIRSID2SEL, enum_stfir2_in_sel); | ||
361 | static const struct snd_kcontrol_new dapm_stfir2_in_select[] = { | ||
362 | SOC_DAPM_ENUM("Sidetone Right Source", dapm_enum_stfir2_in_sel), | ||
363 | }; | ||
364 | |||
365 | /* Vibra */ | ||
366 | |||
367 | static const char * const enum_pwm2vibx[] = {"Audio Path", "PWM Generator"}; | ||
368 | |||
369 | static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib1, AB8500_PWMGENCONF1, | ||
370 | AB8500_PWMGENCONF1_PWMTOVIB1, enum_pwm2vibx); | ||
371 | |||
372 | static const struct snd_kcontrol_new dapm_pwm2vib1[] = { | ||
373 | SOC_DAPM_ENUM("Vibra 1 Controller", dapm_enum_pwm2vib1), | ||
374 | }; | ||
375 | |||
376 | static SOC_ENUM_SINGLE_DECL(dapm_enum_pwm2vib2, AB8500_PWMGENCONF1, | ||
377 | AB8500_PWMGENCONF1_PWMTOVIB2, enum_pwm2vibx); | ||
378 | |||
379 | static const struct snd_kcontrol_new dapm_pwm2vib2[] = { | ||
380 | SOC_DAPM_ENUM("Vibra 2 Controller", dapm_enum_pwm2vib2), | ||
381 | }; | ||
382 | |||
383 | /* | ||
384 | * DAPM-widgets | ||
385 | */ | ||
386 | |||
387 | static const struct snd_soc_dapm_widget ab8500_dapm_widgets[] = { | ||
388 | |||
389 | /* Clocks */ | ||
390 | SND_SOC_DAPM_CLOCK_SUPPLY("audioclk"), | ||
391 | |||
392 | /* Regulators */ | ||
393 | SND_SOC_DAPM_REGULATOR_SUPPLY("V-AUD", 0), | ||
394 | SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC1", 0), | ||
395 | SND_SOC_DAPM_REGULATOR_SUPPLY("V-AMIC2", 0), | ||
396 | SND_SOC_DAPM_REGULATOR_SUPPLY("V-DMIC", 0), | ||
397 | |||
398 | /* Power */ | ||
399 | SND_SOC_DAPM_SUPPLY("Audio Power", | ||
400 | AB8500_POWERUP, AB8500_POWERUP_POWERUP, 0, | ||
401 | NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
402 | SND_SOC_DAPM_SUPPLY("Audio Analog Power", | ||
403 | AB8500_POWERUP, AB8500_POWERUP_ENANA, 0, | ||
404 | NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
405 | |||
406 | /* Main supply node */ | ||
407 | SND_SOC_DAPM_SUPPLY("Main Supply", SND_SOC_NOPM, 0, 0, | ||
408 | NULL, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
409 | |||
410 | /* DA/AD */ | ||
411 | |||
412 | SND_SOC_DAPM_INPUT("ADC Input"), | ||
413 | SND_SOC_DAPM_ADC("ADC", "ab8500_0c", SND_SOC_NOPM, 0, 0), | ||
414 | |||
415 | SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), | ||
416 | SND_SOC_DAPM_OUTPUT("DAC Output"), | ||
417 | |||
418 | SND_SOC_DAPM_AIF_IN("DA_IN1", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
419 | SND_SOC_DAPM_AIF_IN("DA_IN2", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
420 | SND_SOC_DAPM_AIF_IN("DA_IN3", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
421 | SND_SOC_DAPM_AIF_IN("DA_IN4", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
422 | SND_SOC_DAPM_AIF_IN("DA_IN5", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
423 | SND_SOC_DAPM_AIF_IN("DA_IN6", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
424 | SND_SOC_DAPM_AIF_OUT("AD_OUT1", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
425 | SND_SOC_DAPM_AIF_OUT("AD_OUT2", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
426 | SND_SOC_DAPM_AIF_OUT("AD_OUT3", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
427 | SND_SOC_DAPM_AIF_OUT("AD_OUT4", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
428 | SND_SOC_DAPM_AIF_OUT("AD_OUT57", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
429 | SND_SOC_DAPM_AIF_OUT("AD_OUT68", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
430 | |||
431 | /* Headset path */ | ||
432 | |||
433 | SND_SOC_DAPM_SUPPLY("Charge Pump", AB8500_ANACONF5, | ||
434 | AB8500_ANACONF5_ENCPHS, 0, NULL, 0), | ||
435 | |||
436 | SND_SOC_DAPM_DAC("DA1 Enable", "ab8500_0p", | ||
437 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA1, 0), | ||
438 | SND_SOC_DAPM_DAC("DA2 Enable", "ab8500_0p", | ||
439 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA2, 0), | ||
440 | |||
441 | SND_SOC_DAPM_PGA("HSL Digital Volume", SND_SOC_NOPM, 0, 0, | ||
442 | NULL, 0), | ||
443 | SND_SOC_DAPM_PGA("HSR Digital Volume", SND_SOC_NOPM, 0, 0, | ||
444 | NULL, 0), | ||
445 | |||
446 | SND_SOC_DAPM_DAC("HSL DAC", "ab8500_0p", | ||
447 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSL, 0), | ||
448 | SND_SOC_DAPM_DAC("HSR DAC", "ab8500_0p", | ||
449 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHSR, 0), | ||
450 | SND_SOC_DAPM_MIXER("HSL DAC Mute", AB8500_MUTECONF, | ||
451 | AB8500_MUTECONF_MUTDACHSL, 1, | ||
452 | NULL, 0), | ||
453 | SND_SOC_DAPM_MIXER("HSR DAC Mute", AB8500_MUTECONF, | ||
454 | AB8500_MUTECONF_MUTDACHSR, 1, | ||
455 | NULL, 0), | ||
456 | SND_SOC_DAPM_DAC("HSL DAC Driver", "ab8500_0p", | ||
457 | AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSL, 0), | ||
458 | SND_SOC_DAPM_DAC("HSR DAC Driver", "ab8500_0p", | ||
459 | AB8500_ANACONF3, AB8500_ANACONF3_ENDRVHSR, 0), | ||
460 | |||
461 | SND_SOC_DAPM_MIXER("HSL Mute", | ||
462 | AB8500_MUTECONF, AB8500_MUTECONF_MUTHSL, 1, | ||
463 | NULL, 0), | ||
464 | SND_SOC_DAPM_MIXER("HSR Mute", | ||
465 | AB8500_MUTECONF, AB8500_MUTECONF_MUTHSR, 1, | ||
466 | NULL, 0), | ||
467 | SND_SOC_DAPM_MIXER("HSL Enable", | ||
468 | AB8500_ANACONF4, AB8500_ANACONF4_ENHSL, 0, | ||
469 | NULL, 0), | ||
470 | SND_SOC_DAPM_MIXER("HSR Enable", | ||
471 | AB8500_ANACONF4, AB8500_ANACONF4_ENHSR, 0, | ||
472 | NULL, 0), | ||
473 | SND_SOC_DAPM_PGA("HSL Volume", | ||
474 | SND_SOC_NOPM, 0, 0, | ||
475 | NULL, 0), | ||
476 | SND_SOC_DAPM_PGA("HSR Volume", | ||
477 | SND_SOC_NOPM, 0, 0, | ||
478 | NULL, 0), | ||
479 | |||
480 | SND_SOC_DAPM_OUTPUT("Headset Left"), | ||
481 | SND_SOC_DAPM_OUTPUT("Headset Right"), | ||
482 | |||
483 | /* LineOut path */ | ||
484 | |||
485 | SND_SOC_DAPM_MUX("LineOut Source", | ||
486 | SND_SOC_NOPM, 0, 0, dapm_lineout_source), | ||
487 | |||
488 | SND_SOC_DAPM_MIXER("LOL Disable HFL", | ||
489 | AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 1, | ||
490 | NULL, 0), | ||
491 | SND_SOC_DAPM_MIXER("LOR Disable HFR", | ||
492 | AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 1, | ||
493 | NULL, 0), | ||
494 | |||
495 | SND_SOC_DAPM_MIXER("LOL Enable", | ||
496 | AB8500_ANACONF5, AB8500_ANACONF5_ENLOL, 0, | ||
497 | NULL, 0), | ||
498 | SND_SOC_DAPM_MIXER("LOR Enable", | ||
499 | AB8500_ANACONF5, AB8500_ANACONF5_ENLOR, 0, | ||
500 | NULL, 0), | ||
501 | |||
502 | SND_SOC_DAPM_OUTPUT("LineOut Left"), | ||
503 | SND_SOC_DAPM_OUTPUT("LineOut Right"), | ||
504 | |||
505 | /* Earpiece path */ | ||
506 | |||
507 | SND_SOC_DAPM_MUX("Earpiece or LineOut Mono Source", | ||
508 | SND_SOC_NOPM, 0, 0, &dapm_ear_lineout_source), | ||
509 | SND_SOC_DAPM_MIXER("EAR DAC", | ||
510 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACEAR, 0, | ||
511 | NULL, 0), | ||
512 | SND_SOC_DAPM_MIXER("EAR Mute", | ||
513 | AB8500_MUTECONF, AB8500_MUTECONF_MUTEAR, 1, | ||
514 | NULL, 0), | ||
515 | SND_SOC_DAPM_MIXER("EAR Enable", | ||
516 | AB8500_ANACONF4, AB8500_ANACONF4_ENEAR, 0, | ||
517 | NULL, 0), | ||
518 | |||
519 | SND_SOC_DAPM_OUTPUT("Earpiece"), | ||
520 | |||
521 | /* Handsfree path */ | ||
522 | |||
523 | SND_SOC_DAPM_MIXER("DA3 Channel Volume", | ||
524 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA3, 0, | ||
525 | NULL, 0), | ||
526 | SND_SOC_DAPM_MIXER("DA4 Channel Volume", | ||
527 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA4, 0, | ||
528 | NULL, 0), | ||
529 | SND_SOC_DAPM_MUX("Speaker Left Source", | ||
530 | SND_SOC_NOPM, 0, 0, dapm_HFl_select), | ||
531 | SND_SOC_DAPM_MUX("Speaker Right Source", | ||
532 | SND_SOC_NOPM, 0, 0, dapm_HFr_select), | ||
533 | SND_SOC_DAPM_MIXER("HFL DAC", AB8500_DAPATHCONF, | ||
534 | AB8500_DAPATHCONF_ENDACHFL, 0, | ||
535 | NULL, 0), | ||
536 | SND_SOC_DAPM_MIXER("HFR DAC", | ||
537 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACHFR, 0, | ||
538 | NULL, 0), | ||
539 | SND_SOC_DAPM_MIXER("DA4 or ANC path to HfR", | ||
540 | AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFREN, 0, | ||
541 | NULL, 0), | ||
542 | SND_SOC_DAPM_MIXER("DA3 or ANC path to HfL", | ||
543 | AB8500_DIGMULTCONF2, AB8500_DIGMULTCONF2_DATOHFLEN, 0, | ||
544 | NULL, 0), | ||
545 | SND_SOC_DAPM_MIXER("HFL Enable", | ||
546 | AB8500_ANACONF4, AB8500_ANACONF4_ENHFL, 0, | ||
547 | NULL, 0), | ||
548 | SND_SOC_DAPM_MIXER("HFR Enable", | ||
549 | AB8500_ANACONF4, AB8500_ANACONF4_ENHFR, 0, | ||
550 | NULL, 0), | ||
551 | |||
552 | SND_SOC_DAPM_OUTPUT("Speaker Left"), | ||
553 | SND_SOC_DAPM_OUTPUT("Speaker Right"), | ||
554 | |||
555 | /* Vibrator path */ | ||
556 | |||
557 | SND_SOC_DAPM_INPUT("PWMGEN1"), | ||
558 | SND_SOC_DAPM_INPUT("PWMGEN2"), | ||
559 | |||
560 | SND_SOC_DAPM_MIXER("DA5 Channel Volume", | ||
561 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA5, 0, | ||
562 | NULL, 0), | ||
563 | SND_SOC_DAPM_MIXER("DA6 Channel Volume", | ||
564 | AB8500_DAPATHENA, AB8500_DAPATHENA_ENDA6, 0, | ||
565 | NULL, 0), | ||
566 | SND_SOC_DAPM_MIXER("VIB1 DAC", | ||
567 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB1, 0, | ||
568 | NULL, 0), | ||
569 | SND_SOC_DAPM_MIXER("VIB2 DAC", | ||
570 | AB8500_DAPATHCONF, AB8500_DAPATHCONF_ENDACVIB2, 0, | ||
571 | NULL, 0), | ||
572 | SND_SOC_DAPM_MUX("Vibra 1 Controller", | ||
573 | SND_SOC_NOPM, 0, 0, dapm_pwm2vib1), | ||
574 | SND_SOC_DAPM_MUX("Vibra 2 Controller", | ||
575 | SND_SOC_NOPM, 0, 0, dapm_pwm2vib2), | ||
576 | SND_SOC_DAPM_MIXER("VIB1 Enable", | ||
577 | AB8500_ANACONF4, AB8500_ANACONF4_ENVIB1, 0, | ||
578 | NULL, 0), | ||
579 | SND_SOC_DAPM_MIXER("VIB2 Enable", | ||
580 | AB8500_ANACONF4, AB8500_ANACONF4_ENVIB2, 0, | ||
581 | NULL, 0), | ||
582 | |||
583 | SND_SOC_DAPM_OUTPUT("Vibra 1"), | ||
584 | SND_SOC_DAPM_OUTPUT("Vibra 2"), | ||
585 | |||
586 | /* Mic 1 */ | ||
587 | |||
588 | SND_SOC_DAPM_INPUT("Mic 1"), | ||
589 | |||
590 | SND_SOC_DAPM_MUX("Mic 1a or 1b Select", | ||
591 | SND_SOC_NOPM, 0, 0, dapm_mic1ab_mux), | ||
592 | SND_SOC_DAPM_MIXER("MIC1 Mute", | ||
593 | AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC1, 1, | ||
594 | NULL, 0), | ||
595 | SND_SOC_DAPM_MIXER("MIC1A V-AMICx Enable", | ||
596 | AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0, | ||
597 | NULL, 0), | ||
598 | SND_SOC_DAPM_MIXER("MIC1B V-AMICx Enable", | ||
599 | AB8500_ANACONF2, AB8500_ANACONF2_ENMIC1, 0, | ||
600 | NULL, 0), | ||
601 | SND_SOC_DAPM_MIXER("MIC1 ADC", | ||
602 | AB8500_ANACONF3, AB8500_ANACONF3_ENADCMIC, 0, | ||
603 | NULL, 0), | ||
604 | SND_SOC_DAPM_MUX("AD3 Source Select", | ||
605 | SND_SOC_NOPM, 0, 0, dapm_ad3_select), | ||
606 | SND_SOC_DAPM_MIXER("AD3 Channel Volume", | ||
607 | SND_SOC_NOPM, 0, 0, | ||
608 | NULL, 0), | ||
609 | SND_SOC_DAPM_MIXER("AD3 Enable", | ||
610 | AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, 0, | ||
611 | NULL, 0), | ||
612 | |||
613 | /* Mic 2 */ | ||
614 | |||
615 | SND_SOC_DAPM_INPUT("Mic 2"), | ||
616 | |||
617 | SND_SOC_DAPM_MIXER("MIC2 Mute", | ||
618 | AB8500_ANACONF2, AB8500_ANACONF2_MUTMIC2, 1, | ||
619 | NULL, 0), | ||
620 | SND_SOC_DAPM_MIXER("MIC2 V-AMICx Enable", AB8500_ANACONF2, | ||
621 | AB8500_ANACONF2_ENMIC2, 0, | ||
622 | NULL, 0), | ||
623 | |||
624 | /* LineIn */ | ||
625 | |||
626 | SND_SOC_DAPM_INPUT("LineIn Left"), | ||
627 | SND_SOC_DAPM_INPUT("LineIn Right"), | ||
628 | |||
629 | SND_SOC_DAPM_MIXER("LINL Mute", | ||
630 | AB8500_ANACONF2, AB8500_ANACONF2_MUTLINL, 1, | ||
631 | NULL, 0), | ||
632 | SND_SOC_DAPM_MIXER("LINR Mute", | ||
633 | AB8500_ANACONF2, AB8500_ANACONF2_MUTLINR, 1, | ||
634 | NULL, 0), | ||
635 | SND_SOC_DAPM_MIXER("LINL Enable", AB8500_ANACONF2, | ||
636 | AB8500_ANACONF2_ENLINL, 0, | ||
637 | NULL, 0), | ||
638 | SND_SOC_DAPM_MIXER("LINR Enable", AB8500_ANACONF2, | ||
639 | AB8500_ANACONF2_ENLINR, 0, | ||
640 | NULL, 0), | ||
641 | |||
642 | /* LineIn Bypass path */ | ||
643 | SND_SOC_DAPM_MIXER("LINL to HSL Volume", | ||
644 | SND_SOC_NOPM, 0, 0, | ||
645 | NULL, 0), | ||
646 | SND_SOC_DAPM_MIXER("LINR to HSR Volume", | ||
647 | SND_SOC_NOPM, 0, 0, | ||
648 | NULL, 0), | ||
649 | |||
650 | /* LineIn, Mic 2 */ | ||
651 | SND_SOC_DAPM_MUX("Mic 2 or LINR Select", | ||
652 | SND_SOC_NOPM, 0, 0, dapm_mic2lr_select), | ||
653 | SND_SOC_DAPM_MIXER("LINL ADC", AB8500_ANACONF3, | ||
654 | AB8500_ANACONF3_ENADCLINL, 0, | ||
655 | NULL, 0), | ||
656 | SND_SOC_DAPM_MIXER("LINR ADC", AB8500_ANACONF3, | ||
657 | AB8500_ANACONF3_ENADCLINR, 0, | ||
658 | NULL, 0), | ||
659 | SND_SOC_DAPM_MUX("AD1 Source Select", | ||
660 | SND_SOC_NOPM, 0, 0, dapm_ad1_select), | ||
661 | SND_SOC_DAPM_MUX("AD2 Source Select", | ||
662 | SND_SOC_NOPM, 0, 0, dapm_ad2_select), | ||
663 | SND_SOC_DAPM_MIXER("AD1 Channel Volume", | ||
664 | SND_SOC_NOPM, 0, 0, | ||
665 | NULL, 0), | ||
666 | SND_SOC_DAPM_MIXER("AD2 Channel Volume", | ||
667 | SND_SOC_NOPM, 0, 0, | ||
668 | NULL, 0), | ||
669 | |||
670 | SND_SOC_DAPM_MIXER("AD12 Enable", | ||
671 | AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD12, 0, | ||
672 | NULL, 0), | ||
673 | |||
674 | /* HD Capture path */ | ||
675 | |||
676 | SND_SOC_DAPM_MUX("AD5 Source Select", | ||
677 | SND_SOC_NOPM, 0, 0, dapm_ad5_select), | ||
678 | SND_SOC_DAPM_MUX("AD6 Source Select", | ||
679 | SND_SOC_NOPM, 0, 0, dapm_ad6_select), | ||
680 | SND_SOC_DAPM_MIXER("AD5 Channel Volume", | ||
681 | SND_SOC_NOPM, 0, 0, | ||
682 | NULL, 0), | ||
683 | SND_SOC_DAPM_MIXER("AD6 Channel Volume", | ||
684 | SND_SOC_NOPM, 0, 0, | ||
685 | NULL, 0), | ||
686 | SND_SOC_DAPM_MIXER("AD57 Enable", | ||
687 | AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0, | ||
688 | NULL, 0), | ||
689 | SND_SOC_DAPM_MIXER("AD68 Enable", | ||
690 | AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD5768, 0, | ||
691 | NULL, 0), | ||
692 | |||
693 | /* Digital Microphone path */ | ||
694 | |||
695 | SND_SOC_DAPM_INPUT("DMic 1"), | ||
696 | SND_SOC_DAPM_INPUT("DMic 2"), | ||
697 | SND_SOC_DAPM_INPUT("DMic 3"), | ||
698 | SND_SOC_DAPM_INPUT("DMic 4"), | ||
699 | SND_SOC_DAPM_INPUT("DMic 5"), | ||
700 | SND_SOC_DAPM_INPUT("DMic 6"), | ||
701 | |||
702 | SND_SOC_DAPM_MIXER("DMIC1", | ||
703 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC1, 0, | ||
704 | NULL, 0), | ||
705 | SND_SOC_DAPM_MIXER("DMIC2", | ||
706 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC2, 0, | ||
707 | NULL, 0), | ||
708 | SND_SOC_DAPM_MIXER("DMIC3", | ||
709 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC3, 0, | ||
710 | NULL, 0), | ||
711 | SND_SOC_DAPM_MIXER("DMIC4", | ||
712 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC4, 0, | ||
713 | NULL, 0), | ||
714 | SND_SOC_DAPM_MIXER("DMIC5", | ||
715 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC5, 0, | ||
716 | NULL, 0), | ||
717 | SND_SOC_DAPM_MIXER("DMIC6", | ||
718 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_ENDMIC6, 0, | ||
719 | NULL, 0), | ||
720 | SND_SOC_DAPM_MIXER("AD4 Channel Volume", | ||
721 | SND_SOC_NOPM, 0, 0, | ||
722 | NULL, 0), | ||
723 | SND_SOC_DAPM_MIXER("AD4 Enable", | ||
724 | AB8500_ADPATHENA, AB8500_ADPATHENA_ENAD34, | ||
725 | 0, NULL, 0), | ||
726 | |||
727 | /* Acoustical Noise Cancellation path */ | ||
728 | |||
729 | SND_SOC_DAPM_INPUT("ANC Configure Input"), | ||
730 | SND_SOC_DAPM_OUTPUT("ANC Configure Output"), | ||
731 | |||
732 | SND_SOC_DAPM_MUX("ANC Source", | ||
733 | SND_SOC_NOPM, 0, 0, | ||
734 | dapm_anc_in_select), | ||
735 | SND_SOC_DAPM_SWITCH("ANC", | ||
736 | SND_SOC_NOPM, 0, 0, | ||
737 | dapm_anc_enable), | ||
738 | SND_SOC_DAPM_SWITCH("ANC to Earpiece", | ||
739 | SND_SOC_NOPM, 0, 0, | ||
740 | dapm_anc_ear_mute), | ||
741 | |||
742 | /* Sidetone Filter path */ | ||
743 | |||
744 | SND_SOC_DAPM_MUX("Sidetone Left Source", | ||
745 | SND_SOC_NOPM, 0, 0, | ||
746 | dapm_stfir1_in_select), | ||
747 | SND_SOC_DAPM_MUX("Sidetone Right Source", | ||
748 | SND_SOC_NOPM, 0, 0, | ||
749 | dapm_stfir2_in_select), | ||
750 | SND_SOC_DAPM_MIXER("STFIR1 Control", | ||
751 | SND_SOC_NOPM, 0, 0, | ||
752 | NULL, 0), | ||
753 | SND_SOC_DAPM_MIXER("STFIR2 Control", | ||
754 | SND_SOC_NOPM, 0, 0, | ||
755 | NULL, 0), | ||
756 | SND_SOC_DAPM_MIXER("STFIR1 Volume", | ||
757 | SND_SOC_NOPM, 0, 0, | ||
758 | NULL, 0), | ||
759 | SND_SOC_DAPM_MIXER("STFIR2 Volume", | ||
760 | SND_SOC_NOPM, 0, 0, | ||
761 | NULL, 0), | ||
762 | }; | ||
763 | |||
764 | /* | ||
765 | * DAPM-routes | ||
766 | */ | ||
767 | static const struct snd_soc_dapm_route ab8500_dapm_routes[] = { | ||
768 | /* Power AB8500 audio-block when AD/DA is active */ | ||
769 | {"Main Supply", NULL, "V-AUD"}, | ||
770 | {"Main Supply", NULL, "audioclk"}, | ||
771 | {"Main Supply", NULL, "Audio Power"}, | ||
772 | {"Main Supply", NULL, "Audio Analog Power"}, | ||
773 | |||
774 | {"DAC", NULL, "ab8500_0p"}, | ||
775 | {"DAC", NULL, "Main Supply"}, | ||
776 | {"ADC", NULL, "ab8500_0c"}, | ||
777 | {"ADC", NULL, "Main Supply"}, | ||
778 | |||
779 | /* ANC Configure */ | ||
780 | {"ANC Configure Input", NULL, "Main Supply"}, | ||
781 | {"ANC Configure Output", NULL, "ANC Configure Input"}, | ||
782 | |||
783 | /* AD/DA */ | ||
784 | {"ADC", NULL, "ADC Input"}, | ||
785 | {"DAC Output", NULL, "DAC"}, | ||
786 | |||
787 | /* Powerup charge pump if DA1/2 is in use */ | ||
788 | |||
789 | {"DA_IN1", NULL, "ab8500_0p"}, | ||
790 | {"DA_IN1", NULL, "Charge Pump"}, | ||
791 | {"DA_IN2", NULL, "ab8500_0p"}, | ||
792 | {"DA_IN2", NULL, "Charge Pump"}, | ||
793 | |||
794 | /* Headset path */ | ||
795 | |||
796 | {"DA1 Enable", NULL, "DA_IN1"}, | ||
797 | {"DA2 Enable", NULL, "DA_IN2"}, | ||
798 | |||
799 | {"HSL Digital Volume", NULL, "DA1 Enable"}, | ||
800 | {"HSR Digital Volume", NULL, "DA2 Enable"}, | ||
801 | |||
802 | {"HSL DAC", NULL, "HSL Digital Volume"}, | ||
803 | {"HSR DAC", NULL, "HSR Digital Volume"}, | ||
804 | |||
805 | {"HSL DAC Mute", NULL, "HSL DAC"}, | ||
806 | {"HSR DAC Mute", NULL, "HSR DAC"}, | ||
807 | |||
808 | {"HSL DAC Driver", NULL, "HSL DAC Mute"}, | ||
809 | {"HSR DAC Driver", NULL, "HSR DAC Mute"}, | ||
810 | |||
811 | {"HSL Mute", NULL, "HSL DAC Driver"}, | ||
812 | {"HSR Mute", NULL, "HSR DAC Driver"}, | ||
813 | |||
814 | {"HSL Enable", NULL, "HSL Mute"}, | ||
815 | {"HSR Enable", NULL, "HSR Mute"}, | ||
816 | |||
817 | {"HSL Volume", NULL, "HSL Enable"}, | ||
818 | {"HSR Volume", NULL, "HSR Enable"}, | ||
819 | |||
820 | {"Headset Left", NULL, "HSL Volume"}, | ||
821 | {"Headset Right", NULL, "HSR Volume"}, | ||
822 | |||
823 | /* HF or LineOut path */ | ||
824 | |||
825 | {"DA_IN3", NULL, "ab8500_0p"}, | ||
826 | {"DA3 Channel Volume", NULL, "DA_IN3"}, | ||
827 | {"DA_IN4", NULL, "ab8500_0p"}, | ||
828 | {"DA4 Channel Volume", NULL, "DA_IN4"}, | ||
829 | |||
830 | {"Speaker Left Source", "Audio Path", "DA3 Channel Volume"}, | ||
831 | {"Speaker Right Source", "Audio Path", "DA4 Channel Volume"}, | ||
832 | |||
833 | {"DA3 or ANC path to HfL", NULL, "Speaker Left Source"}, | ||
834 | {"DA4 or ANC path to HfR", NULL, "Speaker Right Source"}, | ||
835 | |||
836 | /* HF path */ | ||
837 | |||
838 | {"HFL DAC", NULL, "DA3 or ANC path to HfL"}, | ||
839 | {"HFR DAC", NULL, "DA4 or ANC path to HfR"}, | ||
840 | |||
841 | {"HFL Enable", NULL, "HFL DAC"}, | ||
842 | {"HFR Enable", NULL, "HFR DAC"}, | ||
843 | |||
844 | {"Speaker Left", NULL, "HFL Enable"}, | ||
845 | {"Speaker Right", NULL, "HFR Enable"}, | ||
846 | |||
847 | /* Earpiece path */ | ||
848 | |||
849 | {"Earpiece or LineOut Mono Source", "Headset Left", | ||
850 | "HSL Digital Volume"}, | ||
851 | {"Earpiece or LineOut Mono Source", "Speaker Left", | ||
852 | "DA3 or ANC path to HfL"}, | ||
853 | |||
854 | {"EAR DAC", NULL, "Earpiece or LineOut Mono Source"}, | ||
855 | |||
856 | {"EAR Mute", NULL, "EAR DAC"}, | ||
857 | |||
858 | {"EAR Enable", NULL, "EAR Mute"}, | ||
859 | |||
860 | {"Earpiece", NULL, "EAR Enable"}, | ||
861 | |||
862 | /* LineOut path stereo */ | ||
863 | |||
864 | {"LineOut Source", "Stereo Path", "HSL DAC Driver"}, | ||
865 | {"LineOut Source", "Stereo Path", "HSR DAC Driver"}, | ||
866 | |||
867 | /* LineOut path mono */ | ||
868 | |||
869 | {"LineOut Source", "Mono Path", "EAR DAC"}, | ||
870 | |||
871 | /* LineOut path */ | ||
872 | |||
873 | {"LOL Disable HFL", NULL, "LineOut Source"}, | ||
874 | {"LOR Disable HFR", NULL, "LineOut Source"}, | ||
875 | |||
876 | {"LOL Enable", NULL, "LOL Disable HFL"}, | ||
877 | {"LOR Enable", NULL, "LOR Disable HFR"}, | ||
878 | |||
879 | {"LineOut Left", NULL, "LOL Enable"}, | ||
880 | {"LineOut Right", NULL, "LOR Enable"}, | ||
881 | |||
882 | /* Vibrator path */ | ||
883 | |||
884 | {"DA_IN5", NULL, "ab8500_0p"}, | ||
885 | {"DA5 Channel Volume", NULL, "DA_IN5"}, | ||
886 | {"DA_IN6", NULL, "ab8500_0p"}, | ||
887 | {"DA6 Channel Volume", NULL, "DA_IN6"}, | ||
888 | |||
889 | {"VIB1 DAC", NULL, "DA5 Channel Volume"}, | ||
890 | {"VIB2 DAC", NULL, "DA6 Channel Volume"}, | ||
891 | |||
892 | {"Vibra 1 Controller", "Audio Path", "VIB1 DAC"}, | ||
893 | {"Vibra 2 Controller", "Audio Path", "VIB2 DAC"}, | ||
894 | {"Vibra 1 Controller", "PWM Generator", "PWMGEN1"}, | ||
895 | {"Vibra 2 Controller", "PWM Generator", "PWMGEN2"}, | ||
896 | |||
897 | {"VIB1 Enable", NULL, "Vibra 1 Controller"}, | ||
898 | {"VIB2 Enable", NULL, "Vibra 2 Controller"}, | ||
899 | |||
900 | {"Vibra 1", NULL, "VIB1 Enable"}, | ||
901 | {"Vibra 2", NULL, "VIB2 Enable"}, | ||
902 | |||
903 | |||
904 | /* Mic 2 */ | ||
905 | |||
906 | {"MIC2 V-AMICx Enable", NULL, "Mic 2"}, | ||
907 | |||
908 | /* LineIn */ | ||
909 | {"LINL Mute", NULL, "LineIn Left"}, | ||
910 | {"LINR Mute", NULL, "LineIn Right"}, | ||
911 | |||
912 | {"LINL Enable", NULL, "LINL Mute"}, | ||
913 | {"LINR Enable", NULL, "LINR Mute"}, | ||
914 | |||
915 | /* LineIn, Mic 2 */ | ||
916 | {"Mic 2 or LINR Select", "LineIn Right", "LINR Enable"}, | ||
917 | {"Mic 2 or LINR Select", "Mic 2", "MIC2 V-AMICx Enable"}, | ||
918 | |||
919 | {"LINL ADC", NULL, "LINL Enable"}, | ||
920 | {"LINR ADC", NULL, "Mic 2 or LINR Select"}, | ||
921 | |||
922 | {"AD1 Source Select", "LineIn Left", "LINL ADC"}, | ||
923 | {"AD2 Source Select", "LineIn Right", "LINR ADC"}, | ||
924 | |||
925 | {"AD1 Channel Volume", NULL, "AD1 Source Select"}, | ||
926 | {"AD2 Channel Volume", NULL, "AD2 Source Select"}, | ||
927 | |||
928 | {"AD12 Enable", NULL, "AD1 Channel Volume"}, | ||
929 | {"AD12 Enable", NULL, "AD2 Channel Volume"}, | ||
930 | |||
931 | {"AD_OUT1", NULL, "ab8500_0c"}, | ||
932 | {"AD_OUT1", NULL, "AD12 Enable"}, | ||
933 | {"AD_OUT2", NULL, "ab8500_0c"}, | ||
934 | {"AD_OUT2", NULL, "AD12 Enable"}, | ||
935 | |||
936 | /* Mic 1 */ | ||
937 | |||
938 | {"MIC1 Mute", NULL, "Mic 1"}, | ||
939 | |||
940 | {"MIC1A V-AMICx Enable", NULL, "MIC1 Mute"}, | ||
941 | {"MIC1B V-AMICx Enable", NULL, "MIC1 Mute"}, | ||
942 | |||
943 | {"Mic 1a or 1b Select", "Mic 1a", "MIC1A V-AMICx Enable"}, | ||
944 | {"Mic 1a or 1b Select", "Mic 1b", "MIC1B V-AMICx Enable"}, | ||
945 | |||
946 | {"MIC1 ADC", NULL, "Mic 1a or 1b Select"}, | ||
947 | |||
948 | {"AD3 Source Select", "Mic 1", "MIC1 ADC"}, | ||
949 | |||
950 | {"AD3 Channel Volume", NULL, "AD3 Source Select"}, | ||
951 | |||
952 | {"AD3 Enable", NULL, "AD3 Channel Volume"}, | ||
953 | |||
954 | {"AD_OUT3", NULL, "ab8500_0c"}, | ||
955 | {"AD_OUT3", NULL, "AD3 Enable"}, | ||
956 | |||
957 | /* HD Capture path */ | ||
958 | |||
959 | {"AD5 Source Select", "Mic 2", "LINR ADC"}, | ||
960 | {"AD6 Source Select", "Mic 1", "MIC1 ADC"}, | ||
961 | |||
962 | {"AD5 Channel Volume", NULL, "AD5 Source Select"}, | ||
963 | {"AD6 Channel Volume", NULL, "AD6 Source Select"}, | ||
964 | |||
965 | {"AD57 Enable", NULL, "AD5 Channel Volume"}, | ||
966 | {"AD68 Enable", NULL, "AD6 Channel Volume"}, | ||
967 | |||
968 | {"AD_OUT57", NULL, "ab8500_0c"}, | ||
969 | {"AD_OUT57", NULL, "AD57 Enable"}, | ||
970 | {"AD_OUT68", NULL, "ab8500_0c"}, | ||
971 | {"AD_OUT68", NULL, "AD68 Enable"}, | ||
972 | |||
973 | /* Digital Microphone path */ | ||
974 | |||
975 | {"DMic 1", NULL, "V-DMIC"}, | ||
976 | {"DMic 2", NULL, "V-DMIC"}, | ||
977 | {"DMic 3", NULL, "V-DMIC"}, | ||
978 | {"DMic 4", NULL, "V-DMIC"}, | ||
979 | {"DMic 5", NULL, "V-DMIC"}, | ||
980 | {"DMic 6", NULL, "V-DMIC"}, | ||
981 | |||
982 | {"AD1 Source Select", NULL, "DMic 1"}, | ||
983 | {"AD2 Source Select", NULL, "DMic 2"}, | ||
984 | {"AD3 Source Select", NULL, "DMic 3"}, | ||
985 | {"AD5 Source Select", NULL, "DMic 5"}, | ||
986 | {"AD6 Source Select", NULL, "DMic 6"}, | ||
987 | |||
988 | {"AD4 Channel Volume", NULL, "DMic 4"}, | ||
989 | {"AD4 Enable", NULL, "AD4 Channel Volume"}, | ||
990 | |||
991 | {"AD_OUT4", NULL, "ab8500_0c"}, | ||
992 | {"AD_OUT4", NULL, "AD4 Enable"}, | ||
993 | |||
994 | /* LineIn Bypass path */ | ||
995 | |||
996 | {"LINL to HSL Volume", NULL, "LINL Enable"}, | ||
997 | {"LINR to HSR Volume", NULL, "LINR Enable"}, | ||
998 | |||
999 | {"HSL DAC Driver", NULL, "LINL to HSL Volume"}, | ||
1000 | {"HSR DAC Driver", NULL, "LINR to HSR Volume"}, | ||
1001 | |||
1002 | /* ANC path (Acoustic Noise Cancellation) */ | ||
1003 | |||
1004 | {"ANC Source", "Mic 2 / DMic 5", "AD5 Channel Volume"}, | ||
1005 | {"ANC Source", "Mic 1 / DMic 6", "AD6 Channel Volume"}, | ||
1006 | |||
1007 | {"ANC", "Switch", "ANC Source"}, | ||
1008 | |||
1009 | {"Speaker Left Source", "ANC", "ANC"}, | ||
1010 | {"Speaker Right Source", "ANC", "ANC"}, | ||
1011 | {"ANC to Earpiece", "Switch", "ANC"}, | ||
1012 | |||
1013 | {"HSL Digital Volume", NULL, "ANC to Earpiece"}, | ||
1014 | |||
1015 | /* Sidetone Filter path */ | ||
1016 | |||
1017 | {"Sidetone Left Source", "LineIn Left", "AD12 Enable"}, | ||
1018 | {"Sidetone Left Source", "LineIn Right", "AD12 Enable"}, | ||
1019 | {"Sidetone Left Source", "Mic 1", "AD3 Enable"}, | ||
1020 | {"Sidetone Left Source", "Headset Left", "DA_IN1"}, | ||
1021 | {"Sidetone Right Source", "LineIn Right", "AD12 Enable"}, | ||
1022 | {"Sidetone Right Source", "Mic 1", "AD3 Enable"}, | ||
1023 | {"Sidetone Right Source", "DMic 4", "AD4 Enable"}, | ||
1024 | {"Sidetone Right Source", "Headset Right", "DA_IN2"}, | ||
1025 | |||
1026 | {"STFIR1 Control", NULL, "Sidetone Left Source"}, | ||
1027 | {"STFIR2 Control", NULL, "Sidetone Right Source"}, | ||
1028 | |||
1029 | {"STFIR1 Volume", NULL, "STFIR1 Control"}, | ||
1030 | {"STFIR2 Volume", NULL, "STFIR2 Control"}, | ||
1031 | |||
1032 | {"DA1 Enable", NULL, "STFIR1 Volume"}, | ||
1033 | {"DA2 Enable", NULL, "STFIR2 Volume"}, | ||
1034 | }; | ||
1035 | |||
1036 | static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1a_vamicx[] = { | ||
1037 | {"MIC1A V-AMICx Enable", NULL, "V-AMIC1"}, | ||
1038 | {"MIC1A V-AMICx Enable", NULL, "V-AMIC2"}, | ||
1039 | }; | ||
1040 | |||
1041 | static const struct snd_soc_dapm_route ab8500_dapm_routes_mic1b_vamicx[] = { | ||
1042 | {"MIC1B V-AMICx Enable", NULL, "V-AMIC1"}, | ||
1043 | {"MIC1B V-AMICx Enable", NULL, "V-AMIC2"}, | ||
1044 | }; | ||
1045 | |||
1046 | static const struct snd_soc_dapm_route ab8500_dapm_routes_mic2_vamicx[] = { | ||
1047 | {"MIC2 V-AMICx Enable", NULL, "V-AMIC1"}, | ||
1048 | {"MIC2 V-AMICx Enable", NULL, "V-AMIC2"}, | ||
1049 | }; | ||
1050 | |||
1051 | /* ANC FIR-coefficients configuration sequence */ | ||
1052 | static void anc_fir(struct snd_soc_codec *codec, | ||
1053 | unsigned int bnk, unsigned int par, unsigned int val) | ||
1054 | { | ||
1055 | if (par == 0 && bnk == 0) | ||
1056 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1057 | BIT(AB8500_ANCCONF1_ANCFIRUPDATE), | ||
1058 | BIT(AB8500_ANCCONF1_ANCFIRUPDATE)); | ||
1059 | |||
1060 | snd_soc_write(codec, AB8500_ANCCONF5, val >> 8 & 0xff); | ||
1061 | snd_soc_write(codec, AB8500_ANCCONF6, val & 0xff); | ||
1062 | |||
1063 | if (par == AB8500_ANC_FIR_COEFFS - 1 && bnk == 1) | ||
1064 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1065 | BIT(AB8500_ANCCONF1_ANCFIRUPDATE), 0); | ||
1066 | } | ||
1067 | |||
1068 | /* ANC IIR-coefficients configuration sequence */ | ||
1069 | static void anc_iir(struct snd_soc_codec *codec, unsigned int bnk, | ||
1070 | unsigned int par, unsigned int val) | ||
1071 | { | ||
1072 | if (par == 0) { | ||
1073 | if (bnk == 0) { | ||
1074 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1075 | BIT(AB8500_ANCCONF1_ANCIIRINIT), | ||
1076 | BIT(AB8500_ANCCONF1_ANCIIRINIT)); | ||
1077 | usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY); | ||
1078 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1079 | BIT(AB8500_ANCCONF1_ANCIIRINIT), 0); | ||
1080 | usleep_range(AB8500_ANC_SM_DELAY, AB8500_ANC_SM_DELAY); | ||
1081 | } else { | ||
1082 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1083 | BIT(AB8500_ANCCONF1_ANCIIRUPDATE), | ||
1084 | BIT(AB8500_ANCCONF1_ANCIIRUPDATE)); | ||
1085 | } | ||
1086 | } else if (par > 3) { | ||
1087 | snd_soc_write(codec, AB8500_ANCCONF7, 0); | ||
1088 | snd_soc_write(codec, AB8500_ANCCONF8, val >> 16 & 0xff); | ||
1089 | } | ||
1090 | |||
1091 | snd_soc_write(codec, AB8500_ANCCONF7, val >> 8 & 0xff); | ||
1092 | snd_soc_write(codec, AB8500_ANCCONF8, val & 0xff); | ||
1093 | |||
1094 | if (par == AB8500_ANC_IIR_COEFFS - 1 && bnk == 1) | ||
1095 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1096 | BIT(AB8500_ANCCONF1_ANCIIRUPDATE), 0); | ||
1097 | } | ||
1098 | |||
1099 | /* ANC IIR-/FIR-coefficients configuration sequence */ | ||
1100 | static void anc_configure(struct snd_soc_codec *codec, | ||
1101 | bool apply_fir, bool apply_iir) | ||
1102 | { | ||
1103 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | ||
1104 | unsigned int bnk, par, val; | ||
1105 | |||
1106 | dev_dbg(codec->dev, "%s: Enter.\n", __func__); | ||
1107 | |||
1108 | if (apply_fir) | ||
1109 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1110 | BIT(AB8500_ANCCONF1_ENANC), 0); | ||
1111 | |||
1112 | snd_soc_update_bits(codec, AB8500_ANCCONF1, | ||
1113 | BIT(AB8500_ANCCONF1_ENANC), BIT(AB8500_ANCCONF1_ENANC)); | ||
1114 | |||
1115 | if (apply_fir) | ||
1116 | for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++) | ||
1117 | for (par = 0; par < AB8500_ANC_FIR_COEFFS; par++) { | ||
1118 | val = snd_soc_read(codec, | ||
1119 | drvdata->anc_fir_values[par]); | ||
1120 | anc_fir(codec, bnk, par, val); | ||
1121 | } | ||
1122 | |||
1123 | if (apply_iir) | ||
1124 | for (bnk = 0; bnk < AB8500_NR_OF_ANC_COEFF_BANKS; bnk++) | ||
1125 | for (par = 0; par < AB8500_ANC_IIR_COEFFS; par++) { | ||
1126 | val = snd_soc_read(codec, | ||
1127 | drvdata->anc_iir_values[par]); | ||
1128 | anc_iir(codec, bnk, par, val); | ||
1129 | } | ||
1130 | |||
1131 | dev_dbg(codec->dev, "%s: Exit.\n", __func__); | ||
1132 | } | ||
1133 | |||
1134 | /* | ||
1135 | * Control-events | ||
1136 | */ | ||
1137 | |||
1138 | static int sid_status_control_get(struct snd_kcontrol *kcontrol, | ||
1139 | struct snd_ctl_elem_value *ucontrol) | ||
1140 | { | ||
1141 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1142 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | ||
1143 | |||
1144 | mutex_lock(&codec->mutex); | ||
1145 | ucontrol->value.integer.value[0] = drvdata->sid_status; | ||
1146 | mutex_unlock(&codec->mutex); | ||
1147 | |||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | /* Write sidetone FIR-coefficients configuration sequence */ | ||
1152 | static int sid_status_control_put(struct snd_kcontrol *kcontrol, | ||
1153 | struct snd_ctl_elem_value *ucontrol) | ||
1154 | { | ||
1155 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1156 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | ||
1157 | unsigned int param, sidconf, val; | ||
1158 | int status = 1; | ||
1159 | |||
1160 | dev_dbg(codec->dev, "%s: Enter\n", __func__); | ||
1161 | |||
1162 | if (ucontrol->value.integer.value[0] != SID_APPLY_FIR) { | ||
1163 | dev_err(codec->dev, | ||
1164 | "%s: ERROR: This control supports '%s' only!\n", | ||
1165 | __func__, enum_sid_state[SID_APPLY_FIR]); | ||
1166 | return -EIO; | ||
1167 | } | ||
1168 | |||
1169 | mutex_lock(&codec->mutex); | ||
1170 | |||
1171 | sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF); | ||
1172 | if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) { | ||
1173 | if ((sidconf & BIT(AB8500_SIDFIRCONF_ENFIRSIDS)) == 0) { | ||
1174 | dev_err(codec->dev, "%s: Sidetone busy while off!\n", | ||
1175 | __func__); | ||
1176 | status = -EPERM; | ||
1177 | } else { | ||
1178 | status = -EBUSY; | ||
1179 | } | ||
1180 | goto out; | ||
1181 | } | ||
1182 | |||
1183 | snd_soc_write(codec, AB8500_SIDFIRADR, 0); | ||
1184 | |||
1185 | for (param = 0; param < AB8500_SID_FIR_COEFFS; param++) { | ||
1186 | val = snd_soc_read(codec, drvdata->sid_fir_values[param]); | ||
1187 | snd_soc_write(codec, AB8500_SIDFIRCOEF1, val >> 8 & 0xff); | ||
1188 | snd_soc_write(codec, AB8500_SIDFIRCOEF2, val & 0xff); | ||
1189 | } | ||
1190 | |||
1191 | snd_soc_update_bits(codec, AB8500_SIDFIRADR, | ||
1192 | BIT(AB8500_SIDFIRADR_FIRSIDSET), | ||
1193 | BIT(AB8500_SIDFIRADR_FIRSIDSET)); | ||
1194 | snd_soc_update_bits(codec, AB8500_SIDFIRADR, | ||
1195 | BIT(AB8500_SIDFIRADR_FIRSIDSET), 0); | ||
1196 | |||
1197 | drvdata->sid_status = SID_FIR_CONFIGURED; | ||
1198 | |||
1199 | out: | ||
1200 | mutex_unlock(&codec->mutex); | ||
1201 | |||
1202 | dev_dbg(codec->dev, "%s: Exit\n", __func__); | ||
1203 | |||
1204 | return status; | ||
1205 | } | ||
1206 | |||
1207 | static int anc_status_control_get(struct snd_kcontrol *kcontrol, | ||
1208 | struct snd_ctl_elem_value *ucontrol) | ||
1209 | { | ||
1210 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1211 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | ||
1212 | |||
1213 | mutex_lock(&codec->mutex); | ||
1214 | ucontrol->value.integer.value[0] = drvdata->anc_status; | ||
1215 | mutex_unlock(&codec->mutex); | ||
1216 | |||
1217 | return 0; | ||
1218 | } | ||
1219 | |||
1220 | static int anc_status_control_put(struct snd_kcontrol *kcontrol, | ||
1221 | struct snd_ctl_elem_value *ucontrol) | ||
1222 | { | ||
1223 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1224 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev); | ||
1225 | struct device *dev = codec->dev; | ||
1226 | bool apply_fir, apply_iir; | ||
1227 | int req, status; | ||
1228 | |||
1229 | dev_dbg(dev, "%s: Enter.\n", __func__); | ||
1230 | |||
1231 | mutex_lock(&drvdata->anc_lock); | ||
1232 | |||
1233 | req = ucontrol->value.integer.value[0]; | ||
1234 | if (req != ANC_APPLY_FIR_IIR && req != ANC_APPLY_FIR && | ||
1235 | req != ANC_APPLY_IIR) { | ||
1236 | dev_err(dev, "%s: ERROR: Unsupported status to set '%s'!\n", | ||
1237 | __func__, enum_anc_state[req]); | ||
1238 | status = -EINVAL; | ||
1239 | goto cleanup; | ||
1240 | } | ||
1241 | apply_fir = req == ANC_APPLY_FIR || req == ANC_APPLY_FIR_IIR; | ||
1242 | apply_iir = req == ANC_APPLY_IIR || req == ANC_APPLY_FIR_IIR; | ||
1243 | |||
1244 | status = snd_soc_dapm_force_enable_pin(&codec->dapm, | ||
1245 | "ANC Configure Input"); | ||
1246 | if (status < 0) { | ||
1247 | dev_err(dev, | ||
1248 | "%s: ERROR: Failed to enable power (status = %d)!\n", | ||
1249 | __func__, status); | ||
1250 | goto cleanup; | ||
1251 | } | ||
1252 | snd_soc_dapm_sync(&codec->dapm); | ||
1253 | |||
1254 | mutex_lock(&codec->mutex); | ||
1255 | anc_configure(codec, apply_fir, apply_iir); | ||
1256 | mutex_unlock(&codec->mutex); | ||
1257 | |||
1258 | if (apply_fir) { | ||
1259 | if (drvdata->anc_status == ANC_IIR_CONFIGURED) | ||
1260 | drvdata->anc_status = ANC_FIR_IIR_CONFIGURED; | ||
1261 | else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED) | ||
1262 | drvdata->anc_status = ANC_FIR_CONFIGURED; | ||
1263 | } | ||
1264 | if (apply_iir) { | ||
1265 | if (drvdata->anc_status == ANC_FIR_CONFIGURED) | ||
1266 | drvdata->anc_status = ANC_FIR_IIR_CONFIGURED; | ||
1267 | else if (drvdata->anc_status != ANC_FIR_IIR_CONFIGURED) | ||
1268 | drvdata->anc_status = ANC_IIR_CONFIGURED; | ||
1269 | } | ||
1270 | |||
1271 | status = snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | ||
1272 | snd_soc_dapm_sync(&codec->dapm); | ||
1273 | |||
1274 | cleanup: | ||
1275 | mutex_unlock(&drvdata->anc_lock); | ||
1276 | |||
1277 | if (status < 0) | ||
1278 | dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n", | ||
1279 | __func__, status); | ||
1280 | |||
1281 | dev_dbg(dev, "%s: Exit.\n", __func__); | ||
1282 | |||
1283 | return (status < 0) ? status : 1; | ||
1284 | } | ||
1285 | |||
1286 | static int filter_control_info(struct snd_kcontrol *kcontrol, | ||
1287 | struct snd_ctl_elem_info *uinfo) | ||
1288 | { | ||
1289 | struct filter_control *fc = | ||
1290 | (struct filter_control *)kcontrol->private_value; | ||
1291 | |||
1292 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
1293 | uinfo->count = fc->count; | ||
1294 | uinfo->value.integer.min = fc->min; | ||
1295 | uinfo->value.integer.max = fc->max; | ||
1296 | |||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | static int filter_control_get(struct snd_kcontrol *kcontrol, | ||
1301 | struct snd_ctl_elem_value *ucontrol) | ||
1302 | { | ||
1303 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1304 | struct filter_control *fc = | ||
1305 | (struct filter_control *)kcontrol->private_value; | ||
1306 | unsigned int i; | ||
1307 | |||
1308 | mutex_lock(&codec->mutex); | ||
1309 | for (i = 0; i < fc->count; i++) | ||
1310 | ucontrol->value.integer.value[i] = fc->value[i]; | ||
1311 | mutex_unlock(&codec->mutex); | ||
1312 | |||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | static int filter_control_put(struct snd_kcontrol *kcontrol, | ||
1317 | struct snd_ctl_elem_value *ucontrol) | ||
1318 | { | ||
1319 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
1320 | struct filter_control *fc = | ||
1321 | (struct filter_control *)kcontrol->private_value; | ||
1322 | unsigned int i; | ||
1323 | |||
1324 | mutex_lock(&codec->mutex); | ||
1325 | for (i = 0; i < fc->count; i++) | ||
1326 | fc->value[i] = ucontrol->value.integer.value[i]; | ||
1327 | mutex_unlock(&codec->mutex); | ||
1328 | |||
1329 | return 0; | ||
1330 | } | ||
1331 | |||
1332 | /* | ||
1333 | * Controls - Non-DAPM ASoC | ||
1334 | */ | ||
1335 | |||
1336 | static DECLARE_TLV_DB_SCALE(adx_dig_gain_tlv, -3200, 100, 1); | ||
1337 | /* -32dB = Mute */ | ||
1338 | |||
1339 | static DECLARE_TLV_DB_SCALE(dax_dig_gain_tlv, -6300, 100, 1); | ||
1340 | /* -63dB = Mute */ | ||
1341 | |||
1342 | static DECLARE_TLV_DB_SCALE(hs_ear_dig_gain_tlv, -100, 100, 1); | ||
1343 | /* -1dB = Mute */ | ||
1344 | |||
1345 | static const unsigned int hs_gain_tlv[] = { | ||
1346 | TLV_DB_RANGE_HEAD(2), | ||
1347 | 0, 3, TLV_DB_SCALE_ITEM(-3200, 400, 0), | ||
1348 | 4, 15, TLV_DB_SCALE_ITEM(-1800, 200, 0), | ||
1349 | }; | ||
1350 | |||
1351 | static DECLARE_TLV_DB_SCALE(mic_gain_tlv, 0, 100, 0); | ||
1352 | |||
1353 | static DECLARE_TLV_DB_SCALE(lin_gain_tlv, -1000, 200, 0); | ||
1354 | |||
1355 | static DECLARE_TLV_DB_SCALE(lin2hs_gain_tlv, -3800, 200, 1); | ||
1356 | /* -38dB = Mute */ | ||
1357 | |||
1358 | static const char * const enum_hsfadspeed[] = {"2ms", "0.5ms", "10.6ms", | ||
1359 | "5ms"}; | ||
1360 | static SOC_ENUM_SINGLE_DECL(soc_enum_hsfadspeed, | ||
1361 | AB8500_DIGMICCONF, AB8500_DIGMICCONF_HSFADSPEED, enum_hsfadspeed); | ||
1362 | |||
1363 | static const char * const enum_envdetthre[] = { | ||
1364 | "250mV", "300mV", "350mV", "400mV", | ||
1365 | "450mV", "500mV", "550mV", "600mV", | ||
1366 | "650mV", "700mV", "750mV", "800mV", | ||
1367 | "850mV", "900mV", "950mV", "1.00V" }; | ||
1368 | static SOC_ENUM_SINGLE_DECL(soc_enum_envdeththre, | ||
1369 | AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETHTHRE, enum_envdetthre); | ||
1370 | static SOC_ENUM_SINGLE_DECL(soc_enum_envdetlthre, | ||
1371 | AB8500_ENVCPCONF, AB8500_ENVCPCONF_ENVDETLTHRE, enum_envdetthre); | ||
1372 | static const char * const enum_envdettime[] = { | ||
1373 | "26.6us", "53.2us", "106us", "213us", | ||
1374 | "426us", "851us", "1.70ms", "3.40ms", | ||
1375 | "6.81ms", "13.6ms", "27.2ms", "54.5ms", | ||
1376 | "109ms", "218ms", "436ms", "872ms" }; | ||
1377 | static SOC_ENUM_SINGLE_DECL(soc_enum_envdettime, | ||
1378 | AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETTIME, enum_envdettime); | ||
1379 | |||
1380 | static const char * const enum_sinc31[] = {"Sinc 3", "Sinc 1"}; | ||
1381 | static SOC_ENUM_SINGLE_DECL(soc_enum_hsesinc, AB8500_HSLEARDIGGAIN, | ||
1382 | AB8500_HSLEARDIGGAIN_HSSINC1, enum_sinc31); | ||
1383 | |||
1384 | static const char * const enum_fadespeed[] = {"1ms", "4ms", "8ms", "16ms"}; | ||
1385 | static SOC_ENUM_SINGLE_DECL(soc_enum_fadespeed, AB8500_HSRDIGGAIN, | ||
1386 | AB8500_HSRDIGGAIN_FADESPEED, enum_fadespeed); | ||
1387 | |||
1388 | /* Earpiece */ | ||
1389 | |||
1390 | static const char * const enum_lowpow[] = {"Normal", "Low Power"}; | ||
1391 | static SOC_ENUM_SINGLE_DECL(soc_enum_eardaclowpow, AB8500_ANACONF1, | ||
1392 | AB8500_ANACONF1_EARDACLOWPOW, enum_lowpow); | ||
1393 | static SOC_ENUM_SINGLE_DECL(soc_enum_eardrvlowpow, AB8500_ANACONF1, | ||
1394 | AB8500_ANACONF1_EARDRVLOWPOW, enum_lowpow); | ||
1395 | |||
1396 | static const char * const enum_av_mode[] = {"Audio", "Voice"}; | ||
1397 | static SOC_ENUM_DOUBLE_DECL(soc_enum_ad12voice, AB8500_ADFILTCONF, | ||
1398 | AB8500_ADFILTCONF_AD1VOICE, AB8500_ADFILTCONF_AD2VOICE, enum_av_mode); | ||
1399 | static SOC_ENUM_DOUBLE_DECL(soc_enum_ad34voice, AB8500_ADFILTCONF, | ||
1400 | AB8500_ADFILTCONF_AD3VOICE, AB8500_ADFILTCONF_AD4VOICE, enum_av_mode); | ||
1401 | |||
1402 | /* DA */ | ||
1403 | |||
1404 | static SOC_ENUM_SINGLE_DECL(soc_enum_da12voice, | ||
1405 | AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DA12VOICE, | ||
1406 | enum_av_mode); | ||
1407 | static SOC_ENUM_SINGLE_DECL(soc_enum_da34voice, | ||
1408 | AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DA34VOICE, | ||
1409 | enum_av_mode); | ||
1410 | static SOC_ENUM_SINGLE_DECL(soc_enum_da56voice, | ||
1411 | AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DA56VOICE, | ||
1412 | enum_av_mode); | ||
1413 | |||
1414 | static const char * const enum_da2hslr[] = {"Sidetone", "Audio Path"}; | ||
1415 | static SOC_ENUM_DOUBLE_DECL(soc_enum_da2hslr, AB8500_DIGMULTCONF1, | ||
1416 | AB8500_DIGMULTCONF1_DATOHSLEN, | ||
1417 | AB8500_DIGMULTCONF1_DATOHSREN, enum_da2hslr); | ||
1418 | |||
1419 | static const char * const enum_sinc53[] = {"Sinc 5", "Sinc 3"}; | ||
1420 | static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic12sinc, AB8500_DMICFILTCONF, | ||
1421 | AB8500_DMICFILTCONF_DMIC1SINC3, | ||
1422 | AB8500_DMICFILTCONF_DMIC2SINC3, enum_sinc53); | ||
1423 | static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic34sinc, AB8500_DMICFILTCONF, | ||
1424 | AB8500_DMICFILTCONF_DMIC3SINC3, | ||
1425 | AB8500_DMICFILTCONF_DMIC4SINC3, enum_sinc53); | ||
1426 | static SOC_ENUM_DOUBLE_DECL(soc_enum_dmic56sinc, AB8500_DMICFILTCONF, | ||
1427 | AB8500_DMICFILTCONF_DMIC5SINC3, | ||
1428 | AB8500_DMICFILTCONF_DMIC6SINC3, enum_sinc53); | ||
1429 | |||
1430 | /* Digital interface - DA from slot mapping */ | ||
1431 | static const char * const enum_da_from_slot_map[] = {"SLOT0", | ||
1432 | "SLOT1", | ||
1433 | "SLOT2", | ||
1434 | "SLOT3", | ||
1435 | "SLOT4", | ||
1436 | "SLOT5", | ||
1437 | "SLOT6", | ||
1438 | "SLOT7", | ||
1439 | "SLOT8", | ||
1440 | "SLOT9", | ||
1441 | "SLOT10", | ||
1442 | "SLOT11", | ||
1443 | "SLOT12", | ||
1444 | "SLOT13", | ||
1445 | "SLOT14", | ||
1446 | "SLOT15", | ||
1447 | "SLOT16", | ||
1448 | "SLOT17", | ||
1449 | "SLOT18", | ||
1450 | "SLOT19", | ||
1451 | "SLOT20", | ||
1452 | "SLOT21", | ||
1453 | "SLOT22", | ||
1454 | "SLOT23", | ||
1455 | "SLOT24", | ||
1456 | "SLOT25", | ||
1457 | "SLOT26", | ||
1458 | "SLOT27", | ||
1459 | "SLOT28", | ||
1460 | "SLOT29", | ||
1461 | "SLOT30", | ||
1462 | "SLOT31"}; | ||
1463 | static SOC_ENUM_SINGLE_DECL(soc_enum_da1slotmap, | ||
1464 | AB8500_DASLOTCONF1, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1465 | enum_da_from_slot_map); | ||
1466 | static SOC_ENUM_SINGLE_DECL(soc_enum_da2slotmap, | ||
1467 | AB8500_DASLOTCONF2, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1468 | enum_da_from_slot_map); | ||
1469 | static SOC_ENUM_SINGLE_DECL(soc_enum_da3slotmap, | ||
1470 | AB8500_DASLOTCONF3, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1471 | enum_da_from_slot_map); | ||
1472 | static SOC_ENUM_SINGLE_DECL(soc_enum_da4slotmap, | ||
1473 | AB8500_DASLOTCONF4, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1474 | enum_da_from_slot_map); | ||
1475 | static SOC_ENUM_SINGLE_DECL(soc_enum_da5slotmap, | ||
1476 | AB8500_DASLOTCONF5, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1477 | enum_da_from_slot_map); | ||
1478 | static SOC_ENUM_SINGLE_DECL(soc_enum_da6slotmap, | ||
1479 | AB8500_DASLOTCONF6, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1480 | enum_da_from_slot_map); | ||
1481 | static SOC_ENUM_SINGLE_DECL(soc_enum_da7slotmap, | ||
1482 | AB8500_DASLOTCONF7, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1483 | enum_da_from_slot_map); | ||
1484 | static SOC_ENUM_SINGLE_DECL(soc_enum_da8slotmap, | ||
1485 | AB8500_DASLOTCONF8, AB8500_DASLOTCONFX_SLTODAX_SHIFT, | ||
1486 | enum_da_from_slot_map); | ||
1487 | |||
1488 | /* Digital interface - AD to slot mapping */ | ||
1489 | static const char * const enum_ad_to_slot_map[] = {"AD_OUT1", | ||
1490 | "AD_OUT2", | ||
1491 | "AD_OUT3", | ||
1492 | "AD_OUT4", | ||
1493 | "AD_OUT5", | ||
1494 | "AD_OUT6", | ||
1495 | "AD_OUT7", | ||
1496 | "AD_OUT8", | ||
1497 | "zeroes", | ||
1498 | "tristate"}; | ||
1499 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot0map, | ||
1500 | AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1501 | enum_ad_to_slot_map); | ||
1502 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot1map, | ||
1503 | AB8500_ADSLOTSEL1, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1504 | enum_ad_to_slot_map); | ||
1505 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot2map, | ||
1506 | AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1507 | enum_ad_to_slot_map); | ||
1508 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot3map, | ||
1509 | AB8500_ADSLOTSEL2, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1510 | enum_ad_to_slot_map); | ||
1511 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot4map, | ||
1512 | AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1513 | enum_ad_to_slot_map); | ||
1514 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot5map, | ||
1515 | AB8500_ADSLOTSEL3, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1516 | enum_ad_to_slot_map); | ||
1517 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot6map, | ||
1518 | AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1519 | enum_ad_to_slot_map); | ||
1520 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot7map, | ||
1521 | AB8500_ADSLOTSEL4, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1522 | enum_ad_to_slot_map); | ||
1523 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot8map, | ||
1524 | AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1525 | enum_ad_to_slot_map); | ||
1526 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot9map, | ||
1527 | AB8500_ADSLOTSEL5, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1528 | enum_ad_to_slot_map); | ||
1529 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot10map, | ||
1530 | AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1531 | enum_ad_to_slot_map); | ||
1532 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot11map, | ||
1533 | AB8500_ADSLOTSEL6, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1534 | enum_ad_to_slot_map); | ||
1535 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot12map, | ||
1536 | AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1537 | enum_ad_to_slot_map); | ||
1538 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot13map, | ||
1539 | AB8500_ADSLOTSEL7, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1540 | enum_ad_to_slot_map); | ||
1541 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot14map, | ||
1542 | AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1543 | enum_ad_to_slot_map); | ||
1544 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot15map, | ||
1545 | AB8500_ADSLOTSEL8, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1546 | enum_ad_to_slot_map); | ||
1547 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot16map, | ||
1548 | AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1549 | enum_ad_to_slot_map); | ||
1550 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot17map, | ||
1551 | AB8500_ADSLOTSEL9, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1552 | enum_ad_to_slot_map); | ||
1553 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot18map, | ||
1554 | AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1555 | enum_ad_to_slot_map); | ||
1556 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot19map, | ||
1557 | AB8500_ADSLOTSEL10, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1558 | enum_ad_to_slot_map); | ||
1559 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot20map, | ||
1560 | AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1561 | enum_ad_to_slot_map); | ||
1562 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot21map, | ||
1563 | AB8500_ADSLOTSEL11, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1564 | enum_ad_to_slot_map); | ||
1565 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot22map, | ||
1566 | AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1567 | enum_ad_to_slot_map); | ||
1568 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot23map, | ||
1569 | AB8500_ADSLOTSEL12, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1570 | enum_ad_to_slot_map); | ||
1571 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot24map, | ||
1572 | AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1573 | enum_ad_to_slot_map); | ||
1574 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot25map, | ||
1575 | AB8500_ADSLOTSEL13, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1576 | enum_ad_to_slot_map); | ||
1577 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot26map, | ||
1578 | AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1579 | enum_ad_to_slot_map); | ||
1580 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot27map, | ||
1581 | AB8500_ADSLOTSEL14, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1582 | enum_ad_to_slot_map); | ||
1583 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot28map, | ||
1584 | AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1585 | enum_ad_to_slot_map); | ||
1586 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot29map, | ||
1587 | AB8500_ADSLOTSEL15, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1588 | enum_ad_to_slot_map); | ||
1589 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot30map, | ||
1590 | AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_EVEN_SHIFT, | ||
1591 | enum_ad_to_slot_map); | ||
1592 | static SOC_ENUM_SINGLE_DECL(soc_enum_adslot31map, | ||
1593 | AB8500_ADSLOTSEL16, AB8500_ADSLOTSELX_ODD_SHIFT, | ||
1594 | enum_ad_to_slot_map); | ||
1595 | |||
1596 | /* Digital interface - Burst mode */ | ||
1597 | static const char * const enum_mask[] = {"Unmasked", "Masked"}; | ||
1598 | static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomask, | ||
1599 | AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOMASK, | ||
1600 | enum_mask); | ||
1601 | static const char * const enum_bitclk0[] = {"19_2_MHz", "38_4_MHz"}; | ||
1602 | static SOC_ENUM_SINGLE_DECL(soc_enum_bfifo19m2, | ||
1603 | AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFO19M2, | ||
1604 | enum_bitclk0); | ||
1605 | static const char * const enum_slavemaster[] = {"Slave", "Master"}; | ||
1606 | static SOC_ENUM_SINGLE_DECL(soc_enum_bfifomast, | ||
1607 | AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOMAST_SHIFT, | ||
1608 | enum_slavemaster); | ||
1609 | |||
1610 | /* Sidetone */ | ||
1611 | static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_sidstate, enum_sid_state); | ||
1612 | |||
1613 | /* ANC */ | ||
1614 | static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_ancstate, enum_anc_state); | ||
1615 | |||
1616 | static struct snd_kcontrol_new ab8500_ctrls[] = { | ||
1617 | /* Charge pump */ | ||
1618 | SOC_ENUM("Charge Pump High Threshold For Low Voltage", | ||
1619 | soc_enum_envdeththre), | ||
1620 | SOC_ENUM("Charge Pump Low Threshold For Low Voltage", | ||
1621 | soc_enum_envdetlthre), | ||
1622 | SOC_SINGLE("Charge Pump Envelope Detection Switch", | ||
1623 | AB8500_SIGENVCONF, AB8500_SIGENVCONF_ENVDETCPEN, | ||
1624 | 1, 0), | ||
1625 | SOC_ENUM("Charge Pump Envelope Detection Decay Time", | ||
1626 | soc_enum_envdettime), | ||
1627 | |||
1628 | /* Headset */ | ||
1629 | SOC_ENUM("Headset Mode", soc_enum_da12voice), | ||
1630 | SOC_SINGLE("Headset High Pass Switch", | ||
1631 | AB8500_ANACONF1, AB8500_ANACONF1_HSHPEN, | ||
1632 | 1, 0), | ||
1633 | SOC_SINGLE("Headset Low Power Switch", | ||
1634 | AB8500_ANACONF1, AB8500_ANACONF1_HSLOWPOW, | ||
1635 | 1, 0), | ||
1636 | SOC_SINGLE("Headset DAC Low Power Switch", | ||
1637 | AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW1, | ||
1638 | 1, 0), | ||
1639 | SOC_SINGLE("Headset DAC Drv Low Power Switch", | ||
1640 | AB8500_ANACONF1, AB8500_ANACONF1_DACLOWPOW0, | ||
1641 | 1, 0), | ||
1642 | SOC_ENUM("Headset Fade Speed", soc_enum_hsfadspeed), | ||
1643 | SOC_ENUM("Headset Source", soc_enum_da2hslr), | ||
1644 | SOC_ENUM("Headset Filter", soc_enum_hsesinc), | ||
1645 | SOC_DOUBLE_R_TLV("Headset Master Volume", | ||
1646 | AB8500_DADIGGAIN1, AB8500_DADIGGAIN2, | ||
1647 | 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), | ||
1648 | SOC_DOUBLE_R_TLV("Headset Digital Volume", | ||
1649 | AB8500_HSLEARDIGGAIN, AB8500_HSRDIGGAIN, | ||
1650 | 0, AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX, 1, hs_ear_dig_gain_tlv), | ||
1651 | SOC_DOUBLE_TLV("Headset Volume", | ||
1652 | AB8500_ANAGAIN3, | ||
1653 | AB8500_ANAGAIN3_HSLGAIN, AB8500_ANAGAIN3_HSRGAIN, | ||
1654 | AB8500_ANAGAIN3_HSXGAIN_MAX, 1, hs_gain_tlv), | ||
1655 | |||
1656 | /* Earpiece */ | ||
1657 | SOC_ENUM("Earpiece DAC Mode", | ||
1658 | soc_enum_eardaclowpow), | ||
1659 | SOC_ENUM("Earpiece DAC Drv Mode", | ||
1660 | soc_enum_eardrvlowpow), | ||
1661 | |||
1662 | /* HandsFree */ | ||
1663 | SOC_ENUM("HF Mode", soc_enum_da34voice), | ||
1664 | SOC_SINGLE("HF and Headset Swap Switch", | ||
1665 | AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_SWAPDA12_34, | ||
1666 | 1, 0), | ||
1667 | SOC_DOUBLE("HF Low EMI Mode Switch", | ||
1668 | AB8500_CLASSDCONF1, | ||
1669 | AB8500_CLASSDCONF1_HFLSWAPEN, AB8500_CLASSDCONF1_HFRSWAPEN, | ||
1670 | 1, 0), | ||
1671 | SOC_DOUBLE("HF FIR Bypass Switch", | ||
1672 | AB8500_CLASSDCONF2, | ||
1673 | AB8500_CLASSDCONF2_FIRBYP0, AB8500_CLASSDCONF2_FIRBYP1, | ||
1674 | 1, 0), | ||
1675 | SOC_DOUBLE("HF High Volume Switch", | ||
1676 | AB8500_CLASSDCONF2, | ||
1677 | AB8500_CLASSDCONF2_HIGHVOLEN0, AB8500_CLASSDCONF2_HIGHVOLEN1, | ||
1678 | 1, 0), | ||
1679 | SOC_SINGLE("HF L and R Bridge Switch", | ||
1680 | AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLHF, | ||
1681 | 1, 0), | ||
1682 | SOC_DOUBLE_R_TLV("HF Master Volume", | ||
1683 | AB8500_DADIGGAIN3, AB8500_DADIGGAIN4, | ||
1684 | 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), | ||
1685 | |||
1686 | /* Vibra */ | ||
1687 | SOC_DOUBLE("Vibra High Volume Switch", | ||
1688 | AB8500_CLASSDCONF2, | ||
1689 | AB8500_CLASSDCONF2_HIGHVOLEN2, AB8500_CLASSDCONF2_HIGHVOLEN3, | ||
1690 | 1, 0), | ||
1691 | SOC_DOUBLE("Vibra Low EMI Mode Switch", | ||
1692 | AB8500_CLASSDCONF1, | ||
1693 | AB8500_CLASSDCONF1_VIB1SWAPEN, AB8500_CLASSDCONF1_VIB2SWAPEN, | ||
1694 | 1, 0), | ||
1695 | SOC_DOUBLE("Vibra FIR Bypass Switch", | ||
1696 | AB8500_CLASSDCONF2, | ||
1697 | AB8500_CLASSDCONF2_FIRBYP2, AB8500_CLASSDCONF2_FIRBYP3, | ||
1698 | 1, 0), | ||
1699 | SOC_ENUM("Vibra Mode", soc_enum_da56voice), | ||
1700 | SOC_DOUBLE_R("Vibra PWM Duty Cycle N", | ||
1701 | AB8500_PWMGENCONF3, AB8500_PWMGENCONF5, | ||
1702 | AB8500_PWMGENCONFX_PWMVIBXDUTCYC, | ||
1703 | AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0), | ||
1704 | SOC_DOUBLE_R("Vibra PWM Duty Cycle P", | ||
1705 | AB8500_PWMGENCONF2, AB8500_PWMGENCONF4, | ||
1706 | AB8500_PWMGENCONFX_PWMVIBXDUTCYC, | ||
1707 | AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX, 0), | ||
1708 | SOC_SINGLE("Vibra 1 and 2 Bridge Switch", | ||
1709 | AB8500_CLASSDCONF1, AB8500_CLASSDCONF1_PARLVIB, | ||
1710 | 1, 0), | ||
1711 | SOC_DOUBLE_R_TLV("Vibra Master Volume", | ||
1712 | AB8500_DADIGGAIN5, AB8500_DADIGGAIN6, | ||
1713 | 0, AB8500_DADIGGAINX_DAXGAIN_MAX, 1, dax_dig_gain_tlv), | ||
1714 | |||
1715 | /* HandsFree, Vibra */ | ||
1716 | SOC_SINGLE("ClassD High Pass Volume", | ||
1717 | AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHHPGAIN, | ||
1718 | AB8500_CLASSDCONF3_DITHHPGAIN_MAX, 0), | ||
1719 | SOC_SINGLE("ClassD White Volume", | ||
1720 | AB8500_CLASSDCONF3, AB8500_CLASSDCONF3_DITHWGAIN, | ||
1721 | AB8500_CLASSDCONF3_DITHWGAIN_MAX, 0), | ||
1722 | |||
1723 | /* Mic 1, Mic 2, LineIn */ | ||
1724 | SOC_DOUBLE_R_TLV("Mic Master Volume", | ||
1725 | AB8500_ADDIGGAIN3, AB8500_ADDIGGAIN4, | ||
1726 | 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), | ||
1727 | |||
1728 | /* Mic 1 */ | ||
1729 | SOC_SINGLE_TLV("Mic 1", | ||
1730 | AB8500_ANAGAIN1, | ||
1731 | AB8500_ANAGAINX_MICXGAIN, | ||
1732 | AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv), | ||
1733 | SOC_SINGLE("Mic 1 Low Power Switch", | ||
1734 | AB8500_ANAGAIN1, AB8500_ANAGAINX_LOWPOWMICX, | ||
1735 | 1, 0), | ||
1736 | |||
1737 | /* Mic 2 */ | ||
1738 | SOC_DOUBLE("Mic High Pass Switch", | ||
1739 | AB8500_ADFILTCONF, | ||
1740 | AB8500_ADFILTCONF_AD3NH, AB8500_ADFILTCONF_AD4NH, | ||
1741 | 1, 1), | ||
1742 | SOC_ENUM("Mic Mode", soc_enum_ad34voice), | ||
1743 | SOC_ENUM("Mic Filter", soc_enum_dmic34sinc), | ||
1744 | SOC_SINGLE_TLV("Mic 2", | ||
1745 | AB8500_ANAGAIN2, | ||
1746 | AB8500_ANAGAINX_MICXGAIN, | ||
1747 | AB8500_ANAGAINX_MICXGAIN_MAX, 0, mic_gain_tlv), | ||
1748 | SOC_SINGLE("Mic 2 Low Power Switch", | ||
1749 | AB8500_ANAGAIN2, AB8500_ANAGAINX_LOWPOWMICX, | ||
1750 | 1, 0), | ||
1751 | |||
1752 | /* LineIn */ | ||
1753 | SOC_DOUBLE("LineIn High Pass Switch", | ||
1754 | AB8500_ADFILTCONF, | ||
1755 | AB8500_ADFILTCONF_AD1NH, AB8500_ADFILTCONF_AD2NH, | ||
1756 | 1, 1), | ||
1757 | SOC_ENUM("LineIn Filter", soc_enum_dmic12sinc), | ||
1758 | SOC_ENUM("LineIn Mode", soc_enum_ad12voice), | ||
1759 | SOC_DOUBLE_R_TLV("LineIn Master Volume", | ||
1760 | AB8500_ADDIGGAIN1, AB8500_ADDIGGAIN2, | ||
1761 | 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), | ||
1762 | SOC_DOUBLE_TLV("LineIn", | ||
1763 | AB8500_ANAGAIN4, | ||
1764 | AB8500_ANAGAIN4_LINLGAIN, AB8500_ANAGAIN4_LINRGAIN, | ||
1765 | AB8500_ANAGAIN4_LINXGAIN_MAX, 0, lin_gain_tlv), | ||
1766 | SOC_DOUBLE_R_TLV("LineIn to Headset Volume", | ||
1767 | AB8500_DIGLINHSLGAIN, AB8500_DIGLINHSRGAIN, | ||
1768 | AB8500_DIGLINHSXGAIN_LINTOHSXGAIN, | ||
1769 | AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX, | ||
1770 | 1, lin2hs_gain_tlv), | ||
1771 | |||
1772 | /* DMic */ | ||
1773 | SOC_ENUM("DMic Filter", soc_enum_dmic56sinc), | ||
1774 | SOC_DOUBLE_R_TLV("DMic Master Volume", | ||
1775 | AB8500_ADDIGGAIN5, AB8500_ADDIGGAIN6, | ||
1776 | 0, AB8500_ADDIGGAINX_ADXGAIN_MAX, 1, adx_dig_gain_tlv), | ||
1777 | |||
1778 | /* Digital gains */ | ||
1779 | SOC_ENUM("Digital Gain Fade Speed", soc_enum_fadespeed), | ||
1780 | |||
1781 | /* Analog loopback */ | ||
1782 | SOC_DOUBLE_R_TLV("Analog Loopback Volume", | ||
1783 | AB8500_ADDIGLOOPGAIN1, AB8500_ADDIGLOOPGAIN2, | ||
1784 | 0, AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX, 1, dax_dig_gain_tlv), | ||
1785 | |||
1786 | /* Digital interface - DA from slot mapping */ | ||
1787 | SOC_ENUM("Digital Interface DA 1 From Slot Map", soc_enum_da1slotmap), | ||
1788 | SOC_ENUM("Digital Interface DA 2 From Slot Map", soc_enum_da2slotmap), | ||
1789 | SOC_ENUM("Digital Interface DA 3 From Slot Map", soc_enum_da3slotmap), | ||
1790 | SOC_ENUM("Digital Interface DA 4 From Slot Map", soc_enum_da4slotmap), | ||
1791 | SOC_ENUM("Digital Interface DA 5 From Slot Map", soc_enum_da5slotmap), | ||
1792 | SOC_ENUM("Digital Interface DA 6 From Slot Map", soc_enum_da6slotmap), | ||
1793 | SOC_ENUM("Digital Interface DA 7 From Slot Map", soc_enum_da7slotmap), | ||
1794 | SOC_ENUM("Digital Interface DA 8 From Slot Map", soc_enum_da8slotmap), | ||
1795 | |||
1796 | /* Digital interface - AD to slot mapping */ | ||
1797 | SOC_ENUM("Digital Interface AD To Slot 0 Map", soc_enum_adslot0map), | ||
1798 | SOC_ENUM("Digital Interface AD To Slot 1 Map", soc_enum_adslot1map), | ||
1799 | SOC_ENUM("Digital Interface AD To Slot 2 Map", soc_enum_adslot2map), | ||
1800 | SOC_ENUM("Digital Interface AD To Slot 3 Map", soc_enum_adslot3map), | ||
1801 | SOC_ENUM("Digital Interface AD To Slot 4 Map", soc_enum_adslot4map), | ||
1802 | SOC_ENUM("Digital Interface AD To Slot 5 Map", soc_enum_adslot5map), | ||
1803 | SOC_ENUM("Digital Interface AD To Slot 6 Map", soc_enum_adslot6map), | ||
1804 | SOC_ENUM("Digital Interface AD To Slot 7 Map", soc_enum_adslot7map), | ||
1805 | SOC_ENUM("Digital Interface AD To Slot 8 Map", soc_enum_adslot8map), | ||
1806 | SOC_ENUM("Digital Interface AD To Slot 9 Map", soc_enum_adslot9map), | ||
1807 | SOC_ENUM("Digital Interface AD To Slot 10 Map", soc_enum_adslot10map), | ||
1808 | SOC_ENUM("Digital Interface AD To Slot 11 Map", soc_enum_adslot11map), | ||
1809 | SOC_ENUM("Digital Interface AD To Slot 12 Map", soc_enum_adslot12map), | ||
1810 | SOC_ENUM("Digital Interface AD To Slot 13 Map", soc_enum_adslot13map), | ||
1811 | SOC_ENUM("Digital Interface AD To Slot 14 Map", soc_enum_adslot14map), | ||
1812 | SOC_ENUM("Digital Interface AD To Slot 15 Map", soc_enum_adslot15map), | ||
1813 | SOC_ENUM("Digital Interface AD To Slot 16 Map", soc_enum_adslot16map), | ||
1814 | SOC_ENUM("Digital Interface AD To Slot 17 Map", soc_enum_adslot17map), | ||
1815 | SOC_ENUM("Digital Interface AD To Slot 18 Map", soc_enum_adslot18map), | ||
1816 | SOC_ENUM("Digital Interface AD To Slot 19 Map", soc_enum_adslot19map), | ||
1817 | SOC_ENUM("Digital Interface AD To Slot 20 Map", soc_enum_adslot20map), | ||
1818 | SOC_ENUM("Digital Interface AD To Slot 21 Map", soc_enum_adslot21map), | ||
1819 | SOC_ENUM("Digital Interface AD To Slot 22 Map", soc_enum_adslot22map), | ||
1820 | SOC_ENUM("Digital Interface AD To Slot 23 Map", soc_enum_adslot23map), | ||
1821 | SOC_ENUM("Digital Interface AD To Slot 24 Map", soc_enum_adslot24map), | ||
1822 | SOC_ENUM("Digital Interface AD To Slot 25 Map", soc_enum_adslot25map), | ||
1823 | SOC_ENUM("Digital Interface AD To Slot 26 Map", soc_enum_adslot26map), | ||
1824 | SOC_ENUM("Digital Interface AD To Slot 27 Map", soc_enum_adslot27map), | ||
1825 | SOC_ENUM("Digital Interface AD To Slot 28 Map", soc_enum_adslot28map), | ||
1826 | SOC_ENUM("Digital Interface AD To Slot 29 Map", soc_enum_adslot29map), | ||
1827 | SOC_ENUM("Digital Interface AD To Slot 30 Map", soc_enum_adslot30map), | ||
1828 | SOC_ENUM("Digital Interface AD To Slot 31 Map", soc_enum_adslot31map), | ||
1829 | |||
1830 | /* Digital interface - Loopback */ | ||
1831 | SOC_SINGLE("Digital Interface AD 1 Loopback Switch", | ||
1832 | AB8500_DASLOTCONF1, AB8500_DASLOTCONF1_DAI7TOADO1, | ||
1833 | 1, 0), | ||
1834 | SOC_SINGLE("Digital Interface AD 2 Loopback Switch", | ||
1835 | AB8500_DASLOTCONF2, AB8500_DASLOTCONF2_DAI8TOADO2, | ||
1836 | 1, 0), | ||
1837 | SOC_SINGLE("Digital Interface AD 3 Loopback Switch", | ||
1838 | AB8500_DASLOTCONF3, AB8500_DASLOTCONF3_DAI7TOADO3, | ||
1839 | 1, 0), | ||
1840 | SOC_SINGLE("Digital Interface AD 4 Loopback Switch", | ||
1841 | AB8500_DASLOTCONF4, AB8500_DASLOTCONF4_DAI8TOADO4, | ||
1842 | 1, 0), | ||
1843 | SOC_SINGLE("Digital Interface AD 5 Loopback Switch", | ||
1844 | AB8500_DASLOTCONF5, AB8500_DASLOTCONF5_DAI7TOADO5, | ||
1845 | 1, 0), | ||
1846 | SOC_SINGLE("Digital Interface AD 6 Loopback Switch", | ||
1847 | AB8500_DASLOTCONF6, AB8500_DASLOTCONF6_DAI8TOADO6, | ||
1848 | 1, 0), | ||
1849 | SOC_SINGLE("Digital Interface AD 7 Loopback Switch", | ||
1850 | AB8500_DASLOTCONF7, AB8500_DASLOTCONF7_DAI8TOADO7, | ||
1851 | 1, 0), | ||
1852 | SOC_SINGLE("Digital Interface AD 8 Loopback Switch", | ||
1853 | AB8500_DASLOTCONF8, AB8500_DASLOTCONF8_DAI7TOADO8, | ||
1854 | 1, 0), | ||
1855 | |||
1856 | /* Digital interface - Burst FIFO */ | ||
1857 | SOC_SINGLE("Digital Interface 0 FIFO Enable Switch", | ||
1858 | AB8500_DIGIFCONF3, AB8500_DIGIFCONF3_IF0BFIFOEN, | ||
1859 | 1, 0), | ||
1860 | SOC_ENUM("Burst FIFO Mask", soc_enum_bfifomask), | ||
1861 | SOC_ENUM("Burst FIFO Bit-clock Frequency", soc_enum_bfifo19m2), | ||
1862 | SOC_SINGLE("Burst FIFO Threshold", | ||
1863 | AB8500_FIFOCONF1, AB8500_FIFOCONF1_BFIFOINT_SHIFT, | ||
1864 | AB8500_FIFOCONF1_BFIFOINT_MAX, 0), | ||
1865 | SOC_SINGLE("Burst FIFO Length", | ||
1866 | AB8500_FIFOCONF2, AB8500_FIFOCONF2_BFIFOTX_SHIFT, | ||
1867 | AB8500_FIFOCONF2_BFIFOTX_MAX, 0), | ||
1868 | SOC_SINGLE("Burst FIFO EOS Extra Slots", | ||
1869 | AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFOEXSL_SHIFT, | ||
1870 | AB8500_FIFOCONF3_BFIFOEXSL_MAX, 0), | ||
1871 | SOC_SINGLE("Burst FIFO FS Extra Bit-clocks", | ||
1872 | AB8500_FIFOCONF3, AB8500_FIFOCONF3_PREBITCLK0_SHIFT, | ||
1873 | AB8500_FIFOCONF3_PREBITCLK0_MAX, 0), | ||
1874 | SOC_ENUM("Burst FIFO Interface Mode", soc_enum_bfifomast), | ||
1875 | |||
1876 | SOC_SINGLE("Burst FIFO Interface Switch", | ||
1877 | AB8500_FIFOCONF3, AB8500_FIFOCONF3_BFIFORUN_SHIFT, | ||
1878 | 1, 0), | ||
1879 | SOC_SINGLE("Burst FIFO Switch Frame Number", | ||
1880 | AB8500_FIFOCONF4, AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT, | ||
1881 | AB8500_FIFOCONF4_BFIFOFRAMSW_MAX, 0), | ||
1882 | SOC_SINGLE("Burst FIFO Wake Up Delay", | ||
1883 | AB8500_FIFOCONF5, AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT, | ||
1884 | AB8500_FIFOCONF5_BFIFOWAKEUP_MAX, 0), | ||
1885 | SOC_SINGLE("Burst FIFO Samples In FIFO", | ||
1886 | AB8500_FIFOCONF6, AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT, | ||
1887 | AB8500_FIFOCONF6_BFIFOSAMPLE_MAX, 0), | ||
1888 | |||
1889 | /* ANC */ | ||
1890 | SOC_ENUM_EXT("ANC Status", soc_enum_ancstate, | ||
1891 | anc_status_control_get, anc_status_control_put), | ||
1892 | SOC_SINGLE_XR_SX("ANC Warp Delay Shift", | ||
1893 | AB8500_ANCCONF2, 1, AB8500_ANCCONF2_SHIFT, | ||
1894 | AB8500_ANCCONF2_MIN, AB8500_ANCCONF2_MAX, 0), | ||
1895 | SOC_SINGLE_XR_SX("ANC FIR Output Shift", | ||
1896 | AB8500_ANCCONF3, 1, AB8500_ANCCONF3_SHIFT, | ||
1897 | AB8500_ANCCONF3_MIN, AB8500_ANCCONF3_MAX, 0), | ||
1898 | SOC_SINGLE_XR_SX("ANC IIR Output Shift", | ||
1899 | AB8500_ANCCONF4, 1, AB8500_ANCCONF4_SHIFT, | ||
1900 | AB8500_ANCCONF4_MIN, AB8500_ANCCONF4_MAX, 0), | ||
1901 | SOC_SINGLE_XR_SX("ANC Warp Delay", | ||
1902 | AB8500_ANCCONF9, 2, AB8500_ANC_WARP_DELAY_SHIFT, | ||
1903 | AB8500_ANC_WARP_DELAY_MIN, AB8500_ANC_WARP_DELAY_MAX, 0), | ||
1904 | |||
1905 | /* Sidetone */ | ||
1906 | SOC_ENUM_EXT("Sidetone Status", soc_enum_sidstate, | ||
1907 | sid_status_control_get, sid_status_control_put), | ||
1908 | SOC_SINGLE_STROBE("Sidetone Reset", | ||
1909 | AB8500_SIDFIRADR, AB8500_SIDFIRADR_FIRSIDSET, 0), | ||
1910 | }; | ||
1911 | |||
1912 | static struct snd_kcontrol_new ab8500_filter_controls[] = { | ||
1913 | AB8500_FILTER_CONTROL("ANC FIR Coefficients", AB8500_ANC_FIR_COEFFS, | ||
1914 | AB8500_ANC_FIR_COEFF_MIN, AB8500_ANC_FIR_COEFF_MAX), | ||
1915 | AB8500_FILTER_CONTROL("ANC IIR Coefficients", AB8500_ANC_IIR_COEFFS, | ||
1916 | AB8500_ANC_IIR_COEFF_MIN, AB8500_ANC_IIR_COEFF_MAX), | ||
1917 | AB8500_FILTER_CONTROL("Sidetone FIR Coefficients", | ||
1918 | AB8500_SID_FIR_COEFFS, AB8500_SID_FIR_COEFF_MIN, | ||
1919 | AB8500_SID_FIR_COEFF_MAX) | ||
1920 | }; | ||
1921 | enum ab8500_filter { | ||
1922 | AB8500_FILTER_ANC_FIR = 0, | ||
1923 | AB8500_FILTER_ANC_IIR = 1, | ||
1924 | AB8500_FILTER_SID_FIR = 2, | ||
1925 | }; | ||
1926 | |||
1927 | /* | ||
1928 | * Extended interface for codec-driver | ||
1929 | */ | ||
1930 | |||
1931 | static int ab8500_audio_init_audioblock(struct snd_soc_codec *codec) | ||
1932 | { | ||
1933 | int status; | ||
1934 | |||
1935 | dev_dbg(codec->dev, "%s: Enter.\n", __func__); | ||
1936 | |||
1937 | /* Reset audio-registers and disable 32kHz-clock output 2 */ | ||
1938 | status = ab8500_sysctrl_write(AB8500_STW4500CTRL3, | ||
1939 | AB8500_STW4500CTRL3_CLK32KOUT2DIS | | ||
1940 | AB8500_STW4500CTRL3_RESETAUDN, | ||
1941 | AB8500_STW4500CTRL3_RESETAUDN); | ||
1942 | if (status < 0) | ||
1943 | return status; | ||
1944 | |||
1945 | return 0; | ||
1946 | } | ||
1947 | |||
1948 | static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, | ||
1949 | struct amic_settings *amics) | ||
1950 | { | ||
1951 | u8 value8; | ||
1952 | unsigned int value; | ||
1953 | int status; | ||
1954 | const struct snd_soc_dapm_route *route; | ||
1955 | |||
1956 | dev_dbg(codec->dev, "%s: Enter.\n", __func__); | ||
1957 | |||
1958 | /* Set DMic-clocks to outputs */ | ||
1959 | status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, | ||
1960 | (u8)AB8500_GPIO_DIR4_REG, | ||
1961 | &value8); | ||
1962 | if (status < 0) | ||
1963 | return status; | ||
1964 | value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | | ||
1965 | GPIO31_DIR_OUTPUT; | ||
1966 | status = abx500_set_register_interruptible(codec->dev, | ||
1967 | (u8)AB8500_MISC, | ||
1968 | (u8)AB8500_GPIO_DIR4_REG, | ||
1969 | value); | ||
1970 | if (status < 0) | ||
1971 | return status; | ||
1972 | |||
1973 | /* Attach regulators to AMic DAPM-paths */ | ||
1974 | dev_dbg(codec->dev, "%s: Mic 1a regulator: %s\n", __func__, | ||
1975 | amic_micbias_str(amics->mic1a_micbias)); | ||
1976 | route = &ab8500_dapm_routes_mic1a_vamicx[amics->mic1a_micbias]; | ||
1977 | status = snd_soc_dapm_add_routes(&codec->dapm, route, 1); | ||
1978 | dev_dbg(codec->dev, "%s: Mic 1b regulator: %s\n", __func__, | ||
1979 | amic_micbias_str(amics->mic1b_micbias)); | ||
1980 | route = &ab8500_dapm_routes_mic1b_vamicx[amics->mic1b_micbias]; | ||
1981 | status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); | ||
1982 | dev_dbg(codec->dev, "%s: Mic 2 regulator: %s\n", __func__, | ||
1983 | amic_micbias_str(amics->mic2_micbias)); | ||
1984 | route = &ab8500_dapm_routes_mic2_vamicx[amics->mic2_micbias]; | ||
1985 | status |= snd_soc_dapm_add_routes(&codec->dapm, route, 1); | ||
1986 | if (status < 0) { | ||
1987 | dev_err(codec->dev, | ||
1988 | "%s: Failed to add AMic-regulator DAPM-routes (%d).\n", | ||
1989 | __func__, status); | ||
1990 | return status; | ||
1991 | } | ||
1992 | |||
1993 | /* Set AMic-configuration */ | ||
1994 | dev_dbg(codec->dev, "%s: Mic 1 mic-type: %s\n", __func__, | ||
1995 | amic_type_str(amics->mic1_type)); | ||
1996 | snd_soc_update_bits(codec, AB8500_ANAGAIN1, AB8500_ANAGAINX_ENSEMICX, | ||
1997 | amics->mic1_type == AMIC_TYPE_DIFFERENTIAL ? | ||
1998 | 0 : AB8500_ANAGAINX_ENSEMICX); | ||
1999 | dev_dbg(codec->dev, "%s: Mic 2 mic-type: %s\n", __func__, | ||
2000 | amic_type_str(amics->mic2_type)); | ||
2001 | snd_soc_update_bits(codec, AB8500_ANAGAIN2, AB8500_ANAGAINX_ENSEMICX, | ||
2002 | amics->mic2_type == AMIC_TYPE_DIFFERENTIAL ? | ||
2003 | 0 : AB8500_ANAGAINX_ENSEMICX); | ||
2004 | |||
2005 | return 0; | ||
2006 | } | ||
2007 | EXPORT_SYMBOL_GPL(ab8500_audio_setup_mics); | ||
2008 | |||
2009 | static int ab8500_audio_set_ear_cmv(struct snd_soc_codec *codec, | ||
2010 | enum ear_cm_voltage ear_cmv) | ||
2011 | { | ||
2012 | char *cmv_str; | ||
2013 | |||
2014 | switch (ear_cmv) { | ||
2015 | case EAR_CMV_0_95V: | ||
2016 | cmv_str = "0.95V"; | ||
2017 | break; | ||
2018 | case EAR_CMV_1_10V: | ||
2019 | cmv_str = "1.10V"; | ||
2020 | break; | ||
2021 | case EAR_CMV_1_27V: | ||
2022 | cmv_str = "1.27V"; | ||
2023 | break; | ||
2024 | case EAR_CMV_1_58V: | ||
2025 | cmv_str = "1.58V"; | ||
2026 | break; | ||
2027 | default: | ||
2028 | dev_err(codec->dev, | ||
2029 | "%s: Unknown earpiece CM-voltage (%d)!\n", | ||
2030 | __func__, (int)ear_cmv); | ||
2031 | return -EINVAL; | ||
2032 | } | ||
2033 | dev_dbg(codec->dev, "%s: Earpiece CM-voltage: %s\n", __func__, | ||
2034 | cmv_str); | ||
2035 | snd_soc_update_bits(codec, AB8500_ANACONF1, AB8500_ANACONF1_EARSELCM, | ||
2036 | ear_cmv); | ||
2037 | |||
2038 | return 0; | ||
2039 | } | ||
2040 | EXPORT_SYMBOL_GPL(ab8500_audio_set_ear_cmv); | ||
2041 | |||
2042 | static int ab8500_audio_set_bit_delay(struct snd_soc_dai *dai, | ||
2043 | unsigned int delay) | ||
2044 | { | ||
2045 | unsigned int mask, val; | ||
2046 | struct snd_soc_codec *codec = dai->codec; | ||
2047 | |||
2048 | mask = BIT(AB8500_DIGIFCONF2_IF0DEL); | ||
2049 | val = 0; | ||
2050 | |||
2051 | switch (delay) { | ||
2052 | case 0: | ||
2053 | break; | ||
2054 | case 1: | ||
2055 | val |= BIT(AB8500_DIGIFCONF2_IF0DEL); | ||
2056 | break; | ||
2057 | default: | ||
2058 | dev_err(dai->codec->dev, | ||
2059 | "%s: ERROR: Unsupported bit-delay (0x%x)!\n", | ||
2060 | __func__, delay); | ||
2061 | return -EINVAL; | ||
2062 | } | ||
2063 | |||
2064 | dev_dbg(dai->codec->dev, "%s: IF0 Bit-delay: %d bits.\n", | ||
2065 | __func__, delay); | ||
2066 | snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); | ||
2067 | |||
2068 | return 0; | ||
2069 | } | ||
2070 | |||
2071 | /* Gates clocking according format mask */ | ||
2072 | static int ab8500_codec_set_dai_clock_gate(struct snd_soc_codec *codec, | ||
2073 | unsigned int fmt) | ||
2074 | { | ||
2075 | unsigned int mask; | ||
2076 | unsigned int val; | ||
2077 | |||
2078 | mask = BIT(AB8500_DIGIFCONF1_ENMASTGEN) | | ||
2079 | BIT(AB8500_DIGIFCONF1_ENFSBITCLK0); | ||
2080 | |||
2081 | val = BIT(AB8500_DIGIFCONF1_ENMASTGEN); | ||
2082 | |||
2083 | switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) { | ||
2084 | case SND_SOC_DAIFMT_CONT: /* continuous clock */ | ||
2085 | dev_dbg(codec->dev, "%s: IF0 Clock is continuous.\n", | ||
2086 | __func__); | ||
2087 | val |= BIT(AB8500_DIGIFCONF1_ENFSBITCLK0); | ||
2088 | break; | ||
2089 | case SND_SOC_DAIFMT_GATED: /* clock is gated */ | ||
2090 | dev_dbg(codec->dev, "%s: IF0 Clock is gated.\n", | ||
2091 | __func__); | ||
2092 | break; | ||
2093 | default: | ||
2094 | dev_err(codec->dev, | ||
2095 | "%s: ERROR: Unsupported clock mask (0x%x)!\n", | ||
2096 | __func__, fmt & SND_SOC_DAIFMT_CLOCK_MASK); | ||
2097 | return -EINVAL; | ||
2098 | } | ||
2099 | |||
2100 | snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val); | ||
2101 | |||
2102 | return 0; | ||
2103 | } | ||
2104 | |||
2105 | static int ab8500_codec_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
2106 | { | ||
2107 | unsigned int mask; | ||
2108 | unsigned int val; | ||
2109 | struct snd_soc_codec *codec = dai->codec; | ||
2110 | int status; | ||
2111 | |||
2112 | dev_dbg(codec->dev, "%s: Enter (fmt = 0x%x)\n", __func__, fmt); | ||
2113 | |||
2114 | mask = BIT(AB8500_DIGIFCONF3_IF1DATOIF0AD) | | ||
2115 | BIT(AB8500_DIGIFCONF3_IF1CLKTOIF0CLK) | | ||
2116 | BIT(AB8500_DIGIFCONF3_IF0BFIFOEN) | | ||
2117 | BIT(AB8500_DIGIFCONF3_IF0MASTER); | ||
2118 | val = 0; | ||
2119 | |||
2120 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
2121 | case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & FRM master */ | ||
2122 | dev_dbg(dai->codec->dev, | ||
2123 | "%s: IF0 Master-mode: AB8500 master.\n", __func__); | ||
2124 | val |= BIT(AB8500_DIGIFCONF3_IF0MASTER); | ||
2125 | break; | ||
2126 | case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & FRM slave */ | ||
2127 | dev_dbg(dai->codec->dev, | ||
2128 | "%s: IF0 Master-mode: AB8500 slave.\n", __func__); | ||
2129 | break; | ||
2130 | case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & FRM master */ | ||
2131 | case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */ | ||
2132 | dev_err(dai->codec->dev, | ||
2133 | "%s: ERROR: The device is either a master or a slave.\n", | ||
2134 | __func__); | ||
2135 | default: | ||
2136 | dev_err(dai->codec->dev, | ||
2137 | "%s: ERROR: Unsupporter master mask 0x%x\n", | ||
2138 | __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
2139 | return -EINVAL; | ||
2140 | break; | ||
2141 | } | ||
2142 | |||
2143 | snd_soc_update_bits(codec, AB8500_DIGIFCONF3, mask, val); | ||
2144 | |||
2145 | /* Set clock gating */ | ||
2146 | status = ab8500_codec_set_dai_clock_gate(codec, fmt); | ||
2147 | if (status) { | ||
2148 | dev_err(dai->codec->dev, | ||
2149 | "%s: ERRROR: Failed to set clock gate (%d).\n", | ||
2150 | __func__, status); | ||
2151 | return status; | ||
2152 | } | ||
2153 | |||
2154 | /* Setting data transfer format */ | ||
2155 | |||
2156 | mask = BIT(AB8500_DIGIFCONF2_IF0FORMAT0) | | ||
2157 | BIT(AB8500_DIGIFCONF2_IF0FORMAT1) | | ||
2158 | BIT(AB8500_DIGIFCONF2_FSYNC0P) | | ||
2159 | BIT(AB8500_DIGIFCONF2_BITCLK0P); | ||
2160 | val = 0; | ||
2161 | |||
2162 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
2163 | case SND_SOC_DAIFMT_I2S: /* I2S mode */ | ||
2164 | dev_dbg(dai->codec->dev, "%s: IF0 Protocol: I2S\n", __func__); | ||
2165 | val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT1); | ||
2166 | ab8500_audio_set_bit_delay(dai, 0); | ||
2167 | break; | ||
2168 | |||
2169 | case SND_SOC_DAIFMT_DSP_A: /* L data MSB after FRM LRC */ | ||
2170 | dev_dbg(dai->codec->dev, | ||
2171 | "%s: IF0 Protocol: DSP A (TDM)\n", __func__); | ||
2172 | val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0); | ||
2173 | ab8500_audio_set_bit_delay(dai, 1); | ||
2174 | break; | ||
2175 | |||
2176 | case SND_SOC_DAIFMT_DSP_B: /* L data MSB during FRM LRC */ | ||
2177 | dev_dbg(dai->codec->dev, | ||
2178 | "%s: IF0 Protocol: DSP B (TDM)\n", __func__); | ||
2179 | val |= BIT(AB8500_DIGIFCONF2_IF0FORMAT0); | ||
2180 | ab8500_audio_set_bit_delay(dai, 0); | ||
2181 | break; | ||
2182 | |||
2183 | default: | ||
2184 | dev_err(dai->codec->dev, | ||
2185 | "%s: ERROR: Unsupported format (0x%x)!\n", | ||
2186 | __func__, fmt & SND_SOC_DAIFMT_FORMAT_MASK); | ||
2187 | return -EINVAL; | ||
2188 | } | ||
2189 | |||
2190 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
2191 | case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */ | ||
2192 | dev_dbg(dai->codec->dev, | ||
2193 | "%s: IF0: Normal bit clock, normal frame\n", | ||
2194 | __func__); | ||
2195 | break; | ||
2196 | case SND_SOC_DAIFMT_NB_IF: /* normal BCLK + inv FRM */ | ||
2197 | dev_dbg(dai->codec->dev, | ||
2198 | "%s: IF0: Normal bit clock, inverted frame\n", | ||
2199 | __func__); | ||
2200 | val |= BIT(AB8500_DIGIFCONF2_FSYNC0P); | ||
2201 | break; | ||
2202 | case SND_SOC_DAIFMT_IB_NF: /* invert BCLK + nor FRM */ | ||
2203 | dev_dbg(dai->codec->dev, | ||
2204 | "%s: IF0: Inverted bit clock, normal frame\n", | ||
2205 | __func__); | ||
2206 | val |= BIT(AB8500_DIGIFCONF2_BITCLK0P); | ||
2207 | break; | ||
2208 | case SND_SOC_DAIFMT_IB_IF: /* invert BCLK + FRM */ | ||
2209 | dev_dbg(dai->codec->dev, | ||
2210 | "%s: IF0: Inverted bit clock, inverted frame\n", | ||
2211 | __func__); | ||
2212 | val |= BIT(AB8500_DIGIFCONF2_FSYNC0P); | ||
2213 | val |= BIT(AB8500_DIGIFCONF2_BITCLK0P); | ||
2214 | break; | ||
2215 | default: | ||
2216 | dev_err(dai->codec->dev, | ||
2217 | "%s: ERROR: Unsupported INV mask 0x%x\n", | ||
2218 | __func__, fmt & SND_SOC_DAIFMT_INV_MASK); | ||
2219 | return -EINVAL; | ||
2220 | } | ||
2221 | |||
2222 | snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); | ||
2223 | |||
2224 | return 0; | ||
2225 | } | ||
2226 | |||
2227 | static int ab8500_codec_set_dai_tdm_slot(struct snd_soc_dai *dai, | ||
2228 | unsigned int tx_mask, unsigned int rx_mask, | ||
2229 | int slots, int slot_width) | ||
2230 | { | ||
2231 | struct snd_soc_codec *codec = dai->codec; | ||
2232 | unsigned int val, mask, slots_active; | ||
2233 | |||
2234 | mask = BIT(AB8500_DIGIFCONF2_IF0WL0) | | ||
2235 | BIT(AB8500_DIGIFCONF2_IF0WL1); | ||
2236 | val = 0; | ||
2237 | |||
2238 | switch (slot_width) { | ||
2239 | case 16: | ||
2240 | break; | ||
2241 | case 20: | ||
2242 | val |= BIT(AB8500_DIGIFCONF2_IF0WL0); | ||
2243 | break; | ||
2244 | case 24: | ||
2245 | val |= BIT(AB8500_DIGIFCONF2_IF0WL1); | ||
2246 | break; | ||
2247 | case 32: | ||
2248 | val |= BIT(AB8500_DIGIFCONF2_IF0WL1) | | ||
2249 | BIT(AB8500_DIGIFCONF2_IF0WL0); | ||
2250 | break; | ||
2251 | default: | ||
2252 | dev_err(dai->codec->dev, "%s: Unsupported slot-width 0x%x\n", | ||
2253 | __func__, slot_width); | ||
2254 | return -EINVAL; | ||
2255 | } | ||
2256 | |||
2257 | dev_dbg(dai->codec->dev, "%s: IF0 slot-width: %d bits.\n", | ||
2258 | __func__, slot_width); | ||
2259 | snd_soc_update_bits(codec, AB8500_DIGIFCONF2, mask, val); | ||
2260 | |||
2261 | /* Setup TDM clocking according to slot count */ | ||
2262 | dev_dbg(dai->codec->dev, "%s: Slots, total: %d\n", __func__, slots); | ||
2263 | mask = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) | | ||
2264 | BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); | ||
2265 | switch (slots) { | ||
2266 | case 2: | ||
2267 | val = AB8500_MASK_NONE; | ||
2268 | break; | ||
2269 | case 4: | ||
2270 | val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0); | ||
2271 | break; | ||
2272 | case 8: | ||
2273 | val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); | ||
2274 | break; | ||
2275 | case 16: | ||
2276 | val = BIT(AB8500_DIGIFCONF1_IF0BITCLKOS0) | | ||
2277 | BIT(AB8500_DIGIFCONF1_IF0BITCLKOS1); | ||
2278 | break; | ||
2279 | default: | ||
2280 | dev_err(dai->codec->dev, | ||
2281 | "%s: ERROR: Unsupported number of slots (%d)!\n", | ||
2282 | __func__, slots); | ||
2283 | return -EINVAL; | ||
2284 | } | ||
2285 | snd_soc_update_bits(codec, AB8500_DIGIFCONF1, mask, val); | ||
2286 | |||
2287 | /* Setup TDM DA according to active tx slots */ | ||
2288 | mask = AB8500_DASLOTCONFX_SLTODAX_MASK; | ||
2289 | slots_active = hweight32(tx_mask); | ||
2290 | dev_dbg(dai->codec->dev, "%s: Slots, active, TX: %d\n", __func__, | ||
2291 | slots_active); | ||
2292 | switch (slots_active) { | ||
2293 | case 0: | ||
2294 | break; | ||
2295 | case 1: | ||
2296 | /* Slot 9 -> DA_IN1 & DA_IN3 */ | ||
2297 | snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 11); | ||
2298 | snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 11); | ||
2299 | snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); | ||
2300 | snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); | ||
2301 | break; | ||
2302 | case 2: | ||
2303 | /* Slot 9 -> DA_IN1 & DA_IN3, Slot 11 -> DA_IN2 & DA_IN4 */ | ||
2304 | snd_soc_update_bits(codec, AB8500_DASLOTCONF1, mask, 9); | ||
2305 | snd_soc_update_bits(codec, AB8500_DASLOTCONF3, mask, 9); | ||
2306 | snd_soc_update_bits(codec, AB8500_DASLOTCONF2, mask, 11); | ||
2307 | snd_soc_update_bits(codec, AB8500_DASLOTCONF4, mask, 11); | ||
2308 | |||
2309 | break; | ||
2310 | case 8: | ||
2311 | dev_dbg(dai->codec->dev, | ||
2312 | "%s: In 8-channel mode DA-from-slot mapping is set manually.", | ||
2313 | __func__); | ||
2314 | break; | ||
2315 | default: | ||
2316 | dev_err(dai->codec->dev, | ||
2317 | "%s: Unsupported number of active TX-slots (%d)!\n", | ||
2318 | __func__, slots_active); | ||
2319 | return -EINVAL; | ||
2320 | } | ||
2321 | |||
2322 | /* Setup TDM AD according to active RX-slots */ | ||
2323 | slots_active = hweight32(rx_mask); | ||
2324 | dev_dbg(dai->codec->dev, "%s: Slots, active, RX: %d\n", __func__, | ||
2325 | slots_active); | ||
2326 | switch (slots_active) { | ||
2327 | case 0: | ||
2328 | break; | ||
2329 | case 1: | ||
2330 | /* AD_OUT3 -> slot 0 & 1 */ | ||
2331 | snd_soc_update_bits(codec, AB8500_ADSLOTSEL1, AB8500_MASK_ALL, | ||
2332 | AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | | ||
2333 | AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD); | ||
2334 | break; | ||
2335 | case 2: | ||
2336 | /* AD_OUT3 -> slot 0, AD_OUT2 -> slot 1 */ | ||
2337 | snd_soc_update_bits(codec, | ||
2338 | AB8500_ADSLOTSEL1, | ||
2339 | AB8500_MASK_ALL, | ||
2340 | AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN | | ||
2341 | AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD); | ||
2342 | break; | ||
2343 | case 8: | ||
2344 | dev_dbg(dai->codec->dev, | ||
2345 | "%s: In 8-channel mode AD-to-slot mapping is set manually.", | ||
2346 | __func__); | ||
2347 | break; | ||
2348 | default: | ||
2349 | dev_err(dai->codec->dev, | ||
2350 | "%s: Unsupported number of active RX-slots (%d)!\n", | ||
2351 | __func__, slots_active); | ||
2352 | return -EINVAL; | ||
2353 | } | ||
2354 | |||
2355 | return 0; | ||
2356 | } | ||
2357 | |||
2358 | struct snd_soc_dai_driver ab8500_codec_dai[] = { | ||
2359 | { | ||
2360 | .name = "ab8500-codec-dai.0", | ||
2361 | .id = 0, | ||
2362 | .playback = { | ||
2363 | .stream_name = "ab8500_0p", | ||
2364 | .channels_min = 1, | ||
2365 | .channels_max = 8, | ||
2366 | .rates = AB8500_SUPPORTED_RATE, | ||
2367 | .formats = AB8500_SUPPORTED_FMT, | ||
2368 | }, | ||
2369 | .ops = (struct snd_soc_dai_ops[]) { | ||
2370 | { | ||
2371 | .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, | ||
2372 | .set_fmt = ab8500_codec_set_dai_fmt, | ||
2373 | } | ||
2374 | }, | ||
2375 | .symmetric_rates = 1 | ||
2376 | }, | ||
2377 | { | ||
2378 | .name = "ab8500-codec-dai.1", | ||
2379 | .id = 1, | ||
2380 | .capture = { | ||
2381 | .stream_name = "ab8500_0c", | ||
2382 | .channels_min = 1, | ||
2383 | .channels_max = 8, | ||
2384 | .rates = AB8500_SUPPORTED_RATE, | ||
2385 | .formats = AB8500_SUPPORTED_FMT, | ||
2386 | }, | ||
2387 | .ops = (struct snd_soc_dai_ops[]) { | ||
2388 | { | ||
2389 | .set_tdm_slot = ab8500_codec_set_dai_tdm_slot, | ||
2390 | .set_fmt = ab8500_codec_set_dai_fmt, | ||
2391 | } | ||
2392 | }, | ||
2393 | .symmetric_rates = 1 | ||
2394 | } | ||
2395 | }; | ||
2396 | |||
2397 | static int ab8500_codec_probe(struct snd_soc_codec *codec) | ||
2398 | { | ||
2399 | struct device *dev = codec->dev; | ||
2400 | struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(dev); | ||
2401 | struct ab8500_platform_data *pdata; | ||
2402 | struct filter_control *fc; | ||
2403 | int status; | ||
2404 | |||
2405 | dev_dbg(dev, "%s: Enter.\n", __func__); | ||
2406 | |||
2407 | /* Setup AB8500 according to board-settings */ | ||
2408 | pdata = (struct ab8500_platform_data *)dev_get_platdata(dev->parent); | ||
2409 | status = ab8500_audio_setup_mics(codec, &pdata->codec->amics); | ||
2410 | if (status < 0) { | ||
2411 | pr_err("%s: Failed to setup mics (%d)!\n", __func__, status); | ||
2412 | return status; | ||
2413 | } | ||
2414 | status = ab8500_audio_set_ear_cmv(codec, pdata->codec->ear_cmv); | ||
2415 | if (status < 0) { | ||
2416 | pr_err("%s: Failed to set earpiece CM-voltage (%d)!\n", | ||
2417 | __func__, status); | ||
2418 | return status; | ||
2419 | } | ||
2420 | |||
2421 | status = ab8500_audio_init_audioblock(codec); | ||
2422 | if (status < 0) { | ||
2423 | dev_err(dev, "%s: failed to init audio-block (%d)!\n", | ||
2424 | __func__, status); | ||
2425 | return status; | ||
2426 | } | ||
2427 | |||
2428 | /* Override HW-defaults */ | ||
2429 | ab8500_codec_write_reg(codec, | ||
2430 | AB8500_ANACONF5, | ||
2431 | BIT(AB8500_ANACONF5_HSAUTOEN)); | ||
2432 | ab8500_codec_write_reg(codec, | ||
2433 | AB8500_SHORTCIRCONF, | ||
2434 | BIT(AB8500_SHORTCIRCONF_HSZCDDIS)); | ||
2435 | |||
2436 | /* Add filter controls */ | ||
2437 | status = snd_soc_add_codec_controls(codec, ab8500_filter_controls, | ||
2438 | ARRAY_SIZE(ab8500_filter_controls)); | ||
2439 | if (status < 0) { | ||
2440 | dev_err(dev, | ||
2441 | "%s: failed to add ab8500 filter controls (%d).\n", | ||
2442 | __func__, status); | ||
2443 | return status; | ||
2444 | } | ||
2445 | fc = (struct filter_control *) | ||
2446 | &ab8500_filter_controls[AB8500_FILTER_ANC_FIR].private_value; | ||
2447 | drvdata->anc_fir_values = (long *)fc->value; | ||
2448 | fc = (struct filter_control *) | ||
2449 | &ab8500_filter_controls[AB8500_FILTER_ANC_IIR].private_value; | ||
2450 | drvdata->anc_iir_values = (long *)fc->value; | ||
2451 | fc = (struct filter_control *) | ||
2452 | &ab8500_filter_controls[AB8500_FILTER_SID_FIR].private_value; | ||
2453 | drvdata->sid_fir_values = (long *)fc->value; | ||
2454 | |||
2455 | (void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input"); | ||
2456 | |||
2457 | mutex_init(&drvdata->anc_lock); | ||
2458 | |||
2459 | return status; | ||
2460 | } | ||
2461 | |||
2462 | static struct snd_soc_codec_driver ab8500_codec_driver = { | ||
2463 | .probe = ab8500_codec_probe, | ||
2464 | .read = ab8500_codec_read_reg, | ||
2465 | .write = ab8500_codec_write_reg, | ||
2466 | .reg_word_size = sizeof(u8), | ||
2467 | .controls = ab8500_ctrls, | ||
2468 | .num_controls = ARRAY_SIZE(ab8500_ctrls), | ||
2469 | .dapm_widgets = ab8500_dapm_widgets, | ||
2470 | .num_dapm_widgets = ARRAY_SIZE(ab8500_dapm_widgets), | ||
2471 | .dapm_routes = ab8500_dapm_routes, | ||
2472 | .num_dapm_routes = ARRAY_SIZE(ab8500_dapm_routes), | ||
2473 | }; | ||
2474 | |||
2475 | static int __devinit ab8500_codec_driver_probe(struct platform_device *pdev) | ||
2476 | { | ||
2477 | int status; | ||
2478 | struct ab8500_codec_drvdata *drvdata; | ||
2479 | |||
2480 | dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); | ||
2481 | |||
2482 | /* Create driver private-data struct */ | ||
2483 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct ab8500_codec_drvdata), | ||
2484 | GFP_KERNEL); | ||
2485 | drvdata->sid_status = SID_UNCONFIGURED; | ||
2486 | drvdata->anc_status = ANC_UNCONFIGURED; | ||
2487 | dev_set_drvdata(&pdev->dev, drvdata); | ||
2488 | |||
2489 | dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); | ||
2490 | status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, | ||
2491 | ab8500_codec_dai, | ||
2492 | ARRAY_SIZE(ab8500_codec_dai)); | ||
2493 | if (status < 0) | ||
2494 | dev_err(&pdev->dev, | ||
2495 | "%s: Error: Failed to register codec (%d).\n", | ||
2496 | __func__, status); | ||
2497 | |||
2498 | return status; | ||
2499 | } | ||
2500 | |||
2501 | static int __devexit ab8500_codec_driver_remove(struct platform_device *pdev) | ||
2502 | { | ||
2503 | dev_info(&pdev->dev, "%s Enter.\n", __func__); | ||
2504 | |||
2505 | snd_soc_unregister_codec(&pdev->dev); | ||
2506 | |||
2507 | return 0; | ||
2508 | } | ||
2509 | |||
2510 | static struct platform_driver ab8500_codec_platform_driver = { | ||
2511 | .driver = { | ||
2512 | .name = "ab8500-codec", | ||
2513 | .owner = THIS_MODULE, | ||
2514 | }, | ||
2515 | .probe = ab8500_codec_driver_probe, | ||
2516 | .remove = __devexit_p(ab8500_codec_driver_remove), | ||
2517 | .suspend = NULL, | ||
2518 | .resume = NULL, | ||
2519 | }; | ||
2520 | module_platform_driver(ab8500_codec_platform_driver); | ||
2521 | |||
2522 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/ab8500-codec.h b/sound/soc/codecs/ab8500-codec.h new file mode 100644 index 000000000000..114f69a0c629 --- /dev/null +++ b/sound/soc/codecs/ab8500-codec.h | |||
@@ -0,0 +1,590 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | ||
5 | * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com>, | ||
6 | * Roger Nilsson <roger.xr.nilsson@stericsson.com>, | ||
7 | * for ST-Ericsson. | ||
8 | * | ||
9 | * Based on the early work done by: | ||
10 | * Mikko J. Lehto <mikko.lehto@symbio.com>, | ||
11 | * Mikko Sarmanne <mikko.sarmanne@symbio.com>, | ||
12 | * for ST-Ericsson. | ||
13 | * | ||
14 | * License terms: | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify it | ||
17 | * under the terms of the GNU General Public License version 2 as published | ||
18 | * by the Free Software Foundation. | ||
19 | */ | ||
20 | |||
21 | #ifndef AB8500_CODEC_REGISTERS_H | ||
22 | #define AB8500_CODEC_REGISTERS_H | ||
23 | |||
24 | #define AB8500_SUPPORTED_RATE (SNDRV_PCM_RATE_48000) | ||
25 | #define AB8500_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE) | ||
26 | |||
27 | /* AB8500 audio bank (0x0d) register definitions */ | ||
28 | |||
29 | #define AB8500_POWERUP 0x00 | ||
30 | #define AB8500_AUDSWRESET 0x01 | ||
31 | #define AB8500_ADPATHENA 0x02 | ||
32 | #define AB8500_DAPATHENA 0x03 | ||
33 | #define AB8500_ANACONF1 0x04 | ||
34 | #define AB8500_ANACONF2 0x05 | ||
35 | #define AB8500_DIGMICCONF 0x06 | ||
36 | #define AB8500_ANACONF3 0x07 | ||
37 | #define AB8500_ANACONF4 0x08 | ||
38 | #define AB8500_DAPATHCONF 0x09 | ||
39 | #define AB8500_MUTECONF 0x0A | ||
40 | #define AB8500_SHORTCIRCONF 0x0B | ||
41 | #define AB8500_ANACONF5 0x0C | ||
42 | #define AB8500_ENVCPCONF 0x0D | ||
43 | #define AB8500_SIGENVCONF 0x0E | ||
44 | #define AB8500_PWMGENCONF1 0x0F | ||
45 | #define AB8500_PWMGENCONF2 0x10 | ||
46 | #define AB8500_PWMGENCONF3 0x11 | ||
47 | #define AB8500_PWMGENCONF4 0x12 | ||
48 | #define AB8500_PWMGENCONF5 0x13 | ||
49 | #define AB8500_ANAGAIN1 0x14 | ||
50 | #define AB8500_ANAGAIN2 0x15 | ||
51 | #define AB8500_ANAGAIN3 0x16 | ||
52 | #define AB8500_ANAGAIN4 0x17 | ||
53 | #define AB8500_DIGLINHSLGAIN 0x18 | ||
54 | #define AB8500_DIGLINHSRGAIN 0x19 | ||
55 | #define AB8500_ADFILTCONF 0x1A | ||
56 | #define AB8500_DIGIFCONF1 0x1B | ||
57 | #define AB8500_DIGIFCONF2 0x1C | ||
58 | #define AB8500_DIGIFCONF3 0x1D | ||
59 | #define AB8500_DIGIFCONF4 0x1E | ||
60 | #define AB8500_ADSLOTSEL1 0x1F | ||
61 | #define AB8500_ADSLOTSEL2 0x20 | ||
62 | #define AB8500_ADSLOTSEL3 0x21 | ||
63 | #define AB8500_ADSLOTSEL4 0x22 | ||
64 | #define AB8500_ADSLOTSEL5 0x23 | ||
65 | #define AB8500_ADSLOTSEL6 0x24 | ||
66 | #define AB8500_ADSLOTSEL7 0x25 | ||
67 | #define AB8500_ADSLOTSEL8 0x26 | ||
68 | #define AB8500_ADSLOTSEL9 0x27 | ||
69 | #define AB8500_ADSLOTSEL10 0x28 | ||
70 | #define AB8500_ADSLOTSEL11 0x29 | ||
71 | #define AB8500_ADSLOTSEL12 0x2A | ||
72 | #define AB8500_ADSLOTSEL13 0x2B | ||
73 | #define AB8500_ADSLOTSEL14 0x2C | ||
74 | #define AB8500_ADSLOTSEL15 0x2D | ||
75 | #define AB8500_ADSLOTSEL16 0x2E | ||
76 | #define AB8500_ADSLOTHIZCTRL1 0x2F | ||
77 | #define AB8500_ADSLOTHIZCTRL2 0x30 | ||
78 | #define AB8500_ADSLOTHIZCTRL3 0x31 | ||
79 | #define AB8500_ADSLOTHIZCTRL4 0x32 | ||
80 | #define AB8500_DASLOTCONF1 0x33 | ||
81 | #define AB8500_DASLOTCONF2 0x34 | ||
82 | #define AB8500_DASLOTCONF3 0x35 | ||
83 | #define AB8500_DASLOTCONF4 0x36 | ||
84 | #define AB8500_DASLOTCONF5 0x37 | ||
85 | #define AB8500_DASLOTCONF6 0x38 | ||
86 | #define AB8500_DASLOTCONF7 0x39 | ||
87 | #define AB8500_DASLOTCONF8 0x3A | ||
88 | #define AB8500_CLASSDCONF1 0x3B | ||
89 | #define AB8500_CLASSDCONF2 0x3C | ||
90 | #define AB8500_CLASSDCONF3 0x3D | ||
91 | #define AB8500_DMICFILTCONF 0x3E | ||
92 | #define AB8500_DIGMULTCONF1 0x3F | ||
93 | #define AB8500_DIGMULTCONF2 0x40 | ||
94 | #define AB8500_ADDIGGAIN1 0x41 | ||
95 | #define AB8500_ADDIGGAIN2 0x42 | ||
96 | #define AB8500_ADDIGGAIN3 0x43 | ||
97 | #define AB8500_ADDIGGAIN4 0x44 | ||
98 | #define AB8500_ADDIGGAIN5 0x45 | ||
99 | #define AB8500_ADDIGGAIN6 0x46 | ||
100 | #define AB8500_DADIGGAIN1 0x47 | ||
101 | #define AB8500_DADIGGAIN2 0x48 | ||
102 | #define AB8500_DADIGGAIN3 0x49 | ||
103 | #define AB8500_DADIGGAIN4 0x4A | ||
104 | #define AB8500_DADIGGAIN5 0x4B | ||
105 | #define AB8500_DADIGGAIN6 0x4C | ||
106 | #define AB8500_ADDIGLOOPGAIN1 0x4D | ||
107 | #define AB8500_ADDIGLOOPGAIN2 0x4E | ||
108 | #define AB8500_HSLEARDIGGAIN 0x4F | ||
109 | #define AB8500_HSRDIGGAIN 0x50 | ||
110 | #define AB8500_SIDFIRGAIN1 0x51 | ||
111 | #define AB8500_SIDFIRGAIN2 0x52 | ||
112 | #define AB8500_ANCCONF1 0x53 | ||
113 | #define AB8500_ANCCONF2 0x54 | ||
114 | #define AB8500_ANCCONF3 0x55 | ||
115 | #define AB8500_ANCCONF4 0x56 | ||
116 | #define AB8500_ANCCONF5 0x57 | ||
117 | #define AB8500_ANCCONF6 0x58 | ||
118 | #define AB8500_ANCCONF7 0x59 | ||
119 | #define AB8500_ANCCONF8 0x5A | ||
120 | #define AB8500_ANCCONF9 0x5B | ||
121 | #define AB8500_ANCCONF10 0x5C | ||
122 | #define AB8500_ANCCONF11 0x5D | ||
123 | #define AB8500_ANCCONF12 0x5E | ||
124 | #define AB8500_ANCCONF13 0x5F | ||
125 | #define AB8500_ANCCONF14 0x60 | ||
126 | #define AB8500_SIDFIRADR 0x61 | ||
127 | #define AB8500_SIDFIRCOEF1 0x62 | ||
128 | #define AB8500_SIDFIRCOEF2 0x63 | ||
129 | #define AB8500_SIDFIRCONF 0x64 | ||
130 | #define AB8500_AUDINTMASK1 0x65 | ||
131 | #define AB8500_AUDINTSOURCE1 0x66 | ||
132 | #define AB8500_AUDINTMASK2 0x67 | ||
133 | #define AB8500_AUDINTSOURCE2 0x68 | ||
134 | #define AB8500_FIFOCONF1 0x69 | ||
135 | #define AB8500_FIFOCONF2 0x6A | ||
136 | #define AB8500_FIFOCONF3 0x6B | ||
137 | #define AB8500_FIFOCONF4 0x6C | ||
138 | #define AB8500_FIFOCONF5 0x6D | ||
139 | #define AB8500_FIFOCONF6 0x6E | ||
140 | #define AB8500_AUDREV 0x6F | ||
141 | |||
142 | #define AB8500_FIRST_REG AB8500_POWERUP | ||
143 | #define AB8500_LAST_REG AB8500_AUDREV | ||
144 | #define AB8500_CACHEREGNUM (AB8500_LAST_REG + 1) | ||
145 | |||
146 | #define AB8500_MASK_ALL 0xFF | ||
147 | #define AB8500_MASK_NONE 0x00 | ||
148 | |||
149 | /* AB8500_POWERUP */ | ||
150 | #define AB8500_POWERUP_POWERUP 7 | ||
151 | #define AB8500_POWERUP_ENANA 3 | ||
152 | |||
153 | /* AB8500_AUDSWRESET */ | ||
154 | #define AB8500_AUDSWRESET_SWRESET 7 | ||
155 | |||
156 | /* AB8500_ADPATHENA */ | ||
157 | #define AB8500_ADPATHENA_ENAD12 7 | ||
158 | #define AB8500_ADPATHENA_ENAD34 5 | ||
159 | #define AB8500_ADPATHENA_ENAD5768 3 | ||
160 | |||
161 | /* AB8500_DAPATHENA */ | ||
162 | #define AB8500_DAPATHENA_ENDA1 7 | ||
163 | #define AB8500_DAPATHENA_ENDA2 6 | ||
164 | #define AB8500_DAPATHENA_ENDA3 5 | ||
165 | #define AB8500_DAPATHENA_ENDA4 4 | ||
166 | #define AB8500_DAPATHENA_ENDA5 3 | ||
167 | #define AB8500_DAPATHENA_ENDA6 2 | ||
168 | |||
169 | /* AB8500_ANACONF1 */ | ||
170 | #define AB8500_ANACONF1_HSLOWPOW 7 | ||
171 | #define AB8500_ANACONF1_DACLOWPOW1 6 | ||
172 | #define AB8500_ANACONF1_DACLOWPOW0 5 | ||
173 | #define AB8500_ANACONF1_EARDACLOWPOW 4 | ||
174 | #define AB8500_ANACONF1_EARSELCM 2 | ||
175 | #define AB8500_ANACONF1_HSHPEN 1 | ||
176 | #define AB8500_ANACONF1_EARDRVLOWPOW 0 | ||
177 | |||
178 | /* AB8500_ANACONF2 */ | ||
179 | #define AB8500_ANACONF2_ENMIC1 7 | ||
180 | #define AB8500_ANACONF2_ENMIC2 6 | ||
181 | #define AB8500_ANACONF2_ENLINL 5 | ||
182 | #define AB8500_ANACONF2_ENLINR 4 | ||
183 | #define AB8500_ANACONF2_MUTMIC1 3 | ||
184 | #define AB8500_ANACONF2_MUTMIC2 2 | ||
185 | #define AB8500_ANACONF2_MUTLINL 1 | ||
186 | #define AB8500_ANACONF2_MUTLINR 0 | ||
187 | |||
188 | /* AB8500_DIGMICCONF */ | ||
189 | #define AB8500_DIGMICCONF_ENDMIC1 7 | ||
190 | #define AB8500_DIGMICCONF_ENDMIC2 6 | ||
191 | #define AB8500_DIGMICCONF_ENDMIC3 5 | ||
192 | #define AB8500_DIGMICCONF_ENDMIC4 4 | ||
193 | #define AB8500_DIGMICCONF_ENDMIC5 3 | ||
194 | #define AB8500_DIGMICCONF_ENDMIC6 2 | ||
195 | #define AB8500_DIGMICCONF_HSFADSPEED 0 | ||
196 | |||
197 | /* AB8500_ANACONF3 */ | ||
198 | #define AB8500_ANACONF3_MIC1SEL 7 | ||
199 | #define AB8500_ANACONF3_LINRSEL 6 | ||
200 | #define AB8500_ANACONF3_ENDRVHSL 5 | ||
201 | #define AB8500_ANACONF3_ENDRVHSR 4 | ||
202 | #define AB8500_ANACONF3_ENADCMIC 2 | ||
203 | #define AB8500_ANACONF3_ENADCLINL 1 | ||
204 | #define AB8500_ANACONF3_ENADCLINR 0 | ||
205 | |||
206 | /* AB8500_ANACONF4 */ | ||
207 | #define AB8500_ANACONF4_DISPDVSS 7 | ||
208 | #define AB8500_ANACONF4_ENEAR 6 | ||
209 | #define AB8500_ANACONF4_ENHSL 5 | ||
210 | #define AB8500_ANACONF4_ENHSR 4 | ||
211 | #define AB8500_ANACONF4_ENHFL 3 | ||
212 | #define AB8500_ANACONF4_ENHFR 2 | ||
213 | #define AB8500_ANACONF4_ENVIB1 1 | ||
214 | #define AB8500_ANACONF4_ENVIB2 0 | ||
215 | |||
216 | /* AB8500_DAPATHCONF */ | ||
217 | #define AB8500_DAPATHCONF_ENDACEAR 6 | ||
218 | #define AB8500_DAPATHCONF_ENDACHSL 5 | ||
219 | #define AB8500_DAPATHCONF_ENDACHSR 4 | ||
220 | #define AB8500_DAPATHCONF_ENDACHFL 3 | ||
221 | #define AB8500_DAPATHCONF_ENDACHFR 2 | ||
222 | #define AB8500_DAPATHCONF_ENDACVIB1 1 | ||
223 | #define AB8500_DAPATHCONF_ENDACVIB2 0 | ||
224 | |||
225 | /* AB8500_MUTECONF */ | ||
226 | #define AB8500_MUTECONF_MUTEAR 6 | ||
227 | #define AB8500_MUTECONF_MUTHSL 5 | ||
228 | #define AB8500_MUTECONF_MUTHSR 4 | ||
229 | #define AB8500_MUTECONF_MUTDACEAR 2 | ||
230 | #define AB8500_MUTECONF_MUTDACHSL 1 | ||
231 | #define AB8500_MUTECONF_MUTDACHSR 0 | ||
232 | |||
233 | /* AB8500_SHORTCIRCONF */ | ||
234 | #define AB8500_SHORTCIRCONF_ENSHORTPWD 7 | ||
235 | #define AB8500_SHORTCIRCONF_EARSHORTDIS 6 | ||
236 | #define AB8500_SHORTCIRCONF_HSSHORTDIS 5 | ||
237 | #define AB8500_SHORTCIRCONF_HSPULLDEN 4 | ||
238 | #define AB8500_SHORTCIRCONF_HSOSCEN 2 | ||
239 | #define AB8500_SHORTCIRCONF_HSFADDIS 1 | ||
240 | #define AB8500_SHORTCIRCONF_HSZCDDIS 0 | ||
241 | /* Zero cross should be disabled */ | ||
242 | |||
243 | /* AB8500_ANACONF5 */ | ||
244 | #define AB8500_ANACONF5_ENCPHS 7 | ||
245 | #define AB8500_ANACONF5_HSLDACTOLOL 5 | ||
246 | #define AB8500_ANACONF5_HSRDACTOLOR 4 | ||
247 | #define AB8500_ANACONF5_ENLOL 3 | ||
248 | #define AB8500_ANACONF5_ENLOR 2 | ||
249 | #define AB8500_ANACONF5_HSAUTOEN 0 | ||
250 | |||
251 | /* AB8500_ENVCPCONF */ | ||
252 | #define AB8500_ENVCPCONF_ENVDETHTHRE 4 | ||
253 | #define AB8500_ENVCPCONF_ENVDETLTHRE 0 | ||
254 | #define AB8500_ENVCPCONF_ENVDETHTHRE_MAX 0x0F | ||
255 | #define AB8500_ENVCPCONF_ENVDETLTHRE_MAX 0x0F | ||
256 | |||
257 | /* AB8500_SIGENVCONF */ | ||
258 | #define AB8500_SIGENVCONF_CPLVEN 5 | ||
259 | #define AB8500_SIGENVCONF_ENVDETCPEN 4 | ||
260 | #define AB8500_SIGENVCONF_ENVDETTIME 0 | ||
261 | #define AB8500_SIGENVCONF_ENVDETTIME_MAX 0x0F | ||
262 | |||
263 | /* AB8500_PWMGENCONF1 */ | ||
264 | #define AB8500_PWMGENCONF1_PWMTOVIB1 7 | ||
265 | #define AB8500_PWMGENCONF1_PWMTOVIB2 6 | ||
266 | #define AB8500_PWMGENCONF1_PWM1CTRL 5 | ||
267 | #define AB8500_PWMGENCONF1_PWM2CTRL 4 | ||
268 | #define AB8500_PWMGENCONF1_PWM1NCTRL 3 | ||
269 | #define AB8500_PWMGENCONF1_PWM1PCTRL 2 | ||
270 | #define AB8500_PWMGENCONF1_PWM2NCTRL 1 | ||
271 | #define AB8500_PWMGENCONF1_PWM2PCTRL 0 | ||
272 | |||
273 | /* AB8500_PWMGENCONF2 */ | ||
274 | /* AB8500_PWMGENCONF3 */ | ||
275 | /* AB8500_PWMGENCONF4 */ | ||
276 | /* AB8500_PWMGENCONF5 */ | ||
277 | #define AB8500_PWMGENCONFX_PWMVIBXPOL 7 | ||
278 | #define AB8500_PWMGENCONFX_PWMVIBXDUTCYC 0 | ||
279 | #define AB8500_PWMGENCONFX_PWMVIBXDUTCYC_MAX 0x64 | ||
280 | |||
281 | /* AB8500_ANAGAIN1 */ | ||
282 | /* AB8500_ANAGAIN2 */ | ||
283 | #define AB8500_ANAGAINX_ENSEMICX 7 | ||
284 | #define AB8500_ANAGAINX_LOWPOWMICX 6 | ||
285 | #define AB8500_ANAGAINX_MICXGAIN 0 | ||
286 | #define AB8500_ANAGAINX_MICXGAIN_MAX 0x1F | ||
287 | |||
288 | /* AB8500_ANAGAIN3 */ | ||
289 | #define AB8500_ANAGAIN3_HSLGAIN 4 | ||
290 | #define AB8500_ANAGAIN3_HSRGAIN 0 | ||
291 | #define AB8500_ANAGAIN3_HSXGAIN_MAX 0x0F | ||
292 | |||
293 | /* AB8500_ANAGAIN4 */ | ||
294 | #define AB8500_ANAGAIN4_LINLGAIN 4 | ||
295 | #define AB8500_ANAGAIN4_LINRGAIN 0 | ||
296 | #define AB8500_ANAGAIN4_LINXGAIN_MAX 0x0F | ||
297 | |||
298 | /* AB8500_DIGLINHSLGAIN */ | ||
299 | /* AB8500_DIGLINHSRGAIN */ | ||
300 | #define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN 0 | ||
301 | #define AB8500_DIGLINHSXGAIN_LINTOHSXGAIN_MAX 0x13 | ||
302 | |||
303 | /* AB8500_ADFILTCONF */ | ||
304 | #define AB8500_ADFILTCONF_AD1NH 7 | ||
305 | #define AB8500_ADFILTCONF_AD2NH 6 | ||
306 | #define AB8500_ADFILTCONF_AD3NH 5 | ||
307 | #define AB8500_ADFILTCONF_AD4NH 4 | ||
308 | #define AB8500_ADFILTCONF_AD1VOICE 3 | ||
309 | #define AB8500_ADFILTCONF_AD2VOICE 2 | ||
310 | #define AB8500_ADFILTCONF_AD3VOICE 1 | ||
311 | #define AB8500_ADFILTCONF_AD4VOICE 0 | ||
312 | |||
313 | /* AB8500_DIGIFCONF1 */ | ||
314 | #define AB8500_DIGIFCONF1_ENMASTGEN 7 | ||
315 | #define AB8500_DIGIFCONF1_IF1BITCLKOS1 6 | ||
316 | #define AB8500_DIGIFCONF1_IF1BITCLKOS0 5 | ||
317 | #define AB8500_DIGIFCONF1_ENFSBITCLK1 4 | ||
318 | #define AB8500_DIGIFCONF1_IF0BITCLKOS1 2 | ||
319 | #define AB8500_DIGIFCONF1_IF0BITCLKOS0 1 | ||
320 | #define AB8500_DIGIFCONF1_ENFSBITCLK0 0 | ||
321 | |||
322 | /* AB8500_DIGIFCONF2 */ | ||
323 | #define AB8500_DIGIFCONF2_FSYNC0P 6 | ||
324 | #define AB8500_DIGIFCONF2_BITCLK0P 5 | ||
325 | #define AB8500_DIGIFCONF2_IF0DEL 4 | ||
326 | #define AB8500_DIGIFCONF2_IF0FORMAT1 3 | ||
327 | #define AB8500_DIGIFCONF2_IF0FORMAT0 2 | ||
328 | #define AB8500_DIGIFCONF2_IF0WL1 1 | ||
329 | #define AB8500_DIGIFCONF2_IF0WL0 0 | ||
330 | |||
331 | /* AB8500_DIGIFCONF3 */ | ||
332 | #define AB8500_DIGIFCONF3_IF0DATOIF1AD 7 | ||
333 | #define AB8500_DIGIFCONF3_IF0CLKTOIF1CLK 6 | ||
334 | #define AB8500_DIGIFCONF3_IF1MASTER 5 | ||
335 | #define AB8500_DIGIFCONF3_IF1DATOIF0AD 3 | ||
336 | #define AB8500_DIGIFCONF3_IF1CLKTOIF0CLK 2 | ||
337 | #define AB8500_DIGIFCONF3_IF0MASTER 1 | ||
338 | #define AB8500_DIGIFCONF3_IF0BFIFOEN 0 | ||
339 | |||
340 | /* AB8500_DIGIFCONF4 */ | ||
341 | #define AB8500_DIGIFCONF4_FSYNC1P 6 | ||
342 | #define AB8500_DIGIFCONF4_BITCLK1P 5 | ||
343 | #define AB8500_DIGIFCONF4_IF1DEL 4 | ||
344 | #define AB8500_DIGIFCONF4_IF1FORMAT1 3 | ||
345 | #define AB8500_DIGIFCONF4_IF1FORMAT0 2 | ||
346 | #define AB8500_DIGIFCONF4_IF1WL1 1 | ||
347 | #define AB8500_DIGIFCONF4_IF1WL0 0 | ||
348 | |||
349 | /* AB8500_ADSLOTSELX */ | ||
350 | #define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_ODD 0x00 | ||
351 | #define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_ODD 0x01 | ||
352 | #define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_ODD 0x02 | ||
353 | #define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_ODD 0x03 | ||
354 | #define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_ODD 0x04 | ||
355 | #define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_ODD 0x05 | ||
356 | #define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_ODD 0x06 | ||
357 | #define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_ODD 0x07 | ||
358 | #define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_ODD 0x08 | ||
359 | #define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_ODD 0x0F | ||
360 | #define AB8500_ADSLOTSELX_AD_OUT1_TO_SLOT_EVEN 0x00 | ||
361 | #define AB8500_ADSLOTSELX_AD_OUT2_TO_SLOT_EVEN 0x10 | ||
362 | #define AB8500_ADSLOTSELX_AD_OUT3_TO_SLOT_EVEN 0x20 | ||
363 | #define AB8500_ADSLOTSELX_AD_OUT4_TO_SLOT_EVEN 0x30 | ||
364 | #define AB8500_ADSLOTSELX_AD_OUT5_TO_SLOT_EVEN 0x40 | ||
365 | #define AB8500_ADSLOTSELX_AD_OUT6_TO_SLOT_EVEN 0x50 | ||
366 | #define AB8500_ADSLOTSELX_AD_OUT7_TO_SLOT_EVEN 0x60 | ||
367 | #define AB8500_ADSLOTSELX_AD_OUT8_TO_SLOT_EVEN 0x70 | ||
368 | #define AB8500_ADSLOTSELX_ZEROES_TO_SLOT_EVEN 0x80 | ||
369 | #define AB8500_ADSLOTSELX_TRISTATE_TO_SLOT_EVEN 0xF0 | ||
370 | #define AB8500_ADSLOTSELX_EVEN_SHIFT 0 | ||
371 | #define AB8500_ADSLOTSELX_ODD_SHIFT 4 | ||
372 | |||
373 | /* AB8500_ADSLOTHIZCTRL1 */ | ||
374 | /* AB8500_ADSLOTHIZCTRL2 */ | ||
375 | /* AB8500_ADSLOTHIZCTRL3 */ | ||
376 | /* AB8500_ADSLOTHIZCTRL4 */ | ||
377 | /* AB8500_DASLOTCONF1 */ | ||
378 | #define AB8500_DASLOTCONF1_DA12VOICE 7 | ||
379 | #define AB8500_DASLOTCONF1_SWAPDA12_34 6 | ||
380 | #define AB8500_DASLOTCONF1_DAI7TOADO1 5 | ||
381 | |||
382 | /* AB8500_DASLOTCONF2 */ | ||
383 | #define AB8500_DASLOTCONF2_DAI8TOADO2 5 | ||
384 | |||
385 | /* AB8500_DASLOTCONF3 */ | ||
386 | #define AB8500_DASLOTCONF3_DA34VOICE 7 | ||
387 | #define AB8500_DASLOTCONF3_DAI7TOADO3 5 | ||
388 | |||
389 | /* AB8500_DASLOTCONF4 */ | ||
390 | #define AB8500_DASLOTCONF4_DAI8TOADO4 5 | ||
391 | |||
392 | /* AB8500_DASLOTCONF5 */ | ||
393 | #define AB8500_DASLOTCONF5_DA56VOICE 7 | ||
394 | #define AB8500_DASLOTCONF5_DAI7TOADO5 5 | ||
395 | |||
396 | /* AB8500_DASLOTCONF6 */ | ||
397 | #define AB8500_DASLOTCONF6_DAI8TOADO6 5 | ||
398 | |||
399 | /* AB8500_DASLOTCONF7 */ | ||
400 | #define AB8500_DASLOTCONF7_DAI8TOADO7 5 | ||
401 | |||
402 | /* AB8500_DASLOTCONF8 */ | ||
403 | #define AB8500_DASLOTCONF8_DAI7TOADO8 5 | ||
404 | |||
405 | #define AB8500_DASLOTCONFX_SLTODAX_SHIFT 0 | ||
406 | #define AB8500_DASLOTCONFX_SLTODAX_MASK 0x1F | ||
407 | |||
408 | /* AB8500_CLASSDCONF1 */ | ||
409 | #define AB8500_CLASSDCONF1_PARLHF 7 | ||
410 | #define AB8500_CLASSDCONF1_PARLVIB 6 | ||
411 | #define AB8500_CLASSDCONF1_VIB1SWAPEN 3 | ||
412 | #define AB8500_CLASSDCONF1_VIB2SWAPEN 2 | ||
413 | #define AB8500_CLASSDCONF1_HFLSWAPEN 1 | ||
414 | #define AB8500_CLASSDCONF1_HFRSWAPEN 0 | ||
415 | |||
416 | /* AB8500_CLASSDCONF2 */ | ||
417 | #define AB8500_CLASSDCONF2_FIRBYP3 7 | ||
418 | #define AB8500_CLASSDCONF2_FIRBYP2 6 | ||
419 | #define AB8500_CLASSDCONF2_FIRBYP1 5 | ||
420 | #define AB8500_CLASSDCONF2_FIRBYP0 4 | ||
421 | #define AB8500_CLASSDCONF2_HIGHVOLEN3 3 | ||
422 | #define AB8500_CLASSDCONF2_HIGHVOLEN2 2 | ||
423 | #define AB8500_CLASSDCONF2_HIGHVOLEN1 1 | ||
424 | #define AB8500_CLASSDCONF2_HIGHVOLEN0 0 | ||
425 | |||
426 | /* AB8500_CLASSDCONF3 */ | ||
427 | #define AB8500_CLASSDCONF3_DITHHPGAIN 4 | ||
428 | #define AB8500_CLASSDCONF3_DITHHPGAIN_MAX 0x0A | ||
429 | #define AB8500_CLASSDCONF3_DITHWGAIN 0 | ||
430 | #define AB8500_CLASSDCONF3_DITHWGAIN_MAX 0x0A | ||
431 | |||
432 | /* AB8500_DMICFILTCONF */ | ||
433 | #define AB8500_DMICFILTCONF_ANCINSEL 7 | ||
434 | #define AB8500_DMICFILTCONF_DA3TOEAR 6 | ||
435 | #define AB8500_DMICFILTCONF_DMIC1SINC3 5 | ||
436 | #define AB8500_DMICFILTCONF_DMIC2SINC3 4 | ||
437 | #define AB8500_DMICFILTCONF_DMIC3SINC3 3 | ||
438 | #define AB8500_DMICFILTCONF_DMIC4SINC3 2 | ||
439 | #define AB8500_DMICFILTCONF_DMIC5SINC3 1 | ||
440 | #define AB8500_DMICFILTCONF_DMIC6SINC3 0 | ||
441 | |||
442 | /* AB8500_DIGMULTCONF1 */ | ||
443 | #define AB8500_DIGMULTCONF1_DATOHSLEN 7 | ||
444 | #define AB8500_DIGMULTCONF1_DATOHSREN 6 | ||
445 | #define AB8500_DIGMULTCONF1_AD1SEL 5 | ||
446 | #define AB8500_DIGMULTCONF1_AD2SEL 4 | ||
447 | #define AB8500_DIGMULTCONF1_AD3SEL 3 | ||
448 | #define AB8500_DIGMULTCONF1_AD5SEL 2 | ||
449 | #define AB8500_DIGMULTCONF1_AD6SEL 1 | ||
450 | #define AB8500_DIGMULTCONF1_ANCSEL 0 | ||
451 | |||
452 | /* AB8500_DIGMULTCONF2 */ | ||
453 | #define AB8500_DIGMULTCONF2_DATOHFREN 7 | ||
454 | #define AB8500_DIGMULTCONF2_DATOHFLEN 6 | ||
455 | #define AB8500_DIGMULTCONF2_HFRSEL 5 | ||
456 | #define AB8500_DIGMULTCONF2_HFLSEL 4 | ||
457 | #define AB8500_DIGMULTCONF2_FIRSID1SEL 2 | ||
458 | #define AB8500_DIGMULTCONF2_FIRSID2SEL 0 | ||
459 | |||
460 | /* AB8500_ADDIGGAIN1 */ | ||
461 | /* AB8500_ADDIGGAIN2 */ | ||
462 | /* AB8500_ADDIGGAIN3 */ | ||
463 | /* AB8500_ADDIGGAIN4 */ | ||
464 | /* AB8500_ADDIGGAIN5 */ | ||
465 | /* AB8500_ADDIGGAIN6 */ | ||
466 | #define AB8500_ADDIGGAINX_FADEDISADX 6 | ||
467 | #define AB8500_ADDIGGAINX_ADXGAIN_MAX 0x3F | ||
468 | |||
469 | /* AB8500_DADIGGAIN1 */ | ||
470 | /* AB8500_DADIGGAIN2 */ | ||
471 | /* AB8500_DADIGGAIN3 */ | ||
472 | /* AB8500_DADIGGAIN4 */ | ||
473 | /* AB8500_DADIGGAIN5 */ | ||
474 | /* AB8500_DADIGGAIN6 */ | ||
475 | #define AB8500_DADIGGAINX_FADEDISDAX 6 | ||
476 | #define AB8500_DADIGGAINX_DAXGAIN_MAX 0x3F | ||
477 | |||
478 | /* AB8500_ADDIGLOOPGAIN1 */ | ||
479 | /* AB8500_ADDIGLOOPGAIN2 */ | ||
480 | #define AB8500_ADDIGLOOPGAINX_FADEDISADXL 6 | ||
481 | #define AB8500_ADDIGLOOPGAINX_ADXLBGAIN_MAX 0x3F | ||
482 | |||
483 | /* AB8500_HSLEARDIGGAIN */ | ||
484 | #define AB8500_HSLEARDIGGAIN_HSSINC1 7 | ||
485 | #define AB8500_HSLEARDIGGAIN_FADEDISHSL 4 | ||
486 | #define AB8500_HSLEARDIGGAIN_HSLDGAIN_MAX 0x09 | ||
487 | |||
488 | /* AB8500_HSRDIGGAIN */ | ||
489 | #define AB8500_HSRDIGGAIN_FADESPEED 6 | ||
490 | #define AB8500_HSRDIGGAIN_FADEDISHSR 4 | ||
491 | #define AB8500_HSRDIGGAIN_HSRDGAIN_MAX 0x09 | ||
492 | |||
493 | /* AB8500_SIDFIRGAIN1 */ | ||
494 | /* AB8500_SIDFIRGAIN2 */ | ||
495 | #define AB8500_SIDFIRGAINX_FIRSIDXGAIN_MAX 0x1F | ||
496 | |||
497 | /* AB8500_ANCCONF1 */ | ||
498 | #define AB8500_ANCCONF1_ANCIIRUPDATE 3 | ||
499 | #define AB8500_ANCCONF1_ENANC 2 | ||
500 | #define AB8500_ANCCONF1_ANCIIRINIT 1 | ||
501 | #define AB8500_ANCCONF1_ANCFIRUPDATE 0 | ||
502 | |||
503 | /* AB8500_ANCCONF2 */ | ||
504 | #define AB8500_ANCCONF2_SHIFT 5 | ||
505 | #define AB8500_ANCCONF2_MIN -0x10 | ||
506 | #define AB8500_ANCCONF2_MAX 0xF | ||
507 | |||
508 | /* AB8500_ANCCONF3 */ | ||
509 | #define AB8500_ANCCONF3_SHIFT 5 | ||
510 | #define AB8500_ANCCONF3_MIN -0x10 | ||
511 | #define AB8500_ANCCONF3_MAX 0xF | ||
512 | |||
513 | /* AB8500_ANCCONF4 */ | ||
514 | #define AB8500_ANCCONF4_SHIFT 5 | ||
515 | #define AB8500_ANCCONF4_MIN -0x10 | ||
516 | #define AB8500_ANCCONF4_MAX 0xF | ||
517 | |||
518 | /* AB8500_ANC_FIR_COEFFS */ | ||
519 | #define AB8500_ANC_FIR_COEFF_MIN -0x8000 | ||
520 | #define AB8500_ANC_FIR_COEFF_MAX 0x7FFF | ||
521 | #define AB8500_ANC_FIR_COEFFS 15 | ||
522 | |||
523 | /* AB8500_ANC_IIR_COEFFS */ | ||
524 | #define AB8500_ANC_IIR_COEFF_MIN -0x800000 | ||
525 | #define AB8500_ANC_IIR_COEFF_MAX 0x7FFFFF | ||
526 | #define AB8500_ANC_IIR_COEFFS 24 | ||
527 | /* AB8500_ANC_WARP_DELAY */ | ||
528 | #define AB8500_ANC_WARP_DELAY_SHIFT 16 | ||
529 | #define AB8500_ANC_WARP_DELAY_MIN 0x0000 | ||
530 | #define AB8500_ANC_WARP_DELAY_MAX 0xFFFF | ||
531 | |||
532 | /* AB8500_ANCCONF11 */ | ||
533 | /* AB8500_ANCCONF12 */ | ||
534 | /* AB8500_ANCCONF13 */ | ||
535 | /* AB8500_ANCCONF14 */ | ||
536 | |||
537 | /* AB8500_SIDFIRADR */ | ||
538 | #define AB8500_SIDFIRADR_FIRSIDSET 7 | ||
539 | #define AB8500_SIDFIRADR_ADDRESS_SHIFT 0 | ||
540 | #define AB8500_SIDFIRADR_ADDRESS_MAX 0x7F | ||
541 | |||
542 | /* AB8500_SIDFIRCOEF1 */ | ||
543 | /* AB8500_SIDFIRCOEF2 */ | ||
544 | #define AB8500_SID_FIR_COEFF_MIN 0 | ||
545 | #define AB8500_SID_FIR_COEFF_MAX 0xFFFF | ||
546 | #define AB8500_SID_FIR_COEFFS 128 | ||
547 | |||
548 | /* AB8500_SIDFIRCONF */ | ||
549 | #define AB8500_SIDFIRCONF_ENFIRSIDS 2 | ||
550 | #define AB8500_SIDFIRCONF_FIRSIDSTOIF1 1 | ||
551 | #define AB8500_SIDFIRCONF_FIRSIDBUSY 0 | ||
552 | |||
553 | /* AB8500_AUDINTMASK1 */ | ||
554 | /* AB8500_AUDINTSOURCE1 */ | ||
555 | /* AB8500_AUDINTMASK2 */ | ||
556 | /* AB8500_AUDINTSOURCE2 */ | ||
557 | |||
558 | /* AB8500_FIFOCONF1 */ | ||
559 | #define AB8500_FIFOCONF1_BFIFOMASK 0x80 | ||
560 | #define AB8500_FIFOCONF1_BFIFO19M2 0x40 | ||
561 | #define AB8500_FIFOCONF1_BFIFOINT_SHIFT 0 | ||
562 | #define AB8500_FIFOCONF1_BFIFOINT_MAX 0x3F | ||
563 | |||
564 | /* AB8500_FIFOCONF2 */ | ||
565 | #define AB8500_FIFOCONF2_BFIFOTX_SHIFT 0 | ||
566 | #define AB8500_FIFOCONF2_BFIFOTX_MAX 0xFF | ||
567 | |||
568 | /* AB8500_FIFOCONF3 */ | ||
569 | #define AB8500_FIFOCONF3_BFIFOEXSL_SHIFT 5 | ||
570 | #define AB8500_FIFOCONF3_BFIFOEXSL_MAX 0x5 | ||
571 | #define AB8500_FIFOCONF3_PREBITCLK0_SHIFT 2 | ||
572 | #define AB8500_FIFOCONF3_PREBITCLK0_MAX 0x7 | ||
573 | #define AB8500_FIFOCONF3_BFIFOMAST_SHIFT 1 | ||
574 | #define AB8500_FIFOCONF3_BFIFORUN_SHIFT 0 | ||
575 | |||
576 | /* AB8500_FIFOCONF4 */ | ||
577 | #define AB8500_FIFOCONF4_BFIFOFRAMSW_SHIFT 0 | ||
578 | #define AB8500_FIFOCONF4_BFIFOFRAMSW_MAX 0xFF | ||
579 | |||
580 | /* AB8500_FIFOCONF5 */ | ||
581 | #define AB8500_FIFOCONF5_BFIFOWAKEUP_SHIFT 0 | ||
582 | #define AB8500_FIFOCONF5_BFIFOWAKEUP_MAX 0xFF | ||
583 | |||
584 | /* AB8500_FIFOCONF6 */ | ||
585 | #define AB8500_FIFOCONF6_BFIFOSAMPLE_SHIFT 0 | ||
586 | #define AB8500_FIFOCONF6_BFIFOSAMPLE_MAX 0xFF | ||
587 | |||
588 | /* AB8500_AUDREV */ | ||
589 | |||
590 | #endif | ||
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index 2023c749f232..ea06b834a7de 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -91,11 +91,6 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) | |||
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | static int ac97_soc_remove(struct snd_soc_codec *codec) | ||
95 | { | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | #ifdef CONFIG_PM | 94 | #ifdef CONFIG_PM |
100 | static int ac97_soc_suspend(struct snd_soc_codec *codec) | 95 | static int ac97_soc_suspend(struct snd_soc_codec *codec) |
101 | { | 96 | { |
@@ -119,7 +114,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ac97 = { | |||
119 | .write = ac97_write, | 114 | .write = ac97_write, |
120 | .read = ac97_read, | 115 | .read = ac97_read, |
121 | .probe = ac97_soc_probe, | 116 | .probe = ac97_soc_probe, |
122 | .remove = ac97_soc_remove, | ||
123 | .suspend = ac97_soc_suspend, | 117 | .suspend = ac97_soc_suspend, |
124 | .resume = ac97_soc_resume, | 118 | .resume = ac97_soc_resume, |
125 | }; | 119 | }; |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c new file mode 100644 index 000000000000..5c9cacaf2d52 --- /dev/null +++ b/sound/soc/codecs/arizona.c | |||
@@ -0,0 +1,937 @@ | |||
1 | /* | ||
2 | * arizona.c - Wolfson Arizona class device shared support | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/gcd.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/pm_runtime.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/tlv.h> | ||
19 | |||
20 | #include <linux/mfd/arizona/core.h> | ||
21 | #include <linux/mfd/arizona/registers.h> | ||
22 | |||
23 | #include "arizona.h" | ||
24 | |||
25 | #define ARIZONA_AIF_BCLK_CTRL 0x00 | ||
26 | #define ARIZONA_AIF_TX_PIN_CTRL 0x01 | ||
27 | #define ARIZONA_AIF_RX_PIN_CTRL 0x02 | ||
28 | #define ARIZONA_AIF_RATE_CTRL 0x03 | ||
29 | #define ARIZONA_AIF_FORMAT 0x04 | ||
30 | #define ARIZONA_AIF_TX_BCLK_RATE 0x05 | ||
31 | #define ARIZONA_AIF_RX_BCLK_RATE 0x06 | ||
32 | #define ARIZONA_AIF_FRAME_CTRL_1 0x07 | ||
33 | #define ARIZONA_AIF_FRAME_CTRL_2 0x08 | ||
34 | #define ARIZONA_AIF_FRAME_CTRL_3 0x09 | ||
35 | #define ARIZONA_AIF_FRAME_CTRL_4 0x0A | ||
36 | #define ARIZONA_AIF_FRAME_CTRL_5 0x0B | ||
37 | #define ARIZONA_AIF_FRAME_CTRL_6 0x0C | ||
38 | #define ARIZONA_AIF_FRAME_CTRL_7 0x0D | ||
39 | #define ARIZONA_AIF_FRAME_CTRL_8 0x0E | ||
40 | #define ARIZONA_AIF_FRAME_CTRL_9 0x0F | ||
41 | #define ARIZONA_AIF_FRAME_CTRL_10 0x10 | ||
42 | #define ARIZONA_AIF_FRAME_CTRL_11 0x11 | ||
43 | #define ARIZONA_AIF_FRAME_CTRL_12 0x12 | ||
44 | #define ARIZONA_AIF_FRAME_CTRL_13 0x13 | ||
45 | #define ARIZONA_AIF_FRAME_CTRL_14 0x14 | ||
46 | #define ARIZONA_AIF_FRAME_CTRL_15 0x15 | ||
47 | #define ARIZONA_AIF_FRAME_CTRL_16 0x16 | ||
48 | #define ARIZONA_AIF_FRAME_CTRL_17 0x17 | ||
49 | #define ARIZONA_AIF_FRAME_CTRL_18 0x18 | ||
50 | #define ARIZONA_AIF_TX_ENABLES 0x19 | ||
51 | #define ARIZONA_AIF_RX_ENABLES 0x1A | ||
52 | #define ARIZONA_AIF_FORCE_WRITE 0x1B | ||
53 | |||
54 | #define arizona_fll_err(_fll, fmt, ...) \ | ||
55 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | ||
56 | #define arizona_fll_warn(_fll, fmt, ...) \ | ||
57 | dev_warn(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | ||
58 | #define arizona_fll_dbg(_fll, fmt, ...) \ | ||
59 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | ||
60 | |||
61 | #define arizona_aif_err(_dai, fmt, ...) \ | ||
62 | dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | ||
63 | #define arizona_aif_warn(_dai, fmt, ...) \ | ||
64 | dev_warn(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | ||
65 | #define arizona_aif_dbg(_dai, fmt, ...) \ | ||
66 | dev_err(_dai->dev, "AIF%d: " fmt, _dai->id, ##__VA_ARGS__) | ||
67 | |||
68 | const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS] = { | ||
69 | "None", | ||
70 | "Tone Generator 1", | ||
71 | "Tone Generator 2", | ||
72 | "Haptics", | ||
73 | "AEC", | ||
74 | "Mic Mute Mixer", | ||
75 | "Noise Generator", | ||
76 | "IN1L", | ||
77 | "IN1R", | ||
78 | "IN2L", | ||
79 | "IN2R", | ||
80 | "IN3L", | ||
81 | "IN3R", | ||
82 | "IN4L", | ||
83 | "IN4R", | ||
84 | "AIF1RX1", | ||
85 | "AIF1RX2", | ||
86 | "AIF1RX3", | ||
87 | "AIF1RX4", | ||
88 | "AIF1RX5", | ||
89 | "AIF1RX6", | ||
90 | "AIF1RX7", | ||
91 | "AIF1RX8", | ||
92 | "AIF2RX1", | ||
93 | "AIF2RX2", | ||
94 | "AIF3RX1", | ||
95 | "AIF3RX2", | ||
96 | "SLIMRX1", | ||
97 | "SLIMRX2", | ||
98 | "SLIMRX3", | ||
99 | "SLIMRX4", | ||
100 | "SLIMRX5", | ||
101 | "SLIMRX6", | ||
102 | "SLIMRX7", | ||
103 | "SLIMRX8", | ||
104 | "EQ1", | ||
105 | "EQ2", | ||
106 | "EQ3", | ||
107 | "EQ4", | ||
108 | "DRC1L", | ||
109 | "DRC1R", | ||
110 | "DRC2L", | ||
111 | "DRC2R", | ||
112 | "LHPF1", | ||
113 | "LHPF2", | ||
114 | "LHPF3", | ||
115 | "LHPF4", | ||
116 | "DSP1.1", | ||
117 | "DSP1.2", | ||
118 | "DSP1.3", | ||
119 | "DSP1.4", | ||
120 | "DSP1.5", | ||
121 | "DSP1.6", | ||
122 | "ASRC1L", | ||
123 | "ASRC1R", | ||
124 | "ASRC2L", | ||
125 | "ASRC2R", | ||
126 | }; | ||
127 | EXPORT_SYMBOL_GPL(arizona_mixer_texts); | ||
128 | |||
129 | int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS] = { | ||
130 | 0x00, /* None */ | ||
131 | 0x04, /* Tone */ | ||
132 | 0x05, | ||
133 | 0x06, /* Haptics */ | ||
134 | 0x08, /* AEC */ | ||
135 | 0x0c, /* Noise mixer */ | ||
136 | 0x0d, /* Comfort noise */ | ||
137 | 0x10, /* IN1L */ | ||
138 | 0x11, | ||
139 | 0x12, | ||
140 | 0x13, | ||
141 | 0x14, | ||
142 | 0x15, | ||
143 | 0x16, | ||
144 | 0x17, | ||
145 | 0x20, /* AIF1RX1 */ | ||
146 | 0x21, | ||
147 | 0x22, | ||
148 | 0x23, | ||
149 | 0x24, | ||
150 | 0x25, | ||
151 | 0x26, | ||
152 | 0x27, | ||
153 | 0x28, /* AIF2RX1 */ | ||
154 | 0x29, | ||
155 | 0x30, /* AIF3RX1 */ | ||
156 | 0x31, | ||
157 | 0x38, /* SLIMRX1 */ | ||
158 | 0x39, | ||
159 | 0x3a, | ||
160 | 0x3b, | ||
161 | 0x3c, | ||
162 | 0x3d, | ||
163 | 0x3e, | ||
164 | 0x3f, | ||
165 | 0x50, /* EQ1 */ | ||
166 | 0x51, | ||
167 | 0x52, | ||
168 | 0x53, | ||
169 | 0x58, /* DRC1L */ | ||
170 | 0x59, | ||
171 | 0x5a, | ||
172 | 0x5b, | ||
173 | 0x60, /* LHPF1 */ | ||
174 | 0x61, | ||
175 | 0x62, | ||
176 | 0x63, | ||
177 | 0x68, /* DSP1.1 */ | ||
178 | 0x69, | ||
179 | 0x6a, | ||
180 | 0x6b, | ||
181 | 0x6c, | ||
182 | 0x6d, | ||
183 | 0x90, /* ASRC1L */ | ||
184 | 0x91, | ||
185 | 0x92, | ||
186 | 0x93, | ||
187 | }; | ||
188 | EXPORT_SYMBOL_GPL(arizona_mixer_values); | ||
189 | |||
190 | const DECLARE_TLV_DB_SCALE(arizona_mixer_tlv, -3200, 100, 0); | ||
191 | EXPORT_SYMBOL_GPL(arizona_mixer_tlv); | ||
192 | |||
193 | static const char *arizona_lhpf_mode_text[] = { | ||
194 | "Low-pass", "High-pass" | ||
195 | }; | ||
196 | |||
197 | const struct soc_enum arizona_lhpf1_mode = | ||
198 | SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2, | ||
199 | arizona_lhpf_mode_text); | ||
200 | EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); | ||
201 | |||
202 | const struct soc_enum arizona_lhpf2_mode = | ||
203 | SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2, | ||
204 | arizona_lhpf_mode_text); | ||
205 | EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); | ||
206 | |||
207 | const struct soc_enum arizona_lhpf3_mode = | ||
208 | SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2, | ||
209 | arizona_lhpf_mode_text); | ||
210 | EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); | ||
211 | |||
212 | const struct soc_enum arizona_lhpf4_mode = | ||
213 | SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2, | ||
214 | arizona_lhpf_mode_text); | ||
215 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); | ||
216 | |||
217 | int arizona_in_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, | ||
218 | int event) | ||
219 | { | ||
220 | return 0; | ||
221 | } | ||
222 | EXPORT_SYMBOL_GPL(arizona_in_ev); | ||
223 | |||
224 | int arizona_out_ev(struct snd_soc_dapm_widget *w, | ||
225 | struct snd_kcontrol *kcontrol, | ||
226 | int event) | ||
227 | { | ||
228 | return 0; | ||
229 | } | ||
230 | EXPORT_SYMBOL_GPL(arizona_out_ev); | ||
231 | |||
232 | int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, | ||
233 | int source, unsigned int freq, int dir) | ||
234 | { | ||
235 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
236 | struct arizona *arizona = priv->arizona; | ||
237 | char *name; | ||
238 | unsigned int reg; | ||
239 | unsigned int mask = ARIZONA_SYSCLK_FREQ_MASK | ARIZONA_SYSCLK_SRC_MASK; | ||
240 | unsigned int val = source << ARIZONA_SYSCLK_SRC_SHIFT; | ||
241 | unsigned int *clk; | ||
242 | |||
243 | switch (clk_id) { | ||
244 | case ARIZONA_CLK_SYSCLK: | ||
245 | name = "SYSCLK"; | ||
246 | reg = ARIZONA_SYSTEM_CLOCK_1; | ||
247 | clk = &priv->sysclk; | ||
248 | mask |= ARIZONA_SYSCLK_FRAC; | ||
249 | break; | ||
250 | case ARIZONA_CLK_ASYNCCLK: | ||
251 | name = "ASYNCCLK"; | ||
252 | reg = ARIZONA_ASYNC_CLOCK_1; | ||
253 | clk = &priv->asyncclk; | ||
254 | break; | ||
255 | default: | ||
256 | return -EINVAL; | ||
257 | } | ||
258 | |||
259 | switch (freq) { | ||
260 | case 5644800: | ||
261 | case 6144000: | ||
262 | break; | ||
263 | case 11289600: | ||
264 | case 12288000: | ||
265 | val |= 1 << ARIZONA_SYSCLK_FREQ_SHIFT; | ||
266 | break; | ||
267 | case 22579200: | ||
268 | case 24576000: | ||
269 | val |= 2 << ARIZONA_SYSCLK_FREQ_SHIFT; | ||
270 | break; | ||
271 | case 45158400: | ||
272 | case 49152000: | ||
273 | val |= 3 << ARIZONA_SYSCLK_FREQ_SHIFT; | ||
274 | break; | ||
275 | default: | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | *clk = freq; | ||
280 | |||
281 | if (freq % 6144000) | ||
282 | val |= ARIZONA_SYSCLK_FRAC; | ||
283 | |||
284 | dev_dbg(arizona->dev, "%s set to %uHz", name, freq); | ||
285 | |||
286 | return regmap_update_bits(arizona->regmap, reg, mask, val); | ||
287 | } | ||
288 | EXPORT_SYMBOL_GPL(arizona_set_sysclk); | ||
289 | |||
290 | static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
291 | { | ||
292 | struct snd_soc_codec *codec = dai->codec; | ||
293 | int lrclk, bclk, mode, base; | ||
294 | |||
295 | base = dai->driver->base; | ||
296 | |||
297 | lrclk = 0; | ||
298 | bclk = 0; | ||
299 | |||
300 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
301 | case SND_SOC_DAIFMT_DSP_A: | ||
302 | mode = 0; | ||
303 | break; | ||
304 | case SND_SOC_DAIFMT_DSP_B: | ||
305 | mode = 1; | ||
306 | break; | ||
307 | case SND_SOC_DAIFMT_I2S: | ||
308 | mode = 2; | ||
309 | break; | ||
310 | case SND_SOC_DAIFMT_LEFT_J: | ||
311 | mode = 3; | ||
312 | break; | ||
313 | default: | ||
314 | arizona_aif_err(dai, "Unsupported DAI format %d\n", | ||
315 | fmt & SND_SOC_DAIFMT_FORMAT_MASK); | ||
316 | return -EINVAL; | ||
317 | } | ||
318 | |||
319 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
320 | case SND_SOC_DAIFMT_CBS_CFS: | ||
321 | break; | ||
322 | case SND_SOC_DAIFMT_CBS_CFM: | ||
323 | lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR; | ||
324 | break; | ||
325 | case SND_SOC_DAIFMT_CBM_CFS: | ||
326 | bclk |= ARIZONA_AIF1_BCLK_MSTR; | ||
327 | break; | ||
328 | case SND_SOC_DAIFMT_CBM_CFM: | ||
329 | bclk |= ARIZONA_AIF1_BCLK_MSTR; | ||
330 | lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR; | ||
331 | break; | ||
332 | default: | ||
333 | arizona_aif_err(dai, "Unsupported master mode %d\n", | ||
334 | fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
335 | return -EINVAL; | ||
336 | } | ||
337 | |||
338 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
339 | case SND_SOC_DAIFMT_NB_NF: | ||
340 | break; | ||
341 | case SND_SOC_DAIFMT_IB_IF: | ||
342 | bclk |= ARIZONA_AIF1_BCLK_INV; | ||
343 | lrclk |= ARIZONA_AIF1TX_LRCLK_INV; | ||
344 | break; | ||
345 | case SND_SOC_DAIFMT_IB_NF: | ||
346 | bclk |= ARIZONA_AIF1_BCLK_INV; | ||
347 | break; | ||
348 | case SND_SOC_DAIFMT_NB_IF: | ||
349 | lrclk |= ARIZONA_AIF1TX_LRCLK_INV; | ||
350 | break; | ||
351 | default: | ||
352 | return -EINVAL; | ||
353 | } | ||
354 | |||
355 | snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, | ||
356 | ARIZONA_AIF1_BCLK_INV | ARIZONA_AIF1_BCLK_MSTR, | ||
357 | bclk); | ||
358 | snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_PIN_CTRL, | ||
359 | ARIZONA_AIF1TX_LRCLK_INV | | ||
360 | ARIZONA_AIF1TX_LRCLK_MSTR, lrclk); | ||
361 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_PIN_CTRL, | ||
362 | ARIZONA_AIF1RX_LRCLK_INV | | ||
363 | ARIZONA_AIF1RX_LRCLK_MSTR, lrclk); | ||
364 | snd_soc_update_bits(codec, base + ARIZONA_AIF_FORMAT, | ||
365 | ARIZONA_AIF1_FMT_MASK, mode); | ||
366 | |||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | static const int arizona_48k_bclk_rates[] = { | ||
371 | -1, | ||
372 | 48000, | ||
373 | 64000, | ||
374 | 96000, | ||
375 | 128000, | ||
376 | 192000, | ||
377 | 256000, | ||
378 | 384000, | ||
379 | 512000, | ||
380 | 768000, | ||
381 | 1024000, | ||
382 | 1536000, | ||
383 | 2048000, | ||
384 | 3072000, | ||
385 | 4096000, | ||
386 | 6144000, | ||
387 | 8192000, | ||
388 | 12288000, | ||
389 | 24576000, | ||
390 | }; | ||
391 | |||
392 | static const unsigned int arizona_48k_rates[] = { | ||
393 | 12000, | ||
394 | 24000, | ||
395 | 48000, | ||
396 | 96000, | ||
397 | 192000, | ||
398 | 384000, | ||
399 | 768000, | ||
400 | 4000, | ||
401 | 8000, | ||
402 | 16000, | ||
403 | 32000, | ||
404 | 64000, | ||
405 | 128000, | ||
406 | 256000, | ||
407 | 512000, | ||
408 | }; | ||
409 | |||
410 | static const struct snd_pcm_hw_constraint_list arizona_48k_constraint = { | ||
411 | .count = ARRAY_SIZE(arizona_48k_rates), | ||
412 | .list = arizona_48k_rates, | ||
413 | }; | ||
414 | |||
415 | static const int arizona_44k1_bclk_rates[] = { | ||
416 | -1, | ||
417 | 44100, | ||
418 | 58800, | ||
419 | 88200, | ||
420 | 117600, | ||
421 | 177640, | ||
422 | 235200, | ||
423 | 352800, | ||
424 | 470400, | ||
425 | 705600, | ||
426 | 940800, | ||
427 | 1411200, | ||
428 | 1881600, | ||
429 | 2882400, | ||
430 | 3763200, | ||
431 | 5644800, | ||
432 | 7526400, | ||
433 | 11289600, | ||
434 | 22579200, | ||
435 | }; | ||
436 | |||
437 | static const unsigned int arizona_44k1_rates[] = { | ||
438 | 11025, | ||
439 | 22050, | ||
440 | 44100, | ||
441 | 88200, | ||
442 | 176400, | ||
443 | 352800, | ||
444 | 705600, | ||
445 | }; | ||
446 | |||
447 | static const struct snd_pcm_hw_constraint_list arizona_44k1_constraint = { | ||
448 | .count = ARRAY_SIZE(arizona_44k1_rates), | ||
449 | .list = arizona_44k1_rates, | ||
450 | }; | ||
451 | |||
452 | static int arizona_sr_vals[] = { | ||
453 | 0, | ||
454 | 12000, | ||
455 | 24000, | ||
456 | 48000, | ||
457 | 96000, | ||
458 | 192000, | ||
459 | 384000, | ||
460 | 768000, | ||
461 | 0, | ||
462 | 11025, | ||
463 | 22050, | ||
464 | 44100, | ||
465 | 88200, | ||
466 | 176400, | ||
467 | 352800, | ||
468 | 705600, | ||
469 | 4000, | ||
470 | 8000, | ||
471 | 16000, | ||
472 | 32000, | ||
473 | 64000, | ||
474 | 128000, | ||
475 | 256000, | ||
476 | 512000, | ||
477 | }; | ||
478 | |||
479 | static int arizona_startup(struct snd_pcm_substream *substream, | ||
480 | struct snd_soc_dai *dai) | ||
481 | { | ||
482 | struct snd_soc_codec *codec = dai->codec; | ||
483 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
484 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | ||
485 | const struct snd_pcm_hw_constraint_list *constraint; | ||
486 | unsigned int base_rate; | ||
487 | |||
488 | switch (dai_priv->clk) { | ||
489 | case ARIZONA_CLK_SYSCLK: | ||
490 | base_rate = priv->sysclk; | ||
491 | break; | ||
492 | case ARIZONA_CLK_ASYNCCLK: | ||
493 | base_rate = priv->asyncclk; | ||
494 | break; | ||
495 | default: | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | if (base_rate % 8000) | ||
500 | constraint = &arizona_44k1_constraint; | ||
501 | else | ||
502 | constraint = &arizona_48k_constraint; | ||
503 | |||
504 | return snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
505 | SNDRV_PCM_HW_PARAM_RATE, | ||
506 | constraint); | ||
507 | } | ||
508 | |||
509 | static int arizona_hw_params(struct snd_pcm_substream *substream, | ||
510 | struct snd_pcm_hw_params *params, | ||
511 | struct snd_soc_dai *dai) | ||
512 | { | ||
513 | struct snd_soc_codec *codec = dai->codec; | ||
514 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
515 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | ||
516 | int base = dai->driver->base; | ||
517 | const int *rates; | ||
518 | int i; | ||
519 | int bclk, lrclk, wl, frame, sr_val; | ||
520 | |||
521 | if (params_rate(params) % 8000) | ||
522 | rates = &arizona_44k1_bclk_rates[0]; | ||
523 | else | ||
524 | rates = &arizona_48k_bclk_rates[0]; | ||
525 | |||
526 | for (i = 0; i < ARRAY_SIZE(arizona_44k1_bclk_rates); i++) { | ||
527 | if (rates[i] >= snd_soc_params_to_bclk(params) && | ||
528 | rates[i] % params_rate(params) == 0) { | ||
529 | bclk = i; | ||
530 | break; | ||
531 | } | ||
532 | } | ||
533 | if (i == ARRAY_SIZE(arizona_44k1_bclk_rates)) { | ||
534 | arizona_aif_err(dai, "Unsupported sample rate %dHz\n", | ||
535 | params_rate(params)); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | for (i = 0; i < ARRAY_SIZE(arizona_sr_vals); i++) | ||
540 | if (arizona_sr_vals[i] == params_rate(params)) | ||
541 | break; | ||
542 | if (i == ARRAY_SIZE(arizona_sr_vals)) { | ||
543 | arizona_aif_err(dai, "Unsupported sample rate %dHz\n", | ||
544 | params_rate(params)); | ||
545 | return -EINVAL; | ||
546 | } | ||
547 | sr_val = i; | ||
548 | |||
549 | lrclk = snd_soc_params_to_bclk(params) / params_rate(params); | ||
550 | |||
551 | arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", | ||
552 | rates[bclk], rates[bclk] / lrclk); | ||
553 | |||
554 | wl = snd_pcm_format_width(params_format(params)); | ||
555 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; | ||
556 | |||
557 | /* | ||
558 | * We will need to be more flexible than this in future, | ||
559 | * currently we use a single sample rate for SYSCLK. | ||
560 | */ | ||
561 | switch (dai_priv->clk) { | ||
562 | case ARIZONA_CLK_SYSCLK: | ||
563 | snd_soc_update_bits(codec, ARIZONA_SAMPLE_RATE_1, | ||
564 | ARIZONA_SAMPLE_RATE_1_MASK, sr_val); | ||
565 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
566 | ARIZONA_AIF1_RATE_MASK, 0); | ||
567 | break; | ||
568 | case ARIZONA_CLK_ASYNCCLK: | ||
569 | snd_soc_update_bits(codec, ARIZONA_ASYNC_SAMPLE_RATE_1, | ||
570 | ARIZONA_ASYNC_SAMPLE_RATE_MASK, sr_val); | ||
571 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RATE_CTRL, | ||
572 | ARIZONA_AIF1_RATE_MASK, 8); | ||
573 | break; | ||
574 | default: | ||
575 | arizona_aif_err(dai, "Invalid clock %d\n", dai_priv->clk); | ||
576 | return -EINVAL; | ||
577 | } | ||
578 | |||
579 | snd_soc_update_bits(codec, base + ARIZONA_AIF_BCLK_CTRL, | ||
580 | ARIZONA_AIF1_BCLK_FREQ_MASK, bclk); | ||
581 | snd_soc_update_bits(codec, base + ARIZONA_AIF_TX_BCLK_RATE, | ||
582 | ARIZONA_AIF1TX_BCPF_MASK, lrclk); | ||
583 | snd_soc_update_bits(codec, base + ARIZONA_AIF_RX_BCLK_RATE, | ||
584 | ARIZONA_AIF1RX_BCPF_MASK, lrclk); | ||
585 | snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_1, | ||
586 | ARIZONA_AIF1TX_WL_MASK | | ||
587 | ARIZONA_AIF1TX_SLOT_LEN_MASK, frame); | ||
588 | snd_soc_update_bits(codec, base + ARIZONA_AIF_FRAME_CTRL_2, | ||
589 | ARIZONA_AIF1RX_WL_MASK | | ||
590 | ARIZONA_AIF1RX_SLOT_LEN_MASK, frame); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static const char *arizona_dai_clk_str(int clk_id) | ||
596 | { | ||
597 | switch (clk_id) { | ||
598 | case ARIZONA_CLK_SYSCLK: | ||
599 | return "SYSCLK"; | ||
600 | case ARIZONA_CLK_ASYNCCLK: | ||
601 | return "ASYNCCLK"; | ||
602 | default: | ||
603 | return "Unknown clock"; | ||
604 | } | ||
605 | } | ||
606 | |||
607 | static int arizona_dai_set_sysclk(struct snd_soc_dai *dai, | ||
608 | int clk_id, unsigned int freq, int dir) | ||
609 | { | ||
610 | struct snd_soc_codec *codec = dai->codec; | ||
611 | struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
612 | struct arizona_dai_priv *dai_priv = &priv->dai[dai->id - 1]; | ||
613 | struct snd_soc_dapm_route routes[2]; | ||
614 | |||
615 | switch (clk_id) { | ||
616 | case ARIZONA_CLK_SYSCLK: | ||
617 | case ARIZONA_CLK_ASYNCCLK: | ||
618 | break; | ||
619 | default: | ||
620 | return -EINVAL; | ||
621 | } | ||
622 | |||
623 | if (clk_id == dai_priv->clk) | ||
624 | return 0; | ||
625 | |||
626 | if (dai->active) { | ||
627 | dev_err(codec->dev, "Can't change clock on active DAI %d\n", | ||
628 | dai->id); | ||
629 | return -EBUSY; | ||
630 | } | ||
631 | |||
632 | memset(&routes, 0, sizeof(routes)); | ||
633 | routes[0].sink = dai->driver->capture.stream_name; | ||
634 | routes[1].sink = dai->driver->playback.stream_name; | ||
635 | |||
636 | routes[0].source = arizona_dai_clk_str(dai_priv->clk); | ||
637 | routes[1].source = arizona_dai_clk_str(dai_priv->clk); | ||
638 | snd_soc_dapm_del_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); | ||
639 | |||
640 | routes[0].source = arizona_dai_clk_str(clk_id); | ||
641 | routes[1].source = arizona_dai_clk_str(clk_id); | ||
642 | snd_soc_dapm_add_routes(&codec->dapm, routes, ARRAY_SIZE(routes)); | ||
643 | |||
644 | return snd_soc_dapm_sync(&codec->dapm); | ||
645 | } | ||
646 | |||
647 | const struct snd_soc_dai_ops arizona_dai_ops = { | ||
648 | .startup = arizona_startup, | ||
649 | .set_fmt = arizona_set_fmt, | ||
650 | .hw_params = arizona_hw_params, | ||
651 | .set_sysclk = arizona_dai_set_sysclk, | ||
652 | }; | ||
653 | EXPORT_SYMBOL_GPL(arizona_dai_ops); | ||
654 | |||
655 | int arizona_init_dai(struct arizona_priv *priv, int id) | ||
656 | { | ||
657 | struct arizona_dai_priv *dai_priv = &priv->dai[id]; | ||
658 | |||
659 | dai_priv->clk = ARIZONA_CLK_SYSCLK; | ||
660 | |||
661 | return 0; | ||
662 | } | ||
663 | EXPORT_SYMBOL_GPL(arizona_init_dai); | ||
664 | |||
665 | static irqreturn_t arizona_fll_lock(int irq, void *data) | ||
666 | { | ||
667 | struct arizona_fll *fll = data; | ||
668 | |||
669 | arizona_fll_dbg(fll, "Locked\n"); | ||
670 | |||
671 | complete(&fll->lock); | ||
672 | |||
673 | return IRQ_HANDLED; | ||
674 | } | ||
675 | |||
676 | static irqreturn_t arizona_fll_clock_ok(int irq, void *data) | ||
677 | { | ||
678 | struct arizona_fll *fll = data; | ||
679 | |||
680 | arizona_fll_dbg(fll, "clock OK\n"); | ||
681 | |||
682 | complete(&fll->ok); | ||
683 | |||
684 | return IRQ_HANDLED; | ||
685 | } | ||
686 | |||
687 | static struct { | ||
688 | unsigned int min; | ||
689 | unsigned int max; | ||
690 | u16 fratio; | ||
691 | int ratio; | ||
692 | } fll_fratios[] = { | ||
693 | { 0, 64000, 4, 16 }, | ||
694 | { 64000, 128000, 3, 8 }, | ||
695 | { 128000, 256000, 2, 4 }, | ||
696 | { 256000, 1000000, 1, 2 }, | ||
697 | { 1000000, 13500000, 0, 1 }, | ||
698 | }; | ||
699 | |||
700 | struct arizona_fll_cfg { | ||
701 | int n; | ||
702 | int theta; | ||
703 | int lambda; | ||
704 | int refdiv; | ||
705 | int outdiv; | ||
706 | int fratio; | ||
707 | }; | ||
708 | |||
709 | static int arizona_calc_fll(struct arizona_fll *fll, | ||
710 | struct arizona_fll_cfg *cfg, | ||
711 | unsigned int Fref, | ||
712 | unsigned int Fout) | ||
713 | { | ||
714 | unsigned int target, div, gcd_fll; | ||
715 | int i, ratio; | ||
716 | |||
717 | arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); | ||
718 | |||
719 | /* Fref must be <=13.5MHz */ | ||
720 | div = 1; | ||
721 | cfg->refdiv = 0; | ||
722 | while ((Fref / div) > 13500000) { | ||
723 | div *= 2; | ||
724 | cfg->refdiv++; | ||
725 | |||
726 | if (div > 8) { | ||
727 | arizona_fll_err(fll, | ||
728 | "Can't scale %dMHz in to <=13.5MHz\n", | ||
729 | Fref); | ||
730 | return -EINVAL; | ||
731 | } | ||
732 | } | ||
733 | |||
734 | /* Apply the division for our remaining calculations */ | ||
735 | Fref /= div; | ||
736 | |||
737 | /* Fvco should be over the targt; don't check the upper bound */ | ||
738 | div = 1; | ||
739 | while (Fout * div < 90000000 * fll->vco_mult) { | ||
740 | div++; | ||
741 | if (div > 7) { | ||
742 | arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", | ||
743 | Fout); | ||
744 | return -EINVAL; | ||
745 | } | ||
746 | } | ||
747 | target = Fout * div / fll->vco_mult; | ||
748 | cfg->outdiv = div; | ||
749 | |||
750 | arizona_fll_dbg(fll, "Fvco=%dHz\n", target); | ||
751 | |||
752 | /* Find an appropraite FLL_FRATIO and factor it out of the target */ | ||
753 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | ||
754 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | ||
755 | cfg->fratio = fll_fratios[i].fratio; | ||
756 | ratio = fll_fratios[i].ratio; | ||
757 | break; | ||
758 | } | ||
759 | } | ||
760 | if (i == ARRAY_SIZE(fll_fratios)) { | ||
761 | arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", | ||
762 | Fref); | ||
763 | return -EINVAL; | ||
764 | } | ||
765 | |||
766 | cfg->n = target / (ratio * Fref); | ||
767 | |||
768 | if (target % Fref) { | ||
769 | gcd_fll = gcd(target, ratio * Fref); | ||
770 | arizona_fll_dbg(fll, "GCD=%u\n", gcd_fll); | ||
771 | |||
772 | cfg->theta = (target - (cfg->n * ratio * Fref)) | ||
773 | / gcd_fll; | ||
774 | cfg->lambda = (ratio * Fref) / gcd_fll; | ||
775 | } else { | ||
776 | cfg->theta = 0; | ||
777 | cfg->lambda = 0; | ||
778 | } | ||
779 | |||
780 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", | ||
781 | cfg->n, cfg->theta, cfg->lambda); | ||
782 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", | ||
783 | cfg->fratio, cfg->fratio, cfg->outdiv, cfg->refdiv); | ||
784 | |||
785 | return 0; | ||
786 | |||
787 | } | ||
788 | |||
789 | static void arizona_apply_fll(struct arizona *arizona, unsigned int base, | ||
790 | struct arizona_fll_cfg *cfg, int source) | ||
791 | { | ||
792 | regmap_update_bits(arizona->regmap, base + 3, | ||
793 | ARIZONA_FLL1_THETA_MASK, cfg->theta); | ||
794 | regmap_update_bits(arizona->regmap, base + 4, | ||
795 | ARIZONA_FLL1_LAMBDA_MASK, cfg->lambda); | ||
796 | regmap_update_bits(arizona->regmap, base + 5, | ||
797 | ARIZONA_FLL1_FRATIO_MASK, | ||
798 | cfg->fratio << ARIZONA_FLL1_FRATIO_SHIFT); | ||
799 | regmap_update_bits(arizona->regmap, base + 6, | ||
800 | ARIZONA_FLL1_CLK_REF_DIV_MASK | | ||
801 | ARIZONA_FLL1_CLK_REF_SRC_MASK, | ||
802 | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | | ||
803 | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); | ||
804 | |||
805 | regmap_update_bits(arizona->regmap, base + 2, | ||
806 | ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, | ||
807 | ARIZONA_FLL1_CTRL_UPD | cfg->n); | ||
808 | } | ||
809 | |||
810 | int arizona_set_fll(struct arizona_fll *fll, int source, | ||
811 | unsigned int Fref, unsigned int Fout) | ||
812 | { | ||
813 | struct arizona *arizona = fll->arizona; | ||
814 | struct arizona_fll_cfg cfg, sync; | ||
815 | unsigned int reg, val; | ||
816 | int syncsrc; | ||
817 | bool ena; | ||
818 | int ret; | ||
819 | |||
820 | ret = regmap_read(arizona->regmap, fll->base + 1, ®); | ||
821 | if (ret != 0) { | ||
822 | arizona_fll_err(fll, "Failed to read current state: %d\n", | ||
823 | ret); | ||
824 | return ret; | ||
825 | } | ||
826 | ena = reg & ARIZONA_FLL1_ENA; | ||
827 | |||
828 | if (Fout) { | ||
829 | /* Do we have a 32kHz reference? */ | ||
830 | regmap_read(arizona->regmap, ARIZONA_CLOCK_32K_1, &val); | ||
831 | switch (val & ARIZONA_CLK_32K_SRC_MASK) { | ||
832 | case ARIZONA_CLK_SRC_MCLK1: | ||
833 | case ARIZONA_CLK_SRC_MCLK2: | ||
834 | syncsrc = val & ARIZONA_CLK_32K_SRC_MASK; | ||
835 | break; | ||
836 | default: | ||
837 | syncsrc = -1; | ||
838 | } | ||
839 | |||
840 | if (source == syncsrc) | ||
841 | syncsrc = -1; | ||
842 | |||
843 | if (syncsrc >= 0) { | ||
844 | ret = arizona_calc_fll(fll, &sync, Fref, Fout); | ||
845 | if (ret != 0) | ||
846 | return ret; | ||
847 | |||
848 | ret = arizona_calc_fll(fll, &cfg, 32768, Fout); | ||
849 | if (ret != 0) | ||
850 | return ret; | ||
851 | } else { | ||
852 | ret = arizona_calc_fll(fll, &cfg, Fref, Fout); | ||
853 | if (ret != 0) | ||
854 | return ret; | ||
855 | } | ||
856 | } else { | ||
857 | regmap_update_bits(arizona->regmap, fll->base + 1, | ||
858 | ARIZONA_FLL1_ENA, 0); | ||
859 | regmap_update_bits(arizona->regmap, fll->base + 0x11, | ||
860 | ARIZONA_FLL1_SYNC_ENA, 0); | ||
861 | |||
862 | if (ena) | ||
863 | pm_runtime_put_autosuspend(arizona->dev); | ||
864 | |||
865 | return 0; | ||
866 | } | ||
867 | |||
868 | regmap_update_bits(arizona->regmap, fll->base + 5, | ||
869 | ARIZONA_FLL1_OUTDIV_MASK, | ||
870 | cfg.outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); | ||
871 | |||
872 | if (syncsrc >= 0) { | ||
873 | arizona_apply_fll(arizona, fll->base, &cfg, syncsrc); | ||
874 | arizona_apply_fll(arizona, fll->base + 0x10, &sync, source); | ||
875 | } else { | ||
876 | arizona_apply_fll(arizona, fll->base, &cfg, source); | ||
877 | } | ||
878 | |||
879 | if (!ena) | ||
880 | pm_runtime_get(arizona->dev); | ||
881 | |||
882 | /* Clear any pending completions */ | ||
883 | try_wait_for_completion(&fll->ok); | ||
884 | |||
885 | regmap_update_bits(arizona->regmap, fll->base + 1, | ||
886 | ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); | ||
887 | if (syncsrc >= 0) | ||
888 | regmap_update_bits(arizona->regmap, fll->base + 0x11, | ||
889 | ARIZONA_FLL1_SYNC_ENA, | ||
890 | ARIZONA_FLL1_SYNC_ENA); | ||
891 | |||
892 | ret = wait_for_completion_timeout(&fll->ok, | ||
893 | msecs_to_jiffies(25)); | ||
894 | if (ret == 0) | ||
895 | arizona_fll_warn(fll, "Timed out waiting for lock\n"); | ||
896 | |||
897 | return 0; | ||
898 | } | ||
899 | EXPORT_SYMBOL_GPL(arizona_set_fll); | ||
900 | |||
901 | int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, | ||
902 | int ok_irq, struct arizona_fll *fll) | ||
903 | { | ||
904 | int ret; | ||
905 | |||
906 | init_completion(&fll->lock); | ||
907 | init_completion(&fll->ok); | ||
908 | |||
909 | fll->id = id; | ||
910 | fll->base = base; | ||
911 | fll->arizona = arizona; | ||
912 | |||
913 | snprintf(fll->lock_name, sizeof(fll->lock_name), "FLL%d lock", id); | ||
914 | snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), | ||
915 | "FLL%d clock OK", id); | ||
916 | |||
917 | ret = arizona_request_irq(arizona, lock_irq, fll->lock_name, | ||
918 | arizona_fll_lock, fll); | ||
919 | if (ret != 0) { | ||
920 | dev_err(arizona->dev, "Failed to get FLL%d lock IRQ: %d\n", | ||
921 | id, ret); | ||
922 | } | ||
923 | |||
924 | ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, | ||
925 | arizona_fll_clock_ok, fll); | ||
926 | if (ret != 0) { | ||
927 | dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n", | ||
928 | id, ret); | ||
929 | } | ||
930 | |||
931 | return 0; | ||
932 | } | ||
933 | EXPORT_SYMBOL_GPL(arizona_init_fll); | ||
934 | |||
935 | MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); | ||
936 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
937 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h new file mode 100644 index 000000000000..59caca8865e8 --- /dev/null +++ b/sound/soc/codecs/arizona.h | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * arizona.h - Wolfson Arizona class device shared support | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _ASOC_ARIZONA_H | ||
14 | #define _ASOC_ARIZONA_H | ||
15 | |||
16 | #include <linux/completion.h> | ||
17 | |||
18 | #include <sound/soc.h> | ||
19 | |||
20 | #define ARIZONA_CLK_SYSCLK 1 | ||
21 | #define ARIZONA_CLK_ASYNCCLK 2 | ||
22 | |||
23 | #define ARIZONA_CLK_SRC_MCLK1 0x0 | ||
24 | #define ARIZONA_CLK_SRC_MCLK2 0x1 | ||
25 | #define ARIZONA_CLK_SRC_FLL1 0x4 | ||
26 | #define ARIZONA_CLK_SRC_FLL2 0x5 | ||
27 | #define ARIZONA_CLK_SRC_AIF1BCLK 0x8 | ||
28 | #define ARIZONA_CLK_SRC_AIF2BCLK 0x9 | ||
29 | #define ARIZONA_CLK_SRC_AIF3BCLK 0xa | ||
30 | |||
31 | #define ARIZONA_FLL_SRC_MCLK1 0 | ||
32 | #define ARIZONA_FLL_SRC_MCLK2 1 | ||
33 | #define ARIZONA_FLL_SRC_SLIMCLK 2 | ||
34 | #define ARIZONA_FLL_SRC_FLL1 3 | ||
35 | #define ARIZONA_FLL_SRC_FLL2 4 | ||
36 | #define ARIZONA_FLL_SRC_AIF1BCLK 5 | ||
37 | #define ARIZONA_FLL_SRC_AIF2BCLK 6 | ||
38 | #define ARIZONA_FLL_SRC_AIF3BCLK 7 | ||
39 | #define ARIZONA_FLL_SRC_AIF1LRCLK 8 | ||
40 | #define ARIZONA_FLL_SRC_AIF2LRCLK 9 | ||
41 | #define ARIZONA_FLL_SRC_AIF3LRCLK 10 | ||
42 | |||
43 | #define ARIZONA_MIXER_VOL_MASK 0x00FE | ||
44 | #define ARIZONA_MIXER_VOL_SHIFT 1 | ||
45 | #define ARIZONA_MIXER_VOL_WIDTH 7 | ||
46 | |||
47 | #define ARIZONA_MAX_DAI 3 | ||
48 | |||
49 | struct arizona; | ||
50 | |||
51 | struct arizona_dai_priv { | ||
52 | int clk; | ||
53 | }; | ||
54 | |||
55 | struct arizona_priv { | ||
56 | struct arizona *arizona; | ||
57 | int sysclk; | ||
58 | int asyncclk; | ||
59 | struct arizona_dai_priv dai[ARIZONA_MAX_DAI]; | ||
60 | }; | ||
61 | |||
62 | #define ARIZONA_NUM_MIXER_INPUTS 57 | ||
63 | |||
64 | extern const unsigned int arizona_mixer_tlv[]; | ||
65 | extern const char *arizona_mixer_texts[ARIZONA_NUM_MIXER_INPUTS]; | ||
66 | extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; | ||
67 | |||
68 | #define ARIZONA_MIXER_CONTROLS(name, base) \ | ||
69 | SOC_SINGLE_RANGE_TLV(name " Input 1 Volume", base + 1, \ | ||
70 | ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ | ||
71 | arizona_mixer_tlv), \ | ||
72 | SOC_SINGLE_RANGE_TLV(name " Input 2 Volume", base + 3, \ | ||
73 | ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ | ||
74 | arizona_mixer_tlv), \ | ||
75 | SOC_SINGLE_RANGE_TLV(name " Input 3 Volume", base + 5, \ | ||
76 | ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ | ||
77 | arizona_mixer_tlv), \ | ||
78 | SOC_SINGLE_RANGE_TLV(name " Input 4 Volume", base + 7, \ | ||
79 | ARIZONA_MIXER_VOL_SHIFT, 0x20, 0x50, 0, \ | ||
80 | arizona_mixer_tlv) | ||
81 | |||
82 | #define ARIZONA_MUX_ENUM_DECL(name, reg) \ | ||
83 | SOC_VALUE_ENUM_SINGLE_DECL(name, reg, 0, 0xff, \ | ||
84 | arizona_mixer_texts, arizona_mixer_values) | ||
85 | |||
86 | #define ARIZONA_MUX_CTL_DECL(name) \ | ||
87 | const struct snd_kcontrol_new name##_mux = \ | ||
88 | SOC_DAPM_VALUE_ENUM("Route", name##_enum) | ||
89 | |||
90 | #define ARIZONA_MIXER_ENUMS(name, base_reg) \ | ||
91 | static ARIZONA_MUX_ENUM_DECL(name##_in1_enum, base_reg); \ | ||
92 | static ARIZONA_MUX_ENUM_DECL(name##_in2_enum, base_reg + 2); \ | ||
93 | static ARIZONA_MUX_ENUM_DECL(name##_in3_enum, base_reg + 4); \ | ||
94 | static ARIZONA_MUX_ENUM_DECL(name##_in4_enum, base_reg + 6); \ | ||
95 | static ARIZONA_MUX_CTL_DECL(name##_in1); \ | ||
96 | static ARIZONA_MUX_CTL_DECL(name##_in2); \ | ||
97 | static ARIZONA_MUX_CTL_DECL(name##_in3); \ | ||
98 | static ARIZONA_MUX_CTL_DECL(name##_in4) | ||
99 | |||
100 | #define ARIZONA_MUX(name, ctrl) \ | ||
101 | SND_SOC_DAPM_VALUE_MUX(name, SND_SOC_NOPM, 0, 0, ctrl) | ||
102 | |||
103 | #define ARIZONA_MIXER_WIDGETS(name, name_str) \ | ||
104 | ARIZONA_MUX(name_str " Input 1", &name##_in1_mux), \ | ||
105 | ARIZONA_MUX(name_str " Input 2", &name##_in2_mux), \ | ||
106 | ARIZONA_MUX(name_str " Input 3", &name##_in3_mux), \ | ||
107 | ARIZONA_MUX(name_str " Input 4", &name##_in4_mux), \ | ||
108 | SND_SOC_DAPM_MIXER(name_str " Mixer", SND_SOC_NOPM, 0, 0, NULL, 0) | ||
109 | |||
110 | #define ARIZONA_MIXER_ROUTES(widget, name) \ | ||
111 | { widget, NULL, name " Mixer" }, \ | ||
112 | { name " Mixer", NULL, name " Input 1" }, \ | ||
113 | { name " Mixer", NULL, name " Input 2" }, \ | ||
114 | { name " Mixer", NULL, name " Input 3" }, \ | ||
115 | { name " Mixer", NULL, name " Input 4" }, \ | ||
116 | ARIZONA_MIXER_INPUT_ROUTES(name " Input 1"), \ | ||
117 | ARIZONA_MIXER_INPUT_ROUTES(name " Input 2"), \ | ||
118 | ARIZONA_MIXER_INPUT_ROUTES(name " Input 3"), \ | ||
119 | ARIZONA_MIXER_INPUT_ROUTES(name " Input 4") | ||
120 | |||
121 | extern const struct soc_enum arizona_lhpf1_mode; | ||
122 | extern const struct soc_enum arizona_lhpf2_mode; | ||
123 | extern const struct soc_enum arizona_lhpf3_mode; | ||
124 | extern const struct soc_enum arizona_lhpf4_mode; | ||
125 | |||
126 | extern int arizona_in_ev(struct snd_soc_dapm_widget *w, | ||
127 | struct snd_kcontrol *kcontrol, | ||
128 | int event); | ||
129 | extern int arizona_out_ev(struct snd_soc_dapm_widget *w, | ||
130 | struct snd_kcontrol *kcontrol, | ||
131 | int event); | ||
132 | |||
133 | extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, | ||
134 | int source, unsigned int freq, int dir); | ||
135 | |||
136 | extern const struct snd_soc_dai_ops arizona_dai_ops; | ||
137 | |||
138 | #define ARIZONA_FLL_NAME_LEN 20 | ||
139 | |||
140 | struct arizona_fll { | ||
141 | struct arizona *arizona; | ||
142 | int id; | ||
143 | unsigned int base; | ||
144 | unsigned int vco_mult; | ||
145 | struct completion lock; | ||
146 | struct completion ok; | ||
147 | |||
148 | char lock_name[ARIZONA_FLL_NAME_LEN]; | ||
149 | char clock_ok_name[ARIZONA_FLL_NAME_LEN]; | ||
150 | }; | ||
151 | |||
152 | extern int arizona_init_fll(struct arizona *arizona, int id, int base, | ||
153 | int lock_irq, int ok_irq, struct arizona_fll *fll); | ||
154 | extern int arizona_set_fll(struct arizona_fll *fll, int source, | ||
155 | unsigned int Fref, unsigned int Fout); | ||
156 | |||
157 | extern int arizona_init_dai(struct arizona_priv *priv, int dai); | ||
158 | |||
159 | #endif | ||
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index a7109413aef1..628daf6a1d97 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -14,7 +14,6 @@ | |||
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/version.h> | ||
18 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
19 | #include <linux/init.h> | 18 | #include <linux/init.h> |
20 | #include <linux/delay.h> | 19 | #include <linux/delay.h> |
@@ -1217,11 +1216,11 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, | |||
1217 | return -ENOMEM; | 1216 | return -ENOMEM; |
1218 | cs42l52->dev = &i2c_client->dev; | 1217 | cs42l52->dev = &i2c_client->dev; |
1219 | 1218 | ||
1220 | cs42l52->regmap = regmap_init_i2c(i2c_client, &cs42l52_regmap); | 1219 | cs42l52->regmap = devm_regmap_init_i2c(i2c_client, &cs42l52_regmap); |
1221 | if (IS_ERR(cs42l52->regmap)) { | 1220 | if (IS_ERR(cs42l52->regmap)) { |
1222 | ret = PTR_ERR(cs42l52->regmap); | 1221 | ret = PTR_ERR(cs42l52->regmap); |
1223 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | 1222 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); |
1224 | goto err; | 1223 | return ret; |
1225 | } | 1224 | } |
1226 | 1225 | ||
1227 | i2c_set_clientdata(i2c_client, cs42l52); | 1226 | i2c_set_clientdata(i2c_client, cs42l52); |
@@ -1243,7 +1242,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, | |||
1243 | dev_err(&i2c_client->dev, | 1242 | dev_err(&i2c_client->dev, |
1244 | "CS42L52 Device ID (%X). Expected %X\n", | 1243 | "CS42L52 Device ID (%X). Expected %X\n", |
1245 | devid, CS42L52_CHIP_ID); | 1244 | devid, CS42L52_CHIP_ID); |
1246 | goto err_regmap; | 1245 | return ret; |
1247 | } | 1246 | } |
1248 | 1247 | ||
1249 | regcache_cache_only(cs42l52->regmap, true); | 1248 | regcache_cache_only(cs42l52->regmap, true); |
@@ -1251,23 +1250,13 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client, | |||
1251 | ret = snd_soc_register_codec(&i2c_client->dev, | 1250 | ret = snd_soc_register_codec(&i2c_client->dev, |
1252 | &soc_codec_dev_cs42l52, &cs42l52_dai, 1); | 1251 | &soc_codec_dev_cs42l52, &cs42l52_dai, 1); |
1253 | if (ret < 0) | 1252 | if (ret < 0) |
1254 | goto err_regmap; | 1253 | return ret; |
1255 | return 0; | 1254 | return 0; |
1256 | |||
1257 | err_regmap: | ||
1258 | regmap_exit(cs42l52->regmap); | ||
1259 | |||
1260 | err: | ||
1261 | return ret; | ||
1262 | } | 1255 | } |
1263 | 1256 | ||
1264 | static int cs42l52_i2c_remove(struct i2c_client *client) | 1257 | static int cs42l52_i2c_remove(struct i2c_client *client) |
1265 | { | 1258 | { |
1266 | struct cs42l52_private *cs42l52 = i2c_get_clientdata(client); | ||
1267 | |||
1268 | snd_soc_unregister_codec(&client->dev); | 1259 | snd_soc_unregister_codec(&client->dev); |
1269 | regmap_exit(cs42l52->regmap); | ||
1270 | |||
1271 | return 0; | 1260 | return 0; |
1272 | } | 1261 | } |
1273 | 1262 | ||
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index e0d45fdaa750..2c08c4cb465a 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -1362,11 +1362,11 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1362 | 1362 | ||
1363 | i2c_set_clientdata(i2c_client, cs42l73); | 1363 | i2c_set_clientdata(i2c_client, cs42l73); |
1364 | 1364 | ||
1365 | cs42l73->regmap = regmap_init_i2c(i2c_client, &cs42l73_regmap); | 1365 | cs42l73->regmap = devm_regmap_init_i2c(i2c_client, &cs42l73_regmap); |
1366 | if (IS_ERR(cs42l73->regmap)) { | 1366 | if (IS_ERR(cs42l73->regmap)) { |
1367 | ret = PTR_ERR(cs42l73->regmap); | 1367 | ret = PTR_ERR(cs42l73->regmap); |
1368 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | 1368 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); |
1369 | goto err; | 1369 | return ret; |
1370 | } | 1370 | } |
1371 | /* initialize codec */ | 1371 | /* initialize codec */ |
1372 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); | 1372 | ret = regmap_read(cs42l73->regmap, CS42L73_DEVID_AB, ®); |
@@ -1384,13 +1384,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1384 | dev_err(&i2c_client->dev, | 1384 | dev_err(&i2c_client->dev, |
1385 | "CS42L73 Device ID (%X). Expected %X\n", | 1385 | "CS42L73 Device ID (%X). Expected %X\n", |
1386 | devid, CS42L73_DEVID); | 1386 | devid, CS42L73_DEVID); |
1387 | goto err_regmap; | 1387 | return ret; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®); | 1390 | ret = regmap_read(cs42l73->regmap, CS42L73_REVID, ®); |
1391 | if (ret < 0) { | 1391 | if (ret < 0) { |
1392 | dev_err(&i2c_client->dev, "Get Revision ID failed\n"); | 1392 | dev_err(&i2c_client->dev, "Get Revision ID failed\n"); |
1393 | goto err_regmap; | 1393 | return ret;; |
1394 | } | 1394 | } |
1395 | 1395 | ||
1396 | dev_info(&i2c_client->dev, | 1396 | dev_info(&i2c_client->dev, |
@@ -1402,23 +1402,13 @@ static __devinit int cs42l73_i2c_probe(struct i2c_client *i2c_client, | |||
1402 | &soc_codec_dev_cs42l73, cs42l73_dai, | 1402 | &soc_codec_dev_cs42l73, cs42l73_dai, |
1403 | ARRAY_SIZE(cs42l73_dai)); | 1403 | ARRAY_SIZE(cs42l73_dai)); |
1404 | if (ret < 0) | 1404 | if (ret < 0) |
1405 | goto err_regmap; | 1405 | return ret; |
1406 | return 0; | 1406 | return 0; |
1407 | |||
1408 | err_regmap: | ||
1409 | regmap_exit(cs42l73->regmap); | ||
1410 | |||
1411 | err: | ||
1412 | return ret; | ||
1413 | } | 1407 | } |
1414 | 1408 | ||
1415 | static __devexit int cs42l73_i2c_remove(struct i2c_client *client) | 1409 | static __devexit int cs42l73_i2c_remove(struct i2c_client *client) |
1416 | { | 1410 | { |
1417 | struct cs42l73_private *cs42l73 = i2c_get_clientdata(client); | ||
1418 | |||
1419 | snd_soc_unregister_codec(&client->dev); | 1411 | snd_soc_unregister_codec(&client->dev); |
1420 | regmap_exit(cs42l73->regmap); | ||
1421 | |||
1422 | return 0; | 1412 | return 0; |
1423 | } | 1413 | } |
1424 | 1414 | ||
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c new file mode 100644 index 000000000000..01be2a320e21 --- /dev/null +++ b/sound/soc/codecs/da732x.c | |||
@@ -0,0 +1,1627 @@ | |||
1 | /* | ||
2 | * da732x.c --- Dialog DA732X ALSA SoC Audio Driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Dialog Semiconductor GmbH | ||
5 | * | ||
6 | * Author: Michal Hajduk <Michal.Hajduk@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/sysfs.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 | #include <asm/div64.h> | ||
31 | |||
32 | #include "da732x.h" | ||
33 | #include "da732x_reg.h" | ||
34 | |||
35 | |||
36 | struct da732x_priv { | ||
37 | struct regmap *regmap; | ||
38 | struct snd_soc_codec *codec; | ||
39 | |||
40 | unsigned int sysclk; | ||
41 | bool pll_en; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * da732x register cache - default settings | ||
46 | */ | ||
47 | static struct reg_default da732x_reg_cache[] = { | ||
48 | { DA732X_REG_REF1 , 0x02 }, | ||
49 | { DA732X_REG_BIAS_EN , 0x80 }, | ||
50 | { DA732X_REG_BIAS1 , 0x00 }, | ||
51 | { DA732X_REG_BIAS2 , 0x00 }, | ||
52 | { DA732X_REG_BIAS3 , 0x00 }, | ||
53 | { DA732X_REG_BIAS4 , 0x00 }, | ||
54 | { DA732X_REG_MICBIAS2 , 0x00 }, | ||
55 | { DA732X_REG_MICBIAS1 , 0x00 }, | ||
56 | { DA732X_REG_MICDET , 0x00 }, | ||
57 | { DA732X_REG_MIC1_PRE , 0x01 }, | ||
58 | { DA732X_REG_MIC1 , 0x40 }, | ||
59 | { DA732X_REG_MIC2_PRE , 0x01 }, | ||
60 | { DA732X_REG_MIC2 , 0x40 }, | ||
61 | { DA732X_REG_AUX1L , 0x75 }, | ||
62 | { DA732X_REG_AUX1R , 0x75 }, | ||
63 | { DA732X_REG_MIC3_PRE , 0x01 }, | ||
64 | { DA732X_REG_MIC3 , 0x40 }, | ||
65 | { DA732X_REG_INP_PINBIAS , 0x00 }, | ||
66 | { DA732X_REG_INP_ZC_EN , 0x00 }, | ||
67 | { DA732X_REG_INP_MUX , 0x50 }, | ||
68 | { DA732X_REG_HP_DET , 0x00 }, | ||
69 | { DA732X_REG_HPL_DAC_OFFSET , 0x00 }, | ||
70 | { DA732X_REG_HPL_DAC_OFF_CNTL , 0x00 }, | ||
71 | { DA732X_REG_HPL_OUT_OFFSET , 0x00 }, | ||
72 | { DA732X_REG_HPL , 0x40 }, | ||
73 | { DA732X_REG_HPL_VOL , 0x0F }, | ||
74 | { DA732X_REG_HPR_DAC_OFFSET , 0x00 }, | ||
75 | { DA732X_REG_HPR_DAC_OFF_CNTL , 0x00 }, | ||
76 | { DA732X_REG_HPR_OUT_OFFSET , 0x00 }, | ||
77 | { DA732X_REG_HPR , 0x40 }, | ||
78 | { DA732X_REG_HPR_VOL , 0x0F }, | ||
79 | { DA732X_REG_LIN2 , 0x4F }, | ||
80 | { DA732X_REG_LIN3 , 0x4F }, | ||
81 | { DA732X_REG_LIN4 , 0x4F }, | ||
82 | { DA732X_REG_OUT_ZC_EN , 0x00 }, | ||
83 | { DA732X_REG_HP_LIN1_GNDSEL , 0x00 }, | ||
84 | { DA732X_REG_CP_HP1 , 0x0C }, | ||
85 | { DA732X_REG_CP_HP2 , 0x03 }, | ||
86 | { DA732X_REG_CP_CTRL1 , 0x00 }, | ||
87 | { DA732X_REG_CP_CTRL2 , 0x99 }, | ||
88 | { DA732X_REG_CP_CTRL3 , 0x25 }, | ||
89 | { DA732X_REG_CP_LEVEL_MASK , 0x3F }, | ||
90 | { DA732X_REG_CP_DET , 0x00 }, | ||
91 | { DA732X_REG_CP_STATUS , 0x00 }, | ||
92 | { DA732X_REG_CP_THRESH1 , 0x00 }, | ||
93 | { DA732X_REG_CP_THRESH2 , 0x00 }, | ||
94 | { DA732X_REG_CP_THRESH3 , 0x00 }, | ||
95 | { DA732X_REG_CP_THRESH4 , 0x00 }, | ||
96 | { DA732X_REG_CP_THRESH5 , 0x00 }, | ||
97 | { DA732X_REG_CP_THRESH6 , 0x00 }, | ||
98 | { DA732X_REG_CP_THRESH7 , 0x00 }, | ||
99 | { DA732X_REG_CP_THRESH8 , 0x00 }, | ||
100 | { DA732X_REG_PLL_DIV_LO , 0x00 }, | ||
101 | { DA732X_REG_PLL_DIV_MID , 0x00 }, | ||
102 | { DA732X_REG_PLL_DIV_HI , 0x00 }, | ||
103 | { DA732X_REG_PLL_CTRL , 0x02 }, | ||
104 | { DA732X_REG_CLK_CTRL , 0xaa }, | ||
105 | { DA732X_REG_CLK_DSP , 0x07 }, | ||
106 | { DA732X_REG_CLK_EN1 , 0x00 }, | ||
107 | { DA732X_REG_CLK_EN2 , 0x00 }, | ||
108 | { DA732X_REG_CLK_EN3 , 0x00 }, | ||
109 | { DA732X_REG_CLK_EN4 , 0x00 }, | ||
110 | { DA732X_REG_CLK_EN5 , 0x00 }, | ||
111 | { DA732X_REG_AIF_MCLK , 0x00 }, | ||
112 | { DA732X_REG_AIFA1 , 0x02 }, | ||
113 | { DA732X_REG_AIFA2 , 0x00 }, | ||
114 | { DA732X_REG_AIFA3 , 0x08 }, | ||
115 | { DA732X_REG_AIFB1 , 0x02 }, | ||
116 | { DA732X_REG_AIFB2 , 0x00 }, | ||
117 | { DA732X_REG_AIFB3 , 0x08 }, | ||
118 | { DA732X_REG_PC_CTRL , 0xC0 }, | ||
119 | { DA732X_REG_DATA_ROUTE , 0x00 }, | ||
120 | { DA732X_REG_DSP_CTRL , 0x00 }, | ||
121 | { DA732X_REG_CIF_CTRL2 , 0x00 }, | ||
122 | { DA732X_REG_HANDSHAKE , 0x00 }, | ||
123 | { DA732X_REG_SPARE1_OUT , 0x00 }, | ||
124 | { DA732X_REG_SPARE2_OUT , 0x00 }, | ||
125 | { DA732X_REG_SPARE1_IN , 0x00 }, | ||
126 | { DA732X_REG_ADC1_PD , 0x00 }, | ||
127 | { DA732X_REG_ADC1_HPF , 0x00 }, | ||
128 | { DA732X_REG_ADC1_SEL , 0x00 }, | ||
129 | { DA732X_REG_ADC1_EQ12 , 0x00 }, | ||
130 | { DA732X_REG_ADC1_EQ34 , 0x00 }, | ||
131 | { DA732X_REG_ADC1_EQ5 , 0x00 }, | ||
132 | { DA732X_REG_ADC2_PD , 0x00 }, | ||
133 | { DA732X_REG_ADC2_HPF , 0x00 }, | ||
134 | { DA732X_REG_ADC2_SEL , 0x00 }, | ||
135 | { DA732X_REG_ADC2_EQ12 , 0x00 }, | ||
136 | { DA732X_REG_ADC2_EQ34 , 0x00 }, | ||
137 | { DA732X_REG_ADC2_EQ5 , 0x00 }, | ||
138 | { DA732X_REG_DAC1_HPF , 0x00 }, | ||
139 | { DA732X_REG_DAC1_L_VOL , 0x00 }, | ||
140 | { DA732X_REG_DAC1_R_VOL , 0x00 }, | ||
141 | { DA732X_REG_DAC1_SEL , 0x00 }, | ||
142 | { DA732X_REG_DAC1_SOFTMUTE , 0x00 }, | ||
143 | { DA732X_REG_DAC1_EQ12 , 0x00 }, | ||
144 | { DA732X_REG_DAC1_EQ34 , 0x00 }, | ||
145 | { DA732X_REG_DAC1_EQ5 , 0x00 }, | ||
146 | { DA732X_REG_DAC2_HPF , 0x00 }, | ||
147 | { DA732X_REG_DAC2_L_VOL , 0x00 }, | ||
148 | { DA732X_REG_DAC2_R_VOL , 0x00 }, | ||
149 | { DA732X_REG_DAC2_SEL , 0x00 }, | ||
150 | { DA732X_REG_DAC2_SOFTMUTE , 0x00 }, | ||
151 | { DA732X_REG_DAC2_EQ12 , 0x00 }, | ||
152 | { DA732X_REG_DAC2_EQ34 , 0x00 }, | ||
153 | { DA732X_REG_DAC2_EQ5 , 0x00 }, | ||
154 | { DA732X_REG_DAC3_HPF , 0x00 }, | ||
155 | { DA732X_REG_DAC3_VOL , 0x00 }, | ||
156 | { DA732X_REG_DAC3_SEL , 0x00 }, | ||
157 | { DA732X_REG_DAC3_SOFTMUTE , 0x00 }, | ||
158 | { DA732X_REG_DAC3_EQ12 , 0x00 }, | ||
159 | { DA732X_REG_DAC3_EQ34 , 0x00 }, | ||
160 | { DA732X_REG_DAC3_EQ5 , 0x00 }, | ||
161 | { DA732X_REG_BIQ_BYP , 0x00 }, | ||
162 | { DA732X_REG_DMA_CMD , 0x00 }, | ||
163 | { DA732X_REG_DMA_ADDR0 , 0x00 }, | ||
164 | { DA732X_REG_DMA_ADDR1 , 0x00 }, | ||
165 | { DA732X_REG_DMA_DATA0 , 0x00 }, | ||
166 | { DA732X_REG_DMA_DATA1 , 0x00 }, | ||
167 | { DA732X_REG_DMA_DATA2 , 0x00 }, | ||
168 | { DA732X_REG_DMA_DATA3 , 0x00 }, | ||
169 | { DA732X_REG_UNLOCK , 0x00 }, | ||
170 | }; | ||
171 | |||
172 | static inline int da732x_get_input_div(struct snd_soc_codec *codec, int sysclk) | ||
173 | { | ||
174 | int val; | ||
175 | int ret; | ||
176 | |||
177 | if (sysclk < DA732X_MCLK_10MHZ) { | ||
178 | val = DA732X_MCLK_RET_0_10MHZ; | ||
179 | ret = DA732X_MCLK_VAL_0_10MHZ; | ||
180 | } else if ((sysclk >= DA732X_MCLK_10MHZ) && | ||
181 | (sysclk < DA732X_MCLK_20MHZ)) { | ||
182 | val = DA732X_MCLK_RET_10_20MHZ; | ||
183 | ret = DA732X_MCLK_VAL_10_20MHZ; | ||
184 | } else if ((sysclk >= DA732X_MCLK_20MHZ) && | ||
185 | (sysclk < DA732X_MCLK_40MHZ)) { | ||
186 | val = DA732X_MCLK_RET_20_40MHZ; | ||
187 | ret = DA732X_MCLK_VAL_20_40MHZ; | ||
188 | } else if ((sysclk >= DA732X_MCLK_40MHZ) && | ||
189 | (sysclk <= DA732X_MCLK_54MHZ)) { | ||
190 | val = DA732X_MCLK_RET_40_54MHZ; | ||
191 | ret = DA732X_MCLK_VAL_40_54MHZ; | ||
192 | } else { | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | snd_soc_write(codec, DA732X_REG_PLL_CTRL, val); | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state) | ||
202 | { | ||
203 | switch (state) { | ||
204 | case DA732X_ENABLE_CP: | ||
205 | snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_EN); | ||
206 | snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_EN | | ||
207 | DA732X_HP_CP_REG | DA732X_HP_CP_PULSESKIP); | ||
208 | snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA732X_CP_EN | | ||
209 | DA732X_CP_CTRL_CPVDD1); | ||
210 | snd_soc_write(codec, DA732X_REG_CP_CTRL2, | ||
211 | DA732X_CP_MANAGE_MAGNITUDE | DA732X_CP_BOOST); | ||
212 | snd_soc_write(codec, DA732X_REG_CP_CTRL3, DA732X_CP_1MHZ); | ||
213 | break; | ||
214 | case DA732X_DISABLE_CP: | ||
215 | snd_soc_write(codec, DA732X_REG_CLK_EN2, DA732X_CP_CLK_DIS); | ||
216 | snd_soc_write(codec, DA732X_REG_CP_HP2, DA732X_HP_CP_DIS); | ||
217 | snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); | ||
218 | break; | ||
219 | default: | ||
220 | pr_err(KERN_ERR "Wrong charge pump state\n"); | ||
221 | break; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static const DECLARE_TLV_DB_SCALE(mic_boost_tlv, DA732X_MIC_PRE_VOL_DB_MIN, | ||
226 | DA732X_MIC_PRE_VOL_DB_INC, 0); | ||
227 | |||
228 | static const DECLARE_TLV_DB_SCALE(mic_pga_tlv, DA732X_MIC_VOL_DB_MIN, | ||
229 | DA732X_MIC_VOL_DB_INC, 0); | ||
230 | |||
231 | static const DECLARE_TLV_DB_SCALE(aux_pga_tlv, DA732X_AUX_VOL_DB_MIN, | ||
232 | DA732X_AUX_VOL_DB_INC, 0); | ||
233 | |||
234 | static const DECLARE_TLV_DB_SCALE(hp_pga_tlv, DA732X_HP_VOL_DB_MIN, | ||
235 | DA732X_AUX_VOL_DB_INC, 0); | ||
236 | |||
237 | static const DECLARE_TLV_DB_SCALE(lin2_pga_tlv, DA732X_LIN2_VOL_DB_MIN, | ||
238 | DA732X_LIN2_VOL_DB_INC, 0); | ||
239 | |||
240 | static const DECLARE_TLV_DB_SCALE(lin3_pga_tlv, DA732X_LIN3_VOL_DB_MIN, | ||
241 | DA732X_LIN3_VOL_DB_INC, 0); | ||
242 | |||
243 | static const DECLARE_TLV_DB_SCALE(lin4_pga_tlv, DA732X_LIN4_VOL_DB_MIN, | ||
244 | DA732X_LIN4_VOL_DB_INC, 0); | ||
245 | |||
246 | static const DECLARE_TLV_DB_SCALE(adc_pga_tlv, DA732X_ADC_VOL_DB_MIN, | ||
247 | DA732X_ADC_VOL_DB_INC, 0); | ||
248 | |||
249 | static const DECLARE_TLV_DB_SCALE(dac_pga_tlv, DA732X_DAC_VOL_DB_MIN, | ||
250 | DA732X_DAC_VOL_DB_INC, 0); | ||
251 | |||
252 | static const DECLARE_TLV_DB_SCALE(eq_band_pga_tlv, DA732X_EQ_BAND_VOL_DB_MIN, | ||
253 | DA732X_EQ_BAND_VOL_DB_INC, 0); | ||
254 | |||
255 | static const DECLARE_TLV_DB_SCALE(eq_overall_tlv, DA732X_EQ_OVERALL_VOL_DB_MIN, | ||
256 | DA732X_EQ_OVERALL_VOL_DB_INC, 0); | ||
257 | |||
258 | /* High Pass Filter */ | ||
259 | static const char *da732x_hpf_mode[] = { | ||
260 | "Disable", "Music", "Voice", | ||
261 | }; | ||
262 | |||
263 | static const char *da732x_hpf_music[] = { | ||
264 | "1.8Hz", "3.75Hz", "7.5Hz", "15Hz", | ||
265 | }; | ||
266 | |||
267 | static const char *da732x_hpf_voice[] = { | ||
268 | "2.5Hz", "25Hz", "50Hz", "100Hz", | ||
269 | "150Hz", "200Hz", "300Hz", "400Hz" | ||
270 | }; | ||
271 | |||
272 | static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { | ||
273 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, | ||
274 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
275 | }; | ||
276 | |||
277 | static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { | ||
278 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, | ||
279 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
280 | }; | ||
281 | |||
282 | static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { | ||
283 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, | ||
284 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
285 | }; | ||
286 | |||
287 | static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { | ||
288 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, | ||
289 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
290 | }; | ||
291 | |||
292 | static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { | ||
293 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, | ||
294 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | ||
295 | }; | ||
296 | |||
297 | static const struct soc_enum da732x_dac1_hp_filter_enum[] = { | ||
298 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, | ||
299 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | ||
300 | }; | ||
301 | |||
302 | static const struct soc_enum da732x_dac2_hp_filter_enum[] = { | ||
303 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, | ||
304 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | ||
305 | }; | ||
306 | |||
307 | static const struct soc_enum da732x_dac3_hp_filter_enum[] = { | ||
308 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, | ||
309 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | ||
310 | }; | ||
311 | |||
312 | static const struct soc_enum da732x_adc1_hp_filter_enum[] = { | ||
313 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, | ||
314 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | ||
315 | }; | ||
316 | |||
317 | static const struct soc_enum da732x_adc2_hp_filter_enum[] = { | ||
318 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, | ||
319 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | ||
320 | }; | ||
321 | |||
322 | static const struct soc_enum da732x_dac1_voice_filter_enum[] = { | ||
323 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, | ||
324 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
325 | }; | ||
326 | |||
327 | static const struct soc_enum da732x_dac2_voice_filter_enum[] = { | ||
328 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, | ||
329 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
330 | }; | ||
331 | |||
332 | static const struct soc_enum da732x_dac3_voice_filter_enum[] = { | ||
333 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, | ||
334 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
335 | }; | ||
336 | |||
337 | static const struct soc_enum da732x_adc1_voice_filter_enum[] = { | ||
338 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, | ||
339 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
340 | }; | ||
341 | |||
342 | static const struct soc_enum da732x_adc2_voice_filter_enum[] = { | ||
343 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, | ||
344 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
345 | }; | ||
346 | |||
347 | |||
348 | static int da732x_hpf_set(struct snd_kcontrol *kcontrol, | ||
349 | struct snd_ctl_elem_value *ucontrol) | ||
350 | { | ||
351 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
352 | struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; | ||
353 | unsigned int reg = enum_ctrl->reg; | ||
354 | unsigned int sel = ucontrol->value.integer.value[0]; | ||
355 | unsigned int bits; | ||
356 | |||
357 | switch (sel) { | ||
358 | case DA732X_HPF_DISABLED: | ||
359 | bits = DA732X_HPF_DIS; | ||
360 | break; | ||
361 | case DA732X_HPF_VOICE: | ||
362 | bits = DA732X_HPF_VOICE_EN; | ||
363 | break; | ||
364 | case DA732X_HPF_MUSIC: | ||
365 | bits = DA732X_HPF_MUSIC_EN; | ||
366 | break; | ||
367 | default: | ||
368 | return -EINVAL; | ||
369 | } | ||
370 | |||
371 | snd_soc_update_bits(codec, reg, DA732X_HPF_MASK, bits); | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int da732x_hpf_get(struct snd_kcontrol *kcontrol, | ||
377 | struct snd_ctl_elem_value *ucontrol) | ||
378 | { | ||
379 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
380 | struct soc_enum *enum_ctrl = (struct soc_enum *)kcontrol->private_value; | ||
381 | unsigned int reg = enum_ctrl->reg; | ||
382 | int val; | ||
383 | |||
384 | val = snd_soc_read(codec, reg) & DA732X_HPF_MASK; | ||
385 | |||
386 | switch (val) { | ||
387 | case DA732X_HPF_VOICE_EN: | ||
388 | ucontrol->value.integer.value[0] = DA732X_HPF_VOICE; | ||
389 | break; | ||
390 | case DA732X_HPF_MUSIC_EN: | ||
391 | ucontrol->value.integer.value[0] = DA732X_HPF_MUSIC; | ||
392 | break; | ||
393 | default: | ||
394 | ucontrol->value.integer.value[0] = DA732X_HPF_DISABLED; | ||
395 | break; | ||
396 | } | ||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static const struct snd_kcontrol_new da732x_snd_controls[] = { | ||
402 | /* Input PGAs */ | ||
403 | SOC_SINGLE_RANGE_TLV("MIC1 Boost Volume", DA732X_REG_MIC1_PRE, | ||
404 | DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, | ||
405 | DA732X_MICBOOST_MAX, 0, mic_boost_tlv), | ||
406 | SOC_SINGLE_RANGE_TLV("MIC2 Boost Volume", DA732X_REG_MIC2_PRE, | ||
407 | DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, | ||
408 | DA732X_MICBOOST_MAX, 0, mic_boost_tlv), | ||
409 | SOC_SINGLE_RANGE_TLV("MIC3 Boost Volume", DA732X_REG_MIC3_PRE, | ||
410 | DA732X_MICBOOST_SHIFT, DA732X_MICBOOST_MIN, | ||
411 | DA732X_MICBOOST_MAX, 0, mic_boost_tlv), | ||
412 | |||
413 | /* MICs */ | ||
414 | SOC_SINGLE("MIC1 Switch", DA732X_REG_MIC1, DA732X_MIC_MUTE_SHIFT, | ||
415 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
416 | SOC_SINGLE_RANGE_TLV("MIC1 Volume", DA732X_REG_MIC1, | ||
417 | DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, | ||
418 | DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), | ||
419 | SOC_SINGLE("MIC2 Switch", DA732X_REG_MIC2, DA732X_MIC_MUTE_SHIFT, | ||
420 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
421 | SOC_SINGLE_RANGE_TLV("MIC2 Volume", DA732X_REG_MIC2, | ||
422 | DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, | ||
423 | DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), | ||
424 | SOC_SINGLE("MIC3 Switch", DA732X_REG_MIC3, DA732X_MIC_MUTE_SHIFT, | ||
425 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
426 | SOC_SINGLE_RANGE_TLV("MIC3 Volume", DA732X_REG_MIC3, | ||
427 | DA732X_MIC_VOL_SHIFT, DA732X_MIC_VOL_VAL_MIN, | ||
428 | DA732X_MIC_VOL_VAL_MAX, 0, mic_pga_tlv), | ||
429 | |||
430 | /* AUXs */ | ||
431 | SOC_SINGLE("AUX1L Switch", DA732X_REG_AUX1L, DA732X_AUX_MUTE_SHIFT, | ||
432 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
433 | SOC_SINGLE_TLV("AUX1L Volume", DA732X_REG_AUX1L, | ||
434 | DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX, | ||
435 | DA732X_NO_INVERT, aux_pga_tlv), | ||
436 | SOC_SINGLE("AUX1R Switch", DA732X_REG_AUX1R, DA732X_AUX_MUTE_SHIFT, | ||
437 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
438 | SOC_SINGLE_TLV("AUX1R Volume", DA732X_REG_AUX1R, | ||
439 | DA732X_AUX_VOL_SHIFT, DA732X_AUX_VOL_VAL_MAX, | ||
440 | DA732X_NO_INVERT, aux_pga_tlv), | ||
441 | |||
442 | /* ADCs */ | ||
443 | SOC_DOUBLE_TLV("ADC1 Volume", DA732X_REG_ADC1_SEL, | ||
444 | DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT, | ||
445 | DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv), | ||
446 | |||
447 | SOC_DOUBLE_TLV("ADC2 Volume", DA732X_REG_ADC2_SEL, | ||
448 | DA732X_ADCL_VOL_SHIFT, DA732X_ADCR_VOL_SHIFT, | ||
449 | DA732X_ADC_VOL_VAL_MAX, DA732X_INVERT, adc_pga_tlv), | ||
450 | |||
451 | /* DACs */ | ||
452 | SOC_DOUBLE("Digital Playback DAC12 Switch", DA732X_REG_DAC1_SEL, | ||
453 | DA732X_DACL_MUTE_SHIFT, DA732X_DACR_MUTE_SHIFT, | ||
454 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
455 | SOC_DOUBLE_R_TLV("Digital Playback DAC12 Volume", DA732X_REG_DAC1_L_VOL, | ||
456 | DA732X_REG_DAC1_R_VOL, DA732X_DAC_VOL_SHIFT, | ||
457 | DA732X_DAC_VOL_VAL_MAX, DA732X_INVERT, dac_pga_tlv), | ||
458 | SOC_SINGLE("Digital Playback DAC3 Switch", DA732X_REG_DAC2_SEL, | ||
459 | DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), | ||
460 | SOC_SINGLE_TLV("Digital Playback DAC3 Volume", DA732X_REG_DAC2_L_VOL, | ||
461 | DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, | ||
462 | DA732X_INVERT, dac_pga_tlv), | ||
463 | SOC_SINGLE("Digital Playback DAC4 Switch", DA732X_REG_DAC2_SEL, | ||
464 | DA732X_DACR_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), | ||
465 | SOC_SINGLE_TLV("Digital Playback DAC4 Volume", DA732X_REG_DAC2_R_VOL, | ||
466 | DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, | ||
467 | DA732X_INVERT, dac_pga_tlv), | ||
468 | SOC_SINGLE("Digital Playback DAC5 Switch", DA732X_REG_DAC3_SEL, | ||
469 | DA732X_DACL_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), | ||
470 | SOC_SINGLE_TLV("Digital Playback DAC5 Volume", DA732X_REG_DAC3_VOL, | ||
471 | DA732X_DAC_VOL_SHIFT, DA732X_DAC_VOL_VAL_MAX, | ||
472 | DA732X_INVERT, dac_pga_tlv), | ||
473 | |||
474 | /* High Pass Filters */ | ||
475 | SOC_ENUM_EXT("DAC1 High Pass Filter Mode", | ||
476 | da732x_dac1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), | ||
477 | SOC_ENUM("DAC1 High Pass Filter", da732x_dac1_hp_filter_enum), | ||
478 | SOC_ENUM("DAC1 Voice Filter", da732x_dac1_voice_filter_enum), | ||
479 | |||
480 | SOC_ENUM_EXT("DAC2 High Pass Filter Mode", | ||
481 | da732x_dac2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), | ||
482 | SOC_ENUM("DAC2 High Pass Filter", da732x_dac2_hp_filter_enum), | ||
483 | SOC_ENUM("DAC2 Voice Filter", da732x_dac2_voice_filter_enum), | ||
484 | |||
485 | SOC_ENUM_EXT("DAC3 High Pass Filter Mode", | ||
486 | da732x_dac3_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), | ||
487 | SOC_ENUM("DAC3 High Pass Filter", da732x_dac3_hp_filter_enum), | ||
488 | SOC_ENUM("DAC3 Filter Mode", da732x_dac3_voice_filter_enum), | ||
489 | |||
490 | SOC_ENUM_EXT("ADC1 High Pass Filter Mode", | ||
491 | da732x_adc1_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), | ||
492 | SOC_ENUM("ADC1 High Pass Filter", da732x_adc1_hp_filter_enum), | ||
493 | SOC_ENUM("ADC1 Voice Filter", da732x_adc1_voice_filter_enum), | ||
494 | |||
495 | SOC_ENUM_EXT("ADC2 High Pass Filter Mode", | ||
496 | da732x_adc2_hpf_mode_enum, da732x_hpf_get, da732x_hpf_set), | ||
497 | SOC_ENUM("ADC2 High Pass Filter", da732x_adc2_hp_filter_enum), | ||
498 | SOC_ENUM("ADC2 Voice Filter", da732x_adc2_voice_filter_enum), | ||
499 | |||
500 | /* Equalizers */ | ||
501 | SOC_SINGLE("ADC1 EQ Switch", DA732X_REG_ADC1_EQ5, | ||
502 | DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), | ||
503 | SOC_SINGLE_TLV("ADC1 EQ Band 1 Volume", DA732X_REG_ADC1_EQ12, | ||
504 | DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
505 | DA732X_INVERT, eq_band_pga_tlv), | ||
506 | SOC_SINGLE_TLV("ADC1 EQ Band 2 Volume", DA732X_REG_ADC1_EQ12, | ||
507 | DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
508 | DA732X_INVERT, eq_band_pga_tlv), | ||
509 | SOC_SINGLE_TLV("ADC1 EQ Band 3 Volume", DA732X_REG_ADC1_EQ34, | ||
510 | DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
511 | DA732X_INVERT, eq_band_pga_tlv), | ||
512 | SOC_SINGLE_TLV("ADC1 EQ Band 4 Volume", DA732X_REG_ADC1_EQ34, | ||
513 | DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
514 | DA732X_INVERT, eq_band_pga_tlv), | ||
515 | SOC_SINGLE_TLV("ADC1 EQ Band 5 Volume", DA732X_REG_ADC1_EQ5, | ||
516 | DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
517 | DA732X_INVERT, eq_band_pga_tlv), | ||
518 | SOC_SINGLE_TLV("ADC1 EQ Overall Volume", DA732X_REG_ADC1_EQ5, | ||
519 | DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX, | ||
520 | DA732X_INVERT, eq_overall_tlv), | ||
521 | |||
522 | SOC_SINGLE("ADC2 EQ Switch", DA732X_REG_ADC2_EQ5, | ||
523 | DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), | ||
524 | SOC_SINGLE_TLV("ADC2 EQ Band 1 Volume", DA732X_REG_ADC2_EQ12, | ||
525 | DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
526 | DA732X_INVERT, eq_band_pga_tlv), | ||
527 | SOC_SINGLE_TLV("ADC2 EQ Band 2 Volume", DA732X_REG_ADC2_EQ12, | ||
528 | DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
529 | DA732X_INVERT, eq_band_pga_tlv), | ||
530 | SOC_SINGLE_TLV("ADC2 EQ Band 3 Volume", DA732X_REG_ADC2_EQ34, | ||
531 | DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
532 | DA732X_INVERT, eq_band_pga_tlv), | ||
533 | SOC_SINGLE_TLV("ACD2 EQ Band 4 Volume", DA732X_REG_ADC2_EQ34, | ||
534 | DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
535 | DA732X_INVERT, eq_band_pga_tlv), | ||
536 | SOC_SINGLE_TLV("ACD2 EQ Band 5 Volume", DA732X_REG_ADC2_EQ5, | ||
537 | DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
538 | DA732X_INVERT, eq_band_pga_tlv), | ||
539 | SOC_SINGLE_TLV("ADC2 EQ Overall Volume", DA732X_REG_ADC1_EQ5, | ||
540 | DA732X_EQ_OVERALL_SHIFT, DA732X_EQ_OVERALL_VOL_VAL_MAX, | ||
541 | DA732X_INVERT, eq_overall_tlv), | ||
542 | |||
543 | SOC_SINGLE("DAC1 EQ Switch", DA732X_REG_DAC1_EQ5, | ||
544 | DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), | ||
545 | SOC_SINGLE_TLV("DAC1 EQ Band 1 Volume", DA732X_REG_DAC1_EQ12, | ||
546 | DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
547 | DA732X_INVERT, eq_band_pga_tlv), | ||
548 | SOC_SINGLE_TLV("DAC1 EQ Band 2 Volume", DA732X_REG_DAC1_EQ12, | ||
549 | DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
550 | DA732X_INVERT, eq_band_pga_tlv), | ||
551 | SOC_SINGLE_TLV("DAC1 EQ Band 3 Volume", DA732X_REG_DAC1_EQ34, | ||
552 | DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
553 | DA732X_INVERT, eq_band_pga_tlv), | ||
554 | SOC_SINGLE_TLV("DAC1 EQ Band 4 Volume", DA732X_REG_DAC1_EQ34, | ||
555 | DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
556 | DA732X_INVERT, eq_band_pga_tlv), | ||
557 | SOC_SINGLE_TLV("DAC1 EQ Band 5 Volume", DA732X_REG_DAC1_EQ5, | ||
558 | DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
559 | DA732X_INVERT, eq_band_pga_tlv), | ||
560 | |||
561 | SOC_SINGLE("DAC2 EQ Switch", DA732X_REG_DAC2_EQ5, | ||
562 | DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), | ||
563 | SOC_SINGLE_TLV("DAC2 EQ Band 1 Volume", DA732X_REG_DAC2_EQ12, | ||
564 | DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
565 | DA732X_INVERT, eq_band_pga_tlv), | ||
566 | SOC_SINGLE_TLV("DAC2 EQ Band 2 Volume", DA732X_REG_DAC2_EQ12, | ||
567 | DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
568 | DA732X_INVERT, eq_band_pga_tlv), | ||
569 | SOC_SINGLE_TLV("DAC2 EQ Band 3 Volume", DA732X_REG_DAC2_EQ34, | ||
570 | DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
571 | DA732X_INVERT, eq_band_pga_tlv), | ||
572 | SOC_SINGLE_TLV("DAC2 EQ Band 4 Volume", DA732X_REG_DAC2_EQ34, | ||
573 | DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
574 | DA732X_INVERT, eq_band_pga_tlv), | ||
575 | SOC_SINGLE_TLV("DAC2 EQ Band 5 Volume", DA732X_REG_DAC2_EQ5, | ||
576 | DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
577 | DA732X_INVERT, eq_band_pga_tlv), | ||
578 | |||
579 | SOC_SINGLE("DAC3 EQ Switch", DA732X_REG_DAC3_EQ5, | ||
580 | DA732X_EQ_EN_SHIFT, DA732X_EQ_EN_MAX, DA732X_NO_INVERT), | ||
581 | SOC_SINGLE_TLV("DAC3 EQ Band 1 Volume", DA732X_REG_DAC3_EQ12, | ||
582 | DA732X_EQ_BAND1_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
583 | DA732X_INVERT, eq_band_pga_tlv), | ||
584 | SOC_SINGLE_TLV("DAC3 EQ Band 2 Volume", DA732X_REG_DAC3_EQ12, | ||
585 | DA732X_EQ_BAND2_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
586 | DA732X_INVERT, eq_band_pga_tlv), | ||
587 | SOC_SINGLE_TLV("DAC3 EQ Band 3 Volume", DA732X_REG_DAC3_EQ34, | ||
588 | DA732X_EQ_BAND3_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
589 | DA732X_INVERT, eq_band_pga_tlv), | ||
590 | SOC_SINGLE_TLV("DAC3 EQ Band 4 Volume", DA732X_REG_DAC3_EQ34, | ||
591 | DA732X_EQ_BAND4_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
592 | DA732X_INVERT, eq_band_pga_tlv), | ||
593 | SOC_SINGLE_TLV("DAC3 EQ Band 5 Volume", DA732X_REG_DAC3_EQ5, | ||
594 | DA732X_EQ_BAND5_SHIFT, DA732X_EQ_VOL_VAL_MAX, | ||
595 | DA732X_INVERT, eq_band_pga_tlv), | ||
596 | |||
597 | /* Lineout 2 Reciever*/ | ||
598 | SOC_SINGLE("Lineout 2 Switch", DA732X_REG_LIN2, DA732X_LOUT_MUTE_SHIFT, | ||
599 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
600 | SOC_SINGLE_TLV("Lineout 2 Volume", DA732X_REG_LIN2, | ||
601 | DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, | ||
602 | DA732X_NO_INVERT, lin2_pga_tlv), | ||
603 | |||
604 | /* Lineout 3 SPEAKER*/ | ||
605 | SOC_SINGLE("Lineout 3 Switch", DA732X_REG_LIN3, DA732X_LOUT_MUTE_SHIFT, | ||
606 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
607 | SOC_SINGLE_TLV("Lineout 3 Volume", DA732X_REG_LIN3, | ||
608 | DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, | ||
609 | DA732X_NO_INVERT, lin3_pga_tlv), | ||
610 | |||
611 | /* Lineout 4 */ | ||
612 | SOC_SINGLE("Lineout 4 Switch", DA732X_REG_LIN4, DA732X_LOUT_MUTE_SHIFT, | ||
613 | DA732X_SWITCH_MAX, DA732X_INVERT), | ||
614 | SOC_SINGLE_TLV("Lineout 4 Volume", DA732X_REG_LIN4, | ||
615 | DA732X_LOUT_VOL_SHIFT, DA732X_LOUT_VOL_VAL_MAX, | ||
616 | DA732X_NO_INVERT, lin4_pga_tlv), | ||
617 | |||
618 | /* Headphones */ | ||
619 | SOC_DOUBLE_R("Headphone Switch", DA732X_REG_HPR, DA732X_REG_HPL, | ||
620 | DA732X_HP_MUTE_SHIFT, DA732X_SWITCH_MAX, DA732X_INVERT), | ||
621 | SOC_DOUBLE_R_TLV("Headphone Volume", DA732X_REG_HPL_VOL, | ||
622 | DA732X_REG_HPR_VOL, DA732X_HP_VOL_SHIFT, | ||
623 | DA732X_HP_VOL_VAL_MAX, DA732X_NO_INVERT, hp_pga_tlv), | ||
624 | }; | ||
625 | |||
626 | static int da732x_adc_event(struct snd_soc_dapm_widget *w, | ||
627 | struct snd_kcontrol *kcontrol, int event) | ||
628 | { | ||
629 | struct snd_soc_codec *codec = w->codec; | ||
630 | |||
631 | switch (event) { | ||
632 | case SND_SOC_DAPM_POST_PMU: | ||
633 | switch (w->reg) { | ||
634 | case DA732X_REG_ADC1_PD: | ||
635 | snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, | ||
636 | DA732X_ADCA_BB_CLK_EN, | ||
637 | DA732X_ADCA_BB_CLK_EN); | ||
638 | break; | ||
639 | case DA732X_REG_ADC2_PD: | ||
640 | snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, | ||
641 | DA732X_ADCC_BB_CLK_EN, | ||
642 | DA732X_ADCC_BB_CLK_EN); | ||
643 | break; | ||
644 | default: | ||
645 | return -EINVAL; | ||
646 | } | ||
647 | |||
648 | snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK, | ||
649 | DA732X_ADC_SET_ACT); | ||
650 | snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK, | ||
651 | DA732X_ADC_ON); | ||
652 | break; | ||
653 | case SND_SOC_DAPM_POST_PMD: | ||
654 | snd_soc_update_bits(codec, w->reg, DA732X_ADC_PD_MASK, | ||
655 | DA732X_ADC_OFF); | ||
656 | snd_soc_update_bits(codec, w->reg, DA732X_ADC_RST_MASK, | ||
657 | DA732X_ADC_SET_RST); | ||
658 | |||
659 | switch (w->reg) { | ||
660 | case DA732X_REG_ADC1_PD: | ||
661 | snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, | ||
662 | DA732X_ADCA_BB_CLK_EN, 0); | ||
663 | break; | ||
664 | case DA732X_REG_ADC2_PD: | ||
665 | snd_soc_update_bits(codec, DA732X_REG_CLK_EN3, | ||
666 | DA732X_ADCC_BB_CLK_EN, 0); | ||
667 | break; | ||
668 | default: | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | |||
672 | break; | ||
673 | default: | ||
674 | return -EINVAL; | ||
675 | } | ||
676 | |||
677 | return 0; | ||
678 | } | ||
679 | |||
680 | static int da732x_out_pga_event(struct snd_soc_dapm_widget *w, | ||
681 | struct snd_kcontrol *kcontrol, int event) | ||
682 | { | ||
683 | struct snd_soc_codec *codec = w->codec; | ||
684 | |||
685 | switch (event) { | ||
686 | case SND_SOC_DAPM_POST_PMU: | ||
687 | snd_soc_update_bits(codec, w->reg, | ||
688 | (1 << w->shift) | DA732X_OUT_HIZ_EN, | ||
689 | (1 << w->shift) | DA732X_OUT_HIZ_EN); | ||
690 | break; | ||
691 | case SND_SOC_DAPM_POST_PMD: | ||
692 | snd_soc_update_bits(codec, w->reg, | ||
693 | (1 << w->shift) | DA732X_OUT_HIZ_EN, | ||
694 | (1 << w->shift) | DA732X_OUT_HIZ_DIS); | ||
695 | break; | ||
696 | default: | ||
697 | return -EINVAL; | ||
698 | } | ||
699 | |||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static const char *adcl_text[] = { | ||
704 | "AUX1L", "MIC1" | ||
705 | }; | ||
706 | |||
707 | static const char *adcr_text[] = { | ||
708 | "AUX1R", "MIC2", "MIC3" | ||
709 | }; | ||
710 | |||
711 | static const char *enable_text[] = { | ||
712 | "Disabled", | ||
713 | "Enabled" | ||
714 | }; | ||
715 | |||
716 | /* ADC1LMUX */ | ||
717 | static const struct soc_enum adc1l_enum = | ||
718 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, | ||
719 | DA732X_ADCL_MUX_MAX, adcl_text); | ||
720 | static const struct snd_kcontrol_new adc1l_mux = | ||
721 | SOC_DAPM_ENUM("ADC Route", adc1l_enum); | ||
722 | |||
723 | /* ADC1RMUX */ | ||
724 | static const struct soc_enum adc1r_enum = | ||
725 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, | ||
726 | DA732X_ADCR_MUX_MAX, adcr_text); | ||
727 | static const struct snd_kcontrol_new adc1r_mux = | ||
728 | SOC_DAPM_ENUM("ADC Route", adc1r_enum); | ||
729 | |||
730 | /* ADC2LMUX */ | ||
731 | static const struct soc_enum adc2l_enum = | ||
732 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, | ||
733 | DA732X_ADCL_MUX_MAX, adcl_text); | ||
734 | static const struct snd_kcontrol_new adc2l_mux = | ||
735 | SOC_DAPM_ENUM("ADC Route", adc2l_enum); | ||
736 | |||
737 | /* ADC2RMUX */ | ||
738 | static const struct soc_enum adc2r_enum = | ||
739 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, | ||
740 | DA732X_ADCR_MUX_MAX, adcr_text); | ||
741 | |||
742 | static const struct snd_kcontrol_new adc2r_mux = | ||
743 | SOC_DAPM_ENUM("ADC Route", adc2r_enum); | ||
744 | |||
745 | static const struct soc_enum da732x_hp_left_output = | ||
746 | SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, | ||
747 | DA732X_DAC_EN_MAX, enable_text); | ||
748 | |||
749 | static const struct snd_kcontrol_new hpl_mux = | ||
750 | SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); | ||
751 | |||
752 | static const struct soc_enum da732x_hp_right_output = | ||
753 | SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, | ||
754 | DA732X_DAC_EN_MAX, enable_text); | ||
755 | |||
756 | static const struct snd_kcontrol_new hpr_mux = | ||
757 | SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); | ||
758 | |||
759 | static const struct soc_enum da732x_speaker_output = | ||
760 | SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, | ||
761 | DA732X_DAC_EN_MAX, enable_text); | ||
762 | |||
763 | static const struct snd_kcontrol_new spk_mux = | ||
764 | SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); | ||
765 | |||
766 | static const struct soc_enum da732x_lout4_output = | ||
767 | SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, | ||
768 | DA732X_DAC_EN_MAX, enable_text); | ||
769 | |||
770 | static const struct snd_kcontrol_new lout4_mux = | ||
771 | SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); | ||
772 | |||
773 | static const struct soc_enum da732x_lout2_output = | ||
774 | SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, | ||
775 | DA732X_DAC_EN_MAX, enable_text); | ||
776 | |||
777 | static const struct snd_kcontrol_new lout2_mux = | ||
778 | SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); | ||
779 | |||
780 | static const struct snd_soc_dapm_widget da732x_dapm_widgets[] = { | ||
781 | /* Supplies */ | ||
782 | SND_SOC_DAPM_SUPPLY("ADC1 Supply", DA732X_REG_ADC1_PD, 0, | ||
783 | DA732X_NO_INVERT, da732x_adc_event, | ||
784 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
785 | SND_SOC_DAPM_SUPPLY("ADC2 Supply", DA732X_REG_ADC2_PD, 0, | ||
786 | DA732X_NO_INVERT, da732x_adc_event, | ||
787 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | ||
788 | SND_SOC_DAPM_SUPPLY("DAC1 CLK", DA732X_REG_CLK_EN4, | ||
789 | DA732X_DACA_BB_CLK_SHIFT, DA732X_NO_INVERT, | ||
790 | NULL, 0), | ||
791 | SND_SOC_DAPM_SUPPLY("DAC2 CLK", DA732X_REG_CLK_EN4, | ||
792 | DA732X_DACC_BB_CLK_SHIFT, DA732X_NO_INVERT, | ||
793 | NULL, 0), | ||
794 | SND_SOC_DAPM_SUPPLY("DAC3 CLK", DA732X_REG_CLK_EN5, | ||
795 | DA732X_DACE_BB_CLK_SHIFT, DA732X_NO_INVERT, | ||
796 | NULL, 0), | ||
797 | |||
798 | /* Micbias */ | ||
799 | SND_SOC_DAPM_SUPPLY("MICBIAS1", DA732X_REG_MICBIAS1, | ||
800 | DA732X_MICBIAS_EN_SHIFT, | ||
801 | DA732X_NO_INVERT, NULL, 0), | ||
802 | SND_SOC_DAPM_SUPPLY("MICBIAS2", DA732X_REG_MICBIAS2, | ||
803 | DA732X_MICBIAS_EN_SHIFT, | ||
804 | DA732X_NO_INVERT, NULL, 0), | ||
805 | |||
806 | /* Inputs */ | ||
807 | SND_SOC_DAPM_INPUT("MIC1"), | ||
808 | SND_SOC_DAPM_INPUT("MIC2"), | ||
809 | SND_SOC_DAPM_INPUT("MIC3"), | ||
810 | SND_SOC_DAPM_INPUT("AUX1L"), | ||
811 | SND_SOC_DAPM_INPUT("AUX1R"), | ||
812 | |||
813 | /* Outputs */ | ||
814 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
815 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
816 | SND_SOC_DAPM_OUTPUT("LOUTL"), | ||
817 | SND_SOC_DAPM_OUTPUT("LOUTR"), | ||
818 | SND_SOC_DAPM_OUTPUT("ClassD"), | ||
819 | |||
820 | /* ADCs */ | ||
821 | SND_SOC_DAPM_ADC("ADC1L", NULL, DA732X_REG_ADC1_SEL, | ||
822 | DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT), | ||
823 | SND_SOC_DAPM_ADC("ADC1R", NULL, DA732X_REG_ADC1_SEL, | ||
824 | DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT), | ||
825 | SND_SOC_DAPM_ADC("ADC2L", NULL, DA732X_REG_ADC2_SEL, | ||
826 | DA732X_ADCL_EN_SHIFT, DA732X_NO_INVERT), | ||
827 | SND_SOC_DAPM_ADC("ADC2R", NULL, DA732X_REG_ADC2_SEL, | ||
828 | DA732X_ADCR_EN_SHIFT, DA732X_NO_INVERT), | ||
829 | |||
830 | /* DACs */ | ||
831 | SND_SOC_DAPM_DAC("DAC1L", NULL, DA732X_REG_DAC1_SEL, | ||
832 | DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), | ||
833 | SND_SOC_DAPM_DAC("DAC1R", NULL, DA732X_REG_DAC1_SEL, | ||
834 | DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT), | ||
835 | SND_SOC_DAPM_DAC("DAC2L", NULL, DA732X_REG_DAC2_SEL, | ||
836 | DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), | ||
837 | SND_SOC_DAPM_DAC("DAC2R", NULL, DA732X_REG_DAC2_SEL, | ||
838 | DA732X_DACR_EN_SHIFT, DA732X_NO_INVERT), | ||
839 | SND_SOC_DAPM_DAC("DAC3", NULL, DA732X_REG_DAC3_SEL, | ||
840 | DA732X_DACL_EN_SHIFT, DA732X_NO_INVERT), | ||
841 | |||
842 | /* Input Pgas */ | ||
843 | SND_SOC_DAPM_PGA("MIC1 PGA", DA732X_REG_MIC1, DA732X_MIC_EN_SHIFT, | ||
844 | 0, NULL, 0), | ||
845 | SND_SOC_DAPM_PGA("MIC2 PGA", DA732X_REG_MIC2, DA732X_MIC_EN_SHIFT, | ||
846 | 0, NULL, 0), | ||
847 | SND_SOC_DAPM_PGA("MIC3 PGA", DA732X_REG_MIC3, DA732X_MIC_EN_SHIFT, | ||
848 | 0, NULL, 0), | ||
849 | SND_SOC_DAPM_PGA("AUX1L PGA", DA732X_REG_AUX1L, DA732X_AUX_EN_SHIFT, | ||
850 | 0, NULL, 0), | ||
851 | SND_SOC_DAPM_PGA("AUX1R PGA", DA732X_REG_AUX1R, DA732X_AUX_EN_SHIFT, | ||
852 | 0, NULL, 0), | ||
853 | |||
854 | SND_SOC_DAPM_PGA_E("HP Left", DA732X_REG_HPL, DA732X_HP_OUT_EN_SHIFT, | ||
855 | 0, NULL, 0, da732x_out_pga_event, | ||
856 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
857 | SND_SOC_DAPM_PGA_E("HP Right", DA732X_REG_HPR, DA732X_HP_OUT_EN_SHIFT, | ||
858 | 0, NULL, 0, da732x_out_pga_event, | ||
859 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
860 | SND_SOC_DAPM_PGA_E("LIN2", DA732X_REG_LIN2, DA732X_LIN_OUT_EN_SHIFT, | ||
861 | 0, NULL, 0, da732x_out_pga_event, | ||
862 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
863 | SND_SOC_DAPM_PGA_E("LIN3", DA732X_REG_LIN3, DA732X_LIN_OUT_EN_SHIFT, | ||
864 | 0, NULL, 0, da732x_out_pga_event, | ||
865 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
866 | SND_SOC_DAPM_PGA_E("LIN4", DA732X_REG_LIN4, DA732X_LIN_OUT_EN_SHIFT, | ||
867 | 0, NULL, 0, da732x_out_pga_event, | ||
868 | SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD), | ||
869 | |||
870 | /* MUXs */ | ||
871 | SND_SOC_DAPM_MUX("ADC1 Left MUX", SND_SOC_NOPM, 0, 0, &adc1l_mux), | ||
872 | SND_SOC_DAPM_MUX("ADC1 Right MUX", SND_SOC_NOPM, 0, 0, &adc1r_mux), | ||
873 | SND_SOC_DAPM_MUX("ADC2 Left MUX", SND_SOC_NOPM, 0, 0, &adc2l_mux), | ||
874 | SND_SOC_DAPM_MUX("ADC2 Right MUX", SND_SOC_NOPM, 0, 0, &adc2r_mux), | ||
875 | |||
876 | SND_SOC_DAPM_MUX("HP Left MUX", SND_SOC_NOPM, 0, 0, &hpl_mux), | ||
877 | SND_SOC_DAPM_MUX("HP Right MUX", SND_SOC_NOPM, 0, 0, &hpr_mux), | ||
878 | SND_SOC_DAPM_MUX("Speaker MUX", SND_SOC_NOPM, 0, 0, &spk_mux), | ||
879 | SND_SOC_DAPM_MUX("LOUT2 MUX", SND_SOC_NOPM, 0, 0, &lout2_mux), | ||
880 | SND_SOC_DAPM_MUX("LOUT4 MUX", SND_SOC_NOPM, 0, 0, &lout4_mux), | ||
881 | |||
882 | /* AIF interfaces */ | ||
883 | SND_SOC_DAPM_AIF_OUT("AIFA Output", "AIFA Capture", 0, DA732X_REG_AIFA3, | ||
884 | DA732X_AIF_EN_SHIFT, 0), | ||
885 | SND_SOC_DAPM_AIF_IN("AIFA Input", "AIFA Playback", 0, DA732X_REG_AIFA3, | ||
886 | DA732X_AIF_EN_SHIFT, 0), | ||
887 | |||
888 | SND_SOC_DAPM_AIF_OUT("AIFB Output", "AIFB Capture", 0, DA732X_REG_AIFB3, | ||
889 | DA732X_AIF_EN_SHIFT, 0), | ||
890 | SND_SOC_DAPM_AIF_IN("AIFB Input", "AIFB Playback", 0, DA732X_REG_AIFB3, | ||
891 | DA732X_AIF_EN_SHIFT, 0), | ||
892 | }; | ||
893 | |||
894 | static const struct snd_soc_dapm_route da732x_dapm_routes[] = { | ||
895 | /* Inputs */ | ||
896 | {"AUX1L PGA", "NULL", "AUX1L"}, | ||
897 | {"AUX1R PGA", "NULL", "AUX1R"}, | ||
898 | {"MIC1 PGA", NULL, "MIC1"}, | ||
899 | {"MIC2 PGA", "NULL", "MIC2"}, | ||
900 | {"MIC3 PGA", "NULL", "MIC3"}, | ||
901 | |||
902 | /* Capture Path */ | ||
903 | {"ADC1 Left MUX", "MIC1", "MIC1 PGA"}, | ||
904 | {"ADC1 Left MUX", "AUX1L", "AUX1L PGA"}, | ||
905 | |||
906 | {"ADC1 Right MUX", "AUX1R", "AUX1R PGA"}, | ||
907 | {"ADC1 Right MUX", "MIC2", "MIC2 PGA"}, | ||
908 | {"ADC1 Right MUX", "MIC3", "MIC3 PGA"}, | ||
909 | |||
910 | {"ADC2 Left MUX", "AUX1L", "AUX1L PGA"}, | ||
911 | {"ADC2 Left MUX", "MIC1", "MIC1 PGA"}, | ||
912 | |||
913 | {"ADC2 Right MUX", "AUX1R", "AUX1R PGA"}, | ||
914 | {"ADC2 Right MUX", "MIC2", "MIC2 PGA"}, | ||
915 | {"ADC2 Right MUX", "MIC3", "MIC3 PGA"}, | ||
916 | |||
917 | {"ADC1L", NULL, "ADC1 Supply"}, | ||
918 | {"ADC1R", NULL, "ADC1 Supply"}, | ||
919 | {"ADC2L", NULL, "ADC2 Supply"}, | ||
920 | {"ADC2R", NULL, "ADC2 Supply"}, | ||
921 | |||
922 | {"ADC1L", NULL, "ADC1 Left MUX"}, | ||
923 | {"ADC1R", NULL, "ADC1 Right MUX"}, | ||
924 | {"ADC2L", NULL, "ADC2 Left MUX"}, | ||
925 | {"ADC2R", NULL, "ADC2 Right MUX"}, | ||
926 | |||
927 | {"AIFA Output", NULL, "ADC1L"}, | ||
928 | {"AIFA Output", NULL, "ADC1R"}, | ||
929 | {"AIFB Output", NULL, "ADC2L"}, | ||
930 | {"AIFB Output", NULL, "ADC2R"}, | ||
931 | |||
932 | {"HP Left MUX", "Enabled", "AIFA Input"}, | ||
933 | {"HP Right MUX", "Enabled", "AIFA Input"}, | ||
934 | {"Speaker MUX", "Enabled", "AIFB Input"}, | ||
935 | {"LOUT2 MUX", "Enabled", "AIFB Input"}, | ||
936 | {"LOUT4 MUX", "Enabled", "AIFB Input"}, | ||
937 | |||
938 | {"DAC1L", NULL, "DAC1 CLK"}, | ||
939 | {"DAC1R", NULL, "DAC1 CLK"}, | ||
940 | {"DAC2L", NULL, "DAC2 CLK"}, | ||
941 | {"DAC2R", NULL, "DAC2 CLK"}, | ||
942 | {"DAC3", NULL, "DAC3 CLK"}, | ||
943 | |||
944 | {"DAC1L", NULL, "HP Left MUX"}, | ||
945 | {"DAC1R", NULL, "HP Right MUX"}, | ||
946 | {"DAC2L", NULL, "Speaker MUX"}, | ||
947 | {"DAC2R", NULL, "LOUT4 MUX"}, | ||
948 | {"DAC3", NULL, "LOUT2 MUX"}, | ||
949 | |||
950 | /* Output Pgas */ | ||
951 | {"HP Left", NULL, "DAC1L"}, | ||
952 | {"HP Right", NULL, "DAC1R"}, | ||
953 | {"LIN3", NULL, "DAC2L"}, | ||
954 | {"LIN4", NULL, "DAC2R"}, | ||
955 | {"LIN2", NULL, "DAC3"}, | ||
956 | |||
957 | /* Outputs */ | ||
958 | {"ClassD", NULL, "LIN3"}, | ||
959 | {"LOUTL", NULL, "LIN2"}, | ||
960 | {"LOUTR", NULL, "LIN4"}, | ||
961 | {"HPL", NULL, "HP Left"}, | ||
962 | {"HPR", NULL, "HP Right"}, | ||
963 | }; | ||
964 | |||
965 | static int da732x_hw_params(struct snd_pcm_substream *substream, | ||
966 | struct snd_pcm_hw_params *params, | ||
967 | struct snd_soc_dai *dai) | ||
968 | { | ||
969 | struct snd_soc_codec *codec = dai->codec; | ||
970 | u32 aif = 0; | ||
971 | u32 reg_aif; | ||
972 | u32 fs; | ||
973 | |||
974 | reg_aif = dai->driver->base; | ||
975 | |||
976 | switch (params_format(params)) { | ||
977 | case SNDRV_PCM_FORMAT_S16_LE: | ||
978 | aif |= DA732X_AIF_WORD_16; | ||
979 | break; | ||
980 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
981 | aif |= DA732X_AIF_WORD_20; | ||
982 | break; | ||
983 | case SNDRV_PCM_FORMAT_S24_LE: | ||
984 | aif |= DA732X_AIF_WORD_24; | ||
985 | break; | ||
986 | case SNDRV_PCM_FORMAT_S32_LE: | ||
987 | aif |= DA732X_AIF_WORD_32; | ||
988 | break; | ||
989 | default: | ||
990 | return -EINVAL; | ||
991 | } | ||
992 | |||
993 | switch (params_rate(params)) { | ||
994 | case 8000: | ||
995 | fs = DA732X_SR_8KHZ; | ||
996 | break; | ||
997 | case 11025: | ||
998 | fs = DA732X_SR_11_025KHZ; | ||
999 | break; | ||
1000 | case 12000: | ||
1001 | fs = DA732X_SR_12KHZ; | ||
1002 | break; | ||
1003 | case 16000: | ||
1004 | fs = DA732X_SR_16KHZ; | ||
1005 | break; | ||
1006 | case 22050: | ||
1007 | fs = DA732X_SR_22_05KHZ; | ||
1008 | break; | ||
1009 | case 24000: | ||
1010 | fs = DA732X_SR_24KHZ; | ||
1011 | break; | ||
1012 | case 32000: | ||
1013 | fs = DA732X_SR_32KHZ; | ||
1014 | break; | ||
1015 | case 44100: | ||
1016 | fs = DA732X_SR_44_1KHZ; | ||
1017 | break; | ||
1018 | case 48000: | ||
1019 | fs = DA732X_SR_48KHZ; | ||
1020 | break; | ||
1021 | case 88100: | ||
1022 | fs = DA732X_SR_88_1KHZ; | ||
1023 | break; | ||
1024 | case 96000: | ||
1025 | fs = DA732X_SR_96KHZ; | ||
1026 | break; | ||
1027 | default: | ||
1028 | return -EINVAL; | ||
1029 | } | ||
1030 | |||
1031 | snd_soc_update_bits(codec, reg_aif, DA732X_AIF_WORD_MASK, aif); | ||
1032 | snd_soc_update_bits(codec, DA732X_REG_CLK_CTRL, DA732X_SR1_MASK, fs); | ||
1033 | |||
1034 | return 0; | ||
1035 | } | ||
1036 | |||
1037 | static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt) | ||
1038 | { | ||
1039 | struct snd_soc_codec *codec = dai->codec; | ||
1040 | u32 aif_mclk, pc_count; | ||
1041 | u32 reg_aif1, aif1; | ||
1042 | u32 reg_aif3, aif3; | ||
1043 | |||
1044 | switch (dai->id) { | ||
1045 | case DA732X_DAI_ID1: | ||
1046 | reg_aif1 = DA732X_REG_AIFA1; | ||
1047 | reg_aif3 = DA732X_REG_AIFA3; | ||
1048 | pc_count = DA732X_PC_PULSE_AIFA | DA732X_PC_RESYNC_NOT_AUT | | ||
1049 | DA732X_PC_SAME; | ||
1050 | break; | ||
1051 | case DA732X_DAI_ID2: | ||
1052 | reg_aif1 = DA732X_REG_AIFB1; | ||
1053 | reg_aif3 = DA732X_REG_AIFB3; | ||
1054 | pc_count = DA732X_PC_PULSE_AIFB | DA732X_PC_RESYNC_NOT_AUT | | ||
1055 | DA732X_PC_SAME; | ||
1056 | break; | ||
1057 | default: | ||
1058 | return -EINVAL; | ||
1059 | } | ||
1060 | |||
1061 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
1062 | case SND_SOC_DAIFMT_CBS_CFS: | ||
1063 | aif1 = DA732X_AIF_SLAVE; | ||
1064 | aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA; | ||
1065 | break; | ||
1066 | case SND_SOC_DAIFMT_CBM_CFM: | ||
1067 | aif1 = DA732X_AIF_CLK_FROM_SRC; | ||
1068 | aif_mclk = DA732X_CLK_GENERATION_AIF_A; | ||
1069 | break; | ||
1070 | default: | ||
1071 | return -EINVAL; | ||
1072 | } | ||
1073 | |||
1074 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1075 | case SND_SOC_DAIFMT_I2S: | ||
1076 | aif3 = DA732X_AIF_I2S_MODE; | ||
1077 | break; | ||
1078 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1079 | aif3 = DA732X_AIF_RIGHT_J_MODE; | ||
1080 | break; | ||
1081 | case SND_SOC_DAIFMT_LEFT_J: | ||
1082 | aif3 = DA732X_AIF_LEFT_J_MODE; | ||
1083 | break; | ||
1084 | case SND_SOC_DAIFMT_DSP_B: | ||
1085 | aif3 = DA732X_AIF_DSP_MODE; | ||
1086 | break; | ||
1087 | default: | ||
1088 | return -EINVAL; | ||
1089 | } | ||
1090 | |||
1091 | /* Clock inversion */ | ||
1092 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
1093 | case SND_SOC_DAIFMT_DSP_B: | ||
1094 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1095 | case SND_SOC_DAIFMT_NB_NF: | ||
1096 | break; | ||
1097 | case SND_SOC_DAIFMT_IB_NF: | ||
1098 | aif3 |= DA732X_AIF_BCLK_INV; | ||
1099 | break; | ||
1100 | default: | ||
1101 | return -EINVAL; | ||
1102 | } | ||
1103 | break; | ||
1104 | case SND_SOC_DAIFMT_I2S: | ||
1105 | case SND_SOC_DAIFMT_RIGHT_J: | ||
1106 | case SND_SOC_DAIFMT_LEFT_J: | ||
1107 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
1108 | case SND_SOC_DAIFMT_NB_NF: | ||
1109 | break; | ||
1110 | case SND_SOC_DAIFMT_IB_IF: | ||
1111 | aif3 |= DA732X_AIF_BCLK_INV | DA732X_AIF_WCLK_INV; | ||
1112 | break; | ||
1113 | case SND_SOC_DAIFMT_IB_NF: | ||
1114 | aif3 |= DA732X_AIF_BCLK_INV; | ||
1115 | break; | ||
1116 | case SND_SOC_DAIFMT_NB_IF: | ||
1117 | aif3 |= DA732X_AIF_WCLK_INV; | ||
1118 | break; | ||
1119 | default: | ||
1120 | return -EINVAL; | ||
1121 | } | ||
1122 | break; | ||
1123 | default: | ||
1124 | return -EINVAL; | ||
1125 | } | ||
1126 | |||
1127 | snd_soc_write(codec, DA732X_REG_AIF_MCLK, aif_mclk); | ||
1128 | snd_soc_update_bits(codec, reg_aif1, DA732X_AIF1_CLK_MASK, aif1); | ||
1129 | snd_soc_update_bits(codec, reg_aif3, DA732X_AIF_BCLK_INV | | ||
1130 | DA732X_AIF_WCLK_INV | DA732X_AIF_MODE_MASK, aif3); | ||
1131 | snd_soc_write(codec, DA732X_REG_PC_CTRL, pc_count); | ||
1132 | |||
1133 | return 0; | ||
1134 | } | ||
1135 | |||
1136 | |||
1137 | |||
1138 | static int da732x_set_dai_pll(struct snd_soc_codec *codec, int pll_id, | ||
1139 | int source, unsigned int freq_in, | ||
1140 | unsigned int freq_out) | ||
1141 | { | ||
1142 | struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); | ||
1143 | int fref, indiv; | ||
1144 | u8 div_lo, div_mid, div_hi; | ||
1145 | u64 frac_div; | ||
1146 | |||
1147 | /* Disable PLL */ | ||
1148 | if (freq_out == 0) { | ||
1149 | snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, | ||
1150 | DA732X_PLL_EN, 0); | ||
1151 | da732x->pll_en = false; | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | if (da732x->pll_en) | ||
1156 | return -EBUSY; | ||
1157 | |||
1158 | if (source == DA732X_SRCCLK_MCLK) { | ||
1159 | /* Validate Sysclk rate */ | ||
1160 | switch (da732x->sysclk) { | ||
1161 | case 11290000: | ||
1162 | case 12288000: | ||
1163 | case 22580000: | ||
1164 | case 24576000: | ||
1165 | case 45160000: | ||
1166 | case 49152000: | ||
1167 | snd_soc_write(codec, DA732X_REG_PLL_CTRL, | ||
1168 | DA732X_PLL_BYPASS); | ||
1169 | return 0; | ||
1170 | default: | ||
1171 | dev_err(codec->dev, | ||
1172 | "Cannot use PLL Bypass, invalid SYSCLK rate\n"); | ||
1173 | return -EINVAL; | ||
1174 | } | ||
1175 | } | ||
1176 | |||
1177 | indiv = da732x_get_input_div(codec, da732x->sysclk); | ||
1178 | if (indiv < 0) | ||
1179 | return indiv; | ||
1180 | |||
1181 | fref = (da732x->sysclk / indiv); | ||
1182 | div_hi = freq_out / fref; | ||
1183 | frac_div = (u64)(freq_out % fref) * 8192ULL; | ||
1184 | do_div(frac_div, fref); | ||
1185 | div_mid = (frac_div >> DA732X_1BYTE_SHIFT) & DA732X_U8_MASK; | ||
1186 | div_lo = (frac_div) & DA732X_U8_MASK; | ||
1187 | |||
1188 | snd_soc_write(codec, DA732X_REG_PLL_DIV_LO, div_lo); | ||
1189 | snd_soc_write(codec, DA732X_REG_PLL_DIV_MID, div_mid); | ||
1190 | snd_soc_write(codec, DA732X_REG_PLL_DIV_HI, div_hi); | ||
1191 | |||
1192 | snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, DA732X_PLL_EN, | ||
1193 | DA732X_PLL_EN); | ||
1194 | |||
1195 | da732x->pll_en = true; | ||
1196 | |||
1197 | return 0; | ||
1198 | } | ||
1199 | |||
1200 | static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
1201 | unsigned int freq, int dir) | ||
1202 | { | ||
1203 | struct snd_soc_codec *codec = dai->codec; | ||
1204 | struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); | ||
1205 | |||
1206 | da732x->sysclk = freq; | ||
1207 | |||
1208 | return 0; | ||
1209 | } | ||
1210 | |||
1211 | #define DA732X_RATES SNDRV_PCM_RATE_8000_96000 | ||
1212 | |||
1213 | #define DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
1214 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
1215 | |||
1216 | static struct snd_soc_dai_ops da732x_dai1_ops = { | ||
1217 | .hw_params = da732x_hw_params, | ||
1218 | .set_fmt = da732x_set_dai_fmt, | ||
1219 | .set_sysclk = da732x_set_dai_sysclk, | ||
1220 | }; | ||
1221 | |||
1222 | static struct snd_soc_dai_ops da732x_dai2_ops = { | ||
1223 | .hw_params = da732x_hw_params, | ||
1224 | .set_fmt = da732x_set_dai_fmt, | ||
1225 | .set_sysclk = da732x_set_dai_sysclk, | ||
1226 | }; | ||
1227 | |||
1228 | static struct snd_soc_dai_driver da732x_dai[] = { | ||
1229 | { | ||
1230 | .name = "DA732X_AIFA", | ||
1231 | .id = DA732X_DAI_ID1, | ||
1232 | .base = DA732X_REG_AIFA1, | ||
1233 | .playback = { | ||
1234 | .stream_name = "AIFA Playback", | ||
1235 | .channels_min = 1, | ||
1236 | .channels_max = 2, | ||
1237 | .rates = DA732X_RATES, | ||
1238 | .formats = DA732X_FORMATS, | ||
1239 | }, | ||
1240 | .capture = { | ||
1241 | .stream_name = "AIFA Capture", | ||
1242 | .channels_min = 1, | ||
1243 | .channels_max = 2, | ||
1244 | .rates = DA732X_RATES, | ||
1245 | .formats = DA732X_FORMATS, | ||
1246 | }, | ||
1247 | .ops = &da732x_dai1_ops, | ||
1248 | }, | ||
1249 | { | ||
1250 | .name = "DA732X_AIFB", | ||
1251 | .id = DA732X_DAI_ID2, | ||
1252 | .base = DA732X_REG_AIFB1, | ||
1253 | .playback = { | ||
1254 | .stream_name = "AIFB Playback", | ||
1255 | .channels_min = 1, | ||
1256 | .channels_max = 2, | ||
1257 | .rates = DA732X_RATES, | ||
1258 | .formats = DA732X_FORMATS, | ||
1259 | }, | ||
1260 | .capture = { | ||
1261 | .stream_name = "AIFB Capture", | ||
1262 | .channels_min = 1, | ||
1263 | .channels_max = 2, | ||
1264 | .rates = DA732X_RATES, | ||
1265 | .formats = DA732X_FORMATS, | ||
1266 | }, | ||
1267 | .ops = &da732x_dai2_ops, | ||
1268 | }, | ||
1269 | }; | ||
1270 | |||
1271 | static const struct regmap_config da732x_regmap = { | ||
1272 | .reg_bits = 8, | ||
1273 | .val_bits = 8, | ||
1274 | |||
1275 | .max_register = DA732X_MAX_REG, | ||
1276 | .reg_defaults = da732x_reg_cache, | ||
1277 | .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), | ||
1278 | .cache_type = REGCACHE_RBTREE, | ||
1279 | }; | ||
1280 | |||
1281 | |||
1282 | static void da732x_dac_offset_adjust(struct snd_soc_codec *codec) | ||
1283 | { | ||
1284 | u8 offset[DA732X_HP_DACS]; | ||
1285 | u8 sign[DA732X_HP_DACS]; | ||
1286 | u8 step = DA732X_DAC_OFFSET_STEP; | ||
1287 | |||
1288 | /* Initialize DAC offset calibration circuits and registers */ | ||
1289 | snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, | ||
1290 | DA732X_HP_DAC_OFFSET_TRIM_VAL); | ||
1291 | snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, | ||
1292 | DA732X_HP_DAC_OFFSET_TRIM_VAL); | ||
1293 | snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL, | ||
1294 | DA732X_HP_DAC_OFF_CALIBRATION | | ||
1295 | DA732X_HP_DAC_OFF_SCALE_STEPS); | ||
1296 | snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL, | ||
1297 | DA732X_HP_DAC_OFF_CALIBRATION | | ||
1298 | DA732X_HP_DAC_OFF_SCALE_STEPS); | ||
1299 | |||
1300 | /* Wait for voltage stabilization */ | ||
1301 | msleep(DA732X_WAIT_FOR_STABILIZATION); | ||
1302 | |||
1303 | /* Check DAC offset sign */ | ||
1304 | sign[DA732X_HPL_DAC] = (codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & | ||
1305 | DA732X_HP_DAC_OFF_CNTL_COMPO); | ||
1306 | sign[DA732X_HPR_DAC] = (codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & | ||
1307 | DA732X_HP_DAC_OFF_CNTL_COMPO); | ||
1308 | |||
1309 | /* Binary search DAC offset values (both channels at once) */ | ||
1310 | offset[DA732X_HPL_DAC] = sign[DA732X_HPL_DAC] << DA732X_HP_DAC_COMPO_SHIFT; | ||
1311 | offset[DA732X_HPR_DAC] = sign[DA732X_HPR_DAC] << DA732X_HP_DAC_COMPO_SHIFT; | ||
1312 | |||
1313 | do { | ||
1314 | offset[DA732X_HPL_DAC] |= step; | ||
1315 | offset[DA732X_HPR_DAC] |= step; | ||
1316 | snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, | ||
1317 | ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK); | ||
1318 | snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, | ||
1319 | ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK); | ||
1320 | |||
1321 | msleep(DA732X_WAIT_FOR_STABILIZATION); | ||
1322 | |||
1323 | if ((codec->hw_read(codec, DA732X_REG_HPL_DAC_OFF_CNTL) & | ||
1324 | DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPL_DAC]) | ||
1325 | offset[DA732X_HPL_DAC] &= ~step; | ||
1326 | if ((codec->hw_read(codec, DA732X_REG_HPR_DAC_OFF_CNTL) & | ||
1327 | DA732X_HP_DAC_OFF_CNTL_COMPO) ^ sign[DA732X_HPR_DAC]) | ||
1328 | offset[DA732X_HPR_DAC] &= ~step; | ||
1329 | |||
1330 | step >>= 1; | ||
1331 | } while (step); | ||
1332 | |||
1333 | /* Write final DAC offsets to registers */ | ||
1334 | snd_soc_write(codec, DA732X_REG_HPL_DAC_OFFSET, | ||
1335 | ~offset[DA732X_HPL_DAC] & DA732X_HP_DAC_OFF_MASK); | ||
1336 | snd_soc_write(codec, DA732X_REG_HPR_DAC_OFFSET, | ||
1337 | ~offset[DA732X_HPR_DAC] & DA732X_HP_DAC_OFF_MASK); | ||
1338 | |||
1339 | /* End DAC calibration mode */ | ||
1340 | snd_soc_write(codec, DA732X_REG_HPL_DAC_OFF_CNTL, | ||
1341 | DA732X_HP_DAC_OFF_SCALE_STEPS); | ||
1342 | snd_soc_write(codec, DA732X_REG_HPR_DAC_OFF_CNTL, | ||
1343 | DA732X_HP_DAC_OFF_SCALE_STEPS); | ||
1344 | } | ||
1345 | |||
1346 | static void da732x_output_offset_adjust(struct snd_soc_codec *codec) | ||
1347 | { | ||
1348 | u8 offset[DA732X_HP_AMPS]; | ||
1349 | u8 sign[DA732X_HP_AMPS]; | ||
1350 | u8 step = DA732X_OUTPUT_OFFSET_STEP; | ||
1351 | |||
1352 | offset[DA732X_HPL_AMP] = DA732X_HP_OUT_TRIM_VAL; | ||
1353 | offset[DA732X_HPR_AMP] = DA732X_HP_OUT_TRIM_VAL; | ||
1354 | |||
1355 | /* Initialize output offset calibration circuits and registers */ | ||
1356 | snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL); | ||
1357 | snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, DA732X_HP_OUT_TRIM_VAL); | ||
1358 | snd_soc_write(codec, DA732X_REG_HPL, | ||
1359 | DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN); | ||
1360 | snd_soc_write(codec, DA732X_REG_HPR, | ||
1361 | DA732X_HP_OUT_COMP | DA732X_HP_OUT_EN); | ||
1362 | |||
1363 | /* Wait for voltage stabilization */ | ||
1364 | msleep(DA732X_WAIT_FOR_STABILIZATION); | ||
1365 | |||
1366 | /* Check output offset sign */ | ||
1367 | sign[DA732X_HPL_AMP] = codec->hw_read(codec, DA732X_REG_HPL) & | ||
1368 | DA732X_HP_OUT_COMPO; | ||
1369 | sign[DA732X_HPR_AMP] = codec->hw_read(codec, DA732X_REG_HPR) & | ||
1370 | DA732X_HP_OUT_COMPO; | ||
1371 | |||
1372 | snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_COMP | | ||
1373 | (sign[DA732X_HPL_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) | | ||
1374 | DA732X_HP_OUT_EN); | ||
1375 | snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_COMP | | ||
1376 | (sign[DA732X_HPR_AMP] >> DA732X_HP_OUT_COMPO_SHIFT) | | ||
1377 | DA732X_HP_OUT_EN); | ||
1378 | |||
1379 | /* Binary search output offset values (both channels at once) */ | ||
1380 | do { | ||
1381 | offset[DA732X_HPL_AMP] |= step; | ||
1382 | offset[DA732X_HPR_AMP] |= step; | ||
1383 | snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, | ||
1384 | offset[DA732X_HPL_AMP]); | ||
1385 | snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, | ||
1386 | offset[DA732X_HPR_AMP]); | ||
1387 | |||
1388 | msleep(DA732X_WAIT_FOR_STABILIZATION); | ||
1389 | |||
1390 | if ((codec->hw_read(codec, DA732X_REG_HPL) & | ||
1391 | DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPL_AMP]) | ||
1392 | offset[DA732X_HPL_AMP] &= ~step; | ||
1393 | if ((codec->hw_read(codec, DA732X_REG_HPR) & | ||
1394 | DA732X_HP_OUT_COMPO) ^ sign[DA732X_HPR_AMP]) | ||
1395 | offset[DA732X_HPR_AMP] &= ~step; | ||
1396 | |||
1397 | step >>= 1; | ||
1398 | } while (step); | ||
1399 | |||
1400 | /* Write final DAC offsets to registers */ | ||
1401 | snd_soc_write(codec, DA732X_REG_HPL_OUT_OFFSET, offset[DA732X_HPL_AMP]); | ||
1402 | snd_soc_write(codec, DA732X_REG_HPR_OUT_OFFSET, offset[DA732X_HPR_AMP]); | ||
1403 | } | ||
1404 | |||
1405 | static void da732x_hp_dc_offset_cancellation(struct snd_soc_codec *codec) | ||
1406 | { | ||
1407 | /* Make sure that we have Soft Mute enabled */ | ||
1408 | snd_soc_write(codec, DA732X_REG_DAC1_SOFTMUTE, DA732X_SOFTMUTE_EN | | ||
1409 | DA732X_GAIN_RAMPED | DA732X_16_SAMPLES); | ||
1410 | snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACL_EN | | ||
1411 | DA732X_DACR_EN | DA732X_DACL_SDM | DA732X_DACR_SDM | | ||
1412 | DA732X_DACL_MUTE | DA732X_DACR_MUTE); | ||
1413 | snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN | | ||
1414 | DA732X_HP_OUT_MUTE | DA732X_HP_OUT_EN); | ||
1415 | snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_OUT_EN | | ||
1416 | DA732X_HP_OUT_MUTE | DA732X_HP_OUT_DAC_EN); | ||
1417 | |||
1418 | da732x_dac_offset_adjust(codec); | ||
1419 | da732x_output_offset_adjust(codec); | ||
1420 | |||
1421 | snd_soc_write(codec, DA732X_REG_DAC1_SEL, DA732X_DACS_DIS); | ||
1422 | snd_soc_write(codec, DA732X_REG_HPL, DA732X_HP_DIS); | ||
1423 | snd_soc_write(codec, DA732X_REG_HPR, DA732X_HP_DIS); | ||
1424 | } | ||
1425 | |||
1426 | static int da732x_set_bias_level(struct snd_soc_codec *codec, | ||
1427 | enum snd_soc_bias_level level) | ||
1428 | { | ||
1429 | struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); | ||
1430 | |||
1431 | switch (level) { | ||
1432 | case SND_SOC_BIAS_ON: | ||
1433 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, | ||
1434 | DA732X_BIAS_BOOST_MASK, | ||
1435 | DA732X_BIAS_BOOST_100PC); | ||
1436 | break; | ||
1437 | case SND_SOC_BIAS_PREPARE: | ||
1438 | break; | ||
1439 | case SND_SOC_BIAS_STANDBY: | ||
1440 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
1441 | /* Init Codec */ | ||
1442 | snd_soc_write(codec, DA732X_REG_REF1, | ||
1443 | DA732X_VMID_FASTCHG); | ||
1444 | snd_soc_write(codec, DA732X_REG_BIAS_EN, | ||
1445 | DA732X_BIAS_EN); | ||
1446 | |||
1447 | mdelay(DA732X_STARTUP_DELAY); | ||
1448 | |||
1449 | /* Disable Fast Charge and enable DAC ref voltage */ | ||
1450 | snd_soc_write(codec, DA732X_REG_REF1, | ||
1451 | DA732X_REFBUFX2_EN); | ||
1452 | |||
1453 | /* Enable bypass DSP routing */ | ||
1454 | snd_soc_write(codec, DA732X_REG_DATA_ROUTE, | ||
1455 | DA732X_BYPASS_DSP); | ||
1456 | |||
1457 | /* Enable Digital subsystem */ | ||
1458 | snd_soc_write(codec, DA732X_REG_DSP_CTRL, | ||
1459 | DA732X_DIGITAL_EN); | ||
1460 | |||
1461 | snd_soc_write(codec, DA732X_REG_SPARE1_OUT, | ||
1462 | DA732X_HP_DRIVER_EN | | ||
1463 | DA732X_HP_GATE_LOW | | ||
1464 | DA732X_HP_LOOP_GAIN_CTRL); | ||
1465 | snd_soc_write(codec, DA732X_REG_HP_LIN1_GNDSEL, | ||
1466 | DA732X_HP_OUT_GNDSEL); | ||
1467 | |||
1468 | da732x_set_charge_pump(codec, DA732X_ENABLE_CP); | ||
1469 | |||
1470 | snd_soc_write(codec, DA732X_REG_CLK_EN1, | ||
1471 | DA732X_SYS3_CLK_EN | DA732X_PC_CLK_EN); | ||
1472 | |||
1473 | /* Enable Zero Crossing */ | ||
1474 | snd_soc_write(codec, DA732X_REG_INP_ZC_EN, | ||
1475 | DA732X_MIC1_PRE_ZC_EN | | ||
1476 | DA732X_MIC1_ZC_EN | | ||
1477 | DA732X_MIC2_PRE_ZC_EN | | ||
1478 | DA732X_MIC2_ZC_EN | | ||
1479 | DA732X_AUXL_ZC_EN | | ||
1480 | DA732X_AUXR_ZC_EN | | ||
1481 | DA732X_MIC3_PRE_ZC_EN | | ||
1482 | DA732X_MIC3_ZC_EN); | ||
1483 | snd_soc_write(codec, DA732X_REG_OUT_ZC_EN, | ||
1484 | DA732X_HPL_ZC_EN | DA732X_HPR_ZC_EN | | ||
1485 | DA732X_LIN2_ZC_EN | DA732X_LIN3_ZC_EN | | ||
1486 | DA732X_LIN4_ZC_EN); | ||
1487 | |||
1488 | da732x_hp_dc_offset_cancellation(codec); | ||
1489 | |||
1490 | regcache_cache_only(codec->control_data, false); | ||
1491 | regcache_sync(codec->control_data); | ||
1492 | } else { | ||
1493 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, | ||
1494 | DA732X_BIAS_BOOST_MASK, | ||
1495 | DA732X_BIAS_BOOST_50PC); | ||
1496 | snd_soc_update_bits(codec, DA732X_REG_PLL_CTRL, | ||
1497 | DA732X_PLL_EN, 0); | ||
1498 | da732x->pll_en = false; | ||
1499 | } | ||
1500 | break; | ||
1501 | case SND_SOC_BIAS_OFF: | ||
1502 | regcache_cache_only(codec->control_data, true); | ||
1503 | da732x_set_charge_pump(codec, DA732X_DISABLE_CP); | ||
1504 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, | ||
1505 | DA732X_BIAS_DIS); | ||
1506 | da732x->pll_en = false; | ||
1507 | break; | ||
1508 | } | ||
1509 | |||
1510 | codec->dapm.bias_level = level; | ||
1511 | |||
1512 | return 0; | ||
1513 | } | ||
1514 | |||
1515 | static int da732x_probe(struct snd_soc_codec *codec) | ||
1516 | { | ||
1517 | struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); | ||
1518 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
1519 | int ret = 0; | ||
1520 | |||
1521 | da732x->codec = codec; | ||
1522 | |||
1523 | dapm->idle_bias_off = false; | ||
1524 | |||
1525 | codec->control_data = da732x->regmap; | ||
1526 | |||
1527 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); | ||
1528 | if (ret != 0) { | ||
1529 | dev_err(codec->dev, "Failed to register codec.\n"); | ||
1530 | goto err; | ||
1531 | } | ||
1532 | |||
1533 | da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1534 | err: | ||
1535 | return ret; | ||
1536 | } | ||
1537 | |||
1538 | static int da732x_remove(struct snd_soc_codec *codec) | ||
1539 | { | ||
1540 | |||
1541 | da732x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1542 | |||
1543 | return 0; | ||
1544 | } | ||
1545 | |||
1546 | static struct snd_soc_codec_driver soc_codec_dev_da732x = { | ||
1547 | .probe = da732x_probe, | ||
1548 | .remove = da732x_remove, | ||
1549 | .set_bias_level = da732x_set_bias_level, | ||
1550 | .controls = da732x_snd_controls, | ||
1551 | .num_controls = ARRAY_SIZE(da732x_snd_controls), | ||
1552 | .dapm_widgets = da732x_dapm_widgets, | ||
1553 | .num_dapm_widgets = ARRAY_SIZE(da732x_dapm_widgets), | ||
1554 | .dapm_routes = da732x_dapm_routes, | ||
1555 | .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), | ||
1556 | .set_pll = da732x_set_dai_pll, | ||
1557 | .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), | ||
1558 | }; | ||
1559 | |||
1560 | static __devinit int da732x_i2c_probe(struct i2c_client *i2c, | ||
1561 | const struct i2c_device_id *id) | ||
1562 | { | ||
1563 | struct da732x_priv *da732x; | ||
1564 | unsigned int reg; | ||
1565 | int ret; | ||
1566 | |||
1567 | da732x = devm_kzalloc(&i2c->dev, sizeof(struct da732x_priv), | ||
1568 | GFP_KERNEL); | ||
1569 | if (!da732x) | ||
1570 | return -ENOMEM; | ||
1571 | |||
1572 | i2c_set_clientdata(i2c, da732x); | ||
1573 | |||
1574 | da732x->regmap = devm_regmap_init_i2c(i2c, &da732x_regmap); | ||
1575 | if (IS_ERR(da732x->regmap)) { | ||
1576 | ret = PTR_ERR(da732x->regmap); | ||
1577 | dev_err(&i2c->dev, "Failed to initialize regmap\n"); | ||
1578 | goto err; | ||
1579 | } | ||
1580 | |||
1581 | ret = regmap_read(da732x->regmap, DA732X_REG_ID, ®); | ||
1582 | if (ret < 0) { | ||
1583 | dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); | ||
1584 | goto err; | ||
1585 | } | ||
1586 | |||
1587 | dev_info(&i2c->dev, "Revision: %d.%d\n", | ||
1588 | (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK)); | ||
1589 | |||
1590 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x, | ||
1591 | da732x_dai, ARRAY_SIZE(da732x_dai)); | ||
1592 | if (ret != 0) | ||
1593 | dev_err(&i2c->dev, "Failed to register codec.\n"); | ||
1594 | |||
1595 | err: | ||
1596 | return ret; | ||
1597 | } | ||
1598 | |||
1599 | static __devexit int da732x_i2c_remove(struct i2c_client *client) | ||
1600 | { | ||
1601 | snd_soc_unregister_codec(&client->dev); | ||
1602 | |||
1603 | return 0; | ||
1604 | } | ||
1605 | |||
1606 | static const struct i2c_device_id da732x_i2c_id[] = { | ||
1607 | { "da7320", 0}, | ||
1608 | { } | ||
1609 | }; | ||
1610 | MODULE_DEVICE_TABLE(i2c, da732x_i2c_id); | ||
1611 | |||
1612 | static struct i2c_driver da732x_i2c_driver = { | ||
1613 | .driver = { | ||
1614 | .name = "da7320", | ||
1615 | .owner = THIS_MODULE, | ||
1616 | }, | ||
1617 | .probe = da732x_i2c_probe, | ||
1618 | .remove = __devexit_p(da732x_i2c_remove), | ||
1619 | .id_table = da732x_i2c_id, | ||
1620 | }; | ||
1621 | |||
1622 | module_i2c_driver(da732x_i2c_driver); | ||
1623 | |||
1624 | |||
1625 | MODULE_DESCRIPTION("ASoC DA732X driver"); | ||
1626 | MODULE_AUTHOR("Michal Hajduk <michal.hajduk@diasemi.com>"); | ||
1627 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h new file mode 100644 index 000000000000..c8ce5475de22 --- /dev/null +++ b/sound/soc/codecs/da732x.h | |||
@@ -0,0 +1,133 @@ | |||
1 | /* | ||
2 | * da732x.h -- Dialog DA732X ALSA SoC Audio Driver Header File | ||
3 | * | ||
4 | * Copyright (C) 2012 Dialog Semiconductor GmbH | ||
5 | * | ||
6 | * Author: Michal Hajduk <Michal.Hajduk@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __DA732X_H_ | ||
14 | #define __DA732X_H | ||
15 | |||
16 | #include <sound/soc.h> | ||
17 | |||
18 | /* General */ | ||
19 | #define DA732X_U8_MASK 0xFF | ||
20 | #define DA732X_4BYTES 4 | ||
21 | #define DA732X_3BYTES 3 | ||
22 | #define DA732X_2BYTES 2 | ||
23 | #define DA732X_1BYTE 1 | ||
24 | #define DA732X_1BYTE_SHIFT 8 | ||
25 | #define DA732X_2BYTES_SHIFT 16 | ||
26 | #define DA732X_3BYTES_SHIFT 24 | ||
27 | #define DA732X_4BYTES_SHIFT 32 | ||
28 | |||
29 | #define DA732X_DACS_DIS 0x0 | ||
30 | #define DA732X_HP_DIS 0x0 | ||
31 | #define DA732X_CLEAR_REG 0x0 | ||
32 | |||
33 | /* Calibration */ | ||
34 | #define DA732X_DAC_OFFSET_STEP 0x20 | ||
35 | #define DA732X_OUTPUT_OFFSET_STEP 0x80 | ||
36 | #define DA732X_HP_OUT_TRIM_VAL 0x0 | ||
37 | #define DA732X_WAIT_FOR_STABILIZATION 1 | ||
38 | #define DA732X_HPL_DAC 0 | ||
39 | #define DA732X_HPR_DAC 1 | ||
40 | #define DA732X_HP_DACS 2 | ||
41 | #define DA732X_HPL_AMP 0 | ||
42 | #define DA732X_HPR_AMP 1 | ||
43 | #define DA732X_HP_AMPS 2 | ||
44 | |||
45 | /* Clock settings */ | ||
46 | #define DA732X_STARTUP_DELAY 100 | ||
47 | #define DA732X_PLL_OUT_196608 196608000 | ||
48 | #define DA732X_PLL_OUT_180634 180633600 | ||
49 | #define DA732X_PLL_OUT_SRM 188620800 | ||
50 | #define DA732X_MCLK_10MHZ 10000000 | ||
51 | #define DA732X_MCLK_20MHZ 20000000 | ||
52 | #define DA732X_MCLK_40MHZ 40000000 | ||
53 | #define DA732X_MCLK_54MHZ 54000000 | ||
54 | #define DA732X_MCLK_RET_0_10MHZ 0 | ||
55 | #define DA732X_MCLK_VAL_0_10MHZ 1 | ||
56 | #define DA732X_MCLK_RET_10_20MHZ 1 | ||
57 | #define DA732X_MCLK_VAL_10_20MHZ 2 | ||
58 | #define DA732X_MCLK_RET_20_40MHZ 2 | ||
59 | #define DA732X_MCLK_VAL_20_40MHZ 4 | ||
60 | #define DA732X_MCLK_RET_40_54MHZ 3 | ||
61 | #define DA732X_MCLK_VAL_40_54MHZ 8 | ||
62 | #define DA732X_DAI_ID1 0 | ||
63 | #define DA732X_DAI_ID2 1 | ||
64 | #define DA732X_SRCCLK_PLL 0 | ||
65 | #define DA732X_SRCCLK_MCLK 1 | ||
66 | |||
67 | #define DA732X_LIN_LP_VOL 0x4F | ||
68 | #define DA732X_LP_VOL 0x40 | ||
69 | |||
70 | /* Kcontrols */ | ||
71 | #define DA732X_DAC_EN_MAX 2 | ||
72 | #define DA732X_ADCL_MUX_MAX 2 | ||
73 | #define DA732X_ADCR_MUX_MAX 3 | ||
74 | #define DA732X_HPF_MODE_MAX 3 | ||
75 | #define DA732X_HPF_MODE_SHIFT 4 | ||
76 | #define DA732X_HPF_MUSIC_SHIFT 0 | ||
77 | #define DA732X_HPF_MUSIC_MAX 4 | ||
78 | #define DA732X_HPF_VOICE_SHIFT 4 | ||
79 | #define DA732X_HPF_VOICE_MAX 8 | ||
80 | #define DA732X_EQ_EN_MAX 1 | ||
81 | #define DA732X_HPF_VOICE 1 | ||
82 | #define DA732X_HPF_MUSIC 2 | ||
83 | #define DA732X_HPF_DISABLED 0 | ||
84 | #define DA732X_NO_INVERT 0 | ||
85 | #define DA732X_INVERT 1 | ||
86 | #define DA732X_SWITCH_MAX 1 | ||
87 | #define DA732X_ENABLE_CP 1 | ||
88 | #define DA732X_DISABLE_CP 0 | ||
89 | #define DA732X_DISABLE_ALL_CLKS 0 | ||
90 | #define DA732X_RESET_ADCS 0 | ||
91 | |||
92 | /* dB values */ | ||
93 | #define DA732X_MIC_VOL_DB_MIN 0 | ||
94 | #define DA732X_MIC_VOL_DB_INC 50 | ||
95 | #define DA732X_MIC_PRE_VOL_DB_MIN 0 | ||
96 | #define DA732X_MIC_PRE_VOL_DB_INC 600 | ||
97 | #define DA732X_AUX_VOL_DB_MIN -6000 | ||
98 | #define DA732X_AUX_VOL_DB_INC 150 | ||
99 | #define DA732X_HP_VOL_DB_MIN -2250 | ||
100 | #define DA732X_HP_VOL_DB_INC 150 | ||
101 | #define DA732X_LIN2_VOL_DB_MIN -1650 | ||
102 | #define DA732X_LIN2_VOL_DB_INC 150 | ||
103 | #define DA732X_LIN3_VOL_DB_MIN -1650 | ||
104 | #define DA732X_LIN3_VOL_DB_INC 150 | ||
105 | #define DA732X_LIN4_VOL_DB_MIN -2250 | ||
106 | #define DA732X_LIN4_VOL_DB_INC 150 | ||
107 | #define DA732X_EQ_BAND_VOL_DB_MIN -1050 | ||
108 | #define DA732X_EQ_BAND_VOL_DB_INC 150 | ||
109 | #define DA732X_DAC_VOL_DB_MIN -7725 | ||
110 | #define DA732X_DAC_VOL_DB_INC 75 | ||
111 | #define DA732X_ADC_VOL_DB_MIN 0 | ||
112 | #define DA732X_ADC_VOL_DB_INC -1 | ||
113 | #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 | ||
114 | #define DA732X_EQ_OVERALL_VOL_DB_INC 600 | ||
115 | |||
116 | #define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ | ||
117 | {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} | ||
118 | |||
119 | enum da732x_sysctl { | ||
120 | DA732X_SR_8KHZ = 0x1, | ||
121 | DA732X_SR_11_025KHZ = 0x2, | ||
122 | DA732X_SR_12KHZ = 0x3, | ||
123 | DA732X_SR_16KHZ = 0x5, | ||
124 | DA732X_SR_22_05KHZ = 0x6, | ||
125 | DA732X_SR_24KHZ = 0x7, | ||
126 | DA732X_SR_32KHZ = 0x9, | ||
127 | DA732X_SR_44_1KHZ = 0xA, | ||
128 | DA732X_SR_48KHZ = 0xB, | ||
129 | DA732X_SR_88_1KHZ = 0xE, | ||
130 | DA732X_SR_96KHZ = 0xF, | ||
131 | }; | ||
132 | |||
133 | #endif /* __DA732X_H_ */ | ||
diff --git a/sound/soc/codecs/da732x_reg.h b/sound/soc/codecs/da732x_reg.h new file mode 100644 index 000000000000..bdd03ca4b2de --- /dev/null +++ b/sound/soc/codecs/da732x_reg.h | |||
@@ -0,0 +1,654 @@ | |||
1 | /* | ||
2 | * da732x_reg.h --- Dialog DA732X ALSA SoC Audio Registers Header File | ||
3 | * | ||
4 | * Copyright (C) 2012 Dialog Semiconductor GmbH | ||
5 | * | ||
6 | * Author: Michal Hajduk <Michal.Hajduk@diasemi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __DA732X_REG_H_ | ||
14 | #define __DA732X_REG_H_ | ||
15 | |||
16 | /* DA732X registers */ | ||
17 | #define DA732X_REG_STATUS_EXT 0x00 | ||
18 | #define DA732X_REG_STATUS 0x01 | ||
19 | #define DA732X_REG_REF1 0x02 | ||
20 | #define DA732X_REG_BIAS_EN 0x03 | ||
21 | #define DA732X_REG_BIAS1 0x04 | ||
22 | #define DA732X_REG_BIAS2 0x05 | ||
23 | #define DA732X_REG_BIAS3 0x06 | ||
24 | #define DA732X_REG_BIAS4 0x07 | ||
25 | #define DA732X_REG_MICBIAS2 0x0F | ||
26 | #define DA732X_REG_MICBIAS1 0x10 | ||
27 | #define DA732X_REG_MICDET 0x11 | ||
28 | #define DA732X_REG_MIC1_PRE 0x12 | ||
29 | #define DA732X_REG_MIC1 0x13 | ||
30 | #define DA732X_REG_MIC2_PRE 0x14 | ||
31 | #define DA732X_REG_MIC2 0x15 | ||
32 | #define DA732X_REG_AUX1L 0x16 | ||
33 | #define DA732X_REG_AUX1R 0x17 | ||
34 | #define DA732X_REG_MIC3_PRE 0x18 | ||
35 | #define DA732X_REG_MIC3 0x19 | ||
36 | #define DA732X_REG_INP_PINBIAS 0x1A | ||
37 | #define DA732X_REG_INP_ZC_EN 0x1B | ||
38 | #define DA732X_REG_INP_MUX 0x1D | ||
39 | #define DA732X_REG_HP_DET 0x20 | ||
40 | #define DA732X_REG_HPL_DAC_OFFSET 0x21 | ||
41 | #define DA732X_REG_HPL_DAC_OFF_CNTL 0x22 | ||
42 | #define DA732X_REG_HPL_OUT_OFFSET 0x23 | ||
43 | #define DA732X_REG_HPL 0x24 | ||
44 | #define DA732X_REG_HPL_VOL 0x25 | ||
45 | #define DA732X_REG_HPR_DAC_OFFSET 0x26 | ||
46 | #define DA732X_REG_HPR_DAC_OFF_CNTL 0x27 | ||
47 | #define DA732X_REG_HPR_OUT_OFFSET 0x28 | ||
48 | #define DA732X_REG_HPR 0x29 | ||
49 | #define DA732X_REG_HPR_VOL 0x2A | ||
50 | #define DA732X_REG_LIN2 0x2B | ||
51 | #define DA732X_REG_LIN3 0x2C | ||
52 | #define DA732X_REG_LIN4 0x2D | ||
53 | #define DA732X_REG_OUT_ZC_EN 0x2E | ||
54 | #define DA732X_REG_HP_LIN1_GNDSEL 0x37 | ||
55 | #define DA732X_REG_CP_HP1 0x3A | ||
56 | #define DA732X_REG_CP_HP2 0x3B | ||
57 | #define DA732X_REG_CP_CTRL1 0x40 | ||
58 | #define DA732X_REG_CP_CTRL2 0x41 | ||
59 | #define DA732X_REG_CP_CTRL3 0x42 | ||
60 | #define DA732X_REG_CP_LEVEL_MASK 0x43 | ||
61 | #define DA732X_REG_CP_DET 0x44 | ||
62 | #define DA732X_REG_CP_STATUS 0x45 | ||
63 | #define DA732X_REG_CP_THRESH1 0x46 | ||
64 | #define DA732X_REG_CP_THRESH2 0x47 | ||
65 | #define DA732X_REG_CP_THRESH3 0x48 | ||
66 | #define DA732X_REG_CP_THRESH4 0x49 | ||
67 | #define DA732X_REG_CP_THRESH5 0x4A | ||
68 | #define DA732X_REG_CP_THRESH6 0x4B | ||
69 | #define DA732X_REG_CP_THRESH7 0x4C | ||
70 | #define DA732X_REG_CP_THRESH8 0x4D | ||
71 | #define DA732X_REG_PLL_DIV_LO 0x50 | ||
72 | #define DA732X_REG_PLL_DIV_MID 0x51 | ||
73 | #define DA732X_REG_PLL_DIV_HI 0x52 | ||
74 | #define DA732X_REG_PLL_CTRL 0x53 | ||
75 | #define DA732X_REG_CLK_CTRL 0x54 | ||
76 | #define DA732X_REG_CLK_DSP 0x5A | ||
77 | #define DA732X_REG_CLK_EN1 0x5B | ||
78 | #define DA732X_REG_CLK_EN2 0x5C | ||
79 | #define DA732X_REG_CLK_EN3 0x5D | ||
80 | #define DA732X_REG_CLK_EN4 0x5E | ||
81 | #define DA732X_REG_CLK_EN5 0x5F | ||
82 | #define DA732X_REG_AIF_MCLK 0x60 | ||
83 | #define DA732X_REG_AIFA1 0x61 | ||
84 | #define DA732X_REG_AIFA2 0x62 | ||
85 | #define DA732X_REG_AIFA3 0x63 | ||
86 | #define DA732X_REG_AIFB1 0x64 | ||
87 | #define DA732X_REG_AIFB2 0x65 | ||
88 | #define DA732X_REG_AIFB3 0x66 | ||
89 | #define DA732X_REG_PC_CTRL 0x6A | ||
90 | #define DA732X_REG_DATA_ROUTE 0x70 | ||
91 | #define DA732X_REG_DSP_CTRL 0x71 | ||
92 | #define DA732X_REG_CIF_CTRL2 0x74 | ||
93 | #define DA732X_REG_HANDSHAKE 0x75 | ||
94 | #define DA732X_REG_MBOX0 0x76 | ||
95 | #define DA732X_REG_MBOX1 0x77 | ||
96 | #define DA732X_REG_MBOX2 0x78 | ||
97 | #define DA732X_REG_MBOX_STATUS 0x79 | ||
98 | #define DA732X_REG_SPARE1_OUT 0x7D | ||
99 | #define DA732X_REG_SPARE2_OUT 0x7E | ||
100 | #define DA732X_REG_SPARE1_IN 0x7F | ||
101 | #define DA732X_REG_ID 0x81 | ||
102 | #define DA732X_REG_ADC1_PD 0x90 | ||
103 | #define DA732X_REG_ADC1_HPF 0x93 | ||
104 | #define DA732X_REG_ADC1_SEL 0x94 | ||
105 | #define DA732X_REG_ADC1_EQ12 0x95 | ||
106 | #define DA732X_REG_ADC1_EQ34 0x96 | ||
107 | #define DA732X_REG_ADC1_EQ5 0x97 | ||
108 | #define DA732X_REG_ADC2_PD 0x98 | ||
109 | #define DA732X_REG_ADC2_HPF 0x9B | ||
110 | #define DA732X_REG_ADC2_SEL 0x9C | ||
111 | #define DA732X_REG_ADC2_EQ12 0x9D | ||
112 | #define DA732X_REG_ADC2_EQ34 0x9E | ||
113 | #define DA732X_REG_ADC2_EQ5 0x9F | ||
114 | #define DA732X_REG_DAC1_HPF 0xA0 | ||
115 | #define DA732X_REG_DAC1_L_VOL 0xA1 | ||
116 | #define DA732X_REG_DAC1_R_VOL 0xA2 | ||
117 | #define DA732X_REG_DAC1_SEL 0xA3 | ||
118 | #define DA732X_REG_DAC1_SOFTMUTE 0xA4 | ||
119 | #define DA732X_REG_DAC1_EQ12 0xA5 | ||
120 | #define DA732X_REG_DAC1_EQ34 0xA6 | ||
121 | #define DA732X_REG_DAC1_EQ5 0xA7 | ||
122 | #define DA732X_REG_DAC2_HPF 0xB0 | ||
123 | #define DA732X_REG_DAC2_L_VOL 0xB1 | ||
124 | #define DA732X_REG_DAC2_R_VOL 0xB2 | ||
125 | #define DA732X_REG_DAC2_SEL 0xB3 | ||
126 | #define DA732X_REG_DAC2_SOFTMUTE 0xB4 | ||
127 | #define DA732X_REG_DAC2_EQ12 0xB5 | ||
128 | #define DA732X_REG_DAC2_EQ34 0xB6 | ||
129 | #define DA732X_REG_DAC2_EQ5 0xB7 | ||
130 | #define DA732X_REG_DAC3_HPF 0xC0 | ||
131 | #define DA732X_REG_DAC3_VOL 0xC1 | ||
132 | #define DA732X_REG_DAC3_SEL 0xC3 | ||
133 | #define DA732X_REG_DAC3_SOFTMUTE 0xC4 | ||
134 | #define DA732X_REG_DAC3_EQ12 0xC5 | ||
135 | #define DA732X_REG_DAC3_EQ34 0xC6 | ||
136 | #define DA732X_REG_DAC3_EQ5 0xC7 | ||
137 | #define DA732X_REG_BIQ_BYP 0xD2 | ||
138 | #define DA732X_REG_DMA_CMD 0xD3 | ||
139 | #define DA732X_REG_DMA_ADDR0 0xD4 | ||
140 | #define DA732X_REG_DMA_ADDR1 0xD5 | ||
141 | #define DA732X_REG_DMA_DATA0 0xD6 | ||
142 | #define DA732X_REG_DMA_DATA1 0xD7 | ||
143 | #define DA732X_REG_DMA_DATA2 0xD8 | ||
144 | #define DA732X_REG_DMA_DATA3 0xD9 | ||
145 | #define DA732X_REG_DMA_STATUS 0xDA | ||
146 | #define DA732X_REG_BROWNOUT 0xDF | ||
147 | #define DA732X_REG_UNLOCK 0xE0 | ||
148 | |||
149 | #define DA732X_MAX_REG DA732X_REG_UNLOCK | ||
150 | /* | ||
151 | * Bits | ||
152 | */ | ||
153 | |||
154 | /* DA732X_REG_STATUS_EXT (addr=0x00) */ | ||
155 | #define DA732X_STATUS_EXT_DSP (1 << 4) | ||
156 | #define DA732X_STATUS_EXT_CLEAR (0 << 0) | ||
157 | |||
158 | /* DA732X_REG_STATUS (addr=0x01) */ | ||
159 | #define DA732X_STATUS_PLL_LOCK (1 << 0) | ||
160 | #define DA732X_STATUS_PLL_MCLK_DET (1 << 1) | ||
161 | #define DA732X_STATUS_HPDET_OUT (1 << 2) | ||
162 | #define DA732X_STATUS_INP_MIXDET_1 (1 << 3) | ||
163 | #define DA732X_STATUS_INP_MIXDET_2 (1 << 4) | ||
164 | #define DA732X_STATUS_BO_STATUS (1 << 5) | ||
165 | |||
166 | /* DA732X_REG_REF1 (addr=0x02) */ | ||
167 | #define DA732X_VMID_FASTCHG (1 << 1) | ||
168 | #define DA732X_VMID_FASTDISCHG (1 << 2) | ||
169 | #define DA732X_REFBUFX2_EN (1 << 6) | ||
170 | #define DA732X_REFBUFX2_DIS (0 << 6) | ||
171 | |||
172 | /* DA732X_REG_BIAS_EN (addr=0x03) */ | ||
173 | #define DA732X_BIAS_BOOST_MASK (3 << 0) | ||
174 | #define DA732X_BIAS_BOOST_100PC (0 << 0) | ||
175 | #define DA732X_BIAS_BOOST_133PC (1 << 0) | ||
176 | #define DA732X_BIAS_BOOST_88PC (2 << 0) | ||
177 | #define DA732X_BIAS_BOOST_50PC (3 << 0) | ||
178 | #define DA732X_BIAS_EN (1 << 7) | ||
179 | #define DA732X_BIAS_DIS (0 << 7) | ||
180 | |||
181 | /* DA732X_REG_BIAS1 (addr=0x04) */ | ||
182 | #define DA732X_BIAS1_HP_DAC_BIAS_MASK (3 << 0) | ||
183 | #define DA732X_BIAS1_HP_DAC_BIAS_100PC (0 << 0) | ||
184 | #define DA732X_BIAS1_HP_DAC_BIAS_150PC (1 << 0) | ||
185 | #define DA732X_BIAS1_HP_DAC_BIAS_50PC (2 << 0) | ||
186 | #define DA732X_BIAS1_HP_DAC_BIAS_75PC (3 << 0) | ||
187 | #define DA732X_BIAS1_HP_OUT_BIAS_MASK (7 << 4) | ||
188 | #define DA732X_BIAS1_HP_OUT_BIAS_100PC (0 << 4) | ||
189 | #define DA732X_BIAS1_HP_OUT_BIAS_125PC (1 << 4) | ||
190 | #define DA732X_BIAS1_HP_OUT_BIAS_150PC (2 << 4) | ||
191 | #define DA732X_BIAS1_HP_OUT_BIAS_175PC (3 << 4) | ||
192 | #define DA732X_BIAS1_HP_OUT_BIAS_200PC (4 << 4) | ||
193 | #define DA732X_BIAS1_HP_OUT_BIAS_250PC (5 << 4) | ||
194 | #define DA732X_BIAS1_HP_OUT_BIAS_300PC (6 << 4) | ||
195 | #define DA732X_BIAS1_HP_OUT_BIAS_350PC (7 << 4) | ||
196 | |||
197 | /* DA732X_REG_BIAS2 (addr=0x05) */ | ||
198 | #define DA732X_BIAS2_LINE2_DAC_BIAS_MASK (3 << 0) | ||
199 | #define DA732X_BIAS2_LINE2_DAC_BIAS_100PC (0 << 0) | ||
200 | #define DA732X_BIAS2_LINE2_DAC_BIAS_150PC (1 << 0) | ||
201 | #define DA732X_BIAS2_LINE2_DAC_BIAS_50PC (2 << 0) | ||
202 | #define DA732X_BIAS2_LINE2_DAC_BIAS_75PC (3 << 0) | ||
203 | #define DA732X_BIAS2_LINE2_OUT_BIAS_MASK (7 << 4) | ||
204 | #define DA732X_BIAS2_LINE2_OUT_BIAS_100PC (0 << 4) | ||
205 | #define DA732X_BIAS2_LINE2_OUT_BIAS_125PC (1 << 4) | ||
206 | #define DA732X_BIAS2_LINE2_OUT_BIAS_150PC (2 << 4) | ||
207 | #define DA732X_BIAS2_LINE2_OUT_BIAS_175PC (3 << 4) | ||
208 | #define DA732X_BIAS2_LINE2_OUT_BIAS_200PC (4 << 4) | ||
209 | #define DA732X_BIAS2_LINE2_OUT_BIAS_250PC (5 << 4) | ||
210 | #define DA732X_BIAS2_LINE2_OUT_BIAS_300PC (6 << 4) | ||
211 | #define DA732X_BIAS2_LINE2_OUT_BIAS_350PC (7 << 4) | ||
212 | |||
213 | /* DA732X_REG_BIAS3 (addr=0x06) */ | ||
214 | #define DA732X_BIAS3_LINE3_DAC_BIAS_MASK (3 << 0) | ||
215 | #define DA732X_BIAS3_LINE3_DAC_BIAS_100PC (0 << 0) | ||
216 | #define DA732X_BIAS3_LINE3_DAC_BIAS_150PC (1 << 0) | ||
217 | #define DA732X_BIAS3_LINE3_DAC_BIAS_50PC (2 << 0) | ||
218 | #define DA732X_BIAS3_LINE3_DAC_BIAS_75PC (3 << 0) | ||
219 | #define DA732X_BIAS3_LINE3_OUT_BIAS_MASK (7 << 4) | ||
220 | #define DA732X_BIAS3_LINE3_OUT_BIAS_100PC (0 << 4) | ||
221 | #define DA732X_BIAS3_LINE3_OUT_BIAS_125PC (1 << 4) | ||
222 | #define DA732X_BIAS3_LINE3_OUT_BIAS_150PC (2 << 4) | ||
223 | #define DA732X_BIAS3_LINE3_OUT_BIAS_175PC (3 << 4) | ||
224 | #define DA732X_BIAS3_LINE3_OUT_BIAS_200PC (4 << 4) | ||
225 | #define DA732X_BIAS3_LINE3_OUT_BIAS_250PC (5 << 4) | ||
226 | #define DA732X_BIAS3_LINE3_OUT_BIAS_300PC (6 << 4) | ||
227 | #define DA732X_BIAS3_LINE3_OUT_BIAS_350PC (7 << 4) | ||
228 | |||
229 | /* DA732X_REG_BIAS4 (addr=0x07) */ | ||
230 | #define DA732X_BIAS4_LINE4_DAC_BIAS_MASK (3 << 0) | ||
231 | #define DA732X_BIAS4_LINE4_DAC_BIAS_100PC (0 << 0) | ||
232 | #define DA732X_BIAS4_LINE4_DAC_BIAS_150PC (1 << 0) | ||
233 | #define DA732X_BIAS4_LINE4_DAC_BIAS_50PC (2 << 0) | ||
234 | #define DA732X_BIAS4_LINE4_DAC_BIAS_75PC (3 << 0) | ||
235 | #define DA732X_BIAS4_LINE4_OUT_BIAS_MASK (7 << 4) | ||
236 | #define DA732X_BIAS4_LINE4_OUT_BIAS_100PC (0 << 4) | ||
237 | #define DA732X_BIAS4_LINE4_OUT_BIAS_125PC (1 << 4) | ||
238 | #define DA732X_BIAS4_LINE4_OUT_BIAS_150PC (2 << 4) | ||
239 | #define DA732X_BIAS4_LINE4_OUT_BIAS_175PC (3 << 4) | ||
240 | #define DA732X_BIAS4_LINE4_OUT_BIAS_200PC (4 << 4) | ||
241 | #define DA732X_BIAS4_LINE4_OUT_BIAS_250PC (5 << 4) | ||
242 | #define DA732X_BIAS4_LINE4_OUT_BIAS_300PC (6 << 4) | ||
243 | #define DA732X_BIAS4_LINE4_OUT_BIAS_350PC (7 << 4) | ||
244 | |||
245 | /* DA732X_REG_SIF_VDD_SEL (addr=0x08) */ | ||
246 | #define DA732X_SIF_VDD_SEL_AIFA_VDD2 (1 << 0) | ||
247 | #define DA732X_SIF_VDD_SEL_AIFB_VDD2 (1 << 1) | ||
248 | #define DA732X_SIF_VDD_SEL_CIFA_VDD2 (1 << 4) | ||
249 | |||
250 | /* DA732X_REG_MICBIAS2/1 (addr=0x0F/0x10) */ | ||
251 | #define DA732X_MICBIAS_VOLTAGE_MASK (0x0F << 0) | ||
252 | #define DA732X_MICBIAS_VOLTAGE_2V (0x00 << 0) | ||
253 | #define DA732X_MICBIAS_VOLTAGE_2V05 (0x01 << 0) | ||
254 | #define DA732X_MICBIAS_VOLTAGE_2V1 (0x02 << 0) | ||
255 | #define DA732X_MICBIAS_VOLTAGE_2V15 (0x03 << 0) | ||
256 | #define DA732X_MICBIAS_VOLTAGE_2V2 (0x04 << 0) | ||
257 | #define DA732X_MICBIAS_VOLTAGE_2V25 (0x05 << 0) | ||
258 | #define DA732X_MICBIAS_VOLTAGE_2V3 (0x06 << 0) | ||
259 | #define DA732X_MICBIAS_VOLTAGE_2V35 (0x07 << 0) | ||
260 | #define DA732X_MICBIAS_VOLTAGE_2V4 (0x08 << 0) | ||
261 | #define DA732X_MICBIAS_VOLTAGE_2V45 (0x09 << 0) | ||
262 | #define DA732X_MICBIAS_VOLTAGE_2V5 (0x0A << 0) | ||
263 | #define DA732X_MICBIAS_EN (1 << 7) | ||
264 | #define DA732X_MICBIAS_EN_SHIFT 7 | ||
265 | #define DA732X_MICBIAS_VOLTAGE_SHIFT 0 | ||
266 | #define DA732X_MICBIAS_VOLTAGE_MAX 0x0B | ||
267 | |||
268 | /* DA732X_REG_MICDET (addr=0x11) */ | ||
269 | #define DA732X_MICDET_INP_MICRES (1 << 0) | ||
270 | #define DA732X_MICDET_INP_MICHOOK (1 << 1) | ||
271 | #define DA732X_MICDET_INP_DEBOUNCE_PRD_8MS (0 << 0) | ||
272 | #define DA732X_MICDET_INP_DEBOUNCE_PRD_16MS (1 << 0) | ||
273 | #define DA732X_MICDET_INP_DEBOUNCE_PRD_32MS (2 << 0) | ||
274 | #define DA732X_MICDET_INP_DEBOUNCE_PRD_64MS (3 << 0) | ||
275 | #define DA732X_MICDET_INP_MICDET_EN (1 << 7) | ||
276 | |||
277 | /* DA732X_REG_MIC1/2/3_PRE (addr=0x11/0x14/0x18) */ | ||
278 | #define DA732X_MICBOOST_MASK 0x7 | ||
279 | #define DA732X_MICBOOST_SHIFT 0 | ||
280 | #define DA732X_MICBOOST_MIN 0x1 | ||
281 | #define DA732X_MICBOOST_MAX DA732X_MICBOOST_MASK | ||
282 | |||
283 | /* DA732X_REG_MIC1/2/3 (addr=0x13/0x15/0x19) */ | ||
284 | #define DA732X_MIC_VOL_SHIFT 0 | ||
285 | #define DA732X_MIC_VOL_VAL_MASK 0x1F | ||
286 | #define DA732X_MIC_MUTE_SHIFT 6 | ||
287 | #define DA732X_MIC_EN_SHIFT 7 | ||
288 | #define DA732X_MIC_VOL_VAL_MIN 0x7 | ||
289 | #define DA732X_MIC_VOL_VAL_MAX DA732X_MIC_VOL_VAL_MASK | ||
290 | |||
291 | /* DA732X_REG_AUX1L/R (addr=0x16/0x17) */ | ||
292 | #define DA732X_AUX_VOL_SHIFT 0 | ||
293 | #define DA732X_AUX_VOL_MASK 0x7 | ||
294 | #define DA732X_AUX_MUTE_SHIFT 6 | ||
295 | #define DA732X_AUX_EN_SHIFT 7 | ||
296 | #define DA732X_AUX_VOL_VAL_MAX DA732X_AUX_VOL_MASK | ||
297 | |||
298 | /* DA732X_REG_INP_PINBIAS (addr=0x1A) */ | ||
299 | #define DA732X_INP_MICL_PINBIAS_EN (1 << 0) | ||
300 | #define DA732X_INP_MICR_PINBIAS_EN (1 << 1) | ||
301 | #define DA732X_INP_AUX1L_PINBIAS_EN (1 << 2) | ||
302 | #define DA732X_INP_AUX1R_PINBIAS_EN (1 << 3) | ||
303 | #define DA732X_INP_AUX2_PINBIAS_EN (1 << 4) | ||
304 | |||
305 | /* DA732X_REG_INP_ZC_EN (addr=0x1B) */ | ||
306 | #define DA732X_MIC1_PRE_ZC_EN (1 << 0) | ||
307 | #define DA732X_MIC1_ZC_EN (1 << 1) | ||
308 | #define DA732X_MIC2_PRE_ZC_EN (1 << 2) | ||
309 | #define DA732X_MIC2_ZC_EN (1 << 3) | ||
310 | #define DA732X_AUXL_ZC_EN (1 << 4) | ||
311 | #define DA732X_AUXR_ZC_EN (1 << 5) | ||
312 | #define DA732X_MIC3_PRE_ZC_EN (1 << 6) | ||
313 | #define DA732X_MIC3_ZC_EN (1 << 7) | ||
314 | |||
315 | /* DA732X_REG_INP_MUX (addr=0x1D) */ | ||
316 | #define DA732X_INP_ADC1L_MUX_SEL_AUX1L (0 << 0) | ||
317 | #define DA732X_INP_ADC1L_MUX_SEL_MIC1 (1 << 0) | ||
318 | #define DA732X_INP_ADC1R_MUX_SEL_MASK (3 << 2) | ||
319 | #define DA732X_INP_ADC1R_MUX_SEL_AUX1R (0 << 2) | ||
320 | #define DA732X_INP_ADC1R_MUX_SEL_MIC2 (1 << 2) | ||
321 | #define DA732X_INP_ADC1R_MUX_SEL_MIC3 (2 << 2) | ||
322 | #define DA732X_INP_ADC2L_MUX_SEL_AUX1L (0 << 4) | ||
323 | #define DA732X_INP_ADC2L_MUX_SEL_MICL (1 << 4) | ||
324 | #define DA732X_INP_ADC2R_MUX_SEL_MASK (3 << 6) | ||
325 | #define DA732X_INP_ADC2R_MUX_SEL_AUX1R (0 << 6) | ||
326 | #define DA732X_INP_ADC2R_MUX_SEL_MICR (1 << 6) | ||
327 | #define DA732X_INP_ADC2R_MUX_SEL_AUX2 (2 << 6) | ||
328 | #define DA732X_ADC1L_MUX_SEL_SHIFT 0 | ||
329 | #define DA732X_ADC1R_MUX_SEL_SHIFT 2 | ||
330 | #define DA732X_ADC2L_MUX_SEL_SHIFT 4 | ||
331 | #define DA732X_ADC2R_MUX_SEL_SHIFT 6 | ||
332 | |||
333 | /* DA732X_REG_HP_DET (addr=0x20) */ | ||
334 | #define DA732X_HP_DET_AZ (1 << 0) | ||
335 | #define DA732X_HP_DET_SEL1 (1 << 1) | ||
336 | #define DA732X_HP_DET_IS_MASK (3 << 2) | ||
337 | #define DA732X_HP_DET_IS_0_5UA (0 << 2) | ||
338 | #define DA732X_HP_DET_IS_1UA (1 << 2) | ||
339 | #define DA732X_HP_DET_IS_2UA (2 << 2) | ||
340 | #define DA732X_HP_DET_IS_4UA (3 << 2) | ||
341 | #define DA732X_HP_DET_RS_MASK (3 << 4) | ||
342 | #define DA732X_HP_DET_RS_INFINITE (0 << 4) | ||
343 | #define DA732X_HP_DET_RS_100KOHM (1 << 4) | ||
344 | #define DA732X_HP_DET_RS_10KOHM (2 << 4) | ||
345 | #define DA732X_HP_DET_RS_1KOHM (3 << 4) | ||
346 | #define DA732X_HP_DET_EN (1 << 7) | ||
347 | |||
348 | /* DA732X_REG_HPL_DAC_OFFSET (addr=0x21/0x26) */ | ||
349 | #define DA732X_HP_DAC_OFFSET_TRIM_MASK (0x3F << 0) | ||
350 | #define DA732X_HP_DAC_OFFSET_DAC_SIGN (1 << 6) | ||
351 | |||
352 | /* DA732X_REG_HPL_DAC_OFF_CNTL (addr=0x22/0x27) */ | ||
353 | #define DA732X_HP_DAC_OFF_CNTL_CONT_MASK (7 << 0) | ||
354 | #define DA732X_HP_DAC_OFF_CNTL_COMPO (1 << 3) | ||
355 | #define DA732X_HP_DAC_OFF_CALIBRATION (1 << 0) | ||
356 | #define DA732X_HP_DAC_OFF_SCALE_STEPS (1 << 1) | ||
357 | #define DA732X_HP_DAC_OFF_MASK 0x7F | ||
358 | #define DA732X_HP_DAC_COMPO_SHIFT 3 | ||
359 | |||
360 | /* DA732X_REG_HPL_OUT_OFFSET (addr=0x23/0x28) */ | ||
361 | #define DA732X_HP_OUT_OFFSET_MASK (0xFF << 0) | ||
362 | #define DA732X_HP_DAC_OFFSET_TRIM_VAL 0x7F | ||
363 | |||
364 | /* DA732X_REG_HPL/R (addr=0x24/0x29) */ | ||
365 | #define DA732X_HP_OUT_SIGN (1 << 0) | ||
366 | #define DA732X_HP_OUT_COMP (1 << 1) | ||
367 | #define DA732X_HP_OUT_RESERVED (1 << 2) | ||
368 | #define DA732X_HP_OUT_COMPO (1 << 3) | ||
369 | #define DA732X_HP_OUT_DAC_EN (1 << 4) | ||
370 | #define DA732X_HP_OUT_HIZ_EN (1 << 5) | ||
371 | #define DA732X_HP_OUT_HIZ_DIS (0 << 5) | ||
372 | #define DA732X_HP_OUT_MUTE (1 << 6) | ||
373 | #define DA732X_HP_OUT_EN (1 << 7) | ||
374 | #define DA732X_HP_OUT_COMPO_SHIFT 3 | ||
375 | #define DA732X_HP_OUT_DAC_EN_SHIFT 4 | ||
376 | #define DA732X_HP_HIZ_SHIFT 5 | ||
377 | #define DA732X_HP_MUTE_SHIFT 6 | ||
378 | #define DA732X_HP_OUT_EN_SHIFT 7 | ||
379 | |||
380 | #define DA732X_OUT_HIZ_EN (1 << 5) | ||
381 | #define DA732X_OUT_HIZ_DIS (0 << 5) | ||
382 | |||
383 | /* DA732X_REG_HPL/R_VOL (addr=0x25/0x2A) */ | ||
384 | #define DA732X_HP_VOL_VAL_MASK 0xF | ||
385 | #define DA732X_HP_VOL_SHIFT 0 | ||
386 | #define DA732X_HP_VOL_VAL_MAX DA732X_HP_VOL_VAL_MASK | ||
387 | |||
388 | /* DA732X_REG_LIN2/3/4 (addr=0x2B/0x2C/0x2D) */ | ||
389 | #define DA732X_LOUT_VOL_SHIFT 0 | ||
390 | #define DA732X_LOUT_VOL_MASK 0x0F | ||
391 | #define DA732X_LOUT_DAC_OFF (0 << 4) | ||
392 | #define DA732X_LOUT_DAC_EN (1 << 4) | ||
393 | #define DA732X_LOUT_HIZ_N_DIS (0 << 5) | ||
394 | #define DA732X_LOUT_HIZ_N_EN (1 << 5) | ||
395 | #define DA732X_LOUT_UNMUTED (0 << 6) | ||
396 | #define DA732X_LOUT_MUTED (1 << 6) | ||
397 | #define DA732X_LOUT_EN (0 << 7) | ||
398 | #define DA732X_LOUT_DIS (1 << 7) | ||
399 | #define DA732X_LOUT_DAC_EN_SHIFT 4 | ||
400 | #define DA732X_LOUT_MUTE_SHIFT 6 | ||
401 | #define DA732X_LIN_OUT_EN_SHIFT 7 | ||
402 | #define DA732X_LOUT_VOL_VAL_MAX DA732X_LOUT_VOL_MASK | ||
403 | |||
404 | /* DA732X_REG_OUT_ZC_EN (addr=0x2E) */ | ||
405 | #define DA732X_HPL_ZC_EN_SHIFT 0 | ||
406 | #define DA732X_HPR_ZC_EN_SHIFT 1 | ||
407 | #define DA732X_HPL_ZC_EN (1 << 0) | ||
408 | #define DA732X_HPL_ZC_DIS (0 << 0) | ||
409 | #define DA732X_HPR_ZC_EN (1 << 1) | ||
410 | #define DA732X_HPR_ZC_DIS (0 << 1) | ||
411 | #define DA732X_LIN2_ZC_EN (1 << 2) | ||
412 | #define DA732X_LIN2_ZC_DIS (0 << 2) | ||
413 | #define DA732X_LIN3_ZC_EN (1 << 3) | ||
414 | #define DA732X_LIN3_ZC_DIS (0 << 3) | ||
415 | #define DA732X_LIN4_ZC_EN (1 << 4) | ||
416 | #define DA732X_LIN4_ZC_DIS (0 << 4) | ||
417 | |||
418 | /* DA732X_REG_HP_LIN1_GNDSEL (addr=0x37) */ | ||
419 | #define DA732X_HP_OUT_GNDSEL (1 << 0) | ||
420 | |||
421 | /* DA732X_REG_CP_HP2 (addr=0x3a) */ | ||
422 | #define DA732X_HP_CP_PULSESKIP (1 << 0) | ||
423 | #define DA732X_HP_CP_REG (1 << 1) | ||
424 | #define DA732X_HP_CP_EN (1 << 3) | ||
425 | #define DA732X_HP_CP_DIS (0 << 3) | ||
426 | |||
427 | /* DA732X_REG_CP_CTRL1 (addr=0x40) */ | ||
428 | #define DA732X_CP_MODE_MASK (7 << 1) | ||
429 | #define DA732X_CP_CTRL_STANDBY (0 << 1) | ||
430 | #define DA732X_CP_CTRL_CPVDD6 (2 << 1) | ||
431 | #define DA732X_CP_CTRL_CPVDD5 (3 << 1) | ||
432 | #define DA732X_CP_CTRL_CPVDD4 (4 << 1) | ||
433 | #define DA732X_CP_CTRL_CPVDD3 (5 << 1) | ||
434 | #define DA732X_CP_CTRL_CPVDD2 (6 << 1) | ||
435 | #define DA732X_CP_CTRL_CPVDD1 (7 << 1) | ||
436 | #define DA723X_CP_DIS (0 << 7) | ||
437 | #define DA732X_CP_EN (1 << 7) | ||
438 | |||
439 | /* DA732X_REG_CP_CTRL2 (addr=0x41) */ | ||
440 | #define DA732X_CP_BOOST (1 << 0) | ||
441 | #define DA732X_CP_MANAGE_MAGNITUDE (2 << 2) | ||
442 | |||
443 | /* DA732X_REG_CP_CTRL3 (addr=0x42) */ | ||
444 | #define DA732X_CP_1MHZ (0 << 0) | ||
445 | #define DA732X_CP_500KHZ (1 << 0) | ||
446 | #define DA732X_CP_250KHZ (2 << 0) | ||
447 | #define DA732X_CP_125KHZ (3 << 0) | ||
448 | #define DA732X_CP_63KHZ (4 << 0) | ||
449 | #define DA732X_CP_0KHZ (5 << 0) | ||
450 | |||
451 | /* DA732X_REG_PLL_CTRL (addr=0x53) */ | ||
452 | #define DA732X_PLL_INDIV_MASK (3 << 0) | ||
453 | #define DA732X_PLL_SRM_EN (1 << 2) | ||
454 | #define DA732X_PLL_EN (1 << 7) | ||
455 | #define DA732X_PLL_BYPASS (0 << 0) | ||
456 | |||
457 | /* DA732X_REG_CLK_CTRL (addr=0x54) */ | ||
458 | #define DA732X_SR1_MASK (0xF) | ||
459 | #define DA732X_SR2_MASK (0xF0) | ||
460 | |||
461 | /* DA732X_REG_CLK_DSP (addr=0x5A) */ | ||
462 | #define DA732X_DSP_FREQ_MASK (7 << 0) | ||
463 | #define DA732X_DSP_FREQ_12MHZ (0 << 0) | ||
464 | #define DA732X_DSP_FREQ_24MHZ (1 << 0) | ||
465 | #define DA732X_DSP_FREQ_36MHZ (2 << 0) | ||
466 | #define DA732X_DSP_FREQ_48MHZ (3 << 0) | ||
467 | #define DA732X_DSP_FREQ_60MHZ (4 << 0) | ||
468 | #define DA732X_DSP_FREQ_72MHZ (5 << 0) | ||
469 | #define DA732X_DSP_FREQ_84MHZ (6 << 0) | ||
470 | #define DA732X_DSP_FREQ_96MHZ (7 << 0) | ||
471 | |||
472 | /* DA732X_REG_CLK_EN1 (addr=0x5B) */ | ||
473 | #define DA732X_DSP_CLK_EN (1 << 0) | ||
474 | #define DA732X_SYS3_CLK_EN (1 << 1) | ||
475 | #define DA732X_DSP12_CLK_EN (1 << 2) | ||
476 | #define DA732X_PC_CLK_EN (1 << 3) | ||
477 | #define DA732X_MCLK_SQR_EN (1 << 7) | ||
478 | |||
479 | /* DA732X_REG_CLK_EN2 (addr=0x5C) */ | ||
480 | #define DA732X_UART_CLK_EN (1 << 1) | ||
481 | #define DA732X_CP_CLK_EN (1 << 2) | ||
482 | #define DA732X_CP_CLK_DIS (0 << 2) | ||
483 | |||
484 | /* DA732X_REG_CLK_EN3 (addr=0x5D) */ | ||
485 | #define DA732X_ADCA_BB_CLK_EN (1 << 0) | ||
486 | #define DA732X_ADCC_BB_CLK_EN (1 << 4) | ||
487 | |||
488 | /* DA732X_REG_CLK_EN4 (addr=0x5E) */ | ||
489 | #define DA732X_DACA_BB_CLK_EN (1 << 0) | ||
490 | #define DA732X_DACC_BB_CLK_EN (1 << 4) | ||
491 | #define DA732X_DACA_BB_CLK_SHIFT 0 | ||
492 | #define DA732X_DACC_BB_CLK_SHIFT 4 | ||
493 | |||
494 | /* DA732X_REG_CLK_EN5 (addr=0x5F) */ | ||
495 | #define DA732X_DACE_BB_CLK_EN (1 << 0) | ||
496 | #define DA732X_DACE_BB_CLK_SHIFT 0 | ||
497 | |||
498 | /* DA732X_REG_AIF_MCLK (addr=0x60) */ | ||
499 | #define DA732X_AIFM_FRAME_64 (1 << 2) | ||
500 | #define DA732X_AIFM_SRC_SEL_AIFA (1 << 6) | ||
501 | #define DA732X_CLK_GENERATION_AIF_A (1 << 4) | ||
502 | #define DA732X_NO_CLK_GENERATION 0x0 | ||
503 | |||
504 | /* DA732X_REG_AIFA1 (addr=0x61) */ | ||
505 | #define DA732X_AIF_WORD_MASK (0x3 << 0) | ||
506 | #define DA732X_AIF_WORD_16 (0 << 0) | ||
507 | #define DA732X_AIF_WORD_20 (1 << 0) | ||
508 | #define DA732X_AIF_WORD_24 (2 << 0) | ||
509 | #define DA732X_AIF_WORD_32 (3 << 0) | ||
510 | #define DA732X_AIF_TDM_MONO_SHIFT (1 << 6) | ||
511 | #define DA732X_AIF1_CLK_MASK (1 << 7) | ||
512 | #define DA732X_AIF_SLAVE (0 << 7) | ||
513 | #define DA732X_AIF_CLK_FROM_SRC (1 << 7) | ||
514 | |||
515 | /* DA732X_REG_AIFA3 (addr=0x63) */ | ||
516 | #define DA732X_AIF_MODE_SHIFT 0 | ||
517 | #define DA732X_AIF_MODE_MASK 0x3 | ||
518 | #define DA732X_AIF_I2S_MODE (0 << 0) | ||
519 | #define DA732X_AIF_LEFT_J_MODE (1 << 0) | ||
520 | #define DA732X_AIF_RIGHT_J_MODE (2 << 0) | ||
521 | #define DA732X_AIF_DSP_MODE (3 << 0) | ||
522 | #define DA732X_AIF_WCLK_INV (1 << 4) | ||
523 | #define DA732X_AIF_BCLK_INV (1 << 5) | ||
524 | #define DA732X_AIF_EN (1 << 7) | ||
525 | #define DA732X_AIF_EN_SHIFT 7 | ||
526 | |||
527 | /* DA732X_REG_PC_CTRL (addr=0x6a) */ | ||
528 | #define DA732X_PC_PULSE_AIFA (0 << 0) | ||
529 | #define DA732X_PC_PULSE_AIFB (1 << 0) | ||
530 | #define DA732X_PC_RESYNC_AUT (1 << 6) | ||
531 | #define DA732X_PC_RESYNC_NOT_AUT (0 << 6) | ||
532 | #define DA732X_PC_SAME (1 << 7) | ||
533 | |||
534 | /* DA732X_REG_DATA_ROUTE (addr=0x70) */ | ||
535 | #define DA732X_ADC1_TO_AIFA (0 << 0) | ||
536 | #define DA732X_DSP_TO_AIFA (1 << 0) | ||
537 | #define DA732X_ADC2_TO_AIFB (0 << 1) | ||
538 | #define DA732X_DSP_TO_AIFB (1 << 1) | ||
539 | #define DA732X_AIFA_TO_DAC1L (0 << 2) | ||
540 | #define DA732X_DSP_TO_DAC1L (1 << 2) | ||
541 | #define DA732X_AIFA_TO_DAC1R (0 << 3) | ||
542 | #define DA732X_DSP_TO_DAC1R (1 << 3) | ||
543 | #define DA732X_AIFB_TO_DAC2L (0 << 4) | ||
544 | #define DA732X_DSP_TO_DAC2L (1 << 4) | ||
545 | #define DA732X_AIFB_TO_DAC2R (0 << 5) | ||
546 | #define DA732X_DSP_TO_DAC2R (1 << 5) | ||
547 | #define DA732X_AIFB_TO_DAC3 (0 << 6) | ||
548 | #define DA732X_DSP_TO_DAC3 (1 << 6) | ||
549 | #define DA732X_BYPASS_DSP (0 << 0) | ||
550 | #define DA732X_ALL_TO_DSP (0x7F << 0) | ||
551 | |||
552 | /* DA732X_REG_DSP_CTRL (addr=0x71) */ | ||
553 | #define DA732X_DIGITAL_EN (1 << 0) | ||
554 | #define DA732X_DIGITAL_RESET (0 << 0) | ||
555 | #define DA732X_DSP_CORE_EN (1 << 1) | ||
556 | #define DA732X_DSP_CORE_RESET (0 << 1) | ||
557 | |||
558 | /* DA732X_REG_SPARE1_OUT (addr=0x7D)*/ | ||
559 | #define DA732X_HP_DRIVER_EN (1 << 0) | ||
560 | #define DA732X_HP_GATE_LOW (1 << 2) | ||
561 | #define DA732X_HP_LOOP_GAIN_CTRL (1 << 3) | ||
562 | |||
563 | /* DA732X_REG_ID (addr=0x81)*/ | ||
564 | #define DA732X_ID_MINOR_MASK (0xF << 0) | ||
565 | #define DA732X_ID_MAJOR_MASK (0xF << 4) | ||
566 | |||
567 | /* DA732X_REG_ADC1/2_PD (addr=0x90/0x98) */ | ||
568 | #define DA732X_ADC_RST_MASK (0x3 << 0) | ||
569 | #define DA732X_ADC_PD_MASK (0x3 << 2) | ||
570 | #define DA732X_ADC_SET_ACT (0x3 << 0) | ||
571 | #define DA732X_ADC_SET_RST (0x0 << 0) | ||
572 | #define DA732X_ADC_ON (0x3 << 2) | ||
573 | #define DA732X_ADC_OFF (0x0 << 2) | ||
574 | |||
575 | /* DA732X_REG_ADC1/2_SEL (addr=0x94/0x9C) */ | ||
576 | #define DA732X_ADC_VOL_VAL_MASK 0x7 | ||
577 | #define DA732X_ADCL_VOL_SHIFT 0 | ||
578 | #define DA732X_ADCR_VOL_SHIFT 4 | ||
579 | #define DA732X_ADCL_EN_SHIFT 2 | ||
580 | #define DA732X_ADCR_EN_SHIFT 3 | ||
581 | #define DA732X_ADCL_EN (1 << 2) | ||
582 | #define DA732X_ADCR_EN (1 << 3) | ||
583 | #define DA732X_ADC_VOL_VAL_MAX DA732X_ADC_VOL_VAL_MASK | ||
584 | |||
585 | /* | ||
586 | * DA732X_REG_ADC1/2_HPF (addr=0x93/0x9b) | ||
587 | * DA732x_REG_DAC1/2/3_HPG (addr=0xA5/0xB5/0xC5) | ||
588 | */ | ||
589 | #define DA732X_HPF_MUSIC_EN (1 << 3) | ||
590 | #define DA732X_HPF_VOICE_EN ((1 << 3) | (1 << 7)) | ||
591 | #define DA732X_HPF_MASK ((1 << 3) | (1 << 7)) | ||
592 | #define DA732X_HPF_DIS ((0 << 3) | (0 << 7)) | ||
593 | |||
594 | /* DA732X_REG_DAC1/2/3_VOL */ | ||
595 | #define DA732X_DAC_VOL_VAL_MASK 0x7F | ||
596 | #define DA732X_DAC_VOL_SHIFT 0 | ||
597 | #define DA732X_DAC_VOL_VAL_MAX DA732X_DAC_VOL_VAL_MASK | ||
598 | |||
599 | /* DA732X_REG_DAC1/2/3_SEL (addr=0xA3/0xB3/0xC3) */ | ||
600 | #define DA732X_DACL_EN_SHIFT 3 | ||
601 | #define DA732X_DACR_EN_SHIFT 7 | ||
602 | #define DA732X_DACL_MUTE_SHIFT 2 | ||
603 | #define DA732X_DACR_MUTE_SHIFT 6 | ||
604 | #define DA732X_DACL_EN (1 << 3) | ||
605 | #define DA732X_DACR_EN (1 << 7) | ||
606 | #define DA732X_DACL_SDM (1 << 0) | ||
607 | #define DA732X_DACR_SDM (1 << 4) | ||
608 | #define DA732X_DACL_MUTE (1 << 2) | ||
609 | #define DA732X_DACR_MUTE (1 << 6) | ||
610 | |||
611 | /* DA732X_REG_DAC_SOFTMUTE (addr=0xA4/0xB4/0xC4) */ | ||
612 | #define DA732X_SOFTMUTE_EN (1 << 7) | ||
613 | #define DA732X_GAIN_RAMPED (1 << 6) | ||
614 | #define DA732X_16_SAMPLES (4 << 0) | ||
615 | #define DA732X_SOFTMUTE_MASK (1 << 7) | ||
616 | #define DA732X_SOFTMUTE_SHIFT 7 | ||
617 | |||
618 | /* | ||
619 | * DA732x_REG_ADC1/2_EQ12 (addr=0x95/0x9D) | ||
620 | * DA732x_REG_ADC1/2_EQ34 (addr=0x96/0x9E) | ||
621 | * DA732x_REG_ADC1/2_EQ5 (addr=0x97/0x9F) | ||
622 | * DA732x_REG_DAC1/2/3_EQ12 (addr=0xA5/0xB5/0xC5) | ||
623 | * DA732x_REG_DAC1/2/3_EQ34 (addr=0xA6/0xB6/0xC6) | ||
624 | * DA732x_REG_DAC1/2/3_EQ5 (addr=0xA7/0xB7/0xB7) | ||
625 | */ | ||
626 | #define DA732X_EQ_VOL_VAL_MASK 0xF | ||
627 | #define DA732X_EQ_BAND1_SHIFT 0 | ||
628 | #define DA732X_EQ_BAND2_SHIFT 4 | ||
629 | #define DA732X_EQ_BAND3_SHIFT 0 | ||
630 | #define DA732X_EQ_BAND4_SHIFT 4 | ||
631 | #define DA732X_EQ_BAND5_SHIFT 0 | ||
632 | #define DA732X_EQ_OVERALL_SHIFT 4 | ||
633 | #define DA732X_EQ_OVERALL_VOL_VAL_MASK 0x3 | ||
634 | #define DA732X_EQ_DIS (0 << 7) | ||
635 | #define DA732X_EQ_EN (1 << 7) | ||
636 | #define DA732X_EQ_EN_SHIFT 7 | ||
637 | #define DA732X_EQ_VOL_VAL_MAX DA732X_EQ_VOL_VAL_MASK | ||
638 | #define DA732X_EQ_OVERALL_VOL_VAL_MAX DA732X_EQ_OVERALL_VOL_VAL_MASK | ||
639 | |||
640 | /* DA732X_REG_DMA_CMD (addr=0xD3) */ | ||
641 | #define DA732X_SEL_DSP_DMA_MASK (3 << 0) | ||
642 | #define DA732X_SEL_DSP_DMA_DIS (0 << 0) | ||
643 | #define DA732X_SEL_DSP_DMA_PMEM (1 << 0) | ||
644 | #define DA732X_SEL_DSP_DMA_XMEM (2 << 0) | ||
645 | #define DA732X_SEL_DSP_DMA_YMEM (3 << 0) | ||
646 | #define DA732X_DSP_RW_MASK (1 << 4) | ||
647 | #define DA732X_DSP_DMA_WRITE (0 << 4) | ||
648 | #define DA732X_DSP_DMA_READ (1 << 4) | ||
649 | |||
650 | /* DA732X_REG_DMA_STATUS (addr=0xDA) */ | ||
651 | #define DA732X_DSP_DMA_FREE (0 << 0) | ||
652 | #define DA732X_DSP_DMA_BUSY (1 << 0) | ||
653 | |||
654 | #endif /* __DA732X_REG_H_ */ | ||
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c new file mode 100644 index 000000000000..5d8f39e32978 --- /dev/null +++ b/sound/soc/codecs/isabelle.c | |||
@@ -0,0 +1,1176 @@ | |||
1 | /* | ||
2 | * isabelle.c - Low power high fidelity audio codec driver | ||
3 | * | ||
4 | * Copyright (c) 2012 Texas Instruments, Inc | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | * | ||
11 | * Initially based on sound/soc/codecs/twl6040.c | ||
12 | * | ||
13 | */ | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/i2c.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/soc.h> | ||
28 | #include <sound/soc-dapm.h> | ||
29 | #include <sound/tlv.h> | ||
30 | #include <sound/jack.h> | ||
31 | #include <sound/initval.h> | ||
32 | #include <asm/div64.h> | ||
33 | #include "isabelle.h" | ||
34 | |||
35 | |||
36 | /* Register default values for ISABELLE driver. */ | ||
37 | static struct reg_default isabelle_reg_defs[] = { | ||
38 | { 0, 0x00 }, | ||
39 | { 1, 0x00 }, | ||
40 | { 2, 0x00 }, | ||
41 | { 3, 0x00 }, | ||
42 | { 4, 0x00 }, | ||
43 | { 5, 0x00 }, | ||
44 | { 6, 0x00 }, | ||
45 | { 7, 0x00 }, | ||
46 | { 8, 0x00 }, | ||
47 | { 9, 0x00 }, | ||
48 | { 10, 0x00 }, | ||
49 | { 11, 0x00 }, | ||
50 | { 12, 0x00 }, | ||
51 | { 13, 0x00 }, | ||
52 | { 14, 0x00 }, | ||
53 | { 15, 0x00 }, | ||
54 | { 16, 0x00 }, | ||
55 | { 17, 0x00 }, | ||
56 | { 18, 0x00 }, | ||
57 | { 19, 0x00 }, | ||
58 | { 20, 0x00 }, | ||
59 | { 21, 0x02 }, | ||
60 | { 22, 0x02 }, | ||
61 | { 23, 0x02 }, | ||
62 | { 24, 0x02 }, | ||
63 | { 25, 0x0F }, | ||
64 | { 26, 0x8F }, | ||
65 | { 27, 0x0F }, | ||
66 | { 28, 0x8F }, | ||
67 | { 29, 0x00 }, | ||
68 | { 30, 0x00 }, | ||
69 | { 31, 0x00 }, | ||
70 | { 32, 0x00 }, | ||
71 | { 33, 0x00 }, | ||
72 | { 34, 0x00 }, | ||
73 | { 35, 0x00 }, | ||
74 | { 36, 0x00 }, | ||
75 | { 37, 0x00 }, | ||
76 | { 38, 0x00 }, | ||
77 | { 39, 0x00 }, | ||
78 | { 40, 0x00 }, | ||
79 | { 41, 0x00 }, | ||
80 | { 42, 0x00 }, | ||
81 | { 43, 0x00 }, | ||
82 | { 44, 0x00 }, | ||
83 | { 45, 0x00 }, | ||
84 | { 46, 0x00 }, | ||
85 | { 47, 0x00 }, | ||
86 | { 48, 0x00 }, | ||
87 | { 49, 0x00 }, | ||
88 | { 50, 0x00 }, | ||
89 | { 51, 0x00 }, | ||
90 | { 52, 0x00 }, | ||
91 | { 53, 0x00 }, | ||
92 | { 54, 0x00 }, | ||
93 | { 55, 0x00 }, | ||
94 | { 56, 0x00 }, | ||
95 | { 57, 0x00 }, | ||
96 | { 58, 0x00 }, | ||
97 | { 59, 0x00 }, | ||
98 | { 60, 0x00 }, | ||
99 | { 61, 0x00 }, | ||
100 | { 62, 0x00 }, | ||
101 | { 63, 0x00 }, | ||
102 | { 64, 0x00 }, | ||
103 | { 65, 0x00 }, | ||
104 | { 66, 0x00 }, | ||
105 | { 67, 0x00 }, | ||
106 | { 68, 0x00 }, | ||
107 | { 69, 0x90 }, | ||
108 | { 70, 0x90 }, | ||
109 | { 71, 0x90 }, | ||
110 | { 72, 0x00 }, | ||
111 | { 73, 0x00 }, | ||
112 | { 74, 0x00 }, | ||
113 | { 75, 0x00 }, | ||
114 | { 76, 0x00 }, | ||
115 | { 77, 0x00 }, | ||
116 | { 78, 0x00 }, | ||
117 | { 79, 0x00 }, | ||
118 | { 80, 0x00 }, | ||
119 | { 81, 0x00 }, | ||
120 | { 82, 0x00 }, | ||
121 | { 83, 0x00 }, | ||
122 | { 84, 0x00 }, | ||
123 | { 85, 0x07 }, | ||
124 | { 86, 0x00 }, | ||
125 | { 87, 0x00 }, | ||
126 | { 88, 0x00 }, | ||
127 | { 89, 0x07 }, | ||
128 | { 90, 0x80 }, | ||
129 | { 91, 0x07 }, | ||
130 | { 92, 0x07 }, | ||
131 | { 93, 0x00 }, | ||
132 | { 94, 0x00 }, | ||
133 | { 95, 0x00 }, | ||
134 | { 96, 0x00 }, | ||
135 | { 97, 0x00 }, | ||
136 | { 98, 0x00 }, | ||
137 | { 99, 0x00 }, | ||
138 | }; | ||
139 | |||
140 | static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"}; | ||
141 | static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; | ||
142 | |||
143 | static const struct soc_enum isabelle_rx1_enum[] = { | ||
144 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), | ||
145 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), | ||
146 | }; | ||
147 | |||
148 | static const struct soc_enum isabelle_rx2_enum[] = { | ||
149 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), | ||
150 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), | ||
151 | }; | ||
152 | |||
153 | /* Headset DAC playback switches */ | ||
154 | static const struct snd_kcontrol_new rx1_mux_controls = | ||
155 | SOC_DAPM_ENUM("Route", isabelle_rx1_enum); | ||
156 | |||
157 | static const struct snd_kcontrol_new rx2_mux_controls = | ||
158 | SOC_DAPM_ENUM("Route", isabelle_rx2_enum); | ||
159 | |||
160 | /* TX input selection */ | ||
161 | static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"}; | ||
162 | static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; | ||
163 | |||
164 | static const struct soc_enum isabelle_atx_enum[] = { | ||
165 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), | ||
166 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), | ||
167 | }; | ||
168 | |||
169 | static const struct soc_enum isabelle_vtx_enum[] = { | ||
170 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), | ||
171 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), | ||
172 | }; | ||
173 | |||
174 | static const struct snd_kcontrol_new atx_mux_controls = | ||
175 | SOC_DAPM_ENUM("Route", isabelle_atx_enum); | ||
176 | |||
177 | static const struct snd_kcontrol_new vtx_mux_controls = | ||
178 | SOC_DAPM_ENUM("Route", isabelle_vtx_enum); | ||
179 | |||
180 | /* Left analog microphone selection */ | ||
181 | static const char *isabelle_amic1_texts[] = { | ||
182 | "Main Mic", "Headset Mic", "Aux/FM Left"}; | ||
183 | |||
184 | /* Left analog microphone selection */ | ||
185 | static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; | ||
186 | |||
187 | static const struct soc_enum isabelle_amic1_enum[] = { | ||
188 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, | ||
189 | ARRAY_SIZE(isabelle_amic1_texts), | ||
190 | isabelle_amic1_texts), | ||
191 | }; | ||
192 | |||
193 | static const struct soc_enum isabelle_amic2_enum[] = { | ||
194 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, | ||
195 | ARRAY_SIZE(isabelle_amic2_texts), | ||
196 | isabelle_amic2_texts), | ||
197 | }; | ||
198 | |||
199 | static const struct snd_kcontrol_new amic1_control = | ||
200 | SOC_DAPM_ENUM("Route", isabelle_amic1_enum); | ||
201 | |||
202 | static const struct snd_kcontrol_new amic2_control = | ||
203 | SOC_DAPM_ENUM("Route", isabelle_amic2_enum); | ||
204 | |||
205 | static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"}; | ||
206 | |||
207 | static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; | ||
208 | |||
209 | static const struct soc_enum isabelle_st_audio_enum[] = { | ||
210 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, | ||
211 | isabelle_st_audio_texts), | ||
212 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, | ||
213 | isabelle_st_audio_texts), | ||
214 | }; | ||
215 | |||
216 | static const struct soc_enum isabelle_st_voice_enum[] = { | ||
217 | SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, | ||
218 | isabelle_st_voice_texts), | ||
219 | SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, | ||
220 | isabelle_st_voice_texts), | ||
221 | }; | ||
222 | |||
223 | static const struct snd_kcontrol_new st_audio_control = | ||
224 | SOC_DAPM_ENUM("Route", isabelle_st_audio_enum); | ||
225 | |||
226 | static const struct snd_kcontrol_new st_voice_control = | ||
227 | SOC_DAPM_ENUM("Route", isabelle_st_voice_enum); | ||
228 | |||
229 | /* Mixer controls */ | ||
230 | static const struct snd_kcontrol_new isabelle_hs_left_mixer_controls[] = { | ||
231 | SOC_DAPM_SINGLE("DAC1L Playback Switch", ISABELLE_HSDRV_CFG1_REG, 7, 1, 0), | ||
232 | SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 6, 1, 0), | ||
233 | }; | ||
234 | |||
235 | static const struct snd_kcontrol_new isabelle_hs_right_mixer_controls[] = { | ||
236 | SOC_DAPM_SINGLE("DAC1R Playback Switch", ISABELLE_HSDRV_CFG1_REG, 5, 1, 0), | ||
237 | SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HSDRV_CFG1_REG, 4, 1, 0), | ||
238 | }; | ||
239 | |||
240 | static const struct snd_kcontrol_new isabelle_hf_left_mixer_controls[] = { | ||
241 | SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_HFLPGA_CFG_REG, 7, 1, 0), | ||
242 | SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_HFLPGA_CFG_REG, 6, 1, 0), | ||
243 | }; | ||
244 | |||
245 | static const struct snd_kcontrol_new isabelle_hf_right_mixer_controls[] = { | ||
246 | SOC_DAPM_SINGLE("DAC2R Playback Switch", ISABELLE_HFRPGA_CFG_REG, 7, 1, 0), | ||
247 | SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_HFRPGA_CFG_REG, 6, 1, 0), | ||
248 | }; | ||
249 | |||
250 | static const struct snd_kcontrol_new isabelle_ep_mixer_controls[] = { | ||
251 | SOC_DAPM_SINGLE("DAC2L Playback Switch", ISABELLE_EARDRV_CFG1_REG, 7, 1, 0), | ||
252 | SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_EARDRV_CFG1_REG, 6, 1, 0), | ||
253 | }; | ||
254 | |||
255 | static const struct snd_kcontrol_new isabelle_aux_left_mixer_controls[] = { | ||
256 | SOC_DAPM_SINGLE("DAC3L Playback Switch", ISABELLE_LINEAMP_CFG_REG, 7, 1, 0), | ||
257 | SOC_DAPM_SINGLE("APGA1 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 6, 1, 0), | ||
258 | }; | ||
259 | |||
260 | static const struct snd_kcontrol_new isabelle_aux_right_mixer_controls[] = { | ||
261 | SOC_DAPM_SINGLE("DAC3R Playback Switch", ISABELLE_LINEAMP_CFG_REG, 5, 1, 0), | ||
262 | SOC_DAPM_SINGLE("APGA2 Playback Switch", ISABELLE_LINEAMP_CFG_REG, 4, 1, 0), | ||
263 | }; | ||
264 | |||
265 | static const struct snd_kcontrol_new isabelle_dpga1_left_mixer_controls[] = { | ||
266 | SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 7, 1, 0), | ||
267 | SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 6, 1, 0), | ||
268 | SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 5, 1, 0), | ||
269 | }; | ||
270 | |||
271 | static const struct snd_kcontrol_new isabelle_dpga1_right_mixer_controls[] = { | ||
272 | SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 3, 1, 0), | ||
273 | SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 2, 1, 0), | ||
274 | SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA1LR_IN_SEL_REG, 1, 1, 0), | ||
275 | }; | ||
276 | |||
277 | static const struct snd_kcontrol_new isabelle_dpga2_left_mixer_controls[] = { | ||
278 | SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 7, 1, 0), | ||
279 | SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 6, 1, 0), | ||
280 | SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 5, 1, 0), | ||
281 | SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 4, 1, 0), | ||
282 | SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 3, 1, 0), | ||
283 | SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2L_IN_SEL_REG, 2, 1, 0), | ||
284 | }; | ||
285 | |||
286 | static const struct snd_kcontrol_new isabelle_dpga2_right_mixer_controls[] = { | ||
287 | SOC_DAPM_SINGLE("USNC Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 7, 1, 0), | ||
288 | SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 3, 1, 0), | ||
289 | SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 2, 1, 0), | ||
290 | SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA2R_IN_SEL_REG, 1, 1, 0), | ||
291 | }; | ||
292 | |||
293 | static const struct snd_kcontrol_new isabelle_dpga3_left_mixer_controls[] = { | ||
294 | SOC_DAPM_SINGLE("RX1 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 7, 1, 0), | ||
295 | SOC_DAPM_SINGLE("RX3 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 6, 1, 0), | ||
296 | SOC_DAPM_SINGLE("RX5 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 5, 1, 0), | ||
297 | }; | ||
298 | |||
299 | static const struct snd_kcontrol_new isabelle_dpga3_right_mixer_controls[] = { | ||
300 | SOC_DAPM_SINGLE("RX2 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 3, 1, 0), | ||
301 | SOC_DAPM_SINGLE("RX4 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 2, 1, 0), | ||
302 | SOC_DAPM_SINGLE("RX6 Playback Switch", ISABELLE_DPGA3LR_IN_SEL_REG, 1, 1, 0), | ||
303 | }; | ||
304 | |||
305 | static const struct snd_kcontrol_new isabelle_rx1_mixer_controls[] = { | ||
306 | SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 7, 1, 0), | ||
307 | SOC_DAPM_SINGLE("DL1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 6, 1, 0), | ||
308 | }; | ||
309 | |||
310 | static const struct snd_kcontrol_new isabelle_rx2_mixer_controls[] = { | ||
311 | SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 5, 1, 0), | ||
312 | SOC_DAPM_SINGLE("DL2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 4, 1, 0), | ||
313 | }; | ||
314 | |||
315 | static const struct snd_kcontrol_new isabelle_rx3_mixer_controls[] = { | ||
316 | SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 3, 1, 0), | ||
317 | SOC_DAPM_SINGLE("DL3 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 2, 1, 0), | ||
318 | }; | ||
319 | |||
320 | static const struct snd_kcontrol_new isabelle_rx4_mixer_controls[] = { | ||
321 | SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 1, 1, 0), | ||
322 | SOC_DAPM_SINGLE("DL4 Playback Switch", ISABELLE_RX_INPUT_CFG_REG, 0, 1, 0), | ||
323 | }; | ||
324 | |||
325 | static const struct snd_kcontrol_new isabelle_rx5_mixer_controls[] = { | ||
326 | SOC_DAPM_SINGLE("ST1 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 7, 1, 0), | ||
327 | SOC_DAPM_SINGLE("DL5 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 6, 1, 0), | ||
328 | }; | ||
329 | |||
330 | static const struct snd_kcontrol_new isabelle_rx6_mixer_controls[] = { | ||
331 | SOC_DAPM_SINGLE("ST2 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 5, 1, 0), | ||
332 | SOC_DAPM_SINGLE("DL6 Playback Switch", ISABELLE_RX_INPUT_CFG2_REG, 4, 1, 0), | ||
333 | }; | ||
334 | |||
335 | static const struct snd_kcontrol_new ep_path_enable_control = | ||
336 | SOC_DAPM_SINGLE("Switch", ISABELLE_EARDRV_CFG2_REG, 0, 1, 0); | ||
337 | |||
338 | /* TLV Declarations */ | ||
339 | static const DECLARE_TLV_DB_SCALE(mic_amp_tlv, 0, 100, 0); | ||
340 | static const DECLARE_TLV_DB_SCALE(afm_amp_tlv, -3300, 300, 0); | ||
341 | static const DECLARE_TLV_DB_SCALE(dac_tlv, -1200, 200, 0); | ||
342 | static const DECLARE_TLV_DB_SCALE(hf_tlv, -5000, 200, 0); | ||
343 | |||
344 | /* from -63 to 0 dB in 1 dB steps */ | ||
345 | static const DECLARE_TLV_DB_SCALE(dpga_tlv, -6300, 100, 1); | ||
346 | |||
347 | /* from -63 to 9 dB in 1 dB steps */ | ||
348 | static const DECLARE_TLV_DB_SCALE(rx_tlv, -6300, 100, 1); | ||
349 | |||
350 | static const DECLARE_TLV_DB_SCALE(st_tlv, -2700, 300, 1); | ||
351 | static const DECLARE_TLV_DB_SCALE(tx_tlv, -600, 100, 0); | ||
352 | |||
353 | static const struct snd_kcontrol_new isabelle_snd_controls[] = { | ||
354 | SOC_DOUBLE_TLV("Headset Playback Volume", ISABELLE_HSDRV_GAIN_REG, | ||
355 | 4, 0, 0xF, 0, dac_tlv), | ||
356 | SOC_DOUBLE_R_TLV("Handsfree Playback Volume", | ||
357 | ISABELLE_HFLPGA_CFG_REG, ISABELLE_HFRPGA_CFG_REG, | ||
358 | 0, 0x1F, 0, hf_tlv), | ||
359 | SOC_DOUBLE_TLV("Aux Playback Volume", ISABELLE_LINEAMP_GAIN_REG, | ||
360 | 4, 0, 0xF, 0, dac_tlv), | ||
361 | SOC_SINGLE_TLV("Earpiece Playback Volume", ISABELLE_EARDRV_CFG1_REG, | ||
362 | 0, 0xF, 0, dac_tlv), | ||
363 | |||
364 | SOC_DOUBLE_TLV("Aux FM Volume", ISABELLE_APGA_GAIN_REG, 4, 0, 0xF, 0, | ||
365 | afm_amp_tlv), | ||
366 | SOC_SINGLE_TLV("Mic1 Capture Volume", ISABELLE_MIC1_GAIN_REG, 3, 0x1F, | ||
367 | 0, mic_amp_tlv), | ||
368 | SOC_SINGLE_TLV("Mic2 Capture Volume", ISABELLE_MIC2_GAIN_REG, 3, 0x1F, | ||
369 | 0, mic_amp_tlv), | ||
370 | |||
371 | SOC_DOUBLE_R_TLV("DPGA1 Volume", ISABELLE_DPGA1L_GAIN_REG, | ||
372 | ISABELLE_DPGA1R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), | ||
373 | SOC_DOUBLE_R_TLV("DPGA2 Volume", ISABELLE_DPGA2L_GAIN_REG, | ||
374 | ISABELLE_DPGA2R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), | ||
375 | SOC_DOUBLE_R_TLV("DPGA3 Volume", ISABELLE_DPGA3L_GAIN_REG, | ||
376 | ISABELLE_DPGA3R_GAIN_REG, 0, 0x3F, 0, dpga_tlv), | ||
377 | |||
378 | SOC_SINGLE_TLV("Sidetone Audio TX1 Volume", | ||
379 | ISABELLE_ATX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv), | ||
380 | SOC_SINGLE_TLV("Sidetone Audio TX2 Volume", | ||
381 | ISABELLE_ATX_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv), | ||
382 | SOC_SINGLE_TLV("Sidetone Voice TX1 Volume", | ||
383 | ISABELLE_VTX_STPGA1_CFG_REG, 0, 0xF, 0, st_tlv), | ||
384 | SOC_SINGLE_TLV("Sidetone Voice TX2 Volume", | ||
385 | ISABELLE_VTX2_STPGA2_CFG_REG, 0, 0xF, 0, st_tlv), | ||
386 | |||
387 | SOC_SINGLE_TLV("Audio TX1 Volume", ISABELLE_ATX1_DPGA_REG, 4, 0xF, 0, | ||
388 | tx_tlv), | ||
389 | SOC_SINGLE_TLV("Audio TX2 Volume", ISABELLE_ATX2_DPGA_REG, 4, 0xF, 0, | ||
390 | tx_tlv), | ||
391 | SOC_SINGLE_TLV("Voice TX1 Volume", ISABELLE_VTX1_DPGA_REG, 4, 0xF, 0, | ||
392 | tx_tlv), | ||
393 | SOC_SINGLE_TLV("Voice TX2 Volume", ISABELLE_VTX2_DPGA_REG, 4, 0xF, 0, | ||
394 | tx_tlv), | ||
395 | |||
396 | SOC_SINGLE_TLV("RX1 DPGA Volume", ISABELLE_RX1_DPGA_REG, 0, 0x3F, 0, | ||
397 | rx_tlv), | ||
398 | SOC_SINGLE_TLV("RX2 DPGA Volume", ISABELLE_RX2_DPGA_REG, 0, 0x3F, 0, | ||
399 | rx_tlv), | ||
400 | SOC_SINGLE_TLV("RX3 DPGA Volume", ISABELLE_RX3_DPGA_REG, 0, 0x3F, 0, | ||
401 | rx_tlv), | ||
402 | SOC_SINGLE_TLV("RX4 DPGA Volume", ISABELLE_RX4_DPGA_REG, 0, 0x3F, 0, | ||
403 | rx_tlv), | ||
404 | SOC_SINGLE_TLV("RX5 DPGA Volume", ISABELLE_RX5_DPGA_REG, 0, 0x3F, 0, | ||
405 | rx_tlv), | ||
406 | SOC_SINGLE_TLV("RX6 DPGA Volume", ISABELLE_RX6_DPGA_REG, 0, 0x3F, 0, | ||
407 | rx_tlv), | ||
408 | |||
409 | SOC_SINGLE("Headset Noise Gate", ISABELLE_HS_NG_CFG1_REG, 7, 1, 0), | ||
410 | SOC_SINGLE("Handsfree Noise Gate", ISABELLE_HF_NG_CFG1_REG, 7, 1, 0), | ||
411 | |||
412 | SOC_SINGLE("ATX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
413 | 7, 1, 0), | ||
414 | SOC_SINGLE("ATX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
415 | 6, 1, 0), | ||
416 | SOC_SINGLE("ARX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
417 | 5, 1, 0), | ||
418 | SOC_SINGLE("ARX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
419 | 4, 1, 0), | ||
420 | SOC_SINGLE("ARX3 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
421 | 3, 1, 0), | ||
422 | SOC_SINGLE("ARX4 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
423 | 2, 1, 0), | ||
424 | SOC_SINGLE("ARX5 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
425 | 1, 1, 0), | ||
426 | SOC_SINGLE("ARX6 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
427 | 0, 1, 0), | ||
428 | SOC_SINGLE("VRX1 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
429 | 3, 1, 0), | ||
430 | SOC_SINGLE("VRX2 Filter Bypass Switch", ISABELLE_AUDIO_HPF_CFG_REG, | ||
431 | 2, 1, 0), | ||
432 | |||
433 | SOC_SINGLE("ATX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, | ||
434 | 7, 1, 0), | ||
435 | SOC_SINGLE("ATX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, | ||
436 | 6, 1, 0), | ||
437 | SOC_SINGLE("VTX1 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, | ||
438 | 5, 1, 0), | ||
439 | SOC_SINGLE("VTX2 Filter Enable Switch", ISABELLE_ALU_TX_EN_REG, | ||
440 | 4, 1, 0), | ||
441 | SOC_SINGLE("RX1 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
442 | 5, 1, 0), | ||
443 | SOC_SINGLE("RX2 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
444 | 4, 1, 0), | ||
445 | SOC_SINGLE("RX3 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
446 | 3, 1, 0), | ||
447 | SOC_SINGLE("RX4 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
448 | 2, 1, 0), | ||
449 | SOC_SINGLE("RX5 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
450 | 1, 1, 0), | ||
451 | SOC_SINGLE("RX6 Filter Enable Switch", ISABELLE_ALU_RX_EN_REG, | ||
452 | 0, 1, 0), | ||
453 | |||
454 | SOC_SINGLE("ULATX12 Capture Switch", ISABELLE_ULATX12_INTF_CFG_REG, | ||
455 | 7, 1, 0), | ||
456 | |||
457 | SOC_SINGLE("DL12 Playback Switch", ISABELLE_DL12_INTF_CFG_REG, | ||
458 | 7, 1, 0), | ||
459 | SOC_SINGLE("DL34 Playback Switch", ISABELLE_DL34_INTF_CFG_REG, | ||
460 | 7, 1, 0), | ||
461 | SOC_SINGLE("DL56 Playback Switch", ISABELLE_DL56_INTF_CFG_REG, | ||
462 | 7, 1, 0), | ||
463 | |||
464 | /* DMIC Switch */ | ||
465 | SOC_SINGLE("DMIC Switch", ISABELLE_DMIC_CFG_REG, 0, 1, 0), | ||
466 | }; | ||
467 | |||
468 | static const struct snd_soc_dapm_widget isabelle_dapm_widgets[] = { | ||
469 | /* Inputs */ | ||
470 | SND_SOC_DAPM_INPUT("MAINMIC"), | ||
471 | SND_SOC_DAPM_INPUT("HSMIC"), | ||
472 | SND_SOC_DAPM_INPUT("SUBMIC"), | ||
473 | SND_SOC_DAPM_INPUT("LINEIN1"), | ||
474 | SND_SOC_DAPM_INPUT("LINEIN2"), | ||
475 | SND_SOC_DAPM_INPUT("DMICDAT"), | ||
476 | |||
477 | /* Outputs */ | ||
478 | SND_SOC_DAPM_OUTPUT("HSOL"), | ||
479 | SND_SOC_DAPM_OUTPUT("HSOR"), | ||
480 | SND_SOC_DAPM_OUTPUT("HFL"), | ||
481 | SND_SOC_DAPM_OUTPUT("HFR"), | ||
482 | SND_SOC_DAPM_OUTPUT("EP"), | ||
483 | SND_SOC_DAPM_OUTPUT("LINEOUT1"), | ||
484 | SND_SOC_DAPM_OUTPUT("LINEOUT2"), | ||
485 | |||
486 | SND_SOC_DAPM_PGA("DL1", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
487 | SND_SOC_DAPM_PGA("DL2", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
488 | SND_SOC_DAPM_PGA("DL3", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
489 | SND_SOC_DAPM_PGA("DL4", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
490 | SND_SOC_DAPM_PGA("DL5", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
491 | SND_SOC_DAPM_PGA("DL6", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
492 | |||
493 | /* Analog input muxes for the capture amplifiers */ | ||
494 | SND_SOC_DAPM_MUX("Analog Left Capture Route", | ||
495 | SND_SOC_NOPM, 0, 0, &amic1_control), | ||
496 | SND_SOC_DAPM_MUX("Analog Right Capture Route", | ||
497 | SND_SOC_NOPM, 0, 0, &amic2_control), | ||
498 | |||
499 | SND_SOC_DAPM_MUX("Sidetone Audio Playback", SND_SOC_NOPM, 0, 0, | ||
500 | &st_audio_control), | ||
501 | SND_SOC_DAPM_MUX("Sidetone Voice Playback", SND_SOC_NOPM, 0, 0, | ||
502 | &st_voice_control), | ||
503 | |||
504 | /* AIF */ | ||
505 | SND_SOC_DAPM_AIF_IN("INTF1_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 7, 0), | ||
506 | SND_SOC_DAPM_AIF_IN("INTF2_SDI", NULL, 0, ISABELLE_INTF_EN_REG, 6, 0), | ||
507 | |||
508 | SND_SOC_DAPM_AIF_OUT("INTF1_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 5, 0), | ||
509 | SND_SOC_DAPM_AIF_OUT("INTF2_SDO", NULL, 0, ISABELLE_INTF_EN_REG, 4, 0), | ||
510 | |||
511 | SND_SOC_DAPM_OUT_DRV("ULATX1", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
512 | SND_SOC_DAPM_OUT_DRV("ULATX2", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
513 | SND_SOC_DAPM_OUT_DRV("ULVTX1", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
514 | SND_SOC_DAPM_OUT_DRV("ULVTX2", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
515 | |||
516 | /* Analog Capture PGAs */ | ||
517 | SND_SOC_DAPM_PGA("MicAmp1", ISABELLE_AMIC_CFG_REG, 5, 0, NULL, 0), | ||
518 | SND_SOC_DAPM_PGA("MicAmp2", ISABELLE_AMIC_CFG_REG, 4, 0, NULL, 0), | ||
519 | |||
520 | /* Auxiliary FM PGAs */ | ||
521 | SND_SOC_DAPM_PGA("APGA1", ISABELLE_APGA_CFG_REG, 7, 0, NULL, 0), | ||
522 | SND_SOC_DAPM_PGA("APGA2", ISABELLE_APGA_CFG_REG, 6, 0, NULL, 0), | ||
523 | |||
524 | /* ADCs */ | ||
525 | SND_SOC_DAPM_ADC("ADC1", "Left Front Capture", | ||
526 | ISABELLE_AMIC_CFG_REG, 7, 0), | ||
527 | SND_SOC_DAPM_ADC("ADC2", "Right Front Capture", | ||
528 | ISABELLE_AMIC_CFG_REG, 6, 0), | ||
529 | |||
530 | /* Microphone Bias */ | ||
531 | SND_SOC_DAPM_SUPPLY("Headset Mic Bias", ISABELLE_ABIAS_CFG_REG, | ||
532 | 3, 0, NULL, 0), | ||
533 | SND_SOC_DAPM_SUPPLY("Main Mic Bias", ISABELLE_ABIAS_CFG_REG, | ||
534 | 2, 0, NULL, 0), | ||
535 | SND_SOC_DAPM_SUPPLY("Digital Mic1 Bias", | ||
536 | ISABELLE_DBIAS_CFG_REG, 3, 0, NULL, 0), | ||
537 | SND_SOC_DAPM_SUPPLY("Digital Mic2 Bias", | ||
538 | ISABELLE_DBIAS_CFG_REG, 2, 0, NULL, 0), | ||
539 | |||
540 | /* Mixers */ | ||
541 | SND_SOC_DAPM_MIXER("Headset Left Mixer", SND_SOC_NOPM, 0, 0, | ||
542 | isabelle_hs_left_mixer_controls, | ||
543 | ARRAY_SIZE(isabelle_hs_left_mixer_controls)), | ||
544 | SND_SOC_DAPM_MIXER("Headset Right Mixer", SND_SOC_NOPM, 0, 0, | ||
545 | isabelle_hs_right_mixer_controls, | ||
546 | ARRAY_SIZE(isabelle_hs_right_mixer_controls)), | ||
547 | SND_SOC_DAPM_MIXER("Handsfree Left Mixer", SND_SOC_NOPM, 0, 0, | ||
548 | isabelle_hf_left_mixer_controls, | ||
549 | ARRAY_SIZE(isabelle_hf_left_mixer_controls)), | ||
550 | SND_SOC_DAPM_MIXER("Handsfree Right Mixer", SND_SOC_NOPM, 0, 0, | ||
551 | isabelle_hf_right_mixer_controls, | ||
552 | ARRAY_SIZE(isabelle_hf_right_mixer_controls)), | ||
553 | SND_SOC_DAPM_MIXER("LINEOUT1 Mixer", SND_SOC_NOPM, 0, 0, | ||
554 | isabelle_aux_left_mixer_controls, | ||
555 | ARRAY_SIZE(isabelle_aux_left_mixer_controls)), | ||
556 | SND_SOC_DAPM_MIXER("LINEOUT2 Mixer", SND_SOC_NOPM, 0, 0, | ||
557 | isabelle_aux_right_mixer_controls, | ||
558 | ARRAY_SIZE(isabelle_aux_right_mixer_controls)), | ||
559 | SND_SOC_DAPM_MIXER("Earphone Mixer", SND_SOC_NOPM, 0, 0, | ||
560 | isabelle_ep_mixer_controls, | ||
561 | ARRAY_SIZE(isabelle_ep_mixer_controls)), | ||
562 | |||
563 | SND_SOC_DAPM_MIXER("DPGA1L Mixer", SND_SOC_NOPM, 0, 0, | ||
564 | isabelle_dpga1_left_mixer_controls, | ||
565 | ARRAY_SIZE(isabelle_dpga1_left_mixer_controls)), | ||
566 | SND_SOC_DAPM_MIXER("DPGA1R Mixer", SND_SOC_NOPM, 0, 0, | ||
567 | isabelle_dpga1_right_mixer_controls, | ||
568 | ARRAY_SIZE(isabelle_dpga1_right_mixer_controls)), | ||
569 | SND_SOC_DAPM_MIXER("DPGA2L Mixer", SND_SOC_NOPM, 0, 0, | ||
570 | isabelle_dpga2_left_mixer_controls, | ||
571 | ARRAY_SIZE(isabelle_dpga2_left_mixer_controls)), | ||
572 | SND_SOC_DAPM_MIXER("DPGA2R Mixer", SND_SOC_NOPM, 0, 0, | ||
573 | isabelle_dpga2_right_mixer_controls, | ||
574 | ARRAY_SIZE(isabelle_dpga2_right_mixer_controls)), | ||
575 | SND_SOC_DAPM_MIXER("DPGA3L Mixer", SND_SOC_NOPM, 0, 0, | ||
576 | isabelle_dpga3_left_mixer_controls, | ||
577 | ARRAY_SIZE(isabelle_dpga3_left_mixer_controls)), | ||
578 | SND_SOC_DAPM_MIXER("DPGA3R Mixer", SND_SOC_NOPM, 0, 0, | ||
579 | isabelle_dpga3_right_mixer_controls, | ||
580 | ARRAY_SIZE(isabelle_dpga3_right_mixer_controls)), | ||
581 | |||
582 | SND_SOC_DAPM_MIXER("RX1 Mixer", SND_SOC_NOPM, 0, 0, | ||
583 | isabelle_rx1_mixer_controls, | ||
584 | ARRAY_SIZE(isabelle_rx1_mixer_controls)), | ||
585 | SND_SOC_DAPM_MIXER("RX2 Mixer", SND_SOC_NOPM, 0, 0, | ||
586 | isabelle_rx2_mixer_controls, | ||
587 | ARRAY_SIZE(isabelle_rx2_mixer_controls)), | ||
588 | SND_SOC_DAPM_MIXER("RX3 Mixer", SND_SOC_NOPM, 0, 0, | ||
589 | isabelle_rx3_mixer_controls, | ||
590 | ARRAY_SIZE(isabelle_rx3_mixer_controls)), | ||
591 | SND_SOC_DAPM_MIXER("RX4 Mixer", SND_SOC_NOPM, 0, 0, | ||
592 | isabelle_rx4_mixer_controls, | ||
593 | ARRAY_SIZE(isabelle_rx4_mixer_controls)), | ||
594 | SND_SOC_DAPM_MIXER("RX5 Mixer", SND_SOC_NOPM, 0, 0, | ||
595 | isabelle_rx5_mixer_controls, | ||
596 | ARRAY_SIZE(isabelle_rx5_mixer_controls)), | ||
597 | SND_SOC_DAPM_MIXER("RX6 Mixer", SND_SOC_NOPM, 0, 0, | ||
598 | isabelle_rx6_mixer_controls, | ||
599 | ARRAY_SIZE(isabelle_rx6_mixer_controls)), | ||
600 | |||
601 | /* DACs */ | ||
602 | SND_SOC_DAPM_DAC("DAC1L", "Headset Playback", ISABELLE_DAC_CFG_REG, | ||
603 | 5, 0), | ||
604 | SND_SOC_DAPM_DAC("DAC1R", "Headset Playback", ISABELLE_DAC_CFG_REG, | ||
605 | 4, 0), | ||
606 | SND_SOC_DAPM_DAC("DAC2L", "Handsfree Playback", ISABELLE_DAC_CFG_REG, | ||
607 | 3, 0), | ||
608 | SND_SOC_DAPM_DAC("DAC2R", "Handsfree Playback", ISABELLE_DAC_CFG_REG, | ||
609 | 2, 0), | ||
610 | SND_SOC_DAPM_DAC("DAC3L", "Lineout Playback", ISABELLE_DAC_CFG_REG, | ||
611 | 1, 0), | ||
612 | SND_SOC_DAPM_DAC("DAC3R", "Lineout Playback", ISABELLE_DAC_CFG_REG, | ||
613 | 0, 0), | ||
614 | |||
615 | /* Analog Playback PGAs */ | ||
616 | SND_SOC_DAPM_PGA("Sidetone Audio PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
617 | SND_SOC_DAPM_PGA("Sidetone Voice PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
618 | SND_SOC_DAPM_PGA("HF Left PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
619 | SND_SOC_DAPM_PGA("HF Right PGA", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
620 | SND_SOC_DAPM_PGA("DPGA1L", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
621 | SND_SOC_DAPM_PGA("DPGA1R", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
622 | SND_SOC_DAPM_PGA("DPGA2L", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
623 | SND_SOC_DAPM_PGA("DPGA2R", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
624 | SND_SOC_DAPM_PGA("DPGA3L", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
625 | SND_SOC_DAPM_PGA("DPGA3R", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
626 | |||
627 | /* Analog Playback Mux */ | ||
628 | SND_SOC_DAPM_MUX("RX1 Playback", ISABELLE_ALU_RX_EN_REG, 5, 0, | ||
629 | &rx1_mux_controls), | ||
630 | SND_SOC_DAPM_MUX("RX2 Playback", ISABELLE_ALU_RX_EN_REG, 4, 0, | ||
631 | &rx2_mux_controls), | ||
632 | |||
633 | /* TX Select */ | ||
634 | SND_SOC_DAPM_MUX("ATX Select", ISABELLE_TX_INPUT_CFG_REG, | ||
635 | 7, 0, &atx_mux_controls), | ||
636 | SND_SOC_DAPM_MUX("VTX Select", ISABELLE_TX_INPUT_CFG_REG, | ||
637 | 6, 0, &vtx_mux_controls), | ||
638 | |||
639 | SND_SOC_DAPM_SWITCH("Earphone Playback", SND_SOC_NOPM, 0, 0, | ||
640 | &ep_path_enable_control), | ||
641 | |||
642 | /* Output Drivers */ | ||
643 | SND_SOC_DAPM_OUT_DRV("HS Left Driver", ISABELLE_HSDRV_CFG2_REG, | ||
644 | 1, 0, NULL, 0), | ||
645 | SND_SOC_DAPM_OUT_DRV("HS Right Driver", ISABELLE_HSDRV_CFG2_REG, | ||
646 | 0, 0, NULL, 0), | ||
647 | SND_SOC_DAPM_OUT_DRV("LINEOUT1 Left Driver", ISABELLE_LINEAMP_CFG_REG, | ||
648 | 1, 0, NULL, 0), | ||
649 | SND_SOC_DAPM_OUT_DRV("LINEOUT2 Right Driver", ISABELLE_LINEAMP_CFG_REG, | ||
650 | 0, 0, NULL, 0), | ||
651 | SND_SOC_DAPM_OUT_DRV("Earphone Driver", ISABELLE_EARDRV_CFG2_REG, | ||
652 | 1, 0, NULL, 0), | ||
653 | |||
654 | SND_SOC_DAPM_OUT_DRV("HF Left Driver", ISABELLE_HFDRV_CFG_REG, | ||
655 | 1, 0, NULL, 0), | ||
656 | SND_SOC_DAPM_OUT_DRV("HF Right Driver", ISABELLE_HFDRV_CFG_REG, | ||
657 | 0, 0, NULL, 0), | ||
658 | }; | ||
659 | |||
660 | static const struct snd_soc_dapm_route isabelle_intercon[] = { | ||
661 | /* Interface mapping */ | ||
662 | { "DL1", "DL12 Playback Switch", "INTF1_SDI" }, | ||
663 | { "DL2", "DL12 Playback Switch", "INTF1_SDI" }, | ||
664 | { "DL3", "DL34 Playback Switch", "INTF1_SDI" }, | ||
665 | { "DL4", "DL34 Playback Switch", "INTF1_SDI" }, | ||
666 | { "DL5", "DL56 Playback Switch", "INTF1_SDI" }, | ||
667 | { "DL6", "DL56 Playback Switch", "INTF1_SDI" }, | ||
668 | |||
669 | { "DL1", "DL12 Playback Switch", "INTF2_SDI" }, | ||
670 | { "DL2", "DL12 Playback Switch", "INTF2_SDI" }, | ||
671 | { "DL3", "DL34 Playback Switch", "INTF2_SDI" }, | ||
672 | { "DL4", "DL34 Playback Switch", "INTF2_SDI" }, | ||
673 | { "DL5", "DL56 Playback Switch", "INTF2_SDI" }, | ||
674 | { "DL6", "DL56 Playback Switch", "INTF2_SDI" }, | ||
675 | |||
676 | /* Input side mapping */ | ||
677 | { "Sidetone Audio PGA", NULL, "Sidetone Audio Playback" }, | ||
678 | { "Sidetone Voice PGA", NULL, "Sidetone Voice Playback" }, | ||
679 | |||
680 | { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Audio PGA" }, | ||
681 | |||
682 | { "RX1 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, | ||
683 | { "RX1 Mixer", "DL1 Playback Switch", "DL1" }, | ||
684 | |||
685 | { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Audio PGA" }, | ||
686 | |||
687 | { "RX2 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, | ||
688 | { "RX2 Mixer", "DL2 Playback Switch", "DL2" }, | ||
689 | |||
690 | { "RX3 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, | ||
691 | { "RX3 Mixer", "DL3 Playback Switch", "DL3" }, | ||
692 | |||
693 | { "RX4 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, | ||
694 | { "RX4 Mixer", "DL4 Playback Switch", "DL4" }, | ||
695 | |||
696 | { "RX5 Mixer", "ST1 Playback Switch", "Sidetone Voice PGA" }, | ||
697 | { "RX5 Mixer", "DL5 Playback Switch", "DL5" }, | ||
698 | |||
699 | { "RX6 Mixer", "ST2 Playback Switch", "Sidetone Voice PGA" }, | ||
700 | { "RX6 Mixer", "DL6 Playback Switch", "DL6" }, | ||
701 | |||
702 | /* Capture path */ | ||
703 | { "Analog Left Capture Route", "Headset Mic", "HSMIC" }, | ||
704 | { "Analog Left Capture Route", "Main Mic", "MAINMIC" }, | ||
705 | { "Analog Left Capture Route", "Aux/FM Left", "LINEIN1" }, | ||
706 | |||
707 | { "Analog Right Capture Route", "Sub Mic", "SUBMIC" }, | ||
708 | { "Analog Right Capture Route", "Aux/FM Right", "LINEIN2" }, | ||
709 | |||
710 | { "MicAmp1", NULL, "Analog Left Capture Route" }, | ||
711 | { "MicAmp2", NULL, "Analog Right Capture Route" }, | ||
712 | |||
713 | { "ADC1", NULL, "MicAmp1" }, | ||
714 | { "ADC2", NULL, "MicAmp2" }, | ||
715 | |||
716 | { "ATX Select", "AMIC1", "ADC1" }, | ||
717 | { "ATX Select", "DMIC", "DMICDAT" }, | ||
718 | { "ATX Select", "AMIC2", "ADC2" }, | ||
719 | |||
720 | { "VTX Select", "AMIC1", "ADC1" }, | ||
721 | { "VTX Select", "DMIC", "DMICDAT" }, | ||
722 | { "VTX Select", "AMIC2", "ADC2" }, | ||
723 | |||
724 | { "ULATX1", "ATX1 Filter Enable Switch", "ATX Select" }, | ||
725 | { "ULATX1", "ATX1 Filter Bypass Switch", "ATX Select" }, | ||
726 | { "ULATX2", "ATX2 Filter Enable Switch", "ATX Select" }, | ||
727 | { "ULATX2", "ATX2 Filter Bypass Switch", "ATX Select" }, | ||
728 | |||
729 | { "ULVTX1", "VTX1 Filter Enable Switch", "VTX Select" }, | ||
730 | { "ULVTX1", "VTX1 Filter Bypass Switch", "VTX Select" }, | ||
731 | { "ULVTX2", "VTX2 Filter Enable Switch", "VTX Select" }, | ||
732 | { "ULVTX2", "VTX2 Filter Bypass Switch", "VTX Select" }, | ||
733 | |||
734 | { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX1" }, | ||
735 | { "INTF1_SDO", "ULATX12 Capture Switch", "ULATX2" }, | ||
736 | { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX1" }, | ||
737 | { "INTF2_SDO", "ULATX12 Capture Switch", "ULATX2" }, | ||
738 | |||
739 | { "INTF1_SDO", NULL, "ULVTX1" }, | ||
740 | { "INTF1_SDO", NULL, "ULVTX2" }, | ||
741 | { "INTF2_SDO", NULL, "ULVTX1" }, | ||
742 | { "INTF2_SDO", NULL, "ULVTX2" }, | ||
743 | |||
744 | /* AFM Path */ | ||
745 | { "APGA1", NULL, "LINEIN1" }, | ||
746 | { "APGA2", NULL, "LINEIN2" }, | ||
747 | |||
748 | { "RX1 Playback", "VRX1 Filter Bypass Switch", "RX1 Mixer" }, | ||
749 | { "RX1 Playback", "ARX1 Filter Bypass Switch", "RX1 Mixer" }, | ||
750 | { "RX1 Playback", "RX1 Filter Enable Switch", "RX1 Mixer" }, | ||
751 | |||
752 | { "RX2 Playback", "VRX2 Filter Bypass Switch", "RX2 Mixer" }, | ||
753 | { "RX2 Playback", "ARX2 Filter Bypass Switch", "RX2 Mixer" }, | ||
754 | { "RX2 Playback", "RX2 Filter Enable Switch", "RX2 Mixer" }, | ||
755 | |||
756 | { "RX3 Playback", "ARX3 Filter Bypass Switch", "RX3 Mixer" }, | ||
757 | { "RX3 Playback", "RX3 Filter Enable Switch", "RX3 Mixer" }, | ||
758 | |||
759 | { "RX4 Playback", "ARX4 Filter Bypass Switch", "RX4 Mixer" }, | ||
760 | { "RX4 Playback", "RX4 Filter Enable Switch", "RX4 Mixer" }, | ||
761 | |||
762 | { "RX5 Playback", "ARX5 Filter Bypass Switch", "RX5 Mixer" }, | ||
763 | { "RX5 Playback", "RX5 Filter Enable Switch", "RX5 Mixer" }, | ||
764 | |||
765 | { "RX6 Playback", "ARX6 Filter Bypass Switch", "RX6 Mixer" }, | ||
766 | { "RX6 Playback", "RX6 Filter Enable Switch", "RX6 Mixer" }, | ||
767 | |||
768 | { "DPGA1L Mixer", "RX1 Playback Switch", "RX1 Playback" }, | ||
769 | { "DPGA1L Mixer", "RX3 Playback Switch", "RX3 Playback" }, | ||
770 | { "DPGA1L Mixer", "RX5 Playback Switch", "RX5 Playback" }, | ||
771 | |||
772 | { "DPGA1R Mixer", "RX2 Playback Switch", "RX2 Playback" }, | ||
773 | { "DPGA1R Mixer", "RX4 Playback Switch", "RX4 Playback" }, | ||
774 | { "DPGA1R Mixer", "RX6 Playback Switch", "RX6 Playback" }, | ||
775 | |||
776 | { "DPGA1L", NULL, "DPGA1L Mixer" }, | ||
777 | { "DPGA1R", NULL, "DPGA1R Mixer" }, | ||
778 | |||
779 | { "DAC1L", NULL, "DPGA1L" }, | ||
780 | { "DAC1R", NULL, "DPGA1R" }, | ||
781 | |||
782 | { "DPGA2L Mixer", "RX1 Playback Switch", "RX1 Playback" }, | ||
783 | { "DPGA2L Mixer", "RX2 Playback Switch", "RX2 Playback" }, | ||
784 | { "DPGA2L Mixer", "RX3 Playback Switch", "RX3 Playback" }, | ||
785 | { "DPGA2L Mixer", "RX4 Playback Switch", "RX4 Playback" }, | ||
786 | { "DPGA2L Mixer", "RX5 Playback Switch", "RX5 Playback" }, | ||
787 | { "DPGA2L Mixer", "RX6 Playback Switch", "RX6 Playback" }, | ||
788 | |||
789 | { "DPGA2R Mixer", "RX2 Playback Switch", "RX2 Playback" }, | ||
790 | { "DPGA2R Mixer", "RX4 Playback Switch", "RX4 Playback" }, | ||
791 | { "DPGA2R Mixer", "RX6 Playback Switch", "RX6 Playback" }, | ||
792 | |||
793 | { "DPGA2L", NULL, "DPGA2L Mixer" }, | ||
794 | { "DPGA2R", NULL, "DPGA2R Mixer" }, | ||
795 | |||
796 | { "DAC2L", NULL, "DPGA2L" }, | ||
797 | { "DAC2R", NULL, "DPGA2R" }, | ||
798 | |||
799 | { "DPGA3L Mixer", "RX1 Playback Switch", "RX1 Playback" }, | ||
800 | { "DPGA3L Mixer", "RX3 Playback Switch", "RX3 Playback" }, | ||
801 | { "DPGA3L Mixer", "RX5 Playback Switch", "RX5 Playback" }, | ||
802 | |||
803 | { "DPGA3R Mixer", "RX2 Playback Switch", "RX2 Playback" }, | ||
804 | { "DPGA3R Mixer", "RX4 Playback Switch", "RX4 Playback" }, | ||
805 | { "DPGA3R Mixer", "RX6 Playback Switch", "RX6 Playback" }, | ||
806 | |||
807 | { "DPGA3L", NULL, "DPGA3L Mixer" }, | ||
808 | { "DPGA3R", NULL, "DPGA3R Mixer" }, | ||
809 | |||
810 | { "DAC3L", NULL, "DPGA3L" }, | ||
811 | { "DAC3R", NULL, "DPGA3R" }, | ||
812 | |||
813 | { "Headset Left Mixer", "DAC1L Playback Switch", "DAC1L" }, | ||
814 | { "Headset Left Mixer", "APGA1 Playback Switch", "APGA1" }, | ||
815 | |||
816 | { "Headset Right Mixer", "DAC1R Playback Switch", "DAC1R" }, | ||
817 | { "Headset Right Mixer", "APGA2 Playback Switch", "APGA2" }, | ||
818 | |||
819 | { "HS Left Driver", NULL, "Headset Left Mixer" }, | ||
820 | { "HS Right Driver", NULL, "Headset Right Mixer" }, | ||
821 | |||
822 | { "HSOL", NULL, "HS Left Driver" }, | ||
823 | { "HSOR", NULL, "HS Right Driver" }, | ||
824 | |||
825 | /* Earphone playback path */ | ||
826 | { "Earphone Mixer", "DAC2L Playback Switch", "DAC2L" }, | ||
827 | { "Earphone Mixer", "APGA1 Playback Switch", "APGA1" }, | ||
828 | |||
829 | { "Earphone Playback", "Switch", "Earphone Mixer" }, | ||
830 | { "Earphone Driver", NULL, "Earphone Playback" }, | ||
831 | { "EP", NULL, "Earphone Driver" }, | ||
832 | |||
833 | { "Handsfree Left Mixer", "DAC2L Playback Switch", "DAC2L" }, | ||
834 | { "Handsfree Left Mixer", "APGA1 Playback Switch", "APGA1" }, | ||
835 | |||
836 | { "Handsfree Right Mixer", "DAC2R Playback Switch", "DAC2R" }, | ||
837 | { "Handsfree Right Mixer", "APGA2 Playback Switch", "APGA2" }, | ||
838 | |||
839 | { "HF Left PGA", NULL, "Handsfree Left Mixer" }, | ||
840 | { "HF Right PGA", NULL, "Handsfree Right Mixer" }, | ||
841 | |||
842 | { "HF Left Driver", NULL, "HF Left PGA" }, | ||
843 | { "HF Right Driver", NULL, "HF Right PGA" }, | ||
844 | |||
845 | { "HFL", NULL, "HF Left Driver" }, | ||
846 | { "HFR", NULL, "HF Right Driver" }, | ||
847 | |||
848 | { "LINEOUT1 Mixer", "DAC3L Playback Switch", "DAC3L" }, | ||
849 | { "LINEOUT1 Mixer", "APGA1 Playback Switch", "APGA1" }, | ||
850 | |||
851 | { "LINEOUT2 Mixer", "DAC3R Playback Switch", "DAC3R" }, | ||
852 | { "LINEOUT2 Mixer", "APGA2 Playback Switch", "APGA2" }, | ||
853 | |||
854 | { "LINEOUT1 Driver", NULL, "LINEOUT1 Mixer" }, | ||
855 | { "LINEOUT2 Driver", NULL, "LINEOUT2 Mixer" }, | ||
856 | |||
857 | { "LINEOUT1", NULL, "LINEOUT1 Driver" }, | ||
858 | { "LINEOUT2", NULL, "LINEOUT2 Driver" }, | ||
859 | }; | ||
860 | |||
861 | static int isabelle_hs_mute(struct snd_soc_dai *dai, int mute) | ||
862 | { | ||
863 | snd_soc_update_bits(dai->codec, ISABELLE_DAC1_SOFTRAMP_REG, | ||
864 | BIT(4), (mute ? BIT(4) : 0)); | ||
865 | |||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static int isabelle_hf_mute(struct snd_soc_dai *dai, int mute) | ||
870 | { | ||
871 | snd_soc_update_bits(dai->codec, ISABELLE_DAC2_SOFTRAMP_REG, | ||
872 | BIT(4), (mute ? BIT(4) : 0)); | ||
873 | |||
874 | return 0; | ||
875 | } | ||
876 | |||
877 | static int isabelle_line_mute(struct snd_soc_dai *dai, int mute) | ||
878 | { | ||
879 | snd_soc_update_bits(dai->codec, ISABELLE_DAC3_SOFTRAMP_REG, | ||
880 | BIT(4), (mute ? BIT(4) : 0)); | ||
881 | |||
882 | return 0; | ||
883 | } | ||
884 | |||
885 | static int isabelle_set_bias_level(struct snd_soc_codec *codec, | ||
886 | enum snd_soc_bias_level level) | ||
887 | { | ||
888 | switch (level) { | ||
889 | case SND_SOC_BIAS_ON: | ||
890 | break; | ||
891 | case SND_SOC_BIAS_PREPARE: | ||
892 | break; | ||
893 | |||
894 | case SND_SOC_BIAS_STANDBY: | ||
895 | snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG, | ||
896 | ISABELLE_CHIP_EN, BIT(0)); | ||
897 | break; | ||
898 | |||
899 | case SND_SOC_BIAS_OFF: | ||
900 | snd_soc_update_bits(codec, ISABELLE_PWR_EN_REG, | ||
901 | ISABELLE_CHIP_EN, 0); | ||
902 | break; | ||
903 | } | ||
904 | |||
905 | codec->dapm.bias_level = level; | ||
906 | |||
907 | return 0; | ||
908 | } | ||
909 | |||
910 | static int isabelle_hw_params(struct snd_pcm_substream *substream, | ||
911 | struct snd_pcm_hw_params *params, | ||
912 | struct snd_soc_dai *dai) | ||
913 | { | ||
914 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
915 | struct snd_soc_codec *codec = rtd->codec; | ||
916 | u16 aif = 0; | ||
917 | unsigned int fs_val = 0; | ||
918 | |||
919 | switch (params_rate(params)) { | ||
920 | case 8000: | ||
921 | fs_val = ISABELLE_FS_RATE_8; | ||
922 | break; | ||
923 | case 11025: | ||
924 | fs_val = ISABELLE_FS_RATE_11; | ||
925 | break; | ||
926 | case 12000: | ||
927 | fs_val = ISABELLE_FS_RATE_12; | ||
928 | break; | ||
929 | case 16000: | ||
930 | fs_val = ISABELLE_FS_RATE_16; | ||
931 | break; | ||
932 | case 22050: | ||
933 | fs_val = ISABELLE_FS_RATE_22; | ||
934 | break; | ||
935 | case 24000: | ||
936 | fs_val = ISABELLE_FS_RATE_24; | ||
937 | break; | ||
938 | case 32000: | ||
939 | fs_val = ISABELLE_FS_RATE_32; | ||
940 | break; | ||
941 | case 44100: | ||
942 | fs_val = ISABELLE_FS_RATE_44; | ||
943 | break; | ||
944 | case 48000: | ||
945 | fs_val = ISABELLE_FS_RATE_48; | ||
946 | break; | ||
947 | default: | ||
948 | return -EINVAL; | ||
949 | } | ||
950 | |||
951 | snd_soc_update_bits(codec, ISABELLE_FS_RATE_CFG_REG, | ||
952 | ISABELLE_FS_RATE_MASK, fs_val); | ||
953 | |||
954 | /* bit size */ | ||
955 | switch (params_format(params)) { | ||
956 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
957 | aif |= ISABELLE_AIF_LENGTH_20; | ||
958 | break; | ||
959 | case SNDRV_PCM_FORMAT_S32_LE: | ||
960 | aif |= ISABELLE_AIF_LENGTH_32; | ||
961 | break; | ||
962 | default: | ||
963 | return -EINVAL; | ||
964 | } | ||
965 | |||
966 | snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG, | ||
967 | ISABELLE_AIF_LENGTH_MASK, aif); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
973 | { | ||
974 | struct snd_soc_codec *codec = codec_dai->codec; | ||
975 | unsigned int aif_val = 0; | ||
976 | |||
977 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
978 | case SND_SOC_DAIFMT_CBS_CFS: | ||
979 | aif_val &= ~ISABELLE_AIF_MS; | ||
980 | break; | ||
981 | case SND_SOC_DAIFMT_CBM_CFM: | ||
982 | aif_val |= ISABELLE_AIF_MS; | ||
983 | break; | ||
984 | default: | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
989 | case SND_SOC_DAIFMT_I2S: | ||
990 | aif_val |= ISABELLE_I2S_MODE; | ||
991 | break; | ||
992 | case SND_SOC_DAIFMT_LEFT_J: | ||
993 | aif_val |= ISABELLE_LEFT_J_MODE; | ||
994 | break; | ||
995 | case SND_SOC_DAIFMT_PDM: | ||
996 | aif_val |= ISABELLE_PDM_MODE; | ||
997 | break; | ||
998 | default: | ||
999 | return -EINVAL; | ||
1000 | } | ||
1001 | |||
1002 | snd_soc_update_bits(codec, ISABELLE_INTF_CFG_REG, | ||
1003 | (ISABELLE_AIF_MS | ISABELLE_AIF_FMT_MASK), aif_val); | ||
1004 | |||
1005 | return 0; | ||
1006 | } | ||
1007 | |||
1008 | /* Rates supported by Isabelle driver */ | ||
1009 | #define ISABELLE_RATES SNDRV_PCM_RATE_8000_48000 | ||
1010 | |||
1011 | /* Formates supported by Isabelle driver. */ | ||
1012 | #define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
1013 | SNDRV_PCM_FMTBIT_S32_LE) | ||
1014 | |||
1015 | static struct snd_soc_dai_ops isabelle_hs_dai_ops = { | ||
1016 | .hw_params = isabelle_hw_params, | ||
1017 | .set_fmt = isabelle_set_dai_fmt, | ||
1018 | .digital_mute = isabelle_hs_mute, | ||
1019 | }; | ||
1020 | |||
1021 | static struct snd_soc_dai_ops isabelle_hf_dai_ops = { | ||
1022 | .hw_params = isabelle_hw_params, | ||
1023 | .set_fmt = isabelle_set_dai_fmt, | ||
1024 | .digital_mute = isabelle_hf_mute, | ||
1025 | }; | ||
1026 | |||
1027 | static struct snd_soc_dai_ops isabelle_line_dai_ops = { | ||
1028 | .hw_params = isabelle_hw_params, | ||
1029 | .set_fmt = isabelle_set_dai_fmt, | ||
1030 | .digital_mute = isabelle_line_mute, | ||
1031 | }; | ||
1032 | |||
1033 | static struct snd_soc_dai_ops isabelle_ul_dai_ops = { | ||
1034 | .hw_params = isabelle_hw_params, | ||
1035 | .set_fmt = isabelle_set_dai_fmt, | ||
1036 | }; | ||
1037 | |||
1038 | /* ISABELLE dai structure */ | ||
1039 | static struct snd_soc_dai_driver isabelle_dai[] = { | ||
1040 | { | ||
1041 | .name = "isabelle-dl1", | ||
1042 | .playback = { | ||
1043 | .stream_name = "Headset Playback", | ||
1044 | .channels_min = 1, | ||
1045 | .channels_max = 2, | ||
1046 | .rates = ISABELLE_RATES, | ||
1047 | .formats = ISABELLE_FORMATS, | ||
1048 | }, | ||
1049 | .ops = &isabelle_hs_dai_ops, | ||
1050 | }, | ||
1051 | { | ||
1052 | .name = "isabelle-dl2", | ||
1053 | .playback = { | ||
1054 | .stream_name = "Handsfree Playback", | ||
1055 | .channels_min = 1, | ||
1056 | .channels_max = 2, | ||
1057 | .rates = ISABELLE_RATES, | ||
1058 | .formats = ISABELLE_FORMATS, | ||
1059 | }, | ||
1060 | .ops = &isabelle_hf_dai_ops, | ||
1061 | }, | ||
1062 | { | ||
1063 | .name = "isabelle-lineout", | ||
1064 | .playback = { | ||
1065 | .stream_name = "Lineout Playback", | ||
1066 | .channels_min = 1, | ||
1067 | .channels_max = 2, | ||
1068 | .rates = ISABELLE_RATES, | ||
1069 | .formats = ISABELLE_FORMATS, | ||
1070 | }, | ||
1071 | .ops = &isabelle_line_dai_ops, | ||
1072 | }, | ||
1073 | { | ||
1074 | .name = "isabelle-ul", | ||
1075 | .capture = { | ||
1076 | .stream_name = "Capture", | ||
1077 | .channels_min = 1, | ||
1078 | .channels_max = 2, | ||
1079 | .rates = ISABELLE_RATES, | ||
1080 | .formats = ISABELLE_FORMATS, | ||
1081 | }, | ||
1082 | .ops = &isabelle_ul_dai_ops, | ||
1083 | }, | ||
1084 | }; | ||
1085 | |||
1086 | static int isabelle_probe(struct snd_soc_codec *codec) | ||
1087 | { | ||
1088 | int ret = 0; | ||
1089 | |||
1090 | codec->control_data = dev_get_regmap(codec->dev, NULL); | ||
1091 | |||
1092 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); | ||
1093 | if (ret < 0) { | ||
1094 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | return 0; | ||
1099 | } | ||
1100 | |||
1101 | static struct snd_soc_codec_driver soc_codec_dev_isabelle = { | ||
1102 | .probe = isabelle_probe, | ||
1103 | .set_bias_level = isabelle_set_bias_level, | ||
1104 | .controls = isabelle_snd_controls, | ||
1105 | .num_controls = ARRAY_SIZE(isabelle_snd_controls), | ||
1106 | .dapm_widgets = isabelle_dapm_widgets, | ||
1107 | .num_dapm_widgets = ARRAY_SIZE(isabelle_dapm_widgets), | ||
1108 | .dapm_routes = isabelle_intercon, | ||
1109 | .num_dapm_routes = ARRAY_SIZE(isabelle_intercon), | ||
1110 | .idle_bias_off = true, | ||
1111 | }; | ||
1112 | |||
1113 | static const struct regmap_config isabelle_regmap_config = { | ||
1114 | .reg_bits = 8, | ||
1115 | .val_bits = 8, | ||
1116 | |||
1117 | .max_register = ISABELLE_MAX_REGISTER, | ||
1118 | .reg_defaults = isabelle_reg_defs, | ||
1119 | .num_reg_defaults = ARRAY_SIZE(isabelle_reg_defs), | ||
1120 | .cache_type = REGCACHE_RBTREE, | ||
1121 | }; | ||
1122 | |||
1123 | static int __devinit isabelle_i2c_probe(struct i2c_client *i2c, | ||
1124 | const struct i2c_device_id *id) | ||
1125 | { | ||
1126 | struct regmap *isabelle_regmap; | ||
1127 | int ret = 0; | ||
1128 | |||
1129 | isabelle_regmap = devm_regmap_init_i2c(i2c, &isabelle_regmap_config); | ||
1130 | if (IS_ERR(isabelle_regmap)) { | ||
1131 | ret = PTR_ERR(isabelle_regmap); | ||
1132 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | ||
1133 | ret); | ||
1134 | return ret; | ||
1135 | } | ||
1136 | i2c_set_clientdata(i2c, isabelle_regmap); | ||
1137 | |||
1138 | ret = snd_soc_register_codec(&i2c->dev, | ||
1139 | &soc_codec_dev_isabelle, isabelle_dai, | ||
1140 | ARRAY_SIZE(isabelle_dai)); | ||
1141 | if (ret < 0) { | ||
1142 | dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); | ||
1143 | return ret; | ||
1144 | } | ||
1145 | |||
1146 | return ret; | ||
1147 | } | ||
1148 | |||
1149 | static int __devexit isabelle_i2c_remove(struct i2c_client *client) | ||
1150 | { | ||
1151 | snd_soc_unregister_codec(&client->dev); | ||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | static const struct i2c_device_id isabelle_i2c_id[] = { | ||
1156 | { "isabelle", 0 }, | ||
1157 | { } | ||
1158 | }; | ||
1159 | MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id); | ||
1160 | |||
1161 | static struct i2c_driver isabelle_i2c_driver = { | ||
1162 | .driver = { | ||
1163 | .name = "isabelle", | ||
1164 | .owner = THIS_MODULE, | ||
1165 | }, | ||
1166 | .probe = isabelle_i2c_probe, | ||
1167 | .remove = __devexit_p(isabelle_i2c_remove), | ||
1168 | .id_table = isabelle_i2c_id, | ||
1169 | }; | ||
1170 | |||
1171 | module_i2c_driver(isabelle_i2c_driver); | ||
1172 | |||
1173 | MODULE_DESCRIPTION("ASoC ISABELLE driver"); | ||
1174 | MODULE_AUTHOR("Vishwas A Deshpande <vishwas.a.deshpande@ti.com>"); | ||
1175 | MODULE_AUTHOR("M R Swami Reddy <MR.Swami.Reddy@ti.com>"); | ||
1176 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/isabelle.h b/sound/soc/codecs/isabelle.h new file mode 100644 index 000000000000..96d839a8c956 --- /dev/null +++ b/sound/soc/codecs/isabelle.h | |||
@@ -0,0 +1,143 @@ | |||
1 | /* | ||
2 | * isabelle.h - Low power high fidelity audio codec driver header file | ||
3 | * | ||
4 | * Copyright (c) 2012 Texas Instruments, Inc | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #ifndef _ISABELLE_H | ||
13 | #define _ISABELLE_H | ||
14 | |||
15 | #include <linux/bitops.h> | ||
16 | |||
17 | /* ISABELLE REGISTERS */ | ||
18 | |||
19 | #define ISABELLE_PWR_CFG_REG 0x01 | ||
20 | #define ISABELLE_PWR_EN_REG 0x02 | ||
21 | #define ISABELLE_PS_EN1_REG 0x03 | ||
22 | #define ISABELLE_INT1_STATUS_REG 0x04 | ||
23 | #define ISABELLE_INT1_MASK_REG 0x05 | ||
24 | #define ISABELLE_INT2_STATUS_REG 0x06 | ||
25 | #define ISABELLE_INT2_MASK_REG 0x07 | ||
26 | #define ISABELLE_HKCTL1_REG 0x08 | ||
27 | #define ISABELLE_HKCTL2_REG 0x09 | ||
28 | #define ISABELLE_HKCTL3_REG 0x0A | ||
29 | #define ISABELLE_ACCDET_STATUS_REG 0x0B | ||
30 | #define ISABELLE_BUTTON_ID_REG 0x0C | ||
31 | #define ISABELLE_PLL_CFG_REG 0x10 | ||
32 | #define ISABELLE_PLL_EN_REG 0x11 | ||
33 | #define ISABELLE_FS_RATE_CFG_REG 0x12 | ||
34 | #define ISABELLE_INTF_CFG_REG 0x13 | ||
35 | #define ISABELLE_INTF_EN_REG 0x14 | ||
36 | #define ISABELLE_ULATX12_INTF_CFG_REG 0x15 | ||
37 | #define ISABELLE_DL12_INTF_CFG_REG 0x16 | ||
38 | #define ISABELLE_DL34_INTF_CFG_REG 0x17 | ||
39 | #define ISABELLE_DL56_INTF_CFG_REG 0x18 | ||
40 | #define ISABELLE_ATX_STPGA1_CFG_REG 0x19 | ||
41 | #define ISABELLE_ATX_STPGA2_CFG_REG 0x1A | ||
42 | #define ISABELLE_VTX_STPGA1_CFG_REG 0x1B | ||
43 | #define ISABELLE_VTX2_STPGA2_CFG_REG 0x1C | ||
44 | #define ISABELLE_ATX1_DPGA_REG 0x1D | ||
45 | #define ISABELLE_ATX2_DPGA_REG 0x1E | ||
46 | #define ISABELLE_VTX1_DPGA_REG 0x1F | ||
47 | #define ISABELLE_VTX2_DPGA_REG 0x20 | ||
48 | #define ISABELLE_TX_INPUT_CFG_REG 0x21 | ||
49 | #define ISABELLE_RX_INPUT_CFG_REG 0x22 | ||
50 | #define ISABELLE_RX_INPUT_CFG2_REG 0x23 | ||
51 | #define ISABELLE_VOICE_HPF_CFG_REG 0x24 | ||
52 | #define ISABELLE_AUDIO_HPF_CFG_REG 0x25 | ||
53 | #define ISABELLE_RX1_DPGA_REG 0x26 | ||
54 | #define ISABELLE_RX2_DPGA_REG 0x27 | ||
55 | #define ISABELLE_RX3_DPGA_REG 0x28 | ||
56 | #define ISABELLE_RX4_DPGA_REG 0x29 | ||
57 | #define ISABELLE_RX5_DPGA_REG 0x2A | ||
58 | #define ISABELLE_RX6_DPGA_REG 0x2B | ||
59 | #define ISABELLE_ALU_TX_EN_REG 0x2C | ||
60 | #define ISABELLE_ALU_RX_EN_REG 0x2D | ||
61 | #define ISABELLE_IIR_RESYNC_REG 0x2E | ||
62 | #define ISABELLE_ABIAS_CFG_REG 0x30 | ||
63 | #define ISABELLE_DBIAS_CFG_REG 0x31 | ||
64 | #define ISABELLE_MIC1_GAIN_REG 0x32 | ||
65 | #define ISABELLE_MIC2_GAIN_REG 0x33 | ||
66 | #define ISABELLE_AMIC_CFG_REG 0x34 | ||
67 | #define ISABELLE_DMIC_CFG_REG 0x35 | ||
68 | #define ISABELLE_APGA_GAIN_REG 0x36 | ||
69 | #define ISABELLE_APGA_CFG_REG 0x37 | ||
70 | #define ISABELLE_TX_GAIN_DLY_REG 0x38 | ||
71 | #define ISABELLE_RX_GAIN_DLY_REG 0x39 | ||
72 | #define ISABELLE_RX_PWR_CTRL_REG 0x3A | ||
73 | #define ISABELLE_DPGA1LR_IN_SEL_REG 0x3B | ||
74 | #define ISABELLE_DPGA1L_GAIN_REG 0x3C | ||
75 | #define ISABELLE_DPGA1R_GAIN_REG 0x3D | ||
76 | #define ISABELLE_DPGA2L_IN_SEL_REG 0x3E | ||
77 | #define ISABELLE_DPGA2R_IN_SEL_REG 0x3F | ||
78 | #define ISABELLE_DPGA2L_GAIN_REG 0x40 | ||
79 | #define ISABELLE_DPGA2R_GAIN_REG 0x41 | ||
80 | #define ISABELLE_DPGA3LR_IN_SEL_REG 0x42 | ||
81 | #define ISABELLE_DPGA3L_GAIN_REG 0x43 | ||
82 | #define ISABELLE_DPGA3R_GAIN_REG 0x44 | ||
83 | #define ISABELLE_DAC1_SOFTRAMP_REG 0x45 | ||
84 | #define ISABELLE_DAC2_SOFTRAMP_REG 0x46 | ||
85 | #define ISABELLE_DAC3_SOFTRAMP_REG 0x47 | ||
86 | #define ISABELLE_DAC_CFG_REG 0x48 | ||
87 | #define ISABELLE_EARDRV_CFG1_REG 0x49 | ||
88 | #define ISABELLE_EARDRV_CFG2_REG 0x4A | ||
89 | #define ISABELLE_HSDRV_GAIN_REG 0x4B | ||
90 | #define ISABELLE_HSDRV_CFG1_REG 0x4C | ||
91 | #define ISABELLE_HSDRV_CFG2_REG 0x4D | ||
92 | #define ISABELLE_HS_NG_CFG1_REG 0x4E | ||
93 | #define ISABELLE_HS_NG_CFG2_REG 0x4F | ||
94 | #define ISABELLE_LINEAMP_GAIN_REG 0x50 | ||
95 | #define ISABELLE_LINEAMP_CFG_REG 0x51 | ||
96 | #define ISABELLE_HFL_VOL_CTRL_REG 0x52 | ||
97 | #define ISABELLE_HFL_SFTVOL_CTRL_REG 0x53 | ||
98 | #define ISABELLE_HFL_LIM_CTRL_1_REG 0x54 | ||
99 | #define ISABELLE_HFL_LIM_CTRL_2_REG 0x55 | ||
100 | #define ISABELLE_HFR_VOL_CTRL_REG 0x56 | ||
101 | #define ISABELLE_HFR_SFTVOL_CTRL_REG 0x57 | ||
102 | #define ISABELLE_HFR_LIM_CTRL_1_REG 0x58 | ||
103 | #define ISABELLE_HFR_LIM_CTRL_2_REG 0x59 | ||
104 | #define ISABELLE_HF_MODE_REG 0x5A | ||
105 | #define ISABELLE_HFLPGA_CFG_REG 0x5B | ||
106 | #define ISABELLE_HFRPGA_CFG_REG 0x5C | ||
107 | #define ISABELLE_HFDRV_CFG_REG 0x5D | ||
108 | #define ISABELLE_PDMOUT_CFG1_REG 0x5E | ||
109 | #define ISABELLE_PDMOUT_CFG2_REG 0x5F | ||
110 | #define ISABELLE_PDMOUT_L_WM_REG 0x60 | ||
111 | #define ISABELLE_PDMOUT_R_WM_REG 0x61 | ||
112 | #define ISABELLE_HF_NG_CFG1_REG 0x62 | ||
113 | #define ISABELLE_HF_NG_CFG2_REG 0x63 | ||
114 | |||
115 | /* ISABELLE_PWR_EN_REG (0x02h) */ | ||
116 | #define ISABELLE_CHIP_EN BIT(0) | ||
117 | |||
118 | /* ISABELLE DAI FORMATS */ | ||
119 | #define ISABELLE_AIF_FMT_MASK 0x70 | ||
120 | #define ISABELLE_I2S_MODE 0x0 | ||
121 | #define ISABELLE_LEFT_J_MODE 0x1 | ||
122 | #define ISABELLE_PDM_MODE 0x2 | ||
123 | |||
124 | #define ISABELLE_AIF_LENGTH_MASK 0x30 | ||
125 | #define ISABELLE_AIF_LENGTH_20 0x00 | ||
126 | #define ISABELLE_AIF_LENGTH_32 0x10 | ||
127 | |||
128 | #define ISABELLE_AIF_MS 0x80 | ||
129 | |||
130 | #define ISABELLE_FS_RATE_MASK 0xF | ||
131 | #define ISABELLE_FS_RATE_8 0x0 | ||
132 | #define ISABELLE_FS_RATE_11 0x1 | ||
133 | #define ISABELLE_FS_RATE_12 0x2 | ||
134 | #define ISABELLE_FS_RATE_16 0x4 | ||
135 | #define ISABELLE_FS_RATE_22 0x5 | ||
136 | #define ISABELLE_FS_RATE_24 0x6 | ||
137 | #define ISABELLE_FS_RATE_32 0x8 | ||
138 | #define ISABELLE_FS_RATE_44 0x9 | ||
139 | #define ISABELLE_FS_RATE_48 0xA | ||
140 | |||
141 | #define ISABELLE_MAX_REGISTER 0xFF | ||
142 | |||
143 | #endif | ||
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 802b9f176b16..99b0a9dcff34 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -12,7 +12,6 @@ | |||
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | 14 | #include <linux/moduleparam.h> |
15 | #include <linux/version.h> | ||
16 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
17 | #include <linux/init.h> | 16 | #include <linux/init.h> |
18 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
@@ -1358,7 +1357,7 @@ static struct snd_soc_dai_ops lm49453_lineout_dai_ops = { | |||
1358 | }; | 1357 | }; |
1359 | 1358 | ||
1360 | /* LM49453 dai structure. */ | 1359 | /* LM49453 dai structure. */ |
1361 | static const struct snd_soc_dai_driver lm49453_dai[] = { | 1360 | static struct snd_soc_dai_driver lm49453_dai[] = { |
1362 | { | 1361 | { |
1363 | .name = "LM49453 Headset", | 1362 | .name = "LM49453 Headset", |
1364 | .playback = { | 1363 | .playback = { |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 35179e2c23c9..7cd508e16a5c 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -2216,7 +2216,7 @@ static irqreturn_t max98095_report_jack(int irq, void *data) | |||
2216 | return IRQ_HANDLED; | 2216 | return IRQ_HANDLED; |
2217 | } | 2217 | } |
2218 | 2218 | ||
2219 | int max98095_jack_detect_enable(struct snd_soc_codec *codec) | 2219 | static int max98095_jack_detect_enable(struct snd_soc_codec *codec) |
2220 | { | 2220 | { |
2221 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); | 2221 | struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); |
2222 | int ret = 0; | 2222 | int ret = 0; |
@@ -2245,7 +2245,7 @@ int max98095_jack_detect_enable(struct snd_soc_codec *codec) | |||
2245 | return ret; | 2245 | return ret; |
2246 | } | 2246 | } |
2247 | 2247 | ||
2248 | int max98095_jack_detect_disable(struct snd_soc_codec *codec) | 2248 | static int max98095_jack_detect_disable(struct snd_soc_codec *codec) |
2249 | { | 2249 | { |
2250 | int ret = 0; | 2250 | int ret = 0; |
2251 | 2251 | ||
@@ -2286,6 +2286,7 @@ int max98095_jack_detect(struct snd_soc_codec *codec, | |||
2286 | max98095_report_jack(client->irq, codec); | 2286 | max98095_report_jack(client->irq, codec); |
2287 | return 0; | 2287 | return 0; |
2288 | } | 2288 | } |
2289 | EXPORT_SYMBOL_GPL(max98095_jack_detect); | ||
2289 | 2290 | ||
2290 | #ifdef CONFIG_PM | 2291 | #ifdef CONFIG_PM |
2291 | static int max98095_suspend(struct snd_soc_codec *codec) | 2292 | static int max98095_suspend(struct snd_soc_codec *codec) |
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 22cb5bf59273..96aa5fa05160 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c | |||
@@ -638,7 +638,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c, | |||
638 | 638 | ||
639 | i2c_set_clientdata(i2c, priv); | 639 | i2c_set_clientdata(i2c, priv); |
640 | 640 | ||
641 | priv->regmap = regmap_init_i2c(i2c, &ml26124_i2c_regmap); | 641 | priv->regmap = devm_regmap_init_i2c(i2c, &ml26124_i2c_regmap); |
642 | if (IS_ERR(priv->regmap)) { | 642 | if (IS_ERR(priv->regmap)) { |
643 | ret = PTR_ERR(priv->regmap); | 643 | ret = PTR_ERR(priv->regmap); |
644 | dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret); | 644 | dev_err(&i2c->dev, "regmap_init_i2c() failed: %d\n", ret); |
@@ -651,10 +651,7 @@ static __devinit int ml26124_i2c_probe(struct i2c_client *i2c, | |||
651 | 651 | ||
652 | static __devexit int ml26124_i2c_remove(struct i2c_client *client) | 652 | static __devexit int ml26124_i2c_remove(struct i2c_client *client) |
653 | { | 653 | { |
654 | struct ml26124_priv *priv = i2c_get_clientdata(client); | ||
655 | |||
656 | snd_soc_unregister_codec(&client->dev); | 654 | snd_soc_unregister_codec(&client->dev); |
657 | regmap_exit(priv->regmap); | ||
658 | return 0; | 655 | return 0; |
659 | } | 656 | } |
660 | 657 | ||
diff --git a/sound/soc/codecs/spdif_receiver.c b/sound/soc/codecs/spdif_receiver.c new file mode 100644 index 000000000000..dd8d856053fc --- /dev/null +++ b/sound/soc/codecs/spdif_receiver.c | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * ALSA SoC SPDIF DIR (Digital Interface Reciever) driver | ||
3 | * | ||
4 | * Based on ALSA SoC SPDIF DIT driver | ||
5 | * | ||
6 | * This driver is used by controllers which can operate in DIR (SPDI/F) where | ||
7 | * no codec is needed. This file provides stub codec that can be used | ||
8 | * in these configurations. SPEAr SPDIF IN Audio controller uses this driver. | ||
9 | * | ||
10 | * Author: Vipin Kumar, <vipin.kumar@st.com> | ||
11 | * Copyright: (C) 2012 ST Microelectronics | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * published by the Free Software Foundation. | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/initval.h> | ||
24 | |||
25 | #define STUB_RATES SNDRV_PCM_RATE_8000_192000 | ||
26 | #define STUB_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
27 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) | ||
28 | |||
29 | static struct snd_soc_codec_driver soc_codec_spdif_dir; | ||
30 | |||
31 | static struct snd_soc_dai_driver dir_stub_dai = { | ||
32 | .name = "dir-hifi", | ||
33 | .capture = { | ||
34 | .stream_name = "Capture", | ||
35 | .channels_min = 1, | ||
36 | .channels_max = 384, | ||
37 | .rates = STUB_RATES, | ||
38 | .formats = STUB_FORMATS, | ||
39 | }, | ||
40 | }; | ||
41 | |||
42 | static int spdif_dir_probe(struct platform_device *pdev) | ||
43 | { | ||
44 | return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dir, | ||
45 | &dir_stub_dai, 1); | ||
46 | } | ||
47 | |||
48 | static int spdif_dir_remove(struct platform_device *pdev) | ||
49 | { | ||
50 | snd_soc_unregister_codec(&pdev->dev); | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | static struct platform_driver spdif_dir_driver = { | ||
55 | .probe = spdif_dir_probe, | ||
56 | .remove = spdif_dir_remove, | ||
57 | .driver = { | ||
58 | .name = "spdif-dir", | ||
59 | .owner = THIS_MODULE, | ||
60 | }, | ||
61 | }; | ||
62 | |||
63 | module_platform_driver(spdif_dir_driver); | ||
64 | |||
65 | MODULE_DESCRIPTION("ASoC SPDIF DIR driver"); | ||
66 | MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>"); | ||
67 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c new file mode 100644 index 000000000000..0c225cd569d2 --- /dev/null +++ b/sound/soc/codecs/sta529.c | |||
@@ -0,0 +1,442 @@ | |||
1 | /* | ||
2 | * ASoC codec driver for spear platform | ||
3 | * | ||
4 | * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver | ||
5 | * | ||
6 | * Copyright (C) 2012 ST Microelectronics | ||
7 | * Rajeev Kumar <rajeev-dlh.kumar@st.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/moduleparam.h> | ||
20 | #include <linux/pm.h> | ||
21 | #include <linux/regmap.h> | ||
22 | #include <linux/slab.h> | ||
23 | |||
24 | #include <sound/core.h> | ||
25 | #include <sound/initval.h> | ||
26 | #include <sound/pcm.h> | ||
27 | #include <sound/pcm_params.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/soc-dapm.h> | ||
30 | #include <sound/tlv.h> | ||
31 | |||
32 | /* STA529 Register offsets */ | ||
33 | #define STA529_FFXCFG0 0x00 | ||
34 | #define STA529_FFXCFG1 0x01 | ||
35 | #define STA529_MVOL 0x02 | ||
36 | #define STA529_LVOL 0x03 | ||
37 | #define STA529_RVOL 0x04 | ||
38 | #define STA529_TTF0 0x05 | ||
39 | #define STA529_TTF1 0x06 | ||
40 | #define STA529_TTP0 0x07 | ||
41 | #define STA529_TTP1 0x08 | ||
42 | #define STA529_S2PCFG0 0x0A | ||
43 | #define STA529_S2PCFG1 0x0B | ||
44 | #define STA529_P2SCFG0 0x0C | ||
45 | #define STA529_P2SCFG1 0x0D | ||
46 | #define STA529_PLLCFG0 0x14 | ||
47 | #define STA529_PLLCFG1 0x15 | ||
48 | #define STA529_PLLCFG2 0x16 | ||
49 | #define STA529_PLLCFG3 0x17 | ||
50 | #define STA529_PLLPFE 0x18 | ||
51 | #define STA529_PLLST 0x19 | ||
52 | #define STA529_ADCCFG 0x1E /*mic_select*/ | ||
53 | #define STA529_CKOCFG 0x1F | ||
54 | #define STA529_MISC 0x20 | ||
55 | #define STA529_PADST0 0x21 | ||
56 | #define STA529_PADST1 0x22 | ||
57 | #define STA529_FFXST 0x23 | ||
58 | #define STA529_PWMIN1 0x2D | ||
59 | #define STA529_PWMIN2 0x2E | ||
60 | #define STA529_POWST 0x32 | ||
61 | |||
62 | #define STA529_MAX_REGISTER 0x32 | ||
63 | |||
64 | #define STA529_RATES (SNDRV_PCM_RATE_8000 | \ | ||
65 | SNDRV_PCM_RATE_11025 | \ | ||
66 | SNDRV_PCM_RATE_16000 | \ | ||
67 | SNDRV_PCM_RATE_22050 | \ | ||
68 | SNDRV_PCM_RATE_32000 | \ | ||
69 | SNDRV_PCM_RATE_44100 | \ | ||
70 | SNDRV_PCM_RATE_48000) | ||
71 | |||
72 | #define STA529_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
73 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
74 | SNDRV_PCM_FMTBIT_S32_LE) | ||
75 | #define S2PC_VALUE 0x98 | ||
76 | #define CLOCK_OUT 0x60 | ||
77 | #define LEFT_J_DATA_FORMAT 0x10 | ||
78 | #define I2S_DATA_FORMAT 0x12 | ||
79 | #define RIGHT_J_DATA_FORMAT 0x14 | ||
80 | #define CODEC_MUTE_VAL 0x80 | ||
81 | |||
82 | #define POWER_CNTLMSAK 0x40 | ||
83 | #define POWER_STDBY 0x40 | ||
84 | #define FFX_MASK 0x80 | ||
85 | #define FFX_OFF 0x80 | ||
86 | #define POWER_UP 0x00 | ||
87 | #define FFX_CLK_ENB 0x01 | ||
88 | #define FFX_CLK_DIS 0x00 | ||
89 | #define FFX_CLK_MSK 0x01 | ||
90 | #define PLAY_FREQ_RANGE_MSK 0x70 | ||
91 | #define CAP_FREQ_RANGE_MSK 0x0C | ||
92 | #define PDATA_LEN_MSK 0xC0 | ||
93 | #define BCLK_TO_FS_MSK 0x30 | ||
94 | #define AUDIO_MUTE_MSK 0x80 | ||
95 | |||
96 | static const struct reg_default sta529_reg_defaults[] = { | ||
97 | { 0, 0x35 }, /* R0 - FFX Configuration reg 0 */ | ||
98 | { 1, 0xc8 }, /* R1 - FFX Configuration reg 1 */ | ||
99 | { 2, 0x50 }, /* R2 - Master Volume */ | ||
100 | { 3, 0x00 }, /* R3 - Left Volume */ | ||
101 | { 4, 0x00 }, /* R4 - Right Volume */ | ||
102 | { 10, 0xb2 }, /* R10 - S2P Config Reg 0 */ | ||
103 | { 11, 0x41 }, /* R11 - S2P Config Reg 1 */ | ||
104 | { 12, 0x92 }, /* R12 - P2S Config Reg 0 */ | ||
105 | { 13, 0x41 }, /* R13 - P2S Config Reg 1 */ | ||
106 | { 30, 0xd2 }, /* R30 - ADC Config Reg */ | ||
107 | { 31, 0x40 }, /* R31 - clock Out Reg */ | ||
108 | { 32, 0x21 }, /* R32 - Misc Register */ | ||
109 | }; | ||
110 | |||
111 | struct sta529 { | ||
112 | struct regmap *regmap; | ||
113 | }; | ||
114 | |||
115 | static bool sta529_readable(struct device *dev, unsigned int reg) | ||
116 | { | ||
117 | switch (reg) { | ||
118 | |||
119 | case STA529_FFXCFG0: | ||
120 | case STA529_FFXCFG1: | ||
121 | case STA529_MVOL: | ||
122 | case STA529_LVOL: | ||
123 | case STA529_RVOL: | ||
124 | case STA529_S2PCFG0: | ||
125 | case STA529_S2PCFG1: | ||
126 | case STA529_P2SCFG0: | ||
127 | case STA529_P2SCFG1: | ||
128 | case STA529_ADCCFG: | ||
129 | case STA529_CKOCFG: | ||
130 | case STA529_MISC: | ||
131 | return true; | ||
132 | default: | ||
133 | return false; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | |||
138 | static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary", | ||
139 | "Phase-shift"}; | ||
140 | |||
141 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); | ||
142 | static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); | ||
143 | static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); | ||
144 | |||
145 | static const struct snd_kcontrol_new sta529_snd_controls[] = { | ||
146 | SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, | ||
147 | 127, 0, out_gain_tlv), | ||
148 | SOC_SINGLE_TLV("Master Playback Volume", STA529_MVOL, 0, 127, 1, | ||
149 | master_vol_tlv), | ||
150 | SOC_ENUM("PWM Select", pwm_src), | ||
151 | }; | ||
152 | |||
153 | static int sta529_set_bias_level(struct snd_soc_codec *codec, enum | ||
154 | snd_soc_bias_level level) | ||
155 | { | ||
156 | struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec); | ||
157 | |||
158 | switch (level) { | ||
159 | case SND_SOC_BIAS_ON: | ||
160 | case SND_SOC_BIAS_PREPARE: | ||
161 | snd_soc_update_bits(codec, STA529_FFXCFG0, POWER_CNTLMSAK, | ||
162 | POWER_UP); | ||
163 | snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK, | ||
164 | FFX_CLK_ENB); | ||
165 | break; | ||
166 | case SND_SOC_BIAS_STANDBY: | ||
167 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
168 | regcache_sync(sta529->regmap); | ||
169 | snd_soc_update_bits(codec, STA529_FFXCFG0, | ||
170 | POWER_CNTLMSAK, POWER_STDBY); | ||
171 | /* Making FFX output to zero */ | ||
172 | snd_soc_update_bits(codec, STA529_FFXCFG0, FFX_MASK, | ||
173 | FFX_OFF); | ||
174 | snd_soc_update_bits(codec, STA529_MISC, FFX_CLK_MSK, | ||
175 | FFX_CLK_DIS); | ||
176 | break; | ||
177 | case SND_SOC_BIAS_OFF: | ||
178 | break; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * store the label for powers down audio subsystem for suspend.This is | ||
183 | * used by soc core layer | ||
184 | */ | ||
185 | codec->dapm.bias_level = level; | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | } | ||
190 | |||
191 | static int sta529_hw_params(struct snd_pcm_substream *substream, | ||
192 | struct snd_pcm_hw_params *params, | ||
193 | struct snd_soc_dai *dai) | ||
194 | { | ||
195 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
196 | struct snd_soc_codec *codec = rtd->codec; | ||
197 | int pdata, play_freq_val, record_freq_val; | ||
198 | int bclk_to_fs_ratio; | ||
199 | |||
200 | switch (params_format(params)) { | ||
201 | case SNDRV_PCM_FORMAT_S16_LE: | ||
202 | pdata = 1; | ||
203 | bclk_to_fs_ratio = 0; | ||
204 | break; | ||
205 | case SNDRV_PCM_FORMAT_S24_LE: | ||
206 | pdata = 2; | ||
207 | bclk_to_fs_ratio = 1; | ||
208 | break; | ||
209 | case SNDRV_PCM_FORMAT_S32_LE: | ||
210 | pdata = 3; | ||
211 | bclk_to_fs_ratio = 2; | ||
212 | break; | ||
213 | default: | ||
214 | dev_err(codec->dev, "Unsupported format\n"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | switch (params_rate(params)) { | ||
219 | case 8000: | ||
220 | case 11025: | ||
221 | play_freq_val = 0; | ||
222 | record_freq_val = 2; | ||
223 | break; | ||
224 | case 16000: | ||
225 | case 22050: | ||
226 | play_freq_val = 1; | ||
227 | record_freq_val = 0; | ||
228 | break; | ||
229 | |||
230 | case 32000: | ||
231 | case 44100: | ||
232 | case 48000: | ||
233 | play_freq_val = 2; | ||
234 | record_freq_val = 0; | ||
235 | break; | ||
236 | default: | ||
237 | dev_err(codec->dev, "Unsupported rate\n"); | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
242 | snd_soc_update_bits(codec, STA529_S2PCFG1, PDATA_LEN_MSK, | ||
243 | pdata << 6); | ||
244 | snd_soc_update_bits(codec, STA529_S2PCFG1, BCLK_TO_FS_MSK, | ||
245 | bclk_to_fs_ratio << 4); | ||
246 | snd_soc_update_bits(codec, STA529_MISC, PLAY_FREQ_RANGE_MSK, | ||
247 | play_freq_val << 4); | ||
248 | } else { | ||
249 | snd_soc_update_bits(codec, STA529_P2SCFG1, PDATA_LEN_MSK, | ||
250 | pdata << 6); | ||
251 | snd_soc_update_bits(codec, STA529_P2SCFG1, BCLK_TO_FS_MSK, | ||
252 | bclk_to_fs_ratio << 4); | ||
253 | snd_soc_update_bits(codec, STA529_MISC, CAP_FREQ_RANGE_MSK, | ||
254 | record_freq_val << 2); | ||
255 | } | ||
256 | |||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int sta529_mute(struct snd_soc_dai *dai, int mute) | ||
261 | { | ||
262 | u8 val = 0; | ||
263 | |||
264 | if (mute) | ||
265 | val |= CODEC_MUTE_VAL; | ||
266 | |||
267 | snd_soc_update_bits(dai->codec, STA529_FFXCFG0, AUDIO_MUTE_MSK, val); | ||
268 | |||
269 | return 0; | ||
270 | } | ||
271 | |||
272 | static int sta529_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) | ||
273 | { | ||
274 | struct snd_soc_codec *codec = codec_dai->codec; | ||
275 | u8 mode = 0; | ||
276 | |||
277 | /* interface format */ | ||
278 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
279 | case SND_SOC_DAIFMT_LEFT_J: | ||
280 | mode = LEFT_J_DATA_FORMAT; | ||
281 | break; | ||
282 | case SND_SOC_DAIFMT_I2S: | ||
283 | mode = I2S_DATA_FORMAT; | ||
284 | break; | ||
285 | case SND_SOC_DAIFMT_RIGHT_J: | ||
286 | mode = RIGHT_J_DATA_FORMAT; | ||
287 | break; | ||
288 | default: | ||
289 | return -EINVAL; | ||
290 | } | ||
291 | |||
292 | snd_soc_update_bits(codec, STA529_S2PCFG0, 0x0D, mode); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static const struct snd_soc_dai_ops sta529_dai_ops = { | ||
298 | .hw_params = sta529_hw_params, | ||
299 | .set_fmt = sta529_set_dai_fmt, | ||
300 | .digital_mute = sta529_mute, | ||
301 | }; | ||
302 | |||
303 | static struct snd_soc_dai_driver sta529_dai = { | ||
304 | .name = "sta529-audio", | ||
305 | .playback = { | ||
306 | .stream_name = "Playback", | ||
307 | .channels_min = 2, | ||
308 | .channels_max = 2, | ||
309 | .rates = STA529_RATES, | ||
310 | .formats = STA529_FORMAT, | ||
311 | }, | ||
312 | .capture = { | ||
313 | .stream_name = "Capture", | ||
314 | .channels_min = 2, | ||
315 | .channels_max = 2, | ||
316 | .rates = STA529_RATES, | ||
317 | .formats = STA529_FORMAT, | ||
318 | }, | ||
319 | .ops = &sta529_dai_ops, | ||
320 | }; | ||
321 | |||
322 | static int sta529_probe(struct snd_soc_codec *codec) | ||
323 | { | ||
324 | struct sta529 *sta529 = snd_soc_codec_get_drvdata(codec); | ||
325 | int ret; | ||
326 | |||
327 | codec->control_data = sta529->regmap; | ||
328 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); | ||
329 | |||
330 | if (ret < 0) { | ||
331 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
332 | return ret; | ||
333 | } | ||
334 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | /* power down chip */ | ||
340 | static int sta529_remove(struct snd_soc_codec *codec) | ||
341 | { | ||
342 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
343 | |||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | static int sta529_suspend(struct snd_soc_codec *codec) | ||
348 | { | ||
349 | sta529_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int sta529_resume(struct snd_soc_codec *codec) | ||
355 | { | ||
356 | sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
357 | |||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | struct snd_soc_codec_driver sta529_codec_driver = { | ||
362 | .probe = sta529_probe, | ||
363 | .remove = sta529_remove, | ||
364 | .set_bias_level = sta529_set_bias_level, | ||
365 | .suspend = sta529_suspend, | ||
366 | .resume = sta529_resume, | ||
367 | .controls = sta529_snd_controls, | ||
368 | .num_controls = ARRAY_SIZE(sta529_snd_controls), | ||
369 | }; | ||
370 | |||
371 | static const struct regmap_config sta529_regmap = { | ||
372 | .reg_bits = 8, | ||
373 | .val_bits = 8, | ||
374 | |||
375 | .max_register = STA529_MAX_REGISTER, | ||
376 | .readable_reg = sta529_readable, | ||
377 | |||
378 | .cache_type = REGCACHE_RBTREE, | ||
379 | .reg_defaults = sta529_reg_defaults, | ||
380 | .num_reg_defaults = ARRAY_SIZE(sta529_reg_defaults), | ||
381 | }; | ||
382 | |||
383 | static __devinit int sta529_i2c_probe(struct i2c_client *i2c, | ||
384 | const struct i2c_device_id *id) | ||
385 | { | ||
386 | struct sta529 *sta529; | ||
387 | int ret; | ||
388 | |||
389 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
390 | return -EINVAL; | ||
391 | |||
392 | sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL); | ||
393 | if (sta529 == NULL) { | ||
394 | dev_err(&i2c->dev, "Can not allocate memory\n"); | ||
395 | return -ENOMEM; | ||
396 | } | ||
397 | |||
398 | sta529->regmap = devm_regmap_init_i2c(i2c, &sta529_regmap); | ||
399 | if (IS_ERR(sta529->regmap)) { | ||
400 | ret = PTR_ERR(sta529->regmap); | ||
401 | dev_err(&i2c->dev, "Failed to allocate regmap: %d\n", ret); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | i2c_set_clientdata(i2c, sta529); | ||
406 | |||
407 | ret = snd_soc_register_codec(&i2c->dev, | ||
408 | &sta529_codec_driver, &sta529_dai, 1); | ||
409 | if (ret != 0) | ||
410 | dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int __devexit sta529_i2c_remove(struct i2c_client *client) | ||
416 | { | ||
417 | snd_soc_unregister_codec(&client->dev); | ||
418 | |||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static const struct i2c_device_id sta529_i2c_id[] = { | ||
423 | { "sta529", 0 }, | ||
424 | { } | ||
425 | }; | ||
426 | MODULE_DEVICE_TABLE(i2c, sta529_i2c_id); | ||
427 | |||
428 | static struct i2c_driver sta529_i2c_driver = { | ||
429 | .driver = { | ||
430 | .name = "sta529", | ||
431 | .owner = THIS_MODULE, | ||
432 | }, | ||
433 | .probe = sta529_i2c_probe, | ||
434 | .remove = __devexit_p(sta529_i2c_remove), | ||
435 | .id_table = sta529_i2c_id, | ||
436 | }; | ||
437 | |||
438 | module_i2c_driver(sta529_i2c_driver); | ||
439 | |||
440 | MODULE_DESCRIPTION("ASoC STA529 codec driver"); | ||
441 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | ||
442 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index e9b62b5ea637..dc78f5a4bcbf 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -118,7 +118,9 @@ static const u8 aic3x_reg[AIC3X_CACHEREGNUM] = { | |||
118 | 0x00, 0x00, 0x00, 0x00, /* 88 */ | 118 | 0x00, 0x00, 0x00, 0x00, /* 88 */ |
119 | 0x00, 0x00, 0x00, 0x00, /* 92 */ | 119 | 0x00, 0x00, 0x00, 0x00, /* 92 */ |
120 | 0x00, 0x00, 0x00, 0x00, /* 96 */ | 120 | 0x00, 0x00, 0x00, 0x00, /* 96 */ |
121 | 0x00, 0x00, 0x02, /* 100 */ | 121 | 0x00, 0x00, 0x02, 0x00, /* 100 */ |
122 | 0x00, 0x00, 0x00, 0x00, /* 104 */ | ||
123 | 0x00, 0x00, /* 108 */ | ||
122 | }; | 124 | }; |
123 | 125 | ||
124 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ | 126 | #define SOC_DAPM_SINGLE_AIC3X(xname, reg, shift, mask, invert) \ |
@@ -229,6 +231,25 @@ static const struct soc_enum aic3x_enum[] = { | |||
229 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), | 231 | SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf), |
230 | }; | 232 | }; |
231 | 233 | ||
234 | static const char *aic3x_agc_level[] = | ||
235 | { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" }; | ||
236 | static const struct soc_enum aic3x_agc_level_enum[] = { | ||
237 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level), | ||
238 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level), | ||
239 | }; | ||
240 | |||
241 | static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" }; | ||
242 | static const struct soc_enum aic3x_agc_attack_enum[] = { | ||
243 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack), | ||
244 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack), | ||
245 | }; | ||
246 | |||
247 | static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" }; | ||
248 | static const struct soc_enum aic3x_agc_decay_enum[] = { | ||
249 | SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay), | ||
250 | SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay), | ||
251 | }; | ||
252 | |||
232 | /* | 253 | /* |
233 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps | 254 | * DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps |
234 | */ | 255 | */ |
@@ -353,6 +374,15 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
353 | * adjust PGA to max value when ADC is on and will never go back. | 374 | * adjust PGA to max value when ADC is on and will never go back. |
354 | */ | 375 | */ |
355 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), | 376 | SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0), |
377 | SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]), | ||
378 | SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]), | ||
379 | SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]), | ||
380 | SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]), | ||
381 | SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]), | ||
382 | SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]), | ||
383 | |||
384 | /* De-emphasis */ | ||
385 | SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0), | ||
356 | 386 | ||
357 | /* Input */ | 387 | /* Input */ |
358 | SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL, | 388 | SOC_DOUBLE_R_TLV("PGA Capture Volume", LADC_VOL, RADC_VOL, |
@@ -368,7 +398,7 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = { | |||
368 | static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); | 398 | static DECLARE_TLV_DB_SCALE(classd_amp_tlv, 0, 600, 0); |
369 | 399 | ||
370 | static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = | 400 | static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl = |
371 | SOC_DOUBLE_TLV("Class-D Amplifier Gain", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); | 401 | SOC_DOUBLE_TLV("Class-D Playback Volume", CLASSD_CTRL, 6, 4, 3, 0, classd_amp_tlv); |
372 | 402 | ||
373 | /* Left DAC Mux */ | 403 | /* Left DAC Mux */ |
374 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = | 404 | static const struct snd_kcontrol_new aic3x_left_dac_mux_controls = |
@@ -970,6 +1000,12 @@ static int aic3x_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
970 | struct snd_soc_codec *codec = codec_dai->codec; | 1000 | struct snd_soc_codec *codec = codec_dai->codec; |
971 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); | 1001 | struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec); |
972 | 1002 | ||
1003 | /* set clock on MCLK or GPIO2 or BCLK */ | ||
1004 | snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, PLLCLK_IN_MASK, | ||
1005 | clk_id << PLLCLK_IN_SHIFT); | ||
1006 | snd_soc_update_bits(codec, AIC3X_CLKGEN_CTRL_REG, CLKDIV_IN_MASK, | ||
1007 | clk_id << CLKDIV_IN_SHIFT); | ||
1008 | |||
973 | aic3x->sysclk = freq; | 1009 | aic3x->sysclk = freq; |
974 | return 0; | 1010 | return 0; |
975 | } | 1011 | } |
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index 08c7f6685ff0..6db3c41b0163 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -13,7 +13,7 @@ | |||
13 | #define _AIC3X_H | 13 | #define _AIC3X_H |
14 | 14 | ||
15 | /* AIC3X register space */ | 15 | /* AIC3X register space */ |
16 | #define AIC3X_CACHEREGNUM 103 | 16 | #define AIC3X_CACHEREGNUM 110 |
17 | 17 | ||
18 | /* Page select register */ | 18 | /* Page select register */ |
19 | #define AIC3X_PAGE_SELECT 0 | 19 | #define AIC3X_PAGE_SELECT 0 |
@@ -74,6 +74,8 @@ | |||
74 | #define HPLCOM_CFG 37 | 74 | #define HPLCOM_CFG 37 |
75 | /* Right High Power Output control registers */ | 75 | /* Right High Power Output control registers */ |
76 | #define HPRCOM_CFG 38 | 76 | #define HPRCOM_CFG 38 |
77 | /* High Power Output Stage Control Register */ | ||
78 | #define HPOUT_SC 40 | ||
77 | /* DAC Output Switching control registers */ | 79 | /* DAC Output Switching control registers */ |
78 | #define DAC_LINE_MUX 41 | 80 | #define DAC_LINE_MUX 41 |
79 | /* High Power Output Driver Pop Reduction registers */ | 81 | /* High Power Output Driver Pop Reduction registers */ |
@@ -148,6 +150,17 @@ | |||
148 | #define AIC3X_GPIOB_REG 101 | 150 | #define AIC3X_GPIOB_REG 101 |
149 | /* Clock generation control register */ | 151 | /* Clock generation control register */ |
150 | #define AIC3X_CLKGEN_CTRL_REG 102 | 152 | #define AIC3X_CLKGEN_CTRL_REG 102 |
153 | /* New AGC registers */ | ||
154 | #define LAGCN_ATTACK 103 | ||
155 | #define LAGCN_DECAY 104 | ||
156 | #define RAGCN_ATTACK 105 | ||
157 | #define RAGCN_DECAY 106 | ||
158 | /* New Programmable ADC Digital Path and I2C Bus Condition Register */ | ||
159 | #define NEW_ADC_DIGITALPATH 107 | ||
160 | /* Passive Analog Signal Bypass Selection During Powerdown Register */ | ||
161 | #define PASSIVE_BYPASS 108 | ||
162 | /* DAC Quiescent Current Adjustment Register */ | ||
163 | #define DAC_ICC_ADJ 109 | ||
151 | 164 | ||
152 | /* Page select register bits */ | 165 | /* Page select register bits */ |
153 | #define PAGE0_SELECT 0 | 166 | #define PAGE0_SELECT 0 |
@@ -163,6 +176,10 @@ | |||
163 | #define DUAL_RATE_MODE ((1 << 5) | (1 << 6)) | 176 | #define DUAL_RATE_MODE ((1 << 5) | (1 << 6)) |
164 | #define LDAC2LCH (0x1 << 3) | 177 | #define LDAC2LCH (0x1 << 3) |
165 | #define RDAC2RCH (0x1 << 1) | 178 | #define RDAC2RCH (0x1 << 1) |
179 | #define LDAC2RCH (0x2 << 3) | ||
180 | #define RDAC2LCH (0x2 << 1) | ||
181 | #define LDAC2MONOMIX (0x3 << 3) | ||
182 | #define RDAC2MONOMIX (0x3 << 1) | ||
166 | 183 | ||
167 | /* PLL registers bitfields */ | 184 | /* PLL registers bitfields */ |
168 | #define PLLP_SHIFT 0 | 185 | #define PLLP_SHIFT 0 |
@@ -179,6 +196,14 @@ | |||
179 | #define PLL_CLKIN_SHIFT 4 | 196 | #define PLL_CLKIN_SHIFT 4 |
180 | #define MCLK_SOURCE 0x0 | 197 | #define MCLK_SOURCE 0x0 |
181 | #define PLL_CLKDIV_SHIFT 0 | 198 | #define PLL_CLKDIV_SHIFT 0 |
199 | #define PLLCLK_IN_MASK 0x30 | ||
200 | #define PLLCLK_IN_SHIFT 4 | ||
201 | #define CLKDIV_IN_MASK 0xc0 | ||
202 | #define CLKDIV_IN_SHIFT 6 | ||
203 | /* clock in source */ | ||
204 | #define CLKIN_MCLK 0 | ||
205 | #define CLKIN_GPIO2 1 | ||
206 | #define CLKIN_BCLK 2 | ||
182 | 207 | ||
183 | /* Software reset register bits */ | 208 | /* Software reset register bits */ |
184 | #define SOFT_RESET 0x80 | 209 | #define SOFT_RESET 0x80 |
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c index a36e9fcdf184..0ff1e70b7770 100644 --- a/sound/soc/codecs/twl6040.c +++ b/sound/soc/codecs/twl6040.c | |||
@@ -553,7 +553,7 @@ static const struct snd_kcontrol_new vibrar_mux_controls = | |||
553 | 553 | ||
554 | /* Headset power mode */ | 554 | /* Headset power mode */ |
555 | static const char *twl6040_power_mode_texts[] = { | 555 | static const char *twl6040_power_mode_texts[] = { |
556 | "Low-Power", "High-Perfomance", | 556 | "Low-Power", "High-Performance", |
557 | }; | 557 | }; |
558 | 558 | ||
559 | static const struct soc_enum twl6040_power_mode_enum = | 559 | static const struct soc_enum twl6040_power_mode_enum = |
diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index e0b51e9f8b12..951d7b49476a 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c | |||
@@ -121,20 +121,23 @@ static const struct snd_soc_dai_ops wm1250_ev1_ops = { | |||
121 | .hw_params = wm1250_ev1_hw_params, | 121 | .hw_params = wm1250_ev1_hw_params, |
122 | }; | 122 | }; |
123 | 123 | ||
124 | #define WM1250_EV1_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ | ||
125 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_64000) | ||
126 | |||
124 | static struct snd_soc_dai_driver wm1250_ev1_dai = { | 127 | static struct snd_soc_dai_driver wm1250_ev1_dai = { |
125 | .name = "wm1250-ev1", | 128 | .name = "wm1250-ev1", |
126 | .playback = { | 129 | .playback = { |
127 | .stream_name = "Playback", | 130 | .stream_name = "Playback", |
128 | .channels_min = 1, | 131 | .channels_min = 1, |
129 | .channels_max = 2, | 132 | .channels_max = 2, |
130 | .rates = SNDRV_PCM_RATE_8000, | 133 | .rates = WM1250_EV1_RATES, |
131 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 134 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
132 | }, | 135 | }, |
133 | .capture = { | 136 | .capture = { |
134 | .stream_name = "Capture", | 137 | .stream_name = "Capture", |
135 | .channels_min = 1, | 138 | .channels_min = 1, |
136 | .channels_max = 2, | 139 | .channels_max = 2, |
137 | .rates = SNDRV_PCM_RATE_8000, | 140 | .rates = WM1250_EV1_RATES, |
138 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 141 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
139 | }, | 142 | }, |
140 | .ops = &wm1250_ev1_ops, | 143 | .ops = &wm1250_ev1_ops, |
diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 0418fa11e6bd..3fd5b29dc933 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm2000.c -- WM2000 ALSA Soc Audio driver | 2 | * wm2000.c -- WM2000 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008-2010 Wolfson Microelectronics PLC. | 4 | * Copyright 2008-2011 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -674,9 +674,39 @@ static int wm2000_resume(struct snd_soc_codec *codec) | |||
674 | #define wm2000_resume NULL | 674 | #define wm2000_resume NULL |
675 | #endif | 675 | #endif |
676 | 676 | ||
677 | static bool wm2000_readable_reg(struct device *dev, unsigned int reg) | ||
678 | { | ||
679 | switch (reg) { | ||
680 | case WM2000_REG_SYS_START: | ||
681 | case WM2000_REG_SPEECH_CLARITY: | ||
682 | case WM2000_REG_SYS_WATCHDOG: | ||
683 | case WM2000_REG_ANA_VMID_PD_TIME: | ||
684 | case WM2000_REG_ANA_VMID_PU_TIME: | ||
685 | case WM2000_REG_CAT_FLTR_INDX: | ||
686 | case WM2000_REG_CAT_GAIN_0: | ||
687 | case WM2000_REG_SYS_STATUS: | ||
688 | case WM2000_REG_SYS_MODE_CNTRL: | ||
689 | case WM2000_REG_SYS_START0: | ||
690 | case WM2000_REG_SYS_START1: | ||
691 | case WM2000_REG_ID1: | ||
692 | case WM2000_REG_ID2: | ||
693 | case WM2000_REG_REVISON: | ||
694 | case WM2000_REG_SYS_CTL1: | ||
695 | case WM2000_REG_SYS_CTL2: | ||
696 | case WM2000_REG_ANC_STAT: | ||
697 | case WM2000_REG_IF_CTL: | ||
698 | return true; | ||
699 | default: | ||
700 | return false; | ||
701 | } | ||
702 | } | ||
703 | |||
677 | static const struct regmap_config wm2000_regmap = { | 704 | static const struct regmap_config wm2000_regmap = { |
678 | .reg_bits = 8, | 705 | .reg_bits = 8, |
679 | .val_bits = 8, | 706 | .val_bits = 8, |
707 | |||
708 | .max_register = WM2000_REG_IF_CTL, | ||
709 | .readable_reg = wm2000_readable_reg, | ||
680 | }; | 710 | }; |
681 | 711 | ||
682 | static int wm2000_probe(struct snd_soc_codec *codec) | 712 | static int wm2000_probe(struct snd_soc_codec *codec) |
diff --git a/sound/soc/codecs/wm5100-tables.c b/sound/soc/codecs/wm5100-tables.c index e167207a19cc..e239f4bf2460 100644 --- a/sound/soc/codecs/wm5100-tables.c +++ b/sound/soc/codecs/wm5100-tables.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm5100-tables.c -- WM5100 ALSA SoC Audio driver data | 2 | * wm5100-tables.c -- WM5100 ALSA SoC Audio driver data |
3 | * | 3 | * |
4 | * Copyright 2011 Wolfson Microelectronics plc | 4 | * Copyright 2011-2 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index cb6d5372103a..f4817292ef45 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm5100.c -- WM5100 ALSA SoC Audio driver | 2 | * wm5100.c -- WM5100 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2011 Wolfson Microelectronics plc | 4 | * Copyright 2011-2 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -2378,13 +2378,6 @@ static int wm5100_remove(struct snd_soc_codec *codec) | |||
2378 | return 0; | 2378 | return 0; |
2379 | } | 2379 | } |
2380 | 2380 | ||
2381 | static int wm5100_soc_volatile(struct snd_soc_codec *codec, | ||
2382 | unsigned int reg) | ||
2383 | { | ||
2384 | return true; | ||
2385 | } | ||
2386 | |||
2387 | |||
2388 | static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { | 2381 | static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { |
2389 | .probe = wm5100_probe, | 2382 | .probe = wm5100_probe, |
2390 | .remove = wm5100_remove, | 2383 | .remove = wm5100_remove, |
@@ -2392,8 +2385,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5100 = { | |||
2392 | .set_sysclk = wm5100_set_sysclk, | 2385 | .set_sysclk = wm5100_set_sysclk, |
2393 | .set_pll = wm5100_set_fll, | 2386 | .set_pll = wm5100_set_fll, |
2394 | .idle_bias_off = 1, | 2387 | .idle_bias_off = 1, |
2395 | .reg_cache_size = WM5100_MAX_REGISTER, | ||
2396 | .volatile_register = wm5100_soc_volatile, | ||
2397 | 2388 | ||
2398 | .seq_notifier = wm5100_seq_notifier, | 2389 | .seq_notifier = wm5100_seq_notifier, |
2399 | .controls = wm5100_snd_controls, | 2390 | .controls = wm5100_snd_controls, |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c new file mode 100644 index 000000000000..6537f16d383e --- /dev/null +++ b/sound/soc/codecs/wm5102.c | |||
@@ -0,0 +1,903 @@ | |||
1 | /* | ||
2 | * wm5102.c -- WM5102 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/pm_runtime.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/jack.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
29 | #include <linux/mfd/arizona/core.h> | ||
30 | #include <linux/mfd/arizona/registers.h> | ||
31 | |||
32 | #include "arizona.h" | ||
33 | #include "wm5102.h" | ||
34 | |||
35 | struct wm5102_priv { | ||
36 | struct arizona_priv core; | ||
37 | struct arizona_fll fll[2]; | ||
38 | }; | ||
39 | |||
40 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | ||
41 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
42 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | ||
43 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | ||
44 | |||
45 | static const struct snd_kcontrol_new wm5102_snd_controls[] = { | ||
46 | SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, | ||
47 | ARIZONA_IN1_OSR_SHIFT, 1, 0), | ||
48 | SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL, | ||
49 | ARIZONA_IN2_OSR_SHIFT, 1, 0), | ||
50 | SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL, | ||
51 | ARIZONA_IN3_OSR_SHIFT, 1, 0), | ||
52 | |||
53 | SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL, | ||
54 | ARIZONA_IN1R_CONTROL, | ||
55 | ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
56 | SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL, | ||
57 | ARIZONA_IN2R_CONTROL, | ||
58 | ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
59 | SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL, | ||
60 | ARIZONA_IN3R_CONTROL, | ||
61 | ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
62 | |||
63 | SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
64 | ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1), | ||
65 | SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
66 | ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1), | ||
67 | SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
68 | ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1), | ||
69 | |||
70 | SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
71 | ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT, | ||
72 | 0xbf, 0, digital_tlv), | ||
73 | SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
74 | ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT, | ||
75 | 0xbf, 0, digital_tlv), | ||
76 | SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
77 | ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT, | ||
78 | 0xbf, 0, digital_tlv), | ||
79 | |||
80 | ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), | ||
81 | ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | ||
82 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | ||
83 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | ||
84 | |||
85 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | ||
86 | 24, 0, eq_tlv), | ||
87 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | ||
88 | 24, 0, eq_tlv), | ||
89 | SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT, | ||
90 | 24, 0, eq_tlv), | ||
91 | SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | ||
92 | 24, 0, eq_tlv), | ||
93 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | ||
94 | 24, 0, eq_tlv), | ||
95 | |||
96 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | ||
97 | 24, 0, eq_tlv), | ||
98 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | ||
99 | 24, 0, eq_tlv), | ||
100 | SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT, | ||
101 | 24, 0, eq_tlv), | ||
102 | SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | ||
103 | 24, 0, eq_tlv), | ||
104 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | ||
105 | 24, 0, eq_tlv), | ||
106 | |||
107 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | ||
108 | 24, 0, eq_tlv), | ||
109 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | ||
110 | 24, 0, eq_tlv), | ||
111 | SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT, | ||
112 | 24, 0, eq_tlv), | ||
113 | SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | ||
114 | 24, 0, eq_tlv), | ||
115 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | ||
116 | 24, 0, eq_tlv), | ||
117 | |||
118 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | ||
119 | 24, 0, eq_tlv), | ||
120 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | ||
121 | 24, 0, eq_tlv), | ||
122 | SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT, | ||
123 | 24, 0, eq_tlv), | ||
124 | SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT, | ||
125 | 24, 0, eq_tlv), | ||
126 | SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT, | ||
127 | 24, 0, eq_tlv), | ||
128 | |||
129 | ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE), | ||
130 | ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE), | ||
131 | ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE), | ||
132 | ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE), | ||
133 | |||
134 | SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5, | ||
135 | ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA), | ||
136 | SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5, | ||
137 | ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA), | ||
138 | |||
139 | ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE), | ||
140 | ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), | ||
141 | ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), | ||
142 | ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), | ||
143 | |||
144 | SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), | ||
145 | SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), | ||
146 | SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), | ||
147 | SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), | ||
148 | |||
149 | ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), | ||
150 | ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), | ||
151 | |||
152 | SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
153 | ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv), | ||
154 | |||
155 | ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE), | ||
156 | ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE), | ||
157 | ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE), | ||
158 | ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE), | ||
159 | ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE), | ||
160 | ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE), | ||
161 | ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), | ||
162 | ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), | ||
163 | ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), | ||
164 | |||
165 | SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L, | ||
166 | ARIZONA_OUT1_OSR_SHIFT, 1, 0), | ||
167 | SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L, | ||
168 | ARIZONA_OUT2_OSR_SHIFT, 1, 0), | ||
169 | SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, | ||
170 | ARIZONA_OUT3_OSR_SHIFT, 1, 0), | ||
171 | SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, | ||
172 | ARIZONA_OUT4_OSR_SHIFT, 1, 0), | ||
173 | SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, | ||
174 | ARIZONA_OUT5_OSR_SHIFT, 1, 0), | ||
175 | |||
176 | SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
177 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), | ||
178 | SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
179 | ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1), | ||
180 | SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
181 | ARIZONA_OUT3L_MUTE_SHIFT, 1, 1), | ||
182 | SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
183 | ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1), | ||
184 | SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
185 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1), | ||
186 | |||
187 | SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
188 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT, | ||
189 | 0xbf, 0, digital_tlv), | ||
190 | SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
191 | ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT, | ||
192 | 0xbf, 0, digital_tlv), | ||
193 | SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
194 | ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
195 | SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
196 | ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT, | ||
197 | 0xbf, 0, digital_tlv), | ||
198 | SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
199 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, | ||
200 | 0xbf, 0, digital_tlv), | ||
201 | |||
202 | SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L, | ||
203 | ARIZONA_OUTPUT_PATH_CONFIG_1R, | ||
204 | ARIZONA_OUT1L_PGA_VOL_SHIFT, | ||
205 | 0x34, 0x40, 0, ana_tlv), | ||
206 | SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L, | ||
207 | ARIZONA_OUTPUT_PATH_CONFIG_2R, | ||
208 | ARIZONA_OUT2L_PGA_VOL_SHIFT, | ||
209 | 0x34, 0x40, 0, ana_tlv), | ||
210 | SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, | ||
211 | ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), | ||
212 | |||
213 | SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, | ||
214 | ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), | ||
215 | |||
216 | ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), | ||
217 | ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), | ||
218 | ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), | ||
219 | ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE), | ||
220 | ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE), | ||
221 | ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE), | ||
222 | ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE), | ||
223 | ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), | ||
224 | |||
225 | ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), | ||
226 | ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), | ||
227 | |||
228 | ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), | ||
229 | ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), | ||
230 | }; | ||
231 | |||
232 | ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); | ||
233 | ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); | ||
234 | ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); | ||
235 | ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE); | ||
236 | |||
237 | ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE); | ||
238 | ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE); | ||
239 | ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE); | ||
240 | ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE); | ||
241 | |||
242 | ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE); | ||
243 | ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE); | ||
244 | ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); | ||
245 | ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); | ||
246 | |||
247 | ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE); | ||
248 | ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE); | ||
249 | |||
250 | ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE); | ||
251 | ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE); | ||
252 | |||
253 | ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE); | ||
254 | ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE); | ||
255 | ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE); | ||
256 | ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE); | ||
257 | ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE); | ||
258 | ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE); | ||
259 | ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE); | ||
260 | ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE); | ||
261 | ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE); | ||
262 | |||
263 | ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE); | ||
264 | ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE); | ||
265 | ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE); | ||
266 | ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE); | ||
267 | ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE); | ||
268 | ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE); | ||
269 | ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE); | ||
270 | ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); | ||
271 | |||
272 | ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); | ||
273 | ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); | ||
274 | |||
275 | ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); | ||
276 | ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); | ||
277 | |||
278 | ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); | ||
279 | ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); | ||
280 | ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); | ||
281 | ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); | ||
282 | |||
283 | static const struct snd_soc_dapm_widget wm5102_dapm_widgets[] = { | ||
284 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, | ||
285 | 0, NULL, 0), | ||
286 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, | ||
287 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), | ||
288 | |||
289 | SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), | ||
290 | SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), | ||
291 | SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), | ||
292 | SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0), | ||
293 | SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0), | ||
294 | SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0), | ||
295 | |||
296 | SND_SOC_DAPM_SIGGEN("TONE"), | ||
297 | SND_SOC_DAPM_SIGGEN("NOISE"), | ||
298 | |||
299 | SND_SOC_DAPM_INPUT("IN1L"), | ||
300 | SND_SOC_DAPM_INPUT("IN1R"), | ||
301 | SND_SOC_DAPM_INPUT("IN2L"), | ||
302 | SND_SOC_DAPM_INPUT("IN2R"), | ||
303 | SND_SOC_DAPM_INPUT("IN3L"), | ||
304 | SND_SOC_DAPM_INPUT("IN3R"), | ||
305 | |||
306 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | ||
307 | 0, NULL, 0, arizona_in_ev, | ||
308 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
309 | SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, | ||
310 | 0, NULL, 0, arizona_in_ev, | ||
311 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
312 | SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, | ||
313 | 0, NULL, 0, arizona_in_ev, | ||
314 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
315 | SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, | ||
316 | 0, NULL, 0, arizona_in_ev, | ||
317 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
318 | SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, | ||
319 | 0, NULL, 0, arizona_in_ev, | ||
320 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
321 | SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, | ||
322 | 0, NULL, 0, arizona_in_ev, | ||
323 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
324 | |||
325 | SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, | ||
326 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
327 | SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, | ||
328 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
329 | SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3, | ||
330 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
331 | |||
332 | SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
333 | ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), | ||
334 | |||
335 | SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1, | ||
336 | ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0), | ||
337 | SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1, | ||
338 | ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0), | ||
339 | |||
340 | SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1, | ||
341 | ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0), | ||
342 | |||
343 | SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0), | ||
344 | SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0), | ||
345 | SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0), | ||
346 | SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0), | ||
347 | |||
348 | SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0, | ||
349 | NULL, 0), | ||
350 | SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0, | ||
351 | NULL, 0), | ||
352 | SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0, | ||
353 | NULL, 0), | ||
354 | SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0, | ||
355 | NULL, 0), | ||
356 | |||
357 | SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0, | ||
358 | NULL, 0), | ||
359 | SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0, | ||
360 | NULL, 0), | ||
361 | SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0, | ||
362 | NULL, 0), | ||
363 | SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0, | ||
364 | NULL, 0), | ||
365 | |||
366 | SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT, | ||
367 | 0, NULL, 0), | ||
368 | SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT, | ||
369 | 0, NULL, 0), | ||
370 | |||
371 | SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0, | ||
372 | NULL, 0), | ||
373 | SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0, | ||
374 | NULL, 0), | ||
375 | SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, | ||
376 | NULL, 0), | ||
377 | SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, | ||
378 | NULL, 0), | ||
379 | |||
380 | SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, | ||
381 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), | ||
382 | SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, | ||
383 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), | ||
384 | SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, | ||
385 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), | ||
386 | SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, | ||
387 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), | ||
388 | SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, | ||
389 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), | ||
390 | SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, | ||
391 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), | ||
392 | SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, | ||
393 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), | ||
394 | SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, | ||
395 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), | ||
396 | |||
397 | SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, | ||
398 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), | ||
399 | SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, | ||
400 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), | ||
401 | SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, | ||
402 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), | ||
403 | SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, | ||
404 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), | ||
405 | SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, | ||
406 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), | ||
407 | SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, | ||
408 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), | ||
409 | SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, | ||
410 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), | ||
411 | SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, | ||
412 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), | ||
413 | |||
414 | SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, | ||
415 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), | ||
416 | SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, | ||
417 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), | ||
418 | |||
419 | SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, | ||
420 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), | ||
421 | SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, | ||
422 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), | ||
423 | |||
424 | SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, | ||
425 | ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), | ||
426 | SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, | ||
427 | ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), | ||
428 | |||
429 | SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, | ||
430 | ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), | ||
431 | SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, | ||
432 | ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), | ||
433 | |||
434 | SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, | ||
435 | ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
436 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
437 | SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, | ||
438 | ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
439 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
440 | SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, | ||
441 | ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
442 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
443 | SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, | ||
444 | ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
445 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
446 | SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, | ||
447 | ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
448 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
449 | SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, | ||
450 | ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
451 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
452 | SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, | ||
453 | ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
454 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
455 | SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, | ||
456 | ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
457 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
458 | SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1, | ||
459 | ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
460 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
461 | |||
462 | ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"), | ||
463 | ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"), | ||
464 | ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"), | ||
465 | ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"), | ||
466 | |||
467 | ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"), | ||
468 | ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"), | ||
469 | ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"), | ||
470 | ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"), | ||
471 | |||
472 | ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"), | ||
473 | ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"), | ||
474 | ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"), | ||
475 | ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"), | ||
476 | |||
477 | ARIZONA_MIXER_WIDGETS(Mic, "Mic"), | ||
478 | ARIZONA_MIXER_WIDGETS(Noise, "Noise"), | ||
479 | |||
480 | ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"), | ||
481 | ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"), | ||
482 | |||
483 | ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), | ||
484 | ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), | ||
485 | ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"), | ||
486 | ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"), | ||
487 | ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"), | ||
488 | ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"), | ||
489 | ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"), | ||
490 | ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), | ||
491 | ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), | ||
492 | |||
493 | ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), | ||
494 | ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), | ||
495 | ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), | ||
496 | ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), | ||
497 | ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), | ||
498 | ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), | ||
499 | ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), | ||
500 | ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), | ||
501 | |||
502 | ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), | ||
503 | ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), | ||
504 | |||
505 | ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), | ||
506 | ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), | ||
507 | |||
508 | ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), | ||
509 | ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), | ||
510 | ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), | ||
511 | ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), | ||
512 | |||
513 | SND_SOC_DAPM_OUTPUT("HPOUT1L"), | ||
514 | SND_SOC_DAPM_OUTPUT("HPOUT1R"), | ||
515 | SND_SOC_DAPM_OUTPUT("HPOUT2L"), | ||
516 | SND_SOC_DAPM_OUTPUT("HPOUT2R"), | ||
517 | SND_SOC_DAPM_OUTPUT("EPOUTN"), | ||
518 | SND_SOC_DAPM_OUTPUT("EPOUTP"), | ||
519 | SND_SOC_DAPM_OUTPUT("SPKOUTLN"), | ||
520 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), | ||
521 | SND_SOC_DAPM_OUTPUT("SPKOUTRN"), | ||
522 | SND_SOC_DAPM_OUTPUT("SPKOUTRP"), | ||
523 | SND_SOC_DAPM_OUTPUT("SPKDAT1L"), | ||
524 | SND_SOC_DAPM_OUTPUT("SPKDAT1R"), | ||
525 | }; | ||
526 | |||
527 | #define ARIZONA_MIXER_INPUT_ROUTES(name) \ | ||
528 | { name, "Noise Generator", "Noise Generator" }, \ | ||
529 | { name, "Tone Generator 1", "Tone Generator 1" }, \ | ||
530 | { name, "Tone Generator 2", "Tone Generator 2" }, \ | ||
531 | { name, "IN1L", "IN1L PGA" }, \ | ||
532 | { name, "IN1R", "IN1R PGA" }, \ | ||
533 | { name, "IN2L", "IN2L PGA" }, \ | ||
534 | { name, "IN2R", "IN2R PGA" }, \ | ||
535 | { name, "IN3L", "IN3L PGA" }, \ | ||
536 | { name, "IN3R", "IN3R PGA" }, \ | ||
537 | { name, "Mic Mute Mixer", "Mic Mute Mixer" }, \ | ||
538 | { name, "AIF1RX1", "AIF1RX1" }, \ | ||
539 | { name, "AIF1RX2", "AIF1RX2" }, \ | ||
540 | { name, "AIF1RX3", "AIF1RX3" }, \ | ||
541 | { name, "AIF1RX4", "AIF1RX4" }, \ | ||
542 | { name, "AIF1RX5", "AIF1RX5" }, \ | ||
543 | { name, "AIF1RX6", "AIF1RX6" }, \ | ||
544 | { name, "AIF1RX7", "AIF1RX7" }, \ | ||
545 | { name, "AIF1RX8", "AIF1RX8" }, \ | ||
546 | { name, "AIF2RX1", "AIF2RX1" }, \ | ||
547 | { name, "AIF2RX2", "AIF2RX2" }, \ | ||
548 | { name, "AIF3RX1", "AIF3RX1" }, \ | ||
549 | { name, "AIF3RX2", "AIF3RX2" }, \ | ||
550 | { name, "EQ1", "EQ1" }, \ | ||
551 | { name, "EQ2", "EQ2" }, \ | ||
552 | { name, "EQ3", "EQ3" }, \ | ||
553 | { name, "EQ4", "EQ4" }, \ | ||
554 | { name, "DRC1L", "DRC1L" }, \ | ||
555 | { name, "DRC1R", "DRC1R" }, \ | ||
556 | { name, "DRC2L", "DRC2L" }, \ | ||
557 | { name, "DRC2R", "DRC2R" }, \ | ||
558 | { name, "LHPF1", "LHPF1" }, \ | ||
559 | { name, "LHPF2", "LHPF2" }, \ | ||
560 | { name, "LHPF3", "LHPF3" }, \ | ||
561 | { name, "LHPF4", "LHPF4" }, \ | ||
562 | { name, "ASRC1L", "ASRC1L" }, \ | ||
563 | { name, "ASRC1R", "ASRC1R" }, \ | ||
564 | { name, "ASRC2L", "ASRC2L" }, \ | ||
565 | { name, "ASRC2R", "ASRC2R" } | ||
566 | |||
567 | static const struct snd_soc_dapm_route wm5102_dapm_routes[] = { | ||
568 | { "AIF2 Capture", NULL, "DBVDD2" }, | ||
569 | { "AIF2 Playback", NULL, "DBVDD2" }, | ||
570 | |||
571 | { "AIF3 Capture", NULL, "DBVDD3" }, | ||
572 | { "AIF3 Playback", NULL, "DBVDD3" }, | ||
573 | |||
574 | { "OUT1L", NULL, "CPVDD" }, | ||
575 | { "OUT1R", NULL, "CPVDD" }, | ||
576 | { "OUT2L", NULL, "CPVDD" }, | ||
577 | { "OUT2R", NULL, "CPVDD" }, | ||
578 | { "OUT3L", NULL, "CPVDD" }, | ||
579 | |||
580 | { "OUT4L", NULL, "SPKVDDL" }, | ||
581 | { "OUT4R", NULL, "SPKVDDR" }, | ||
582 | |||
583 | { "OUT1L", NULL, "SYSCLK" }, | ||
584 | { "OUT1R", NULL, "SYSCLK" }, | ||
585 | { "OUT2L", NULL, "SYSCLK" }, | ||
586 | { "OUT2R", NULL, "SYSCLK" }, | ||
587 | { "OUT3L", NULL, "SYSCLK" }, | ||
588 | { "OUT4L", NULL, "SYSCLK" }, | ||
589 | { "OUT4R", NULL, "SYSCLK" }, | ||
590 | { "OUT5L", NULL, "SYSCLK" }, | ||
591 | { "OUT5R", NULL, "SYSCLK" }, | ||
592 | |||
593 | { "MICBIAS1", NULL, "MICVDD" }, | ||
594 | { "MICBIAS2", NULL, "MICVDD" }, | ||
595 | { "MICBIAS3", NULL, "MICVDD" }, | ||
596 | |||
597 | { "Noise Generator", NULL, "NOISE" }, | ||
598 | { "Tone Generator 1", NULL, "TONE" }, | ||
599 | { "Tone Generator 2", NULL, "TONE" }, | ||
600 | |||
601 | { "Mic Mute Mixer", NULL, "Noise Mixer" }, | ||
602 | { "Mic Mute Mixer", NULL, "Mic Mixer" }, | ||
603 | |||
604 | { "AIF1 Capture", NULL, "AIF1TX1" }, | ||
605 | { "AIF1 Capture", NULL, "AIF1TX2" }, | ||
606 | { "AIF1 Capture", NULL, "AIF1TX3" }, | ||
607 | { "AIF1 Capture", NULL, "AIF1TX4" }, | ||
608 | { "AIF1 Capture", NULL, "AIF1TX5" }, | ||
609 | { "AIF1 Capture", NULL, "AIF1TX6" }, | ||
610 | { "AIF1 Capture", NULL, "AIF1TX7" }, | ||
611 | { "AIF1 Capture", NULL, "AIF1TX8" }, | ||
612 | |||
613 | { "AIF1RX1", NULL, "AIF1 Playback" }, | ||
614 | { "AIF1RX2", NULL, "AIF1 Playback" }, | ||
615 | { "AIF1RX3", NULL, "AIF1 Playback" }, | ||
616 | { "AIF1RX4", NULL, "AIF1 Playback" }, | ||
617 | { "AIF1RX5", NULL, "AIF1 Playback" }, | ||
618 | { "AIF1RX6", NULL, "AIF1 Playback" }, | ||
619 | { "AIF1RX7", NULL, "AIF1 Playback" }, | ||
620 | { "AIF1RX8", NULL, "AIF1 Playback" }, | ||
621 | |||
622 | { "AIF2 Capture", NULL, "AIF2TX1" }, | ||
623 | { "AIF2 Capture", NULL, "AIF2TX2" }, | ||
624 | |||
625 | { "AIF2RX1", NULL, "AIF2 Playback" }, | ||
626 | { "AIF2RX2", NULL, "AIF2 Playback" }, | ||
627 | |||
628 | { "AIF3 Capture", NULL, "AIF3TX1" }, | ||
629 | { "AIF3 Capture", NULL, "AIF3TX2" }, | ||
630 | |||
631 | { "AIF3RX1", NULL, "AIF3 Playback" }, | ||
632 | { "AIF3RX2", NULL, "AIF3 Playback" }, | ||
633 | |||
634 | { "AIF1 Playback", NULL, "SYSCLK" }, | ||
635 | { "AIF2 Playback", NULL, "SYSCLK" }, | ||
636 | { "AIF3 Playback", NULL, "SYSCLK" }, | ||
637 | |||
638 | { "AIF1 Capture", NULL, "SYSCLK" }, | ||
639 | { "AIF2 Capture", NULL, "SYSCLK" }, | ||
640 | { "AIF3 Capture", NULL, "SYSCLK" }, | ||
641 | |||
642 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | ||
643 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | ||
644 | ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), | ||
645 | ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"), | ||
646 | ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"), | ||
647 | |||
648 | ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"), | ||
649 | ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"), | ||
650 | ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), | ||
651 | ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), | ||
652 | |||
653 | ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"), | ||
654 | ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"), | ||
655 | |||
656 | ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), | ||
657 | ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), | ||
658 | ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), | ||
659 | ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), | ||
660 | ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), | ||
661 | ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), | ||
662 | ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), | ||
663 | ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), | ||
664 | |||
665 | ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), | ||
666 | ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), | ||
667 | |||
668 | ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), | ||
669 | ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), | ||
670 | |||
671 | ARIZONA_MIXER_ROUTES("EQ1", "EQ1"), | ||
672 | ARIZONA_MIXER_ROUTES("EQ2", "EQ2"), | ||
673 | ARIZONA_MIXER_ROUTES("EQ3", "EQ3"), | ||
674 | ARIZONA_MIXER_ROUTES("EQ4", "EQ4"), | ||
675 | |||
676 | ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"), | ||
677 | ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"), | ||
678 | ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"), | ||
679 | ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"), | ||
680 | |||
681 | ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"), | ||
682 | ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"), | ||
683 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), | ||
684 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), | ||
685 | |||
686 | ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), | ||
687 | ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), | ||
688 | ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), | ||
689 | ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), | ||
690 | |||
691 | { "HPOUT1L", NULL, "OUT1L" }, | ||
692 | { "HPOUT1R", NULL, "OUT1R" }, | ||
693 | |||
694 | { "HPOUT2L", NULL, "OUT2L" }, | ||
695 | { "HPOUT2R", NULL, "OUT2R" }, | ||
696 | |||
697 | { "EPOUTN", NULL, "OUT3L" }, | ||
698 | { "EPOUTP", NULL, "OUT3L" }, | ||
699 | |||
700 | { "SPKOUTLN", NULL, "OUT4L" }, | ||
701 | { "SPKOUTLP", NULL, "OUT4L" }, | ||
702 | |||
703 | { "SPKOUTRN", NULL, "OUT4R" }, | ||
704 | { "SPKOUTRP", NULL, "OUT4R" }, | ||
705 | |||
706 | { "SPKDAT1L", NULL, "OUT5L" }, | ||
707 | { "SPKDAT1R", NULL, "OUT5R" }, | ||
708 | }; | ||
709 | |||
710 | static int wm5102_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | ||
711 | unsigned int Fref, unsigned int Fout) | ||
712 | { | ||
713 | struct wm5102_priv *wm5102 = snd_soc_codec_get_drvdata(codec); | ||
714 | |||
715 | switch (fll_id) { | ||
716 | case WM5102_FLL1: | ||
717 | return arizona_set_fll(&wm5102->fll[0], source, Fref, Fout); | ||
718 | case WM5102_FLL2: | ||
719 | return arizona_set_fll(&wm5102->fll[1], source, Fref, Fout); | ||
720 | default: | ||
721 | return -EINVAL; | ||
722 | } | ||
723 | } | ||
724 | |||
725 | #define WM5102_RATES SNDRV_PCM_RATE_8000_192000 | ||
726 | |||
727 | #define WM5102_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
728 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
729 | |||
730 | static struct snd_soc_dai_driver wm5102_dai[] = { | ||
731 | { | ||
732 | .name = "wm5102-aif1", | ||
733 | .id = 1, | ||
734 | .base = ARIZONA_AIF1_BCLK_CTRL, | ||
735 | .playback = { | ||
736 | .stream_name = "AIF1 Playback", | ||
737 | .channels_min = 1, | ||
738 | .channels_max = 8, | ||
739 | .rates = WM5102_RATES, | ||
740 | .formats = WM5102_FORMATS, | ||
741 | }, | ||
742 | .capture = { | ||
743 | .stream_name = "AIF1 Capture", | ||
744 | .channels_min = 1, | ||
745 | .channels_max = 8, | ||
746 | .rates = WM5102_RATES, | ||
747 | .formats = WM5102_FORMATS, | ||
748 | }, | ||
749 | .ops = &arizona_dai_ops, | ||
750 | .symmetric_rates = 1, | ||
751 | }, | ||
752 | { | ||
753 | .name = "wm5102-aif2", | ||
754 | .id = 2, | ||
755 | .base = ARIZONA_AIF2_BCLK_CTRL, | ||
756 | .playback = { | ||
757 | .stream_name = "AIF2 Playback", | ||
758 | .channels_min = 1, | ||
759 | .channels_max = 2, | ||
760 | .rates = WM5102_RATES, | ||
761 | .formats = WM5102_FORMATS, | ||
762 | }, | ||
763 | .capture = { | ||
764 | .stream_name = "AIF2 Capture", | ||
765 | .channels_min = 1, | ||
766 | .channels_max = 2, | ||
767 | .rates = WM5102_RATES, | ||
768 | .formats = WM5102_FORMATS, | ||
769 | }, | ||
770 | .ops = &arizona_dai_ops, | ||
771 | .symmetric_rates = 1, | ||
772 | }, | ||
773 | { | ||
774 | .name = "wm5102-aif3", | ||
775 | .id = 3, | ||
776 | .base = ARIZONA_AIF3_BCLK_CTRL, | ||
777 | .playback = { | ||
778 | .stream_name = "AIF3 Playback", | ||
779 | .channels_min = 1, | ||
780 | .channels_max = 2, | ||
781 | .rates = WM5102_RATES, | ||
782 | .formats = WM5102_FORMATS, | ||
783 | }, | ||
784 | .capture = { | ||
785 | .stream_name = "AIF3 Capture", | ||
786 | .channels_min = 1, | ||
787 | .channels_max = 2, | ||
788 | .rates = WM5102_RATES, | ||
789 | .formats = WM5102_FORMATS, | ||
790 | }, | ||
791 | .ops = &arizona_dai_ops, | ||
792 | .symmetric_rates = 1, | ||
793 | }, | ||
794 | }; | ||
795 | |||
796 | static int wm5102_codec_probe(struct snd_soc_codec *codec) | ||
797 | { | ||
798 | struct wm5102_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
799 | |||
800 | codec->control_data = priv->core.arizona->regmap; | ||
801 | return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); | ||
802 | } | ||
803 | |||
804 | #define WM5102_DIG_VU 0x0200 | ||
805 | |||
806 | static unsigned int wm5102_digital_vu[] = { | ||
807 | ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
808 | ARIZONA_ADC_DIGITAL_VOLUME_1R, | ||
809 | ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
810 | ARIZONA_ADC_DIGITAL_VOLUME_2R, | ||
811 | ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
812 | ARIZONA_ADC_DIGITAL_VOLUME_3R, | ||
813 | |||
814 | ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
815 | ARIZONA_DAC_DIGITAL_VOLUME_1R, | ||
816 | ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
817 | ARIZONA_DAC_DIGITAL_VOLUME_2R, | ||
818 | ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
819 | ARIZONA_DAC_DIGITAL_VOLUME_3R, | ||
820 | ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
821 | ARIZONA_DAC_DIGITAL_VOLUME_4R, | ||
822 | ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
823 | ARIZONA_DAC_DIGITAL_VOLUME_5R, | ||
824 | }; | ||
825 | |||
826 | static struct snd_soc_codec_driver soc_codec_dev_wm5102 = { | ||
827 | .probe = wm5102_codec_probe, | ||
828 | |||
829 | .idle_bias_off = true, | ||
830 | |||
831 | .set_sysclk = arizona_set_sysclk, | ||
832 | .set_pll = wm5102_set_fll, | ||
833 | |||
834 | .controls = wm5102_snd_controls, | ||
835 | .num_controls = ARRAY_SIZE(wm5102_snd_controls), | ||
836 | .dapm_widgets = wm5102_dapm_widgets, | ||
837 | .num_dapm_widgets = ARRAY_SIZE(wm5102_dapm_widgets), | ||
838 | .dapm_routes = wm5102_dapm_routes, | ||
839 | .num_dapm_routes = ARRAY_SIZE(wm5102_dapm_routes), | ||
840 | }; | ||
841 | |||
842 | static int __devinit wm5102_probe(struct platform_device *pdev) | ||
843 | { | ||
844 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | ||
845 | struct wm5102_priv *wm5102; | ||
846 | int i; | ||
847 | |||
848 | wm5102 = devm_kzalloc(&pdev->dev, sizeof(struct wm5102_priv), | ||
849 | GFP_KERNEL); | ||
850 | if (wm5102 == NULL) | ||
851 | return -ENOMEM; | ||
852 | platform_set_drvdata(pdev, wm5102); | ||
853 | |||
854 | wm5102->core.arizona = arizona; | ||
855 | |||
856 | for (i = 0; i < ARRAY_SIZE(wm5102->fll); i++) | ||
857 | wm5102->fll[i].vco_mult = 1; | ||
858 | |||
859 | arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1, | ||
860 | ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK, | ||
861 | &wm5102->fll[0]); | ||
862 | arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1, | ||
863 | ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, | ||
864 | &wm5102->fll[1]); | ||
865 | |||
866 | for (i = 0; i < ARRAY_SIZE(wm5102_dai); i++) | ||
867 | arizona_init_dai(&wm5102->core, i); | ||
868 | |||
869 | /* Latch volume update bits */ | ||
870 | for (i = 0; i < ARRAY_SIZE(wm5102_digital_vu); i++) | ||
871 | regmap_update_bits(arizona->regmap, wm5102_digital_vu[i], | ||
872 | WM5102_DIG_VU, WM5102_DIG_VU); | ||
873 | |||
874 | pm_runtime_enable(&pdev->dev); | ||
875 | pm_runtime_idle(&pdev->dev); | ||
876 | |||
877 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5102, | ||
878 | wm5102_dai, ARRAY_SIZE(wm5102_dai)); | ||
879 | } | ||
880 | |||
881 | static int __devexit wm5102_remove(struct platform_device *pdev) | ||
882 | { | ||
883 | snd_soc_unregister_codec(&pdev->dev); | ||
884 | pm_runtime_disable(&pdev->dev); | ||
885 | |||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static struct platform_driver wm5102_codec_driver = { | ||
890 | .driver = { | ||
891 | .name = "wm5102-codec", | ||
892 | .owner = THIS_MODULE, | ||
893 | }, | ||
894 | .probe = wm5102_probe, | ||
895 | .remove = __devexit_p(wm5102_remove), | ||
896 | }; | ||
897 | |||
898 | module_platform_driver(wm5102_codec_driver); | ||
899 | |||
900 | MODULE_DESCRIPTION("ASoC WM5102 driver"); | ||
901 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
902 | MODULE_LICENSE("GPL"); | ||
903 | MODULE_ALIAS("platform:wm5102-codec"); | ||
diff --git a/sound/soc/codecs/wm5102.h b/sound/soc/codecs/wm5102.h new file mode 100644 index 000000000000..d30477f3070c --- /dev/null +++ b/sound/soc/codecs/wm5102.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * wm5102.h -- WM5102 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _WM5102_H | ||
14 | #define _WM5102_H | ||
15 | |||
16 | #include "arizona.h" | ||
17 | |||
18 | #define WM5102_FLL1 1 | ||
19 | #define WM5102_FLL2 2 | ||
20 | |||
21 | #endif | ||
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c new file mode 100644 index 000000000000..8033f7065189 --- /dev/null +++ b/sound/soc/codecs/wm5110.c | |||
@@ -0,0 +1,950 @@ | |||
1 | /* | ||
2 | * wm5110.c -- WM5110 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/moduleparam.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/delay.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/pm_runtime.h> | ||
19 | #include <linux/regmap.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/jack.h> | ||
26 | #include <sound/initval.h> | ||
27 | #include <sound/tlv.h> | ||
28 | |||
29 | #include <linux/mfd/arizona/core.h> | ||
30 | #include <linux/mfd/arizona/registers.h> | ||
31 | |||
32 | #include "arizona.h" | ||
33 | #include "wm5110.h" | ||
34 | |||
35 | struct wm5110_priv { | ||
36 | struct arizona_priv core; | ||
37 | struct arizona_fll fll[2]; | ||
38 | }; | ||
39 | |||
40 | static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); | ||
41 | static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | ||
42 | static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); | ||
43 | static DECLARE_TLV_DB_SCALE(noise_tlv, 0, 600, 0); | ||
44 | |||
45 | static const struct snd_kcontrol_new wm5110_snd_controls[] = { | ||
46 | SOC_SINGLE("IN1 High Performance Switch", ARIZONA_IN1L_CONTROL, | ||
47 | ARIZONA_IN1_OSR_SHIFT, 1, 0), | ||
48 | SOC_SINGLE("IN2 High Performance Switch", ARIZONA_IN2L_CONTROL, | ||
49 | ARIZONA_IN2_OSR_SHIFT, 1, 0), | ||
50 | SOC_SINGLE("IN3 High Performance Switch", ARIZONA_IN3L_CONTROL, | ||
51 | ARIZONA_IN3_OSR_SHIFT, 1, 0), | ||
52 | SOC_SINGLE("IN4 High Performance Switch", ARIZONA_IN4L_CONTROL, | ||
53 | ARIZONA_IN4_OSR_SHIFT, 1, 0), | ||
54 | |||
55 | SOC_DOUBLE_R_RANGE_TLV("IN1 Volume", ARIZONA_IN1L_CONTROL, | ||
56 | ARIZONA_IN1R_CONTROL, | ||
57 | ARIZONA_IN1L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
58 | SOC_DOUBLE_R_RANGE_TLV("IN2 Volume", ARIZONA_IN2L_CONTROL, | ||
59 | ARIZONA_IN2R_CONTROL, | ||
60 | ARIZONA_IN2L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
61 | SOC_DOUBLE_R_RANGE_TLV("IN3 Volume", ARIZONA_IN3L_CONTROL, | ||
62 | ARIZONA_IN3R_CONTROL, | ||
63 | ARIZONA_IN3L_PGA_VOL_SHIFT, 0x40, 0x5f, 0, ana_tlv), | ||
64 | |||
65 | SOC_DOUBLE_R("IN1 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
66 | ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_MUTE_SHIFT, 1, 1), | ||
67 | SOC_DOUBLE_R("IN2 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
68 | ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_MUTE_SHIFT, 1, 1), | ||
69 | SOC_DOUBLE_R("IN3 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
70 | ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_MUTE_SHIFT, 1, 1), | ||
71 | SOC_DOUBLE_R("IN4 Digital Switch", ARIZONA_ADC_DIGITAL_VOLUME_4L, | ||
72 | ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_MUTE_SHIFT, 1, 1), | ||
73 | |||
74 | SOC_DOUBLE_R_TLV("IN1 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
75 | ARIZONA_ADC_DIGITAL_VOLUME_1R, ARIZONA_IN1L_DIG_VOL_SHIFT, | ||
76 | 0xbf, 0, digital_tlv), | ||
77 | SOC_DOUBLE_R_TLV("IN2 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
78 | ARIZONA_ADC_DIGITAL_VOLUME_2R, ARIZONA_IN2L_DIG_VOL_SHIFT, | ||
79 | 0xbf, 0, digital_tlv), | ||
80 | SOC_DOUBLE_R_TLV("IN3 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
81 | ARIZONA_ADC_DIGITAL_VOLUME_3R, ARIZONA_IN3L_DIG_VOL_SHIFT, | ||
82 | 0xbf, 0, digital_tlv), | ||
83 | SOC_DOUBLE_R_TLV("IN4 Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4L, | ||
84 | ARIZONA_ADC_DIGITAL_VOLUME_4R, ARIZONA_IN4L_DIG_VOL_SHIFT, | ||
85 | 0xbf, 0, digital_tlv), | ||
86 | |||
87 | ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE), | ||
88 | ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | ||
89 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | ||
90 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | ||
91 | |||
92 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | ||
93 | 24, 0, eq_tlv), | ||
94 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | ||
95 | 24, 0, eq_tlv), | ||
96 | SOC_SINGLE_TLV("EQ1 B3 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B3_GAIN_SHIFT, | ||
97 | 24, 0, eq_tlv), | ||
98 | SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | ||
99 | 24, 0, eq_tlv), | ||
100 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | ||
101 | 24, 0, eq_tlv), | ||
102 | |||
103 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | ||
104 | 24, 0, eq_tlv), | ||
105 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | ||
106 | 24, 0, eq_tlv), | ||
107 | SOC_SINGLE_TLV("EQ2 B3 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B3_GAIN_SHIFT, | ||
108 | 24, 0, eq_tlv), | ||
109 | SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | ||
110 | 24, 0, eq_tlv), | ||
111 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | ||
112 | 24, 0, eq_tlv), | ||
113 | |||
114 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | ||
115 | 24, 0, eq_tlv), | ||
116 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | ||
117 | 24, 0, eq_tlv), | ||
118 | SOC_SINGLE_TLV("EQ3 B3 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B3_GAIN_SHIFT, | ||
119 | 24, 0, eq_tlv), | ||
120 | SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | ||
121 | 24, 0, eq_tlv), | ||
122 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | ||
123 | 24, 0, eq_tlv), | ||
124 | |||
125 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | ||
126 | 24, 0, eq_tlv), | ||
127 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | ||
128 | 24, 0, eq_tlv), | ||
129 | SOC_SINGLE_TLV("EQ4 B3 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B3_GAIN_SHIFT, | ||
130 | 24, 0, eq_tlv), | ||
131 | SOC_SINGLE_TLV("EQ4 B4 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B4_GAIN_SHIFT, | ||
132 | 24, 0, eq_tlv), | ||
133 | SOC_SINGLE_TLV("EQ4 B5 Volume", ARIZONA_EQ4_2, ARIZONA_EQ4_B5_GAIN_SHIFT, | ||
134 | 24, 0, eq_tlv), | ||
135 | |||
136 | ARIZONA_MIXER_CONTROLS("DRC1L", ARIZONA_DRC1LMIX_INPUT_1_SOURCE), | ||
137 | ARIZONA_MIXER_CONTROLS("DRC1R", ARIZONA_DRC1RMIX_INPUT_1_SOURCE), | ||
138 | ARIZONA_MIXER_CONTROLS("DRC2L", ARIZONA_DRC2LMIX_INPUT_1_SOURCE), | ||
139 | ARIZONA_MIXER_CONTROLS("DRC2R", ARIZONA_DRC2RMIX_INPUT_1_SOURCE), | ||
140 | |||
141 | SND_SOC_BYTES_MASK("DRC1", ARIZONA_DRC1_CTRL1, 5, | ||
142 | ARIZONA_DRC1R_ENA | ARIZONA_DRC1L_ENA), | ||
143 | SND_SOC_BYTES_MASK("DRC2", ARIZONA_DRC2_CTRL1, 5, | ||
144 | ARIZONA_DRC2R_ENA | ARIZONA_DRC2L_ENA), | ||
145 | |||
146 | ARIZONA_MIXER_CONTROLS("LHPF1", ARIZONA_HPLP1MIX_INPUT_1_SOURCE), | ||
147 | ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), | ||
148 | ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), | ||
149 | ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), | ||
150 | |||
151 | SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), | ||
152 | SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), | ||
153 | SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), | ||
154 | SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), | ||
155 | |||
156 | ARIZONA_MIXER_CONTROLS("Mic", ARIZONA_MICMIX_INPUT_1_SOURCE), | ||
157 | ARIZONA_MIXER_CONTROLS("Noise", ARIZONA_NOISEMIX_INPUT_1_SOURCE), | ||
158 | |||
159 | SOC_SINGLE_TLV("Noise Generator Volume", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
160 | ARIZONA_NOISE_GEN_GAIN_SHIFT, 0x16, 0, noise_tlv), | ||
161 | |||
162 | ARIZONA_MIXER_CONTROLS("HPOUT1L", ARIZONA_OUT1LMIX_INPUT_1_SOURCE), | ||
163 | ARIZONA_MIXER_CONTROLS("HPOUT1R", ARIZONA_OUT1RMIX_INPUT_1_SOURCE), | ||
164 | ARIZONA_MIXER_CONTROLS("HPOUT2L", ARIZONA_OUT2LMIX_INPUT_1_SOURCE), | ||
165 | ARIZONA_MIXER_CONTROLS("HPOUT2R", ARIZONA_OUT2RMIX_INPUT_1_SOURCE), | ||
166 | ARIZONA_MIXER_CONTROLS("EPOUT", ARIZONA_OUT3LMIX_INPUT_1_SOURCE), | ||
167 | ARIZONA_MIXER_CONTROLS("SPKOUTL", ARIZONA_OUT4LMIX_INPUT_1_SOURCE), | ||
168 | ARIZONA_MIXER_CONTROLS("SPKOUTR", ARIZONA_OUT4RMIX_INPUT_1_SOURCE), | ||
169 | ARIZONA_MIXER_CONTROLS("SPKDAT1L", ARIZONA_OUT5LMIX_INPUT_1_SOURCE), | ||
170 | ARIZONA_MIXER_CONTROLS("SPKDAT1R", ARIZONA_OUT5RMIX_INPUT_1_SOURCE), | ||
171 | ARIZONA_MIXER_CONTROLS("SPKDAT2L", ARIZONA_OUT6LMIX_INPUT_1_SOURCE), | ||
172 | ARIZONA_MIXER_CONTROLS("SPKDAT2R", ARIZONA_OUT6RMIX_INPUT_1_SOURCE), | ||
173 | |||
174 | SOC_SINGLE("HPOUT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_1L, | ||
175 | ARIZONA_OUT1_OSR_SHIFT, 1, 0), | ||
176 | SOC_SINGLE("OUT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_2L, | ||
177 | ARIZONA_OUT2_OSR_SHIFT, 1, 0), | ||
178 | SOC_SINGLE("EPOUT High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_3L, | ||
179 | ARIZONA_OUT3_OSR_SHIFT, 1, 0), | ||
180 | SOC_SINGLE("Speaker High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_4L, | ||
181 | ARIZONA_OUT4_OSR_SHIFT, 1, 0), | ||
182 | SOC_SINGLE("SPKDAT1 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_5L, | ||
183 | ARIZONA_OUT5_OSR_SHIFT, 1, 0), | ||
184 | SOC_SINGLE("SPKDAT2 High Performance Switch", ARIZONA_OUTPUT_PATH_CONFIG_6L, | ||
185 | ARIZONA_OUT6_OSR_SHIFT, 1, 0), | ||
186 | |||
187 | SOC_DOUBLE_R("HPOUT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
188 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_MUTE_SHIFT, 1, 1), | ||
189 | SOC_DOUBLE_R("OUT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
190 | ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_MUTE_SHIFT, 1, 1), | ||
191 | SOC_SINGLE("EPOUT Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
192 | ARIZONA_OUT3L_MUTE_SHIFT, 1, 1), | ||
193 | SOC_DOUBLE_R("Speaker Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
194 | ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_MUTE_SHIFT, 1, 1), | ||
195 | SOC_DOUBLE_R("SPKDAT1 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
196 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_MUTE_SHIFT, 1, 1), | ||
197 | SOC_DOUBLE_R("SPKDAT2 Digital Switch", ARIZONA_DAC_DIGITAL_VOLUME_6L, | ||
198 | ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_MUTE_SHIFT, 1, 1), | ||
199 | |||
200 | SOC_DOUBLE_R_TLV("HPOUT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
201 | ARIZONA_DAC_DIGITAL_VOLUME_1R, ARIZONA_OUT1L_VOL_SHIFT, | ||
202 | 0xbf, 0, digital_tlv), | ||
203 | SOC_DOUBLE_R_TLV("OUT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
204 | ARIZONA_DAC_DIGITAL_VOLUME_2R, ARIZONA_OUT2L_VOL_SHIFT, | ||
205 | 0xbf, 0, digital_tlv), | ||
206 | SOC_SINGLE_TLV("EPOUT Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
207 | ARIZONA_OUT3L_VOL_SHIFT, 0xbf, 0, digital_tlv), | ||
208 | SOC_DOUBLE_R_TLV("Speaker Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
209 | ARIZONA_DAC_DIGITAL_VOLUME_4R, ARIZONA_OUT4L_VOL_SHIFT, | ||
210 | 0xbf, 0, digital_tlv), | ||
211 | SOC_DOUBLE_R_TLV("SPKDAT1 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
212 | ARIZONA_DAC_DIGITAL_VOLUME_5R, ARIZONA_OUT5L_VOL_SHIFT, | ||
213 | 0xbf, 0, digital_tlv), | ||
214 | SOC_DOUBLE_R_TLV("SPKDAT2 Digital Volume", ARIZONA_DAC_DIGITAL_VOLUME_6L, | ||
215 | ARIZONA_DAC_DIGITAL_VOLUME_6R, ARIZONA_OUT6L_VOL_SHIFT, | ||
216 | 0xbf, 0, digital_tlv), | ||
217 | |||
218 | SOC_DOUBLE_R_RANGE_TLV("HPOUT1 Volume", ARIZONA_OUTPUT_PATH_CONFIG_1L, | ||
219 | ARIZONA_OUTPUT_PATH_CONFIG_1R, | ||
220 | ARIZONA_OUT1L_PGA_VOL_SHIFT, | ||
221 | 0x34, 0x40, 0, ana_tlv), | ||
222 | SOC_DOUBLE_R_RANGE_TLV("OUT2 Volume", ARIZONA_OUTPUT_PATH_CONFIG_2L, | ||
223 | ARIZONA_OUTPUT_PATH_CONFIG_2R, | ||
224 | ARIZONA_OUT2L_PGA_VOL_SHIFT, | ||
225 | 0x34, 0x40, 0, ana_tlv), | ||
226 | SOC_SINGLE_RANGE_TLV("EPOUT Volume", ARIZONA_OUTPUT_PATH_CONFIG_3L, | ||
227 | ARIZONA_OUT3L_PGA_VOL_SHIFT, 0x34, 0x40, 0, ana_tlv), | ||
228 | |||
229 | SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, | ||
230 | ARIZONA_SPK1R_MUTE_SHIFT, 1, 1), | ||
231 | SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, | ||
232 | ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), | ||
233 | |||
234 | ARIZONA_MIXER_CONTROLS("AIF1TX1", ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE), | ||
235 | ARIZONA_MIXER_CONTROLS("AIF1TX2", ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE), | ||
236 | ARIZONA_MIXER_CONTROLS("AIF1TX3", ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE), | ||
237 | ARIZONA_MIXER_CONTROLS("AIF1TX4", ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE), | ||
238 | ARIZONA_MIXER_CONTROLS("AIF1TX5", ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE), | ||
239 | ARIZONA_MIXER_CONTROLS("AIF1TX6", ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE), | ||
240 | ARIZONA_MIXER_CONTROLS("AIF1TX7", ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE), | ||
241 | ARIZONA_MIXER_CONTROLS("AIF1TX8", ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE), | ||
242 | |||
243 | ARIZONA_MIXER_CONTROLS("AIF2TX1", ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE), | ||
244 | ARIZONA_MIXER_CONTROLS("AIF2TX2", ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE), | ||
245 | |||
246 | ARIZONA_MIXER_CONTROLS("AIF3TX1", ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE), | ||
247 | ARIZONA_MIXER_CONTROLS("AIF3TX2", ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE), | ||
248 | }; | ||
249 | |||
250 | ARIZONA_MIXER_ENUMS(EQ1, ARIZONA_EQ1MIX_INPUT_1_SOURCE); | ||
251 | ARIZONA_MIXER_ENUMS(EQ2, ARIZONA_EQ2MIX_INPUT_1_SOURCE); | ||
252 | ARIZONA_MIXER_ENUMS(EQ3, ARIZONA_EQ3MIX_INPUT_1_SOURCE); | ||
253 | ARIZONA_MIXER_ENUMS(EQ4, ARIZONA_EQ4MIX_INPUT_1_SOURCE); | ||
254 | |||
255 | ARIZONA_MIXER_ENUMS(DRC1L, ARIZONA_DRC1LMIX_INPUT_1_SOURCE); | ||
256 | ARIZONA_MIXER_ENUMS(DRC1R, ARIZONA_DRC1RMIX_INPUT_1_SOURCE); | ||
257 | ARIZONA_MIXER_ENUMS(DRC2L, ARIZONA_DRC2LMIX_INPUT_1_SOURCE); | ||
258 | ARIZONA_MIXER_ENUMS(DRC2R, ARIZONA_DRC2RMIX_INPUT_1_SOURCE); | ||
259 | |||
260 | ARIZONA_MIXER_ENUMS(LHPF1, ARIZONA_HPLP1MIX_INPUT_1_SOURCE); | ||
261 | ARIZONA_MIXER_ENUMS(LHPF2, ARIZONA_HPLP2MIX_INPUT_1_SOURCE); | ||
262 | ARIZONA_MIXER_ENUMS(LHPF3, ARIZONA_HPLP3MIX_INPUT_1_SOURCE); | ||
263 | ARIZONA_MIXER_ENUMS(LHPF4, ARIZONA_HPLP4MIX_INPUT_1_SOURCE); | ||
264 | |||
265 | ARIZONA_MIXER_ENUMS(Mic, ARIZONA_MICMIX_INPUT_1_SOURCE); | ||
266 | ARIZONA_MIXER_ENUMS(Noise, ARIZONA_NOISEMIX_INPUT_1_SOURCE); | ||
267 | |||
268 | ARIZONA_MIXER_ENUMS(PWM1, ARIZONA_PWM1MIX_INPUT_1_SOURCE); | ||
269 | ARIZONA_MIXER_ENUMS(PWM2, ARIZONA_PWM2MIX_INPUT_1_SOURCE); | ||
270 | |||
271 | ARIZONA_MIXER_ENUMS(OUT1L, ARIZONA_OUT1LMIX_INPUT_1_SOURCE); | ||
272 | ARIZONA_MIXER_ENUMS(OUT1R, ARIZONA_OUT1RMIX_INPUT_1_SOURCE); | ||
273 | ARIZONA_MIXER_ENUMS(OUT2L, ARIZONA_OUT2LMIX_INPUT_1_SOURCE); | ||
274 | ARIZONA_MIXER_ENUMS(OUT2R, ARIZONA_OUT2RMIX_INPUT_1_SOURCE); | ||
275 | ARIZONA_MIXER_ENUMS(OUT3, ARIZONA_OUT3LMIX_INPUT_1_SOURCE); | ||
276 | ARIZONA_MIXER_ENUMS(SPKOUTL, ARIZONA_OUT4LMIX_INPUT_1_SOURCE); | ||
277 | ARIZONA_MIXER_ENUMS(SPKOUTR, ARIZONA_OUT4RMIX_INPUT_1_SOURCE); | ||
278 | ARIZONA_MIXER_ENUMS(SPKDAT1L, ARIZONA_OUT5LMIX_INPUT_1_SOURCE); | ||
279 | ARIZONA_MIXER_ENUMS(SPKDAT1R, ARIZONA_OUT5RMIX_INPUT_1_SOURCE); | ||
280 | ARIZONA_MIXER_ENUMS(SPKDAT2L, ARIZONA_OUT6LMIX_INPUT_1_SOURCE); | ||
281 | ARIZONA_MIXER_ENUMS(SPKDAT2R, ARIZONA_OUT6RMIX_INPUT_1_SOURCE); | ||
282 | |||
283 | ARIZONA_MIXER_ENUMS(AIF1TX1, ARIZONA_AIF1TX1MIX_INPUT_1_SOURCE); | ||
284 | ARIZONA_MIXER_ENUMS(AIF1TX2, ARIZONA_AIF1TX2MIX_INPUT_1_SOURCE); | ||
285 | ARIZONA_MIXER_ENUMS(AIF1TX3, ARIZONA_AIF1TX3MIX_INPUT_1_SOURCE); | ||
286 | ARIZONA_MIXER_ENUMS(AIF1TX4, ARIZONA_AIF1TX4MIX_INPUT_1_SOURCE); | ||
287 | ARIZONA_MIXER_ENUMS(AIF1TX5, ARIZONA_AIF1TX5MIX_INPUT_1_SOURCE); | ||
288 | ARIZONA_MIXER_ENUMS(AIF1TX6, ARIZONA_AIF1TX6MIX_INPUT_1_SOURCE); | ||
289 | ARIZONA_MIXER_ENUMS(AIF1TX7, ARIZONA_AIF1TX7MIX_INPUT_1_SOURCE); | ||
290 | ARIZONA_MIXER_ENUMS(AIF1TX8, ARIZONA_AIF1TX8MIX_INPUT_1_SOURCE); | ||
291 | |||
292 | ARIZONA_MIXER_ENUMS(AIF2TX1, ARIZONA_AIF2TX1MIX_INPUT_1_SOURCE); | ||
293 | ARIZONA_MIXER_ENUMS(AIF2TX2, ARIZONA_AIF2TX2MIX_INPUT_1_SOURCE); | ||
294 | |||
295 | ARIZONA_MIXER_ENUMS(AIF3TX1, ARIZONA_AIF3TX1MIX_INPUT_1_SOURCE); | ||
296 | ARIZONA_MIXER_ENUMS(AIF3TX2, ARIZONA_AIF3TX2MIX_INPUT_1_SOURCE); | ||
297 | |||
298 | ARIZONA_MIXER_ENUMS(ASRC1L, ARIZONA_ASRC1LMIX_INPUT_1_SOURCE); | ||
299 | ARIZONA_MIXER_ENUMS(ASRC1R, ARIZONA_ASRC1RMIX_INPUT_1_SOURCE); | ||
300 | ARIZONA_MIXER_ENUMS(ASRC2L, ARIZONA_ASRC2LMIX_INPUT_1_SOURCE); | ||
301 | ARIZONA_MIXER_ENUMS(ASRC2R, ARIZONA_ASRC2RMIX_INPUT_1_SOURCE); | ||
302 | |||
303 | static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = { | ||
304 | SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT, | ||
305 | 0, NULL, 0), | ||
306 | SND_SOC_DAPM_SUPPLY("ASYNCCLK", ARIZONA_ASYNC_CLOCK_1, | ||
307 | ARIZONA_ASYNC_CLK_ENA_SHIFT, 0, NULL, 0), | ||
308 | |||
309 | SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD2", 0), | ||
310 | SND_SOC_DAPM_REGULATOR_SUPPLY("DBVDD3", 0), | ||
311 | SND_SOC_DAPM_REGULATOR_SUPPLY("CPVDD", 20), | ||
312 | SND_SOC_DAPM_REGULATOR_SUPPLY("MICVDD", 0), | ||
313 | SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDL", 0), | ||
314 | SND_SOC_DAPM_REGULATOR_SUPPLY("SPKVDDR", 0), | ||
315 | |||
316 | SND_SOC_DAPM_SIGGEN("TONE"), | ||
317 | SND_SOC_DAPM_SIGGEN("NOISE"), | ||
318 | |||
319 | SND_SOC_DAPM_INPUT("IN1L"), | ||
320 | SND_SOC_DAPM_INPUT("IN1R"), | ||
321 | SND_SOC_DAPM_INPUT("IN2L"), | ||
322 | SND_SOC_DAPM_INPUT("IN2R"), | ||
323 | SND_SOC_DAPM_INPUT("IN3L"), | ||
324 | SND_SOC_DAPM_INPUT("IN3R"), | ||
325 | SND_SOC_DAPM_INPUT("IN4L"), | ||
326 | SND_SOC_DAPM_INPUT("IN4R"), | ||
327 | |||
328 | SND_SOC_DAPM_PGA_E("IN1L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1L_ENA_SHIFT, | ||
329 | 0, NULL, 0, arizona_in_ev, | ||
330 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
331 | SND_SOC_DAPM_PGA_E("IN1R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN1R_ENA_SHIFT, | ||
332 | 0, NULL, 0, arizona_in_ev, | ||
333 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
334 | SND_SOC_DAPM_PGA_E("IN2L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2L_ENA_SHIFT, | ||
335 | 0, NULL, 0, arizona_in_ev, | ||
336 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
337 | SND_SOC_DAPM_PGA_E("IN2R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN2R_ENA_SHIFT, | ||
338 | 0, NULL, 0, arizona_in_ev, | ||
339 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
340 | SND_SOC_DAPM_PGA_E("IN3L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3L_ENA_SHIFT, | ||
341 | 0, NULL, 0, arizona_in_ev, | ||
342 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
343 | SND_SOC_DAPM_PGA_E("IN3R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN3R_ENA_SHIFT, | ||
344 | 0, NULL, 0, arizona_in_ev, | ||
345 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
346 | SND_SOC_DAPM_PGA_E("IN4L PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4L_ENA_SHIFT, | ||
347 | 0, NULL, 0, arizona_in_ev, | ||
348 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
349 | SND_SOC_DAPM_PGA_E("IN4R PGA", ARIZONA_INPUT_ENABLES, ARIZONA_IN4R_ENA_SHIFT, | ||
350 | 0, NULL, 0, arizona_in_ev, | ||
351 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
352 | |||
353 | SND_SOC_DAPM_SUPPLY("MICBIAS1", ARIZONA_MIC_BIAS_CTRL_1, | ||
354 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
355 | SND_SOC_DAPM_SUPPLY("MICBIAS2", ARIZONA_MIC_BIAS_CTRL_2, | ||
356 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
357 | SND_SOC_DAPM_SUPPLY("MICBIAS3", ARIZONA_MIC_BIAS_CTRL_3, | ||
358 | ARIZONA_MICB1_ENA_SHIFT, 0, NULL, 0), | ||
359 | |||
360 | SND_SOC_DAPM_PGA("Noise Generator", ARIZONA_COMFORT_NOISE_GENERATOR, | ||
361 | ARIZONA_NOISE_GEN_ENA_SHIFT, 0, NULL, 0), | ||
362 | |||
363 | SND_SOC_DAPM_PGA("Tone Generator 1", ARIZONA_TONE_GENERATOR_1, | ||
364 | ARIZONA_TONE1_ENA_SHIFT, 0, NULL, 0), | ||
365 | SND_SOC_DAPM_PGA("Tone Generator 2", ARIZONA_TONE_GENERATOR_1, | ||
366 | ARIZONA_TONE2_ENA_SHIFT, 0, NULL, 0), | ||
367 | |||
368 | SND_SOC_DAPM_PGA("Mic Mute Mixer", ARIZONA_MIC_NOISE_MIX_CONTROL_1, | ||
369 | ARIZONA_MICMUTE_MIX_ENA_SHIFT, 0, NULL, 0), | ||
370 | |||
371 | SND_SOC_DAPM_PGA("EQ1", ARIZONA_EQ1_1, ARIZONA_EQ1_ENA_SHIFT, 0, NULL, 0), | ||
372 | SND_SOC_DAPM_PGA("EQ2", ARIZONA_EQ2_1, ARIZONA_EQ2_ENA_SHIFT, 0, NULL, 0), | ||
373 | SND_SOC_DAPM_PGA("EQ3", ARIZONA_EQ3_1, ARIZONA_EQ3_ENA_SHIFT, 0, NULL, 0), | ||
374 | SND_SOC_DAPM_PGA("EQ4", ARIZONA_EQ4_1, ARIZONA_EQ4_ENA_SHIFT, 0, NULL, 0), | ||
375 | |||
376 | SND_SOC_DAPM_PGA("DRC1L", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1L_ENA_SHIFT, 0, | ||
377 | NULL, 0), | ||
378 | SND_SOC_DAPM_PGA("DRC1R", ARIZONA_DRC1_CTRL1, ARIZONA_DRC1R_ENA_SHIFT, 0, | ||
379 | NULL, 0), | ||
380 | SND_SOC_DAPM_PGA("DRC2L", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2L_ENA_SHIFT, 0, | ||
381 | NULL, 0), | ||
382 | SND_SOC_DAPM_PGA("DRC2R", ARIZONA_DRC2_CTRL1, ARIZONA_DRC2R_ENA_SHIFT, 0, | ||
383 | NULL, 0), | ||
384 | |||
385 | SND_SOC_DAPM_PGA("LHPF1", ARIZONA_HPLPF1_1, ARIZONA_LHPF1_ENA_SHIFT, 0, | ||
386 | NULL, 0), | ||
387 | SND_SOC_DAPM_PGA("LHPF2", ARIZONA_HPLPF2_1, ARIZONA_LHPF2_ENA_SHIFT, 0, | ||
388 | NULL, 0), | ||
389 | SND_SOC_DAPM_PGA("LHPF3", ARIZONA_HPLPF3_1, ARIZONA_LHPF3_ENA_SHIFT, 0, | ||
390 | NULL, 0), | ||
391 | SND_SOC_DAPM_PGA("LHPF4", ARIZONA_HPLPF4_1, ARIZONA_LHPF4_ENA_SHIFT, 0, | ||
392 | NULL, 0), | ||
393 | |||
394 | SND_SOC_DAPM_PGA("PWM1 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM1_ENA_SHIFT, | ||
395 | 0, NULL, 0), | ||
396 | SND_SOC_DAPM_PGA("PWM2 Driver", ARIZONA_PWM_DRIVE_1, ARIZONA_PWM2_ENA_SHIFT, | ||
397 | 0, NULL, 0), | ||
398 | |||
399 | SND_SOC_DAPM_PGA("ASRC1L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1L_ENA_SHIFT, 0, | ||
400 | NULL, 0), | ||
401 | SND_SOC_DAPM_PGA("ASRC1R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC1R_ENA_SHIFT, 0, | ||
402 | NULL, 0), | ||
403 | SND_SOC_DAPM_PGA("ASRC2L", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2L_ENA_SHIFT, 0, | ||
404 | NULL, 0), | ||
405 | SND_SOC_DAPM_PGA("ASRC2R", ARIZONA_ASRC_ENABLE, ARIZONA_ASRC2R_ENA_SHIFT, 0, | ||
406 | NULL, 0), | ||
407 | |||
408 | SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0, | ||
409 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0), | ||
410 | SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0, | ||
411 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX2_ENA_SHIFT, 0), | ||
412 | SND_SOC_DAPM_AIF_OUT("AIF1TX3", NULL, 0, | ||
413 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX3_ENA_SHIFT, 0), | ||
414 | SND_SOC_DAPM_AIF_OUT("AIF1TX4", NULL, 0, | ||
415 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX4_ENA_SHIFT, 0), | ||
416 | SND_SOC_DAPM_AIF_OUT("AIF1TX5", NULL, 0, | ||
417 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX5_ENA_SHIFT, 0), | ||
418 | SND_SOC_DAPM_AIF_OUT("AIF1TX6", NULL, 0, | ||
419 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX6_ENA_SHIFT, 0), | ||
420 | SND_SOC_DAPM_AIF_OUT("AIF1TX7", NULL, 0, | ||
421 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX7_ENA_SHIFT, 0), | ||
422 | SND_SOC_DAPM_AIF_OUT("AIF1TX8", NULL, 0, | ||
423 | ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX8_ENA_SHIFT, 0), | ||
424 | |||
425 | SND_SOC_DAPM_AIF_IN("AIF1RX1", NULL, 0, | ||
426 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX1_ENA_SHIFT, 0), | ||
427 | SND_SOC_DAPM_AIF_IN("AIF1RX2", NULL, 0, | ||
428 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX2_ENA_SHIFT, 0), | ||
429 | SND_SOC_DAPM_AIF_IN("AIF1RX3", NULL, 0, | ||
430 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX3_ENA_SHIFT, 0), | ||
431 | SND_SOC_DAPM_AIF_IN("AIF1RX4", NULL, 0, | ||
432 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX4_ENA_SHIFT, 0), | ||
433 | SND_SOC_DAPM_AIF_IN("AIF1RX5", NULL, 0, | ||
434 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX5_ENA_SHIFT, 0), | ||
435 | SND_SOC_DAPM_AIF_IN("AIF1RX6", NULL, 0, | ||
436 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX6_ENA_SHIFT, 0), | ||
437 | SND_SOC_DAPM_AIF_IN("AIF1RX7", NULL, 0, | ||
438 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX7_ENA_SHIFT, 0), | ||
439 | SND_SOC_DAPM_AIF_IN("AIF1RX8", NULL, 0, | ||
440 | ARIZONA_AIF1_RX_ENABLES, ARIZONA_AIF1RX8_ENA_SHIFT, 0), | ||
441 | |||
442 | SND_SOC_DAPM_AIF_OUT("AIF2TX1", NULL, 0, | ||
443 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX1_ENA_SHIFT, 0), | ||
444 | SND_SOC_DAPM_AIF_OUT("AIF2TX2", NULL, 0, | ||
445 | ARIZONA_AIF2_TX_ENABLES, ARIZONA_AIF2TX2_ENA_SHIFT, 0), | ||
446 | |||
447 | SND_SOC_DAPM_AIF_IN("AIF2RX1", NULL, 0, | ||
448 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX1_ENA_SHIFT, 0), | ||
449 | SND_SOC_DAPM_AIF_IN("AIF2RX2", NULL, 0, | ||
450 | ARIZONA_AIF2_RX_ENABLES, ARIZONA_AIF2RX2_ENA_SHIFT, 0), | ||
451 | |||
452 | SND_SOC_DAPM_AIF_OUT("AIF3TX1", NULL, 0, | ||
453 | ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX1_ENA_SHIFT, 0), | ||
454 | SND_SOC_DAPM_AIF_OUT("AIF3TX2", NULL, 0, | ||
455 | ARIZONA_AIF3_TX_ENABLES, ARIZONA_AIF3TX2_ENA_SHIFT, 0), | ||
456 | |||
457 | SND_SOC_DAPM_AIF_IN("AIF3RX1", NULL, 0, | ||
458 | ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX1_ENA_SHIFT, 0), | ||
459 | SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, | ||
460 | ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), | ||
461 | |||
462 | SND_SOC_DAPM_PGA_E("OUT1L", ARIZONA_OUTPUT_ENABLES_1, | ||
463 | ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
464 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
465 | SND_SOC_DAPM_PGA_E("OUT1R", ARIZONA_OUTPUT_ENABLES_1, | ||
466 | ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
467 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
468 | SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, | ||
469 | ARIZONA_OUT2L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
470 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
471 | SND_SOC_DAPM_PGA_E("OUT2R", ARIZONA_OUTPUT_ENABLES_1, | ||
472 | ARIZONA_OUT2R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
473 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
474 | SND_SOC_DAPM_PGA_E("OUT3L", ARIZONA_OUTPUT_ENABLES_1, | ||
475 | ARIZONA_OUT3L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
476 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
477 | SND_SOC_DAPM_PGA_E("OUT4L", ARIZONA_OUTPUT_ENABLES_1, | ||
478 | ARIZONA_OUT4L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
479 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
480 | SND_SOC_DAPM_PGA_E("OUT4R", ARIZONA_OUTPUT_ENABLES_1, | ||
481 | ARIZONA_OUT4R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
482 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
483 | SND_SOC_DAPM_PGA_E("OUT5L", ARIZONA_OUTPUT_ENABLES_1, | ||
484 | ARIZONA_OUT5L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
485 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
486 | SND_SOC_DAPM_PGA_E("OUT5R", ARIZONA_OUTPUT_ENABLES_1, | ||
487 | ARIZONA_OUT5R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
488 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
489 | SND_SOC_DAPM_PGA_E("OUT6L", ARIZONA_OUTPUT_ENABLES_1, | ||
490 | ARIZONA_OUT6L_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
491 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
492 | SND_SOC_DAPM_PGA_E("OUT6R", ARIZONA_OUTPUT_ENABLES_1, | ||
493 | ARIZONA_OUT6R_ENA_SHIFT, 0, NULL, 0, arizona_out_ev, | ||
494 | SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), | ||
495 | |||
496 | ARIZONA_MIXER_WIDGETS(EQ1, "EQ1"), | ||
497 | ARIZONA_MIXER_WIDGETS(EQ2, "EQ2"), | ||
498 | ARIZONA_MIXER_WIDGETS(EQ3, "EQ3"), | ||
499 | ARIZONA_MIXER_WIDGETS(EQ4, "EQ4"), | ||
500 | |||
501 | ARIZONA_MIXER_WIDGETS(DRC1L, "DRC1L"), | ||
502 | ARIZONA_MIXER_WIDGETS(DRC1R, "DRC1R"), | ||
503 | ARIZONA_MIXER_WIDGETS(DRC2L, "DRC2L"), | ||
504 | ARIZONA_MIXER_WIDGETS(DRC2R, "DRC2R"), | ||
505 | |||
506 | ARIZONA_MIXER_WIDGETS(LHPF1, "LHPF1"), | ||
507 | ARIZONA_MIXER_WIDGETS(LHPF2, "LHPF2"), | ||
508 | ARIZONA_MIXER_WIDGETS(LHPF3, "LHPF3"), | ||
509 | ARIZONA_MIXER_WIDGETS(LHPF4, "LHPF4"), | ||
510 | |||
511 | ARIZONA_MIXER_WIDGETS(Mic, "Mic"), | ||
512 | ARIZONA_MIXER_WIDGETS(Noise, "Noise"), | ||
513 | |||
514 | ARIZONA_MIXER_WIDGETS(PWM1, "PWM1"), | ||
515 | ARIZONA_MIXER_WIDGETS(PWM2, "PWM2"), | ||
516 | |||
517 | ARIZONA_MIXER_WIDGETS(OUT1L, "HPOUT1L"), | ||
518 | ARIZONA_MIXER_WIDGETS(OUT1R, "HPOUT1R"), | ||
519 | ARIZONA_MIXER_WIDGETS(OUT2L, "HPOUT2L"), | ||
520 | ARIZONA_MIXER_WIDGETS(OUT2R, "HPOUT2R"), | ||
521 | ARIZONA_MIXER_WIDGETS(OUT3, "EPOUT"), | ||
522 | ARIZONA_MIXER_WIDGETS(SPKOUTL, "SPKOUTL"), | ||
523 | ARIZONA_MIXER_WIDGETS(SPKOUTR, "SPKOUTR"), | ||
524 | ARIZONA_MIXER_WIDGETS(SPKDAT1L, "SPKDAT1L"), | ||
525 | ARIZONA_MIXER_WIDGETS(SPKDAT1R, "SPKDAT1R"), | ||
526 | ARIZONA_MIXER_WIDGETS(SPKDAT2L, "SPKDAT2L"), | ||
527 | ARIZONA_MIXER_WIDGETS(SPKDAT2R, "SPKDAT2R"), | ||
528 | |||
529 | ARIZONA_MIXER_WIDGETS(AIF1TX1, "AIF1TX1"), | ||
530 | ARIZONA_MIXER_WIDGETS(AIF1TX2, "AIF1TX2"), | ||
531 | ARIZONA_MIXER_WIDGETS(AIF1TX3, "AIF1TX3"), | ||
532 | ARIZONA_MIXER_WIDGETS(AIF1TX4, "AIF1TX4"), | ||
533 | ARIZONA_MIXER_WIDGETS(AIF1TX5, "AIF1TX5"), | ||
534 | ARIZONA_MIXER_WIDGETS(AIF1TX6, "AIF1TX6"), | ||
535 | ARIZONA_MIXER_WIDGETS(AIF1TX7, "AIF1TX7"), | ||
536 | ARIZONA_MIXER_WIDGETS(AIF1TX8, "AIF1TX8"), | ||
537 | |||
538 | ARIZONA_MIXER_WIDGETS(AIF2TX1, "AIF2TX1"), | ||
539 | ARIZONA_MIXER_WIDGETS(AIF2TX2, "AIF2TX2"), | ||
540 | |||
541 | ARIZONA_MIXER_WIDGETS(AIF3TX1, "AIF3TX1"), | ||
542 | ARIZONA_MIXER_WIDGETS(AIF3TX2, "AIF3TX2"), | ||
543 | |||
544 | ARIZONA_MIXER_WIDGETS(ASRC1L, "ASRC1L"), | ||
545 | ARIZONA_MIXER_WIDGETS(ASRC1R, "ASRC1R"), | ||
546 | ARIZONA_MIXER_WIDGETS(ASRC2L, "ASRC2L"), | ||
547 | ARIZONA_MIXER_WIDGETS(ASRC2R, "ASRC2R"), | ||
548 | |||
549 | SND_SOC_DAPM_OUTPUT("HPOUT1L"), | ||
550 | SND_SOC_DAPM_OUTPUT("HPOUT1R"), | ||
551 | SND_SOC_DAPM_OUTPUT("HPOUT2L"), | ||
552 | SND_SOC_DAPM_OUTPUT("HPOUT2R"), | ||
553 | SND_SOC_DAPM_OUTPUT("EPOUTN"), | ||
554 | SND_SOC_DAPM_OUTPUT("EPOUTP"), | ||
555 | SND_SOC_DAPM_OUTPUT("SPKOUTLN"), | ||
556 | SND_SOC_DAPM_OUTPUT("SPKOUTLP"), | ||
557 | SND_SOC_DAPM_OUTPUT("SPKOUTRN"), | ||
558 | SND_SOC_DAPM_OUTPUT("SPKOUTRP"), | ||
559 | SND_SOC_DAPM_OUTPUT("SPKDAT1L"), | ||
560 | SND_SOC_DAPM_OUTPUT("SPKDAT1R"), | ||
561 | SND_SOC_DAPM_OUTPUT("SPKDAT2L"), | ||
562 | SND_SOC_DAPM_OUTPUT("SPKDAT2R"), | ||
563 | }; | ||
564 | |||
565 | #define ARIZONA_MIXER_INPUT_ROUTES(name) \ | ||
566 | { name, "Noise Generator", "Noise Generator" }, \ | ||
567 | { name, "Tone Generator 1", "Tone Generator 1" }, \ | ||
568 | { name, "Tone Generator 2", "Tone Generator 2" }, \ | ||
569 | { name, "IN1L", "IN1L PGA" }, \ | ||
570 | { name, "IN1R", "IN1R PGA" }, \ | ||
571 | { name, "IN2L", "IN2L PGA" }, \ | ||
572 | { name, "IN2R", "IN2R PGA" }, \ | ||
573 | { name, "IN3L", "IN3L PGA" }, \ | ||
574 | { name, "IN3R", "IN3R PGA" }, \ | ||
575 | { name, "IN4L", "IN4L PGA" }, \ | ||
576 | { name, "IN4R", "IN4R PGA" }, \ | ||
577 | { name, "Mic Mute Mixer", "Mic Mute Mixer" }, \ | ||
578 | { name, "AIF1RX1", "AIF1RX1" }, \ | ||
579 | { name, "AIF1RX2", "AIF1RX2" }, \ | ||
580 | { name, "AIF1RX3", "AIF1RX3" }, \ | ||
581 | { name, "AIF1RX4", "AIF1RX4" }, \ | ||
582 | { name, "AIF1RX5", "AIF1RX5" }, \ | ||
583 | { name, "AIF1RX6", "AIF1RX6" }, \ | ||
584 | { name, "AIF1RX7", "AIF1RX7" }, \ | ||
585 | { name, "AIF1RX8", "AIF1RX8" }, \ | ||
586 | { name, "AIF2RX1", "AIF2RX1" }, \ | ||
587 | { name, "AIF2RX2", "AIF2RX2" }, \ | ||
588 | { name, "AIF3RX1", "AIF3RX1" }, \ | ||
589 | { name, "AIF3RX2", "AIF3RX2" }, \ | ||
590 | { name, "EQ1", "EQ1" }, \ | ||
591 | { name, "EQ2", "EQ2" }, \ | ||
592 | { name, "EQ3", "EQ3" }, \ | ||
593 | { name, "EQ4", "EQ4" }, \ | ||
594 | { name, "DRC1L", "DRC1L" }, \ | ||
595 | { name, "DRC1R", "DRC1R" }, \ | ||
596 | { name, "DRC2L", "DRC2L" }, \ | ||
597 | { name, "DRC2R", "DRC2R" }, \ | ||
598 | { name, "LHPF1", "LHPF1" }, \ | ||
599 | { name, "LHPF2", "LHPF2" }, \ | ||
600 | { name, "LHPF3", "LHPF3" }, \ | ||
601 | { name, "LHPF4", "LHPF4" }, \ | ||
602 | { name, "ASRC1L", "ASRC1L" }, \ | ||
603 | { name, "ASRC1R", "ASRC1R" }, \ | ||
604 | { name, "ASRC2L", "ASRC2L" }, \ | ||
605 | { name, "ASRC2R", "ASRC2R" } | ||
606 | |||
607 | static const struct snd_soc_dapm_route wm5110_dapm_routes[] = { | ||
608 | { "AIF2 Capture", NULL, "DBVDD2" }, | ||
609 | { "AIF2 Playback", NULL, "DBVDD2" }, | ||
610 | |||
611 | { "AIF3 Capture", NULL, "DBVDD3" }, | ||
612 | { "AIF3 Playback", NULL, "DBVDD3" }, | ||
613 | |||
614 | { "OUT1L", NULL, "CPVDD" }, | ||
615 | { "OUT1R", NULL, "CPVDD" }, | ||
616 | { "OUT2L", NULL, "CPVDD" }, | ||
617 | { "OUT2R", NULL, "CPVDD" }, | ||
618 | { "OUT3L", NULL, "CPVDD" }, | ||
619 | |||
620 | { "OUT4L", NULL, "SPKVDDL" }, | ||
621 | { "OUT4R", NULL, "SPKVDDR" }, | ||
622 | |||
623 | { "OUT1L", NULL, "SYSCLK" }, | ||
624 | { "OUT1R", NULL, "SYSCLK" }, | ||
625 | { "OUT2L", NULL, "SYSCLK" }, | ||
626 | { "OUT2R", NULL, "SYSCLK" }, | ||
627 | { "OUT3L", NULL, "SYSCLK" }, | ||
628 | { "OUT4L", NULL, "SYSCLK" }, | ||
629 | { "OUT4R", NULL, "SYSCLK" }, | ||
630 | { "OUT5L", NULL, "SYSCLK" }, | ||
631 | { "OUT5R", NULL, "SYSCLK" }, | ||
632 | { "OUT6L", NULL, "SYSCLK" }, | ||
633 | { "OUT6R", NULL, "SYSCLK" }, | ||
634 | |||
635 | { "MICBIAS1", NULL, "MICVDD" }, | ||
636 | { "MICBIAS2", NULL, "MICVDD" }, | ||
637 | { "MICBIAS3", NULL, "MICVDD" }, | ||
638 | |||
639 | { "Noise Generator", NULL, "NOISE" }, | ||
640 | { "Tone Generator 1", NULL, "TONE" }, | ||
641 | { "Tone Generator 2", NULL, "TONE" }, | ||
642 | |||
643 | { "Mic Mute Mixer", NULL, "Noise Mixer" }, | ||
644 | { "Mic Mute Mixer", NULL, "Mic Mixer" }, | ||
645 | |||
646 | { "AIF1 Capture", NULL, "AIF1TX1" }, | ||
647 | { "AIF1 Capture", NULL, "AIF1TX2" }, | ||
648 | { "AIF1 Capture", NULL, "AIF1TX3" }, | ||
649 | { "AIF1 Capture", NULL, "AIF1TX4" }, | ||
650 | { "AIF1 Capture", NULL, "AIF1TX5" }, | ||
651 | { "AIF1 Capture", NULL, "AIF1TX6" }, | ||
652 | { "AIF1 Capture", NULL, "AIF1TX7" }, | ||
653 | { "AIF1 Capture", NULL, "AIF1TX8" }, | ||
654 | |||
655 | { "AIF1RX1", NULL, "AIF1 Playback" }, | ||
656 | { "AIF1RX2", NULL, "AIF1 Playback" }, | ||
657 | { "AIF1RX3", NULL, "AIF1 Playback" }, | ||
658 | { "AIF1RX4", NULL, "AIF1 Playback" }, | ||
659 | { "AIF1RX5", NULL, "AIF1 Playback" }, | ||
660 | { "AIF1RX6", NULL, "AIF1 Playback" }, | ||
661 | { "AIF1RX7", NULL, "AIF1 Playback" }, | ||
662 | { "AIF1RX8", NULL, "AIF1 Playback" }, | ||
663 | |||
664 | { "AIF2 Capture", NULL, "AIF2TX1" }, | ||
665 | { "AIF2 Capture", NULL, "AIF2TX2" }, | ||
666 | |||
667 | { "AIF2RX1", NULL, "AIF2 Playback" }, | ||
668 | { "AIF2RX2", NULL, "AIF2 Playback" }, | ||
669 | |||
670 | { "AIF3 Capture", NULL, "AIF3TX1" }, | ||
671 | { "AIF3 Capture", NULL, "AIF3TX2" }, | ||
672 | |||
673 | { "AIF3RX1", NULL, "AIF3 Playback" }, | ||
674 | { "AIF3RX2", NULL, "AIF3 Playback" }, | ||
675 | |||
676 | { "AIF1 Playback", NULL, "SYSCLK" }, | ||
677 | { "AIF2 Playback", NULL, "SYSCLK" }, | ||
678 | { "AIF3 Playback", NULL, "SYSCLK" }, | ||
679 | |||
680 | { "AIF1 Capture", NULL, "SYSCLK" }, | ||
681 | { "AIF2 Capture", NULL, "SYSCLK" }, | ||
682 | { "AIF3 Capture", NULL, "SYSCLK" }, | ||
683 | |||
684 | ARIZONA_MIXER_ROUTES("OUT1L", "HPOUT1L"), | ||
685 | ARIZONA_MIXER_ROUTES("OUT1R", "HPOUT1R"), | ||
686 | ARIZONA_MIXER_ROUTES("OUT2L", "HPOUT2L"), | ||
687 | ARIZONA_MIXER_ROUTES("OUT2R", "HPOUT2R"), | ||
688 | ARIZONA_MIXER_ROUTES("OUT3L", "EPOUT"), | ||
689 | |||
690 | ARIZONA_MIXER_ROUTES("OUT4L", "SPKOUTL"), | ||
691 | ARIZONA_MIXER_ROUTES("OUT4R", "SPKOUTR"), | ||
692 | ARIZONA_MIXER_ROUTES("OUT5L", "SPKDAT1L"), | ||
693 | ARIZONA_MIXER_ROUTES("OUT5R", "SPKDAT1R"), | ||
694 | ARIZONA_MIXER_ROUTES("OUT6L", "SPKDAT2L"), | ||
695 | ARIZONA_MIXER_ROUTES("OUT6R", "SPKDAT2R"), | ||
696 | |||
697 | ARIZONA_MIXER_ROUTES("PWM1 Driver", "PWM1"), | ||
698 | ARIZONA_MIXER_ROUTES("PWM2 Driver", "PWM2"), | ||
699 | |||
700 | ARIZONA_MIXER_ROUTES("AIF1TX1", "AIF1TX1"), | ||
701 | ARIZONA_MIXER_ROUTES("AIF1TX2", "AIF1TX2"), | ||
702 | ARIZONA_MIXER_ROUTES("AIF1TX3", "AIF1TX3"), | ||
703 | ARIZONA_MIXER_ROUTES("AIF1TX4", "AIF1TX4"), | ||
704 | ARIZONA_MIXER_ROUTES("AIF1TX5", "AIF1TX5"), | ||
705 | ARIZONA_MIXER_ROUTES("AIF1TX6", "AIF1TX6"), | ||
706 | ARIZONA_MIXER_ROUTES("AIF1TX7", "AIF1TX7"), | ||
707 | ARIZONA_MIXER_ROUTES("AIF1TX8", "AIF1TX8"), | ||
708 | |||
709 | ARIZONA_MIXER_ROUTES("AIF2TX1", "AIF2TX1"), | ||
710 | ARIZONA_MIXER_ROUTES("AIF2TX2", "AIF2TX2"), | ||
711 | |||
712 | ARIZONA_MIXER_ROUTES("AIF3TX1", "AIF3TX1"), | ||
713 | ARIZONA_MIXER_ROUTES("AIF3TX2", "AIF3TX2"), | ||
714 | |||
715 | ARIZONA_MIXER_ROUTES("EQ1", "EQ1"), | ||
716 | ARIZONA_MIXER_ROUTES("EQ2", "EQ2"), | ||
717 | ARIZONA_MIXER_ROUTES("EQ3", "EQ3"), | ||
718 | ARIZONA_MIXER_ROUTES("EQ4", "EQ4"), | ||
719 | |||
720 | ARIZONA_MIXER_ROUTES("DRC1L", "DRC1L"), | ||
721 | ARIZONA_MIXER_ROUTES("DRC1R", "DRC1R"), | ||
722 | ARIZONA_MIXER_ROUTES("DRC2L", "DRC2L"), | ||
723 | ARIZONA_MIXER_ROUTES("DRC2R", "DRC2R"), | ||
724 | |||
725 | ARIZONA_MIXER_ROUTES("LHPF1", "LHPF1"), | ||
726 | ARIZONA_MIXER_ROUTES("LHPF2", "LHPF2"), | ||
727 | ARIZONA_MIXER_ROUTES("LHPF3", "LHPF3"), | ||
728 | ARIZONA_MIXER_ROUTES("LHPF4", "LHPF4"), | ||
729 | |||
730 | ARIZONA_MIXER_ROUTES("ASRC1L", "ASRC1L"), | ||
731 | ARIZONA_MIXER_ROUTES("ASRC1R", "ASRC1R"), | ||
732 | ARIZONA_MIXER_ROUTES("ASRC2L", "ASRC2L"), | ||
733 | ARIZONA_MIXER_ROUTES("ASRC2R", "ASRC2R"), | ||
734 | |||
735 | { "HPOUT1L", NULL, "OUT1L" }, | ||
736 | { "HPOUT1R", NULL, "OUT1R" }, | ||
737 | |||
738 | { "HPOUT2L", NULL, "OUT2L" }, | ||
739 | { "HPOUT2R", NULL, "OUT2R" }, | ||
740 | |||
741 | { "EPOUTN", NULL, "OUT3L" }, | ||
742 | { "EPOUTP", NULL, "OUT3L" }, | ||
743 | |||
744 | { "SPKOUTLN", NULL, "OUT4L" }, | ||
745 | { "SPKOUTLP", NULL, "OUT4L" }, | ||
746 | |||
747 | { "SPKOUTRN", NULL, "OUT4R" }, | ||
748 | { "SPKOUTRP", NULL, "OUT4R" }, | ||
749 | |||
750 | { "SPKDAT1L", NULL, "OUT5L" }, | ||
751 | { "SPKDAT1R", NULL, "OUT5R" }, | ||
752 | |||
753 | { "SPKDAT2L", NULL, "OUT6L" }, | ||
754 | { "SPKDAT2R", NULL, "OUT6R" }, | ||
755 | }; | ||
756 | |||
757 | static int wm5110_set_fll(struct snd_soc_codec *codec, int fll_id, int source, | ||
758 | unsigned int Fref, unsigned int Fout) | ||
759 | { | ||
760 | struct wm5110_priv *wm5110 = snd_soc_codec_get_drvdata(codec); | ||
761 | |||
762 | switch (fll_id) { | ||
763 | case WM5110_FLL1: | ||
764 | return arizona_set_fll(&wm5110->fll[0], source, Fref, Fout); | ||
765 | case WM5110_FLL2: | ||
766 | return arizona_set_fll(&wm5110->fll[1], source, Fref, Fout); | ||
767 | default: | ||
768 | return -EINVAL; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | #define WM5110_RATES SNDRV_PCM_RATE_8000_192000 | ||
773 | |||
774 | #define WM5110_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | ||
775 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) | ||
776 | |||
777 | static struct snd_soc_dai_driver wm5110_dai[] = { | ||
778 | { | ||
779 | .name = "wm5110-aif1", | ||
780 | .id = 1, | ||
781 | .base = ARIZONA_AIF1_BCLK_CTRL, | ||
782 | .playback = { | ||
783 | .stream_name = "AIF1 Playback", | ||
784 | .channels_min = 1, | ||
785 | .channels_max = 8, | ||
786 | .rates = WM5110_RATES, | ||
787 | .formats = WM5110_FORMATS, | ||
788 | }, | ||
789 | .capture = { | ||
790 | .stream_name = "AIF1 Capture", | ||
791 | .channels_min = 1, | ||
792 | .channels_max = 8, | ||
793 | .rates = WM5110_RATES, | ||
794 | .formats = WM5110_FORMATS, | ||
795 | }, | ||
796 | .ops = &arizona_dai_ops, | ||
797 | .symmetric_rates = 1, | ||
798 | }, | ||
799 | { | ||
800 | .name = "wm5110-aif2", | ||
801 | .id = 2, | ||
802 | .base = ARIZONA_AIF2_BCLK_CTRL, | ||
803 | .playback = { | ||
804 | .stream_name = "AIF2 Playback", | ||
805 | .channels_min = 1, | ||
806 | .channels_max = 2, | ||
807 | .rates = WM5110_RATES, | ||
808 | .formats = WM5110_FORMATS, | ||
809 | }, | ||
810 | .capture = { | ||
811 | .stream_name = "AIF2 Capture", | ||
812 | .channels_min = 1, | ||
813 | .channels_max = 2, | ||
814 | .rates = WM5110_RATES, | ||
815 | .formats = WM5110_FORMATS, | ||
816 | }, | ||
817 | .ops = &arizona_dai_ops, | ||
818 | .symmetric_rates = 1, | ||
819 | }, | ||
820 | { | ||
821 | .name = "wm5110-aif3", | ||
822 | .id = 3, | ||
823 | .base = ARIZONA_AIF3_BCLK_CTRL, | ||
824 | .playback = { | ||
825 | .stream_name = "AIF3 Playback", | ||
826 | .channels_min = 1, | ||
827 | .channels_max = 2, | ||
828 | .rates = WM5110_RATES, | ||
829 | .formats = WM5110_FORMATS, | ||
830 | }, | ||
831 | .capture = { | ||
832 | .stream_name = "AIF3 Capture", | ||
833 | .channels_min = 1, | ||
834 | .channels_max = 2, | ||
835 | .rates = WM5110_RATES, | ||
836 | .formats = WM5110_FORMATS, | ||
837 | }, | ||
838 | .ops = &arizona_dai_ops, | ||
839 | .symmetric_rates = 1, | ||
840 | }, | ||
841 | }; | ||
842 | |||
843 | static int wm5110_codec_probe(struct snd_soc_codec *codec) | ||
844 | { | ||
845 | struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); | ||
846 | |||
847 | codec->control_data = priv->core.arizona->regmap; | ||
848 | return snd_soc_codec_set_cache_io(codec, 32, 16, SND_SOC_REGMAP); | ||
849 | } | ||
850 | |||
851 | #define WM5110_DIG_VU 0x0200 | ||
852 | |||
853 | static unsigned int wm5110_digital_vu[] = { | ||
854 | ARIZONA_ADC_DIGITAL_VOLUME_1L, | ||
855 | ARIZONA_ADC_DIGITAL_VOLUME_1R, | ||
856 | ARIZONA_ADC_DIGITAL_VOLUME_2L, | ||
857 | ARIZONA_ADC_DIGITAL_VOLUME_2R, | ||
858 | ARIZONA_ADC_DIGITAL_VOLUME_3L, | ||
859 | ARIZONA_ADC_DIGITAL_VOLUME_3R, | ||
860 | |||
861 | ARIZONA_DAC_DIGITAL_VOLUME_1L, | ||
862 | ARIZONA_DAC_DIGITAL_VOLUME_1R, | ||
863 | ARIZONA_DAC_DIGITAL_VOLUME_2L, | ||
864 | ARIZONA_DAC_DIGITAL_VOLUME_2R, | ||
865 | ARIZONA_DAC_DIGITAL_VOLUME_3L, | ||
866 | ARIZONA_DAC_DIGITAL_VOLUME_3R, | ||
867 | ARIZONA_DAC_DIGITAL_VOLUME_4L, | ||
868 | ARIZONA_DAC_DIGITAL_VOLUME_4R, | ||
869 | ARIZONA_DAC_DIGITAL_VOLUME_5L, | ||
870 | ARIZONA_DAC_DIGITAL_VOLUME_5R, | ||
871 | }; | ||
872 | |||
873 | static struct snd_soc_codec_driver soc_codec_dev_wm5110 = { | ||
874 | .probe = wm5110_codec_probe, | ||
875 | |||
876 | .idle_bias_off = true, | ||
877 | |||
878 | .set_sysclk = arizona_set_sysclk, | ||
879 | .set_pll = wm5110_set_fll, | ||
880 | |||
881 | .controls = wm5110_snd_controls, | ||
882 | .num_controls = ARRAY_SIZE(wm5110_snd_controls), | ||
883 | .dapm_widgets = wm5110_dapm_widgets, | ||
884 | .num_dapm_widgets = ARRAY_SIZE(wm5110_dapm_widgets), | ||
885 | .dapm_routes = wm5110_dapm_routes, | ||
886 | .num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes), | ||
887 | }; | ||
888 | |||
889 | static int __devinit wm5110_probe(struct platform_device *pdev) | ||
890 | { | ||
891 | struct arizona *arizona = dev_get_drvdata(pdev->dev.parent); | ||
892 | struct wm5110_priv *wm5110; | ||
893 | int i; | ||
894 | |||
895 | wm5110 = devm_kzalloc(&pdev->dev, sizeof(struct wm5110_priv), | ||
896 | GFP_KERNEL); | ||
897 | if (wm5110 == NULL) | ||
898 | return -ENOMEM; | ||
899 | platform_set_drvdata(pdev, wm5110); | ||
900 | |||
901 | wm5110->core.arizona = arizona; | ||
902 | |||
903 | for (i = 0; i < ARRAY_SIZE(wm5110->fll); i++) | ||
904 | wm5110->fll[i].vco_mult = 3; | ||
905 | |||
906 | arizona_init_fll(arizona, 1, ARIZONA_FLL1_CONTROL_1 - 1, | ||
907 | ARIZONA_IRQ_FLL1_LOCK, ARIZONA_IRQ_FLL1_CLOCK_OK, | ||
908 | &wm5110->fll[0]); | ||
909 | arizona_init_fll(arizona, 2, ARIZONA_FLL2_CONTROL_1 - 1, | ||
910 | ARIZONA_IRQ_FLL2_LOCK, ARIZONA_IRQ_FLL2_CLOCK_OK, | ||
911 | &wm5110->fll[1]); | ||
912 | |||
913 | for (i = 0; i < ARRAY_SIZE(wm5110_dai); i++) | ||
914 | arizona_init_dai(&wm5110->core, i); | ||
915 | |||
916 | /* Latch volume update bits */ | ||
917 | for (i = 0; i < ARRAY_SIZE(wm5110_digital_vu); i++) | ||
918 | regmap_update_bits(arizona->regmap, wm5110_digital_vu[i], | ||
919 | WM5110_DIG_VU, WM5110_DIG_VU); | ||
920 | |||
921 | pm_runtime_enable(&pdev->dev); | ||
922 | pm_runtime_idle(&pdev->dev); | ||
923 | |||
924 | return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110, | ||
925 | wm5110_dai, ARRAY_SIZE(wm5110_dai)); | ||
926 | } | ||
927 | |||
928 | static int __devexit wm5110_remove(struct platform_device *pdev) | ||
929 | { | ||
930 | snd_soc_unregister_codec(&pdev->dev); | ||
931 | pm_runtime_disable(&pdev->dev); | ||
932 | |||
933 | return 0; | ||
934 | } | ||
935 | |||
936 | static struct platform_driver wm5110_codec_driver = { | ||
937 | .driver = { | ||
938 | .name = "wm5110-codec", | ||
939 | .owner = THIS_MODULE, | ||
940 | }, | ||
941 | .probe = wm5110_probe, | ||
942 | .remove = __devexit_p(wm5110_remove), | ||
943 | }; | ||
944 | |||
945 | module_platform_driver(wm5110_codec_driver); | ||
946 | |||
947 | MODULE_DESCRIPTION("ASoC WM5110 driver"); | ||
948 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | ||
949 | MODULE_LICENSE("GPL"); | ||
950 | MODULE_ALIAS("platform:wm5110-codec"); | ||
diff --git a/sound/soc/codecs/wm5110.h b/sound/soc/codecs/wm5110.h new file mode 100644 index 000000000000..75e9351ccab0 --- /dev/null +++ b/sound/soc/codecs/wm5110.h | |||
@@ -0,0 +1,21 @@ | |||
1 | /* | ||
2 | * wm5110.h -- WM5110 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2012 Wolfson Microelectronics plc | ||
5 | * | ||
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _WM5110_H | ||
14 | #define _WM5110_H | ||
15 | |||
16 | #include "arizona.h" | ||
17 | |||
18 | #define WM5110_FLL1 1 | ||
19 | #define WM5110_FLL2 2 | ||
20 | |||
21 | #endif | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 555ee146ae0d..d26c8ae4e6d9 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8350.c -- WM8350 ALSA SoC audio driver | 2 | * wm8350.c -- WM8350 ALSA SoC audio driver |
3 | * | 3 | * |
4 | * Copyright (C) 2007, 2008 Wolfson Microelectronics PLC. | 4 | * Copyright (C) 2007-12 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 6 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
7 | * | 7 | * |
@@ -71,20 +71,6 @@ struct wm8350_data { | |||
71 | int fll_freq_in; | 71 | int fll_freq_in; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | static unsigned int wm8350_codec_read(struct snd_soc_codec *codec, | ||
75 | unsigned int reg) | ||
76 | { | ||
77 | struct wm8350 *wm8350 = codec->control_data; | ||
78 | return wm8350_reg_read(wm8350, reg); | ||
79 | } | ||
80 | |||
81 | static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg, | ||
82 | unsigned int value) | ||
83 | { | ||
84 | struct wm8350 *wm8350 = codec->control_data; | ||
85 | return wm8350_reg_write(wm8350, reg, value); | ||
86 | } | ||
87 | |||
88 | /* | 74 | /* |
89 | * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. | 75 | * Ramp OUT1 PGA volume to minimise pops at stream startup and shutdown. |
90 | */ | 76 | */ |
@@ -1519,7 +1505,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec) | |||
1519 | if (ret != 0) | 1505 | if (ret != 0) |
1520 | return ret; | 1506 | return ret; |
1521 | 1507 | ||
1522 | codec->control_data = wm8350; | 1508 | codec->control_data = wm8350->regmap; |
1509 | |||
1510 | snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); | ||
1523 | 1511 | ||
1524 | /* Put the codec into reset if it wasn't already */ | 1512 | /* Put the codec into reset if it wasn't already */ |
1525 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); | 1513 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA); |
@@ -1629,8 +1617,6 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8350 = { | |||
1629 | .remove = wm8350_codec_remove, | 1617 | .remove = wm8350_codec_remove, |
1630 | .suspend = wm8350_suspend, | 1618 | .suspend = wm8350_suspend, |
1631 | .resume = wm8350_resume, | 1619 | .resume = wm8350_resume, |
1632 | .read = wm8350_codec_read, | ||
1633 | .write = wm8350_codec_write, | ||
1634 | .set_bias_level = wm8350_set_bias_level, | 1620 | .set_bias_level = wm8350_set_bias_level, |
1635 | 1621 | ||
1636 | .controls = wm8350_snd_controls, | 1622 | .controls = wm8350_snd_controls, |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 5dc31ebcd0e7..5d277a915f81 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8400.c -- WM8400 ALSA Soc Audio driver | 2 | * wm8400.c -- WM8400 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. | 4 | * Copyright 2008-11 Wolfson Microelectronics PLC. |
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 211285164d70..7c68226376e4 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8580.c -- WM8580 ALSA Soc Audio driver | 2 | * wm8580.c -- WM8580 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008, 2009 Wolfson Microelectronics PLC. | 4 | * Copyright 2008-11 Wolfson Microelectronics PLC. |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 6 | * This program is free software; you can redistribute it and/or modify it |
7 | * under the terms of the GNU General Public License as published by the | 7 | * under the terms of the GNU General Public License as published by the |
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 9d1b9b0271f1..bb1d26919b10 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c | |||
@@ -2,6 +2,7 @@ | |||
2 | * wm8731.c -- WM8731 ALSA SoC Audio driver | 2 | * wm8731.c -- WM8731 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2005 Openedhand Ltd. | 4 | * Copyright 2005 Openedhand Ltd. |
5 | * Copyright 2006-12 Wolfson Microelectronics, plc | ||
5 | * | 6 | * |
6 | * Author: Richard Purdie <richard@openedhand.com> | 7 | * Author: Richard Purdie <richard@openedhand.com> |
7 | * | 8 | * |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 6e849cb04243..35f3d23200e0 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8741.c -- WM8741 ALSA SoC Audio driver | 2 | * wm8741.c -- WM8741 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2010 Wolfson Microelectronics plc | 4 | * Copyright 2010-1 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> | 6 | * Author: Ian Lartey <ian@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index a26482cd7654..13bff87ddcf5 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8753.c -- WM8753 ALSA Soc Audio driver | 2 | * wm8753.c -- WM8753 ALSA Soc Audio driver |
3 | * | 3 | * |
4 | * Copyright 2003 Wolfson Microelectronics PLC. | 4 | * Copyright 2003-11 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index a19db5a0a17a..879c356a9045 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8776.c -- WM8776 ALSA SoC Audio driver | 2 | * wm8776.c -- WM8776 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2009 Wolfson Microelectronics plc | 4 | * Copyright 2009-12 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 6bd1b767b138..c088020172ab 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8804.c -- WM8804 S/PDIF transceiver driver | 2 | * wm8804.c -- WM8804 S/PDIF transceiver driver |
3 | * | 3 | * |
4 | * Copyright 2010 Wolfson Microelectronics plc | 4 | * Copyright 2010-11 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> | 6 | * Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index 86b8a2926591..73f1c8d7bafb 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * wm8903.c -- WM8903 ALSA SoC Audio driver | 2 | * wm8903.c -- WM8903 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2008 Wolfson Microelectronics | 4 | * Copyright 2008-12 Wolfson Microelectronics |
5 | * Copyright 2011 NVIDIA, Inc. | 5 | * Copyright 2011-2012 NVIDIA, Inc. |
6 | * | 6 | * |
7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 7 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
8 | * | 8 | * |
@@ -116,6 +116,7 @@ static const struct reg_default wm8903_reg_defaults[] = { | |||
116 | 116 | ||
117 | struct wm8903_priv { | 117 | struct wm8903_priv { |
118 | struct wm8903_platform_data *pdata; | 118 | struct wm8903_platform_data *pdata; |
119 | struct device *dev; | ||
119 | struct snd_soc_codec *codec; | 120 | struct snd_soc_codec *codec; |
120 | struct regmap *regmap; | 121 | struct regmap *regmap; |
121 | 122 | ||
@@ -1635,17 +1636,27 @@ EXPORT_SYMBOL_GPL(wm8903_mic_detect); | |||
1635 | 1636 | ||
1636 | static irqreturn_t wm8903_irq(int irq, void *data) | 1637 | static irqreturn_t wm8903_irq(int irq, void *data) |
1637 | { | 1638 | { |
1638 | struct snd_soc_codec *codec = data; | 1639 | struct wm8903_priv *wm8903 = data; |
1639 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 1640 | int mic_report, ret; |
1640 | int mic_report; | 1641 | unsigned int int_val, mask, int_pol; |
1641 | int int_pol; | ||
1642 | int int_val = 0; | ||
1643 | int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK); | ||
1644 | 1642 | ||
1645 | int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask; | 1643 | ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1_MASK, |
1644 | &mask); | ||
1645 | if (ret != 0) { | ||
1646 | dev_err(wm8903->dev, "Failed to read IRQ mask: %d\n", ret); | ||
1647 | return IRQ_NONE; | ||
1648 | } | ||
1649 | |||
1650 | ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_STATUS_1, &int_val); | ||
1651 | if (ret != 0) { | ||
1652 | dev_err(wm8903->dev, "Failed to read IRQ status: %d\n", ret); | ||
1653 | return IRQ_NONE; | ||
1654 | } | ||
1655 | |||
1656 | int_val &= ~mask; | ||
1646 | 1657 | ||
1647 | if (int_val & WM8903_WSEQ_BUSY_EINT) { | 1658 | if (int_val & WM8903_WSEQ_BUSY_EINT) { |
1648 | dev_warn(codec->dev, "Write sequencer done\n"); | 1659 | dev_warn(wm8903->dev, "Write sequencer done\n"); |
1649 | } | 1660 | } |
1650 | 1661 | ||
1651 | /* | 1662 | /* |
@@ -1656,22 +1667,28 @@ static irqreturn_t wm8903_irq(int irq, void *data) | |||
1656 | * the polarity register. | 1667 | * the polarity register. |
1657 | */ | 1668 | */ |
1658 | mic_report = wm8903->mic_last_report; | 1669 | mic_report = wm8903->mic_last_report; |
1659 | int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1); | 1670 | ret = regmap_read(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1, |
1671 | &int_pol); | ||
1672 | if (ret != 0) { | ||
1673 | dev_err(wm8903->dev, "Failed to read interrupt polarity: %d\n", | ||
1674 | ret); | ||
1675 | return IRQ_HANDLED; | ||
1676 | } | ||
1660 | 1677 | ||
1661 | #ifndef CONFIG_SND_SOC_WM8903_MODULE | 1678 | #ifndef CONFIG_SND_SOC_WM8903_MODULE |
1662 | if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT)) | 1679 | if (int_val & (WM8903_MICSHRT_EINT | WM8903_MICDET_EINT)) |
1663 | trace_snd_soc_jack_irq(dev_name(codec->dev)); | 1680 | trace_snd_soc_jack_irq(dev_name(wm8903->dev)); |
1664 | #endif | 1681 | #endif |
1665 | 1682 | ||
1666 | if (int_val & WM8903_MICSHRT_EINT) { | 1683 | if (int_val & WM8903_MICSHRT_EINT) { |
1667 | dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol); | 1684 | dev_dbg(wm8903->dev, "Microphone short (pol=%x)\n", int_pol); |
1668 | 1685 | ||
1669 | mic_report ^= wm8903->mic_short; | 1686 | mic_report ^= wm8903->mic_short; |
1670 | int_pol ^= WM8903_MICSHRT_INV; | 1687 | int_pol ^= WM8903_MICSHRT_INV; |
1671 | } | 1688 | } |
1672 | 1689 | ||
1673 | if (int_val & WM8903_MICDET_EINT) { | 1690 | if (int_val & WM8903_MICDET_EINT) { |
1674 | dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol); | 1691 | dev_dbg(wm8903->dev, "Microphone detect (pol=%x)\n", int_pol); |
1675 | 1692 | ||
1676 | mic_report ^= wm8903->mic_det; | 1693 | mic_report ^= wm8903->mic_det; |
1677 | int_pol ^= WM8903_MICDET_INV; | 1694 | int_pol ^= WM8903_MICDET_INV; |
@@ -1679,8 +1696,8 @@ static irqreturn_t wm8903_irq(int irq, void *data) | |||
1679 | msleep(wm8903->mic_delay); | 1696 | msleep(wm8903->mic_delay); |
1680 | } | 1697 | } |
1681 | 1698 | ||
1682 | snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1, | 1699 | regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_POLARITY_1, |
1683 | WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol); | 1700 | WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol); |
1684 | 1701 | ||
1685 | snd_soc_jack_report(wm8903->mic_jack, mic_report, | 1702 | snd_soc_jack_report(wm8903->mic_jack, mic_report, |
1686 | wm8903->mic_short | wm8903->mic_det); | 1703 | wm8903->mic_short | wm8903->mic_det); |
@@ -1774,7 +1791,6 @@ static int wm8903_gpio_request(struct gpio_chip *chip, unsigned offset) | |||
1774 | static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | 1791 | static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) |
1775 | { | 1792 | { |
1776 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | 1793 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); |
1777 | struct snd_soc_codec *codec = wm8903->codec; | ||
1778 | unsigned int mask, val; | 1794 | unsigned int mask, val; |
1779 | int ret; | 1795 | int ret; |
1780 | 1796 | ||
@@ -1782,8 +1798,8 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | |||
1782 | val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | | 1798 | val = (WM8903_GPn_FN_GPIO_INPUT << WM8903_GP1_FN_SHIFT) | |
1783 | WM8903_GP1_DIR; | 1799 | WM8903_GP1_DIR; |
1784 | 1800 | ||
1785 | ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | 1801 | ret = regmap_update_bits(wm8903->regmap, |
1786 | mask, val); | 1802 | WM8903_GPIO_CONTROL_1 + offset, mask, val); |
1787 | if (ret < 0) | 1803 | if (ret < 0) |
1788 | return ret; | 1804 | return ret; |
1789 | 1805 | ||
@@ -1793,10 +1809,9 @@ static int wm8903_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | |||
1793 | static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) | 1809 | static int wm8903_gpio_get(struct gpio_chip *chip, unsigned offset) |
1794 | { | 1810 | { |
1795 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | 1811 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); |
1796 | struct snd_soc_codec *codec = wm8903->codec; | 1812 | unsigned int reg; |
1797 | int reg; | ||
1798 | 1813 | ||
1799 | reg = snd_soc_read(codec, WM8903_GPIO_CONTROL_1 + offset); | 1814 | regmap_read(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, ®); |
1800 | 1815 | ||
1801 | return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; | 1816 | return (reg & WM8903_GP1_LVL_MASK) >> WM8903_GP1_LVL_SHIFT; |
1802 | } | 1817 | } |
@@ -1805,7 +1820,6 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, | |||
1805 | unsigned offset, int value) | 1820 | unsigned offset, int value) |
1806 | { | 1821 | { |
1807 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | 1822 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); |
1808 | struct snd_soc_codec *codec = wm8903->codec; | ||
1809 | unsigned int mask, val; | 1823 | unsigned int mask, val; |
1810 | int ret; | 1824 | int ret; |
1811 | 1825 | ||
@@ -1813,8 +1827,8 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, | |||
1813 | val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | | 1827 | val = (WM8903_GPn_FN_GPIO_OUTPUT << WM8903_GP1_FN_SHIFT) | |
1814 | (value << WM8903_GP2_LVL_SHIFT); | 1828 | (value << WM8903_GP2_LVL_SHIFT); |
1815 | 1829 | ||
1816 | ret = snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | 1830 | ret = regmap_update_bits(wm8903->regmap, |
1817 | mask, val); | 1831 | WM8903_GPIO_CONTROL_1 + offset, mask, val); |
1818 | if (ret < 0) | 1832 | if (ret < 0) |
1819 | return ret; | 1833 | return ret; |
1820 | 1834 | ||
@@ -1824,11 +1838,10 @@ static int wm8903_gpio_direction_out(struct gpio_chip *chip, | |||
1824 | static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | 1838 | static void wm8903_gpio_set(struct gpio_chip *chip, unsigned offset, int value) |
1825 | { | 1839 | { |
1826 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); | 1840 | struct wm8903_priv *wm8903 = gpio_to_wm8903(chip); |
1827 | struct snd_soc_codec *codec = wm8903->codec; | ||
1828 | 1841 | ||
1829 | snd_soc_update_bits(codec, WM8903_GPIO_CONTROL_1 + offset, | 1842 | regmap_update_bits(wm8903->regmap, WM8903_GPIO_CONTROL_1 + offset, |
1830 | WM8903_GP1_LVL_MASK, | 1843 | WM8903_GP1_LVL_MASK, |
1831 | !!value << WM8903_GP1_LVL_SHIFT); | 1844 | !!value << WM8903_GP1_LVL_SHIFT); |
1832 | } | 1845 | } |
1833 | 1846 | ||
1834 | static struct gpio_chip wm8903_template_chip = { | 1847 | static struct gpio_chip wm8903_template_chip = { |
@@ -1842,15 +1855,14 @@ static struct gpio_chip wm8903_template_chip = { | |||
1842 | .can_sleep = 1, | 1855 | .can_sleep = 1, |
1843 | }; | 1856 | }; |
1844 | 1857 | ||
1845 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | 1858 | static void wm8903_init_gpio(struct wm8903_priv *wm8903) |
1846 | { | 1859 | { |
1847 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1848 | struct wm8903_platform_data *pdata = wm8903->pdata; | 1860 | struct wm8903_platform_data *pdata = wm8903->pdata; |
1849 | int ret; | 1861 | int ret; |
1850 | 1862 | ||
1851 | wm8903->gpio_chip = wm8903_template_chip; | 1863 | wm8903->gpio_chip = wm8903_template_chip; |
1852 | wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; | 1864 | wm8903->gpio_chip.ngpio = WM8903_NUM_GPIO; |
1853 | wm8903->gpio_chip.dev = codec->dev; | 1865 | wm8903->gpio_chip.dev = wm8903->dev; |
1854 | 1866 | ||
1855 | if (pdata->gpio_base) | 1867 | if (pdata->gpio_base) |
1856 | wm8903->gpio_chip.base = pdata->gpio_base; | 1868 | wm8903->gpio_chip.base = pdata->gpio_base; |
@@ -1859,24 +1871,23 @@ static void wm8903_init_gpio(struct snd_soc_codec *codec) | |||
1859 | 1871 | ||
1860 | ret = gpiochip_add(&wm8903->gpio_chip); | 1872 | ret = gpiochip_add(&wm8903->gpio_chip); |
1861 | if (ret != 0) | 1873 | if (ret != 0) |
1862 | dev_err(codec->dev, "Failed to add GPIOs: %d\n", ret); | 1874 | dev_err(wm8903->dev, "Failed to add GPIOs: %d\n", ret); |
1863 | } | 1875 | } |
1864 | 1876 | ||
1865 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | 1877 | static void wm8903_free_gpio(struct wm8903_priv *wm8903) |
1866 | { | 1878 | { |
1867 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
1868 | int ret; | 1879 | int ret; |
1869 | 1880 | ||
1870 | ret = gpiochip_remove(&wm8903->gpio_chip); | 1881 | ret = gpiochip_remove(&wm8903->gpio_chip); |
1871 | if (ret != 0) | 1882 | if (ret != 0) |
1872 | dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); | 1883 | dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); |
1873 | } | 1884 | } |
1874 | #else | 1885 | #else |
1875 | static void wm8903_init_gpio(struct snd_soc_codec *codec) | 1886 | static void wm8903_init_gpio(struct wm8903_priv *wm8903) |
1876 | { | 1887 | { |
1877 | } | 1888 | } |
1878 | 1889 | ||
1879 | static void wm8903_free_gpio(struct snd_soc_codec *codec) | 1890 | static void wm8903_free_gpio(struct wm8903_priv *wm8903) |
1880 | { | 1891 | { |
1881 | } | 1892 | } |
1882 | #endif | 1893 | #endif |
@@ -1884,11 +1895,7 @@ static void wm8903_free_gpio(struct snd_soc_codec *codec) | |||
1884 | static int wm8903_probe(struct snd_soc_codec *codec) | 1895 | static int wm8903_probe(struct snd_soc_codec *codec) |
1885 | { | 1896 | { |
1886 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | 1897 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); |
1887 | struct wm8903_platform_data *pdata = wm8903->pdata; | 1898 | int ret; |
1888 | int ret, i; | ||
1889 | int trigger, irq_pol; | ||
1890 | u16 val; | ||
1891 | bool mic_gpio = false; | ||
1892 | 1899 | ||
1893 | wm8903->codec = codec; | 1900 | wm8903->codec = codec; |
1894 | codec->control_data = wm8903->regmap; | 1901 | codec->control_data = wm8903->regmap; |
@@ -1899,121 +1906,16 @@ static int wm8903_probe(struct snd_soc_codec *codec) | |||
1899 | return ret; | 1906 | return ret; |
1900 | } | 1907 | } |
1901 | 1908 | ||
1902 | /* Set up GPIOs, detect if any are MIC detect outputs */ | ||
1903 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { | ||
1904 | if ((!pdata->gpio_cfg[i]) || | ||
1905 | (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO)) | ||
1906 | continue; | ||
1907 | |||
1908 | snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i, | ||
1909 | pdata->gpio_cfg[i] & 0x7fff); | ||
1910 | |||
1911 | val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK) | ||
1912 | >> WM8903_GP1_FN_SHIFT; | ||
1913 | |||
1914 | switch (val) { | ||
1915 | case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT: | ||
1916 | case WM8903_GPn_FN_MICBIAS_SHORT_DETECT: | ||
1917 | mic_gpio = true; | ||
1918 | break; | ||
1919 | default: | ||
1920 | break; | ||
1921 | } | ||
1922 | } | ||
1923 | |||
1924 | /* Set up microphone detection */ | ||
1925 | snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0, | ||
1926 | pdata->micdet_cfg); | ||
1927 | |||
1928 | /* Microphone detection needs the WSEQ clock */ | ||
1929 | if (pdata->micdet_cfg) | ||
1930 | snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0, | ||
1931 | WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); | ||
1932 | |||
1933 | /* If microphone detection is enabled by pdata but | ||
1934 | * detected via IRQ then interrupts can be lost before | ||
1935 | * the machine driver has set up microphone detection | ||
1936 | * IRQs as the IRQs are clear on read. The detection | ||
1937 | * will be enabled when the machine driver configures. | ||
1938 | */ | ||
1939 | WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA)); | ||
1940 | |||
1941 | wm8903->mic_delay = pdata->micdet_delay; | ||
1942 | |||
1943 | if (wm8903->irq) { | ||
1944 | if (pdata->irq_active_low) { | ||
1945 | trigger = IRQF_TRIGGER_LOW; | ||
1946 | irq_pol = WM8903_IRQ_POL; | ||
1947 | } else { | ||
1948 | trigger = IRQF_TRIGGER_HIGH; | ||
1949 | irq_pol = 0; | ||
1950 | } | ||
1951 | |||
1952 | snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL, | ||
1953 | WM8903_IRQ_POL, irq_pol); | ||
1954 | |||
1955 | ret = request_threaded_irq(wm8903->irq, NULL, wm8903_irq, | ||
1956 | trigger | IRQF_ONESHOT, | ||
1957 | "wm8903", codec); | ||
1958 | if (ret != 0) { | ||
1959 | dev_err(codec->dev, "Failed to request IRQ: %d\n", | ||
1960 | ret); | ||
1961 | return ret; | ||
1962 | } | ||
1963 | |||
1964 | /* Enable write sequencer interrupts */ | ||
1965 | snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK, | ||
1966 | WM8903_IM_WSEQ_BUSY_EINT, 0); | ||
1967 | } | ||
1968 | |||
1969 | /* power on device */ | 1909 | /* power on device */ |
1970 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1910 | wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1971 | 1911 | ||
1972 | /* Latch volume update bits */ | ||
1973 | val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); | ||
1974 | val |= WM8903_ADCVU; | ||
1975 | snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); | ||
1976 | snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); | ||
1977 | |||
1978 | val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); | ||
1979 | val |= WM8903_DACVU; | ||
1980 | snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); | ||
1981 | snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); | ||
1982 | |||
1983 | val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT); | ||
1984 | val |= WM8903_HPOUTVU; | ||
1985 | snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); | ||
1986 | snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); | ||
1987 | |||
1988 | val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT); | ||
1989 | val |= WM8903_LINEOUTVU; | ||
1990 | snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); | ||
1991 | snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); | ||
1992 | |||
1993 | val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT); | ||
1994 | val |= WM8903_SPKVU; | ||
1995 | snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); | ||
1996 | snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); | ||
1997 | |||
1998 | /* Enable DAC soft mute by default */ | ||
1999 | snd_soc_update_bits(codec, WM8903_DAC_DIGITAL_1, | ||
2000 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE, | ||
2001 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE); | ||
2002 | |||
2003 | wm8903_init_gpio(codec); | ||
2004 | |||
2005 | return ret; | 1912 | return ret; |
2006 | } | 1913 | } |
2007 | 1914 | ||
2008 | /* power down chip */ | 1915 | /* power down chip */ |
2009 | static int wm8903_remove(struct snd_soc_codec *codec) | 1916 | static int wm8903_remove(struct snd_soc_codec *codec) |
2010 | { | 1917 | { |
2011 | struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec); | ||
2012 | |||
2013 | wm8903_free_gpio(codec); | ||
2014 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1918 | wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF); |
2015 | if (wm8903->irq) | ||
2016 | free_irq(wm8903->irq, codec); | ||
2017 | 1919 | ||
2018 | return 0; | 1920 | return 0; |
2019 | } | 1921 | } |
@@ -2123,15 +2025,18 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2123 | { | 2025 | { |
2124 | struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); | 2026 | struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev); |
2125 | struct wm8903_priv *wm8903; | 2027 | struct wm8903_priv *wm8903; |
2126 | unsigned int val; | 2028 | int trigger; |
2127 | int ret; | 2029 | bool mic_gpio = false; |
2030 | unsigned int val, irq_pol; | ||
2031 | int ret, i; | ||
2128 | 2032 | ||
2129 | wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv), | 2033 | wm8903 = devm_kzalloc(&i2c->dev, sizeof(struct wm8903_priv), |
2130 | GFP_KERNEL); | 2034 | GFP_KERNEL); |
2131 | if (wm8903 == NULL) | 2035 | if (wm8903 == NULL) |
2132 | return -ENOMEM; | 2036 | return -ENOMEM; |
2037 | wm8903->dev = &i2c->dev; | ||
2133 | 2038 | ||
2134 | wm8903->regmap = regmap_init_i2c(i2c, &wm8903_regmap); | 2039 | wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap); |
2135 | if (IS_ERR(wm8903->regmap)) { | 2040 | if (IS_ERR(wm8903->regmap)) { |
2136 | ret = PTR_ERR(wm8903->regmap); | 2041 | ret = PTR_ERR(wm8903->regmap); |
2137 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 2042 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
@@ -2140,7 +2045,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2140 | } | 2045 | } |
2141 | 2046 | ||
2142 | i2c_set_clientdata(i2c, wm8903); | 2047 | i2c_set_clientdata(i2c, wm8903); |
2143 | wm8903->irq = i2c->irq; | ||
2144 | 2048 | ||
2145 | /* If no platform data was supplied, create storage for defaults */ | 2049 | /* If no platform data was supplied, create storage for defaults */ |
2146 | if (pdata) { | 2050 | if (pdata) { |
@@ -2167,6 +2071,8 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2167 | } | 2071 | } |
2168 | } | 2072 | } |
2169 | 2073 | ||
2074 | pdata = wm8903->pdata; | ||
2075 | |||
2170 | ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); | 2076 | ret = regmap_read(wm8903->regmap, WM8903_SW_RESET_AND_ID, &val); |
2171 | if (ret != 0) { | 2077 | if (ret != 0) { |
2172 | dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); | 2078 | dev_err(&i2c->dev, "Failed to read chip ID: %d\n", ret); |
@@ -2189,6 +2095,107 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2189 | /* Reset the device */ | 2095 | /* Reset the device */ |
2190 | regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903); | 2096 | regmap_write(wm8903->regmap, WM8903_SW_RESET_AND_ID, 0x8903); |
2191 | 2097 | ||
2098 | wm8903_init_gpio(wm8903); | ||
2099 | |||
2100 | /* Set up GPIO pin state, detect if any are MIC detect outputs */ | ||
2101 | for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) { | ||
2102 | if ((!pdata->gpio_cfg[i]) || | ||
2103 | (pdata->gpio_cfg[i] > WM8903_GPIO_CONFIG_ZERO)) | ||
2104 | continue; | ||
2105 | |||
2106 | regmap_write(wm8903->regmap, WM8903_GPIO_CONTROL_1 + i, | ||
2107 | pdata->gpio_cfg[i] & 0x7fff); | ||
2108 | |||
2109 | val = (pdata->gpio_cfg[i] & WM8903_GP1_FN_MASK) | ||
2110 | >> WM8903_GP1_FN_SHIFT; | ||
2111 | |||
2112 | switch (val) { | ||
2113 | case WM8903_GPn_FN_MICBIAS_CURRENT_DETECT: | ||
2114 | case WM8903_GPn_FN_MICBIAS_SHORT_DETECT: | ||
2115 | mic_gpio = true; | ||
2116 | break; | ||
2117 | default: | ||
2118 | break; | ||
2119 | } | ||
2120 | } | ||
2121 | |||
2122 | /* Set up microphone detection */ | ||
2123 | regmap_write(wm8903->regmap, WM8903_MIC_BIAS_CONTROL_0, | ||
2124 | pdata->micdet_cfg); | ||
2125 | |||
2126 | /* Microphone detection needs the WSEQ clock */ | ||
2127 | if (pdata->micdet_cfg) | ||
2128 | regmap_update_bits(wm8903->regmap, WM8903_WRITE_SEQUENCER_0, | ||
2129 | WM8903_WSEQ_ENA, WM8903_WSEQ_ENA); | ||
2130 | |||
2131 | /* If microphone detection is enabled by pdata but | ||
2132 | * detected via IRQ then interrupts can be lost before | ||
2133 | * the machine driver has set up microphone detection | ||
2134 | * IRQs as the IRQs are clear on read. The detection | ||
2135 | * will be enabled when the machine driver configures. | ||
2136 | */ | ||
2137 | WARN_ON(!mic_gpio && (pdata->micdet_cfg & WM8903_MICDET_ENA)); | ||
2138 | |||
2139 | wm8903->mic_delay = pdata->micdet_delay; | ||
2140 | |||
2141 | if (i2c->irq) { | ||
2142 | if (pdata->irq_active_low) { | ||
2143 | trigger = IRQF_TRIGGER_LOW; | ||
2144 | irq_pol = WM8903_IRQ_POL; | ||
2145 | } else { | ||
2146 | trigger = IRQF_TRIGGER_HIGH; | ||
2147 | irq_pol = 0; | ||
2148 | } | ||
2149 | |||
2150 | regmap_update_bits(wm8903->regmap, WM8903_INTERRUPT_CONTROL, | ||
2151 | WM8903_IRQ_POL, irq_pol); | ||
2152 | |||
2153 | ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq, | ||
2154 | trigger | IRQF_ONESHOT, | ||
2155 | "wm8903", wm8903); | ||
2156 | if (ret != 0) { | ||
2157 | dev_err(wm8903->dev, "Failed to request IRQ: %d\n", | ||
2158 | ret); | ||
2159 | return ret; | ||
2160 | } | ||
2161 | |||
2162 | /* Enable write sequencer interrupts */ | ||
2163 | regmap_update_bits(wm8903->regmap, | ||
2164 | WM8903_INTERRUPT_STATUS_1_MASK, | ||
2165 | WM8903_IM_WSEQ_BUSY_EINT, 0); | ||
2166 | } | ||
2167 | |||
2168 | /* Latch volume update bits */ | ||
2169 | regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_LEFT, | ||
2170 | WM8903_ADCVU, WM8903_ADCVU); | ||
2171 | regmap_update_bits(wm8903->regmap, WM8903_ADC_DIGITAL_VOLUME_RIGHT, | ||
2172 | WM8903_ADCVU, WM8903_ADCVU); | ||
2173 | |||
2174 | regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_LEFT, | ||
2175 | WM8903_DACVU, WM8903_DACVU); | ||
2176 | regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_VOLUME_RIGHT, | ||
2177 | WM8903_DACVU, WM8903_DACVU); | ||
2178 | |||
2179 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_LEFT, | ||
2180 | WM8903_HPOUTVU, WM8903_HPOUTVU); | ||
2181 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT1_RIGHT, | ||
2182 | WM8903_HPOUTVU, WM8903_HPOUTVU); | ||
2183 | |||
2184 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_LEFT, | ||
2185 | WM8903_LINEOUTVU, WM8903_LINEOUTVU); | ||
2186 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT2_RIGHT, | ||
2187 | WM8903_LINEOUTVU, WM8903_LINEOUTVU); | ||
2188 | |||
2189 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_LEFT, | ||
2190 | WM8903_SPKVU, WM8903_SPKVU); | ||
2191 | regmap_update_bits(wm8903->regmap, WM8903_ANALOGUE_OUT3_RIGHT, | ||
2192 | WM8903_SPKVU, WM8903_SPKVU); | ||
2193 | |||
2194 | /* Enable DAC soft mute by default */ | ||
2195 | regmap_update_bits(wm8903->regmap, WM8903_DAC_DIGITAL_1, | ||
2196 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE, | ||
2197 | WM8903_DAC_MUTEMODE | WM8903_DAC_MUTE); | ||
2198 | |||
2192 | ret = snd_soc_register_codec(&i2c->dev, | 2199 | ret = snd_soc_register_codec(&i2c->dev, |
2193 | &soc_codec_dev_wm8903, &wm8903_dai, 1); | 2200 | &soc_codec_dev_wm8903, &wm8903_dai, 1); |
2194 | if (ret != 0) | 2201 | if (ret != 0) |
@@ -2196,7 +2203,6 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, | |||
2196 | 2203 | ||
2197 | return 0; | 2204 | return 0; |
2198 | err: | 2205 | err: |
2199 | regmap_exit(wm8903->regmap); | ||
2200 | return ret; | 2206 | return ret; |
2201 | } | 2207 | } |
2202 | 2208 | ||
@@ -2204,7 +2210,9 @@ static __devexit int wm8903_i2c_remove(struct i2c_client *client) | |||
2204 | { | 2210 | { |
2205 | struct wm8903_priv *wm8903 = i2c_get_clientdata(client); | 2211 | struct wm8903_priv *wm8903 = i2c_get_clientdata(client); |
2206 | 2212 | ||
2207 | regmap_exit(wm8903->regmap); | 2213 | if (client->irq) |
2214 | free_irq(client->irq, wm8903); | ||
2215 | wm8903_free_gpio(wm8903); | ||
2208 | snd_soc_unregister_codec(&client->dev); | 2216 | snd_soc_unregister_codec(&client->dev); |
2209 | 2217 | ||
2210 | return 0; | 2218 | return 0; |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 812acd83fb48..0013afe48e66 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8904.c -- WM8904 ALSA SoC Audio driver | 2 | * wm8904.c -- WM8904 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2009 Wolfson Microelectronics plc | 4 | * Copyright 2009-12 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -314,11 +314,6 @@ static bool wm8904_readable_register(struct device *dev, unsigned int reg) | |||
314 | } | 314 | } |
315 | } | 315 | } |
316 | 316 | ||
317 | static int wm8904_reset(struct snd_soc_codec *codec) | ||
318 | { | ||
319 | return snd_soc_write(codec, WM8904_SW_RESET_AND_ID, 0); | ||
320 | } | ||
321 | |||
322 | static int wm8904_configure_clocking(struct snd_soc_codec *codec) | 317 | static int wm8904_configure_clocking(struct snd_soc_codec *codec) |
323 | { | 318 | { |
324 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); | 319 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); |
@@ -1945,25 +1940,6 @@ static struct snd_soc_dai_driver wm8904_dai = { | |||
1945 | .symmetric_rates = 1, | 1940 | .symmetric_rates = 1, |
1946 | }; | 1941 | }; |
1947 | 1942 | ||
1948 | #ifdef CONFIG_PM | ||
1949 | static int wm8904_suspend(struct snd_soc_codec *codec) | ||
1950 | { | ||
1951 | wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1952 | |||
1953 | return 0; | ||
1954 | } | ||
1955 | |||
1956 | static int wm8904_resume(struct snd_soc_codec *codec) | ||
1957 | { | ||
1958 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1959 | |||
1960 | return 0; | ||
1961 | } | ||
1962 | #else | ||
1963 | #define wm8904_suspend NULL | ||
1964 | #define wm8904_resume NULL | ||
1965 | #endif | ||
1966 | |||
1967 | static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) | 1943 | static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) |
1968 | { | 1944 | { |
1969 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); | 1945 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); |
@@ -2078,8 +2054,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) | |||
2078 | static int wm8904_probe(struct snd_soc_codec *codec) | 2054 | static int wm8904_probe(struct snd_soc_codec *codec) |
2079 | { | 2055 | { |
2080 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); | 2056 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); |
2081 | struct wm8904_pdata *pdata = wm8904->pdata; | 2057 | int ret; |
2082 | int ret, i; | ||
2083 | 2058 | ||
2084 | codec->control_data = wm8904->regmap; | 2059 | codec->control_data = wm8904->regmap; |
2085 | 2060 | ||
@@ -2101,127 +2076,17 @@ static int wm8904_probe(struct snd_soc_codec *codec) | |||
2101 | return ret; | 2076 | return ret; |
2102 | } | 2077 | } |
2103 | 2078 | ||
2104 | for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) | ||
2105 | wm8904->supplies[i].supply = wm8904_supply_names[i]; | ||
2106 | |||
2107 | ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8904->supplies), | ||
2108 | wm8904->supplies); | ||
2109 | if (ret != 0) { | ||
2110 | dev_err(codec->dev, "Failed to request supplies: %d\n", ret); | ||
2111 | return ret; | ||
2112 | } | ||
2113 | |||
2114 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), | ||
2115 | wm8904->supplies); | ||
2116 | if (ret != 0) { | ||
2117 | dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); | ||
2118 | goto err_get; | ||
2119 | } | ||
2120 | |||
2121 | ret = snd_soc_read(codec, WM8904_SW_RESET_AND_ID); | ||
2122 | if (ret < 0) { | ||
2123 | dev_err(codec->dev, "Failed to read ID register\n"); | ||
2124 | goto err_enable; | ||
2125 | } | ||
2126 | if (ret != 0x8904) { | ||
2127 | dev_err(codec->dev, "Device is not a WM8904, ID is %x\n", ret); | ||
2128 | ret = -EINVAL; | ||
2129 | goto err_enable; | ||
2130 | } | ||
2131 | |||
2132 | ret = snd_soc_read(codec, WM8904_REVISION); | ||
2133 | if (ret < 0) { | ||
2134 | dev_err(codec->dev, "Failed to read device revision: %d\n", | ||
2135 | ret); | ||
2136 | goto err_enable; | ||
2137 | } | ||
2138 | dev_info(codec->dev, "revision %c\n", ret + 'A'); | ||
2139 | |||
2140 | ret = wm8904_reset(codec); | ||
2141 | if (ret < 0) { | ||
2142 | dev_err(codec->dev, "Failed to issue reset\n"); | ||
2143 | goto err_enable; | ||
2144 | } | ||
2145 | |||
2146 | regcache_cache_only(wm8904->regmap, true); | ||
2147 | /* Change some default settings - latch VU and enable ZC */ | ||
2148 | snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_LEFT, | ||
2149 | WM8904_ADC_VU, WM8904_ADC_VU); | ||
2150 | snd_soc_update_bits(codec, WM8904_ADC_DIGITAL_VOLUME_RIGHT, | ||
2151 | WM8904_ADC_VU, WM8904_ADC_VU); | ||
2152 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_LEFT, | ||
2153 | WM8904_DAC_VU, WM8904_DAC_VU); | ||
2154 | snd_soc_update_bits(codec, WM8904_DAC_DIGITAL_VOLUME_RIGHT, | ||
2155 | WM8904_DAC_VU, WM8904_DAC_VU); | ||
2156 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_LEFT, | ||
2157 | WM8904_HPOUT_VU | WM8904_HPOUTLZC, | ||
2158 | WM8904_HPOUT_VU | WM8904_HPOUTLZC); | ||
2159 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT1_RIGHT, | ||
2160 | WM8904_HPOUT_VU | WM8904_HPOUTRZC, | ||
2161 | WM8904_HPOUT_VU | WM8904_HPOUTRZC); | ||
2162 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_LEFT, | ||
2163 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC, | ||
2164 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC); | ||
2165 | snd_soc_update_bits(codec, WM8904_ANALOGUE_OUT2_RIGHT, | ||
2166 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC, | ||
2167 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC); | ||
2168 | snd_soc_update_bits(codec, WM8904_CLOCK_RATES_0, | ||
2169 | WM8904_SR_MODE, 0); | ||
2170 | |||
2171 | /* Apply configuration from the platform data. */ | ||
2172 | if (wm8904->pdata) { | ||
2173 | for (i = 0; i < WM8904_GPIO_REGS; i++) { | ||
2174 | if (!pdata->gpio_cfg[i]) | ||
2175 | continue; | ||
2176 | |||
2177 | regmap_update_bits(wm8904->regmap, | ||
2178 | WM8904_GPIO_CONTROL_1 + i, | ||
2179 | 0xffff, | ||
2180 | pdata->gpio_cfg[i]); | ||
2181 | } | ||
2182 | |||
2183 | /* Zero is the default value for these anyway */ | ||
2184 | for (i = 0; i < WM8904_MIC_REGS; i++) | ||
2185 | regmap_update_bits(wm8904->regmap, | ||
2186 | WM8904_MIC_BIAS_CONTROL_0 + i, | ||
2187 | 0xffff, | ||
2188 | pdata->mic_cfg[i]); | ||
2189 | } | ||
2190 | |||
2191 | /* Set Class W by default - this will be managed by the Class | ||
2192 | * G widget at runtime where bypass paths are available. | ||
2193 | */ | ||
2194 | snd_soc_update_bits(codec, WM8904_CLASS_W_0, | ||
2195 | WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR); | ||
2196 | |||
2197 | /* Use normal bias source */ | ||
2198 | snd_soc_update_bits(codec, WM8904_BIAS_CONTROL_0, | ||
2199 | WM8904_POBCTRL, 0); | ||
2200 | |||
2201 | wm8904_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2202 | |||
2203 | /* Bias level configuration will have done an extra enable */ | ||
2204 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2205 | |||
2206 | wm8904_handle_pdata(codec); | 2079 | wm8904_handle_pdata(codec); |
2207 | 2080 | ||
2208 | wm8904_add_widgets(codec); | 2081 | wm8904_add_widgets(codec); |
2209 | 2082 | ||
2210 | return 0; | 2083 | return 0; |
2211 | |||
2212 | err_enable: | ||
2213 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2214 | err_get: | ||
2215 | regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2216 | return ret; | ||
2217 | } | 2084 | } |
2218 | 2085 | ||
2219 | static int wm8904_remove(struct snd_soc_codec *codec) | 2086 | static int wm8904_remove(struct snd_soc_codec *codec) |
2220 | { | 2087 | { |
2221 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); | 2088 | struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec); |
2222 | 2089 | ||
2223 | wm8904_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2224 | regulator_bulk_free(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2225 | kfree(wm8904->retune_mobile_texts); | 2090 | kfree(wm8904->retune_mobile_texts); |
2226 | kfree(wm8904->drc_texts); | 2091 | kfree(wm8904->drc_texts); |
2227 | 2092 | ||
@@ -2231,8 +2096,6 @@ static int wm8904_remove(struct snd_soc_codec *codec) | |||
2231 | static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { | 2096 | static struct snd_soc_codec_driver soc_codec_dev_wm8904 = { |
2232 | .probe = wm8904_probe, | 2097 | .probe = wm8904_probe, |
2233 | .remove = wm8904_remove, | 2098 | .remove = wm8904_remove, |
2234 | .suspend = wm8904_suspend, | ||
2235 | .resume = wm8904_resume, | ||
2236 | .set_bias_level = wm8904_set_bias_level, | 2099 | .set_bias_level = wm8904_set_bias_level, |
2237 | .idle_bias_off = true, | 2100 | .idle_bias_off = true, |
2238 | }; | 2101 | }; |
@@ -2254,14 +2117,15 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, | |||
2254 | const struct i2c_device_id *id) | 2117 | const struct i2c_device_id *id) |
2255 | { | 2118 | { |
2256 | struct wm8904_priv *wm8904; | 2119 | struct wm8904_priv *wm8904; |
2257 | int ret; | 2120 | unsigned int val; |
2121 | int ret, i; | ||
2258 | 2122 | ||
2259 | wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), | 2123 | wm8904 = devm_kzalloc(&i2c->dev, sizeof(struct wm8904_priv), |
2260 | GFP_KERNEL); | 2124 | GFP_KERNEL); |
2261 | if (wm8904 == NULL) | 2125 | if (wm8904 == NULL) |
2262 | return -ENOMEM; | 2126 | return -ENOMEM; |
2263 | 2127 | ||
2264 | wm8904->regmap = regmap_init_i2c(i2c, &wm8904_regmap); | 2128 | wm8904->regmap = devm_regmap_init_i2c(i2c, &wm8904_regmap); |
2265 | if (IS_ERR(wm8904->regmap)) { | 2129 | if (IS_ERR(wm8904->regmap)) { |
2266 | ret = PTR_ERR(wm8904->regmap); | 2130 | ret = PTR_ERR(wm8904->regmap); |
2267 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", | 2131 | dev_err(&i2c->dev, "Failed to allocate register map: %d\n", |
@@ -2273,23 +2137,121 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c, | |||
2273 | i2c_set_clientdata(i2c, wm8904); | 2137 | i2c_set_clientdata(i2c, wm8904); |
2274 | wm8904->pdata = i2c->dev.platform_data; | 2138 | wm8904->pdata = i2c->dev.platform_data; |
2275 | 2139 | ||
2140 | for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) | ||
2141 | wm8904->supplies[i].supply = wm8904_supply_names[i]; | ||
2142 | |||
2143 | ret = devm_regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8904->supplies), | ||
2144 | wm8904->supplies); | ||
2145 | if (ret != 0) { | ||
2146 | dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); | ||
2147 | return ret; | ||
2148 | } | ||
2149 | |||
2150 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8904->supplies), | ||
2151 | wm8904->supplies); | ||
2152 | if (ret != 0) { | ||
2153 | dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); | ||
2154 | return ret; | ||
2155 | } | ||
2156 | |||
2157 | ret = regmap_read(wm8904->regmap, WM8904_SW_RESET_AND_ID, &val); | ||
2158 | if (ret < 0) { | ||
2159 | dev_err(&i2c->dev, "Failed to read ID register: %d\n", ret); | ||
2160 | goto err_enable; | ||
2161 | } | ||
2162 | if (val != 0x8904) { | ||
2163 | dev_err(&i2c->dev, "Device is not a WM8904, ID is %x\n", val); | ||
2164 | ret = -EINVAL; | ||
2165 | goto err_enable; | ||
2166 | } | ||
2167 | |||
2168 | ret = regmap_read(wm8904->regmap, WM8904_REVISION, &val); | ||
2169 | if (ret < 0) { | ||
2170 | dev_err(&i2c->dev, "Failed to read device revision: %d\n", | ||
2171 | ret); | ||
2172 | goto err_enable; | ||
2173 | } | ||
2174 | dev_info(&i2c->dev, "revision %c\n", val + 'A'); | ||
2175 | |||
2176 | ret = regmap_write(wm8904->regmap, WM8904_SW_RESET_AND_ID, 0); | ||
2177 | if (ret < 0) { | ||
2178 | dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); | ||
2179 | goto err_enable; | ||
2180 | } | ||
2181 | |||
2182 | /* Change some default settings - latch VU and enable ZC */ | ||
2183 | regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_LEFT, | ||
2184 | WM8904_ADC_VU, WM8904_ADC_VU); | ||
2185 | regmap_update_bits(wm8904->regmap, WM8904_ADC_DIGITAL_VOLUME_RIGHT, | ||
2186 | WM8904_ADC_VU, WM8904_ADC_VU); | ||
2187 | regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_LEFT, | ||
2188 | WM8904_DAC_VU, WM8904_DAC_VU); | ||
2189 | regmap_update_bits(wm8904->regmap, WM8904_DAC_DIGITAL_VOLUME_RIGHT, | ||
2190 | WM8904_DAC_VU, WM8904_DAC_VU); | ||
2191 | regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_LEFT, | ||
2192 | WM8904_HPOUT_VU | WM8904_HPOUTLZC, | ||
2193 | WM8904_HPOUT_VU | WM8904_HPOUTLZC); | ||
2194 | regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT1_RIGHT, | ||
2195 | WM8904_HPOUT_VU | WM8904_HPOUTRZC, | ||
2196 | WM8904_HPOUT_VU | WM8904_HPOUTRZC); | ||
2197 | regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_LEFT, | ||
2198 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC, | ||
2199 | WM8904_LINEOUT_VU | WM8904_LINEOUTLZC); | ||
2200 | regmap_update_bits(wm8904->regmap, WM8904_ANALOGUE_OUT2_RIGHT, | ||
2201 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC, | ||
2202 | WM8904_LINEOUT_VU | WM8904_LINEOUTRZC); | ||
2203 | regmap_update_bits(wm8904->regmap, WM8904_CLOCK_RATES_0, | ||
2204 | WM8904_SR_MODE, 0); | ||
2205 | |||
2206 | /* Apply configuration from the platform data. */ | ||
2207 | if (wm8904->pdata) { | ||
2208 | for (i = 0; i < WM8904_GPIO_REGS; i++) { | ||
2209 | if (!wm8904->pdata->gpio_cfg[i]) | ||
2210 | continue; | ||
2211 | |||
2212 | regmap_update_bits(wm8904->regmap, | ||
2213 | WM8904_GPIO_CONTROL_1 + i, | ||
2214 | 0xffff, | ||
2215 | wm8904->pdata->gpio_cfg[i]); | ||
2216 | } | ||
2217 | |||
2218 | /* Zero is the default value for these anyway */ | ||
2219 | for (i = 0; i < WM8904_MIC_REGS; i++) | ||
2220 | regmap_update_bits(wm8904->regmap, | ||
2221 | WM8904_MIC_BIAS_CONTROL_0 + i, | ||
2222 | 0xffff, | ||
2223 | wm8904->pdata->mic_cfg[i]); | ||
2224 | } | ||
2225 | |||
2226 | /* Set Class W by default - this will be managed by the Class | ||
2227 | * G widget at runtime where bypass paths are available. | ||
2228 | */ | ||
2229 | regmap_update_bits(wm8904->regmap, WM8904_CLASS_W_0, | ||
2230 | WM8904_CP_DYN_PWR, WM8904_CP_DYN_PWR); | ||
2231 | |||
2232 | /* Use normal bias source */ | ||
2233 | regmap_update_bits(wm8904->regmap, WM8904_BIAS_CONTROL_0, | ||
2234 | WM8904_POBCTRL, 0); | ||
2235 | |||
2236 | /* Can leave the device powered off until we need it */ | ||
2237 | regcache_cache_only(wm8904->regmap, true); | ||
2238 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); | ||
2239 | |||
2276 | ret = snd_soc_register_codec(&i2c->dev, | 2240 | ret = snd_soc_register_codec(&i2c->dev, |
2277 | &soc_codec_dev_wm8904, &wm8904_dai, 1); | 2241 | &soc_codec_dev_wm8904, &wm8904_dai, 1); |
2278 | if (ret != 0) | 2242 | if (ret != 0) |
2279 | goto err; | 2243 | return ret; |
2280 | 2244 | ||
2281 | return 0; | 2245 | return 0; |
2282 | 2246 | ||
2283 | err: | 2247 | err_enable: |
2284 | regmap_exit(wm8904->regmap); | 2248 | regulator_bulk_disable(ARRAY_SIZE(wm8904->supplies), wm8904->supplies); |
2285 | return ret; | 2249 | return ret; |
2286 | } | 2250 | } |
2287 | 2251 | ||
2288 | static __devexit int wm8904_i2c_remove(struct i2c_client *client) | 2252 | static __devexit int wm8904_i2c_remove(struct i2c_client *client) |
2289 | { | 2253 | { |
2290 | struct wm8904_priv *wm8904 = i2c_get_clientdata(client); | ||
2291 | snd_soc_unregister_codec(&client->dev); | 2254 | snd_soc_unregister_codec(&client->dev); |
2292 | regmap_exit(wm8904->regmap); | ||
2293 | return 0; | 2255 | return 0; |
2294 | } | 2256 | } |
2295 | 2257 | ||
@@ -2311,23 +2273,7 @@ static struct i2c_driver wm8904_i2c_driver = { | |||
2311 | .id_table = wm8904_i2c_id, | 2273 | .id_table = wm8904_i2c_id, |
2312 | }; | 2274 | }; |
2313 | 2275 | ||
2314 | static int __init wm8904_modinit(void) | 2276 | module_i2c_driver(wm8904_i2c_driver); |
2315 | { | ||
2316 | int ret = 0; | ||
2317 | ret = i2c_add_driver(&wm8904_i2c_driver); | ||
2318 | if (ret != 0) { | ||
2319 | printk(KERN_ERR "Failed to register wm8904 I2C driver: %d\n", | ||
2320 | ret); | ||
2321 | } | ||
2322 | return ret; | ||
2323 | } | ||
2324 | module_init(wm8904_modinit); | ||
2325 | |||
2326 | static void __exit wm8904_exit(void) | ||
2327 | { | ||
2328 | i2c_del_driver(&wm8904_i2c_driver); | ||
2329 | } | ||
2330 | module_exit(wm8904_exit); | ||
2331 | 2277 | ||
2332 | MODULE_DESCRIPTION("ASoC WM8904 driver"); | 2278 | MODULE_DESCRIPTION("ASoC WM8904 driver"); |
2333 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); | 2279 | MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 8bc659d8dd2e..96518ac8e24c 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -1,6 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * wm8960.c -- WM8960 ALSA SoC Audio driver | 2 | * wm8960.c -- WM8960 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2007-11 Wolfson Microelectronics, plc | ||
5 | * | ||
4 | * Author: Liam Girdwood | 6 | * Author: Liam Girdwood |
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index 05ea7c274093..01edbcc754d2 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c | |||
@@ -1,6 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * wm8961.c -- WM8961 ALSA SoC Audio driver | 2 | * wm8961.c -- WM8961 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2009-10 Wolfson Microelectronics, plc | ||
5 | * | ||
4 | * Author: Mark Brown | 6 | * Author: Mark Brown |
5 | * | 7 | * |
6 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 0cfce9999c89..eaf65863ec21 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8962.c -- WM8962 ALSA SoC Audio driver | 2 | * wm8962.c -- WM8962 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2010 Wolfson Microelectronics plc | 4 | * Copyright 2010-2 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -2580,6 +2580,9 @@ static int wm8962_hw_params(struct snd_pcm_substream *substream, | |||
2580 | WM8962_SAMPLE_RATE_INT_MODE | | 2580 | WM8962_SAMPLE_RATE_INT_MODE | |
2581 | WM8962_SAMPLE_RATE_MASK, adctl3); | 2581 | WM8962_SAMPLE_RATE_MASK, adctl3); |
2582 | 2582 | ||
2583 | dev_dbg(codec->dev, "hw_params set BCLK %dHz LRCLK %dHz\n", | ||
2584 | wm8962->bclk, wm8962->lrclk); | ||
2585 | |||
2583 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) | 2586 | if (codec->dapm.bias_level == SND_SOC_BIAS_ON) |
2584 | wm8962_configure_bclk(codec); | 2587 | wm8962_configure_bclk(codec); |
2585 | 2588 | ||
@@ -3722,6 +3725,9 @@ static int wm8962_runtime_resume(struct device *dev) | |||
3722 | } | 3725 | } |
3723 | 3726 | ||
3724 | regcache_cache_only(wm8962->regmap, false); | 3727 | regcache_cache_only(wm8962->regmap, false); |
3728 | |||
3729 | wm8962_reset(wm8962); | ||
3730 | |||
3725 | regcache_sync(wm8962->regmap); | 3731 | regcache_sync(wm8962->regmap); |
3726 | 3732 | ||
3727 | regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, | 3733 | regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP, |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 36acfccab999..9fd80d688979 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8993.c -- WM8993 ALSA SoC audio driver | 2 | * wm8993.c -- WM8993 ALSA SoC audio driver |
3 | * | 3 | * |
4 | * Copyright 2009, 2010 Wolfson Microelectronics plc | 4 | * Copyright 2009-12 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index 1436b6ce74d1..bb62f4b3d563 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8994.c -- WM8994 ALSA SoC Audio driver | 2 | * wm8994.c -- WM8994 ALSA SoC Audio driver |
3 | * | 3 | * |
4 | * Copyright 2009 Wolfson Microelectronics plc | 4 | * Copyright 2009-12 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
@@ -2967,23 +2967,8 @@ static struct snd_soc_dai_driver wm8994_dai[] = { | |||
2967 | static int wm8994_codec_suspend(struct snd_soc_codec *codec) | 2967 | static int wm8994_codec_suspend(struct snd_soc_codec *codec) |
2968 | { | 2968 | { |
2969 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2969 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
2970 | struct wm8994 *control = wm8994->wm8994; | ||
2971 | int i, ret; | 2970 | int i, ret; |
2972 | 2971 | ||
2973 | switch (control->type) { | ||
2974 | case WM8994: | ||
2975 | snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); | ||
2976 | break; | ||
2977 | case WM1811: | ||
2978 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
2979 | WM1811_JACKDET_MODE_MASK, 0); | ||
2980 | /* Fall through */ | ||
2981 | case WM8958: | ||
2982 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
2983 | WM8958_MICD_ENA, 0); | ||
2984 | break; | ||
2985 | } | ||
2986 | |||
2987 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { | 2972 | for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) { |
2988 | memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], | 2973 | memcpy(&wm8994->fll_suspend[i], &wm8994->fll[i], |
2989 | sizeof(struct wm8994_fll_config)); | 2974 | sizeof(struct wm8994_fll_config)); |
@@ -3033,28 +3018,6 @@ static int wm8994_codec_resume(struct snd_soc_codec *codec) | |||
3033 | i + 1, ret); | 3018 | i + 1, ret); |
3034 | } | 3019 | } |
3035 | 3020 | ||
3036 | switch (control->type) { | ||
3037 | case WM8994: | ||
3038 | if (wm8994->micdet[0].jack || wm8994->micdet[1].jack) | ||
3039 | snd_soc_update_bits(codec, WM8994_MICBIAS, | ||
3040 | WM8994_MICD_ENA, WM8994_MICD_ENA); | ||
3041 | break; | ||
3042 | case WM1811: | ||
3043 | if (wm8994->jackdet && wm8994->jack_cb) { | ||
3044 | /* Restart from idle */ | ||
3045 | snd_soc_update_bits(codec, WM8994_ANTIPOP_2, | ||
3046 | WM1811_JACKDET_MODE_MASK, | ||
3047 | WM1811_JACKDET_MODE_JACK); | ||
3048 | break; | ||
3049 | } | ||
3050 | break; | ||
3051 | case WM8958: | ||
3052 | if (wm8994->jack_cb) | ||
3053 | snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, | ||
3054 | WM8958_MICD_ENA, WM8958_MICD_ENA); | ||
3055 | break; | ||
3056 | } | ||
3057 | |||
3058 | return 0; | 3021 | return 0; |
3059 | } | 3022 | } |
3060 | #else | 3023 | #else |
@@ -3729,9 +3692,6 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3729 | 3692 | ||
3730 | if (wm8994->pdata && wm8994->pdata->micdet_irq) | 3693 | if (wm8994->pdata && wm8994->pdata->micdet_irq) |
3731 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; | 3694 | wm8994->micdet_irq = wm8994->pdata->micdet_irq; |
3732 | else if (wm8994->pdata && wm8994->pdata->irq_base) | ||
3733 | wm8994->micdet_irq = wm8994->pdata->irq_base + | ||
3734 | WM8994_IRQ_MIC1_DET; | ||
3735 | 3695 | ||
3736 | pm_runtime_enable(codec->dev); | 3696 | pm_runtime_enable(codec->dev); |
3737 | pm_runtime_idle(codec->dev); | 3697 | pm_runtime_idle(codec->dev); |
@@ -3870,6 +3830,10 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec) | |||
3870 | dev_warn(codec->dev, | 3830 | dev_warn(codec->dev, |
3871 | "Failed to request Mic detect IRQ: %d\n", | 3831 | "Failed to request Mic detect IRQ: %d\n", |
3872 | ret); | 3832 | ret); |
3833 | } else { | ||
3834 | wm8994_request_irq(wm8994->wm8994, WM8994_IRQ_MIC1_DET, | ||
3835 | wm8958_mic_irq, "Mic detect", | ||
3836 | wm8994); | ||
3873 | } | 3837 | } |
3874 | } | 3838 | } |
3875 | 3839 | ||
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index dc9b42b7fc4d..00f183dfa454 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm8996.c - WM8996 audio codec interface | 2 | * wm8996.c - WM8996 audio codec interface |
3 | * | 3 | * |
4 | * Copyright 2011 Wolfson Microelectronics PLC. | 4 | * Copyright 2011-2 Wolfson Microelectronics PLC. |
5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 5 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
@@ -296,184 +296,6 @@ static struct reg_default wm8996_reg[] = { | |||
296 | { WM8996_RIGHT_PDM_SPEAKER, 0x1 }, | 296 | { WM8996_RIGHT_PDM_SPEAKER, 0x1 }, |
297 | { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 }, | 297 | { WM8996_PDM_SPEAKER_MUTE_SEQUENCE, 0x69 }, |
298 | { WM8996_PDM_SPEAKER_VOLUME, 0x66 }, | 298 | { WM8996_PDM_SPEAKER_VOLUME, 0x66 }, |
299 | { WM8996_WRITE_SEQUENCER_0, 0x1 }, | ||
300 | { WM8996_WRITE_SEQUENCER_1, 0x1 }, | ||
301 | { WM8996_WRITE_SEQUENCER_3, 0x6 }, | ||
302 | { WM8996_WRITE_SEQUENCER_4, 0x40 }, | ||
303 | { WM8996_WRITE_SEQUENCER_5, 0x1 }, | ||
304 | { WM8996_WRITE_SEQUENCER_6, 0xf }, | ||
305 | { WM8996_WRITE_SEQUENCER_7, 0x6 }, | ||
306 | { WM8996_WRITE_SEQUENCER_8, 0x1 }, | ||
307 | { WM8996_WRITE_SEQUENCER_9, 0x3 }, | ||
308 | { WM8996_WRITE_SEQUENCER_10, 0x104 }, | ||
309 | { WM8996_WRITE_SEQUENCER_12, 0x60 }, | ||
310 | { WM8996_WRITE_SEQUENCER_13, 0x11 }, | ||
311 | { WM8996_WRITE_SEQUENCER_14, 0x401 }, | ||
312 | { WM8996_WRITE_SEQUENCER_16, 0x50 }, | ||
313 | { WM8996_WRITE_SEQUENCER_17, 0x3 }, | ||
314 | { WM8996_WRITE_SEQUENCER_18, 0x100 }, | ||
315 | { WM8996_WRITE_SEQUENCER_20, 0x51 }, | ||
316 | { WM8996_WRITE_SEQUENCER_21, 0x3 }, | ||
317 | { WM8996_WRITE_SEQUENCER_22, 0x104 }, | ||
318 | { WM8996_WRITE_SEQUENCER_23, 0xa }, | ||
319 | { WM8996_WRITE_SEQUENCER_24, 0x60 }, | ||
320 | { WM8996_WRITE_SEQUENCER_25, 0x3b }, | ||
321 | { WM8996_WRITE_SEQUENCER_26, 0x502 }, | ||
322 | { WM8996_WRITE_SEQUENCER_27, 0x100 }, | ||
323 | { WM8996_WRITE_SEQUENCER_28, 0x2fff }, | ||
324 | { WM8996_WRITE_SEQUENCER_32, 0x2fff }, | ||
325 | { WM8996_WRITE_SEQUENCER_36, 0x2fff }, | ||
326 | { WM8996_WRITE_SEQUENCER_40, 0x2fff }, | ||
327 | { WM8996_WRITE_SEQUENCER_44, 0x2fff }, | ||
328 | { WM8996_WRITE_SEQUENCER_48, 0x2fff }, | ||
329 | { WM8996_WRITE_SEQUENCER_52, 0x2fff }, | ||
330 | { WM8996_WRITE_SEQUENCER_56, 0x2fff }, | ||
331 | { WM8996_WRITE_SEQUENCER_60, 0x2fff }, | ||
332 | { WM8996_WRITE_SEQUENCER_64, 0x1 }, | ||
333 | { WM8996_WRITE_SEQUENCER_65, 0x1 }, | ||
334 | { WM8996_WRITE_SEQUENCER_67, 0x6 }, | ||
335 | { WM8996_WRITE_SEQUENCER_68, 0x40 }, | ||
336 | { WM8996_WRITE_SEQUENCER_69, 0x1 }, | ||
337 | { WM8996_WRITE_SEQUENCER_70, 0xf }, | ||
338 | { WM8996_WRITE_SEQUENCER_71, 0x6 }, | ||
339 | { WM8996_WRITE_SEQUENCER_72, 0x1 }, | ||
340 | { WM8996_WRITE_SEQUENCER_73, 0x3 }, | ||
341 | { WM8996_WRITE_SEQUENCER_74, 0x104 }, | ||
342 | { WM8996_WRITE_SEQUENCER_76, 0x60 }, | ||
343 | { WM8996_WRITE_SEQUENCER_77, 0x11 }, | ||
344 | { WM8996_WRITE_SEQUENCER_78, 0x401 }, | ||
345 | { WM8996_WRITE_SEQUENCER_80, 0x50 }, | ||
346 | { WM8996_WRITE_SEQUENCER_81, 0x3 }, | ||
347 | { WM8996_WRITE_SEQUENCER_82, 0x100 }, | ||
348 | { WM8996_WRITE_SEQUENCER_84, 0x60 }, | ||
349 | { WM8996_WRITE_SEQUENCER_85, 0x3b }, | ||
350 | { WM8996_WRITE_SEQUENCER_86, 0x502 }, | ||
351 | { WM8996_WRITE_SEQUENCER_87, 0x100 }, | ||
352 | { WM8996_WRITE_SEQUENCER_88, 0x2fff }, | ||
353 | { WM8996_WRITE_SEQUENCER_92, 0x2fff }, | ||
354 | { WM8996_WRITE_SEQUENCER_96, 0x2fff }, | ||
355 | { WM8996_WRITE_SEQUENCER_100, 0x2fff }, | ||
356 | { WM8996_WRITE_SEQUENCER_104, 0x2fff }, | ||
357 | { WM8996_WRITE_SEQUENCER_108, 0x2fff }, | ||
358 | { WM8996_WRITE_SEQUENCER_112, 0x2fff }, | ||
359 | { WM8996_WRITE_SEQUENCER_116, 0x2fff }, | ||
360 | { WM8996_WRITE_SEQUENCER_120, 0x2fff }, | ||
361 | { WM8996_WRITE_SEQUENCER_124, 0x2fff }, | ||
362 | { WM8996_WRITE_SEQUENCER_128, 0x1 }, | ||
363 | { WM8996_WRITE_SEQUENCER_129, 0x1 }, | ||
364 | { WM8996_WRITE_SEQUENCER_131, 0x6 }, | ||
365 | { WM8996_WRITE_SEQUENCER_132, 0x40 }, | ||
366 | { WM8996_WRITE_SEQUENCER_133, 0x1 }, | ||
367 | { WM8996_WRITE_SEQUENCER_134, 0xf }, | ||
368 | { WM8996_WRITE_SEQUENCER_135, 0x6 }, | ||
369 | { WM8996_WRITE_SEQUENCER_136, 0x1 }, | ||
370 | { WM8996_WRITE_SEQUENCER_137, 0x3 }, | ||
371 | { WM8996_WRITE_SEQUENCER_138, 0x106 }, | ||
372 | { WM8996_WRITE_SEQUENCER_140, 0x61 }, | ||
373 | { WM8996_WRITE_SEQUENCER_141, 0x11 }, | ||
374 | { WM8996_WRITE_SEQUENCER_142, 0x401 }, | ||
375 | { WM8996_WRITE_SEQUENCER_144, 0x50 }, | ||
376 | { WM8996_WRITE_SEQUENCER_145, 0x3 }, | ||
377 | { WM8996_WRITE_SEQUENCER_146, 0x102 }, | ||
378 | { WM8996_WRITE_SEQUENCER_148, 0x51 }, | ||
379 | { WM8996_WRITE_SEQUENCER_149, 0x3 }, | ||
380 | { WM8996_WRITE_SEQUENCER_150, 0x106 }, | ||
381 | { WM8996_WRITE_SEQUENCER_151, 0xa }, | ||
382 | { WM8996_WRITE_SEQUENCER_152, 0x61 }, | ||
383 | { WM8996_WRITE_SEQUENCER_153, 0x3b }, | ||
384 | { WM8996_WRITE_SEQUENCER_154, 0x502 }, | ||
385 | { WM8996_WRITE_SEQUENCER_155, 0x100 }, | ||
386 | { WM8996_WRITE_SEQUENCER_156, 0x2fff }, | ||
387 | { WM8996_WRITE_SEQUENCER_160, 0x2fff }, | ||
388 | { WM8996_WRITE_SEQUENCER_164, 0x2fff }, | ||
389 | { WM8996_WRITE_SEQUENCER_168, 0x2fff }, | ||
390 | { WM8996_WRITE_SEQUENCER_172, 0x2fff }, | ||
391 | { WM8996_WRITE_SEQUENCER_176, 0x2fff }, | ||
392 | { WM8996_WRITE_SEQUENCER_180, 0x2fff }, | ||
393 | { WM8996_WRITE_SEQUENCER_184, 0x2fff }, | ||
394 | { WM8996_WRITE_SEQUENCER_188, 0x2fff }, | ||
395 | { WM8996_WRITE_SEQUENCER_192, 0x1 }, | ||
396 | { WM8996_WRITE_SEQUENCER_193, 0x1 }, | ||
397 | { WM8996_WRITE_SEQUENCER_195, 0x6 }, | ||
398 | { WM8996_WRITE_SEQUENCER_196, 0x40 }, | ||
399 | { WM8996_WRITE_SEQUENCER_197, 0x1 }, | ||
400 | { WM8996_WRITE_SEQUENCER_198, 0xf }, | ||
401 | { WM8996_WRITE_SEQUENCER_199, 0x6 }, | ||
402 | { WM8996_WRITE_SEQUENCER_200, 0x1 }, | ||
403 | { WM8996_WRITE_SEQUENCER_201, 0x3 }, | ||
404 | { WM8996_WRITE_SEQUENCER_202, 0x106 }, | ||
405 | { WM8996_WRITE_SEQUENCER_204, 0x61 }, | ||
406 | { WM8996_WRITE_SEQUENCER_205, 0x11 }, | ||
407 | { WM8996_WRITE_SEQUENCER_206, 0x401 }, | ||
408 | { WM8996_WRITE_SEQUENCER_208, 0x50 }, | ||
409 | { WM8996_WRITE_SEQUENCER_209, 0x3 }, | ||
410 | { WM8996_WRITE_SEQUENCER_210, 0x102 }, | ||
411 | { WM8996_WRITE_SEQUENCER_212, 0x61 }, | ||
412 | { WM8996_WRITE_SEQUENCER_213, 0x3b }, | ||
413 | { WM8996_WRITE_SEQUENCER_214, 0x502 }, | ||
414 | { WM8996_WRITE_SEQUENCER_215, 0x100 }, | ||
415 | { WM8996_WRITE_SEQUENCER_216, 0x2fff }, | ||
416 | { WM8996_WRITE_SEQUENCER_220, 0x2fff }, | ||
417 | { WM8996_WRITE_SEQUENCER_224, 0x2fff }, | ||
418 | { WM8996_WRITE_SEQUENCER_228, 0x2fff }, | ||
419 | { WM8996_WRITE_SEQUENCER_232, 0x2fff }, | ||
420 | { WM8996_WRITE_SEQUENCER_236, 0x2fff }, | ||
421 | { WM8996_WRITE_SEQUENCER_240, 0x2fff }, | ||
422 | { WM8996_WRITE_SEQUENCER_244, 0x2fff }, | ||
423 | { WM8996_WRITE_SEQUENCER_248, 0x2fff }, | ||
424 | { WM8996_WRITE_SEQUENCER_252, 0x2fff }, | ||
425 | { WM8996_WRITE_SEQUENCER_256, 0x60 }, | ||
426 | { WM8996_WRITE_SEQUENCER_258, 0x601 }, | ||
427 | { WM8996_WRITE_SEQUENCER_260, 0x50 }, | ||
428 | { WM8996_WRITE_SEQUENCER_262, 0x100 }, | ||
429 | { WM8996_WRITE_SEQUENCER_264, 0x1 }, | ||
430 | { WM8996_WRITE_SEQUENCER_266, 0x104 }, | ||
431 | { WM8996_WRITE_SEQUENCER_267, 0x100 }, | ||
432 | { WM8996_WRITE_SEQUENCER_268, 0x2fff }, | ||
433 | { WM8996_WRITE_SEQUENCER_272, 0x2fff }, | ||
434 | { WM8996_WRITE_SEQUENCER_276, 0x2fff }, | ||
435 | { WM8996_WRITE_SEQUENCER_280, 0x2fff }, | ||
436 | { WM8996_WRITE_SEQUENCER_284, 0x2fff }, | ||
437 | { WM8996_WRITE_SEQUENCER_288, 0x2fff }, | ||
438 | { WM8996_WRITE_SEQUENCER_292, 0x2fff }, | ||
439 | { WM8996_WRITE_SEQUENCER_296, 0x2fff }, | ||
440 | { WM8996_WRITE_SEQUENCER_300, 0x2fff }, | ||
441 | { WM8996_WRITE_SEQUENCER_304, 0x2fff }, | ||
442 | { WM8996_WRITE_SEQUENCER_308, 0x2fff }, | ||
443 | { WM8996_WRITE_SEQUENCER_312, 0x2fff }, | ||
444 | { WM8996_WRITE_SEQUENCER_316, 0x2fff }, | ||
445 | { WM8996_WRITE_SEQUENCER_320, 0x61 }, | ||
446 | { WM8996_WRITE_SEQUENCER_322, 0x601 }, | ||
447 | { WM8996_WRITE_SEQUENCER_324, 0x50 }, | ||
448 | { WM8996_WRITE_SEQUENCER_326, 0x102 }, | ||
449 | { WM8996_WRITE_SEQUENCER_328, 0x1 }, | ||
450 | { WM8996_WRITE_SEQUENCER_330, 0x106 }, | ||
451 | { WM8996_WRITE_SEQUENCER_331, 0x100 }, | ||
452 | { WM8996_WRITE_SEQUENCER_332, 0x2fff }, | ||
453 | { WM8996_WRITE_SEQUENCER_336, 0x2fff }, | ||
454 | { WM8996_WRITE_SEQUENCER_340, 0x2fff }, | ||
455 | { WM8996_WRITE_SEQUENCER_344, 0x2fff }, | ||
456 | { WM8996_WRITE_SEQUENCER_348, 0x2fff }, | ||
457 | { WM8996_WRITE_SEQUENCER_352, 0x2fff }, | ||
458 | { WM8996_WRITE_SEQUENCER_356, 0x2fff }, | ||
459 | { WM8996_WRITE_SEQUENCER_360, 0x2fff }, | ||
460 | { WM8996_WRITE_SEQUENCER_364, 0x2fff }, | ||
461 | { WM8996_WRITE_SEQUENCER_368, 0x2fff }, | ||
462 | { WM8996_WRITE_SEQUENCER_372, 0x2fff }, | ||
463 | { WM8996_WRITE_SEQUENCER_376, 0x2fff }, | ||
464 | { WM8996_WRITE_SEQUENCER_380, 0x2fff }, | ||
465 | { WM8996_WRITE_SEQUENCER_384, 0x60 }, | ||
466 | { WM8996_WRITE_SEQUENCER_386, 0x601 }, | ||
467 | { WM8996_WRITE_SEQUENCER_388, 0x61 }, | ||
468 | { WM8996_WRITE_SEQUENCER_390, 0x601 }, | ||
469 | { WM8996_WRITE_SEQUENCER_392, 0x50 }, | ||
470 | { WM8996_WRITE_SEQUENCER_394, 0x300 }, | ||
471 | { WM8996_WRITE_SEQUENCER_396, 0x1 }, | ||
472 | { WM8996_WRITE_SEQUENCER_398, 0x304 }, | ||
473 | { WM8996_WRITE_SEQUENCER_400, 0x40 }, | ||
474 | { WM8996_WRITE_SEQUENCER_402, 0xf }, | ||
475 | { WM8996_WRITE_SEQUENCER_404, 0x1 }, | ||
476 | { WM8996_WRITE_SEQUENCER_407, 0x100 }, | ||
477 | }; | 299 | }; |
478 | 300 | ||
479 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0); | 301 | static const DECLARE_TLV_DB_SCALE(inpga_tlv, 0, 100, 0); |
@@ -1706,18 +1528,6 @@ static bool wm8996_volatile_register(struct device *dev, unsigned int reg) | |||
1706 | } | 1528 | } |
1707 | } | 1529 | } |
1708 | 1530 | ||
1709 | static int wm8996_reset(struct wm8996_priv *wm8996) | ||
1710 | { | ||
1711 | if (wm8996->pdata.ldo_ena > 0) { | ||
1712 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); | ||
1713 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 1); | ||
1714 | return 0; | ||
1715 | } else { | ||
1716 | return regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET, | ||
1717 | 0x8915); | ||
1718 | } | ||
1719 | } | ||
1720 | |||
1721 | static const int bclk_divs[] = { | 1531 | static const int bclk_divs[] = { |
1722 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 | 1532 | 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96 |
1723 | }; | 1533 | }; |
@@ -1809,8 +1619,10 @@ static int wm8996_set_bias_level(struct snd_soc_codec *codec, | |||
1809 | 1619 | ||
1810 | case SND_SOC_BIAS_OFF: | 1620 | case SND_SOC_BIAS_OFF: |
1811 | regcache_cache_only(codec->control_data, true); | 1621 | regcache_cache_only(codec->control_data, true); |
1812 | if (wm8996->pdata.ldo_ena >= 0) | 1622 | if (wm8996->pdata.ldo_ena >= 0) { |
1813 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); | 1623 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); |
1624 | regcache_cache_only(codec->control_data, true); | ||
1625 | } | ||
1814 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), | 1626 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), |
1815 | wm8996->supplies); | 1627 | wm8996->supplies); |
1816 | break; | 1628 | break; |
@@ -2807,7 +2619,7 @@ static int wm8996_probe(struct snd_soc_codec *codec) | |||
2807 | int ret; | 2619 | int ret; |
2808 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 2620 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
2809 | struct i2c_client *i2c = to_i2c_client(codec->dev); | 2621 | struct i2c_client *i2c = to_i2c_client(codec->dev); |
2810 | int i, irq_flags; | 2622 | int irq_flags; |
2811 | 2623 | ||
2812 | wm8996->codec = codec; | 2624 | wm8996->codec = codec; |
2813 | 2625 | ||
@@ -2822,177 +2634,12 @@ static int wm8996_probe(struct snd_soc_codec *codec) | |||
2822 | goto err; | 2634 | goto err; |
2823 | } | 2635 | } |
2824 | 2636 | ||
2825 | wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0; | ||
2826 | wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1; | ||
2827 | wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2; | ||
2828 | |||
2829 | /* This should really be moved into the regulator core */ | ||
2830 | for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { | ||
2831 | ret = regulator_register_notifier(wm8996->supplies[i].consumer, | ||
2832 | &wm8996->disable_nb[i]); | ||
2833 | if (ret != 0) { | ||
2834 | dev_err(codec->dev, | ||
2835 | "Failed to register regulator notifier: %d\n", | ||
2836 | ret); | ||
2837 | } | ||
2838 | } | ||
2839 | |||
2840 | /* Apply platform data settings */ | ||
2841 | snd_soc_update_bits(codec, WM8996_LINE_INPUT_CONTROL, | ||
2842 | WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK, | ||
2843 | wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT | | ||
2844 | wm8996->pdata.inr_mode); | ||
2845 | |||
2846 | for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) { | ||
2847 | if (!wm8996->pdata.gpio_default[i]) | ||
2848 | continue; | ||
2849 | |||
2850 | snd_soc_write(codec, WM8996_GPIO_1 + i, | ||
2851 | wm8996->pdata.gpio_default[i] & 0xffff); | ||
2852 | } | ||
2853 | |||
2854 | if (wm8996->pdata.spkmute_seq) | ||
2855 | snd_soc_update_bits(codec, WM8996_PDM_SPEAKER_MUTE_SEQUENCE, | ||
2856 | WM8996_SPK_MUTE_ENDIAN | | ||
2857 | WM8996_SPK_MUTE_SEQ1_MASK, | ||
2858 | wm8996->pdata.spkmute_seq); | ||
2859 | |||
2860 | snd_soc_update_bits(codec, WM8996_ACCESSORY_DETECT_MODE_2, | ||
2861 | WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC | | ||
2862 | WM8996_MICD_SRC, wm8996->pdata.micdet_def); | ||
2863 | |||
2864 | /* Latch volume update bits */ | ||
2865 | snd_soc_update_bits(codec, WM8996_LEFT_LINE_INPUT_VOLUME, | ||
2866 | WM8996_IN1_VU, WM8996_IN1_VU); | ||
2867 | snd_soc_update_bits(codec, WM8996_RIGHT_LINE_INPUT_VOLUME, | ||
2868 | WM8996_IN1_VU, WM8996_IN1_VU); | ||
2869 | |||
2870 | snd_soc_update_bits(codec, WM8996_DAC1_LEFT_VOLUME, | ||
2871 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2872 | snd_soc_update_bits(codec, WM8996_DAC1_RIGHT_VOLUME, | ||
2873 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2874 | snd_soc_update_bits(codec, WM8996_DAC2_LEFT_VOLUME, | ||
2875 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2876 | snd_soc_update_bits(codec, WM8996_DAC2_RIGHT_VOLUME, | ||
2877 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2878 | |||
2879 | snd_soc_update_bits(codec, WM8996_OUTPUT1_LEFT_VOLUME, | ||
2880 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2881 | snd_soc_update_bits(codec, WM8996_OUTPUT1_RIGHT_VOLUME, | ||
2882 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2883 | snd_soc_update_bits(codec, WM8996_OUTPUT2_LEFT_VOLUME, | ||
2884 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2885 | snd_soc_update_bits(codec, WM8996_OUTPUT2_RIGHT_VOLUME, | ||
2886 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2887 | |||
2888 | snd_soc_update_bits(codec, WM8996_DSP1_TX_LEFT_VOLUME, | ||
2889 | WM8996_DSP1TX_VU, WM8996_DSP1TX_VU); | ||
2890 | snd_soc_update_bits(codec, WM8996_DSP1_TX_RIGHT_VOLUME, | ||
2891 | WM8996_DSP1TX_VU, WM8996_DSP1TX_VU); | ||
2892 | snd_soc_update_bits(codec, WM8996_DSP2_TX_LEFT_VOLUME, | ||
2893 | WM8996_DSP2TX_VU, WM8996_DSP2TX_VU); | ||
2894 | snd_soc_update_bits(codec, WM8996_DSP2_TX_RIGHT_VOLUME, | ||
2895 | WM8996_DSP2TX_VU, WM8996_DSP2TX_VU); | ||
2896 | |||
2897 | snd_soc_update_bits(codec, WM8996_DSP1_RX_LEFT_VOLUME, | ||
2898 | WM8996_DSP1RX_VU, WM8996_DSP1RX_VU); | ||
2899 | snd_soc_update_bits(codec, WM8996_DSP1_RX_RIGHT_VOLUME, | ||
2900 | WM8996_DSP1RX_VU, WM8996_DSP1RX_VU); | ||
2901 | snd_soc_update_bits(codec, WM8996_DSP2_RX_LEFT_VOLUME, | ||
2902 | WM8996_DSP2RX_VU, WM8996_DSP2RX_VU); | ||
2903 | snd_soc_update_bits(codec, WM8996_DSP2_RX_RIGHT_VOLUME, | ||
2904 | WM8996_DSP2RX_VU, WM8996_DSP2RX_VU); | ||
2905 | |||
2906 | /* No support currently for the underclocked TDM modes and | ||
2907 | * pick a default TDM layout with each channel pair working with | ||
2908 | * slots 0 and 1. */ | ||
2909 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_0_CONFIGURATION, | ||
2910 | WM8996_AIF1RX_CHAN0_SLOTS_MASK | | ||
2911 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2912 | 1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0); | ||
2913 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_1_CONFIGURATION, | ||
2914 | WM8996_AIF1RX_CHAN1_SLOTS_MASK | | ||
2915 | WM8996_AIF1RX_CHAN1_START_SLOT_MASK, | ||
2916 | 1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1); | ||
2917 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_2_CONFIGURATION, | ||
2918 | WM8996_AIF1RX_CHAN2_SLOTS_MASK | | ||
2919 | WM8996_AIF1RX_CHAN2_START_SLOT_MASK, | ||
2920 | 1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0); | ||
2921 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_3_CONFIGURATION, | ||
2922 | WM8996_AIF1RX_CHAN3_SLOTS_MASK | | ||
2923 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2924 | 1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1); | ||
2925 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_4_CONFIGURATION, | ||
2926 | WM8996_AIF1RX_CHAN4_SLOTS_MASK | | ||
2927 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2928 | 1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0); | ||
2929 | snd_soc_update_bits(codec, WM8996_AIF1RX_CHANNEL_5_CONFIGURATION, | ||
2930 | WM8996_AIF1RX_CHAN5_SLOTS_MASK | | ||
2931 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2932 | 1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1); | ||
2933 | |||
2934 | snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_0_CONFIGURATION, | ||
2935 | WM8996_AIF2RX_CHAN0_SLOTS_MASK | | ||
2936 | WM8996_AIF2RX_CHAN0_START_SLOT_MASK, | ||
2937 | 1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0); | ||
2938 | snd_soc_update_bits(codec, WM8996_AIF2RX_CHANNEL_1_CONFIGURATION, | ||
2939 | WM8996_AIF2RX_CHAN1_SLOTS_MASK | | ||
2940 | WM8996_AIF2RX_CHAN1_START_SLOT_MASK, | ||
2941 | 1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1); | ||
2942 | |||
2943 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_0_CONFIGURATION, | ||
2944 | WM8996_AIF1TX_CHAN0_SLOTS_MASK | | ||
2945 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2946 | 1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0); | ||
2947 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, | ||
2948 | WM8996_AIF1TX_CHAN1_SLOTS_MASK | | ||
2949 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2950 | 1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1); | ||
2951 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_2_CONFIGURATION, | ||
2952 | WM8996_AIF1TX_CHAN2_SLOTS_MASK | | ||
2953 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2954 | 1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0); | ||
2955 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_3_CONFIGURATION, | ||
2956 | WM8996_AIF1TX_CHAN3_SLOTS_MASK | | ||
2957 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2958 | 1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1); | ||
2959 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_4_CONFIGURATION, | ||
2960 | WM8996_AIF1TX_CHAN4_SLOTS_MASK | | ||
2961 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2962 | 1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0); | ||
2963 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_5_CONFIGURATION, | ||
2964 | WM8996_AIF1TX_CHAN5_SLOTS_MASK | | ||
2965 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2966 | 1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1); | ||
2967 | |||
2968 | snd_soc_update_bits(codec, WM8996_AIF2TX_CHANNEL_0_CONFIGURATION, | ||
2969 | WM8996_AIF2TX_CHAN0_SLOTS_MASK | | ||
2970 | WM8996_AIF2TX_CHAN0_START_SLOT_MASK, | ||
2971 | 1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0); | ||
2972 | snd_soc_update_bits(codec, WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, | ||
2973 | WM8996_AIF2TX_CHAN1_SLOTS_MASK | | ||
2974 | WM8996_AIF2TX_CHAN1_START_SLOT_MASK, | ||
2975 | 1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1); | ||
2976 | |||
2977 | if (wm8996->pdata.num_retune_mobile_cfgs) | 2637 | if (wm8996->pdata.num_retune_mobile_cfgs) |
2978 | wm8996_retune_mobile_pdata(codec); | 2638 | wm8996_retune_mobile_pdata(codec); |
2979 | else | 2639 | else |
2980 | snd_soc_add_codec_controls(codec, wm8996_eq_controls, | 2640 | snd_soc_add_codec_controls(codec, wm8996_eq_controls, |
2981 | ARRAY_SIZE(wm8996_eq_controls)); | 2641 | ARRAY_SIZE(wm8996_eq_controls)); |
2982 | 2642 | ||
2983 | /* If the TX LRCLK pins are not in LRCLK mode configure the | ||
2984 | * AIFs to source their clocks from the RX LRCLKs. | ||
2985 | */ | ||
2986 | if ((snd_soc_read(codec, WM8996_GPIO_1))) | ||
2987 | snd_soc_update_bits(codec, WM8996_AIF1_TX_LRCLK_2, | ||
2988 | WM8996_AIF1TX_LRCLK_MODE, | ||
2989 | WM8996_AIF1TX_LRCLK_MODE); | ||
2990 | |||
2991 | if ((snd_soc_read(codec, WM8996_GPIO_2))) | ||
2992 | snd_soc_update_bits(codec, WM8996_AIF2_TX_LRCLK_2, | ||
2993 | WM8996_AIF2TX_LRCLK_MODE, | ||
2994 | WM8996_AIF2TX_LRCLK_MODE); | ||
2995 | |||
2996 | if (i2c->irq) { | 2643 | if (i2c->irq) { |
2997 | if (wm8996->pdata.irq_flags) | 2644 | if (wm8996->pdata.irq_flags) |
2998 | irq_flags = wm8996->pdata.irq_flags; | 2645 | irq_flags = wm8996->pdata.irq_flags; |
@@ -3036,9 +2683,7 @@ err: | |||
3036 | 2683 | ||
3037 | static int wm8996_remove(struct snd_soc_codec *codec) | 2684 | static int wm8996_remove(struct snd_soc_codec *codec) |
3038 | { | 2685 | { |
3039 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | ||
3040 | struct i2c_client *i2c = to_i2c_client(codec->dev); | 2686 | struct i2c_client *i2c = to_i2c_client(codec->dev); |
3041 | int i; | ||
3042 | 2687 | ||
3043 | snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL, | 2688 | snd_soc_update_bits(codec, WM8996_INTERRUPT_CONTROL, |
3044 | WM8996_IM_IRQ, WM8996_IM_IRQ); | 2689 | WM8996_IM_IRQ, WM8996_IM_IRQ); |
@@ -3046,10 +2691,6 @@ static int wm8996_remove(struct snd_soc_codec *codec) | |||
3046 | if (i2c->irq) | 2691 | if (i2c->irq) |
3047 | free_irq(i2c->irq, codec); | 2692 | free_irq(i2c->irq, codec); |
3048 | 2693 | ||
3049 | for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) | ||
3050 | regulator_unregister_notifier(wm8996->supplies[i].consumer, | ||
3051 | &wm8996->disable_nb[i]); | ||
3052 | |||
3053 | return 0; | 2694 | return 0; |
3054 | } | 2695 | } |
3055 | 2696 | ||
@@ -3163,6 +2804,21 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, | |||
3163 | goto err_gpio; | 2804 | goto err_gpio; |
3164 | } | 2805 | } |
3165 | 2806 | ||
2807 | wm8996->disable_nb[0].notifier_call = wm8996_regulator_event_0; | ||
2808 | wm8996->disable_nb[1].notifier_call = wm8996_regulator_event_1; | ||
2809 | wm8996->disable_nb[2].notifier_call = wm8996_regulator_event_2; | ||
2810 | |||
2811 | /* This should really be moved into the regulator core */ | ||
2812 | for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) { | ||
2813 | ret = regulator_register_notifier(wm8996->supplies[i].consumer, | ||
2814 | &wm8996->disable_nb[i]); | ||
2815 | if (ret != 0) { | ||
2816 | dev_err(&i2c->dev, | ||
2817 | "Failed to register regulator notifier: %d\n", | ||
2818 | ret); | ||
2819 | } | ||
2820 | } | ||
2821 | |||
3166 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), | 2822 | ret = regulator_bulk_enable(ARRAY_SIZE(wm8996->supplies), |
3167 | wm8996->supplies); | 2823 | wm8996->supplies); |
3168 | if (ret != 0) { | 2824 | if (ret != 0) { |
@@ -3175,7 +2831,7 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, | |||
3175 | msleep(5); | 2831 | msleep(5); |
3176 | } | 2832 | } |
3177 | 2833 | ||
3178 | wm8996->regmap = regmap_init_i2c(i2c, &wm8996_regmap); | 2834 | wm8996->regmap = devm_regmap_init_i2c(i2c, &wm8996_regmap); |
3179 | if (IS_ERR(wm8996->regmap)) { | 2835 | if (IS_ERR(wm8996->regmap)) { |
3180 | ret = PTR_ERR(wm8996->regmap); | 2836 | ret = PTR_ERR(wm8996->regmap); |
3181 | dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); | 2837 | dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); |
@@ -3203,15 +2859,199 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, | |||
3203 | dev_info(&i2c->dev, "revision %c\n", | 2859 | dev_info(&i2c->dev, "revision %c\n", |
3204 | (reg & WM8996_CHIP_REV_MASK) + 'A'); | 2860 | (reg & WM8996_CHIP_REV_MASK) + 'A'); |
3205 | 2861 | ||
3206 | ret = wm8996_reset(wm8996); | 2862 | if (wm8996->pdata.ldo_ena > 0) { |
3207 | if (ret < 0) { | 2863 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); |
3208 | dev_err(&i2c->dev, "Failed to issue reset\n"); | 2864 | regcache_cache_only(wm8996->regmap, true); |
3209 | goto err_regmap; | 2865 | } else { |
2866 | ret = regmap_write(wm8996->regmap, WM8996_SOFTWARE_RESET, | ||
2867 | 0x8915); | ||
2868 | if (ret != 0) { | ||
2869 | dev_err(&i2c->dev, "Failed to issue reset: %d\n", ret); | ||
2870 | goto err_regmap; | ||
2871 | } | ||
3210 | } | 2872 | } |
3211 | 2873 | ||
3212 | regcache_cache_only(wm8996->regmap, true); | ||
3213 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); | 2874 | regulator_bulk_disable(ARRAY_SIZE(wm8996->supplies), wm8996->supplies); |
3214 | 2875 | ||
2876 | /* Apply platform data settings */ | ||
2877 | regmap_update_bits(wm8996->regmap, WM8996_LINE_INPUT_CONTROL, | ||
2878 | WM8996_INL_MODE_MASK | WM8996_INR_MODE_MASK, | ||
2879 | wm8996->pdata.inl_mode << WM8996_INL_MODE_SHIFT | | ||
2880 | wm8996->pdata.inr_mode); | ||
2881 | |||
2882 | for (i = 0; i < ARRAY_SIZE(wm8996->pdata.gpio_default); i++) { | ||
2883 | if (!wm8996->pdata.gpio_default[i]) | ||
2884 | continue; | ||
2885 | |||
2886 | regmap_write(wm8996->regmap, WM8996_GPIO_1 + i, | ||
2887 | wm8996->pdata.gpio_default[i] & 0xffff); | ||
2888 | } | ||
2889 | |||
2890 | if (wm8996->pdata.spkmute_seq) | ||
2891 | regmap_update_bits(wm8996->regmap, | ||
2892 | WM8996_PDM_SPEAKER_MUTE_SEQUENCE, | ||
2893 | WM8996_SPK_MUTE_ENDIAN | | ||
2894 | WM8996_SPK_MUTE_SEQ1_MASK, | ||
2895 | wm8996->pdata.spkmute_seq); | ||
2896 | |||
2897 | regmap_update_bits(wm8996->regmap, WM8996_ACCESSORY_DETECT_MODE_2, | ||
2898 | WM8996_MICD_BIAS_SRC | WM8996_HPOUT1FB_SRC | | ||
2899 | WM8996_MICD_SRC, wm8996->pdata.micdet_def); | ||
2900 | |||
2901 | /* Latch volume update bits */ | ||
2902 | regmap_update_bits(wm8996->regmap, WM8996_LEFT_LINE_INPUT_VOLUME, | ||
2903 | WM8996_IN1_VU, WM8996_IN1_VU); | ||
2904 | regmap_update_bits(wm8996->regmap, WM8996_RIGHT_LINE_INPUT_VOLUME, | ||
2905 | WM8996_IN1_VU, WM8996_IN1_VU); | ||
2906 | |||
2907 | regmap_update_bits(wm8996->regmap, WM8996_DAC1_LEFT_VOLUME, | ||
2908 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2909 | regmap_update_bits(wm8996->regmap, WM8996_DAC1_RIGHT_VOLUME, | ||
2910 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2911 | regmap_update_bits(wm8996->regmap, WM8996_DAC2_LEFT_VOLUME, | ||
2912 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2913 | regmap_update_bits(wm8996->regmap, WM8996_DAC2_RIGHT_VOLUME, | ||
2914 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2915 | |||
2916 | regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_LEFT_VOLUME, | ||
2917 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2918 | regmap_update_bits(wm8996->regmap, WM8996_OUTPUT1_RIGHT_VOLUME, | ||
2919 | WM8996_DAC1_VU, WM8996_DAC1_VU); | ||
2920 | regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_LEFT_VOLUME, | ||
2921 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2922 | regmap_update_bits(wm8996->regmap, WM8996_OUTPUT2_RIGHT_VOLUME, | ||
2923 | WM8996_DAC2_VU, WM8996_DAC2_VU); | ||
2924 | |||
2925 | regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_LEFT_VOLUME, | ||
2926 | WM8996_DSP1TX_VU, WM8996_DSP1TX_VU); | ||
2927 | regmap_update_bits(wm8996->regmap, WM8996_DSP1_TX_RIGHT_VOLUME, | ||
2928 | WM8996_DSP1TX_VU, WM8996_DSP1TX_VU); | ||
2929 | regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_LEFT_VOLUME, | ||
2930 | WM8996_DSP2TX_VU, WM8996_DSP2TX_VU); | ||
2931 | regmap_update_bits(wm8996->regmap, WM8996_DSP2_TX_RIGHT_VOLUME, | ||
2932 | WM8996_DSP2TX_VU, WM8996_DSP2TX_VU); | ||
2933 | |||
2934 | regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_LEFT_VOLUME, | ||
2935 | WM8996_DSP1RX_VU, WM8996_DSP1RX_VU); | ||
2936 | regmap_update_bits(wm8996->regmap, WM8996_DSP1_RX_RIGHT_VOLUME, | ||
2937 | WM8996_DSP1RX_VU, WM8996_DSP1RX_VU); | ||
2938 | regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_LEFT_VOLUME, | ||
2939 | WM8996_DSP2RX_VU, WM8996_DSP2RX_VU); | ||
2940 | regmap_update_bits(wm8996->regmap, WM8996_DSP2_RX_RIGHT_VOLUME, | ||
2941 | WM8996_DSP2RX_VU, WM8996_DSP2RX_VU); | ||
2942 | |||
2943 | /* No support currently for the underclocked TDM modes and | ||
2944 | * pick a default TDM layout with each channel pair working with | ||
2945 | * slots 0 and 1. */ | ||
2946 | regmap_update_bits(wm8996->regmap, | ||
2947 | WM8996_AIF1RX_CHANNEL_0_CONFIGURATION, | ||
2948 | WM8996_AIF1RX_CHAN0_SLOTS_MASK | | ||
2949 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2950 | 1 << WM8996_AIF1RX_CHAN0_SLOTS_SHIFT | 0); | ||
2951 | regmap_update_bits(wm8996->regmap, | ||
2952 | WM8996_AIF1RX_CHANNEL_1_CONFIGURATION, | ||
2953 | WM8996_AIF1RX_CHAN1_SLOTS_MASK | | ||
2954 | WM8996_AIF1RX_CHAN1_START_SLOT_MASK, | ||
2955 | 1 << WM8996_AIF1RX_CHAN1_SLOTS_SHIFT | 1); | ||
2956 | regmap_update_bits(wm8996->regmap, | ||
2957 | WM8996_AIF1RX_CHANNEL_2_CONFIGURATION, | ||
2958 | WM8996_AIF1RX_CHAN2_SLOTS_MASK | | ||
2959 | WM8996_AIF1RX_CHAN2_START_SLOT_MASK, | ||
2960 | 1 << WM8996_AIF1RX_CHAN2_SLOTS_SHIFT | 0); | ||
2961 | regmap_update_bits(wm8996->regmap, | ||
2962 | WM8996_AIF1RX_CHANNEL_3_CONFIGURATION, | ||
2963 | WM8996_AIF1RX_CHAN3_SLOTS_MASK | | ||
2964 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2965 | 1 << WM8996_AIF1RX_CHAN3_SLOTS_SHIFT | 1); | ||
2966 | regmap_update_bits(wm8996->regmap, | ||
2967 | WM8996_AIF1RX_CHANNEL_4_CONFIGURATION, | ||
2968 | WM8996_AIF1RX_CHAN4_SLOTS_MASK | | ||
2969 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2970 | 1 << WM8996_AIF1RX_CHAN4_SLOTS_SHIFT | 0); | ||
2971 | regmap_update_bits(wm8996->regmap, | ||
2972 | WM8996_AIF1RX_CHANNEL_5_CONFIGURATION, | ||
2973 | WM8996_AIF1RX_CHAN5_SLOTS_MASK | | ||
2974 | WM8996_AIF1RX_CHAN0_START_SLOT_MASK, | ||
2975 | 1 << WM8996_AIF1RX_CHAN5_SLOTS_SHIFT | 1); | ||
2976 | |||
2977 | regmap_update_bits(wm8996->regmap, | ||
2978 | WM8996_AIF2RX_CHANNEL_0_CONFIGURATION, | ||
2979 | WM8996_AIF2RX_CHAN0_SLOTS_MASK | | ||
2980 | WM8996_AIF2RX_CHAN0_START_SLOT_MASK, | ||
2981 | 1 << WM8996_AIF2RX_CHAN0_SLOTS_SHIFT | 0); | ||
2982 | regmap_update_bits(wm8996->regmap, | ||
2983 | WM8996_AIF2RX_CHANNEL_1_CONFIGURATION, | ||
2984 | WM8996_AIF2RX_CHAN1_SLOTS_MASK | | ||
2985 | WM8996_AIF2RX_CHAN1_START_SLOT_MASK, | ||
2986 | 1 << WM8996_AIF2RX_CHAN1_SLOTS_SHIFT | 1); | ||
2987 | |||
2988 | regmap_update_bits(wm8996->regmap, | ||
2989 | WM8996_AIF1TX_CHANNEL_0_CONFIGURATION, | ||
2990 | WM8996_AIF1TX_CHAN0_SLOTS_MASK | | ||
2991 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2992 | 1 << WM8996_AIF1TX_CHAN0_SLOTS_SHIFT | 0); | ||
2993 | regmap_update_bits(wm8996->regmap, | ||
2994 | WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, | ||
2995 | WM8996_AIF1TX_CHAN1_SLOTS_MASK | | ||
2996 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
2997 | 1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1); | ||
2998 | regmap_update_bits(wm8996->regmap, | ||
2999 | WM8996_AIF1TX_CHANNEL_2_CONFIGURATION, | ||
3000 | WM8996_AIF1TX_CHAN2_SLOTS_MASK | | ||
3001 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
3002 | 1 << WM8996_AIF1TX_CHAN2_SLOTS_SHIFT | 0); | ||
3003 | regmap_update_bits(wm8996->regmap, | ||
3004 | WM8996_AIF1TX_CHANNEL_3_CONFIGURATION, | ||
3005 | WM8996_AIF1TX_CHAN3_SLOTS_MASK | | ||
3006 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
3007 | 1 << WM8996_AIF1TX_CHAN3_SLOTS_SHIFT | 1); | ||
3008 | regmap_update_bits(wm8996->regmap, | ||
3009 | WM8996_AIF1TX_CHANNEL_4_CONFIGURATION, | ||
3010 | WM8996_AIF1TX_CHAN4_SLOTS_MASK | | ||
3011 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
3012 | 1 << WM8996_AIF1TX_CHAN4_SLOTS_SHIFT | 0); | ||
3013 | regmap_update_bits(wm8996->regmap, | ||
3014 | WM8996_AIF1TX_CHANNEL_5_CONFIGURATION, | ||
3015 | WM8996_AIF1TX_CHAN5_SLOTS_MASK | | ||
3016 | WM8996_AIF1TX_CHAN0_START_SLOT_MASK, | ||
3017 | 1 << WM8996_AIF1TX_CHAN5_SLOTS_SHIFT | 1); | ||
3018 | |||
3019 | regmap_update_bits(wm8996->regmap, | ||
3020 | WM8996_AIF2TX_CHANNEL_0_CONFIGURATION, | ||
3021 | WM8996_AIF2TX_CHAN0_SLOTS_MASK | | ||
3022 | WM8996_AIF2TX_CHAN0_START_SLOT_MASK, | ||
3023 | 1 << WM8996_AIF2TX_CHAN0_SLOTS_SHIFT | 0); | ||
3024 | regmap_update_bits(wm8996->regmap, | ||
3025 | WM8996_AIF1TX_CHANNEL_1_CONFIGURATION, | ||
3026 | WM8996_AIF2TX_CHAN1_SLOTS_MASK | | ||
3027 | WM8996_AIF2TX_CHAN1_START_SLOT_MASK, | ||
3028 | 1 << WM8996_AIF1TX_CHAN1_SLOTS_SHIFT | 1); | ||
3029 | |||
3030 | /* If the TX LRCLK pins are not in LRCLK mode configure the | ||
3031 | * AIFs to source their clocks from the RX LRCLKs. | ||
3032 | */ | ||
3033 | ret = regmap_read(wm8996->regmap, WM8996_GPIO_1, ®); | ||
3034 | if (ret != 0) { | ||
3035 | dev_err(&i2c->dev, "Failed to read GPIO1: %d\n", ret); | ||
3036 | goto err_regmap; | ||
3037 | } | ||
3038 | |||
3039 | if (reg & WM8996_GP1_FN_MASK) | ||
3040 | regmap_update_bits(wm8996->regmap, WM8996_AIF1_TX_LRCLK_2, | ||
3041 | WM8996_AIF1TX_LRCLK_MODE, | ||
3042 | WM8996_AIF1TX_LRCLK_MODE); | ||
3043 | |||
3044 | ret = regmap_read(wm8996->regmap, WM8996_GPIO_2, ®); | ||
3045 | if (ret != 0) { | ||
3046 | dev_err(&i2c->dev, "Failed to read GPIO2: %d\n", ret); | ||
3047 | goto err_regmap; | ||
3048 | } | ||
3049 | |||
3050 | if (reg & WM8996_GP2_FN_MASK) | ||
3051 | regmap_update_bits(wm8996->regmap, WM8996_AIF2_TX_LRCLK_2, | ||
3052 | WM8996_AIF2TX_LRCLK_MODE, | ||
3053 | WM8996_AIF2TX_LRCLK_MODE); | ||
3054 | |||
3215 | wm8996_init_gpio(wm8996); | 3055 | wm8996_init_gpio(wm8996); |
3216 | 3056 | ||
3217 | ret = snd_soc_register_codec(&i2c->dev, | 3057 | ret = snd_soc_register_codec(&i2c->dev, |
@@ -3225,7 +3065,6 @@ static __devinit int wm8996_i2c_probe(struct i2c_client *i2c, | |||
3225 | err_gpiolib: | 3065 | err_gpiolib: |
3226 | wm8996_free_gpio(wm8996); | 3066 | wm8996_free_gpio(wm8996); |
3227 | err_regmap: | 3067 | err_regmap: |
3228 | regmap_exit(wm8996->regmap); | ||
3229 | err_enable: | 3068 | err_enable: |
3230 | if (wm8996->pdata.ldo_ena > 0) | 3069 | if (wm8996->pdata.ldo_ena > 0) |
3231 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); | 3070 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); |
@@ -3241,14 +3080,18 @@ err: | |||
3241 | static __devexit int wm8996_i2c_remove(struct i2c_client *client) | 3080 | static __devexit int wm8996_i2c_remove(struct i2c_client *client) |
3242 | { | 3081 | { |
3243 | struct wm8996_priv *wm8996 = i2c_get_clientdata(client); | 3082 | struct wm8996_priv *wm8996 = i2c_get_clientdata(client); |
3083 | int i; | ||
3244 | 3084 | ||
3245 | snd_soc_unregister_codec(&client->dev); | 3085 | snd_soc_unregister_codec(&client->dev); |
3246 | wm8996_free_gpio(wm8996); | 3086 | wm8996_free_gpio(wm8996); |
3247 | regmap_exit(wm8996->regmap); | ||
3248 | if (wm8996->pdata.ldo_ena > 0) { | 3087 | if (wm8996->pdata.ldo_ena > 0) { |
3249 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); | 3088 | gpio_set_value_cansleep(wm8996->pdata.ldo_ena, 0); |
3250 | gpio_free(wm8996->pdata.ldo_ena); | 3089 | gpio_free(wm8996->pdata.ldo_ena); |
3251 | } | 3090 | } |
3091 | for (i = 0; i < ARRAY_SIZE(wm8996->supplies); i++) | ||
3092 | regulator_unregister_notifier(wm8996->supplies[i].consumer, | ||
3093 | &wm8996->disable_nb[i]); | ||
3094 | |||
3252 | return 0; | 3095 | return 0; |
3253 | } | 3096 | } |
3254 | 3097 | ||
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 9328270df16c..2de74e1ea225 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Author: Mark Brown | 4 | * Author: Mark Brown |
5 | * | 5 | * |
6 | * Copyright 2009 Wolfson Microelectronics plc | 6 | * Copyright 2009-12 Wolfson Microelectronics plc |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 4b263b6edf13..2c2346fdd637 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * ALSA SoC WM9090 driver | 2 | * ALSA SoC WM9090 driver |
3 | * | 3 | * |
4 | * Copyright 2009, 2010 Wolfson Microelectronics | 4 | * Copyright 2009-12 Wolfson Microelectronics |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index a1541414d904..099e6ec32125 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm9712.c -- ALSA Soc WM9712 codec support | 2 | * wm9712.c -- ALSA Soc WM9712 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006-12 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 2d22cc70d536..3eb19fb71d17 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm9713.c -- ALSA Soc WM9713 codec support | 2 | * wm9713.c -- ALSA Soc WM9713 codec support |
3 | * | 3 | * |
4 | * Copyright 2006 Wolfson Microelectronics PLC. | 4 | * Copyright 2006-10 Wolfson Microelectronics PLC. |
5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> | 5 | * Author: Liam Girdwood <lrg@slimlogic.co.uk> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify it | 7 | * This program is free software; you can redistribute it and/or modify it |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index dfe957a47f29..61baa48823cb 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * wm_hubs.c -- WM8993/4 common code | 2 | * wm_hubs.c -- WM8993/4 common code |
3 | * | 3 | * |
4 | * Copyright 2009 Wolfson Microelectronics plc | 4 | * Copyright 2009-12 Wolfson Microelectronics plc |
5 | * | 5 | * |
6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | 6 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> |
7 | * | 7 | * |
diff --git a/sound/soc/dwc/Kconfig b/sound/soc/dwc/Kconfig new file mode 100644 index 000000000000..e334900cf0b8 --- /dev/null +++ b/sound/soc/dwc/Kconfig | |||
@@ -0,0 +1,9 @@ | |||
1 | config SND_DESIGNWARE_I2S | ||
2 | tristate "Synopsys I2S Device Driver" | ||
3 | depends on CLKDEV_LOOKUP | ||
4 | help | ||
5 | Say Y or M if you want to add support for I2S driver for | ||
6 | Synopsys desigwnware I2S device. The device supports upto | ||
7 | maximum of 8 channels each for play and record. | ||
8 | |||
9 | |||
diff --git a/sound/soc/dwc/Makefile b/sound/soc/dwc/Makefile new file mode 100644 index 000000000000..319371f690f4 --- /dev/null +++ b/sound/soc/dwc/Makefile | |||
@@ -0,0 +1,3 @@ | |||
1 | # SYNOPSYS Platform Support | ||
2 | obj-$(CONFIG_SND_DESIGNWARE_I2S) += designware_i2s.o | ||
3 | |||
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c new file mode 100644 index 000000000000..1aa51300c564 --- /dev/null +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -0,0 +1,455 @@ | |||
1 | /* | ||
2 | * ALSA SoC Synopsys I2S Audio Layer | ||
3 | * | ||
4 | * sound/soc/spear/designware_i2s.c | ||
5 | * | ||
6 | * Copyright (C) 2010 ST Microelectronics | ||
7 | * Rajeev Kumar <rajeev-dlh.kumar@st.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/clk.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/interrupt.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/designware_i2s.h> | ||
22 | #include <sound/pcm.h> | ||
23 | #include <sound/pcm_params.h> | ||
24 | #include <sound/soc.h> | ||
25 | |||
26 | /* common register for all channel */ | ||
27 | #define IER 0x000 | ||
28 | #define IRER 0x004 | ||
29 | #define ITER 0x008 | ||
30 | #define CER 0x00C | ||
31 | #define CCR 0x010 | ||
32 | #define RXFFR 0x014 | ||
33 | #define TXFFR 0x018 | ||
34 | |||
35 | /* I2STxRxRegisters for all channels */ | ||
36 | #define LRBR_LTHR(x) (0x40 * x + 0x020) | ||
37 | #define RRBR_RTHR(x) (0x40 * x + 0x024) | ||
38 | #define RER(x) (0x40 * x + 0x028) | ||
39 | #define TER(x) (0x40 * x + 0x02C) | ||
40 | #define RCR(x) (0x40 * x + 0x030) | ||
41 | #define TCR(x) (0x40 * x + 0x034) | ||
42 | #define ISR(x) (0x40 * x + 0x038) | ||
43 | #define IMR(x) (0x40 * x + 0x03C) | ||
44 | #define ROR(x) (0x40 * x + 0x040) | ||
45 | #define TOR(x) (0x40 * x + 0x044) | ||
46 | #define RFCR(x) (0x40 * x + 0x048) | ||
47 | #define TFCR(x) (0x40 * x + 0x04C) | ||
48 | #define RFF(x) (0x40 * x + 0x050) | ||
49 | #define TFF(x) (0x40 * x + 0x054) | ||
50 | |||
51 | /* I2SCOMPRegisters */ | ||
52 | #define I2S_COMP_PARAM_2 0x01F0 | ||
53 | #define I2S_COMP_PARAM_1 0x01F4 | ||
54 | #define I2S_COMP_VERSION 0x01F8 | ||
55 | #define I2S_COMP_TYPE 0x01FC | ||
56 | |||
57 | #define MAX_CHANNEL_NUM 8 | ||
58 | #define MIN_CHANNEL_NUM 2 | ||
59 | |||
60 | struct dw_i2s_dev { | ||
61 | void __iomem *i2s_base; | ||
62 | struct clk *clk; | ||
63 | int active; | ||
64 | unsigned int capability; | ||
65 | struct device *dev; | ||
66 | |||
67 | /* data related to DMA transfers b/w i2s and DMAC */ | ||
68 | struct i2s_dma_data play_dma_data; | ||
69 | struct i2s_dma_data capture_dma_data; | ||
70 | struct i2s_clk_config_data config; | ||
71 | int (*i2s_clk_cfg)(struct i2s_clk_config_data *config); | ||
72 | }; | ||
73 | |||
74 | static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val) | ||
75 | { | ||
76 | writel(val, io_base + reg); | ||
77 | } | ||
78 | |||
79 | static inline u32 i2s_read_reg(void __iomem *io_base, int reg) | ||
80 | { | ||
81 | return readl(io_base + reg); | ||
82 | } | ||
83 | |||
84 | static inline void i2s_disable_channels(struct dw_i2s_dev *dev, u32 stream) | ||
85 | { | ||
86 | u32 i = 0; | ||
87 | |||
88 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
89 | for (i = 0; i < 4; i++) | ||
90 | i2s_write_reg(dev->i2s_base, TER(i), 0); | ||
91 | } else { | ||
92 | for (i = 0; i < 4; i++) | ||
93 | i2s_write_reg(dev->i2s_base, RER(i), 0); | ||
94 | } | ||
95 | } | ||
96 | |||
97 | static inline void i2s_clear_irqs(struct dw_i2s_dev *dev, u32 stream) | ||
98 | { | ||
99 | u32 i = 0; | ||
100 | |||
101 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
102 | for (i = 0; i < 4; i++) | ||
103 | i2s_write_reg(dev->i2s_base, TOR(i), 0); | ||
104 | } else { | ||
105 | for (i = 0; i < 4; i++) | ||
106 | i2s_write_reg(dev->i2s_base, ROR(i), 0); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | static void i2s_start(struct dw_i2s_dev *dev, | ||
111 | struct snd_pcm_substream *substream) | ||
112 | { | ||
113 | |||
114 | i2s_write_reg(dev->i2s_base, IER, 1); | ||
115 | |||
116 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
117 | i2s_write_reg(dev->i2s_base, ITER, 1); | ||
118 | else | ||
119 | i2s_write_reg(dev->i2s_base, IRER, 1); | ||
120 | |||
121 | i2s_write_reg(dev->i2s_base, CER, 1); | ||
122 | } | ||
123 | |||
124 | static void i2s_stop(struct dw_i2s_dev *dev, | ||
125 | struct snd_pcm_substream *substream) | ||
126 | { | ||
127 | u32 i = 0, irq; | ||
128 | |||
129 | i2s_clear_irqs(dev, substream->stream); | ||
130 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
131 | i2s_write_reg(dev->i2s_base, ITER, 0); | ||
132 | |||
133 | for (i = 0; i < 4; i++) { | ||
134 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
135 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x30); | ||
136 | } | ||
137 | } else { | ||
138 | i2s_write_reg(dev->i2s_base, IRER, 0); | ||
139 | |||
140 | for (i = 0; i < 4; i++) { | ||
141 | irq = i2s_read_reg(dev->i2s_base, IMR(i)); | ||
142 | i2s_write_reg(dev->i2s_base, IMR(i), irq | 0x03); | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if (!dev->active) { | ||
147 | i2s_write_reg(dev->i2s_base, CER, 0); | ||
148 | i2s_write_reg(dev->i2s_base, IER, 0); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | static int dw_i2s_startup(struct snd_pcm_substream *substream, | ||
153 | struct snd_soc_dai *cpu_dai) | ||
154 | { | ||
155 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); | ||
156 | struct i2s_dma_data *dma_data = NULL; | ||
157 | |||
158 | if (!(dev->capability & DWC_I2S_RECORD) && | ||
159 | (substream->stream == SNDRV_PCM_STREAM_CAPTURE)) | ||
160 | return -EINVAL; | ||
161 | |||
162 | if (!(dev->capability & DWC_I2S_PLAY) && | ||
163 | (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)) | ||
164 | return -EINVAL; | ||
165 | |||
166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
167 | dma_data = &dev->play_dma_data; | ||
168 | else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
169 | dma_data = &dev->capture_dma_data; | ||
170 | |||
171 | snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data); | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int dw_i2s_hw_params(struct snd_pcm_substream *substream, | ||
177 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
178 | { | ||
179 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
180 | struct i2s_clk_config_data *config = &dev->config; | ||
181 | u32 ccr, xfer_resolution, ch_reg, irq; | ||
182 | int ret; | ||
183 | |||
184 | switch (params_format(params)) { | ||
185 | case SNDRV_PCM_FORMAT_S16_LE: | ||
186 | config->data_width = 16; | ||
187 | ccr = 0x00; | ||
188 | xfer_resolution = 0x02; | ||
189 | break; | ||
190 | |||
191 | case SNDRV_PCM_FORMAT_S24_LE: | ||
192 | config->data_width = 24; | ||
193 | ccr = 0x08; | ||
194 | xfer_resolution = 0x04; | ||
195 | break; | ||
196 | |||
197 | case SNDRV_PCM_FORMAT_S32_LE: | ||
198 | config->data_width = 32; | ||
199 | ccr = 0x10; | ||
200 | xfer_resolution = 0x05; | ||
201 | break; | ||
202 | |||
203 | default: | ||
204 | dev_err(dev->dev, "designware-i2s: unsuppted PCM fmt"); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | |||
208 | config->chan_nr = params_channels(params); | ||
209 | |||
210 | switch (config->chan_nr) { | ||
211 | case EIGHT_CHANNEL_SUPPORT: | ||
212 | ch_reg = 3; | ||
213 | case SIX_CHANNEL_SUPPORT: | ||
214 | ch_reg = 2; | ||
215 | case FOUR_CHANNEL_SUPPORT: | ||
216 | ch_reg = 1; | ||
217 | case TWO_CHANNEL_SUPPORT: | ||
218 | ch_reg = 0; | ||
219 | break; | ||
220 | default: | ||
221 | dev_err(dev->dev, "channel not supported\n"); | ||
222 | } | ||
223 | |||
224 | i2s_disable_channels(dev, substream->stream); | ||
225 | |||
226 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
227 | i2s_write_reg(dev->i2s_base, TCR(ch_reg), xfer_resolution); | ||
228 | i2s_write_reg(dev->i2s_base, TFCR(ch_reg), 0x02); | ||
229 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | ||
230 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x30); | ||
231 | i2s_write_reg(dev->i2s_base, TER(ch_reg), 1); | ||
232 | } else { | ||
233 | i2s_write_reg(dev->i2s_base, RCR(ch_reg), xfer_resolution); | ||
234 | i2s_write_reg(dev->i2s_base, RFCR(ch_reg), 0x07); | ||
235 | irq = i2s_read_reg(dev->i2s_base, IMR(ch_reg)); | ||
236 | i2s_write_reg(dev->i2s_base, IMR(ch_reg), irq & ~0x03); | ||
237 | i2s_write_reg(dev->i2s_base, RER(ch_reg), 1); | ||
238 | } | ||
239 | |||
240 | i2s_write_reg(dev->i2s_base, CCR, ccr); | ||
241 | |||
242 | config->sample_rate = params_rate(params); | ||
243 | |||
244 | if (!dev->i2s_clk_cfg) | ||
245 | return -EINVAL; | ||
246 | |||
247 | ret = dev->i2s_clk_cfg(config); | ||
248 | if (ret < 0) { | ||
249 | dev_err(dev->dev, "runtime audio clk config fail\n"); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static void dw_i2s_shutdown(struct snd_pcm_substream *substream, | ||
257 | struct snd_soc_dai *dai) | ||
258 | { | ||
259 | snd_soc_dai_set_dma_data(dai, substream, NULL); | ||
260 | } | ||
261 | |||
262 | static int dw_i2s_trigger(struct snd_pcm_substream *substream, | ||
263 | int cmd, struct snd_soc_dai *dai) | ||
264 | { | ||
265 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
266 | int ret = 0; | ||
267 | |||
268 | switch (cmd) { | ||
269 | case SNDRV_PCM_TRIGGER_START: | ||
270 | case SNDRV_PCM_TRIGGER_RESUME: | ||
271 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
272 | dev->active++; | ||
273 | i2s_start(dev, substream); | ||
274 | break; | ||
275 | |||
276 | case SNDRV_PCM_TRIGGER_STOP: | ||
277 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
278 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
279 | dev->active--; | ||
280 | i2s_stop(dev, substream); | ||
281 | break; | ||
282 | default: | ||
283 | ret = -EINVAL; | ||
284 | break; | ||
285 | } | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | static struct snd_soc_dai_ops dw_i2s_dai_ops = { | ||
290 | .startup = dw_i2s_startup, | ||
291 | .shutdown = dw_i2s_shutdown, | ||
292 | .hw_params = dw_i2s_hw_params, | ||
293 | .trigger = dw_i2s_trigger, | ||
294 | }; | ||
295 | |||
296 | #ifdef CONFIG_PM | ||
297 | |||
298 | static int dw_i2s_suspend(struct snd_soc_dai *dai) | ||
299 | { | ||
300 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
301 | |||
302 | clk_disable(dev->clk); | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int dw_i2s_resume(struct snd_soc_dai *dai) | ||
307 | { | ||
308 | struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai); | ||
309 | |||
310 | clk_enable(dev->clk); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | #else | ||
315 | #define dw_i2s_suspend NULL | ||
316 | #define dw_i2s_resume NULL | ||
317 | #endif | ||
318 | |||
319 | static int dw_i2s_probe(struct platform_device *pdev) | ||
320 | { | ||
321 | const struct i2s_platform_data *pdata = pdev->dev.platform_data; | ||
322 | struct dw_i2s_dev *dev; | ||
323 | struct resource *res; | ||
324 | int ret; | ||
325 | unsigned int cap; | ||
326 | struct snd_soc_dai_driver *dw_i2s_dai; | ||
327 | |||
328 | if (!pdata) { | ||
329 | dev_err(&pdev->dev, "Invalid platform data\n"); | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | |||
333 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
334 | if (!res) { | ||
335 | dev_err(&pdev->dev, "no i2s resource defined\n"); | ||
336 | return -ENODEV; | ||
337 | } | ||
338 | |||
339 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
340 | resource_size(res), pdev->name)) { | ||
341 | dev_err(&pdev->dev, "i2s region already claimed\n"); | ||
342 | return -EBUSY; | ||
343 | } | ||
344 | |||
345 | dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); | ||
346 | if (!dev) { | ||
347 | dev_warn(&pdev->dev, "kzalloc fail\n"); | ||
348 | return -ENOMEM; | ||
349 | } | ||
350 | |||
351 | dev->i2s_base = devm_ioremap(&pdev->dev, res->start, | ||
352 | resource_size(res)); | ||
353 | if (!dev->i2s_base) { | ||
354 | dev_err(&pdev->dev, "ioremap fail for i2s_region\n"); | ||
355 | return -ENOMEM; | ||
356 | } | ||
357 | |||
358 | cap = pdata->cap; | ||
359 | dev->capability = cap; | ||
360 | dev->i2s_clk_cfg = pdata->i2s_clk_cfg; | ||
361 | |||
362 | /* Set DMA slaves info */ | ||
363 | |||
364 | dev->play_dma_data.data = pdata->play_dma_data; | ||
365 | dev->capture_dma_data.data = pdata->capture_dma_data; | ||
366 | dev->play_dma_data.addr = res->start + I2S_TXDMA; | ||
367 | dev->capture_dma_data.addr = res->start + I2S_RXDMA; | ||
368 | dev->play_dma_data.max_burst = 16; | ||
369 | dev->capture_dma_data.max_burst = 16; | ||
370 | dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
371 | dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; | ||
372 | dev->play_dma_data.filter = pdata->filter; | ||
373 | dev->capture_dma_data.filter = pdata->filter; | ||
374 | |||
375 | dev->clk = clk_get(&pdev->dev, NULL); | ||
376 | if (IS_ERR(dev->clk)) | ||
377 | return PTR_ERR(dev->clk); | ||
378 | |||
379 | ret = clk_enable(dev->clk); | ||
380 | if (ret < 0) | ||
381 | goto err_clk_put; | ||
382 | |||
383 | dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL); | ||
384 | if (!dw_i2s_dai) { | ||
385 | dev_err(&pdev->dev, "mem allocation failed for dai driver\n"); | ||
386 | ret = -ENOMEM; | ||
387 | goto err_clk_disable; | ||
388 | } | ||
389 | |||
390 | if (cap & DWC_I2S_PLAY) { | ||
391 | dev_dbg(&pdev->dev, " SPEAr: play supported\n"); | ||
392 | dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM; | ||
393 | dw_i2s_dai->playback.channels_max = pdata->channel; | ||
394 | dw_i2s_dai->playback.formats = pdata->snd_fmts; | ||
395 | dw_i2s_dai->playback.rates = pdata->snd_rates; | ||
396 | } | ||
397 | |||
398 | if (cap & DWC_I2S_RECORD) { | ||
399 | dev_dbg(&pdev->dev, "SPEAr: record supported\n"); | ||
400 | dw_i2s_dai->capture.channels_min = MIN_CHANNEL_NUM; | ||
401 | dw_i2s_dai->capture.channels_max = pdata->channel; | ||
402 | dw_i2s_dai->capture.formats = pdata->snd_fmts; | ||
403 | dw_i2s_dai->capture.rates = pdata->snd_rates; | ||
404 | } | ||
405 | |||
406 | dw_i2s_dai->ops = &dw_i2s_dai_ops; | ||
407 | dw_i2s_dai->suspend = dw_i2s_suspend; | ||
408 | dw_i2s_dai->resume = dw_i2s_resume; | ||
409 | |||
410 | dev->dev = &pdev->dev; | ||
411 | dev_set_drvdata(&pdev->dev, dev); | ||
412 | ret = snd_soc_register_dai(&pdev->dev, dw_i2s_dai); | ||
413 | if (ret != 0) { | ||
414 | dev_err(&pdev->dev, "not able to register dai\n"); | ||
415 | goto err_set_drvdata; | ||
416 | } | ||
417 | |||
418 | return 0; | ||
419 | |||
420 | err_set_drvdata: | ||
421 | dev_set_drvdata(&pdev->dev, NULL); | ||
422 | err_clk_disable: | ||
423 | clk_disable(dev->clk); | ||
424 | err_clk_put: | ||
425 | clk_put(dev->clk); | ||
426 | return ret; | ||
427 | } | ||
428 | |||
429 | static int dw_i2s_remove(struct platform_device *pdev) | ||
430 | { | ||
431 | struct dw_i2s_dev *dev = dev_get_drvdata(&pdev->dev); | ||
432 | |||
433 | snd_soc_unregister_dai(&pdev->dev); | ||
434 | dev_set_drvdata(&pdev->dev, NULL); | ||
435 | |||
436 | clk_put(dev->clk); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static struct platform_driver dw_i2s_driver = { | ||
442 | .probe = dw_i2s_probe, | ||
443 | .remove = dw_i2s_remove, | ||
444 | .driver = { | ||
445 | .name = "designware-i2s", | ||
446 | .owner = THIS_MODULE, | ||
447 | }, | ||
448 | }; | ||
449 | |||
450 | module_platform_driver(dw_i2s_driver); | ||
451 | |||
452 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | ||
453 | MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); | ||
454 | MODULE_LICENSE("GPL"); | ||
455 | MODULE_ALIAS("platform:designware_i2s"); | ||
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c index 162dbb74f4cc..4eea98b42bc8 100644 --- a/sound/soc/ep93xx/ep93xx-pcm.c +++ b/sound/soc/ep93xx/ep93xx-pcm.c | |||
@@ -136,7 +136,7 @@ static struct snd_pcm_ops ep93xx_pcm_ops = { | |||
136 | .hw_params = ep93xx_pcm_hw_params, | 136 | .hw_params = ep93xx_pcm_hw_params, |
137 | .hw_free = ep93xx_pcm_hw_free, | 137 | .hw_free = ep93xx_pcm_hw_free, |
138 | .trigger = snd_dmaengine_pcm_trigger, | 138 | .trigger = snd_dmaengine_pcm_trigger, |
139 | .pointer = snd_dmaengine_pcm_pointer, | 139 | .pointer = snd_dmaengine_pcm_pointer_no_residue, |
140 | .mmap = ep93xx_pcm_mmap, | 140 | .mmap = ep93xx_pcm_mmap, |
141 | }; | 141 | }; |
142 | 142 | ||
diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index 080327414c6b..e7c800ebbd75 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c | |||
@@ -156,7 +156,7 @@ static void __init audmux_debugfs_init(void) | |||
156 | return; | 156 | return; |
157 | } | 157 | } |
158 | 158 | ||
159 | for (i = 0; i < MX31_AUDMUX_PORT6_SSI_PINS_6 + 1; i++) { | 159 | for (i = 0; i < MX31_AUDMUX_PORT7_SSI_PINS_7 + 1; i++) { |
160 | snprintf(buf, sizeof(buf), "ssi%d", i); | 160 | snprintf(buf, sizeof(buf), "ssi%d", i); |
161 | if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, | 161 | if (!debugfs_create_file(buf, 0444, audmux_debugfs_root, |
162 | (void *)i, &audmux_debugfs_fops)) | 162 | (void *)i, &audmux_debugfs_fops)) |
diff --git a/sound/soc/fsl/imx-audmux.h b/sound/soc/fsl/imx-audmux.h index 04ebbab8d7b9..b8ff44b9dafa 100644 --- a/sound/soc/fsl/imx-audmux.h +++ b/sound/soc/fsl/imx-audmux.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #define MX31_AUDMUX_PORT4_SSI_PINS_4 3 | 14 | #define MX31_AUDMUX_PORT4_SSI_PINS_4 3 |
15 | #define MX31_AUDMUX_PORT5_SSI_PINS_5 4 | 15 | #define MX31_AUDMUX_PORT5_SSI_PINS_5 4 |
16 | #define MX31_AUDMUX_PORT6_SSI_PINS_6 5 | 16 | #define MX31_AUDMUX_PORT6_SSI_PINS_6 5 |
17 | #define MX31_AUDMUX_PORT7_SSI_PINS_7 6 | ||
17 | 18 | ||
18 | #define MX51_AUDMUX_PORT1_SSI0 0 | 19 | #define MX51_AUDMUX_PORT1_SSI0 0 |
19 | #define MX51_AUDMUX_PORT2_SSI1 1 | 20 | #define MX51_AUDMUX_PORT2_SSI1 1 |
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index f59c34943662..549b31fdc9dd 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c | |||
@@ -111,22 +111,39 @@ static int __devinit imx_mc13783_probe(struct platform_device *pdev) | |||
111 | return ret; | 111 | return ret; |
112 | } | 112 | } |
113 | 113 | ||
114 | imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4, | 114 | if (machine_is_mx31_3ds()) { |
115 | IMX_AUDMUX_V2_PTCR_SYN, | 115 | imx_audmux_v2_configure_port(MX31_AUDMUX_PORT4_SSI_PINS_4, |
116 | IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) | | 116 | IMX_AUDMUX_V2_PTCR_SYN, |
117 | IMX_AUDMUX_V2_PDCR_MODE(1) | | 117 | IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT1_SSI0) | |
118 | IMX_AUDMUX_V2_PDCR_INMMASK(0xfc)); | 118 | IMX_AUDMUX_V2_PDCR_MODE(1) | |
119 | imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, | 119 | IMX_AUDMUX_V2_PDCR_INMMASK(0xfc)); |
120 | IMX_AUDMUX_V2_PTCR_SYN | | 120 | imx_audmux_v2_configure_port(MX31_AUDMUX_PORT1_SSI0, |
121 | IMX_AUDMUX_V2_PTCR_TFSDIR | | 121 | IMX_AUDMUX_V2_PTCR_SYN | |
122 | IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | | 122 | IMX_AUDMUX_V2_PTCR_TFSDIR | |
123 | IMX_AUDMUX_V2_PTCR_TCLKDIR | | 123 | IMX_AUDMUX_V2_PTCR_TFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | |
124 | IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | | 124 | IMX_AUDMUX_V2_PTCR_TCLKDIR | |
125 | IMX_AUDMUX_V2_PTCR_RFSDIR | | 125 | IMX_AUDMUX_V2_PTCR_TCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | |
126 | IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | | 126 | IMX_AUDMUX_V2_PTCR_RFSDIR | |
127 | IMX_AUDMUX_V2_PTCR_RCLKDIR | | 127 | IMX_AUDMUX_V2_PTCR_RFSEL(MX31_AUDMUX_PORT4_SSI_PINS_4) | |
128 | IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4), | 128 | IMX_AUDMUX_V2_PTCR_RCLKDIR | |
129 | IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4)); | 129 | IMX_AUDMUX_V2_PTCR_RCSEL(MX31_AUDMUX_PORT4_SSI_PINS_4), |
130 | IMX_AUDMUX_V2_PDCR_RXDSEL(MX31_AUDMUX_PORT4_SSI_PINS_4)); | ||
131 | } else if (machine_is_mx27_3ds()) { | ||
132 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, | ||
133 | IMX_AUDMUX_V1_PCR_SYN | | ||
134 | IMX_AUDMUX_V1_PCR_TFSDIR | | ||
135 | IMX_AUDMUX_V1_PCR_TCLKDIR | | ||
136 | IMX_AUDMUX_V1_PCR_RFSDIR | | ||
137 | IMX_AUDMUX_V1_PCR_RCLKDIR | | ||
138 | IMX_AUDMUX_V1_PCR_TFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | | ||
139 | IMX_AUDMUX_V1_PCR_RFCSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | | ||
140 | IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR3_SSI_PINS_4) | ||
141 | ); | ||
142 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR3_SSI_PINS_4, | ||
143 | IMX_AUDMUX_V1_PCR_SYN | | ||
144 | IMX_AUDMUX_V1_PCR_RXDSEL(MX27_AUDMUX_HPCR1_SSI0) | ||
145 | ); | ||
146 | } | ||
130 | 147 | ||
131 | return ret; | 148 | return ret; |
132 | } | 149 | } |
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index f3c0a5ef35c8..48f9d886f020 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c | |||
@@ -141,7 +141,7 @@ static struct snd_pcm_ops imx_pcm_ops = { | |||
141 | .ioctl = snd_pcm_lib_ioctl, | 141 | .ioctl = snd_pcm_lib_ioctl, |
142 | .hw_params = snd_imx_pcm_hw_params, | 142 | .hw_params = snd_imx_pcm_hw_params, |
143 | .trigger = snd_dmaengine_pcm_trigger, | 143 | .trigger = snd_dmaengine_pcm_trigger, |
144 | .pointer = snd_dmaengine_pcm_pointer, | 144 | .pointer = snd_dmaengine_pcm_pointer_no_residue, |
145 | .mmap = snd_imx_pcm_mmap, | 145 | .mmap = snd_imx_pcm_mmap, |
146 | }; | 146 | }; |
147 | 147 | ||
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index 3a729caeb8c8..fb21b17f17f5 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c | |||
@@ -95,8 +95,7 @@ static int __devinit imx_sgtl5000_probe(struct platform_device *pdev) | |||
95 | return ret; | 95 | return ret; |
96 | } | 96 | } |
97 | imx_audmux_v2_configure_port(ext_port, | 97 | imx_audmux_v2_configure_port(ext_port, |
98 | IMX_AUDMUX_V2_PTCR_SYN | | 98 | IMX_AUDMUX_V2_PTCR_SYN, |
99 | IMX_AUDMUX_V2_PTCR_TCSEL(int_port), | ||
100 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); | 99 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); |
101 | if (ret) { | 100 | if (ret) { |
102 | dev_err(&pdev->dev, "audmux external port setup failed\n"); | 101 | dev_err(&pdev->dev, "audmux external port setup failed\n"); |
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c index 373dec90579f..f82d766cbf9e 100644 --- a/sound/soc/mxs/mxs-pcm.c +++ b/sound/soc/mxs/mxs-pcm.c | |||
@@ -141,7 +141,7 @@ static struct snd_pcm_ops mxs_pcm_ops = { | |||
141 | .ioctl = snd_pcm_lib_ioctl, | 141 | .ioctl = snd_pcm_lib_ioctl, |
142 | .hw_params = snd_mxs_pcm_hw_params, | 142 | .hw_params = snd_mxs_pcm_hw_params, |
143 | .trigger = snd_dmaengine_pcm_trigger, | 143 | .trigger = snd_dmaengine_pcm_trigger, |
144 | .pointer = snd_dmaengine_pcm_pointer, | 144 | .pointer = snd_dmaengine_pcm_pointer_no_residue, |
145 | .mmap = snd_mxs_pcm_mmap, | 145 | .mmap = snd_mxs_pcm_mmap, |
146 | }; | 146 | }; |
147 | 147 | ||
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index 3e6e8764b2e6..215113b05f7d 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c | |||
@@ -133,7 +133,7 @@ static int __devinit mxs_sgtl5000_probe_dt(struct platform_device *pdev) | |||
133 | mxs_sgtl5000_dai[i].codec_name = NULL; | 133 | mxs_sgtl5000_dai[i].codec_name = NULL; |
134 | mxs_sgtl5000_dai[i].codec_of_node = codec_np; | 134 | mxs_sgtl5000_dai[i].codec_of_node = codec_np; |
135 | mxs_sgtl5000_dai[i].cpu_dai_name = NULL; | 135 | mxs_sgtl5000_dai[i].cpu_dai_name = NULL; |
136 | mxs_sgtl5000_dai[i].cpu_dai_of_node = saif_np[i]; | 136 | mxs_sgtl5000_dai[i].cpu_of_node = saif_np[i]; |
137 | mxs_sgtl5000_dai[i].platform_name = NULL; | 137 | mxs_sgtl5000_dai[i].platform_name = NULL; |
138 | mxs_sgtl5000_dai[i].platform_of_node = saif_np[i]; | 138 | mxs_sgtl5000_dai[i].platform_of_node = saif_np[i]; |
139 | } | 139 | } |
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig index a0f7d3cfa470..4d2e46fae77c 100644 --- a/sound/soc/pxa/Kconfig +++ b/sound/soc/pxa/Kconfig | |||
@@ -8,6 +8,15 @@ config SND_PXA2XX_SOC | |||
8 | the PXA2xx AC97, I2S or SSP interface. You will also need | 8 | the PXA2xx AC97, I2S or SSP interface. You will also need |
9 | to select the audio interfaces to support below. | 9 | to select the audio interfaces to support below. |
10 | 10 | ||
11 | config SND_MMP_SOC | ||
12 | bool "Soc Audio for Marvell MMP chips" | ||
13 | depends on ARCH_MMP | ||
14 | select SND_SOC_DMAENGINE_PCM | ||
15 | select SND_ARM | ||
16 | help | ||
17 | Say Y if you want to add support for codecs attached to | ||
18 | the MMP SSPA interface. | ||
19 | |||
11 | config SND_PXA2XX_AC97 | 20 | config SND_PXA2XX_AC97 |
12 | tristate | 21 | tristate |
13 | select SND_AC97_CODEC | 22 | select SND_AC97_CODEC |
@@ -26,6 +35,9 @@ config SND_PXA_SOC_SSP | |||
26 | tristate | 35 | tristate |
27 | select PXA_SSP | 36 | select PXA_SSP |
28 | 37 | ||
38 | config SND_MMP_SOC_SSPA | ||
39 | tristate | ||
40 | |||
29 | config SND_PXA2XX_SOC_CORGI | 41 | config SND_PXA2XX_SOC_CORGI |
30 | tristate "SoC Audio support for Sharp Zaurus SL-C7x0" | 42 | tristate "SoC Audio support for Sharp Zaurus SL-C7x0" |
31 | depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx | 43 | depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx |
@@ -138,6 +150,26 @@ config SND_SOC_TAVOREVB3 | |||
138 | Say Y if you want to add support for SoC audio on the | 150 | Say Y if you want to add support for SoC audio on the |
139 | Marvell Saarb reference platform. | 151 | Marvell Saarb reference platform. |
140 | 152 | ||
153 | config SND_PXA910_SOC | ||
154 | tristate "SoC Audio for Marvell PXA910 chip" | ||
155 | depends on ARCH_MMP && SND | ||
156 | select SND_PCM | ||
157 | help | ||
158 | Say Y if you want to add support for SoC audio on the | ||
159 | Marvell PXA910 reference platform. | ||
160 | |||
161 | config SND_SOC_TTC_DKB | ||
162 | bool "SoC Audio support for TTC DKB" | ||
163 | depends on SND_PXA910_SOC && MACH_TTC_DKB | ||
164 | select PXA_SSP | ||
165 | select SND_PXA_SOC_SSP | ||
166 | select SND_MMP_SOC | ||
167 | select MFD_88PM860X | ||
168 | select SND_SOC_88PM860X | ||
169 | help | ||
170 | Say Y if you want to add support for SoC audio on TTC DKB | ||
171 | |||
172 | |||
141 | config SND_SOC_ZYLONITE | 173 | config SND_SOC_ZYLONITE |
142 | tristate "SoC Audio support for Marvell Zylonite" | 174 | tristate "SoC Audio support for Marvell Zylonite" |
143 | depends on SND_PXA2XX_SOC && MACH_ZYLONITE | 175 | depends on SND_PXA2XX_SOC && MACH_ZYLONITE |
@@ -194,3 +226,13 @@ config SND_PXA2XX_SOC_IMOTE2 | |||
194 | help | 226 | help |
195 | Say Y if you want to add support for SoC audio on the | 227 | Say Y if you want to add support for SoC audio on the |
196 | IMote 2. | 228 | IMote 2. |
229 | |||
230 | config SND_MMP_SOC_BROWNSTONE | ||
231 | tristate "SoC Audio support for Marvell Brownstone" | ||
232 | depends on SND_MMP_SOC && MACH_BROWNSTONE | ||
233 | select SND_MMP_SOC_SSPA | ||
234 | select MFD_WM8994 | ||
235 | select SND_SOC_WM8994 | ||
236 | help | ||
237 | Say Y if you want to add support for SoC audio on the | ||
238 | Marvell Brownstone reference platform. | ||
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile index af357623be9d..d8a265d2d5d7 100644 --- a/sound/soc/pxa/Makefile +++ b/sound/soc/pxa/Makefile | |||
@@ -3,11 +3,15 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o | |||
3 | snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o | 3 | snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o |
4 | snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o | 4 | snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o |
5 | snd-soc-pxa-ssp-objs := pxa-ssp.o | 5 | snd-soc-pxa-ssp-objs := pxa-ssp.o |
6 | snd-soc-mmp-objs := mmp-pcm.o | ||
7 | snd-soc-mmp-sspa-objs := mmp-sspa.o | ||
6 | 8 | ||
7 | obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o | 9 | obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o |
8 | obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o | 10 | obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o |
9 | obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o | 11 | obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o |
10 | obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o | 12 | obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o |
13 | obj-$(CONFIG_SND_MMP_SOC) += snd-soc-mmp.o | ||
14 | obj-$(CONFIG_SND_MMP_SOC_SSPA) += snd-soc-mmp-sspa.o | ||
11 | 15 | ||
12 | # PXA Machine Support | 16 | # PXA Machine Support |
13 | snd-soc-corgi-objs := corgi.o | 17 | snd-soc-corgi-objs := corgi.o |
@@ -28,6 +32,8 @@ snd-soc-mioa701-objs := mioa701_wm9713.o | |||
28 | snd-soc-z2-objs := z2.o | 32 | snd-soc-z2-objs := z2.o |
29 | snd-soc-imote2-objs := imote2.o | 33 | snd-soc-imote2-objs := imote2.o |
30 | snd-soc-raumfeld-objs := raumfeld.o | 34 | snd-soc-raumfeld-objs := raumfeld.o |
35 | snd-soc-brownstone-objs := brownstone.o | ||
36 | snd-soc-ttc-dkb-objs := ttc-dkb.o | ||
31 | 37 | ||
32 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o | 38 | obj-$(CONFIG_SND_PXA2XX_SOC_CORGI) += snd-soc-corgi.o |
33 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o | 39 | obj-$(CONFIG_SND_PXA2XX_SOC_POODLE) += snd-soc-poodle.o |
@@ -47,3 +53,5 @@ obj-$(CONFIG_SND_SOC_TAVOREVB3) += snd-soc-tavorevb3.o | |||
47 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o | 53 | obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o |
48 | obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o | 54 | obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o |
49 | obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o | 55 | obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o |
56 | obj-$(CONFIG_SND_MMP_SOC_BROWNSTONE) += snd-soc-brownstone.o | ||
57 | obj-$(CONFIG_SND_SOC_TTC_DKB) += snd-soc-ttc-dkb.o | ||
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c new file mode 100644 index 000000000000..5e666e03d333 --- /dev/null +++ b/sound/soc/pxa/brownstone.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/pxa/brownstone.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Marvell International Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <sound/jack.h> | ||
18 | |||
19 | #include "../codecs/wm8994.h" | ||
20 | #include "mmp-sspa.h" | ||
21 | |||
22 | static const struct snd_kcontrol_new brownstone_dapm_control[] = { | ||
23 | SOC_DAPM_PIN_SWITCH("Ext Spk"), | ||
24 | }; | ||
25 | |||
26 | static const struct snd_soc_dapm_widget brownstone_dapm_widgets[] = { | ||
27 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
28 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | ||
29 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
30 | SND_SOC_DAPM_MIC("Main Mic", NULL), | ||
31 | }; | ||
32 | |||
33 | static const struct snd_soc_dapm_route brownstone_audio_map[] = { | ||
34 | {"Ext Spk", NULL, "SPKOUTLP"}, | ||
35 | {"Ext Spk", NULL, "SPKOUTLN"}, | ||
36 | {"Ext Spk", NULL, "SPKOUTRP"}, | ||
37 | {"Ext Spk", NULL, "SPKOUTRN"}, | ||
38 | |||
39 | {"Headset Stereophone", NULL, "HPOUT1L"}, | ||
40 | {"Headset Stereophone", NULL, "HPOUT1R"}, | ||
41 | |||
42 | {"IN1RN", NULL, "Headset Mic"}, | ||
43 | |||
44 | {"DMIC1DAT", NULL, "MICBIAS1"}, | ||
45 | {"MICBIAS1", NULL, "Main Mic"}, | ||
46 | }; | ||
47 | |||
48 | static int brownstone_wm8994_init(struct snd_soc_pcm_runtime *rtd) | ||
49 | { | ||
50 | struct snd_soc_codec *codec = rtd->codec; | ||
51 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
52 | |||
53 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | ||
54 | snd_soc_dapm_enable_pin(dapm, "Headset Stereophone"); | ||
55 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | ||
56 | snd_soc_dapm_enable_pin(dapm, "Main Mic"); | ||
57 | |||
58 | /* set endpoints to not connected */ | ||
59 | snd_soc_dapm_nc_pin(dapm, "HPOUT2P"); | ||
60 | snd_soc_dapm_nc_pin(dapm, "HPOUT2N"); | ||
61 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1N"); | ||
62 | snd_soc_dapm_nc_pin(dapm, "LINEOUT1P"); | ||
63 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2N"); | ||
64 | snd_soc_dapm_nc_pin(dapm, "LINEOUT2P"); | ||
65 | snd_soc_dapm_nc_pin(dapm, "IN1LN"); | ||
66 | snd_soc_dapm_nc_pin(dapm, "IN1LP"); | ||
67 | snd_soc_dapm_nc_pin(dapm, "IN1RP"); | ||
68 | snd_soc_dapm_nc_pin(dapm, "IN2LP:VXRN"); | ||
69 | snd_soc_dapm_nc_pin(dapm, "IN2RN"); | ||
70 | snd_soc_dapm_nc_pin(dapm, "IN2RP:VXRP"); | ||
71 | snd_soc_dapm_nc_pin(dapm, "IN2LN"); | ||
72 | |||
73 | snd_soc_dapm_sync(dapm); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, | ||
79 | struct snd_pcm_hw_params *params) | ||
80 | { | ||
81 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
82 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
83 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
84 | int freq_out, sspa_mclk, sysclk; | ||
85 | int sspa_div; | ||
86 | |||
87 | if (params_rate(params) > 11025) { | ||
88 | freq_out = params_rate(params) * 512; | ||
89 | sysclk = params_rate(params) * 256; | ||
90 | sspa_mclk = params_rate(params) * 64; | ||
91 | } else { | ||
92 | freq_out = params_rate(params) * 1024; | ||
93 | sysclk = params_rate(params) * 512; | ||
94 | sspa_mclk = params_rate(params) * 64; | ||
95 | } | ||
96 | sspa_div = freq_out; | ||
97 | do_div(sspa_div, sspa_mclk); | ||
98 | |||
99 | snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); | ||
100 | snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); | ||
101 | snd_soc_dai_set_pll(cpu_dai, MMP_SSPA_CLK, 0, freq_out, sspa_mclk); | ||
102 | |||
103 | /* set wm8994 sysclk */ | ||
104 | snd_soc_dai_set_sysclk(codec_dai, WM8994_SYSCLK_MCLK1, sysclk, 0); | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* machine stream operations */ | ||
110 | static struct snd_soc_ops brownstone_ops = { | ||
111 | .hw_params = brownstone_wm8994_hw_params, | ||
112 | }; | ||
113 | |||
114 | static struct snd_soc_dai_link brownstone_wm8994_dai[] = { | ||
115 | { | ||
116 | .name = "WM8994", | ||
117 | .stream_name = "WM8994 HiFi", | ||
118 | .cpu_dai_name = "mmp-sspa-dai.0", | ||
119 | .codec_dai_name = "wm8994-aif1", | ||
120 | .platform_name = "mmp-pcm-audio", | ||
121 | .codec_name = "wm8994-codec", | ||
122 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
123 | SND_SOC_DAIFMT_CBS_CFS, | ||
124 | .ops = &brownstone_ops, | ||
125 | .init = brownstone_wm8994_init, | ||
126 | }, | ||
127 | }; | ||
128 | |||
129 | /* audio machine driver */ | ||
130 | static struct snd_soc_card brownstone = { | ||
131 | .name = "brownstone", | ||
132 | .dai_link = brownstone_wm8994_dai, | ||
133 | .num_links = ARRAY_SIZE(brownstone_wm8994_dai), | ||
134 | |||
135 | .controls = brownstone_dapm_control, | ||
136 | .num_controls = ARRAY_SIZE(brownstone_dapm_control), | ||
137 | .dapm_widgets = brownstone_dapm_widgets, | ||
138 | .num_dapm_widgets = ARRAY_SIZE(brownstone_dapm_widgets), | ||
139 | .dapm_routes = brownstone_audio_map, | ||
140 | .num_dapm_routes = ARRAY_SIZE(brownstone_audio_map), | ||
141 | }; | ||
142 | |||
143 | static int __devinit brownstone_probe(struct platform_device *pdev) | ||
144 | { | ||
145 | int ret; | ||
146 | |||
147 | brownstone.dev = &pdev->dev; | ||
148 | ret = snd_soc_register_card(&brownstone); | ||
149 | if (ret) | ||
150 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
151 | ret); | ||
152 | return ret; | ||
153 | } | ||
154 | |||
155 | static int __devexit brownstone_remove(struct platform_device *pdev) | ||
156 | { | ||
157 | snd_soc_unregister_card(&brownstone); | ||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static struct platform_driver mmp_driver = { | ||
162 | .driver = { | ||
163 | .name = "brownstone-audio", | ||
164 | .owner = THIS_MODULE, | ||
165 | }, | ||
166 | .probe = brownstone_probe, | ||
167 | .remove = __devexit_p(brownstone_remove), | ||
168 | }; | ||
169 | |||
170 | module_platform_driver(mmp_driver); | ||
171 | |||
172 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | ||
173 | MODULE_DESCRIPTION("ALSA SoC Brownstone"); | ||
174 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c new file mode 100644 index 000000000000..73ac5463c9e4 --- /dev/null +++ b/sound/soc/pxa/mmp-pcm.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/pxa/mmp-pcm.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Marvell International Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | */ | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/dmaengine.h> | ||
18 | #include <linux/platform_data/mmp_audio.h> | ||
19 | #include <sound/pxa2xx-lib.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <mach/sram.h> | ||
25 | #include <sound/dmaengine_pcm.h> | ||
26 | |||
27 | struct mmp_dma_data { | ||
28 | int ssp_id; | ||
29 | struct resource *dma_res; | ||
30 | }; | ||
31 | |||
32 | #define MMP_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ | ||
33 | SNDRV_PCM_INFO_MMAP_VALID | \ | ||
34 | SNDRV_PCM_INFO_INTERLEAVED | \ | ||
35 | SNDRV_PCM_INFO_PAUSE | \ | ||
36 | SNDRV_PCM_INFO_RESUME) | ||
37 | |||
38 | #define MMP_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
39 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
40 | SNDRV_PCM_FMTBIT_S32_LE) | ||
41 | |||
42 | static struct snd_pcm_hardware mmp_pcm_hardware[] = { | ||
43 | { | ||
44 | .info = MMP_PCM_INFO, | ||
45 | .formats = MMP_PCM_FORMATS, | ||
46 | .period_bytes_min = 1024, | ||
47 | .period_bytes_max = 2048, | ||
48 | .periods_min = 2, | ||
49 | .periods_max = 32, | ||
50 | .buffer_bytes_max = 4096, | ||
51 | .fifo_size = 32, | ||
52 | }, | ||
53 | { | ||
54 | .info = MMP_PCM_INFO, | ||
55 | .formats = MMP_PCM_FORMATS, | ||
56 | .period_bytes_min = 1024, | ||
57 | .period_bytes_max = 2048, | ||
58 | .periods_min = 2, | ||
59 | .periods_max = 32, | ||
60 | .buffer_bytes_max = 4096, | ||
61 | .fifo_size = 32, | ||
62 | }, | ||
63 | }; | ||
64 | |||
65 | static int mmp_pcm_hw_params(struct snd_pcm_substream *substream, | ||
66 | struct snd_pcm_hw_params *params) | ||
67 | { | ||
68 | struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); | ||
69 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
70 | struct pxa2xx_pcm_dma_params *dma_params; | ||
71 | struct dma_slave_config slave_config; | ||
72 | int ret; | ||
73 | |||
74 | dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
75 | if (!dma_params) | ||
76 | return 0; | ||
77 | |||
78 | ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config); | ||
79 | if (ret) | ||
80 | return ret; | ||
81 | |||
82 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
83 | slave_config.dst_addr = dma_params->dev_addr; | ||
84 | slave_config.dst_maxburst = 4; | ||
85 | } else { | ||
86 | slave_config.src_addr = dma_params->dev_addr; | ||
87 | slave_config.src_maxburst = 4; | ||
88 | } | ||
89 | |||
90 | ret = dmaengine_slave_config(chan, &slave_config); | ||
91 | if (ret) | ||
92 | return ret; | ||
93 | |||
94 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static bool filter(struct dma_chan *chan, void *param) | ||
100 | { | ||
101 | struct mmp_dma_data *dma_data = param; | ||
102 | bool found = false; | ||
103 | char *devname; | ||
104 | |||
105 | devname = kasprintf(GFP_KERNEL, "%s.%d", dma_data->dma_res->name, | ||
106 | dma_data->ssp_id); | ||
107 | if ((strcmp(dev_name(chan->device->dev), devname) == 0) && | ||
108 | (chan->chan_id == dma_data->dma_res->start)) { | ||
109 | found = true; | ||
110 | } | ||
111 | |||
112 | kfree(devname); | ||
113 | return found; | ||
114 | } | ||
115 | |||
116 | static int mmp_pcm_open(struct snd_pcm_substream *substream) | ||
117 | { | ||
118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
119 | struct platform_device *pdev = to_platform_device(rtd->platform->dev); | ||
120 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
121 | struct mmp_dma_data *dma_data; | ||
122 | struct resource *r; | ||
123 | int ret; | ||
124 | |||
125 | r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream); | ||
126 | if (!r) | ||
127 | return -EBUSY; | ||
128 | |||
129 | snd_soc_set_runtime_hwparams(substream, | ||
130 | &mmp_pcm_hardware[substream->stream]); | ||
131 | dma_data = devm_kzalloc(&pdev->dev, | ||
132 | sizeof(struct mmp_dma_data), GFP_KERNEL); | ||
133 | if (dma_data == NULL) | ||
134 | return -ENOMEM; | ||
135 | |||
136 | dma_data->dma_res = r; | ||
137 | dma_data->ssp_id = cpu_dai->id; | ||
138 | |||
139 | ret = snd_dmaengine_pcm_open(substream, filter, dma_data); | ||
140 | if (ret) { | ||
141 | devm_kfree(&pdev->dev, dma_data); | ||
142 | return ret; | ||
143 | } | ||
144 | |||
145 | snd_dmaengine_pcm_set_data(substream, dma_data); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int mmp_pcm_close(struct snd_pcm_substream *substream) | ||
150 | { | ||
151 | struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); | ||
152 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
153 | struct platform_device *pdev = to_platform_device(rtd->platform->dev); | ||
154 | |||
155 | snd_dmaengine_pcm_close(substream); | ||
156 | devm_kfree(&pdev->dev, dma_data); | ||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int mmp_pcm_mmap(struct snd_pcm_substream *substream, | ||
161 | struct vm_area_struct *vma) | ||
162 | { | ||
163 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
164 | unsigned long off = vma->vm_pgoff; | ||
165 | |||
166 | vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); | ||
167 | return remap_pfn_range(vma, vma->vm_start, | ||
168 | __phys_to_pfn(runtime->dma_addr) + off, | ||
169 | vma->vm_end - vma->vm_start, vma->vm_page_prot); | ||
170 | } | ||
171 | |||
172 | struct snd_pcm_ops mmp_pcm_ops = { | ||
173 | .open = mmp_pcm_open, | ||
174 | .close = mmp_pcm_close, | ||
175 | .ioctl = snd_pcm_lib_ioctl, | ||
176 | .hw_params = mmp_pcm_hw_params, | ||
177 | .trigger = snd_dmaengine_pcm_trigger, | ||
178 | .pointer = snd_dmaengine_pcm_pointer, | ||
179 | .mmap = mmp_pcm_mmap, | ||
180 | }; | ||
181 | |||
182 | static void mmp_pcm_free_dma_buffers(struct snd_pcm *pcm) | ||
183 | { | ||
184 | struct snd_pcm_substream *substream; | ||
185 | struct snd_dma_buffer *buf; | ||
186 | int stream; | ||
187 | struct gen_pool *gpool; | ||
188 | |||
189 | gpool = sram_get_gpool("asram"); | ||
190 | if (!gpool) | ||
191 | return; | ||
192 | |||
193 | for (stream = 0; stream < 2; stream++) { | ||
194 | size_t size = mmp_pcm_hardware[stream].buffer_bytes_max; | ||
195 | |||
196 | substream = pcm->streams[stream].substream; | ||
197 | if (!substream) | ||
198 | continue; | ||
199 | |||
200 | buf = &substream->dma_buffer; | ||
201 | if (!buf->area) | ||
202 | continue; | ||
203 | gen_pool_free(gpool, (unsigned long)buf->area, size); | ||
204 | buf->area = NULL; | ||
205 | } | ||
206 | |||
207 | return; | ||
208 | } | ||
209 | |||
210 | static int mmp_pcm_preallocate_dma_buffer(struct snd_pcm_substream *substream, | ||
211 | int stream) | ||
212 | { | ||
213 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
214 | size_t size = mmp_pcm_hardware[stream].buffer_bytes_max; | ||
215 | struct gen_pool *gpool; | ||
216 | |||
217 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
218 | buf->dev.dev = substream->pcm->card->dev; | ||
219 | buf->private_data = NULL; | ||
220 | |||
221 | gpool = sram_get_gpool("asram"); | ||
222 | if (!gpool) | ||
223 | return -ENOMEM; | ||
224 | |||
225 | buf->area = (unsigned char *)gen_pool_alloc(gpool, size); | ||
226 | if (!buf->area) | ||
227 | return -ENOMEM; | ||
228 | buf->addr = gen_pool_virt_to_phys(gpool, (unsigned long)buf->area); | ||
229 | buf->bytes = size; | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | int mmp_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
234 | { | ||
235 | struct snd_pcm_substream *substream; | ||
236 | struct snd_pcm *pcm = rtd->pcm; | ||
237 | int ret = 0, stream; | ||
238 | |||
239 | for (stream = 0; stream < 2; stream++) { | ||
240 | substream = pcm->streams[stream].substream; | ||
241 | |||
242 | ret = mmp_pcm_preallocate_dma_buffer(substream, stream); | ||
243 | if (ret) | ||
244 | goto err; | ||
245 | } | ||
246 | |||
247 | return 0; | ||
248 | |||
249 | err: | ||
250 | mmp_pcm_free_dma_buffers(pcm); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | struct snd_soc_platform_driver mmp_soc_platform = { | ||
255 | .ops = &mmp_pcm_ops, | ||
256 | .pcm_new = mmp_pcm_new, | ||
257 | .pcm_free = mmp_pcm_free_dma_buffers, | ||
258 | }; | ||
259 | |||
260 | static __devinit int mmp_pcm_probe(struct platform_device *pdev) | ||
261 | { | ||
262 | struct mmp_audio_platdata *pdata = pdev->dev.platform_data; | ||
263 | |||
264 | if (pdata) { | ||
265 | mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].buffer_bytes_max = | ||
266 | pdata->buffer_max_playback; | ||
267 | mmp_pcm_hardware[SNDRV_PCM_STREAM_PLAYBACK].period_bytes_max = | ||
268 | pdata->period_max_playback; | ||
269 | mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].buffer_bytes_max = | ||
270 | pdata->buffer_max_capture; | ||
271 | mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max = | ||
272 | pdata->period_max_capture; | ||
273 | } | ||
274 | return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); | ||
275 | } | ||
276 | |||
277 | static int __devexit mmp_pcm_remove(struct platform_device *pdev) | ||
278 | { | ||
279 | snd_soc_unregister_platform(&pdev->dev); | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static struct platform_driver mmp_pcm_driver = { | ||
284 | .driver = { | ||
285 | .name = "mmp-pcm-audio", | ||
286 | .owner = THIS_MODULE, | ||
287 | }, | ||
288 | |||
289 | .probe = mmp_pcm_probe, | ||
290 | .remove = __devexit_p(mmp_pcm_remove), | ||
291 | }; | ||
292 | |||
293 | module_platform_driver(mmp_pcm_driver); | ||
294 | |||
295 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | ||
296 | MODULE_DESCRIPTION("MMP Soc Audio DMA module"); | ||
297 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/mmp-sspa.c b/sound/soc/pxa/mmp-sspa.c new file mode 100644 index 000000000000..4d6cb8a30fc8 --- /dev/null +++ b/sound/soc/pxa/mmp-sspa.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/pxa/mmp-sspa.c | ||
3 | * Base on pxa2xx-ssp.c | ||
4 | * | ||
5 | * Copyright (C) 2011 Marvell International Ltd. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | * | ||
21 | */ | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/clk.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/pxa2xx_ssp.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <sound/core.h> | ||
31 | #include <sound/pcm.h> | ||
32 | #include <sound/initval.h> | ||
33 | #include <sound/pcm_params.h> | ||
34 | #include <sound/soc.h> | ||
35 | #include <sound/pxa2xx-lib.h> | ||
36 | #include "mmp-sspa.h" | ||
37 | |||
38 | /* | ||
39 | * SSPA audio private data | ||
40 | */ | ||
41 | struct sspa_priv { | ||
42 | struct ssp_device *sspa; | ||
43 | struct pxa2xx_pcm_dma_params *dma_params; | ||
44 | struct clk *audio_clk; | ||
45 | struct clk *sysclk; | ||
46 | int dai_fmt; | ||
47 | int running_cnt; | ||
48 | }; | ||
49 | |||
50 | static void mmp_sspa_write_reg(struct ssp_device *sspa, u32 reg, u32 val) | ||
51 | { | ||
52 | __raw_writel(val, sspa->mmio_base + reg); | ||
53 | } | ||
54 | |||
55 | static u32 mmp_sspa_read_reg(struct ssp_device *sspa, u32 reg) | ||
56 | { | ||
57 | return __raw_readl(sspa->mmio_base + reg); | ||
58 | } | ||
59 | |||
60 | static void mmp_sspa_tx_enable(struct ssp_device *sspa) | ||
61 | { | ||
62 | unsigned int sspa_sp; | ||
63 | |||
64 | sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP); | ||
65 | sspa_sp |= SSPA_SP_S_EN; | ||
66 | sspa_sp |= SSPA_SP_WEN; | ||
67 | mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); | ||
68 | } | ||
69 | |||
70 | static void mmp_sspa_tx_disable(struct ssp_device *sspa) | ||
71 | { | ||
72 | unsigned int sspa_sp; | ||
73 | |||
74 | sspa_sp = mmp_sspa_read_reg(sspa, SSPA_TXSP); | ||
75 | sspa_sp &= ~SSPA_SP_S_EN; | ||
76 | sspa_sp |= SSPA_SP_WEN; | ||
77 | mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); | ||
78 | } | ||
79 | |||
80 | static void mmp_sspa_rx_enable(struct ssp_device *sspa) | ||
81 | { | ||
82 | unsigned int sspa_sp; | ||
83 | |||
84 | sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP); | ||
85 | sspa_sp |= SSPA_SP_S_EN; | ||
86 | sspa_sp |= SSPA_SP_WEN; | ||
87 | mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); | ||
88 | } | ||
89 | |||
90 | static void mmp_sspa_rx_disable(struct ssp_device *sspa) | ||
91 | { | ||
92 | unsigned int sspa_sp; | ||
93 | |||
94 | sspa_sp = mmp_sspa_read_reg(sspa, SSPA_RXSP); | ||
95 | sspa_sp &= ~SSPA_SP_S_EN; | ||
96 | sspa_sp |= SSPA_SP_WEN; | ||
97 | mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); | ||
98 | } | ||
99 | |||
100 | static int mmp_sspa_startup(struct snd_pcm_substream *substream, | ||
101 | struct snd_soc_dai *dai) | ||
102 | { | ||
103 | struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
104 | |||
105 | clk_enable(priv->sysclk); | ||
106 | clk_enable(priv->sspa->clk); | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static void mmp_sspa_shutdown(struct snd_pcm_substream *substream, | ||
112 | struct snd_soc_dai *dai) | ||
113 | { | ||
114 | struct sspa_priv *priv = snd_soc_dai_get_drvdata(dai); | ||
115 | |||
116 | clk_disable(priv->sspa->clk); | ||
117 | clk_disable(priv->sysclk); | ||
118 | |||
119 | return; | ||
120 | } | ||
121 | |||
122 | /* | ||
123 | * Set the SSP ports SYSCLK. | ||
124 | */ | ||
125 | static int mmp_sspa_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | ||
126 | int clk_id, unsigned int freq, int dir) | ||
127 | { | ||
128 | struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
129 | int ret = 0; | ||
130 | |||
131 | switch (clk_id) { | ||
132 | case MMP_SSPA_CLK_AUDIO: | ||
133 | ret = clk_set_rate(priv->audio_clk, freq); | ||
134 | if (ret) | ||
135 | return ret; | ||
136 | break; | ||
137 | case MMP_SSPA_CLK_PLL: | ||
138 | case MMP_SSPA_CLK_VCXO: | ||
139 | /* not support yet */ | ||
140 | return -EINVAL; | ||
141 | default: | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int mmp_sspa_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, | ||
149 | int source, unsigned int freq_in, | ||
150 | unsigned int freq_out) | ||
151 | { | ||
152 | struct sspa_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
153 | int ret = 0; | ||
154 | |||
155 | switch (pll_id) { | ||
156 | case MMP_SYSCLK: | ||
157 | ret = clk_set_rate(priv->sysclk, freq_out); | ||
158 | if (ret) | ||
159 | return ret; | ||
160 | break; | ||
161 | case MMP_SSPA_CLK: | ||
162 | ret = clk_set_rate(priv->sspa->clk, freq_out); | ||
163 | if (ret) | ||
164 | return ret; | ||
165 | break; | ||
166 | default: | ||
167 | return -ENODEV; | ||
168 | } | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Set up the sspa dai format. The sspa port must be inactive | ||
175 | * before calling this function as the physical | ||
176 | * interface format is changed. | ||
177 | */ | ||
178 | static int mmp_sspa_set_dai_fmt(struct snd_soc_dai *cpu_dai, | ||
179 | unsigned int fmt) | ||
180 | { | ||
181 | struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(cpu_dai); | ||
182 | struct ssp_device *sspa = sspa_priv->sspa; | ||
183 | u32 sspa_sp, sspa_ctrl; | ||
184 | |||
185 | /* check if we need to change anything at all */ | ||
186 | if (sspa_priv->dai_fmt == fmt) | ||
187 | return 0; | ||
188 | |||
189 | /* we can only change the settings if the port is not in use */ | ||
190 | if ((mmp_sspa_read_reg(sspa, SSPA_TXSP) & SSPA_SP_S_EN) || | ||
191 | (mmp_sspa_read_reg(sspa, SSPA_RXSP) & SSPA_SP_S_EN)) { | ||
192 | dev_err(&sspa->pdev->dev, | ||
193 | "can't change hardware dai format: stream is in use\n"); | ||
194 | return -EINVAL; | ||
195 | } | ||
196 | |||
197 | /* reset port settings */ | ||
198 | sspa_sp = SSPA_SP_WEN | SSPA_SP_S_RST | SSPA_SP_FFLUSH; | ||
199 | sspa_ctrl = 0; | ||
200 | |||
201 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
202 | case SND_SOC_DAIFMT_CBS_CFS: | ||
203 | sspa_sp |= SSPA_SP_MSL; | ||
204 | break; | ||
205 | case SND_SOC_DAIFMT_CBM_CFM: | ||
206 | break; | ||
207 | default: | ||
208 | return -EINVAL; | ||
209 | } | ||
210 | |||
211 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
212 | case SND_SOC_DAIFMT_NB_NF: | ||
213 | sspa_sp |= SSPA_SP_FSP; | ||
214 | break; | ||
215 | default: | ||
216 | return -EINVAL; | ||
217 | } | ||
218 | |||
219 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
220 | case SND_SOC_DAIFMT_I2S: | ||
221 | sspa_sp |= SSPA_TXSP_FPER(63); | ||
222 | sspa_sp |= SSPA_SP_FWID(31); | ||
223 | sspa_ctrl |= SSPA_CTL_XDATDLY(1); | ||
224 | break; | ||
225 | default: | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); | ||
230 | mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); | ||
231 | |||
232 | sspa_sp &= ~(SSPA_SP_S_RST | SSPA_SP_FFLUSH); | ||
233 | mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); | ||
234 | mmp_sspa_write_reg(sspa, SSPA_RXSP, sspa_sp); | ||
235 | |||
236 | /* | ||
237 | * FIXME: hw issue, for the tx serial port, | ||
238 | * can not config the master/slave mode; | ||
239 | * so must clean this bit. | ||
240 | * The master/slave mode has been set in the | ||
241 | * rx port. | ||
242 | */ | ||
243 | sspa_sp &= ~SSPA_SP_MSL; | ||
244 | mmp_sspa_write_reg(sspa, SSPA_TXSP, sspa_sp); | ||
245 | |||
246 | mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); | ||
247 | mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); | ||
248 | |||
249 | /* Since we are configuring the timings for the format by hand | ||
250 | * we have to defer some things until hw_params() where we | ||
251 | * know parameters like the sample size. | ||
252 | */ | ||
253 | sspa_priv->dai_fmt = fmt; | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Set the SSPA audio DMA parameters and sample size. | ||
259 | * Can be called multiple times by oss emulation. | ||
260 | */ | ||
261 | static int mmp_sspa_hw_params(struct snd_pcm_substream *substream, | ||
262 | struct snd_pcm_hw_params *params, | ||
263 | struct snd_soc_dai *dai) | ||
264 | { | ||
265 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
266 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
267 | struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); | ||
268 | struct ssp_device *sspa = sspa_priv->sspa; | ||
269 | struct pxa2xx_pcm_dma_params *dma_params; | ||
270 | u32 sspa_ctrl; | ||
271 | |||
272 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
273 | sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_TXCTL); | ||
274 | else | ||
275 | sspa_ctrl = mmp_sspa_read_reg(sspa, SSPA_RXCTL); | ||
276 | |||
277 | sspa_ctrl &= ~SSPA_CTL_XFRLEN1_MASK; | ||
278 | sspa_ctrl |= SSPA_CTL_XFRLEN1(params_channels(params) - 1); | ||
279 | sspa_ctrl &= ~SSPA_CTL_XWDLEN1_MASK; | ||
280 | sspa_ctrl |= SSPA_CTL_XWDLEN1(SSPA_CTL_32_BITS); | ||
281 | sspa_ctrl &= ~SSPA_CTL_XSSZ1_MASK; | ||
282 | |||
283 | switch (params_format(params)) { | ||
284 | case SNDRV_PCM_FORMAT_S8: | ||
285 | sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_8_BITS); | ||
286 | break; | ||
287 | case SNDRV_PCM_FORMAT_S16_LE: | ||
288 | sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_16_BITS); | ||
289 | break; | ||
290 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
291 | sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_20_BITS); | ||
292 | break; | ||
293 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
294 | sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_24_BITS); | ||
295 | break; | ||
296 | case SNDRV_PCM_FORMAT_S32_LE: | ||
297 | sspa_ctrl |= SSPA_CTL_XSSZ1(SSPA_CTL_32_BITS); | ||
298 | break; | ||
299 | default: | ||
300 | return -EINVAL; | ||
301 | } | ||
302 | |||
303 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
304 | mmp_sspa_write_reg(sspa, SSPA_TXCTL, sspa_ctrl); | ||
305 | mmp_sspa_write_reg(sspa, SSPA_TXFIFO_LL, 0x1); | ||
306 | } else { | ||
307 | mmp_sspa_write_reg(sspa, SSPA_RXCTL, sspa_ctrl); | ||
308 | mmp_sspa_write_reg(sspa, SSPA_RXFIFO_UL, 0x0); | ||
309 | } | ||
310 | |||
311 | dma_params = &sspa_priv->dma_params[substream->stream]; | ||
312 | dma_params->dev_addr = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
313 | (sspa->phys_base + SSPA_TXD) : | ||
314 | (sspa->phys_base + SSPA_RXD); | ||
315 | snd_soc_dai_set_dma_data(cpu_dai, substream, dma_params); | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int mmp_sspa_trigger(struct snd_pcm_substream *substream, int cmd, | ||
320 | struct snd_soc_dai *dai) | ||
321 | { | ||
322 | struct sspa_priv *sspa_priv = snd_soc_dai_get_drvdata(dai); | ||
323 | struct ssp_device *sspa = sspa_priv->sspa; | ||
324 | int ret = 0; | ||
325 | |||
326 | switch (cmd) { | ||
327 | case SNDRV_PCM_TRIGGER_START: | ||
328 | case SNDRV_PCM_TRIGGER_RESUME: | ||
329 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
330 | /* | ||
331 | * whatever playback or capture, must enable rx. | ||
332 | * this is a hw issue, so need check if rx has been | ||
333 | * enabled or not; if has been enabled by another | ||
334 | * stream, do not enable again. | ||
335 | */ | ||
336 | if (!sspa_priv->running_cnt) | ||
337 | mmp_sspa_rx_enable(sspa); | ||
338 | |||
339 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
340 | mmp_sspa_tx_enable(sspa); | ||
341 | |||
342 | sspa_priv->running_cnt++; | ||
343 | break; | ||
344 | |||
345 | case SNDRV_PCM_TRIGGER_STOP: | ||
346 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
347 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
348 | sspa_priv->running_cnt--; | ||
349 | |||
350 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
351 | mmp_sspa_tx_disable(sspa); | ||
352 | |||
353 | /* have no capture stream, disable rx port */ | ||
354 | if (!sspa_priv->running_cnt) | ||
355 | mmp_sspa_rx_disable(sspa); | ||
356 | break; | ||
357 | |||
358 | default: | ||
359 | ret = -EINVAL; | ||
360 | } | ||
361 | |||
362 | return ret; | ||
363 | } | ||
364 | |||
365 | static int mmp_sspa_probe(struct snd_soc_dai *dai) | ||
366 | { | ||
367 | struct sspa_priv *priv = dev_get_drvdata(dai->dev); | ||
368 | |||
369 | snd_soc_dai_set_drvdata(dai, priv); | ||
370 | return 0; | ||
371 | |||
372 | } | ||
373 | |||
374 | #define MMP_SSPA_RATES SNDRV_PCM_RATE_8000_192000 | ||
375 | #define MMP_SSPA_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | ||
376 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
377 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
378 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
379 | SNDRV_PCM_FMTBIT_S32_LE) | ||
380 | |||
381 | static struct snd_soc_dai_ops mmp_sspa_dai_ops = { | ||
382 | .startup = mmp_sspa_startup, | ||
383 | .shutdown = mmp_sspa_shutdown, | ||
384 | .trigger = mmp_sspa_trigger, | ||
385 | .hw_params = mmp_sspa_hw_params, | ||
386 | .set_sysclk = mmp_sspa_set_dai_sysclk, | ||
387 | .set_pll = mmp_sspa_set_dai_pll, | ||
388 | .set_fmt = mmp_sspa_set_dai_fmt, | ||
389 | }; | ||
390 | |||
391 | struct snd_soc_dai_driver mmp_sspa_dai = { | ||
392 | .probe = mmp_sspa_probe, | ||
393 | .playback = { | ||
394 | .channels_min = 1, | ||
395 | .channels_max = 128, | ||
396 | .rates = MMP_SSPA_RATES, | ||
397 | .formats = MMP_SSPA_FORMATS, | ||
398 | }, | ||
399 | .capture = { | ||
400 | .channels_min = 1, | ||
401 | .channels_max = 2, | ||
402 | .rates = MMP_SSPA_RATES, | ||
403 | .formats = MMP_SSPA_FORMATS, | ||
404 | }, | ||
405 | .ops = &mmp_sspa_dai_ops, | ||
406 | }; | ||
407 | |||
408 | static __devinit int asoc_mmp_sspa_probe(struct platform_device *pdev) | ||
409 | { | ||
410 | struct sspa_priv *priv; | ||
411 | struct resource *res; | ||
412 | |||
413 | priv = devm_kzalloc(&pdev->dev, | ||
414 | sizeof(struct sspa_priv), GFP_KERNEL); | ||
415 | if (!priv) | ||
416 | return -ENOMEM; | ||
417 | |||
418 | priv->sspa = devm_kzalloc(&pdev->dev, | ||
419 | sizeof(struct ssp_device), GFP_KERNEL); | ||
420 | if (priv->sspa == NULL) | ||
421 | return -ENOMEM; | ||
422 | |||
423 | priv->dma_params = devm_kzalloc(&pdev->dev, | ||
424 | 2 * sizeof(struct pxa2xx_pcm_dma_params), GFP_KERNEL); | ||
425 | if (priv->dma_params == NULL) | ||
426 | return -ENOMEM; | ||
427 | |||
428 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
429 | if (res == NULL) | ||
430 | return -ENOMEM; | ||
431 | |||
432 | priv->sspa->mmio_base = devm_request_and_ioremap(&pdev->dev, res); | ||
433 | if (priv->sspa->mmio_base == NULL) | ||
434 | return -ENODEV; | ||
435 | |||
436 | priv->sspa->clk = devm_clk_get(&pdev->dev, NULL); | ||
437 | if (IS_ERR(priv->sspa->clk)) | ||
438 | return PTR_ERR(priv->sspa->clk); | ||
439 | |||
440 | priv->audio_clk = clk_get(NULL, "mmp-audio"); | ||
441 | if (IS_ERR(priv->audio_clk)) | ||
442 | return PTR_ERR(priv->audio_clk); | ||
443 | |||
444 | priv->sysclk = clk_get(NULL, "mmp-sysclk"); | ||
445 | if (IS_ERR(priv->sysclk)) { | ||
446 | clk_put(priv->audio_clk); | ||
447 | return PTR_ERR(priv->sysclk); | ||
448 | } | ||
449 | clk_enable(priv->audio_clk); | ||
450 | priv->dai_fmt = (unsigned int) -1; | ||
451 | platform_set_drvdata(pdev, priv); | ||
452 | |||
453 | return snd_soc_register_dai(&pdev->dev, &mmp_sspa_dai); | ||
454 | } | ||
455 | |||
456 | static int __devexit asoc_mmp_sspa_remove(struct platform_device *pdev) | ||
457 | { | ||
458 | struct sspa_priv *priv = platform_get_drvdata(pdev); | ||
459 | |||
460 | clk_disable(priv->audio_clk); | ||
461 | clk_put(priv->audio_clk); | ||
462 | clk_put(priv->sysclk); | ||
463 | snd_soc_unregister_dai(&pdev->dev); | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static struct platform_driver asoc_mmp_sspa_driver = { | ||
468 | .driver = { | ||
469 | .name = "mmp-sspa-dai", | ||
470 | .owner = THIS_MODULE, | ||
471 | }, | ||
472 | .probe = asoc_mmp_sspa_probe, | ||
473 | .remove = __devexit_p(asoc_mmp_sspa_remove), | ||
474 | }; | ||
475 | |||
476 | module_platform_driver(asoc_mmp_sspa_driver); | ||
477 | |||
478 | MODULE_AUTHOR("Leo Yan <leoy@marvell.com>"); | ||
479 | MODULE_DESCRIPTION("MMP SSPA SoC Interface"); | ||
480 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/pxa/mmp-sspa.h b/sound/soc/pxa/mmp-sspa.h new file mode 100644 index 000000000000..ea365cb9e784 --- /dev/null +++ b/sound/soc/pxa/mmp-sspa.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/pxa/mmp-sspa.h | ||
3 | * | ||
4 | * Copyright (C) 2011 Marvell International Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #ifndef _MMP_SSPA_H | ||
22 | #define _MMP_SSPA_H | ||
23 | |||
24 | /* | ||
25 | * SSPA Registers | ||
26 | */ | ||
27 | #define SSPA_RXD (0x00) | ||
28 | #define SSPA_RXID (0x04) | ||
29 | #define SSPA_RXCTL (0x08) | ||
30 | #define SSPA_RXSP (0x0c) | ||
31 | #define SSPA_RXFIFO_UL (0x10) | ||
32 | #define SSPA_RXINT_MASK (0x14) | ||
33 | #define SSPA_RXC (0x18) | ||
34 | #define SSPA_RXFIFO_NOFS (0x1c) | ||
35 | #define SSPA_RXFIFO_SIZE (0x20) | ||
36 | |||
37 | #define SSPA_TXD (0x80) | ||
38 | #define SSPA_TXID (0x84) | ||
39 | #define SSPA_TXCTL (0x88) | ||
40 | #define SSPA_TXSP (0x8c) | ||
41 | #define SSPA_TXFIFO_LL (0x90) | ||
42 | #define SSPA_TXINT_MASK (0x94) | ||
43 | #define SSPA_TXC (0x98) | ||
44 | #define SSPA_TXFIFO_NOFS (0x9c) | ||
45 | #define SSPA_TXFIFO_SIZE (0xa0) | ||
46 | |||
47 | /* SSPA Control Register */ | ||
48 | #define SSPA_CTL_XPH (1 << 31) /* Read Phase */ | ||
49 | #define SSPA_CTL_XFIG (1 << 15) /* Transmit Zeros when FIFO Empty */ | ||
50 | #define SSPA_CTL_JST (1 << 3) /* Audio Sample Justification */ | ||
51 | #define SSPA_CTL_XFRLEN2_MASK (7 << 24) | ||
52 | #define SSPA_CTL_XFRLEN2(x) ((x) << 24) /* Transmit Frame Length in Phase 2 */ | ||
53 | #define SSPA_CTL_XWDLEN2_MASK (7 << 21) | ||
54 | #define SSPA_CTL_XWDLEN2(x) ((x) << 21) /* Transmit Word Length in Phase 2 */ | ||
55 | #define SSPA_CTL_XDATDLY(x) ((x) << 19) /* Tansmit Data Delay */ | ||
56 | #define SSPA_CTL_XSSZ2_MASK (7 << 16) | ||
57 | #define SSPA_CTL_XSSZ2(x) ((x) << 16) /* Transmit Sample Audio Size */ | ||
58 | #define SSPA_CTL_XFRLEN1_MASK (7 << 8) | ||
59 | #define SSPA_CTL_XFRLEN1(x) ((x) << 8) /* Transmit Frame Length in Phase 1 */ | ||
60 | #define SSPA_CTL_XWDLEN1_MASK (7 << 5) | ||
61 | #define SSPA_CTL_XWDLEN1(x) ((x) << 5) /* Transmit Word Length in Phase 1 */ | ||
62 | #define SSPA_CTL_XSSZ1_MASK (7 << 0) | ||
63 | #define SSPA_CTL_XSSZ1(x) ((x) << 0) /* XSSZ1 */ | ||
64 | |||
65 | #define SSPA_CTL_8_BITS (0x0) /* Sample Size */ | ||
66 | #define SSPA_CTL_12_BITS (0x1) | ||
67 | #define SSPA_CTL_16_BITS (0x2) | ||
68 | #define SSPA_CTL_20_BITS (0x3) | ||
69 | #define SSPA_CTL_24_BITS (0x4) | ||
70 | #define SSPA_CTL_32_BITS (0x5) | ||
71 | |||
72 | /* SSPA Serial Port Register */ | ||
73 | #define SSPA_SP_WEN (1 << 31) /* Write Configuration Enable */ | ||
74 | #define SSPA_SP_MSL (1 << 18) /* Master Slave Configuration */ | ||
75 | #define SSPA_SP_CLKP (1 << 17) /* CLKP Polarity Clock Edge Select */ | ||
76 | #define SSPA_SP_FSP (1 << 16) /* FSP Polarity Clock Edge Select */ | ||
77 | #define SSPA_SP_FFLUSH (1 << 2) /* FIFO Flush */ | ||
78 | #define SSPA_SP_S_RST (1 << 1) /* Active High Reset Signal */ | ||
79 | #define SSPA_SP_S_EN (1 << 0) /* Serial Clock Domain Enable */ | ||
80 | #define SSPA_SP_FWID(x) ((x) << 20) /* Frame-Sync Width */ | ||
81 | #define SSPA_TXSP_FPER(x) ((x) << 4) /* Frame-Sync Active */ | ||
82 | |||
83 | /* sspa clock sources */ | ||
84 | #define MMP_SSPA_CLK_PLL 0 | ||
85 | #define MMP_SSPA_CLK_VCXO 1 | ||
86 | #define MMP_SSPA_CLK_AUDIO 3 | ||
87 | |||
88 | /* sspa pll id */ | ||
89 | #define MMP_SYSCLK 0 | ||
90 | #define MMP_SSPA_CLK 1 | ||
91 | |||
92 | #endif /* _MMP_SSPA_H */ | ||
diff --git a/sound/soc/pxa/ttc-dkb.c b/sound/soc/pxa/ttc-dkb.c new file mode 100644 index 000000000000..935491a8a770 --- /dev/null +++ b/sound/soc/pxa/ttc-dkb.c | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * linux/sound/soc/pxa/ttc_dkb.c | ||
3 | * | ||
4 | * Copyright (C) 2012 Marvell International Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | #include <linux/module.h> | ||
22 | #include <linux/moduleparam.h> | ||
23 | #include <sound/core.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/jack.h> | ||
27 | #include <asm/mach-types.h> | ||
28 | #include <sound/pcm_params.h> | ||
29 | #include "../codecs/88pm860x-codec.h" | ||
30 | |||
31 | static struct snd_soc_jack hs_jack, mic_jack; | ||
32 | |||
33 | static struct snd_soc_jack_pin hs_jack_pins[] = { | ||
34 | { .pin = "Headset Stereophone", .mask = SND_JACK_HEADPHONE, }, | ||
35 | }; | ||
36 | |||
37 | static struct snd_soc_jack_pin mic_jack_pins[] = { | ||
38 | { .pin = "Headset Mic 2", .mask = SND_JACK_MICROPHONE, }, | ||
39 | }; | ||
40 | |||
41 | /* ttc machine dapm widgets */ | ||
42 | static const struct snd_soc_dapm_widget ttc_dapm_widgets[] = { | ||
43 | SND_SOC_DAPM_HP("Headset Stereophone", NULL), | ||
44 | SND_SOC_DAPM_LINE("Lineout Out 1", NULL), | ||
45 | SND_SOC_DAPM_LINE("Lineout Out 2", NULL), | ||
46 | SND_SOC_DAPM_SPK("Ext Speaker", NULL), | ||
47 | SND_SOC_DAPM_MIC("Ext Mic 1", NULL), | ||
48 | SND_SOC_DAPM_MIC("Headset Mic 2", NULL), | ||
49 | SND_SOC_DAPM_MIC("Ext Mic 3", NULL), | ||
50 | }; | ||
51 | |||
52 | /* ttc machine audio map */ | ||
53 | static const struct snd_soc_dapm_route ttc_audio_map[] = { | ||
54 | {"Headset Stereophone", NULL, "HS1"}, | ||
55 | {"Headset Stereophone", NULL, "HS2"}, | ||
56 | |||
57 | {"Ext Speaker", NULL, "LSP"}, | ||
58 | {"Ext Speaker", NULL, "LSN"}, | ||
59 | |||
60 | {"Lineout Out 1", NULL, "LINEOUT1"}, | ||
61 | {"Lineout Out 2", NULL, "LINEOUT2"}, | ||
62 | |||
63 | {"MIC1P", NULL, "Mic1 Bias"}, | ||
64 | {"MIC1N", NULL, "Mic1 Bias"}, | ||
65 | {"Mic1 Bias", NULL, "Ext Mic 1"}, | ||
66 | |||
67 | {"MIC2P", NULL, "Mic1 Bias"}, | ||
68 | {"MIC2N", NULL, "Mic1 Bias"}, | ||
69 | {"Mic1 Bias", NULL, "Headset Mic 2"}, | ||
70 | |||
71 | {"MIC3P", NULL, "Mic3 Bias"}, | ||
72 | {"MIC3N", NULL, "Mic3 Bias"}, | ||
73 | {"Mic3 Bias", NULL, "Ext Mic 3"}, | ||
74 | }; | ||
75 | |||
76 | static int ttc_pm860x_init(struct snd_soc_pcm_runtime *rtd) | ||
77 | { | ||
78 | struct snd_soc_codec *codec = rtd->codec; | ||
79 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
80 | |||
81 | /* connected pins */ | ||
82 | snd_soc_dapm_enable_pin(dapm, "Ext Speaker"); | ||
83 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 1"); | ||
84 | snd_soc_dapm_enable_pin(dapm, "Ext Mic 3"); | ||
85 | snd_soc_dapm_disable_pin(dapm, "Headset Mic 2"); | ||
86 | snd_soc_dapm_disable_pin(dapm, "Headset Stereophone"); | ||
87 | |||
88 | /* Headset jack detection */ | ||
89 | snd_soc_jack_new(codec, "Headphone Jack", SND_JACK_HEADPHONE | ||
90 | | SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2, | ||
91 | &hs_jack); | ||
92 | snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins), | ||
93 | hs_jack_pins); | ||
94 | snd_soc_jack_new(codec, "Microphone Jack", SND_JACK_MICROPHONE, | ||
95 | &mic_jack); | ||
96 | snd_soc_jack_add_pins(&mic_jack, ARRAY_SIZE(mic_jack_pins), | ||
97 | mic_jack_pins); | ||
98 | |||
99 | /* headphone, microphone detection & headset short detection */ | ||
100 | pm860x_hs_jack_detect(codec, &hs_jack, SND_JACK_HEADPHONE, | ||
101 | SND_JACK_BTN_0, SND_JACK_BTN_1, SND_JACK_BTN_2); | ||
102 | pm860x_mic_jack_detect(codec, &hs_jack, SND_JACK_MICROPHONE); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | /* ttc/td-dkb digital audio interface glue - connects codec <--> CPU */ | ||
108 | static struct snd_soc_dai_link ttc_pm860x_hifi_dai[] = { | ||
109 | { | ||
110 | .name = "88pm860x i2s", | ||
111 | .stream_name = "audio playback", | ||
112 | .codec_name = "88pm860x-codec", | ||
113 | .platform_name = "mmp-pcm-audio", | ||
114 | .cpu_dai_name = "pxa-ssp-dai.1", | ||
115 | .codec_dai_name = "88pm860x-i2s", | ||
116 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
117 | SND_SOC_DAIFMT_CBM_CFM, | ||
118 | .init = ttc_pm860x_init, | ||
119 | }, | ||
120 | }; | ||
121 | |||
122 | /* ttc/td audio machine driver */ | ||
123 | static struct snd_soc_card ttc_dkb_card = { | ||
124 | .name = "ttc-dkb-hifi", | ||
125 | .dai_link = ttc_pm860x_hifi_dai, | ||
126 | .num_links = ARRAY_SIZE(ttc_pm860x_hifi_dai), | ||
127 | |||
128 | .dapm_widgets = ttc_dapm_widgets, | ||
129 | .num_dapm_widgets = ARRAY_SIZE(ttc_dapm_widgets), | ||
130 | .dapm_routes = ttc_audio_map, | ||
131 | .num_dapm_routes = ARRAY_SIZE(ttc_audio_map), | ||
132 | }; | ||
133 | |||
134 | static int __devinit ttc_dkb_probe(struct platform_device *pdev) | ||
135 | { | ||
136 | struct snd_soc_card *card = &ttc_dkb_card; | ||
137 | int ret; | ||
138 | |||
139 | card->dev = &pdev->dev; | ||
140 | |||
141 | ret = snd_soc_register_card(card); | ||
142 | if (ret) | ||
143 | dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n", | ||
144 | ret); | ||
145 | |||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static int __devexit ttc_dkb_remove(struct platform_device *pdev) | ||
150 | { | ||
151 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
152 | |||
153 | snd_soc_unregister_card(card); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static struct platform_driver ttc_dkb_driver = { | ||
159 | .driver = { | ||
160 | .name = "ttc-dkb-audio", | ||
161 | .owner = THIS_MODULE, | ||
162 | }, | ||
163 | .probe = ttc_dkb_probe, | ||
164 | .remove = __devexit_p(ttc_dkb_remove), | ||
165 | }; | ||
166 | |||
167 | module_platform_driver(ttc_dkb_driver); | ||
168 | |||
169 | /* Module information */ | ||
170 | MODULE_AUTHOR("Qiao Zhou, <zhouqiao@marvell.com>"); | ||
171 | MODULE_DESCRIPTION("ALSA SoC TTC DKB"); | ||
172 | MODULE_LICENSE("GPL"); | ||
173 | MODULE_ALIAS("platform:ttc-dkb-audio"); | ||
diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index c82c646b8a08..ee52c8a00779 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c | |||
@@ -211,6 +211,11 @@ static int bbclk_ev(struct snd_soc_dapm_widget *w, | |||
211 | return 0; | 211 | return 0; |
212 | } | 212 | } |
213 | 213 | ||
214 | static const struct snd_kcontrol_new controls[] = { | ||
215 | SOC_DAPM_PIN_SWITCH("WM1250 Input"), | ||
216 | SOC_DAPM_PIN_SWITCH("WM1250 Output"), | ||
217 | }; | ||
218 | |||
214 | static struct snd_soc_dapm_widget widgets[] = { | 219 | static struct snd_soc_dapm_widget widgets[] = { |
215 | SND_SOC_DAPM_HP("Headphone", NULL), | 220 | SND_SOC_DAPM_HP("Headphone", NULL), |
216 | 221 | ||
@@ -282,6 +287,8 @@ static struct snd_soc_card littlemill = { | |||
282 | .set_bias_level = littlemill_set_bias_level, | 287 | .set_bias_level = littlemill_set_bias_level, |
283 | .set_bias_level_post = littlemill_set_bias_level_post, | 288 | .set_bias_level_post = littlemill_set_bias_level_post, |
284 | 289 | ||
290 | .controls = controls, | ||
291 | .num_controls = ARRAY_SIZE(controls), | ||
285 | .dapm_widgets = widgets, | 292 | .dapm_widgets = widgets, |
286 | .num_dapm_widgets = ARRAY_SIZE(widgets), | 293 | .num_dapm_widgets = ARRAY_SIZE(widgets), |
287 | .dapm_routes = audio_paths, | 294 | .dapm_routes = audio_paths, |
diff --git a/sound/soc/samsung/s3c2412-i2s.c b/sound/soc/samsung/s3c2412-i2s.c index 79fbeea99d46..ac7701b3c5dc 100644 --- a/sound/soc/samsung/s3c2412-i2s.c +++ b/sound/soc/samsung/s3c2412-i2s.c | |||
@@ -25,7 +25,6 @@ | |||
25 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
26 | #include <sound/pcm_params.h> | 26 | #include <sound/pcm_params.h> |
27 | 27 | ||
28 | #include <mach/regs-gpio.h> | ||
29 | #include <mach/dma.h> | 28 | #include <mach/dma.h> |
30 | 29 | ||
31 | #include "dma.h" | 30 | #include "dma.h" |
@@ -83,12 +82,9 @@ static int s3c2412_i2s_probe(struct snd_soc_dai *dai) | |||
83 | 82 | ||
84 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; | 83 | s3c2412_i2s.iis_cclk = s3c2412_i2s.iis_pclk; |
85 | 84 | ||
86 | /* Configure the I2S pins in correct mode */ | 85 | /* Configure the I2S pins (GPE0...GPE4) in correct mode */ |
87 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | 86 | s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), |
88 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); | 87 | S3C_GPIO_PULL_NONE); |
89 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); | ||
90 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | ||
91 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | ||
92 | 88 | ||
93 | return 0; | 89 | return 0; |
94 | } | 90 | } |
diff --git a/sound/soc/samsung/s3c24xx-i2s.c b/sound/soc/samsung/s3c24xx-i2s.c index c4aa4d412fbf..0aae3a3883dc 100644 --- a/sound/soc/samsung/s3c24xx-i2s.c +++ b/sound/soc/samsung/s3c24xx-i2s.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
24 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
25 | 25 | ||
26 | #include <mach/regs-gpio.h> | ||
27 | #include <mach/dma.h> | 26 | #include <mach/dma.h> |
28 | #include <plat/regs-iis.h> | 27 | #include <plat/regs-iis.h> |
29 | 28 | ||
@@ -391,12 +390,9 @@ static int s3c24xx_i2s_probe(struct snd_soc_dai *dai) | |||
391 | } | 390 | } |
392 | clk_enable(s3c24xx_i2s.iis_clk); | 391 | clk_enable(s3c24xx_i2s.iis_clk); |
393 | 392 | ||
394 | /* Configure the I2S pins in correct mode */ | 393 | /* Configure the I2S pins (GPE0...GPE4) in correct mode */ |
395 | s3c2410_gpio_cfgpin(S3C2410_GPE0, S3C2410_GPE0_I2SLRCK); | 394 | s3c_gpio_cfgall_range(S3C2410_GPE(0), 5, S3C_GPIO_SFN(2), |
396 | s3c2410_gpio_cfgpin(S3C2410_GPE1, S3C2410_GPE1_I2SSCLK); | 395 | S3C_GPIO_PULL_NONE); |
397 | s3c2410_gpio_cfgpin(S3C2410_GPE2, S3C2410_GPE2_CDCLK); | ||
398 | s3c2410_gpio_cfgpin(S3C2410_GPE3, S3C2410_GPE3_I2SSDI); | ||
399 | s3c2410_gpio_cfgpin(S3C2410_GPE4, S3C2410_GPE4_I2SSDO); | ||
400 | 396 | ||
401 | writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); | 397 | writel(S3C2410_IISCON_IISEN, s3c24xx_i2s.regs + S3C2410_IISCON); |
402 | 398 | ||
diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index 8eb309f23d18..48dd4dd9ee08 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c | |||
@@ -149,31 +149,41 @@ static struct snd_soc_card smdk = { | |||
149 | .num_links = ARRAY_SIZE(smdk_dai), | 149 | .num_links = ARRAY_SIZE(smdk_dai), |
150 | }; | 150 | }; |
151 | 151 | ||
152 | static struct platform_device *smdk_snd_device; | ||
153 | 152 | ||
154 | static int __init smdk_audio_init(void) | 153 | static int __devinit smdk_audio_probe(struct platform_device *pdev) |
155 | { | 154 | { |
156 | int ret; | 155 | int ret; |
156 | struct snd_soc_card *card = &smdk; | ||
157 | 157 | ||
158 | smdk_snd_device = platform_device_alloc("soc-audio", -1); | 158 | card->dev = &pdev->dev; |
159 | if (!smdk_snd_device) | 159 | ret = snd_soc_register_card(card); |
160 | return -ENOMEM; | ||
161 | 160 | ||
162 | platform_set_drvdata(smdk_snd_device, &smdk); | ||
163 | |||
164 | ret = platform_device_add(smdk_snd_device); | ||
165 | if (ret) | 161 | if (ret) |
166 | platform_device_put(smdk_snd_device); | 162 | dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret); |
167 | 163 | ||
168 | return ret; | 164 | return ret; |
169 | } | 165 | } |
170 | module_init(smdk_audio_init); | ||
171 | 166 | ||
172 | static void __exit smdk_audio_exit(void) | 167 | static int __devexit smdk_audio_remove(struct platform_device *pdev) |
173 | { | 168 | { |
174 | platform_device_unregister(smdk_snd_device); | 169 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
170 | |||
171 | snd_soc_unregister_card(card); | ||
172 | |||
173 | return 0; | ||
175 | } | 174 | } |
176 | module_exit(smdk_audio_exit); | 175 | |
176 | static struct platform_driver smdk_audio_driver = { | ||
177 | .driver = { | ||
178 | .name = "smdk-audio", | ||
179 | .owner = THIS_MODULE, | ||
180 | }, | ||
181 | .probe = smdk_audio_probe, | ||
182 | .remove = __devexit_p(smdk_audio_remove), | ||
183 | }; | ||
184 | |||
185 | module_platform_driver(smdk_audio_driver); | ||
177 | 186 | ||
178 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); | 187 | MODULE_DESCRIPTION("ALSA SoC SMDK WM8994"); |
179 | MODULE_LICENSE("GPL"); | 188 | MODULE_LICENSE("GPL"); |
189 | MODULE_ALIAS("platform:smdk-audio"); | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 2ef98536f1da..53486ff9c2af 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -247,7 +247,7 @@ struct fsi_priv { | |||
247 | struct fsi_stream_handler { | 247 | struct fsi_stream_handler { |
248 | int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); | 248 | int (*init)(struct fsi_priv *fsi, struct fsi_stream *io); |
249 | int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); | 249 | int (*quit)(struct fsi_priv *fsi, struct fsi_stream *io); |
250 | int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io); | 250 | int (*probe)(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev); |
251 | int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); | 251 | int (*transfer)(struct fsi_priv *fsi, struct fsi_stream *io); |
252 | int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); | 252 | int (*remove)(struct fsi_priv *fsi, struct fsi_stream *io); |
253 | void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, | 253 | void (*start_stop)(struct fsi_priv *fsi, struct fsi_stream *io, |
@@ -571,16 +571,16 @@ static int fsi_stream_transfer(struct fsi_stream *io) | |||
571 | #define fsi_stream_stop(fsi, io)\ | 571 | #define fsi_stream_stop(fsi, io)\ |
572 | fsi_stream_handler_call(io, start_stop, fsi, io, 0) | 572 | fsi_stream_handler_call(io, start_stop, fsi, io, 0) |
573 | 573 | ||
574 | static int fsi_stream_probe(struct fsi_priv *fsi) | 574 | static int fsi_stream_probe(struct fsi_priv *fsi, struct device *dev) |
575 | { | 575 | { |
576 | struct fsi_stream *io; | 576 | struct fsi_stream *io; |
577 | int ret1, ret2; | 577 | int ret1, ret2; |
578 | 578 | ||
579 | io = &fsi->playback; | 579 | io = &fsi->playback; |
580 | ret1 = fsi_stream_handler_call(io, probe, fsi, io); | 580 | ret1 = fsi_stream_handler_call(io, probe, fsi, io, dev); |
581 | 581 | ||
582 | io = &fsi->capture; | 582 | io = &fsi->capture; |
583 | ret2 = fsi_stream_handler_call(io, probe, fsi, io); | 583 | ret2 = fsi_stream_handler_call(io, probe, fsi, io, dev); |
584 | 584 | ||
585 | if (ret1 < 0) | 585 | if (ret1 < 0) |
586 | return ret1; | 586 | return ret1; |
@@ -1089,13 +1089,10 @@ static void fsi_dma_do_tasklet(unsigned long data) | |||
1089 | { | 1089 | { |
1090 | struct fsi_stream *io = (struct fsi_stream *)data; | 1090 | struct fsi_stream *io = (struct fsi_stream *)data; |
1091 | struct fsi_priv *fsi = fsi_stream_to_priv(io); | 1091 | struct fsi_priv *fsi = fsi_stream_to_priv(io); |
1092 | struct dma_chan *chan; | ||
1093 | struct snd_soc_dai *dai; | 1092 | struct snd_soc_dai *dai; |
1094 | struct dma_async_tx_descriptor *desc; | 1093 | struct dma_async_tx_descriptor *desc; |
1095 | struct scatterlist sg; | ||
1096 | struct snd_pcm_runtime *runtime; | 1094 | struct snd_pcm_runtime *runtime; |
1097 | enum dma_data_direction dir; | 1095 | enum dma_data_direction dir; |
1098 | dma_cookie_t cookie; | ||
1099 | int is_play = fsi_stream_is_play(fsi, io); | 1096 | int is_play = fsi_stream_is_play(fsi, io); |
1100 | int len; | 1097 | int len; |
1101 | dma_addr_t buf; | 1098 | dma_addr_t buf; |
@@ -1104,7 +1101,6 @@ static void fsi_dma_do_tasklet(unsigned long data) | |||
1104 | return; | 1101 | return; |
1105 | 1102 | ||
1106 | dai = fsi_get_dai(io->substream); | 1103 | dai = fsi_get_dai(io->substream); |
1107 | chan = io->chan; | ||
1108 | runtime = io->substream->runtime; | 1104 | runtime = io->substream->runtime; |
1109 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1105 | dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
1110 | len = samples_to_bytes(runtime, io->period_samples); | 1106 | len = samples_to_bytes(runtime, io->period_samples); |
@@ -1112,14 +1108,8 @@ static void fsi_dma_do_tasklet(unsigned long data) | |||
1112 | 1108 | ||
1113 | dma_sync_single_for_device(dai->dev, buf, len, dir); | 1109 | dma_sync_single_for_device(dai->dev, buf, len, dir); |
1114 | 1110 | ||
1115 | sg_init_table(&sg, 1); | 1111 | desc = dmaengine_prep_slave_single(io->chan, buf, len, dir, |
1116 | sg_set_page(&sg, pfn_to_page(PFN_DOWN(buf)), | 1112 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); |
1117 | len , offset_in_page(buf)); | ||
1118 | sg_dma_address(&sg) = buf; | ||
1119 | sg_dma_len(&sg) = len; | ||
1120 | |||
1121 | desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, | ||
1122 | DMA_PREP_INTERRUPT | DMA_CTRL_ACK); | ||
1123 | if (!desc) { | 1113 | if (!desc) { |
1124 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); | 1114 | dev_err(dai->dev, "dmaengine_prep_slave_sg() fail\n"); |
1125 | return; | 1115 | return; |
@@ -1128,13 +1118,12 @@ static void fsi_dma_do_tasklet(unsigned long data) | |||
1128 | desc->callback = fsi_dma_complete; | 1118 | desc->callback = fsi_dma_complete; |
1129 | desc->callback_param = io; | 1119 | desc->callback_param = io; |
1130 | 1120 | ||
1131 | cookie = desc->tx_submit(desc); | 1121 | if (dmaengine_submit(desc) < 0) { |
1132 | if (cookie < 0) { | ||
1133 | dev_err(dai->dev, "tx_submit() fail\n"); | 1122 | dev_err(dai->dev, "tx_submit() fail\n"); |
1134 | return; | 1123 | return; |
1135 | } | 1124 | } |
1136 | 1125 | ||
1137 | dma_async_issue_pending(chan); | 1126 | dma_async_issue_pending(io->chan); |
1138 | 1127 | ||
1139 | /* | 1128 | /* |
1140 | * FIXME | 1129 | * FIXME |
@@ -1184,7 +1173,7 @@ static void fsi_dma_push_start_stop(struct fsi_priv *fsi, struct fsi_stream *io, | |||
1184 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); | 1173 | fsi_master_mask_set(master, CLK_RST, clk, (enable) ? clk : 0); |
1185 | } | 1174 | } |
1186 | 1175 | ||
1187 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) | 1176 | static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io, struct device *dev) |
1188 | { | 1177 | { |
1189 | dma_cap_mask_t mask; | 1178 | dma_cap_mask_t mask; |
1190 | 1179 | ||
@@ -1192,8 +1181,19 @@ static int fsi_dma_probe(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1192 | dma_cap_set(DMA_SLAVE, mask); | 1181 | dma_cap_set(DMA_SLAVE, mask); |
1193 | 1182 | ||
1194 | io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); | 1183 | io->chan = dma_request_channel(mask, fsi_dma_filter, &io->slave); |
1195 | if (!io->chan) | 1184 | if (!io->chan) { |
1196 | return -EIO; | 1185 | |
1186 | /* switch to PIO handler */ | ||
1187 | if (fsi_stream_is_play(fsi, io)) | ||
1188 | fsi->playback.handler = &fsi_pio_push_handler; | ||
1189 | else | ||
1190 | fsi->capture.handler = &fsi_pio_pop_handler; | ||
1191 | |||
1192 | dev_info(dev, "switch handler (dma => pio)\n"); | ||
1193 | |||
1194 | /* probe again */ | ||
1195 | return fsi_stream_probe(fsi, dev); | ||
1196 | } | ||
1197 | 1197 | ||
1198 | tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); | 1198 | tasklet_init(&io->tasklet, fsi_dma_do_tasklet, (unsigned long)io); |
1199 | 1199 | ||
@@ -1683,7 +1683,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
1683 | master->fsia.master = master; | 1683 | master->fsia.master = master; |
1684 | master->fsia.info = &info->port_a; | 1684 | master->fsia.info = &info->port_a; |
1685 | fsi_handler_init(&master->fsia); | 1685 | fsi_handler_init(&master->fsia); |
1686 | ret = fsi_stream_probe(&master->fsia); | 1686 | ret = fsi_stream_probe(&master->fsia, &pdev->dev); |
1687 | if (ret < 0) { | 1687 | if (ret < 0) { |
1688 | dev_err(&pdev->dev, "FSIA stream probe failed\n"); | 1688 | dev_err(&pdev->dev, "FSIA stream probe failed\n"); |
1689 | goto exit_iounmap; | 1689 | goto exit_iounmap; |
@@ -1694,7 +1694,7 @@ static int fsi_probe(struct platform_device *pdev) | |||
1694 | master->fsib.master = master; | 1694 | master->fsib.master = master; |
1695 | master->fsib.info = &info->port_b; | 1695 | master->fsib.info = &info->port_b; |
1696 | fsi_handler_init(&master->fsib); | 1696 | fsi_handler_init(&master->fsib); |
1697 | ret = fsi_stream_probe(&master->fsib); | 1697 | ret = fsi_stream_probe(&master->fsib, &pdev->dev); |
1698 | if (ret < 0) { | 1698 | if (ret < 0) { |
1699 | dev_err(&pdev->dev, "FSIB stream probe failed\n"); | 1699 | dev_err(&pdev->dev, "FSIB stream probe failed\n"); |
1700 | goto exit_fsia; | 1700 | goto exit_fsia; |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index b37ee8077ed1..f219b2f7ee68 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -812,13 +812,15 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
812 | 812 | ||
813 | /* Find CPU DAI from registered DAIs*/ | 813 | /* Find CPU DAI from registered DAIs*/ |
814 | list_for_each_entry(cpu_dai, &dai_list, list) { | 814 | list_for_each_entry(cpu_dai, &dai_list, list) { |
815 | if (dai_link->cpu_dai_of_node) { | 815 | if (dai_link->cpu_of_node && |
816 | if (cpu_dai->dev->of_node != dai_link->cpu_dai_of_node) | 816 | (cpu_dai->dev->of_node != dai_link->cpu_of_node)) |
817 | continue; | 817 | continue; |
818 | } else { | 818 | if (dai_link->cpu_name && |
819 | if (strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | 819 | strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) |
820 | continue; | 820 | continue; |
821 | } | 821 | if (dai_link->cpu_dai_name && |
822 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
823 | continue; | ||
822 | 824 | ||
823 | rtd->cpu_dai = cpu_dai; | 825 | rtd->cpu_dai = cpu_dai; |
824 | } | 826 | } |
@@ -896,6 +898,28 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
896 | return 0; | 898 | return 0; |
897 | } | 899 | } |
898 | 900 | ||
901 | static int soc_remove_platform(struct snd_soc_platform *platform) | ||
902 | { | ||
903 | int ret; | ||
904 | |||
905 | if (platform->driver->remove) { | ||
906 | ret = platform->driver->remove(platform); | ||
907 | if (ret < 0) | ||
908 | pr_err("asoc: failed to remove %s: %d\n", | ||
909 | platform->name, ret); | ||
910 | } | ||
911 | |||
912 | /* Make sure all DAPM widgets are freed */ | ||
913 | snd_soc_dapm_free(&platform->dapm); | ||
914 | |||
915 | soc_cleanup_platform_debugfs(platform); | ||
916 | platform->probed = 0; | ||
917 | list_del(&platform->card_list); | ||
918 | module_put(platform->dev->driver->owner); | ||
919 | |||
920 | return 0; | ||
921 | } | ||
922 | |||
899 | static void soc_remove_codec(struct snd_soc_codec *codec) | 923 | static void soc_remove_codec(struct snd_soc_codec *codec) |
900 | { | 924 | { |
901 | int err; | 925 | int err; |
@@ -917,11 +941,9 @@ static void soc_remove_codec(struct snd_soc_codec *codec) | |||
917 | module_put(codec->dev->driver->owner); | 941 | module_put(codec->dev->driver->owner); |
918 | } | 942 | } |
919 | 943 | ||
920 | static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | 944 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) |
921 | { | 945 | { |
922 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 946 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
923 | struct snd_soc_codec *codec = rtd->codec; | ||
924 | struct snd_soc_platform *platform = rtd->platform; | ||
925 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; | 947 | struct snd_soc_dai *codec_dai = rtd->codec_dai, *cpu_dai = rtd->cpu_dai; |
926 | int err; | 948 | int err; |
927 | 949 | ||
@@ -946,30 +968,6 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | |||
946 | list_del(&codec_dai->card_list); | 968 | list_del(&codec_dai->card_list); |
947 | } | 969 | } |
948 | 970 | ||
949 | /* remove the platform */ | ||
950 | if (platform && platform->probed && | ||
951 | platform->driver->remove_order == order) { | ||
952 | if (platform->driver->remove) { | ||
953 | err = platform->driver->remove(platform); | ||
954 | if (err < 0) | ||
955 | pr_err("asoc: failed to remove %s: %d\n", | ||
956 | platform->name, err); | ||
957 | } | ||
958 | |||
959 | /* Make sure all DAPM widgets are freed */ | ||
960 | snd_soc_dapm_free(&platform->dapm); | ||
961 | |||
962 | soc_cleanup_platform_debugfs(platform); | ||
963 | platform->probed = 0; | ||
964 | list_del(&platform->card_list); | ||
965 | module_put(platform->dev->driver->owner); | ||
966 | } | ||
967 | |||
968 | /* remove the CODEC */ | ||
969 | if (codec && codec->probed && | ||
970 | codec->driver->remove_order == order) | ||
971 | soc_remove_codec(codec); | ||
972 | |||
973 | /* remove the cpu_dai */ | 971 | /* remove the cpu_dai */ |
974 | if (cpu_dai && cpu_dai->probed && | 972 | if (cpu_dai && cpu_dai->probed && |
975 | cpu_dai->driver->remove_order == order) { | 973 | cpu_dai->driver->remove_order == order) { |
@@ -981,7 +979,43 @@ static void soc_remove_dai_link(struct snd_soc_card *card, int num, int order) | |||
981 | } | 979 | } |
982 | cpu_dai->probed = 0; | 980 | cpu_dai->probed = 0; |
983 | list_del(&cpu_dai->card_list); | 981 | list_del(&cpu_dai->card_list); |
984 | module_put(cpu_dai->dev->driver->owner); | 982 | |
983 | if (!cpu_dai->codec) { | ||
984 | snd_soc_dapm_free(&cpu_dai->dapm); | ||
985 | module_put(cpu_dai->dev->driver->owner); | ||
986 | } | ||
987 | } | ||
988 | } | ||
989 | |||
990 | static void soc_remove_link_components(struct snd_soc_card *card, int num, | ||
991 | int order) | ||
992 | { | ||
993 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | ||
994 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
995 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
996 | struct snd_soc_platform *platform = rtd->platform; | ||
997 | struct snd_soc_codec *codec; | ||
998 | |||
999 | /* remove the platform */ | ||
1000 | if (platform && platform->probed && | ||
1001 | platform->driver->remove_order == order) { | ||
1002 | soc_remove_platform(platform); | ||
1003 | } | ||
1004 | |||
1005 | /* remove the CODEC-side CODEC */ | ||
1006 | if (codec_dai) { | ||
1007 | codec = codec_dai->codec; | ||
1008 | if (codec && codec->probed && | ||
1009 | codec->driver->remove_order == order) | ||
1010 | soc_remove_codec(codec); | ||
1011 | } | ||
1012 | |||
1013 | /* remove any CPU-side CODEC */ | ||
1014 | if (cpu_dai) { | ||
1015 | codec = cpu_dai->codec; | ||
1016 | if (codec && codec->probed && | ||
1017 | codec->driver->remove_order == order) | ||
1018 | soc_remove_codec(codec); | ||
985 | } | 1019 | } |
986 | } | 1020 | } |
987 | 1021 | ||
@@ -992,8 +1026,15 @@ static void soc_remove_dai_links(struct snd_soc_card *card) | |||
992 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | 1026 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; |
993 | order++) { | 1027 | order++) { |
994 | for (dai = 0; dai < card->num_rtd; dai++) | 1028 | for (dai = 0; dai < card->num_rtd; dai++) |
995 | soc_remove_dai_link(card, dai, order); | 1029 | soc_remove_link_dais(card, dai, order); |
996 | } | 1030 | } |
1031 | |||
1032 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | ||
1033 | order++) { | ||
1034 | for (dai = 0; dai < card->num_rtd; dai++) | ||
1035 | soc_remove_link_components(card, dai, order); | ||
1036 | } | ||
1037 | |||
997 | card->num_rtd = 0; | 1038 | card->num_rtd = 0; |
998 | } | 1039 | } |
999 | 1040 | ||
@@ -1054,6 +1095,10 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1054 | } | 1095 | } |
1055 | } | 1096 | } |
1056 | 1097 | ||
1098 | /* If the driver didn't set I/O up try regmap */ | ||
1099 | if (!codec->control_data) | ||
1100 | snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); | ||
1101 | |||
1057 | if (driver->controls) | 1102 | if (driver->controls) |
1058 | snd_soc_add_codec_controls(codec, driver->controls, | 1103 | snd_soc_add_codec_controls(codec, driver->controls, |
1059 | driver->num_controls); | 1104 | driver->num_controls); |
@@ -1230,7 +1275,44 @@ out: | |||
1230 | return 0; | 1275 | return 0; |
1231 | } | 1276 | } |
1232 | 1277 | ||
1233 | static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | 1278 | static int soc_probe_link_components(struct snd_soc_card *card, int num, |
1279 | int order) | ||
1280 | { | ||
1281 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | ||
1282 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1283 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
1284 | struct snd_soc_platform *platform = rtd->platform; | ||
1285 | int ret; | ||
1286 | |||
1287 | /* probe the CPU-side component, if it is a CODEC */ | ||
1288 | if (cpu_dai->codec && | ||
1289 | !cpu_dai->codec->probed && | ||
1290 | cpu_dai->codec->driver->probe_order == order) { | ||
1291 | ret = soc_probe_codec(card, cpu_dai->codec); | ||
1292 | if (ret < 0) | ||
1293 | return ret; | ||
1294 | } | ||
1295 | |||
1296 | /* probe the CODEC-side component */ | ||
1297 | if (!codec_dai->codec->probed && | ||
1298 | codec_dai->codec->driver->probe_order == order) { | ||
1299 | ret = soc_probe_codec(card, codec_dai->codec); | ||
1300 | if (ret < 0) | ||
1301 | return ret; | ||
1302 | } | ||
1303 | |||
1304 | /* probe the platform */ | ||
1305 | if (!platform->probed && | ||
1306 | platform->driver->probe_order == order) { | ||
1307 | ret = soc_probe_platform(card, platform); | ||
1308 | if (ret < 0) | ||
1309 | return ret; | ||
1310 | } | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||
1314 | |||
1315 | static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | ||
1234 | { | 1316 | { |
1235 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 1317 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
1236 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1318 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
@@ -1255,11 +1337,14 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | |||
1255 | /* probe the cpu_dai */ | 1337 | /* probe the cpu_dai */ |
1256 | if (!cpu_dai->probed && | 1338 | if (!cpu_dai->probed && |
1257 | cpu_dai->driver->probe_order == order) { | 1339 | cpu_dai->driver->probe_order == order) { |
1258 | cpu_dai->dapm.card = card; | 1340 | if (!cpu_dai->codec) { |
1259 | if (!try_module_get(cpu_dai->dev->driver->owner)) | 1341 | cpu_dai->dapm.card = card; |
1260 | return -ENODEV; | 1342 | if (!try_module_get(cpu_dai->dev->driver->owner)) |
1343 | return -ENODEV; | ||
1261 | 1344 | ||
1262 | snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai); | 1345 | list_add(&cpu_dai->dapm.list, &card->dapm_list); |
1346 | snd_soc_dapm_new_dai_widgets(&cpu_dai->dapm, cpu_dai); | ||
1347 | } | ||
1263 | 1348 | ||
1264 | if (cpu_dai->driver->probe) { | 1349 | if (cpu_dai->driver->probe) { |
1265 | ret = cpu_dai->driver->probe(cpu_dai); | 1350 | ret = cpu_dai->driver->probe(cpu_dai); |
@@ -1275,22 +1360,6 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) | |||
1275 | list_add(&cpu_dai->card_list, &card->dai_dev_list); | 1360 | list_add(&cpu_dai->card_list, &card->dai_dev_list); |
1276 | } | 1361 | } |
1277 | 1362 | ||
1278 | /* probe the CODEC */ | ||
1279 | if (!codec->probed && | ||
1280 | codec->driver->probe_order == order) { | ||
1281 | ret = soc_probe_codec(card, codec); | ||
1282 | if (ret < 0) | ||
1283 | return ret; | ||
1284 | } | ||
1285 | |||
1286 | /* probe the platform */ | ||
1287 | if (!platform->probed && | ||
1288 | platform->driver->probe_order == order) { | ||
1289 | ret = soc_probe_platform(card, platform); | ||
1290 | if (ret < 0) | ||
1291 | return ret; | ||
1292 | } | ||
1293 | |||
1294 | /* probe the CODEC DAI */ | 1363 | /* probe the CODEC DAI */ |
1295 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { | 1364 | if (!codec_dai->probed && codec_dai->driver->probe_order == order) { |
1296 | if (codec_dai->driver->probe) { | 1365 | if (codec_dai->driver->probe) { |
@@ -1565,14 +1634,27 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) | |||
1565 | goto card_probe_error; | 1634 | goto card_probe_error; |
1566 | } | 1635 | } |
1567 | 1636 | ||
1568 | /* early DAI link probe */ | 1637 | /* probe all components used by DAI links on this card */ |
1569 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | 1638 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; |
1570 | order++) { | 1639 | order++) { |
1571 | for (i = 0; i < card->num_links; i++) { | 1640 | for (i = 0; i < card->num_links; i++) { |
1572 | ret = soc_probe_dai_link(card, i, order); | 1641 | ret = soc_probe_link_components(card, i, order); |
1573 | if (ret < 0) { | 1642 | if (ret < 0) { |
1574 | pr_err("asoc: failed to instantiate card %s: %d\n", | 1643 | pr_err("asoc: failed to instantiate card %s: %d\n", |
1575 | card->name, ret); | 1644 | card->name, ret); |
1645 | goto probe_dai_err; | ||
1646 | } | ||
1647 | } | ||
1648 | } | ||
1649 | |||
1650 | /* probe all DAI links on this card */ | ||
1651 | for (order = SND_SOC_COMP_ORDER_FIRST; order <= SND_SOC_COMP_ORDER_LAST; | ||
1652 | order++) { | ||
1653 | for (i = 0; i < card->num_links; i++) { | ||
1654 | ret = soc_probe_link_dais(card, i, order); | ||
1655 | if (ret < 0) { | ||
1656 | pr_err("asoc: failed to instantiate card %s: %d\n", | ||
1657 | card->name, ret); | ||
1576 | goto probe_dai_err; | 1658 | goto probe_dai_err; |
1577 | } | 1659 | } |
1578 | } | 1660 | } |
@@ -2790,6 +2872,104 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol, | |||
2790 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); | 2872 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); |
2791 | 2873 | ||
2792 | /** | 2874 | /** |
2875 | * snd_soc_info_volsw_range - single mixer info callback with range. | ||
2876 | * @kcontrol: mixer control | ||
2877 | * @uinfo: control element information | ||
2878 | * | ||
2879 | * Callback to provide information, within a range, about a single | ||
2880 | * mixer control. | ||
2881 | * | ||
2882 | * returns 0 for success. | ||
2883 | */ | ||
2884 | int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, | ||
2885 | struct snd_ctl_elem_info *uinfo) | ||
2886 | { | ||
2887 | struct soc_mixer_control *mc = | ||
2888 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2889 | int platform_max; | ||
2890 | int min = mc->min; | ||
2891 | |||
2892 | if (!mc->platform_max) | ||
2893 | mc->platform_max = mc->max; | ||
2894 | platform_max = mc->platform_max; | ||
2895 | |||
2896 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
2897 | uinfo->count = 1; | ||
2898 | uinfo->value.integer.min = 0; | ||
2899 | uinfo->value.integer.max = platform_max - min; | ||
2900 | |||
2901 | return 0; | ||
2902 | } | ||
2903 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); | ||
2904 | |||
2905 | /** | ||
2906 | * snd_soc_put_volsw_range - single mixer put value callback with range. | ||
2907 | * @kcontrol: mixer control | ||
2908 | * @ucontrol: control element information | ||
2909 | * | ||
2910 | * Callback to set the value, within a range, for a single mixer control. | ||
2911 | * | ||
2912 | * Returns 0 for success. | ||
2913 | */ | ||
2914 | int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | ||
2915 | struct snd_ctl_elem_value *ucontrol) | ||
2916 | { | ||
2917 | struct soc_mixer_control *mc = | ||
2918 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2919 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2920 | unsigned int reg = mc->reg; | ||
2921 | unsigned int shift = mc->shift; | ||
2922 | int min = mc->min; | ||
2923 | int max = mc->max; | ||
2924 | unsigned int mask = (1 << fls(max)) - 1; | ||
2925 | unsigned int invert = mc->invert; | ||
2926 | unsigned int val, val_mask; | ||
2927 | |||
2928 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2929 | if (invert) | ||
2930 | val = max - val; | ||
2931 | val_mask = mask << shift; | ||
2932 | val = val << shift; | ||
2933 | |||
2934 | return snd_soc_update_bits_locked(codec, reg, val_mask, val); | ||
2935 | } | ||
2936 | EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); | ||
2937 | |||
2938 | /** | ||
2939 | * snd_soc_get_volsw_range - single mixer get callback with range | ||
2940 | * @kcontrol: mixer control | ||
2941 | * @ucontrol: control element information | ||
2942 | * | ||
2943 | * Callback to get the value, within a range, of a single mixer control. | ||
2944 | * | ||
2945 | * Returns 0 for success. | ||
2946 | */ | ||
2947 | int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | ||
2948 | struct snd_ctl_elem_value *ucontrol) | ||
2949 | { | ||
2950 | struct soc_mixer_control *mc = | ||
2951 | (struct soc_mixer_control *)kcontrol->private_value; | ||
2952 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2953 | unsigned int reg = mc->reg; | ||
2954 | unsigned int shift = mc->shift; | ||
2955 | int min = mc->min; | ||
2956 | int max = mc->max; | ||
2957 | unsigned int mask = (1 << fls(max)) - 1; | ||
2958 | unsigned int invert = mc->invert; | ||
2959 | |||
2960 | ucontrol->value.integer.value[0] = | ||
2961 | (snd_soc_read(codec, reg) >> shift) & mask; | ||
2962 | if (invert) | ||
2963 | ucontrol->value.integer.value[0] = | ||
2964 | max - ucontrol->value.integer.value[0]; | ||
2965 | ucontrol->value.integer.value[0] = | ||
2966 | ucontrol->value.integer.value[0] - min; | ||
2967 | |||
2968 | return 0; | ||
2969 | } | ||
2970 | EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); | ||
2971 | |||
2972 | /** | ||
2793 | * snd_soc_limit_volume - Set new limit to an existing volume control. | 2973 | * snd_soc_limit_volume - Set new limit to an existing volume control. |
2794 | * | 2974 | * |
2795 | * @codec: where to look for the control | 2975 | * @codec: where to look for the control |
@@ -3346,6 +3526,12 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3346 | link->name); | 3526 | link->name); |
3347 | return -EINVAL; | 3527 | return -EINVAL; |
3348 | } | 3528 | } |
3529 | /* Codec DAI name must be specified */ | ||
3530 | if (!link->codec_dai_name) { | ||
3531 | dev_err(card->dev, "codec_dai_name not set for %s\n", | ||
3532 | link->name); | ||
3533 | return -EINVAL; | ||
3534 | } | ||
3349 | 3535 | ||
3350 | /* | 3536 | /* |
3351 | * Platform may be specified by either name or OF node, but | 3537 | * Platform may be specified by either name or OF node, but |
@@ -3358,12 +3544,24 @@ int snd_soc_register_card(struct snd_soc_card *card) | |||
3358 | } | 3544 | } |
3359 | 3545 | ||
3360 | /* | 3546 | /* |
3361 | * CPU DAI must be specified by 1 of name or OF node, | 3547 | * CPU device may be specified by either name or OF node, but |
3362 | * not both or neither. | 3548 | * can be left unspecified, and will be matched based on DAI |
3549 | * name alone.. | ||
3550 | */ | ||
3551 | if (link->cpu_name && link->cpu_of_node) { | ||
3552 | dev_err(card->dev, | ||
3553 | "Neither/both cpu name/of_node are set for %s\n", | ||
3554 | link->name); | ||
3555 | return -EINVAL; | ||
3556 | } | ||
3557 | /* | ||
3558 | * At least one of CPU DAI name or CPU device name/node must be | ||
3559 | * specified | ||
3363 | */ | 3560 | */ |
3364 | if (!!link->cpu_dai_name == !!link->cpu_dai_of_node) { | 3561 | if (!link->cpu_dai_name && |
3562 | !(link->cpu_name || link->cpu_of_node)) { | ||
3365 | dev_err(card->dev, | 3563 | dev_err(card->dev, |
3366 | "Neither/both cpu_dai name/of_node are set for %s\n", | 3564 | "Neither cpu_dai_name nor cpu_name/of_node are set for %s\n", |
3367 | link->name); | 3565 | link->name); |
3368 | return -EINVAL; | 3566 | return -EINVAL; |
3369 | } | 3567 | } |
@@ -3938,6 +4136,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
3938 | dev_err(card->dev, | 4136 | dev_err(card->dev, |
3939 | "Property '%s' index %d could not be read: %d\n", | 4137 | "Property '%s' index %d could not be read: %d\n", |
3940 | propname, 2 * i, ret); | 4138 | propname, 2 * i, ret); |
4139 | kfree(routes); | ||
3941 | return -EINVAL; | 4140 | return -EINVAL; |
3942 | } | 4141 | } |
3943 | ret = of_property_read_string_index(np, propname, | 4142 | ret = of_property_read_string_index(np, propname, |
@@ -3946,6 +4145,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
3946 | dev_err(card->dev, | 4145 | dev_err(card->dev, |
3947 | "Property '%s' index %d could not be read: %d\n", | 4146 | "Property '%s' index %d could not be read: %d\n", |
3948 | propname, (2 * i) + 1, ret); | 4147 | propname, (2 * i) + 1, ret); |
4148 | kfree(routes); | ||
3949 | return -EINVAL; | 4149 | return -EINVAL; |
3950 | } | 4150 | } |
3951 | } | 4151 | } |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 89eae93445cf..f7a13f720529 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/debugfs.h> | 35 | #include <linux/debugfs.h> |
36 | #include <linux/pm_runtime.h> | 36 | #include <linux/pm_runtime.h> |
37 | #include <linux/regulator/consumer.h> | 37 | #include <linux/regulator/consumer.h> |
38 | #include <linux/clk.h> | ||
38 | #include <linux/slab.h> | 39 | #include <linux/slab.h> |
39 | #include <sound/core.h> | 40 | #include <sound/core.h> |
40 | #include <sound/pcm.h> | 41 | #include <sound/pcm.h> |
@@ -51,6 +52,7 @@ static int dapm_up_seq[] = { | |||
51 | [snd_soc_dapm_pre] = 0, | 52 | [snd_soc_dapm_pre] = 0, |
52 | [snd_soc_dapm_supply] = 1, | 53 | [snd_soc_dapm_supply] = 1, |
53 | [snd_soc_dapm_regulator_supply] = 1, | 54 | [snd_soc_dapm_regulator_supply] = 1, |
55 | [snd_soc_dapm_clock_supply] = 1, | ||
54 | [snd_soc_dapm_micbias] = 2, | 56 | [snd_soc_dapm_micbias] = 2, |
55 | [snd_soc_dapm_dai_link] = 2, | 57 | [snd_soc_dapm_dai_link] = 2, |
56 | [snd_soc_dapm_dai] = 3, | 58 | [snd_soc_dapm_dai] = 3, |
@@ -92,6 +94,7 @@ static int dapm_down_seq[] = { | |||
92 | [snd_soc_dapm_aif_out] = 10, | 94 | [snd_soc_dapm_aif_out] = 10, |
93 | [snd_soc_dapm_dai] = 10, | 95 | [snd_soc_dapm_dai] = 10, |
94 | [snd_soc_dapm_dai_link] = 11, | 96 | [snd_soc_dapm_dai_link] = 11, |
97 | [snd_soc_dapm_clock_supply] = 12, | ||
95 | [snd_soc_dapm_regulator_supply] = 12, | 98 | [snd_soc_dapm_regulator_supply] = 12, |
96 | [snd_soc_dapm_supply] = 12, | 99 | [snd_soc_dapm_supply] = 12, |
97 | [snd_soc_dapm_post] = 13, | 100 | [snd_soc_dapm_post] = 13, |
@@ -391,6 +394,7 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
391 | case snd_soc_dapm_vmid: | 394 | case snd_soc_dapm_vmid: |
392 | case snd_soc_dapm_supply: | 395 | case snd_soc_dapm_supply: |
393 | case snd_soc_dapm_regulator_supply: | 396 | case snd_soc_dapm_regulator_supply: |
397 | case snd_soc_dapm_clock_supply: | ||
394 | case snd_soc_dapm_aif_in: | 398 | case snd_soc_dapm_aif_in: |
395 | case snd_soc_dapm_aif_out: | 399 | case snd_soc_dapm_aif_out: |
396 | case snd_soc_dapm_dai: | 400 | case snd_soc_dapm_dai: |
@@ -764,6 +768,7 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget, | |||
764 | switch (widget->id) { | 768 | switch (widget->id) { |
765 | case snd_soc_dapm_supply: | 769 | case snd_soc_dapm_supply: |
766 | case snd_soc_dapm_regulator_supply: | 770 | case snd_soc_dapm_regulator_supply: |
771 | case snd_soc_dapm_clock_supply: | ||
767 | return 0; | 772 | return 0; |
768 | default: | 773 | default: |
769 | break; | 774 | break; |
@@ -850,6 +855,7 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget, | |||
850 | switch (widget->id) { | 855 | switch (widget->id) { |
851 | case snd_soc_dapm_supply: | 856 | case snd_soc_dapm_supply: |
852 | case snd_soc_dapm_regulator_supply: | 857 | case snd_soc_dapm_regulator_supply: |
858 | case snd_soc_dapm_clock_supply: | ||
853 | return 0; | 859 | return 0; |
854 | default: | 860 | default: |
855 | break; | 861 | break; |
@@ -996,6 +1002,27 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
996 | } | 1002 | } |
997 | EXPORT_SYMBOL_GPL(dapm_regulator_event); | 1003 | EXPORT_SYMBOL_GPL(dapm_regulator_event); |
998 | 1004 | ||
1005 | /* | ||
1006 | * Handler for clock supply widget. | ||
1007 | */ | ||
1008 | int dapm_clock_event(struct snd_soc_dapm_widget *w, | ||
1009 | struct snd_kcontrol *kcontrol, int event) | ||
1010 | { | ||
1011 | if (!w->clk) | ||
1012 | return -EIO; | ||
1013 | |||
1014 | #ifdef CONFIG_HAVE_CLK | ||
1015 | if (SND_SOC_DAPM_EVENT_ON(event)) { | ||
1016 | return clk_enable(w->clk); | ||
1017 | } else { | ||
1018 | clk_disable(w->clk); | ||
1019 | return 0; | ||
1020 | } | ||
1021 | #endif | ||
1022 | return 0; | ||
1023 | } | ||
1024 | EXPORT_SYMBOL_GPL(dapm_clock_event); | ||
1025 | |||
999 | static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) | 1026 | static int dapm_widget_power_check(struct snd_soc_dapm_widget *w) |
1000 | { | 1027 | { |
1001 | if (w->power_checked) | 1028 | if (w->power_checked) |
@@ -1487,6 +1514,7 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power, | |||
1487 | switch (w->id) { | 1514 | switch (w->id) { |
1488 | case snd_soc_dapm_supply: | 1515 | case snd_soc_dapm_supply: |
1489 | case snd_soc_dapm_regulator_supply: | 1516 | case snd_soc_dapm_regulator_supply: |
1517 | case snd_soc_dapm_clock_supply: | ||
1490 | /* Supplies can't affect their outputs, only their inputs */ | 1518 | /* Supplies can't affect their outputs, only their inputs */ |
1491 | break; | 1519 | break; |
1492 | default: | 1520 | default: |
@@ -1587,6 +1615,7 @@ static int dapm_power_widgets(struct snd_soc_dapm_context *dapm, int event) | |||
1587 | break; | 1615 | break; |
1588 | case snd_soc_dapm_supply: | 1616 | case snd_soc_dapm_supply: |
1589 | case snd_soc_dapm_regulator_supply: | 1617 | case snd_soc_dapm_regulator_supply: |
1618 | case snd_soc_dapm_clock_supply: | ||
1590 | case snd_soc_dapm_micbias: | 1619 | case snd_soc_dapm_micbias: |
1591 | if (d->target_bias_level < SND_SOC_BIAS_STANDBY) | 1620 | if (d->target_bias_level < SND_SOC_BIAS_STANDBY) |
1592 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | 1621 | d->target_bias_level = SND_SOC_BIAS_STANDBY; |
@@ -1941,6 +1970,7 @@ static ssize_t dapm_widget_show(struct device *dev, | |||
1941 | case snd_soc_dapm_mixer_named_ctl: | 1970 | case snd_soc_dapm_mixer_named_ctl: |
1942 | case snd_soc_dapm_supply: | 1971 | case snd_soc_dapm_supply: |
1943 | case snd_soc_dapm_regulator_supply: | 1972 | case snd_soc_dapm_regulator_supply: |
1973 | case snd_soc_dapm_clock_supply: | ||
1944 | if (w->name) | 1974 | if (w->name) |
1945 | count += sprintf(buf + count, "%s: %s\n", | 1975 | count += sprintf(buf + count, "%s: %s\n", |
1946 | w->name, w->power ? "On":"Off"); | 1976 | w->name, w->power ? "On":"Off"); |
@@ -2187,6 +2217,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2187 | case snd_soc_dapm_post: | 2217 | case snd_soc_dapm_post: |
2188 | case snd_soc_dapm_supply: | 2218 | case snd_soc_dapm_supply: |
2189 | case snd_soc_dapm_regulator_supply: | 2219 | case snd_soc_dapm_regulator_supply: |
2220 | case snd_soc_dapm_clock_supply: | ||
2190 | case snd_soc_dapm_aif_in: | 2221 | case snd_soc_dapm_aif_in: |
2191 | case snd_soc_dapm_aif_out: | 2222 | case snd_soc_dapm_aif_out: |
2192 | case snd_soc_dapm_dai: | 2223 | case snd_soc_dapm_dai: |
@@ -2221,6 +2252,10 @@ static int snd_soc_dapm_add_route(struct snd_soc_dapm_context *dapm, | |||
2221 | path->connect = 0; | 2252 | path->connect = 0; |
2222 | return 0; | 2253 | return 0; |
2223 | } | 2254 | } |
2255 | |||
2256 | dapm_mark_dirty(wsource, "Route added"); | ||
2257 | dapm_mark_dirty(wsink, "Route added"); | ||
2258 | |||
2224 | return 0; | 2259 | return 0; |
2225 | 2260 | ||
2226 | err: | 2261 | err: |
@@ -2230,6 +2265,59 @@ err: | |||
2230 | return ret; | 2265 | return ret; |
2231 | } | 2266 | } |
2232 | 2267 | ||
2268 | static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm, | ||
2269 | const struct snd_soc_dapm_route *route) | ||
2270 | { | ||
2271 | struct snd_soc_dapm_path *path, *p; | ||
2272 | const char *sink; | ||
2273 | const char *source; | ||
2274 | char prefixed_sink[80]; | ||
2275 | char prefixed_source[80]; | ||
2276 | |||
2277 | if (route->control) { | ||
2278 | dev_err(dapm->dev, | ||
2279 | "Removal of routes with controls not supported\n"); | ||
2280 | return -EINVAL; | ||
2281 | } | ||
2282 | |||
2283 | if (dapm->codec && dapm->codec->name_prefix) { | ||
2284 | snprintf(prefixed_sink, sizeof(prefixed_sink), "%s %s", | ||
2285 | dapm->codec->name_prefix, route->sink); | ||
2286 | sink = prefixed_sink; | ||
2287 | snprintf(prefixed_source, sizeof(prefixed_source), "%s %s", | ||
2288 | dapm->codec->name_prefix, route->source); | ||
2289 | source = prefixed_source; | ||
2290 | } else { | ||
2291 | sink = route->sink; | ||
2292 | source = route->source; | ||
2293 | } | ||
2294 | |||
2295 | path = NULL; | ||
2296 | list_for_each_entry(p, &dapm->card->paths, list) { | ||
2297 | if (strcmp(p->source->name, source) != 0) | ||
2298 | continue; | ||
2299 | if (strcmp(p->sink->name, sink) != 0) | ||
2300 | continue; | ||
2301 | path = p; | ||
2302 | break; | ||
2303 | } | ||
2304 | |||
2305 | if (path) { | ||
2306 | dapm_mark_dirty(path->source, "Route removed"); | ||
2307 | dapm_mark_dirty(path->sink, "Route removed"); | ||
2308 | |||
2309 | list_del(&path->list); | ||
2310 | list_del(&path->list_sink); | ||
2311 | list_del(&path->list_source); | ||
2312 | kfree(path); | ||
2313 | } else { | ||
2314 | dev_warn(dapm->dev, "Route %s->%s does not exist\n", | ||
2315 | source, sink); | ||
2316 | } | ||
2317 | |||
2318 | return 0; | ||
2319 | } | ||
2320 | |||
2233 | /** | 2321 | /** |
2234 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets | 2322 | * snd_soc_dapm_add_routes - Add routes between DAPM widgets |
2235 | * @dapm: DAPM context | 2323 | * @dapm: DAPM context |
@@ -2246,15 +2334,15 @@ err: | |||
2246 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | 2334 | int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, |
2247 | const struct snd_soc_dapm_route *route, int num) | 2335 | const struct snd_soc_dapm_route *route, int num) |
2248 | { | 2336 | { |
2249 | int i, ret = 0; | 2337 | int i, r, ret = 0; |
2250 | 2338 | ||
2251 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | 2339 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); |
2252 | for (i = 0; i < num; i++) { | 2340 | for (i = 0; i < num; i++) { |
2253 | ret = snd_soc_dapm_add_route(dapm, route); | 2341 | r = snd_soc_dapm_add_route(dapm, route); |
2254 | if (ret < 0) { | 2342 | if (r < 0) { |
2255 | dev_err(dapm->dev, "Failed to add route %s->%s\n", | 2343 | dev_err(dapm->dev, "Failed to add route %s->%s\n", |
2256 | route->source, route->sink); | 2344 | route->source, route->sink); |
2257 | break; | 2345 | ret = r; |
2258 | } | 2346 | } |
2259 | route++; | 2347 | route++; |
2260 | } | 2348 | } |
@@ -2264,6 +2352,30 @@ int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm, | |||
2264 | } | 2352 | } |
2265 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); | 2353 | EXPORT_SYMBOL_GPL(snd_soc_dapm_add_routes); |
2266 | 2354 | ||
2355 | /** | ||
2356 | * snd_soc_dapm_del_routes - Remove routes between DAPM widgets | ||
2357 | * @dapm: DAPM context | ||
2358 | * @route: audio routes | ||
2359 | * @num: number of routes | ||
2360 | * | ||
2361 | * Removes routes from the DAPM context. | ||
2362 | */ | ||
2363 | int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, | ||
2364 | const struct snd_soc_dapm_route *route, int num) | ||
2365 | { | ||
2366 | int i, ret = 0; | ||
2367 | |||
2368 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_INIT); | ||
2369 | for (i = 0; i < num; i++) { | ||
2370 | snd_soc_dapm_del_route(dapm, route); | ||
2371 | route++; | ||
2372 | } | ||
2373 | mutex_unlock(&dapm->card->dapm_mutex); | ||
2374 | |||
2375 | return ret; | ||
2376 | } | ||
2377 | EXPORT_SYMBOL_GPL(snd_soc_dapm_del_routes); | ||
2378 | |||
2267 | static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, | 2379 | static int snd_soc_dapm_weak_route(struct snd_soc_dapm_context *dapm, |
2268 | const struct snd_soc_dapm_route *route) | 2380 | const struct snd_soc_dapm_route *route) |
2269 | { | 2381 | { |
@@ -2434,23 +2546,20 @@ int snd_soc_dapm_get_volsw(struct snd_kcontrol *kcontrol, | |||
2434 | (struct soc_mixer_control *)kcontrol->private_value; | 2546 | (struct soc_mixer_control *)kcontrol->private_value; |
2435 | unsigned int reg = mc->reg; | 2547 | unsigned int reg = mc->reg; |
2436 | unsigned int shift = mc->shift; | 2548 | unsigned int shift = mc->shift; |
2437 | unsigned int rshift = mc->rshift; | ||
2438 | int max = mc->max; | 2549 | int max = mc->max; |
2439 | unsigned int invert = mc->invert; | ||
2440 | unsigned int mask = (1 << fls(max)) - 1; | 2550 | unsigned int mask = (1 << fls(max)) - 1; |
2551 | unsigned int invert = mc->invert; | ||
2552 | |||
2553 | if (snd_soc_volsw_is_stereo(mc)) | ||
2554 | dev_warn(widget->dapm->dev, | ||
2555 | "Control '%s' is stereo, which is not supported\n", | ||
2556 | kcontrol->id.name); | ||
2441 | 2557 | ||
2442 | ucontrol->value.integer.value[0] = | 2558 | ucontrol->value.integer.value[0] = |
2443 | (snd_soc_read(widget->codec, reg) >> shift) & mask; | 2559 | (snd_soc_read(widget->codec, reg) >> shift) & mask; |
2444 | if (shift != rshift) | 2560 | if (invert) |
2445 | ucontrol->value.integer.value[1] = | ||
2446 | (snd_soc_read(widget->codec, reg) >> rshift) & mask; | ||
2447 | if (invert) { | ||
2448 | ucontrol->value.integer.value[0] = | 2561 | ucontrol->value.integer.value[0] = |
2449 | max - ucontrol->value.integer.value[0]; | 2562 | max - ucontrol->value.integer.value[0]; |
2450 | if (shift != rshift) | ||
2451 | ucontrol->value.integer.value[1] = | ||
2452 | max - ucontrol->value.integer.value[1]; | ||
2453 | } | ||
2454 | 2563 | ||
2455 | return 0; | 2564 | return 0; |
2456 | } | 2565 | } |
@@ -2484,20 +2593,19 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, | |||
2484 | struct snd_soc_dapm_update update; | 2593 | struct snd_soc_dapm_update update; |
2485 | int wi; | 2594 | int wi; |
2486 | 2595 | ||
2596 | if (snd_soc_volsw_is_stereo(mc)) | ||
2597 | dev_warn(widget->dapm->dev, | ||
2598 | "Control '%s' is stereo, which is not supported\n", | ||
2599 | kcontrol->id.name); | ||
2600 | |||
2487 | val = (ucontrol->value.integer.value[0] & mask); | 2601 | val = (ucontrol->value.integer.value[0] & mask); |
2602 | connect = !!val; | ||
2488 | 2603 | ||
2489 | if (invert) | 2604 | if (invert) |
2490 | val = max - val; | 2605 | val = max - val; |
2491 | mask = mask << shift; | 2606 | mask = mask << shift; |
2492 | val = val << shift; | 2607 | val = val << shift; |
2493 | 2608 | ||
2494 | if (val) | ||
2495 | /* new connection */ | ||
2496 | connect = invert ? 0 : 1; | ||
2497 | else | ||
2498 | /* old connection must be powered down */ | ||
2499 | connect = invert ? 1 : 0; | ||
2500 | |||
2501 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2609 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2502 | 2610 | ||
2503 | change = snd_soc_test_bits(widget->codec, reg, mask, val); | 2611 | change = snd_soc_test_bits(widget->codec, reg, mask, val); |
@@ -2873,6 +2981,19 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2873 | return NULL; | 2981 | return NULL; |
2874 | } | 2982 | } |
2875 | break; | 2983 | break; |
2984 | case snd_soc_dapm_clock_supply: | ||
2985 | #ifdef CONFIG_CLKDEV_LOOKUP | ||
2986 | w->clk = devm_clk_get(dapm->dev, w->name); | ||
2987 | if (IS_ERR(w->clk)) { | ||
2988 | ret = PTR_ERR(w->clk); | ||
2989 | dev_err(dapm->dev, "Failed to request %s: %d\n", | ||
2990 | w->name, ret); | ||
2991 | return NULL; | ||
2992 | } | ||
2993 | #else | ||
2994 | return NULL; | ||
2995 | #endif | ||
2996 | break; | ||
2876 | default: | 2997 | default: |
2877 | break; | 2998 | break; |
2878 | } | 2999 | } |
@@ -2924,6 +3045,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
2924 | break; | 3045 | break; |
2925 | case snd_soc_dapm_supply: | 3046 | case snd_soc_dapm_supply: |
2926 | case snd_soc_dapm_regulator_supply: | 3047 | case snd_soc_dapm_regulator_supply: |
3048 | case snd_soc_dapm_clock_supply: | ||
2927 | w->power_check = dapm_supply_check_power; | 3049 | w->power_check = dapm_supply_check_power; |
2928 | break; | 3050 | break; |
2929 | case snd_soc_dapm_dai: | 3051 | case snd_soc_dapm_dai: |
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c index 475695234b3d..5df529eda251 100644 --- a/sound/soc/soc-dmaengine-pcm.c +++ b/sound/soc/soc-dmaengine-pcm.c | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | struct dmaengine_pcm_runtime_data { | 31 | struct dmaengine_pcm_runtime_data { |
32 | struct dma_chan *dma_chan; | 32 | struct dma_chan *dma_chan; |
33 | dma_cookie_t cookie; | ||
33 | 34 | ||
34 | unsigned int pos; | 35 | unsigned int pos; |
35 | 36 | ||
@@ -153,7 +154,7 @@ static int dmaengine_pcm_prepare_and_submit(struct snd_pcm_substream *substream) | |||
153 | 154 | ||
154 | desc->callback = dmaengine_pcm_dma_complete; | 155 | desc->callback = dmaengine_pcm_dma_complete; |
155 | desc->callback_param = substream; | 156 | desc->callback_param = substream; |
156 | dmaengine_submit(desc); | 157 | prtd->cookie = dmaengine_submit(desc); |
157 | 158 | ||
158 | return 0; | 159 | return 0; |
159 | } | 160 | } |
@@ -200,6 +201,20 @@ int snd_dmaengine_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
200 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); | 201 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); |
201 | 202 | ||
202 | /** | 203 | /** |
204 | * snd_dmaengine_pcm_pointer_no_residue - dmaengine based PCM pointer implementation | ||
205 | * @substream: PCM substream | ||
206 | * | ||
207 | * This function is deprecated and should not be used by new drivers, as its | ||
208 | * results may be unreliable. | ||
209 | */ | ||
210 | snd_pcm_uframes_t snd_dmaengine_pcm_pointer_no_residue(struct snd_pcm_substream *substream) | ||
211 | { | ||
212 | struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); | ||
213 | return bytes_to_frames(substream->runtime, prtd->pos); | ||
214 | } | ||
215 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer_no_residue); | ||
216 | |||
217 | /** | ||
203 | * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation | 218 | * snd_dmaengine_pcm_pointer - dmaengine based PCM pointer implementation |
204 | * @substream: PCM substream | 219 | * @substream: PCM substream |
205 | * | 220 | * |
@@ -209,7 +224,19 @@ EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_trigger); | |||
209 | snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) | 224 | snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream) |
210 | { | 225 | { |
211 | struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); | 226 | struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); |
212 | return bytes_to_frames(substream->runtime, prtd->pos); | 227 | struct dma_tx_state state; |
228 | enum dma_status status; | ||
229 | unsigned int buf_size; | ||
230 | unsigned int pos = 0; | ||
231 | |||
232 | status = dmaengine_tx_status(prtd->dma_chan, prtd->cookie, &state); | ||
233 | if (status == DMA_IN_PROGRESS || status == DMA_PAUSED) { | ||
234 | buf_size = snd_pcm_lib_buffer_bytes(substream); | ||
235 | if (state.residue > 0 && state.residue <= buf_size) | ||
236 | pos = buf_size - state.residue; | ||
237 | } | ||
238 | |||
239 | return bytes_to_frames(substream->runtime, pos); | ||
213 | } | 240 | } |
214 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); | 241 | EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); |
215 | 242 | ||
@@ -243,7 +270,7 @@ static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd | |||
243 | * Note that this function will use private_data field of the substream's | 270 | * Note that this function will use private_data field of the substream's |
244 | * runtime. So it is not availabe to your pcm driver implementation. If you need | 271 | * runtime. So it is not availabe to your pcm driver implementation. If you need |
245 | * to keep additional data attached to a substream use | 272 | * to keep additional data attached to a substream use |
246 | * snd_dmaeinge_pcm_{set,get}_data. | 273 | * snd_dmaengine_pcm_{set,get}_data. |
247 | */ | 274 | */ |
248 | int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, | 275 | int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, |
249 | dma_filter_fn filter_fn, void *filter_data) | 276 | dma_filter_fn filter_fn, void *filter_data) |
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 4d8dc6a27d4d..29183ef2b93d 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c | |||
@@ -142,11 +142,16 @@ int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, | |||
142 | case SND_SOC_REGMAP: | 142 | case SND_SOC_REGMAP: |
143 | /* Device has made its own regmap arrangements */ | 143 | /* Device has made its own regmap arrangements */ |
144 | codec->using_regmap = true; | 144 | codec->using_regmap = true; |
145 | 145 | if (!codec->control_data) | |
146 | ret = regmap_get_val_bytes(codec->control_data); | 146 | codec->control_data = dev_get_regmap(codec->dev, NULL); |
147 | /* Errors are legitimate for non-integer byte multiples */ | 147 | |
148 | if (ret > 0) | 148 | if (codec->control_data) { |
149 | codec->val_bytes = ret; | 149 | ret = regmap_get_val_bytes(codec->control_data); |
150 | /* Errors are legitimate for non-integer byte | ||
151 | * multiples */ | ||
152 | if (ret > 0) | ||
153 | codec->val_bytes = ret; | ||
154 | } | ||
150 | break; | 155 | break; |
151 | 156 | ||
152 | default: | 157 | default: |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 48fd15b312c1..ef22d0bd9e9e 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -1955,10 +1955,8 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) | |||
1955 | fe->dpcm[stream].runtime = fe_substream->runtime; | 1955 | fe->dpcm[stream].runtime = fe_substream->runtime; |
1956 | 1956 | ||
1957 | if (dpcm_path_get(fe, stream, &list) <= 0) { | 1957 | if (dpcm_path_get(fe, stream, &list) <= 0) { |
1958 | dev_warn(fe->dev, "asoc: %s no valid %s route\n", | 1958 | dev_dbg(fe->dev, "asoc: %s no valid %s route\n", |
1959 | fe->dai_link->name, stream ? "capture" : "playback"); | 1959 | fe->dai_link->name, stream ? "capture" : "playback"); |
1960 | mutex_unlock(&fe->card->mutex); | ||
1961 | return -EINVAL; | ||
1962 | } | 1960 | } |
1963 | 1961 | ||
1964 | /* calculate valid and active FE <-> BE dpcms */ | 1962 | /* calculate valid and active FE <-> BE dpcms */ |
@@ -2003,7 +2001,6 @@ static int dpcm_fe_dai_close(struct snd_pcm_substream *fe_substream) | |||
2003 | /* create a new pcm */ | 2001 | /* create a new pcm */ |
2004 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | 2002 | int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) |
2005 | { | 2003 | { |
2006 | struct snd_soc_codec *codec = rtd->codec; | ||
2007 | struct snd_soc_platform *platform = rtd->platform; | 2004 | struct snd_soc_platform *platform = rtd->platform; |
2008 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 2005 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
2009 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 2006 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
@@ -2042,7 +2039,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2042 | capture, &pcm); | 2039 | capture, &pcm); |
2043 | } | 2040 | } |
2044 | if (ret < 0) { | 2041 | if (ret < 0) { |
2045 | printk(KERN_ERR "asoc: can't create pcm for codec %s\n", codec->name); | 2042 | dev_err(rtd->card->dev, "can't create pcm for %s\n", |
2043 | rtd->dai_link->name); | ||
2046 | return ret; | 2044 | return ret; |
2047 | } | 2045 | } |
2048 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); | 2046 | dev_dbg(rtd->card->dev, "registered pcm #%d %s\n",num, new_name); |
@@ -2099,14 +2097,14 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num) | |||
2099 | if (platform->driver->pcm_new) { | 2097 | if (platform->driver->pcm_new) { |
2100 | ret = platform->driver->pcm_new(rtd); | 2098 | ret = platform->driver->pcm_new(rtd); |
2101 | if (ret < 0) { | 2099 | if (ret < 0) { |
2102 | pr_err("asoc: platform pcm constructor failed\n"); | 2100 | dev_err(platform->dev, "pcm constructor failed\n"); |
2103 | return ret; | 2101 | return ret; |
2104 | } | 2102 | } |
2105 | } | 2103 | } |
2106 | 2104 | ||
2107 | pcm->private_free = platform->driver->pcm_free; | 2105 | pcm->private_free = platform->driver->pcm_free; |
2108 | out: | 2106 | out: |
2109 | printk(KERN_INFO "asoc: %s <-> %s mapping ok\n", codec_dai->name, | 2107 | dev_info(rtd->card->dev, " %s <-> %s mapping ok\n", codec_dai->name, |
2110 | cpu_dai->name); | 2108 | cpu_dai->name); |
2111 | return ret; | 2109 | return ret; |
2112 | } | 2110 | } |
diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c new file mode 100644 index 000000000000..c7c4b20395bb --- /dev/null +++ b/sound/soc/spear/spdif_in.c | |||
@@ -0,0 +1,297 @@ | |||
1 | /* | ||
2 | * ALSA SoC SPDIF In Audio Layer for spear processors | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Vipin Kumar <vipin.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/spear_dma.h> | ||
25 | #include <sound/spear_spdif.h> | ||
26 | #include "spdif_in_regs.h" | ||
27 | |||
28 | struct spdif_in_params { | ||
29 | u32 format; | ||
30 | }; | ||
31 | |||
32 | struct spdif_in_dev { | ||
33 | struct clk *clk; | ||
34 | struct spear_dma_data dma_params; | ||
35 | struct spdif_in_params saved_params; | ||
36 | void *io_base; | ||
37 | struct device *dev; | ||
38 | void (*reset_perip)(void); | ||
39 | int irq; | ||
40 | }; | ||
41 | |||
42 | static void spdif_in_configure(struct spdif_in_dev *host) | ||
43 | { | ||
44 | u32 ctrl = SPDIF_IN_PRTYEN | SPDIF_IN_STATEN | SPDIF_IN_USREN | | ||
45 | SPDIF_IN_VALEN | SPDIF_IN_BLKEN; | ||
46 | ctrl |= SPDIF_MODE_16BIT | SPDIF_FIFO_THRES_16; | ||
47 | |||
48 | writel(ctrl, host->io_base + SPDIF_IN_CTRL); | ||
49 | writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK); | ||
50 | } | ||
51 | |||
52 | static int spdif_in_startup(struct snd_pcm_substream *substream, | ||
53 | struct snd_soc_dai *cpu_dai) | ||
54 | { | ||
55 | struct spdif_in_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | ||
56 | |||
57 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) | ||
58 | return -EINVAL; | ||
59 | |||
60 | snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params); | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static void spdif_in_shutdown(struct snd_pcm_substream *substream, | ||
65 | struct snd_soc_dai *dai) | ||
66 | { | ||
67 | struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); | ||
68 | |||
69 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) | ||
70 | return; | ||
71 | |||
72 | writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK); | ||
73 | snd_soc_dai_set_dma_data(dai, substream, NULL); | ||
74 | } | ||
75 | |||
76 | static void spdif_in_format(struct spdif_in_dev *host, u32 format) | ||
77 | { | ||
78 | u32 ctrl = readl(host->io_base + SPDIF_IN_CTRL); | ||
79 | |||
80 | switch (format) { | ||
81 | case SNDRV_PCM_FORMAT_S16_LE: | ||
82 | ctrl |= SPDIF_XTRACT_16BIT; | ||
83 | break; | ||
84 | |||
85 | case SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE: | ||
86 | ctrl &= ~SPDIF_XTRACT_16BIT; | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | writel(ctrl, host->io_base + SPDIF_IN_CTRL); | ||
91 | } | ||
92 | |||
93 | static int spdif_in_hw_params(struct snd_pcm_substream *substream, | ||
94 | struct snd_pcm_hw_params *params, | ||
95 | struct snd_soc_dai *dai) | ||
96 | { | ||
97 | struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); | ||
98 | u32 format; | ||
99 | |||
100 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) | ||
101 | return -EINVAL; | ||
102 | |||
103 | format = params_format(params); | ||
104 | host->saved_params.format = format; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static int spdif_in_trigger(struct snd_pcm_substream *substream, int cmd, | ||
110 | struct snd_soc_dai *dai) | ||
111 | { | ||
112 | struct spdif_in_dev *host = snd_soc_dai_get_drvdata(dai); | ||
113 | u32 ctrl; | ||
114 | int ret = 0; | ||
115 | |||
116 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) | ||
117 | return -EINVAL; | ||
118 | |||
119 | switch (cmd) { | ||
120 | case SNDRV_PCM_TRIGGER_START: | ||
121 | case SNDRV_PCM_TRIGGER_RESUME: | ||
122 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
123 | clk_enable(host->clk); | ||
124 | spdif_in_configure(host); | ||
125 | spdif_in_format(host, host->saved_params.format); | ||
126 | |||
127 | ctrl = readl(host->io_base + SPDIF_IN_CTRL); | ||
128 | ctrl |= SPDIF_IN_SAMPLE | SPDIF_IN_ENB; | ||
129 | writel(ctrl, host->io_base + SPDIF_IN_CTRL); | ||
130 | writel(0xF, host->io_base + SPDIF_IN_IRQ_MASK); | ||
131 | break; | ||
132 | |||
133 | case SNDRV_PCM_TRIGGER_STOP: | ||
134 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
135 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
136 | ctrl = readl(host->io_base + SPDIF_IN_CTRL); | ||
137 | ctrl &= ~(SPDIF_IN_SAMPLE | SPDIF_IN_ENB); | ||
138 | writel(ctrl, host->io_base + SPDIF_IN_CTRL); | ||
139 | writel(0x0, host->io_base + SPDIF_IN_IRQ_MASK); | ||
140 | |||
141 | if (host->reset_perip) | ||
142 | host->reset_perip(); | ||
143 | clk_disable(host->clk); | ||
144 | break; | ||
145 | |||
146 | default: | ||
147 | ret = -EINVAL; | ||
148 | break; | ||
149 | } | ||
150 | return ret; | ||
151 | } | ||
152 | |||
153 | static struct snd_soc_dai_ops spdif_in_dai_ops = { | ||
154 | .startup = spdif_in_startup, | ||
155 | .shutdown = spdif_in_shutdown, | ||
156 | .trigger = spdif_in_trigger, | ||
157 | .hw_params = spdif_in_hw_params, | ||
158 | }; | ||
159 | |||
160 | struct snd_soc_dai_driver spdif_in_dai = { | ||
161 | .capture = { | ||
162 | .channels_min = 2, | ||
163 | .channels_max = 2, | ||
164 | .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
165 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ | ||
166 | SNDRV_PCM_RATE_192000), | ||
167 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ | ||
168 | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE, | ||
169 | }, | ||
170 | .ops = &spdif_in_dai_ops, | ||
171 | }; | ||
172 | |||
173 | static irqreturn_t spdif_in_irq(int irq, void *arg) | ||
174 | { | ||
175 | struct spdif_in_dev *host = (struct spdif_in_dev *)arg; | ||
176 | |||
177 | u32 irq_status = readl(host->io_base + SPDIF_IN_IRQ); | ||
178 | |||
179 | if (!irq_status) | ||
180 | return IRQ_NONE; | ||
181 | |||
182 | if (irq_status & SPDIF_IRQ_FIFOWRITE) | ||
183 | dev_err(host->dev, "spdif in: fifo write error"); | ||
184 | if (irq_status & SPDIF_IRQ_EMPTYFIFOREAD) | ||
185 | dev_err(host->dev, "spdif in: empty fifo read error"); | ||
186 | if (irq_status & SPDIF_IRQ_FIFOFULL) | ||
187 | dev_err(host->dev, "spdif in: fifo full error"); | ||
188 | if (irq_status & SPDIF_IRQ_OUTOFRANGE) | ||
189 | dev_err(host->dev, "spdif in: out of range error"); | ||
190 | |||
191 | writel(0, host->io_base + SPDIF_IN_IRQ); | ||
192 | |||
193 | return IRQ_HANDLED; | ||
194 | } | ||
195 | |||
196 | static int spdif_in_probe(struct platform_device *pdev) | ||
197 | { | ||
198 | struct spdif_in_dev *host; | ||
199 | struct spear_spdif_platform_data *pdata; | ||
200 | struct resource *res, *res_fifo; | ||
201 | int ret; | ||
202 | |||
203 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
204 | if (!res) | ||
205 | return -EINVAL; | ||
206 | |||
207 | res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
208 | if (!res_fifo) | ||
209 | return -EINVAL; | ||
210 | |||
211 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
212 | resource_size(res), pdev->name)) { | ||
213 | dev_warn(&pdev->dev, "Failed to get memory resourse\n"); | ||
214 | return -ENOENT; | ||
215 | } | ||
216 | |||
217 | host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); | ||
218 | if (!host) { | ||
219 | dev_warn(&pdev->dev, "kzalloc fail\n"); | ||
220 | return -ENOMEM; | ||
221 | } | ||
222 | |||
223 | host->io_base = devm_ioremap(&pdev->dev, res->start, | ||
224 | resource_size(res)); | ||
225 | if (!host->io_base) { | ||
226 | dev_warn(&pdev->dev, "ioremap failed\n"); | ||
227 | return -ENOMEM; | ||
228 | } | ||
229 | |||
230 | host->irq = platform_get_irq(pdev, 0); | ||
231 | if (host->irq < 0) | ||
232 | return -EINVAL; | ||
233 | |||
234 | host->clk = clk_get(&pdev->dev, NULL); | ||
235 | if (IS_ERR(host->clk)) | ||
236 | return PTR_ERR(host->clk); | ||
237 | |||
238 | pdata = dev_get_platdata(&pdev->dev); | ||
239 | |||
240 | if (!pdata) | ||
241 | return -EINVAL; | ||
242 | |||
243 | host->dma_params.data = pdata->dma_params; | ||
244 | host->dma_params.addr = res_fifo->start; | ||
245 | host->dma_params.max_burst = 16; | ||
246 | host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
247 | host->dma_params.filter = pdata->filter; | ||
248 | host->reset_perip = pdata->reset_perip; | ||
249 | |||
250 | host->dev = &pdev->dev; | ||
251 | dev_set_drvdata(&pdev->dev, host); | ||
252 | |||
253 | ret = devm_request_irq(&pdev->dev, host->irq, spdif_in_irq, 0, | ||
254 | "spdif-in", host); | ||
255 | if (ret) { | ||
256 | clk_put(host->clk); | ||
257 | dev_warn(&pdev->dev, "request_irq failed\n"); | ||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | ret = snd_soc_register_dai(&pdev->dev, &spdif_in_dai); | ||
262 | if (ret != 0) { | ||
263 | clk_put(host->clk); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
268 | } | ||
269 | |||
270 | static int spdif_in_remove(struct platform_device *pdev) | ||
271 | { | ||
272 | struct spdif_in_dev *host = dev_get_drvdata(&pdev->dev); | ||
273 | |||
274 | snd_soc_unregister_dai(&pdev->dev); | ||
275 | dev_set_drvdata(&pdev->dev, NULL); | ||
276 | |||
277 | clk_put(host->clk); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | |||
283 | static struct platform_driver spdif_in_driver = { | ||
284 | .probe = spdif_in_probe, | ||
285 | .remove = spdif_in_remove, | ||
286 | .driver = { | ||
287 | .name = "spdif-in", | ||
288 | .owner = THIS_MODULE, | ||
289 | }, | ||
290 | }; | ||
291 | |||
292 | module_platform_driver(spdif_in_driver); | ||
293 | |||
294 | MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>"); | ||
295 | MODULE_DESCRIPTION("SPEAr SPDIF IN SoC Interface"); | ||
296 | MODULE_LICENSE("GPL"); | ||
297 | MODULE_ALIAS("platform:spdif_in"); | ||
diff --git a/sound/soc/spear/spdif_in_regs.h b/sound/soc/spear/spdif_in_regs.h new file mode 100644 index 000000000000..37af7bc66b7f --- /dev/null +++ b/sound/soc/spear/spdif_in_regs.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * SPEAr SPDIF IN controller header file | ||
3 | * | ||
4 | * Copyright (ST) 2011 Vipin Kumar (vipin.kumar@st.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef SPDIF_IN_REGS_H | ||
22 | #define SPDIF_IN_REGS_H | ||
23 | |||
24 | #define SPDIF_IN_CTRL 0x00 | ||
25 | #define SPDIF_IN_PRTYEN (1 << 20) | ||
26 | #define SPDIF_IN_STATEN (1 << 19) | ||
27 | #define SPDIF_IN_USREN (1 << 18) | ||
28 | #define SPDIF_IN_VALEN (1 << 17) | ||
29 | #define SPDIF_IN_BLKEN (1 << 16) | ||
30 | |||
31 | #define SPDIF_MODE_24BIT (8 << 12) | ||
32 | #define SPDIF_MODE_23BIT (7 << 12) | ||
33 | #define SPDIF_MODE_22BIT (6 << 12) | ||
34 | #define SPDIF_MODE_21BIT (5 << 12) | ||
35 | #define SPDIF_MODE_20BIT (4 << 12) | ||
36 | #define SPDIF_MODE_19BIT (3 << 12) | ||
37 | #define SPDIF_MODE_18BIT (2 << 12) | ||
38 | #define SPDIF_MODE_17BIT (1 << 12) | ||
39 | #define SPDIF_MODE_16BIT (0 << 12) | ||
40 | #define SPDIF_MODE_MASK (0x0F << 12) | ||
41 | |||
42 | #define SPDIF_IN_VALID (1 << 11) | ||
43 | #define SPDIF_IN_SAMPLE (1 << 10) | ||
44 | #define SPDIF_DATA_SWAP (1 << 9) | ||
45 | #define SPDIF_IN_ENB (1 << 8) | ||
46 | #define SPDIF_DATA_REVERT (1 << 7) | ||
47 | #define SPDIF_XTRACT_16BIT (1 << 6) | ||
48 | #define SPDIF_FIFO_THRES_16 (16 << 0) | ||
49 | |||
50 | #define SPDIF_IN_IRQ_MASK 0x04 | ||
51 | #define SPDIF_IN_IRQ 0x08 | ||
52 | #define SPDIF_IRQ_FIFOWRITE (1 << 0) | ||
53 | #define SPDIF_IRQ_EMPTYFIFOREAD (1 << 1) | ||
54 | #define SPDIF_IRQ_FIFOFULL (1 << 2) | ||
55 | #define SPDIF_IRQ_OUTOFRANGE (1 << 3) | ||
56 | |||
57 | #define SPDIF_IN_STA 0x0C | ||
58 | #define SPDIF_IN_LOCK (0x1 << 0) | ||
59 | |||
60 | #endif /* SPDIF_IN_REGS_H */ | ||
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c new file mode 100644 index 000000000000..5eac4cda2fd7 --- /dev/null +++ b/sound/soc/spear/spdif_out.c | |||
@@ -0,0 +1,389 @@ | |||
1 | /* | ||
2 | * ALSA SoC SPDIF Out Audio Layer for spear processors | ||
3 | * | ||
4 | * Copyright (C) 2012 ST Microelectronics | ||
5 | * Vipin Kumar <vipin.kumar@st.com> | ||
6 | * | ||
7 | * This file is licensed under the terms of the GNU General Public | ||
8 | * License version 2. This program is licensed "as is" without any | ||
9 | * warranty of any kind, whether express or implied. | ||
10 | */ | ||
11 | |||
12 | #include <linux/clk.h> | ||
13 | #include <linux/delay.h> | ||
14 | #include <linux/device.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/ioport.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/spear_dma.h> | ||
23 | #include <sound/spear_spdif.h> | ||
24 | #include "spdif_out_regs.h" | ||
25 | |||
26 | struct spdif_out_params { | ||
27 | u32 rate; | ||
28 | u32 core_freq; | ||
29 | u32 mute; | ||
30 | }; | ||
31 | |||
32 | struct spdif_out_dev { | ||
33 | struct clk *clk; | ||
34 | struct spear_dma_data dma_params; | ||
35 | struct spdif_out_params saved_params; | ||
36 | u32 running; | ||
37 | void __iomem *io_base; | ||
38 | }; | ||
39 | |||
40 | static void spdif_out_configure(struct spdif_out_dev *host) | ||
41 | { | ||
42 | writel(SPDIF_OUT_RESET, host->io_base + SPDIF_OUT_SOFT_RST); | ||
43 | mdelay(1); | ||
44 | writel(readl(host->io_base + SPDIF_OUT_SOFT_RST) & ~SPDIF_OUT_RESET, | ||
45 | host->io_base + SPDIF_OUT_SOFT_RST); | ||
46 | |||
47 | writel(SPDIF_OUT_FDMA_TRIG_16 | SPDIF_OUT_MEMFMT_16_16 | | ||
48 | SPDIF_OUT_VALID_HW | SPDIF_OUT_USER_HW | | ||
49 | SPDIF_OUT_CHNLSTA_HW | SPDIF_OUT_PARITY_HW, | ||
50 | host->io_base + SPDIF_OUT_CFG); | ||
51 | |||
52 | writel(0x7F, host->io_base + SPDIF_OUT_INT_STA_CLR); | ||
53 | writel(0x7F, host->io_base + SPDIF_OUT_INT_EN_CLR); | ||
54 | } | ||
55 | |||
56 | static int spdif_out_startup(struct snd_pcm_substream *substream, | ||
57 | struct snd_soc_dai *cpu_dai) | ||
58 | { | ||
59 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | ||
60 | int ret; | ||
61 | |||
62 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
63 | return -EINVAL; | ||
64 | |||
65 | snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)&host->dma_params); | ||
66 | |||
67 | ret = clk_enable(host->clk); | ||
68 | if (ret) | ||
69 | return ret; | ||
70 | |||
71 | host->running = true; | ||
72 | spdif_out_configure(host); | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void spdif_out_shutdown(struct snd_pcm_substream *substream, | ||
78 | struct snd_soc_dai *dai) | ||
79 | { | ||
80 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai); | ||
81 | |||
82 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
83 | return; | ||
84 | |||
85 | clk_disable(host->clk); | ||
86 | host->running = false; | ||
87 | snd_soc_dai_set_dma_data(dai, substream, NULL); | ||
88 | } | ||
89 | |||
90 | static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq, | ||
91 | u32 rate) | ||
92 | { | ||
93 | u32 divider, ctrl; | ||
94 | |||
95 | clk_set_rate(host->clk, core_freq); | ||
96 | divider = DIV_ROUND_CLOSEST(clk_get_rate(host->clk), (rate * 128)); | ||
97 | |||
98 | ctrl = readl(host->io_base + SPDIF_OUT_CTRL); | ||
99 | ctrl &= ~SPDIF_DIVIDER_MASK; | ||
100 | ctrl |= (divider << SPDIF_DIVIDER_SHIFT) & SPDIF_DIVIDER_MASK; | ||
101 | writel(ctrl, host->io_base + SPDIF_OUT_CTRL); | ||
102 | } | ||
103 | |||
104 | static int spdif_out_hw_params(struct snd_pcm_substream *substream, | ||
105 | struct snd_pcm_hw_params *params, | ||
106 | struct snd_soc_dai *dai) | ||
107 | { | ||
108 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai); | ||
109 | u32 rate, core_freq; | ||
110 | |||
111 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
112 | return -EINVAL; | ||
113 | |||
114 | rate = params_rate(params); | ||
115 | |||
116 | switch (rate) { | ||
117 | case 8000: | ||
118 | case 16000: | ||
119 | case 32000: | ||
120 | case 64000: | ||
121 | /* | ||
122 | * The clock is multiplied by 10 to bring it to feasible range | ||
123 | * of frequencies for sscg | ||
124 | */ | ||
125 | core_freq = 64000 * 128 * 10; /* 81.92 MHz */ | ||
126 | break; | ||
127 | case 5512: | ||
128 | case 11025: | ||
129 | case 22050: | ||
130 | case 44100: | ||
131 | case 88200: | ||
132 | case 176400: | ||
133 | core_freq = 176400 * 128; /* 22.5792 MHz */ | ||
134 | break; | ||
135 | case 48000: | ||
136 | case 96000: | ||
137 | case 192000: | ||
138 | default: | ||
139 | core_freq = 192000 * 128; /* 24.576 MHz */ | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | spdif_out_clock(host, core_freq, rate); | ||
144 | host->saved_params.core_freq = core_freq; | ||
145 | host->saved_params.rate = rate; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int spdif_out_trigger(struct snd_pcm_substream *substream, int cmd, | ||
151 | struct snd_soc_dai *dai) | ||
152 | { | ||
153 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai); | ||
154 | u32 ctrl; | ||
155 | int ret = 0; | ||
156 | |||
157 | if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) | ||
158 | return -EINVAL; | ||
159 | |||
160 | switch (cmd) { | ||
161 | case SNDRV_PCM_TRIGGER_START: | ||
162 | case SNDRV_PCM_TRIGGER_RESUME: | ||
163 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
164 | ctrl = readl(host->io_base + SPDIF_OUT_CTRL); | ||
165 | ctrl &= ~SPDIF_OPMODE_MASK; | ||
166 | if (!host->saved_params.mute) | ||
167 | ctrl |= SPDIF_OPMODE_AUD_DATA | | ||
168 | SPDIF_STATE_NORMAL; | ||
169 | else | ||
170 | ctrl |= SPDIF_OPMODE_MUTE_PCM; | ||
171 | writel(ctrl, host->io_base + SPDIF_OUT_CTRL); | ||
172 | break; | ||
173 | |||
174 | case SNDRV_PCM_TRIGGER_STOP: | ||
175 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
176 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
177 | ctrl = readl(host->io_base + SPDIF_OUT_CTRL); | ||
178 | ctrl &= ~SPDIF_OPMODE_MASK; | ||
179 | ctrl |= SPDIF_OPMODE_OFF; | ||
180 | writel(ctrl, host->io_base + SPDIF_OUT_CTRL); | ||
181 | break; | ||
182 | |||
183 | default: | ||
184 | ret = -EINVAL; | ||
185 | break; | ||
186 | } | ||
187 | return ret; | ||
188 | } | ||
189 | |||
190 | static int spdif_digital_mute(struct snd_soc_dai *dai, int mute) | ||
191 | { | ||
192 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai); | ||
193 | u32 val; | ||
194 | |||
195 | host->saved_params.mute = mute; | ||
196 | val = readl(host->io_base + SPDIF_OUT_CTRL); | ||
197 | val &= ~SPDIF_OPMODE_MASK; | ||
198 | |||
199 | if (mute) | ||
200 | val |= SPDIF_OPMODE_MUTE_PCM; | ||
201 | else { | ||
202 | if (host->running) | ||
203 | val |= SPDIF_OPMODE_AUD_DATA | SPDIF_STATE_NORMAL; | ||
204 | else | ||
205 | val |= SPDIF_OPMODE_OFF; | ||
206 | } | ||
207 | |||
208 | writel(val, host->io_base + SPDIF_OUT_CTRL); | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int spdif_mute_get(struct snd_kcontrol *kcontrol, | ||
213 | struct snd_ctl_elem_value *ucontrol) | ||
214 | { | ||
215 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
216 | struct snd_soc_card *card = codec->card; | ||
217 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
218 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
219 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | ||
220 | |||
221 | ucontrol->value.integer.value[0] = host->saved_params.mute; | ||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int spdif_mute_put(struct snd_kcontrol *kcontrol, | ||
226 | struct snd_ctl_elem_value *ucontrol) | ||
227 | { | ||
228 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
229 | struct snd_soc_card *card = codec->card; | ||
230 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
231 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
232 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | ||
233 | |||
234 | if (host->saved_params.mute == ucontrol->value.integer.value[0]) | ||
235 | return 0; | ||
236 | |||
237 | spdif_digital_mute(cpu_dai, ucontrol->value.integer.value[0]); | ||
238 | |||
239 | return 1; | ||
240 | } | ||
241 | static const struct snd_kcontrol_new spdif_out_controls[] = { | ||
242 | SOC_SINGLE_BOOL_EXT("IEC958 Playback Switch", 0, | ||
243 | spdif_mute_get, spdif_mute_put), | ||
244 | }; | ||
245 | |||
246 | int spdif_soc_dai_probe(struct snd_soc_dai *dai) | ||
247 | { | ||
248 | return snd_soc_add_dai_controls(dai, spdif_out_controls, | ||
249 | ARRAY_SIZE(spdif_out_controls)); | ||
250 | } | ||
251 | |||
252 | static const struct snd_soc_dai_ops spdif_out_dai_ops = { | ||
253 | .digital_mute = spdif_digital_mute, | ||
254 | .startup = spdif_out_startup, | ||
255 | .shutdown = spdif_out_shutdown, | ||
256 | .trigger = spdif_out_trigger, | ||
257 | .hw_params = spdif_out_hw_params, | ||
258 | }; | ||
259 | |||
260 | static struct snd_soc_dai_driver spdif_out_dai = { | ||
261 | .playback = { | ||
262 | .channels_min = 2, | ||
263 | .channels_max = 2, | ||
264 | .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \ | ||
265 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \ | ||
266 | SNDRV_PCM_RATE_192000), | ||
267 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
268 | }, | ||
269 | .probe = spdif_soc_dai_probe, | ||
270 | .ops = &spdif_out_dai_ops, | ||
271 | }; | ||
272 | |||
273 | static int spdif_out_probe(struct platform_device *pdev) | ||
274 | { | ||
275 | struct spdif_out_dev *host; | ||
276 | struct spear_spdif_platform_data *pdata; | ||
277 | struct resource *res; | ||
278 | int ret; | ||
279 | |||
280 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
281 | if (!res) | ||
282 | return -EINVAL; | ||
283 | |||
284 | if (!devm_request_mem_region(&pdev->dev, res->start, | ||
285 | resource_size(res), pdev->name)) { | ||
286 | dev_warn(&pdev->dev, "Failed to get memory resourse\n"); | ||
287 | return -ENOENT; | ||
288 | } | ||
289 | |||
290 | host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); | ||
291 | if (!host) { | ||
292 | dev_warn(&pdev->dev, "kzalloc fail\n"); | ||
293 | return -ENOMEM; | ||
294 | } | ||
295 | |||
296 | host->io_base = devm_ioremap(&pdev->dev, res->start, | ||
297 | resource_size(res)); | ||
298 | if (!host->io_base) { | ||
299 | dev_warn(&pdev->dev, "ioremap failed\n"); | ||
300 | return -ENOMEM; | ||
301 | } | ||
302 | |||
303 | host->clk = clk_get(&pdev->dev, NULL); | ||
304 | if (IS_ERR(host->clk)) | ||
305 | return PTR_ERR(host->clk); | ||
306 | |||
307 | pdata = dev_get_platdata(&pdev->dev); | ||
308 | |||
309 | host->dma_params.data = pdata->dma_params; | ||
310 | host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA; | ||
311 | host->dma_params.max_burst = 16; | ||
312 | host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
313 | host->dma_params.filter = pdata->filter; | ||
314 | |||
315 | dev_set_drvdata(&pdev->dev, host); | ||
316 | |||
317 | ret = snd_soc_register_dai(&pdev->dev, &spdif_out_dai); | ||
318 | if (ret != 0) { | ||
319 | clk_put(host->clk); | ||
320 | return ret; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | static int spdif_out_remove(struct platform_device *pdev) | ||
327 | { | ||
328 | struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev); | ||
329 | |||
330 | snd_soc_unregister_dai(&pdev->dev); | ||
331 | dev_set_drvdata(&pdev->dev, NULL); | ||
332 | |||
333 | clk_put(host->clk); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | #ifdef CONFIG_PM | ||
339 | static int spdif_out_suspend(struct device *dev) | ||
340 | { | ||
341 | struct platform_device *pdev = to_platform_device(dev); | ||
342 | struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev); | ||
343 | |||
344 | if (host->running) | ||
345 | clk_disable(host->clk); | ||
346 | |||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int spdif_out_resume(struct device *dev) | ||
351 | { | ||
352 | struct platform_device *pdev = to_platform_device(dev); | ||
353 | struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev); | ||
354 | |||
355 | if (host->running) { | ||
356 | clk_enable(host->clk); | ||
357 | spdif_out_configure(host); | ||
358 | spdif_out_clock(host, host->saved_params.core_freq, | ||
359 | host->saved_params.rate); | ||
360 | } | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static SIMPLE_DEV_PM_OPS(spdif_out_dev_pm_ops, spdif_out_suspend, \ | ||
365 | spdif_out_resume); | ||
366 | |||
367 | #define SPDIF_OUT_DEV_PM_OPS (&spdif_out_dev_pm_ops) | ||
368 | |||
369 | #else | ||
370 | #define SPDIF_OUT_DEV_PM_OPS NULL | ||
371 | |||
372 | #endif | ||
373 | |||
374 | static struct platform_driver spdif_out_driver = { | ||
375 | .probe = spdif_out_probe, | ||
376 | .remove = spdif_out_remove, | ||
377 | .driver = { | ||
378 | .name = "spdif-out", | ||
379 | .owner = THIS_MODULE, | ||
380 | .pm = SPDIF_OUT_DEV_PM_OPS, | ||
381 | }, | ||
382 | }; | ||
383 | |||
384 | module_platform_driver(spdif_out_driver); | ||
385 | |||
386 | MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>"); | ||
387 | MODULE_DESCRIPTION("SPEAr SPDIF OUT SoC Interface"); | ||
388 | MODULE_LICENSE("GPL"); | ||
389 | MODULE_ALIAS("platform:spdif_out"); | ||
diff --git a/sound/soc/spear/spdif_out_regs.h b/sound/soc/spear/spdif_out_regs.h new file mode 100644 index 000000000000..a5e53324b452 --- /dev/null +++ b/sound/soc/spear/spdif_out_regs.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * SPEAr SPDIF OUT controller header file | ||
3 | * | ||
4 | * Copyright (ST) 2011 Vipin Kumar (vipin.kumar@st.com) | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #ifndef SPDIF_OUT_REGS_H | ||
22 | #define SPDIF_OUT_REGS_H | ||
23 | |||
24 | #define SPDIF_OUT_SOFT_RST 0x00 | ||
25 | #define SPDIF_OUT_RESET (1 << 0) | ||
26 | #define SPDIF_OUT_FIFO_DATA 0x04 | ||
27 | #define SPDIF_OUT_INT_STA 0x08 | ||
28 | #define SPDIF_OUT_INT_STA_CLR 0x0C | ||
29 | #define SPDIF_INT_UNDERFLOW (1 << 0) | ||
30 | #define SPDIF_INT_EODATA (1 << 1) | ||
31 | #define SPDIF_INT_EOBLOCK (1 << 2) | ||
32 | #define SPDIF_INT_EOLATENCY (1 << 3) | ||
33 | #define SPDIF_INT_EOPD_DATA (1 << 4) | ||
34 | #define SPDIF_INT_MEMFULLREAD (1 << 5) | ||
35 | #define SPDIF_INT_EOPD_PAUSE (1 << 6) | ||
36 | |||
37 | #define SPDIF_OUT_INT_EN 0x10 | ||
38 | #define SPDIF_OUT_INT_EN_SET 0x14 | ||
39 | #define SPDIF_OUT_INT_EN_CLR 0x18 | ||
40 | #define SPDIF_OUT_CTRL 0x1C | ||
41 | #define SPDIF_OPMODE_MASK (7 << 0) | ||
42 | #define SPDIF_OPMODE_OFF (0 << 0) | ||
43 | #define SPDIF_OPMODE_MUTE_PCM (1 << 0) | ||
44 | #define SPDIF_OPMODE_MUTE_PAUSE (2 << 0) | ||
45 | #define SPDIF_OPMODE_AUD_DATA (3 << 0) | ||
46 | #define SPDIF_OPMODE_ENCODE (4 << 0) | ||
47 | #define SPDIF_STATE_NORMAL (1 << 3) | ||
48 | #define SPDIF_DIVIDER_MASK (0xff << 5) | ||
49 | #define SPDIF_DIVIDER_SHIFT (5) | ||
50 | #define SPDIF_SAMPLEREAD_MASK (0x1ffff << 15) | ||
51 | #define SPDIF_SAMPLEREAD_SHIFT (15) | ||
52 | #define SPDIF_OUT_STA 0x20 | ||
53 | #define SPDIF_OUT_PA_PB 0x24 | ||
54 | #define SPDIF_OUT_PC_PD 0x28 | ||
55 | #define SPDIF_OUT_CL1 0x2C | ||
56 | #define SPDIF_OUT_CR1 0x30 | ||
57 | #define SPDIF_OUT_CL2_CR2_UV 0x34 | ||
58 | #define SPDIF_OUT_PAUSE_LAT 0x38 | ||
59 | #define SPDIF_OUT_FRMLEN_BRST 0x3C | ||
60 | #define SPDIF_OUT_CFG 0x40 | ||
61 | #define SPDIF_OUT_MEMFMT_16_0 (0 << 5) | ||
62 | #define SPDIF_OUT_MEMFMT_16_16 (1 << 5) | ||
63 | #define SPDIF_OUT_VALID_DMA (0 << 3) | ||
64 | #define SPDIF_OUT_VALID_HW (1 << 3) | ||
65 | #define SPDIF_OUT_USER_DMA (0 << 2) | ||
66 | #define SPDIF_OUT_USER_HW (1 << 2) | ||
67 | #define SPDIF_OUT_CHNLSTA_DMA (0 << 1) | ||
68 | #define SPDIF_OUT_CHNLSTA_HW (1 << 1) | ||
69 | #define SPDIF_OUT_PARITY_HW (0 << 0) | ||
70 | #define SPDIF_OUT_PARITY_DMA (1 << 0) | ||
71 | #define SPDIF_OUT_FDMA_TRIG_2 (2 << 8) | ||
72 | #define SPDIF_OUT_FDMA_TRIG_6 (6 << 8) | ||
73 | #define SPDIF_OUT_FDMA_TRIG_8 (8 << 8) | ||
74 | #define SPDIF_OUT_FDMA_TRIG_10 (10 << 8) | ||
75 | #define SPDIF_OUT_FDMA_TRIG_12 (12 << 8) | ||
76 | #define SPDIF_OUT_FDMA_TRIG_16 (16 << 8) | ||
77 | #define SPDIF_OUT_FDMA_TRIG_18 (18 << 8) | ||
78 | |||
79 | #endif /* SPDIF_OUT_REGS_H */ | ||
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c new file mode 100644 index 000000000000..97c2cac8e92c --- /dev/null +++ b/sound/soc/spear/spear_pcm.c | |||
@@ -0,0 +1,214 @@ | |||
1 | /* | ||
2 | * ALSA PCM interface for ST SPEAr Processors | ||
3 | * | ||
4 | * sound/soc/spear/spear_pcm.c | ||
5 | * | ||
6 | * Copyright (C) 2012 ST Microelectronics | ||
7 | * Rajeev Kumar<rajeev-dlh.kumar@st.com> | ||
8 | * | ||
9 | * This file is licensed under the terms of the GNU General Public | ||
10 | * License version 2. This program is licensed "as is" without any | ||
11 | * warranty of any kind, whether express or implied. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/dmaengine.h> | ||
16 | #include <linux/dma-mapping.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/dmaengine_pcm.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/spear_dma.h> | ||
27 | |||
28 | struct snd_pcm_hardware spear_pcm_hardware = { | ||
29 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
30 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
31 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), | ||
32 | .buffer_bytes_max = 16 * 1024, /* max buffer size */ | ||
33 | .period_bytes_min = 2 * 1024, /* 1 msec data minimum period size */ | ||
34 | .period_bytes_max = 2 * 1024, /* maximum period size */ | ||
35 | .periods_min = 1, /* min # periods */ | ||
36 | .periods_max = 8, /* max # of periods */ | ||
37 | .fifo_size = 0, /* fifo size in bytes */ | ||
38 | }; | ||
39 | |||
40 | static int spear_pcm_hw_params(struct snd_pcm_substream *substream, | ||
41 | struct snd_pcm_hw_params *params) | ||
42 | { | ||
43 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static int spear_pcm_hw_free(struct snd_pcm_substream *substream) | ||
49 | { | ||
50 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
51 | |||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int spear_pcm_open(struct snd_pcm_substream *substream) | ||
56 | { | ||
57 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
58 | |||
59 | struct spear_dma_data *dma_data = (struct spear_dma_data *) | ||
60 | snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
61 | int ret; | ||
62 | |||
63 | ret = snd_soc_set_runtime_hwparams(substream, &spear_pcm_hardware); | ||
64 | if (ret) | ||
65 | return ret; | ||
66 | |||
67 | ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data); | ||
68 | if (ret) | ||
69 | return ret; | ||
70 | |||
71 | snd_dmaengine_pcm_set_data(substream, dma_data); | ||
72 | |||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | static int spear_pcm_close(struct snd_pcm_substream *substream) | ||
77 | { | ||
78 | |||
79 | snd_dmaengine_pcm_close(substream); | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int spear_pcm_mmap(struct snd_pcm_substream *substream, | ||
85 | struct vm_area_struct *vma) | ||
86 | { | ||
87 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
88 | |||
89 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
90 | runtime->dma_area, runtime->dma_addr, | ||
91 | runtime->dma_bytes); | ||
92 | } | ||
93 | |||
94 | static struct snd_pcm_ops spear_pcm_ops = { | ||
95 | .open = spear_pcm_open, | ||
96 | .close = spear_pcm_close, | ||
97 | .ioctl = snd_pcm_lib_ioctl, | ||
98 | .hw_params = spear_pcm_hw_params, | ||
99 | .hw_free = spear_pcm_hw_free, | ||
100 | .trigger = snd_dmaengine_pcm_trigger, | ||
101 | .pointer = snd_dmaengine_pcm_pointer, | ||
102 | .mmap = spear_pcm_mmap, | ||
103 | }; | ||
104 | |||
105 | static int | ||
106 | spear_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream, | ||
107 | size_t size) | ||
108 | { | ||
109 | struct snd_pcm_substream *substream = pcm->streams[stream].substream; | ||
110 | struct snd_dma_buffer *buf = &substream->dma_buffer; | ||
111 | |||
112 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
113 | buf->dev.dev = pcm->card->dev; | ||
114 | buf->private_data = NULL; | ||
115 | |||
116 | buf->area = dma_alloc_writecombine(pcm->card->dev, size, | ||
117 | &buf->addr, GFP_KERNEL); | ||
118 | if (!buf->area) | ||
119 | return -ENOMEM; | ||
120 | |||
121 | dev_info(buf->dev.dev, | ||
122 | " preallocate_dma_buffer: area=%p, addr=%p, size=%d\n", | ||
123 | (void *)buf->area, (void *)buf->addr, size); | ||
124 | |||
125 | buf->bytes = size; | ||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | static void spear_pcm_free(struct snd_pcm *pcm) | ||
130 | { | ||
131 | struct snd_pcm_substream *substream; | ||
132 | struct snd_dma_buffer *buf; | ||
133 | int stream; | ||
134 | |||
135 | for (stream = 0; stream < 2; stream++) { | ||
136 | substream = pcm->streams[stream].substream; | ||
137 | if (!substream) | ||
138 | continue; | ||
139 | |||
140 | buf = &substream->dma_buffer; | ||
141 | if (!buf && !buf->area) | ||
142 | continue; | ||
143 | |||
144 | dma_free_writecombine(pcm->card->dev, buf->bytes, | ||
145 | buf->area, buf->addr); | ||
146 | buf->area = NULL; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static u64 spear_pcm_dmamask = DMA_BIT_MASK(32); | ||
151 | |||
152 | static int spear_pcm_new(struct snd_card *card, | ||
153 | struct snd_soc_dai *dai, struct snd_pcm *pcm) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | if (!card->dev->dma_mask) | ||
158 | card->dev->dma_mask = &spear_pcm_dmamask; | ||
159 | if (!card->dev->coherent_dma_mask) | ||
160 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | ||
161 | |||
162 | if (dai->driver->playback.channels_min) { | ||
163 | ret = spear_pcm_preallocate_dma_buffer(pcm, | ||
164 | SNDRV_PCM_STREAM_PLAYBACK, | ||
165 | spear_pcm_hardware.buffer_bytes_max); | ||
166 | if (ret) | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | if (dai->driver->capture.channels_min) { | ||
171 | ret = spear_pcm_preallocate_dma_buffer(pcm, | ||
172 | SNDRV_PCM_STREAM_CAPTURE, | ||
173 | spear_pcm_hardware.buffer_bytes_max); | ||
174 | if (ret) | ||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | struct snd_soc_platform_driver spear_soc_platform = { | ||
182 | .ops = &spear_pcm_ops, | ||
183 | .pcm_new = spear_pcm_new, | ||
184 | .pcm_free = spear_pcm_free, | ||
185 | }; | ||
186 | |||
187 | static int __devinit spear_soc_platform_probe(struct platform_device *pdev) | ||
188 | { | ||
189 | return snd_soc_register_platform(&pdev->dev, &spear_soc_platform); | ||
190 | } | ||
191 | |||
192 | static int __devexit spear_soc_platform_remove(struct platform_device *pdev) | ||
193 | { | ||
194 | snd_soc_unregister_platform(&pdev->dev); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static struct platform_driver spear_pcm_driver = { | ||
200 | .driver = { | ||
201 | .name = "spear-pcm-audio", | ||
202 | .owner = THIS_MODULE, | ||
203 | }, | ||
204 | |||
205 | .probe = spear_soc_platform_probe, | ||
206 | .remove = __devexit_p(spear_soc_platform_remove), | ||
207 | }; | ||
208 | |||
209 | module_platform_driver(spear_pcm_driver); | ||
210 | |||
211 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | ||
212 | MODULE_DESCRIPTION("SPEAr PCM DMA module"); | ||
213 | MODULE_LICENSE("GPL"); | ||
214 | MODULE_ALIAS("platform:spear-pcm-audio"); | ||
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index c1c8e955f4d3..7b6a1ebd197a 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -1,7 +1,8 @@ | |||
1 | config SND_SOC_TEGRA | 1 | config SND_SOC_TEGRA |
2 | tristate "SoC Audio for the Tegra System-on-Chip" | 2 | tristate "SoC Audio for the Tegra System-on-Chip" |
3 | depends on ARCH_TEGRA && TEGRA_SYSTEM_DMA | 3 | depends on ARCH_TEGRA && (TEGRA_SYSTEM_DMA || TEGRA20_APB_DMA) |
4 | select REGMAP_MMIO | 4 | select REGMAP_MMIO |
5 | select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA | ||
5 | help | 6 | help |
6 | Say Y or M here if you want support for SoC audio on Tegra. | 7 | Say Y or M here if you want support for SoC audio on Tegra. |
7 | 8 | ||
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 0c7af63d444b..c5fc6b1404f6 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c | |||
@@ -46,18 +46,6 @@ | |||
46 | 46 | ||
47 | #define DRV_NAME "tegra20-i2s" | 47 | #define DRV_NAME "tegra20-i2s" |
48 | 48 | ||
49 | static inline void tegra20_i2s_write(struct tegra20_i2s *i2s, u32 reg, u32 val) | ||
50 | { | ||
51 | regmap_write(i2s->regmap, reg, val); | ||
52 | } | ||
53 | |||
54 | static inline u32 tegra20_i2s_read(struct tegra20_i2s *i2s, u32 reg) | ||
55 | { | ||
56 | u32 val; | ||
57 | regmap_read(i2s->regmap, reg, &val); | ||
58 | return val; | ||
59 | } | ||
60 | |||
61 | static int tegra20_i2s_runtime_suspend(struct device *dev) | 49 | static int tegra20_i2s_runtime_suspend(struct device *dev) |
62 | { | 50 | { |
63 | struct tegra20_i2s *i2s = dev_get_drvdata(dev); | 51 | struct tegra20_i2s *i2s = dev_get_drvdata(dev); |
@@ -85,6 +73,7 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, | |||
85 | unsigned int fmt) | 73 | unsigned int fmt) |
86 | { | 74 | { |
87 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 75 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
76 | unsigned int mask, val; | ||
88 | 77 | ||
89 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 78 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
90 | case SND_SOC_DAIFMT_NB_NF: | 79 | case SND_SOC_DAIFMT_NB_NF: |
@@ -93,10 +82,10 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, | |||
93 | return -EINVAL; | 82 | return -EINVAL; |
94 | } | 83 | } |
95 | 84 | ||
96 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_MASTER_ENABLE; | 85 | mask = TEGRA20_I2S_CTRL_MASTER_ENABLE; |
97 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 86 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
98 | case SND_SOC_DAIFMT_CBS_CFS: | 87 | case SND_SOC_DAIFMT_CBS_CFS: |
99 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_MASTER_ENABLE; | 88 | val = TEGRA20_I2S_CTRL_MASTER_ENABLE; |
100 | break; | 89 | break; |
101 | case SND_SOC_DAIFMT_CBM_CFM: | 90 | case SND_SOC_DAIFMT_CBM_CFM: |
102 | break; | 91 | break; |
@@ -104,33 +93,35 @@ static int tegra20_i2s_set_fmt(struct snd_soc_dai *dai, | |||
104 | return -EINVAL; | 93 | return -EINVAL; |
105 | } | 94 | } |
106 | 95 | ||
107 | i2s->reg_ctrl &= ~(TEGRA20_I2S_CTRL_BIT_FORMAT_MASK | | 96 | mask |= TEGRA20_I2S_CTRL_BIT_FORMAT_MASK | |
108 | TEGRA20_I2S_CTRL_LRCK_MASK); | 97 | TEGRA20_I2S_CTRL_LRCK_MASK; |
109 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 98 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
110 | case SND_SOC_DAIFMT_DSP_A: | 99 | case SND_SOC_DAIFMT_DSP_A: |
111 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; | 100 | val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; |
112 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | 101 | val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; |
113 | break; | 102 | break; |
114 | case SND_SOC_DAIFMT_DSP_B: | 103 | case SND_SOC_DAIFMT_DSP_B: |
115 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; | 104 | val |= TEGRA20_I2S_CTRL_BIT_FORMAT_DSP; |
116 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_R_LOW; | 105 | val |= TEGRA20_I2S_CTRL_LRCK_R_LOW; |
117 | break; | 106 | break; |
118 | case SND_SOC_DAIFMT_I2S: | 107 | case SND_SOC_DAIFMT_I2S: |
119 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S; | 108 | val |= TEGRA20_I2S_CTRL_BIT_FORMAT_I2S; |
120 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | 109 | val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; |
121 | break; | 110 | break; |
122 | case SND_SOC_DAIFMT_RIGHT_J: | 111 | case SND_SOC_DAIFMT_RIGHT_J: |
123 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM; | 112 | val |= TEGRA20_I2S_CTRL_BIT_FORMAT_RJM; |
124 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | 113 | val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; |
125 | break; | 114 | break; |
126 | case SND_SOC_DAIFMT_LEFT_J: | 115 | case SND_SOC_DAIFMT_LEFT_J: |
127 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM; | 116 | val |= TEGRA20_I2S_CTRL_BIT_FORMAT_LJM; |
128 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_LRCK_L_LOW; | 117 | val |= TEGRA20_I2S_CTRL_LRCK_L_LOW; |
129 | break; | 118 | break; |
130 | default: | 119 | default: |
131 | return -EINVAL; | 120 | return -EINVAL; |
132 | } | 121 | } |
133 | 122 | ||
123 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val); | ||
124 | |||
134 | return 0; | 125 | return 0; |
135 | } | 126 | } |
136 | 127 | ||
@@ -138,29 +129,34 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream, | |||
138 | struct snd_pcm_hw_params *params, | 129 | struct snd_pcm_hw_params *params, |
139 | struct snd_soc_dai *dai) | 130 | struct snd_soc_dai *dai) |
140 | { | 131 | { |
141 | struct device *dev = substream->pcm->card->dev; | 132 | struct device *dev = dai->dev; |
142 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 133 | struct tegra20_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
143 | u32 reg; | 134 | unsigned int mask, val; |
144 | int ret, sample_size, srate, i2sclock, bitcnt; | 135 | int ret, sample_size, srate, i2sclock, bitcnt; |
145 | 136 | ||
146 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_BIT_SIZE_MASK; | 137 | mask = TEGRA20_I2S_CTRL_BIT_SIZE_MASK; |
147 | switch (params_format(params)) { | 138 | switch (params_format(params)) { |
148 | case SNDRV_PCM_FORMAT_S16_LE: | 139 | case SNDRV_PCM_FORMAT_S16_LE: |
149 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_16; | 140 | val = TEGRA20_I2S_CTRL_BIT_SIZE_16; |
150 | sample_size = 16; | 141 | sample_size = 16; |
151 | break; | 142 | break; |
152 | case SNDRV_PCM_FORMAT_S24_LE: | 143 | case SNDRV_PCM_FORMAT_S24_LE: |
153 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_24; | 144 | val = TEGRA20_I2S_CTRL_BIT_SIZE_24; |
154 | sample_size = 24; | 145 | sample_size = 24; |
155 | break; | 146 | break; |
156 | case SNDRV_PCM_FORMAT_S32_LE: | 147 | case SNDRV_PCM_FORMAT_S32_LE: |
157 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_BIT_SIZE_32; | 148 | val = TEGRA20_I2S_CTRL_BIT_SIZE_32; |
158 | sample_size = 32; | 149 | sample_size = 32; |
159 | break; | 150 | break; |
160 | default: | 151 | default: |
161 | return -EINVAL; | 152 | return -EINVAL; |
162 | } | 153 | } |
163 | 154 | ||
155 | mask |= TEGRA20_I2S_CTRL_FIFO_FORMAT_MASK; | ||
156 | val |= TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED; | ||
157 | |||
158 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, mask, val); | ||
159 | |||
164 | srate = params_rate(params); | 160 | srate = params_rate(params); |
165 | 161 | ||
166 | /* Final "* 2" required by Tegra hardware */ | 162 | /* Final "* 2" required by Tegra hardware */ |
@@ -175,42 +171,44 @@ static int tegra20_i2s_hw_params(struct snd_pcm_substream *substream, | |||
175 | bitcnt = (i2sclock / (2 * srate)) - 1; | 171 | bitcnt = (i2sclock / (2 * srate)) - 1; |
176 | if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) | 172 | if (bitcnt < 0 || bitcnt > TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_MASK_US) |
177 | return -EINVAL; | 173 | return -EINVAL; |
178 | reg = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; | 174 | val = bitcnt << TEGRA20_I2S_TIMING_CHANNEL_BIT_COUNT_SHIFT; |
179 | 175 | ||
180 | if (i2sclock % (2 * srate)) | 176 | if (i2sclock % (2 * srate)) |
181 | reg |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; | 177 | val |= TEGRA20_I2S_TIMING_NON_SYM_ENABLE; |
182 | 178 | ||
183 | tegra20_i2s_write(i2s, TEGRA20_I2S_TIMING, reg); | 179 | regmap_write(i2s->regmap, TEGRA20_I2S_TIMING, val); |
184 | 180 | ||
185 | tegra20_i2s_write(i2s, TEGRA20_I2S_FIFO_SCR, | 181 | regmap_write(i2s->regmap, TEGRA20_I2S_FIFO_SCR, |
186 | TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | | 182 | TEGRA20_I2S_FIFO_SCR_FIFO2_ATN_LVL_FOUR_SLOTS | |
187 | TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); | 183 | TEGRA20_I2S_FIFO_SCR_FIFO1_ATN_LVL_FOUR_SLOTS); |
188 | 184 | ||
189 | return 0; | 185 | return 0; |
190 | } | 186 | } |
191 | 187 | ||
192 | static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s) | 188 | static void tegra20_i2s_start_playback(struct tegra20_i2s *i2s) |
193 | { | 189 | { |
194 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO1_ENABLE; | 190 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, |
195 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | 191 | TEGRA20_I2S_CTRL_FIFO1_ENABLE, |
192 | TEGRA20_I2S_CTRL_FIFO1_ENABLE); | ||
196 | } | 193 | } |
197 | 194 | ||
198 | static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s) | 195 | static void tegra20_i2s_stop_playback(struct tegra20_i2s *i2s) |
199 | { | 196 | { |
200 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO1_ENABLE; | 197 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, |
201 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | 198 | TEGRA20_I2S_CTRL_FIFO1_ENABLE, 0); |
202 | } | 199 | } |
203 | 200 | ||
204 | static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s) | 201 | static void tegra20_i2s_start_capture(struct tegra20_i2s *i2s) |
205 | { | 202 | { |
206 | i2s->reg_ctrl |= TEGRA20_I2S_CTRL_FIFO2_ENABLE; | 203 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, |
207 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | 204 | TEGRA20_I2S_CTRL_FIFO2_ENABLE, |
205 | TEGRA20_I2S_CTRL_FIFO2_ENABLE); | ||
208 | } | 206 | } |
209 | 207 | ||
210 | static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s) | 208 | static void tegra20_i2s_stop_capture(struct tegra20_i2s *i2s) |
211 | { | 209 | { |
212 | i2s->reg_ctrl &= ~TEGRA20_I2S_CTRL_FIFO2_ENABLE; | 210 | regmap_update_bits(i2s->regmap, TEGRA20_I2S_CTRL, |
213 | tegra20_i2s_write(i2s, TEGRA20_I2S_CTRL, i2s->reg_ctrl); | 211 | TEGRA20_I2S_CTRL_FIFO2_ENABLE, 0); |
214 | } | 212 | } |
215 | 213 | ||
216 | static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | 214 | static int tegra20_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
@@ -261,12 +259,14 @@ static const struct snd_soc_dai_ops tegra20_i2s_dai_ops = { | |||
261 | static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { | 259 | static const struct snd_soc_dai_driver tegra20_i2s_dai_template = { |
262 | .probe = tegra20_i2s_probe, | 260 | .probe = tegra20_i2s_probe, |
263 | .playback = { | 261 | .playback = { |
262 | .stream_name = "Playback", | ||
264 | .channels_min = 2, | 263 | .channels_min = 2, |
265 | .channels_max = 2, | 264 | .channels_max = 2, |
266 | .rates = SNDRV_PCM_RATE_8000_96000, | 265 | .rates = SNDRV_PCM_RATE_8000_96000, |
267 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 266 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
268 | }, | 267 | }, |
269 | .capture = { | 268 | .capture = { |
269 | .stream_name = "Capture", | ||
270 | .channels_min = 2, | 270 | .channels_min = 2, |
271 | .channels_max = 2, | 271 | .channels_max = 2, |
272 | .rates = SNDRV_PCM_RATE_8000_96000, | 272 | .rates = SNDRV_PCM_RATE_8000_96000, |
@@ -412,8 +412,6 @@ static __devinit int tegra20_i2s_platform_probe(struct platform_device *pdev) | |||
412 | i2s->playback_dma_data.width = 32; | 412 | i2s->playback_dma_data.width = 32; |
413 | i2s->playback_dma_data.req_sel = dma_ch; | 413 | i2s->playback_dma_data.req_sel = dma_ch; |
414 | 414 | ||
415 | i2s->reg_ctrl = TEGRA20_I2S_CTRL_FIFO_FORMAT_PACKED; | ||
416 | |||
417 | pm_runtime_enable(&pdev->dev); | 415 | pm_runtime_enable(&pdev->dev); |
418 | if (!pm_runtime_enabled(&pdev->dev)) { | 416 | if (!pm_runtime_enabled(&pdev->dev)) { |
419 | ret = tegra20_i2s_runtime_resume(&pdev->dev); | 417 | ret = tegra20_i2s_runtime_resume(&pdev->dev); |
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h index a57efc6a597e..c27069d24d77 100644 --- a/sound/soc/tegra/tegra20_i2s.h +++ b/sound/soc/tegra/tegra20_i2s.h | |||
@@ -158,7 +158,6 @@ struct tegra20_i2s { | |||
158 | struct tegra_pcm_dma_params capture_dma_data; | 158 | struct tegra_pcm_dma_params capture_dma_data; |
159 | struct tegra_pcm_dma_params playback_dma_data; | 159 | struct tegra_pcm_dma_params playback_dma_data; |
160 | struct regmap *regmap; | 160 | struct regmap *regmap; |
161 | u32 reg_ctrl; | ||
162 | }; | 161 | }; |
163 | 162 | ||
164 | #endif | 163 | #endif |
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index f9b57418bd08..5c33c618929d 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c | |||
@@ -37,19 +37,6 @@ | |||
37 | 37 | ||
38 | #define DRV_NAME "tegra20-spdif" | 38 | #define DRV_NAME "tegra20-spdif" |
39 | 39 | ||
40 | static inline void tegra20_spdif_write(struct tegra20_spdif *spdif, u32 reg, | ||
41 | u32 val) | ||
42 | { | ||
43 | regmap_write(spdif->regmap, reg, val); | ||
44 | } | ||
45 | |||
46 | static inline u32 tegra20_spdif_read(struct tegra20_spdif *spdif, u32 reg) | ||
47 | { | ||
48 | u32 val; | ||
49 | regmap_read(spdif->regmap, reg, &val); | ||
50 | return val; | ||
51 | } | ||
52 | |||
53 | static int tegra20_spdif_runtime_suspend(struct device *dev) | 40 | static int tegra20_spdif_runtime_suspend(struct device *dev) |
54 | { | 41 | { |
55 | struct tegra20_spdif *spdif = dev_get_drvdata(dev); | 42 | struct tegra20_spdif *spdif = dev_get_drvdata(dev); |
@@ -77,21 +64,24 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, | |||
77 | struct snd_pcm_hw_params *params, | 64 | struct snd_pcm_hw_params *params, |
78 | struct snd_soc_dai *dai) | 65 | struct snd_soc_dai *dai) |
79 | { | 66 | { |
80 | struct device *dev = substream->pcm->card->dev; | 67 | struct device *dev = dai->dev; |
81 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); | 68 | struct tegra20_spdif *spdif = snd_soc_dai_get_drvdata(dai); |
69 | unsigned int mask, val; | ||
82 | int ret, spdifclock; | 70 | int ret, spdifclock; |
83 | 71 | ||
84 | spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_PACK; | 72 | mask = TEGRA20_SPDIF_CTRL_PACK | |
85 | spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; | 73 | TEGRA20_SPDIF_CTRL_BIT_MODE_MASK; |
86 | switch (params_format(params)) { | 74 | switch (params_format(params)) { |
87 | case SNDRV_PCM_FORMAT_S16_LE: | 75 | case SNDRV_PCM_FORMAT_S16_LE: |
88 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_PACK; | 76 | val = TEGRA20_SPDIF_CTRL_PACK | |
89 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; | 77 | TEGRA20_SPDIF_CTRL_BIT_MODE_16BIT; |
90 | break; | 78 | break; |
91 | default: | 79 | default: |
92 | return -EINVAL; | 80 | return -EINVAL; |
93 | } | 81 | } |
94 | 82 | ||
83 | regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, mask, val); | ||
84 | |||
95 | switch (params_rate(params)) { | 85 | switch (params_rate(params)) { |
96 | case 32000: | 86 | case 32000: |
97 | spdifclock = 4096000; | 87 | spdifclock = 4096000; |
@@ -129,14 +119,15 @@ static int tegra20_spdif_hw_params(struct snd_pcm_substream *substream, | |||
129 | 119 | ||
130 | static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif) | 120 | static void tegra20_spdif_start_playback(struct tegra20_spdif *spdif) |
131 | { | 121 | { |
132 | spdif->reg_ctrl |= TEGRA20_SPDIF_CTRL_TX_EN; | 122 | regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, |
133 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl); | 123 | TEGRA20_SPDIF_CTRL_TX_EN, |
124 | TEGRA20_SPDIF_CTRL_TX_EN); | ||
134 | } | 125 | } |
135 | 126 | ||
136 | static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) | 127 | static void tegra20_spdif_stop_playback(struct tegra20_spdif *spdif) |
137 | { | 128 | { |
138 | spdif->reg_ctrl &= ~TEGRA20_SPDIF_CTRL_TX_EN; | 129 | regmap_update_bits(spdif->regmap, TEGRA20_SPDIF_CTRL, |
139 | tegra20_spdif_write(spdif, TEGRA20_SPDIF_CTRL, spdif->reg_ctrl); | 130 | TEGRA20_SPDIF_CTRL_TX_EN, 0); |
140 | } | 131 | } |
141 | 132 | ||
142 | static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | 133 | static int tegra20_spdif_trigger(struct snd_pcm_substream *substream, int cmd, |
@@ -181,6 +172,7 @@ static struct snd_soc_dai_driver tegra20_spdif_dai = { | |||
181 | .name = DRV_NAME, | 172 | .name = DRV_NAME, |
182 | .probe = tegra20_spdif_probe, | 173 | .probe = tegra20_spdif_probe, |
183 | .playback = { | 174 | .playback = { |
175 | .stream_name = "Playback", | ||
184 | .channels_min = 2, | 176 | .channels_min = 2, |
185 | .channels_max = 2, | 177 | .channels_max = 2, |
186 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | 178 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | |
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h index ed756527efea..b48d699fd583 100644 --- a/sound/soc/tegra/tegra20_spdif.h +++ b/sound/soc/tegra/tegra20_spdif.h | |||
@@ -465,7 +465,6 @@ struct tegra20_spdif { | |||
465 | struct tegra_pcm_dma_params capture_dma_data; | 465 | struct tegra_pcm_dma_params capture_dma_data; |
466 | struct tegra_pcm_dma_params playback_dma_data; | 466 | struct tegra_pcm_dma_params playback_dma_data; |
467 | struct regmap *regmap; | 467 | struct regmap *regmap; |
468 | u32 reg_ctrl; | ||
469 | }; | 468 | }; |
470 | 469 | ||
471 | #endif | 470 | #endif |
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 8596032985dc..b68e27a14608 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c | |||
@@ -44,18 +44,6 @@ | |||
44 | 44 | ||
45 | #define DRV_NAME "tegra30-i2s" | 45 | #define DRV_NAME "tegra30-i2s" |
46 | 46 | ||
47 | static inline void tegra30_i2s_write(struct tegra30_i2s *i2s, u32 reg, u32 val) | ||
48 | { | ||
49 | regmap_write(i2s->regmap, reg, val); | ||
50 | } | ||
51 | |||
52 | static inline u32 tegra30_i2s_read(struct tegra30_i2s *i2s, u32 reg) | ||
53 | { | ||
54 | u32 val; | ||
55 | regmap_read(i2s->regmap, reg, &val); | ||
56 | return val; | ||
57 | } | ||
58 | |||
59 | static int tegra30_i2s_runtime_suspend(struct device *dev) | 47 | static int tegra30_i2s_runtime_suspend(struct device *dev) |
60 | { | 48 | { |
61 | struct tegra30_i2s *i2s = dev_get_drvdata(dev); | 49 | struct tegra30_i2s *i2s = dev_get_drvdata(dev); |
@@ -128,6 +116,7 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, | |||
128 | unsigned int fmt) | 116 | unsigned int fmt) |
129 | { | 117 | { |
130 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 118 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
119 | unsigned int mask, val; | ||
131 | 120 | ||
132 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 121 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
133 | case SND_SOC_DAIFMT_NB_NF: | 122 | case SND_SOC_DAIFMT_NB_NF: |
@@ -136,10 +125,10 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, | |||
136 | return -EINVAL; | 125 | return -EINVAL; |
137 | } | 126 | } |
138 | 127 | ||
139 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_MASTER_ENABLE; | 128 | mask = TEGRA30_I2S_CTRL_MASTER_ENABLE; |
140 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 129 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
141 | case SND_SOC_DAIFMT_CBS_CFS: | 130 | case SND_SOC_DAIFMT_CBS_CFS: |
142 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_MASTER_ENABLE; | 131 | val = TEGRA30_I2S_CTRL_MASTER_ENABLE; |
143 | break; | 132 | break; |
144 | case SND_SOC_DAIFMT_CBM_CFM: | 133 | case SND_SOC_DAIFMT_CBM_CFM: |
145 | break; | 134 | break; |
@@ -147,33 +136,37 @@ static int tegra30_i2s_set_fmt(struct snd_soc_dai *dai, | |||
147 | return -EINVAL; | 136 | return -EINVAL; |
148 | } | 137 | } |
149 | 138 | ||
150 | i2s->reg_ctrl &= ~(TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | | 139 | mask |= TEGRA30_I2S_CTRL_FRAME_FORMAT_MASK | |
151 | TEGRA30_I2S_CTRL_LRCK_MASK); | 140 | TEGRA30_I2S_CTRL_LRCK_MASK; |
152 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 141 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
153 | case SND_SOC_DAIFMT_DSP_A: | 142 | case SND_SOC_DAIFMT_DSP_A: |
154 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; | 143 | val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; |
155 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | 144 | val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; |
156 | break; | 145 | break; |
157 | case SND_SOC_DAIFMT_DSP_B: | 146 | case SND_SOC_DAIFMT_DSP_B: |
158 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; | 147 | val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_FSYNC; |
159 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_R_LOW; | 148 | val |= TEGRA30_I2S_CTRL_LRCK_R_LOW; |
160 | break; | 149 | break; |
161 | case SND_SOC_DAIFMT_I2S: | 150 | case SND_SOC_DAIFMT_I2S: |
162 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | 151 | val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; |
163 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | 152 | val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; |
164 | break; | 153 | break; |
165 | case SND_SOC_DAIFMT_RIGHT_J: | 154 | case SND_SOC_DAIFMT_RIGHT_J: |
166 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | 155 | val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; |
167 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | 156 | val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; |
168 | break; | 157 | break; |
169 | case SND_SOC_DAIFMT_LEFT_J: | 158 | case SND_SOC_DAIFMT_LEFT_J: |
170 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; | 159 | val |= TEGRA30_I2S_CTRL_FRAME_FORMAT_LRCK; |
171 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_LRCK_L_LOW; | 160 | val |= TEGRA30_I2S_CTRL_LRCK_L_LOW; |
172 | break; | 161 | break; |
173 | default: | 162 | default: |
174 | return -EINVAL; | 163 | return -EINVAL; |
175 | } | 164 | } |
176 | 165 | ||
166 | pm_runtime_get_sync(dai->dev); | ||
167 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); | ||
168 | pm_runtime_put(dai->dev); | ||
169 | |||
177 | return 0; | 170 | return 0; |
178 | } | 171 | } |
179 | 172 | ||
@@ -181,24 +174,26 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, | |||
181 | struct snd_pcm_hw_params *params, | 174 | struct snd_pcm_hw_params *params, |
182 | struct snd_soc_dai *dai) | 175 | struct snd_soc_dai *dai) |
183 | { | 176 | { |
184 | struct device *dev = substream->pcm->card->dev; | 177 | struct device *dev = dai->dev; |
185 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); | 178 | struct tegra30_i2s *i2s = snd_soc_dai_get_drvdata(dai); |
186 | u32 val; | 179 | unsigned int mask, val, reg; |
187 | int ret, sample_size, srate, i2sclock, bitcnt; | 180 | int ret, sample_size, srate, i2sclock, bitcnt; |
188 | 181 | ||
189 | if (params_channels(params) != 2) | 182 | if (params_channels(params) != 2) |
190 | return -EINVAL; | 183 | return -EINVAL; |
191 | 184 | ||
192 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_BIT_SIZE_MASK; | 185 | mask = TEGRA30_I2S_CTRL_BIT_SIZE_MASK; |
193 | switch (params_format(params)) { | 186 | switch (params_format(params)) { |
194 | case SNDRV_PCM_FORMAT_S16_LE: | 187 | case SNDRV_PCM_FORMAT_S16_LE: |
195 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_BIT_SIZE_16; | 188 | val = TEGRA30_I2S_CTRL_BIT_SIZE_16; |
196 | sample_size = 16; | 189 | sample_size = 16; |
197 | break; | 190 | break; |
198 | default: | 191 | default: |
199 | return -EINVAL; | 192 | return -EINVAL; |
200 | } | 193 | } |
201 | 194 | ||
195 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, mask, val); | ||
196 | |||
202 | srate = params_rate(params); | 197 | srate = params_rate(params); |
203 | 198 | ||
204 | /* Final "* 2" required by Tegra hardware */ | 199 | /* Final "* 2" required by Tegra hardware */ |
@@ -219,7 +214,7 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, | |||
219 | if (i2sclock % (2 * srate)) | 214 | if (i2sclock % (2 * srate)) |
220 | val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; | 215 | val |= TEGRA30_I2S_TIMING_NON_SYM_ENABLE; |
221 | 216 | ||
222 | tegra30_i2s_write(i2s, TEGRA30_I2S_TIMING, val); | 217 | regmap_write(i2s->regmap, TEGRA30_I2S_TIMING, val); |
223 | 218 | ||
224 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | | 219 | val = (0 << TEGRA30_AUDIOCIF_CTRL_FIFO_THRESHOLD_SHIFT) | |
225 | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | | 220 | (1 << TEGRA30_AUDIOCIF_CTRL_AUDIO_CHANNELS_SHIFT) | |
@@ -229,15 +224,17 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, | |||
229 | 224 | ||
230 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 225 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
231 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; | 226 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_RX; |
232 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_RX_CTRL, val); | 227 | reg = TEGRA30_I2S_CIF_RX_CTRL; |
233 | } else { | 228 | } else { |
234 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; | 229 | val |= TEGRA30_AUDIOCIF_CTRL_DIRECTION_TX; |
235 | tegra30_i2s_write(i2s, TEGRA30_I2S_CIF_TX_CTRL, val); | 230 | reg = TEGRA30_I2S_CIF_RX_CTRL; |
236 | } | 231 | } |
237 | 232 | ||
233 | regmap_write(i2s->regmap, reg, val); | ||
234 | |||
238 | val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | | 235 | val = (1 << TEGRA30_I2S_OFFSET_RX_DATA_OFFSET_SHIFT) | |
239 | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); | 236 | (1 << TEGRA30_I2S_OFFSET_TX_DATA_OFFSET_SHIFT); |
240 | tegra30_i2s_write(i2s, TEGRA30_I2S_OFFSET, val); | 237 | regmap_write(i2s->regmap, TEGRA30_I2S_OFFSET, val); |
241 | 238 | ||
242 | return 0; | 239 | return 0; |
243 | } | 240 | } |
@@ -245,29 +242,31 @@ static int tegra30_i2s_hw_params(struct snd_pcm_substream *substream, | |||
245 | static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) | 242 | static void tegra30_i2s_start_playback(struct tegra30_i2s *i2s) |
246 | { | 243 | { |
247 | tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif); | 244 | tegra30_ahub_enable_tx_fifo(i2s->playback_fifo_cif); |
248 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_TX; | 245 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, |
249 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | 246 | TEGRA30_I2S_CTRL_XFER_EN_TX, |
247 | TEGRA30_I2S_CTRL_XFER_EN_TX); | ||
250 | } | 248 | } |
251 | 249 | ||
252 | static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) | 250 | static void tegra30_i2s_stop_playback(struct tegra30_i2s *i2s) |
253 | { | 251 | { |
254 | tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif); | 252 | tegra30_ahub_disable_tx_fifo(i2s->playback_fifo_cif); |
255 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_TX; | 253 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, |
256 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | 254 | TEGRA30_I2S_CTRL_XFER_EN_TX, 0); |
257 | } | 255 | } |
258 | 256 | ||
259 | static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) | 257 | static void tegra30_i2s_start_capture(struct tegra30_i2s *i2s) |
260 | { | 258 | { |
261 | tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif); | 259 | tegra30_ahub_enable_rx_fifo(i2s->capture_fifo_cif); |
262 | i2s->reg_ctrl |= TEGRA30_I2S_CTRL_XFER_EN_RX; | 260 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, |
263 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | 261 | TEGRA30_I2S_CTRL_XFER_EN_RX, |
262 | TEGRA30_I2S_CTRL_XFER_EN_RX); | ||
264 | } | 263 | } |
265 | 264 | ||
266 | static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) | 265 | static void tegra30_i2s_stop_capture(struct tegra30_i2s *i2s) |
267 | { | 266 | { |
268 | tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif); | 267 | tegra30_ahub_disable_rx_fifo(i2s->capture_fifo_cif); |
269 | i2s->reg_ctrl &= ~TEGRA30_I2S_CTRL_XFER_EN_RX; | 268 | regmap_update_bits(i2s->regmap, TEGRA30_I2S_CTRL, |
270 | tegra30_i2s_write(i2s, TEGRA30_I2S_CTRL, i2s->reg_ctrl); | 269 | TEGRA30_I2S_CTRL_XFER_EN_RX, 0); |
271 | } | 270 | } |
272 | 271 | ||
273 | static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | 272 | static int tegra30_i2s_trigger(struct snd_pcm_substream *substream, int cmd, |
@@ -320,12 +319,14 @@ static struct snd_soc_dai_ops tegra30_i2s_dai_ops = { | |||
320 | static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { | 319 | static const struct snd_soc_dai_driver tegra30_i2s_dai_template = { |
321 | .probe = tegra30_i2s_probe, | 320 | .probe = tegra30_i2s_probe, |
322 | .playback = { | 321 | .playback = { |
322 | .stream_name = "Playback", | ||
323 | .channels_min = 2, | 323 | .channels_min = 2, |
324 | .channels_max = 2, | 324 | .channels_max = 2, |
325 | .rates = SNDRV_PCM_RATE_8000_96000, | 325 | .rates = SNDRV_PCM_RATE_8000_96000, |
326 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 326 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
327 | }, | 327 | }, |
328 | .capture = { | 328 | .capture = { |
329 | .stream_name = "Capture", | ||
329 | .channels_min = 2, | 330 | .channels_min = 2, |
330 | .channels_max = 2, | 331 | .channels_max = 2, |
331 | .rates = SNDRV_PCM_RATE_8000_96000, | 332 | .rates = SNDRV_PCM_RATE_8000_96000, |
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h index 91adf29c7a87..34dc47b9581c 100644 --- a/sound/soc/tegra/tegra30_i2s.h +++ b/sound/soc/tegra/tegra30_i2s.h | |||
@@ -236,7 +236,6 @@ struct tegra30_i2s { | |||
236 | enum tegra30_ahub_txcif playback_fifo_cif; | 236 | enum tegra30_ahub_txcif playback_fifo_cif; |
237 | struct tegra_pcm_dma_params playback_dma_data; | 237 | struct tegra_pcm_dma_params playback_dma_data; |
238 | struct regmap *regmap; | 238 | struct regmap *regmap; |
239 | u32 reg_ctrl; | ||
240 | }; | 239 | }; |
241 | 240 | ||
242 | #endif | 241 | #endif |
diff --git a/sound/soc/tegra/tegra_alc5632.c b/sound/soc/tegra/tegra_alc5632.c index 32de7006daf0..d684df294c0c 100644 --- a/sound/soc/tegra/tegra_alc5632.c +++ b/sound/soc/tegra/tegra_alc5632.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver | 2 | * tegra_alc5632.c -- Toshiba AC100(PAZ00) machine ASoC driver |
3 | * | 3 | * |
4 | * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> | 4 | * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> |
5 | * Copyright (C) 2012 - NVIDIA, Inc. | 5 | * Copyright (C) 2012 - NVIDIA, Inc. |
@@ -33,11 +33,8 @@ | |||
33 | 33 | ||
34 | #define DRV_NAME "tegra-alc5632" | 34 | #define DRV_NAME "tegra-alc5632" |
35 | 35 | ||
36 | #define GPIO_HP_DET BIT(0) | ||
37 | |||
38 | struct tegra_alc5632 { | 36 | struct tegra_alc5632 { |
39 | struct tegra_asoc_utils_data util_data; | 37 | struct tegra_asoc_utils_data util_data; |
40 | int gpio_requested; | ||
41 | int gpio_hp_det; | 38 | int gpio_hp_det; |
42 | }; | 39 | }; |
43 | 40 | ||
@@ -46,7 +43,7 @@ static int tegra_alc5632_asoc_hw_params(struct snd_pcm_substream *substream, | |||
46 | { | 43 | { |
47 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 44 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
48 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 45 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
49 | struct snd_soc_codec *codec = rtd->codec; | 46 | struct snd_soc_codec *codec = codec_dai->codec; |
50 | struct snd_soc_card *card = codec->card; | 47 | struct snd_soc_card *card = codec->card; |
51 | struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); | 48 | struct tegra_alc5632 *alc5632 = snd_soc_card_get_drvdata(card); |
52 | int srate, mclk; | 49 | int srate, mclk; |
@@ -108,9 +105,9 @@ static const struct snd_kcontrol_new tegra_alc5632_controls[] = { | |||
108 | 105 | ||
109 | static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) | 106 | static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) |
110 | { | 107 | { |
111 | struct snd_soc_codec *codec = rtd->codec; | 108 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
109 | struct snd_soc_codec *codec = codec_dai->codec; | ||
112 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 110 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
113 | struct device_node *np = codec->card->dev->of_node; | ||
114 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card); | 111 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(codec->card); |
115 | 112 | ||
116 | snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, | 113 | snd_soc_jack_new(codec, "Headset Jack", SND_JACK_HEADSET, |
@@ -119,14 +116,11 @@ static int tegra_alc5632_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
119 | ARRAY_SIZE(tegra_alc5632_hs_jack_pins), | 116 | ARRAY_SIZE(tegra_alc5632_hs_jack_pins), |
120 | tegra_alc5632_hs_jack_pins); | 117 | tegra_alc5632_hs_jack_pins); |
121 | 118 | ||
122 | machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); | ||
123 | |||
124 | if (gpio_is_valid(machine->gpio_hp_det)) { | 119 | if (gpio_is_valid(machine->gpio_hp_det)) { |
125 | tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; | 120 | tegra_alc5632_hp_jack_gpio.gpio = machine->gpio_hp_det; |
126 | snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack, | 121 | snd_soc_jack_add_gpios(&tegra_alc5632_hs_jack, |
127 | 1, | 122 | 1, |
128 | &tegra_alc5632_hp_jack_gpio); | 123 | &tegra_alc5632_hp_jack_gpio); |
129 | machine->gpio_requested |= GPIO_HP_DET; | ||
130 | } | 124 | } |
131 | 125 | ||
132 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); | 126 | snd_soc_dapm_force_enable_pin(dapm, "MICBIAS1"); |
@@ -159,6 +153,7 @@ static struct snd_soc_card snd_soc_tegra_alc5632 = { | |||
159 | 153 | ||
160 | static __devinit int tegra_alc5632_probe(struct platform_device *pdev) | 154 | static __devinit int tegra_alc5632_probe(struct platform_device *pdev) |
161 | { | 155 | { |
156 | struct device_node *np = pdev->dev.of_node; | ||
162 | struct snd_soc_card *card = &snd_soc_tegra_alc5632; | 157 | struct snd_soc_card *card = &snd_soc_tegra_alc5632; |
163 | struct tegra_alc5632 *alc5632; | 158 | struct tegra_alc5632 *alc5632; |
164 | int ret; | 159 | int ret; |
@@ -181,6 +176,10 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) | |||
181 | goto err; | 176 | goto err; |
182 | } | 177 | } |
183 | 178 | ||
179 | alc5632->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0); | ||
180 | if (alc5632->gpio_hp_det == -ENODEV) | ||
181 | return -EPROBE_DEFER; | ||
182 | |||
184 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); | 183 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); |
185 | if (ret) | 184 | if (ret) |
186 | goto err; | 185 | goto err; |
@@ -199,16 +198,16 @@ static __devinit int tegra_alc5632_probe(struct platform_device *pdev) | |||
199 | goto err; | 198 | goto err; |
200 | } | 199 | } |
201 | 200 | ||
202 | tegra_alc5632_dai.cpu_dai_of_node = of_parse_phandle( | 201 | tegra_alc5632_dai.cpu_of_node = of_parse_phandle( |
203 | pdev->dev.of_node, "nvidia,i2s-controller", 0); | 202 | pdev->dev.of_node, "nvidia,i2s-controller", 0); |
204 | if (!tegra_alc5632_dai.cpu_dai_of_node) { | 203 | if (!tegra_alc5632_dai.cpu_of_node) { |
205 | dev_err(&pdev->dev, | 204 | dev_err(&pdev->dev, |
206 | "Property 'nvidia,i2s-controller' missing or invalid\n"); | 205 | "Property 'nvidia,i2s-controller' missing or invalid\n"); |
207 | ret = -EINVAL; | 206 | ret = -EINVAL; |
208 | goto err; | 207 | goto err; |
209 | } | 208 | } |
210 | 209 | ||
211 | tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_dai_of_node; | 210 | tegra_alc5632_dai.platform_of_node = tegra_alc5632_dai.cpu_of_node; |
212 | 211 | ||
213 | ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev); | 212 | ret = tegra_asoc_utils_init(&alc5632->util_data, &pdev->dev); |
214 | if (ret) | 213 | if (ret) |
@@ -234,11 +233,8 @@ static int __devexit tegra_alc5632_remove(struct platform_device *pdev) | |||
234 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 233 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
235 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); | 234 | struct tegra_alc5632 *machine = snd_soc_card_get_drvdata(card); |
236 | 235 | ||
237 | if (machine->gpio_requested & GPIO_HP_DET) | 236 | snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, 1, |
238 | snd_soc_jack_free_gpios(&tegra_alc5632_hs_jack, | 237 | &tegra_alc5632_hp_jack_gpio); |
239 | 1, | ||
240 | &tegra_alc5632_hp_jack_gpio); | ||
241 | machine->gpio_requested = 0; | ||
242 | 238 | ||
243 | snd_soc_unregister_card(card); | 239 | snd_soc_unregister_card(card); |
244 | 240 | ||
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c index 127348dc09b1..5658bcec1931 100644 --- a/sound/soc/tegra/tegra_pcm.c +++ b/sound/soc/tegra/tegra_pcm.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <sound/pcm.h> | 36 | #include <sound/pcm.h> |
37 | #include <sound/pcm_params.h> | 37 | #include <sound/pcm_params.h> |
38 | #include <sound/soc.h> | 38 | #include <sound/soc.h> |
39 | #include <sound/dmaengine_pcm.h> | ||
39 | 40 | ||
40 | #include "tegra_pcm.h" | 41 | #include "tegra_pcm.h" |
41 | 42 | ||
@@ -56,6 +57,7 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = { | |||
56 | .fifo_size = 4, | 57 | .fifo_size = 4, |
57 | }; | 58 | }; |
58 | 59 | ||
60 | #if defined(CONFIG_TEGRA_SYSTEM_DMA) | ||
59 | static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) | 61 | static void tegra_pcm_queue_dma(struct tegra_runtime_data *prtd) |
60 | { | 62 | { |
61 | struct snd_pcm_substream *substream = prtd->substream; | 63 | struct snd_pcm_substream *substream = prtd->substream; |
@@ -285,6 +287,119 @@ static struct snd_pcm_ops tegra_pcm_ops = { | |||
285 | .pointer = tegra_pcm_pointer, | 287 | .pointer = tegra_pcm_pointer, |
286 | .mmap = tegra_pcm_mmap, | 288 | .mmap = tegra_pcm_mmap, |
287 | }; | 289 | }; |
290 | #else | ||
291 | static int tegra_pcm_open(struct snd_pcm_substream *substream) | ||
292 | { | ||
293 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
294 | struct device *dev = rtd->platform->dev; | ||
295 | int ret; | ||
296 | |||
297 | /* Set HW params now that initialization is complete */ | ||
298 | snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware); | ||
299 | |||
300 | ret = snd_dmaengine_pcm_open(substream, NULL, NULL); | ||
301 | if (ret) { | ||
302 | dev_err(dev, "dmaengine pcm open failed with err %d\n", ret); | ||
303 | return ret; | ||
304 | } | ||
305 | |||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int tegra_pcm_close(struct snd_pcm_substream *substream) | ||
310 | { | ||
311 | snd_dmaengine_pcm_close(substream); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | static int tegra_pcm_hw_params(struct snd_pcm_substream *substream, | ||
316 | struct snd_pcm_hw_params *params) | ||
317 | { | ||
318 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
319 | struct device *dev = rtd->platform->dev; | ||
320 | struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream); | ||
321 | struct tegra_pcm_dma_params *dmap; | ||
322 | struct dma_slave_config slave_config; | ||
323 | int ret; | ||
324 | |||
325 | dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); | ||
326 | |||
327 | ret = snd_hwparams_to_dma_slave_config(substream, params, | ||
328 | &slave_config); | ||
329 | if (ret) { | ||
330 | dev_err(dev, "hw params config failed with err %d\n", ret); | ||
331 | return ret; | ||
332 | } | ||
333 | |||
334 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
335 | slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
336 | slave_config.dst_addr = dmap->addr; | ||
337 | slave_config.src_maxburst = 0; | ||
338 | } else { | ||
339 | slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
340 | slave_config.src_addr = dmap->addr; | ||
341 | slave_config.dst_maxburst = 0; | ||
342 | } | ||
343 | slave_config.slave_id = dmap->req_sel; | ||
344 | |||
345 | ret = dmaengine_slave_config(chan, &slave_config); | ||
346 | if (ret < 0) { | ||
347 | dev_err(dev, "dma slave config failed with err %d\n", ret); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | static int tegra_pcm_hw_free(struct snd_pcm_substream *substream) | ||
356 | { | ||
357 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
358 | return 0; | ||
359 | } | ||
360 | |||
361 | static int tegra_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
362 | { | ||
363 | switch (cmd) { | ||
364 | case SNDRV_PCM_TRIGGER_START: | ||
365 | case SNDRV_PCM_TRIGGER_RESUME: | ||
366 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
367 | return snd_dmaengine_pcm_trigger(substream, | ||
368 | SNDRV_PCM_TRIGGER_START); | ||
369 | |||
370 | case SNDRV_PCM_TRIGGER_STOP: | ||
371 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
372 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
373 | return snd_dmaengine_pcm_trigger(substream, | ||
374 | SNDRV_PCM_TRIGGER_STOP); | ||
375 | default: | ||
376 | return -EINVAL; | ||
377 | } | ||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int tegra_pcm_mmap(struct snd_pcm_substream *substream, | ||
382 | struct vm_area_struct *vma) | ||
383 | { | ||
384 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
385 | |||
386 | return dma_mmap_writecombine(substream->pcm->card->dev, vma, | ||
387 | runtime->dma_area, | ||
388 | runtime->dma_addr, | ||
389 | runtime->dma_bytes); | ||
390 | } | ||
391 | |||
392 | static struct snd_pcm_ops tegra_pcm_ops = { | ||
393 | .open = tegra_pcm_open, | ||
394 | .close = tegra_pcm_close, | ||
395 | .ioctl = snd_pcm_lib_ioctl, | ||
396 | .hw_params = tegra_pcm_hw_params, | ||
397 | .hw_free = tegra_pcm_hw_free, | ||
398 | .trigger = tegra_pcm_trigger, | ||
399 | .pointer = snd_dmaengine_pcm_pointer, | ||
400 | .mmap = tegra_pcm_mmap, | ||
401 | }; | ||
402 | #endif | ||
288 | 403 | ||
289 | static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) | 404 | static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream) |
290 | { | 405 | { |
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h index 985d418a35e7..a3a450352dcf 100644 --- a/sound/soc/tegra/tegra_pcm.h +++ b/sound/soc/tegra/tegra_pcm.h | |||
@@ -40,6 +40,7 @@ struct tegra_pcm_dma_params { | |||
40 | unsigned long req_sel; | 40 | unsigned long req_sel; |
41 | }; | 41 | }; |
42 | 42 | ||
43 | #if defined(CONFIG_TEGRA_SYSTEM_DMA) | ||
43 | struct tegra_runtime_data { | 44 | struct tegra_runtime_data { |
44 | struct snd_pcm_substream *substream; | 45 | struct snd_pcm_substream *substream; |
45 | spinlock_t lock; | 46 | spinlock_t lock; |
@@ -51,6 +52,7 @@ struct tegra_runtime_data { | |||
51 | struct tegra_dma_req dma_req[2]; | 52 | struct tegra_dma_req dma_req[2]; |
52 | struct tegra_dma_channel *dma_chan; | 53 | struct tegra_dma_channel *dma_chan; |
53 | }; | 54 | }; |
55 | #endif | ||
54 | 56 | ||
55 | int tegra_pcm_platform_register(struct device *dev); | 57 | int tegra_pcm_platform_register(struct device *dev); |
56 | void tegra_pcm_platform_unregister(struct device *dev); | 58 | void tegra_pcm_platform_unregister(struct device *dev); |
diff --git a/sound/soc/tegra/tegra_wm8753.c b/sound/soc/tegra/tegra_wm8753.c index 4e77026807a2..ea9166d5c4eb 100644 --- a/sound/soc/tegra/tegra_wm8753.c +++ b/sound/soc/tegra/tegra_wm8753.c | |||
@@ -57,7 +57,7 @@ static int tegra_wm8753_hw_params(struct snd_pcm_substream *substream, | |||
57 | { | 57 | { |
58 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 58 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
59 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 59 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
60 | struct snd_soc_codec *codec = rtd->codec; | 60 | struct snd_soc_codec *codec = codec_dai->codec; |
61 | struct snd_soc_card *card = codec->card; | 61 | struct snd_soc_card *card = codec->card; |
62 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); | 62 | struct tegra_wm8753 *machine = snd_soc_card_get_drvdata(card); |
63 | int srate, mclk; | 63 | int srate, mclk; |
@@ -157,9 +157,9 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) | |||
157 | goto err; | 157 | goto err; |
158 | } | 158 | } |
159 | 159 | ||
160 | tegra_wm8753_dai.cpu_dai_of_node = of_parse_phandle( | 160 | tegra_wm8753_dai.cpu_of_node = of_parse_phandle( |
161 | pdev->dev.of_node, "nvidia,i2s-controller", 0); | 161 | pdev->dev.of_node, "nvidia,i2s-controller", 0); |
162 | if (!tegra_wm8753_dai.cpu_dai_of_node) { | 162 | if (!tegra_wm8753_dai.cpu_of_node) { |
163 | dev_err(&pdev->dev, | 163 | dev_err(&pdev->dev, |
164 | "Property 'nvidia,i2s-controller' missing or invalid\n"); | 164 | "Property 'nvidia,i2s-controller' missing or invalid\n"); |
165 | ret = -EINVAL; | 165 | ret = -EINVAL; |
@@ -167,7 +167,7 @@ static __devinit int tegra_wm8753_driver_probe(struct platform_device *pdev) | |||
167 | } | 167 | } |
168 | 168 | ||
169 | tegra_wm8753_dai.platform_of_node = | 169 | tegra_wm8753_dai.platform_of_node = |
170 | tegra_wm8753_dai.cpu_dai_of_node; | 170 | tegra_wm8753_dai.cpu_of_node; |
171 | 171 | ||
172 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); | 172 | ret = tegra_asoc_utils_init(&machine->util_data, &pdev->dev); |
173 | if (ret) | 173 | if (ret) |
diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 3b6da91188a9..0c5bb33d258e 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c | |||
@@ -28,8 +28,6 @@ | |||
28 | * | 28 | * |
29 | */ | 29 | */ |
30 | 30 | ||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include <linux/module.h> | 31 | #include <linux/module.h> |
34 | #include <linux/platform_device.h> | 32 | #include <linux/platform_device.h> |
35 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
@@ -50,16 +48,9 @@ | |||
50 | 48 | ||
51 | #define DRV_NAME "tegra-snd-wm8903" | 49 | #define DRV_NAME "tegra-snd-wm8903" |
52 | 50 | ||
53 | #define GPIO_SPKR_EN BIT(0) | ||
54 | #define GPIO_HP_MUTE BIT(1) | ||
55 | #define GPIO_INT_MIC_EN BIT(2) | ||
56 | #define GPIO_EXT_MIC_EN BIT(3) | ||
57 | #define GPIO_HP_DET BIT(4) | ||
58 | |||
59 | struct tegra_wm8903 { | 51 | struct tegra_wm8903 { |
60 | struct tegra_wm8903_platform_data pdata; | 52 | struct tegra_wm8903_platform_data pdata; |
61 | struct tegra_asoc_utils_data util_data; | 53 | struct tegra_asoc_utils_data util_data; |
62 | int gpio_requested; | ||
63 | }; | 54 | }; |
64 | 55 | ||
65 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | 56 | static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, |
@@ -67,8 +58,7 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
67 | { | 58 | { |
68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 59 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
69 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 60 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
70 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 61 | struct snd_soc_codec *codec = codec_dai->codec; |
71 | struct snd_soc_codec *codec = rtd->codec; | ||
72 | struct snd_soc_card *card = codec->card; | 62 | struct snd_soc_card *card = codec->card; |
73 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 63 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
74 | int srate, mclk; | 64 | int srate, mclk; |
@@ -95,24 +85,6 @@ static int tegra_wm8903_hw_params(struct snd_pcm_substream *substream, | |||
95 | return err; | 85 | return err; |
96 | } | 86 | } |
97 | 87 | ||
98 | err = snd_soc_dai_set_fmt(codec_dai, | ||
99 | SND_SOC_DAIFMT_I2S | | ||
100 | SND_SOC_DAIFMT_NB_NF | | ||
101 | SND_SOC_DAIFMT_CBS_CFS); | ||
102 | if (err < 0) { | ||
103 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
104 | return err; | ||
105 | } | ||
106 | |||
107 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
108 | SND_SOC_DAIFMT_I2S | | ||
109 | SND_SOC_DAIFMT_NB_NF | | ||
110 | SND_SOC_DAIFMT_CBS_CFS); | ||
111 | if (err < 0) { | ||
112 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
113 | return err; | ||
114 | } | ||
115 | |||
116 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | 88 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, |
117 | SND_SOC_CLOCK_IN); | 89 | SND_SOC_CLOCK_IN); |
118 | if (err < 0) { | 90 | if (err < 0) { |
@@ -160,7 +132,7 @@ static int tegra_wm8903_event_int_spk(struct snd_soc_dapm_widget *w, | |||
160 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 132 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
161 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; | 133 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; |
162 | 134 | ||
163 | if (!(machine->gpio_requested & GPIO_SPKR_EN)) | 135 | if (!gpio_is_valid(pdata->gpio_spkr_en)) |
164 | return 0; | 136 | return 0; |
165 | 137 | ||
166 | gpio_set_value_cansleep(pdata->gpio_spkr_en, | 138 | gpio_set_value_cansleep(pdata->gpio_spkr_en, |
@@ -177,7 +149,7 @@ static int tegra_wm8903_event_hp(struct snd_soc_dapm_widget *w, | |||
177 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 149 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
178 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; | 150 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; |
179 | 151 | ||
180 | if (!(machine->gpio_requested & GPIO_HP_MUTE)) | 152 | if (!gpio_is_valid(pdata->gpio_hp_mute)) |
181 | return 0; | 153 | return 0; |
182 | 154 | ||
183 | gpio_set_value_cansleep(pdata->gpio_hp_mute, | 155 | gpio_set_value_cansleep(pdata->gpio_hp_mute, |
@@ -203,122 +175,18 @@ static const struct snd_soc_dapm_route harmony_audio_map[] = { | |||
203 | {"IN1L", NULL, "Mic Jack"}, | 175 | {"IN1L", NULL, "Mic Jack"}, |
204 | }; | 176 | }; |
205 | 177 | ||
206 | static const struct snd_soc_dapm_route seaboard_audio_map[] = { | ||
207 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
208 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
209 | {"Int Spk", NULL, "ROP"}, | ||
210 | {"Int Spk", NULL, "RON"}, | ||
211 | {"Int Spk", NULL, "LOP"}, | ||
212 | {"Int Spk", NULL, "LON"}, | ||
213 | {"Mic Jack", NULL, "MICBIAS"}, | ||
214 | {"IN1R", NULL, "Mic Jack"}, | ||
215 | }; | ||
216 | |||
217 | static const struct snd_soc_dapm_route kaen_audio_map[] = { | ||
218 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
219 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
220 | {"Int Spk", NULL, "ROP"}, | ||
221 | {"Int Spk", NULL, "RON"}, | ||
222 | {"Int Spk", NULL, "LOP"}, | ||
223 | {"Int Spk", NULL, "LON"}, | ||
224 | {"Mic Jack", NULL, "MICBIAS"}, | ||
225 | {"IN2R", NULL, "Mic Jack"}, | ||
226 | }; | ||
227 | |||
228 | static const struct snd_soc_dapm_route aebl_audio_map[] = { | ||
229 | {"Headphone Jack", NULL, "HPOUTR"}, | ||
230 | {"Headphone Jack", NULL, "HPOUTL"}, | ||
231 | {"Int Spk", NULL, "LINEOUTR"}, | ||
232 | {"Int Spk", NULL, "LINEOUTL"}, | ||
233 | {"Mic Jack", NULL, "MICBIAS"}, | ||
234 | {"IN1R", NULL, "Mic Jack"}, | ||
235 | }; | ||
236 | |||
237 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { | 178 | static const struct snd_kcontrol_new tegra_wm8903_controls[] = { |
238 | SOC_DAPM_PIN_SWITCH("Int Spk"), | 179 | SOC_DAPM_PIN_SWITCH("Int Spk"), |
239 | }; | 180 | }; |
240 | 181 | ||
241 | static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | 182 | static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) |
242 | { | 183 | { |
243 | struct snd_soc_codec *codec = rtd->codec; | 184 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
185 | struct snd_soc_codec *codec = codec_dai->codec; | ||
244 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 186 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
245 | struct snd_soc_card *card = codec->card; | 187 | struct snd_soc_card *card = codec->card; |
246 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 188 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
247 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; | 189 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; |
248 | struct device_node *np = card->dev->of_node; | ||
249 | int ret; | ||
250 | |||
251 | if (card->dev->platform_data) { | ||
252 | memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); | ||
253 | } else if (np) { | ||
254 | /* | ||
255 | * This part must be in init() rather than probe() in order to | ||
256 | * guarantee that the WM8903 has been probed, and hence its | ||
257 | * GPIO controller registered, which is a pre-condition for | ||
258 | * of_get_named_gpio() to be able to map the phandles in the | ||
259 | * properties to the controller node. Given this, all | ||
260 | * pdata handling is in init() for consistency. | ||
261 | */ | ||
262 | pdata->gpio_spkr_en = of_get_named_gpio(np, | ||
263 | "nvidia,spkr-en-gpios", 0); | ||
264 | pdata->gpio_hp_mute = of_get_named_gpio(np, | ||
265 | "nvidia,hp-mute-gpios", 0); | ||
266 | pdata->gpio_hp_det = of_get_named_gpio(np, | ||
267 | "nvidia,hp-det-gpios", 0); | ||
268 | pdata->gpio_int_mic_en = of_get_named_gpio(np, | ||
269 | "nvidia,int-mic-en-gpios", 0); | ||
270 | pdata->gpio_ext_mic_en = of_get_named_gpio(np, | ||
271 | "nvidia,ext-mic-en-gpios", 0); | ||
272 | } else { | ||
273 | dev_err(card->dev, "No platform data supplied\n"); | ||
274 | return -EINVAL; | ||
275 | } | ||
276 | |||
277 | if (gpio_is_valid(pdata->gpio_spkr_en)) { | ||
278 | ret = gpio_request(pdata->gpio_spkr_en, "spkr_en"); | ||
279 | if (ret) { | ||
280 | dev_err(card->dev, "cannot get spkr_en gpio\n"); | ||
281 | return ret; | ||
282 | } | ||
283 | machine->gpio_requested |= GPIO_SPKR_EN; | ||
284 | |||
285 | gpio_direction_output(pdata->gpio_spkr_en, 0); | ||
286 | } | ||
287 | |||
288 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
289 | ret = gpio_request(pdata->gpio_hp_mute, "hp_mute"); | ||
290 | if (ret) { | ||
291 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
292 | return ret; | ||
293 | } | ||
294 | machine->gpio_requested |= GPIO_HP_MUTE; | ||
295 | |||
296 | gpio_direction_output(pdata->gpio_hp_mute, 1); | ||
297 | } | ||
298 | |||
299 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
300 | ret = gpio_request(pdata->gpio_int_mic_en, "int_mic_en"); | ||
301 | if (ret) { | ||
302 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
303 | return ret; | ||
304 | } | ||
305 | machine->gpio_requested |= GPIO_INT_MIC_EN; | ||
306 | |||
307 | /* Disable int mic; enable signal is active-high */ | ||
308 | gpio_direction_output(pdata->gpio_int_mic_en, 0); | ||
309 | } | ||
310 | |||
311 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
312 | ret = gpio_request(pdata->gpio_ext_mic_en, "ext_mic_en"); | ||
313 | if (ret) { | ||
314 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
315 | return ret; | ||
316 | } | ||
317 | machine->gpio_requested |= GPIO_EXT_MIC_EN; | ||
318 | |||
319 | /* Enable ext mic; enable signal is active-low */ | ||
320 | gpio_direction_output(pdata->gpio_ext_mic_en, 0); | ||
321 | } | ||
322 | 190 | ||
323 | if (gpio_is_valid(pdata->gpio_hp_det)) { | 191 | if (gpio_is_valid(pdata->gpio_hp_det)) { |
324 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; | 192 | tegra_wm8903_hp_jack_gpio.gpio = pdata->gpio_hp_det; |
@@ -330,7 +198,6 @@ static int tegra_wm8903_init(struct snd_soc_pcm_runtime *rtd) | |||
330 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, | 198 | snd_soc_jack_add_gpios(&tegra_wm8903_hp_jack, |
331 | 1, | 199 | 1, |
332 | &tegra_wm8903_hp_jack_gpio); | 200 | &tegra_wm8903_hp_jack_gpio); |
333 | machine->gpio_requested |= GPIO_HP_DET; | ||
334 | } | 201 | } |
335 | 202 | ||
336 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | 203 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, |
@@ -366,6 +233,9 @@ static struct snd_soc_dai_link tegra_wm8903_dai = { | |||
366 | .codec_dai_name = "wm8903-hifi", | 233 | .codec_dai_name = "wm8903-hifi", |
367 | .init = tegra_wm8903_init, | 234 | .init = tegra_wm8903_init, |
368 | .ops = &tegra_wm8903_ops, | 235 | .ops = &tegra_wm8903_ops, |
236 | .dai_fmt = SND_SOC_DAIFMT_I2S | | ||
237 | SND_SOC_DAIFMT_NB_NF | | ||
238 | SND_SOC_DAIFMT_CBS_CFS, | ||
369 | }; | 239 | }; |
370 | 240 | ||
371 | static struct snd_soc_card snd_soc_tegra_wm8903 = { | 241 | static struct snd_soc_card snd_soc_tegra_wm8903 = { |
@@ -385,8 +255,10 @@ static struct snd_soc_card snd_soc_tegra_wm8903 = { | |||
385 | 255 | ||
386 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | 256 | static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) |
387 | { | 257 | { |
258 | struct device_node *np = pdev->dev.of_node; | ||
388 | struct snd_soc_card *card = &snd_soc_tegra_wm8903; | 259 | struct snd_soc_card *card = &snd_soc_tegra_wm8903; |
389 | struct tegra_wm8903 *machine; | 260 | struct tegra_wm8903 *machine; |
261 | struct tegra_wm8903_platform_data *pdata; | ||
390 | int ret; | 262 | int ret; |
391 | 263 | ||
392 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { | 264 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { |
@@ -401,12 +273,42 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
401 | ret = -ENOMEM; | 273 | ret = -ENOMEM; |
402 | goto err; | 274 | goto err; |
403 | } | 275 | } |
276 | pdata = &machine->pdata; | ||
404 | 277 | ||
405 | card->dev = &pdev->dev; | 278 | card->dev = &pdev->dev; |
406 | platform_set_drvdata(pdev, card); | 279 | platform_set_drvdata(pdev, card); |
407 | snd_soc_card_set_drvdata(card, machine); | 280 | snd_soc_card_set_drvdata(card, machine); |
408 | 281 | ||
409 | if (pdev->dev.of_node) { | 282 | if (pdev->dev.platform_data) { |
283 | memcpy(pdata, card->dev->platform_data, sizeof(*pdata)); | ||
284 | } else if (np) { | ||
285 | pdata->gpio_spkr_en = of_get_named_gpio(np, | ||
286 | "nvidia,spkr-en-gpios", 0); | ||
287 | if (pdata->gpio_spkr_en == -ENODEV) | ||
288 | return -EPROBE_DEFER; | ||
289 | |||
290 | pdata->gpio_hp_mute = of_get_named_gpio(np, | ||
291 | "nvidia,hp-mute-gpios", 0); | ||
292 | if (pdata->gpio_hp_mute == -ENODEV) | ||
293 | return -EPROBE_DEFER; | ||
294 | |||
295 | pdata->gpio_hp_det = of_get_named_gpio(np, | ||
296 | "nvidia,hp-det-gpios", 0); | ||
297 | if (pdata->gpio_hp_det == -ENODEV) | ||
298 | return -EPROBE_DEFER; | ||
299 | |||
300 | pdata->gpio_int_mic_en = of_get_named_gpio(np, | ||
301 | "nvidia,int-mic-en-gpios", 0); | ||
302 | if (pdata->gpio_int_mic_en == -ENODEV) | ||
303 | return -EPROBE_DEFER; | ||
304 | |||
305 | pdata->gpio_ext_mic_en = of_get_named_gpio(np, | ||
306 | "nvidia,ext-mic-en-gpios", 0); | ||
307 | if (pdata->gpio_ext_mic_en == -ENODEV) | ||
308 | return -EPROBE_DEFER; | ||
309 | } | ||
310 | |||
311 | if (np) { | ||
410 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); | 312 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); |
411 | if (ret) | 313 | if (ret) |
412 | goto err; | 314 | goto err; |
@@ -417,8 +319,8 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
417 | goto err; | 319 | goto err; |
418 | 320 | ||
419 | tegra_wm8903_dai.codec_name = NULL; | 321 | tegra_wm8903_dai.codec_name = NULL; |
420 | tegra_wm8903_dai.codec_of_node = of_parse_phandle( | 322 | tegra_wm8903_dai.codec_of_node = of_parse_phandle(np, |
421 | pdev->dev.of_node, "nvidia,audio-codec", 0); | 323 | "nvidia,audio-codec", 0); |
422 | if (!tegra_wm8903_dai.codec_of_node) { | 324 | if (!tegra_wm8903_dai.codec_of_node) { |
423 | dev_err(&pdev->dev, | 325 | dev_err(&pdev->dev, |
424 | "Property 'nvidia,audio-codec' missing or invalid\n"); | 326 | "Property 'nvidia,audio-codec' missing or invalid\n"); |
@@ -427,9 +329,9 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
427 | } | 329 | } |
428 | 330 | ||
429 | tegra_wm8903_dai.cpu_dai_name = NULL; | 331 | tegra_wm8903_dai.cpu_dai_name = NULL; |
430 | tegra_wm8903_dai.cpu_dai_of_node = of_parse_phandle( | 332 | tegra_wm8903_dai.cpu_of_node = of_parse_phandle(np, |
431 | pdev->dev.of_node, "nvidia,i2s-controller", 0); | 333 | "nvidia,i2s-controller", 0); |
432 | if (!tegra_wm8903_dai.cpu_dai_of_node) { | 334 | if (!tegra_wm8903_dai.cpu_of_node) { |
433 | dev_err(&pdev->dev, | 335 | dev_err(&pdev->dev, |
434 | "Property 'nvidia,i2s-controller' missing or invalid\n"); | 336 | "Property 'nvidia,i2s-controller' missing or invalid\n"); |
435 | ret = -EINVAL; | 337 | ret = -EINVAL; |
@@ -438,20 +340,47 @@ static __devinit int tegra_wm8903_driver_probe(struct platform_device *pdev) | |||
438 | 340 | ||
439 | tegra_wm8903_dai.platform_name = NULL; | 341 | tegra_wm8903_dai.platform_name = NULL; |
440 | tegra_wm8903_dai.platform_of_node = | 342 | tegra_wm8903_dai.platform_of_node = |
441 | tegra_wm8903_dai.cpu_dai_of_node; | 343 | tegra_wm8903_dai.cpu_of_node; |
442 | } else { | 344 | } else { |
443 | if (machine_is_harmony()) { | 345 | card->dapm_routes = harmony_audio_map; |
444 | card->dapm_routes = harmony_audio_map; | 346 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); |
445 | card->num_dapm_routes = ARRAY_SIZE(harmony_audio_map); | 347 | } |
446 | } else if (machine_is_seaboard()) { | 348 | |
447 | card->dapm_routes = seaboard_audio_map; | 349 | if (gpio_is_valid(pdata->gpio_spkr_en)) { |
448 | card->num_dapm_routes = ARRAY_SIZE(seaboard_audio_map); | 350 | ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_spkr_en, |
449 | } else if (machine_is_kaen()) { | 351 | GPIOF_OUT_INIT_LOW, "spkr_en"); |
450 | card->dapm_routes = kaen_audio_map; | 352 | if (ret) { |
451 | card->num_dapm_routes = ARRAY_SIZE(kaen_audio_map); | 353 | dev_err(card->dev, "cannot get spkr_en gpio\n"); |
452 | } else { | 354 | return ret; |
453 | card->dapm_routes = aebl_audio_map; | 355 | } |
454 | card->num_dapm_routes = ARRAY_SIZE(aebl_audio_map); | 356 | } |
357 | |||
358 | if (gpio_is_valid(pdata->gpio_hp_mute)) { | ||
359 | ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_hp_mute, | ||
360 | GPIOF_OUT_INIT_HIGH, "hp_mute"); | ||
361 | if (ret) { | ||
362 | dev_err(card->dev, "cannot get hp_mute gpio\n"); | ||
363 | return ret; | ||
364 | } | ||
365 | } | ||
366 | |||
367 | if (gpio_is_valid(pdata->gpio_int_mic_en)) { | ||
368 | /* Disable int mic; enable signal is active-high */ | ||
369 | ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_int_mic_en, | ||
370 | GPIOF_OUT_INIT_LOW, "int_mic_en"); | ||
371 | if (ret) { | ||
372 | dev_err(card->dev, "cannot get int_mic_en gpio\n"); | ||
373 | return ret; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | if (gpio_is_valid(pdata->gpio_ext_mic_en)) { | ||
378 | /* Enable ext mic; enable signal is active-low */ | ||
379 | ret = devm_gpio_request_one(&pdev->dev, pdata->gpio_ext_mic_en, | ||
380 | GPIOF_OUT_INIT_LOW, "ext_mic_en"); | ||
381 | if (ret) { | ||
382 | dev_err(card->dev, "cannot get ext_mic_en gpio\n"); | ||
383 | return ret; | ||
455 | } | 384 | } |
456 | } | 385 | } |
457 | 386 | ||
@@ -478,21 +407,9 @@ static int __devexit tegra_wm8903_driver_remove(struct platform_device *pdev) | |||
478 | { | 407 | { |
479 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 408 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
480 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); | 409 | struct tegra_wm8903 *machine = snd_soc_card_get_drvdata(card); |
481 | struct tegra_wm8903_platform_data *pdata = &machine->pdata; | ||
482 | 410 | ||
483 | if (machine->gpio_requested & GPIO_HP_DET) | 411 | snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, 1, |
484 | snd_soc_jack_free_gpios(&tegra_wm8903_hp_jack, | 412 | &tegra_wm8903_hp_jack_gpio); |
485 | 1, | ||
486 | &tegra_wm8903_hp_jack_gpio); | ||
487 | if (machine->gpio_requested & GPIO_EXT_MIC_EN) | ||
488 | gpio_free(pdata->gpio_ext_mic_en); | ||
489 | if (machine->gpio_requested & GPIO_INT_MIC_EN) | ||
490 | gpio_free(pdata->gpio_int_mic_en); | ||
491 | if (machine->gpio_requested & GPIO_HP_MUTE) | ||
492 | gpio_free(pdata->gpio_hp_mute); | ||
493 | if (machine->gpio_requested & GPIO_SPKR_EN) | ||
494 | gpio_free(pdata->gpio_spkr_en); | ||
495 | machine->gpio_requested = 0; | ||
496 | 413 | ||
497 | snd_soc_unregister_card(card); | 414 | snd_soc_unregister_card(card); |
498 | 415 | ||
diff --git a/sound/soc/tegra/trimslice.c b/sound/soc/tegra/trimslice.c index 4a8d5b672c9f..e69a4f7000d6 100644 --- a/sound/soc/tegra/trimslice.c +++ b/sound/soc/tegra/trimslice.c | |||
@@ -52,8 +52,7 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, | |||
52 | { | 52 | { |
53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
54 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 54 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
55 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 55 | struct snd_soc_codec *codec = codec_dai->codec; |
56 | struct snd_soc_codec *codec = rtd->codec; | ||
57 | struct snd_soc_card *card = codec->card; | 56 | struct snd_soc_card *card = codec->card; |
58 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); | 57 | struct tegra_trimslice *trimslice = snd_soc_card_get_drvdata(card); |
59 | int srate, mclk; | 58 | int srate, mclk; |
@@ -68,24 +67,6 @@ static int trimslice_asoc_hw_params(struct snd_pcm_substream *substream, | |||
68 | return err; | 67 | return err; |
69 | } | 68 | } |
70 | 69 | ||
71 | err = snd_soc_dai_set_fmt(codec_dai, | ||
72 | SND_SOC_DAIFMT_I2S | | ||
73 | SND_SOC_DAIFMT_NB_NF | | ||
74 | SND_SOC_DAIFMT_CBS_CFS); | ||
75 | if (err < 0) { | ||
76 | dev_err(card->dev, "codec_dai fmt not set\n"); | ||
77 | return err; | ||
78 | } | ||
79 | |||
80 | err = snd_soc_dai_set_fmt(cpu_dai, | ||
81 | SND_SOC_DAIFMT_I2S | | ||
82 | SND_SOC_DAIFMT_NB_NF | | ||
83 | SND_SOC_DAIFMT_CBS_CFS); | ||
84 | if (err < 0) { | ||
85 | dev_err(card->dev, "cpu_dai fmt not set\n"); | ||
86 | return err; | ||
87 | } | ||
88 | |||
89 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, | 70 | err = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, |
90 | SND_SOC_CLOCK_IN); | 71 | SND_SOC_CLOCK_IN); |
91 | if (err < 0) { | 72 | if (err < 0) { |
@@ -121,6 +102,9 @@ static struct snd_soc_dai_link trimslice_tlv320aic23_dai = { | |||
121 | .cpu_dai_name = "tegra20-i2s.0", | 102 | .cpu_dai_name = "tegra20-i2s.0", |
122 | .codec_dai_name = "tlv320aic23-hifi", | 103 | .codec_dai_name = "tlv320aic23-hifi", |
123 | .ops = &trimslice_asoc_ops, | 104 | .ops = &trimslice_asoc_ops, |
105 | .dai_fmt = SND_SOC_DAIFMT_I2S | | ||
106 | SND_SOC_DAIFMT_NB_NF | | ||
107 | SND_SOC_DAIFMT_CBS_CFS, | ||
124 | }; | 108 | }; |
125 | 109 | ||
126 | static struct snd_soc_card snd_soc_trimslice = { | 110 | static struct snd_soc_card snd_soc_trimslice = { |
@@ -162,9 +146,9 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) | |||
162 | } | 146 | } |
163 | 147 | ||
164 | trimslice_tlv320aic23_dai.cpu_dai_name = NULL; | 148 | trimslice_tlv320aic23_dai.cpu_dai_name = NULL; |
165 | trimslice_tlv320aic23_dai.cpu_dai_of_node = of_parse_phandle( | 149 | trimslice_tlv320aic23_dai.cpu_of_node = of_parse_phandle( |
166 | pdev->dev.of_node, "nvidia,i2s-controller", 0); | 150 | pdev->dev.of_node, "nvidia,i2s-controller", 0); |
167 | if (!trimslice_tlv320aic23_dai.cpu_dai_of_node) { | 151 | if (!trimslice_tlv320aic23_dai.cpu_of_node) { |
168 | dev_err(&pdev->dev, | 152 | dev_err(&pdev->dev, |
169 | "Property 'nvidia,i2s-controller' missing or invalid\n"); | 153 | "Property 'nvidia,i2s-controller' missing or invalid\n"); |
170 | ret = -EINVAL; | 154 | ret = -EINVAL; |
@@ -173,7 +157,7 @@ static __devinit int tegra_snd_trimslice_probe(struct platform_device *pdev) | |||
173 | 157 | ||
174 | trimslice_tlv320aic23_dai.platform_name = NULL; | 158 | trimslice_tlv320aic23_dai.platform_name = NULL; |
175 | trimslice_tlv320aic23_dai.platform_of_node = | 159 | trimslice_tlv320aic23_dai.platform_of_node = |
176 | trimslice_tlv320aic23_dai.cpu_dai_of_node; | 160 | trimslice_tlv320aic23_dai.cpu_of_node; |
177 | } | 161 | } |
178 | 162 | ||
179 | ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); | 163 | ret = tegra_asoc_utils_init(&trimslice->util_data, &pdev->dev); |
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig index 44cf43404cd9..069330d82be5 100644 --- a/sound/soc/ux500/Kconfig +++ b/sound/soc/ux500/Kconfig | |||
@@ -12,3 +12,21 @@ menuconfig SND_SOC_UX500 | |||
12 | config SND_SOC_UX500_PLAT_MSP_I2S | 12 | config SND_SOC_UX500_PLAT_MSP_I2S |
13 | tristate | 13 | tristate |
14 | depends on SND_SOC_UX500 | 14 | depends on SND_SOC_UX500 |
15 | |||
16 | config SND_SOC_UX500_PLAT_DMA | ||
17 | tristate "Platform - DB8500 (DMA)" | ||
18 | depends on SND_SOC_UX500 | ||
19 | select SND_SOC_DMAENGINE_PCM | ||
20 | help | ||
21 | Say Y if you want to enable the Ux500 platform-driver. | ||
22 | |||
23 | +config SND_SOC_UX500_MACH_MOP500 | ||
24 | + tristate "Machine - MOP500 (Ux500 + AB8500)" | ||
25 | depends on AB8500_CORE && AB8500_GPADC && SND_SOC_UX500 | ||
26 | select SND_SOC_AB8500_CODEC | ||
27 | select SND_SOC_UX500_PLAT_MSP_I2S | ||
28 | select SND_SOC_UX500_PLAT_DMA | ||
29 | help | ||
30 | Select this to enable the MOP500 machine-driver. | ||
31 | This will enable platform-drivers for: Ux500 | ||
32 | This will enable codec-drivers for: AB8500 | ||
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile index 19974c5a2ea1..cce0c11a4d86 100644 --- a/sound/soc/ux500/Makefile +++ b/sound/soc/ux500/Makefile | |||
@@ -2,3 +2,9 @@ | |||
2 | 2 | ||
3 | snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o | 3 | snd-soc-ux500-plat-msp-i2s-objs := ux500_msp_dai.o ux500_msp_i2s.o |
4 | obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o | 4 | obj-$(CONFIG_SND_SOC_UX500_PLAT_MSP_I2S) += snd-soc-ux500-plat-msp-i2s.o |
5 | |||
6 | snd-soc-ux500-plat-dma-objs := ux500_pcm.o | ||
7 | obj-$(CONFIG_SND_SOC_UX500_PLAT_DMA) += snd-soc-ux500-plat-dma.o | ||
8 | |||
9 | snd-soc-ux500-mach-mop500-objs := mop500.o mop500_ab8500.o | ||
10 | obj-$(CONFIG_SND_SOC_UX500_MACH_MOP500) += snd-soc-ux500-mach-mop500.o | ||
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c new file mode 100644 index 000000000000..31c4d26d0359 --- /dev/null +++ b/sound/soc/ux500/mop500.c | |||
@@ -0,0 +1,113 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja (ola.o.lilja@stericsson.com) | ||
5 | * for ST-Ericsson. | ||
6 | * | ||
7 | * License terms: | ||
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 published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <asm/mach-types.h> | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/spi/spi.h> | ||
19 | |||
20 | #include <sound/soc.h> | ||
21 | #include <sound/initval.h> | ||
22 | |||
23 | #include "ux500_pcm.h" | ||
24 | #include "ux500_msp_dai.h" | ||
25 | |||
26 | #include <mop500_ab8500.h> | ||
27 | |||
28 | /* Define the whole MOP500 soundcard, linking platform to the codec-drivers */ | ||
29 | struct snd_soc_dai_link mop500_dai_links[] = { | ||
30 | { | ||
31 | .name = "ab8500_0", | ||
32 | .stream_name = "ab8500_0", | ||
33 | .cpu_dai_name = "ux500-msp-i2s.1", | ||
34 | .codec_dai_name = "ab8500-codec-dai.0", | ||
35 | .platform_name = "ux500-pcm.0", | ||
36 | .codec_name = "ab8500-codec.0", | ||
37 | .init = mop500_ab8500_machine_init, | ||
38 | .ops = mop500_ab8500_ops, | ||
39 | }, | ||
40 | { | ||
41 | .name = "ab8500_1", | ||
42 | .stream_name = "ab8500_1", | ||
43 | .cpu_dai_name = "ux500-msp-i2s.3", | ||
44 | .codec_dai_name = "ab8500-codec-dai.1", | ||
45 | .platform_name = "ux500-pcm.0", | ||
46 | .codec_name = "ab8500-codec.0", | ||
47 | .init = NULL, | ||
48 | .ops = mop500_ab8500_ops, | ||
49 | }, | ||
50 | }; | ||
51 | |||
52 | static struct snd_soc_card mop500_card = { | ||
53 | .name = "MOP500-card", | ||
54 | .probe = NULL, | ||
55 | .dai_link = mop500_dai_links, | ||
56 | .num_links = ARRAY_SIZE(mop500_dai_links), | ||
57 | }; | ||
58 | |||
59 | static int __devinit mop500_probe(struct platform_device *pdev) | ||
60 | { | ||
61 | int ret; | ||
62 | |||
63 | pr_debug("%s: Enter.\n", __func__); | ||
64 | |||
65 | dev_dbg(&pdev->dev, "%s: Enter.\n", __func__); | ||
66 | |||
67 | mop500_card.dev = &pdev->dev; | ||
68 | |||
69 | dev_dbg(&pdev->dev, "%s: Card %s: Set platform drvdata.\n", | ||
70 | __func__, mop500_card.name); | ||
71 | platform_set_drvdata(pdev, &mop500_card); | ||
72 | |||
73 | snd_soc_card_set_drvdata(&mop500_card, NULL); | ||
74 | |||
75 | dev_dbg(&pdev->dev, "%s: Card %s: num_links = %d\n", | ||
76 | __func__, mop500_card.name, mop500_card.num_links); | ||
77 | dev_dbg(&pdev->dev, "%s: Card %s: DAI-link 0: name = %s\n", | ||
78 | __func__, mop500_card.name, mop500_card.dai_link[0].name); | ||
79 | dev_dbg(&pdev->dev, "%s: Card %s: DAI-link 0: stream_name = %s\n", | ||
80 | __func__, mop500_card.name, | ||
81 | mop500_card.dai_link[0].stream_name); | ||
82 | |||
83 | ret = snd_soc_register_card(&mop500_card); | ||
84 | if (ret) | ||
85 | dev_err(&pdev->dev, | ||
86 | "Error: snd_soc_register_card failed (%d)!\n", | ||
87 | ret); | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static int __devexit mop500_remove(struct platform_device *pdev) | ||
93 | { | ||
94 | struct snd_soc_card *mop500_card = platform_get_drvdata(pdev); | ||
95 | |||
96 | pr_debug("%s: Enter.\n", __func__); | ||
97 | |||
98 | snd_soc_unregister_card(mop500_card); | ||
99 | mop500_ab8500_remove(mop500_card); | ||
100 | |||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static struct platform_driver snd_soc_mop500_driver = { | ||
105 | .driver = { | ||
106 | .owner = THIS_MODULE, | ||
107 | .name = "snd-soc-mop500", | ||
108 | }, | ||
109 | .probe = mop500_probe, | ||
110 | .remove = __devexit_p(mop500_remove), | ||
111 | }; | ||
112 | |||
113 | module_platform_driver(snd_soc_mop500_driver); | ||
diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c new file mode 100644 index 000000000000..78cce236693e --- /dev/null +++ b/sound/soc/ux500/mop500_ab8500.c | |||
@@ -0,0 +1,431 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | ||
5 | * Kristoffer Karlsson <kristoffer.karlsson@stericsson.com> | ||
6 | * for ST-Ericsson. | ||
7 | * | ||
8 | * License terms: | ||
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 published | ||
12 | * by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/device.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/clk.h> | ||
19 | |||
20 | #include <mach/hardware.h> | ||
21 | |||
22 | #include <sound/soc.h> | ||
23 | #include <sound/soc-dapm.h> | ||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | |||
27 | #include "ux500_pcm.h" | ||
28 | #include "ux500_msp_dai.h" | ||
29 | #include "../codecs/ab8500-codec.h" | ||
30 | |||
31 | #define TX_SLOT_MONO 0x0008 | ||
32 | #define TX_SLOT_STEREO 0x000a | ||
33 | #define RX_SLOT_MONO 0x0001 | ||
34 | #define RX_SLOT_STEREO 0x0003 | ||
35 | #define TX_SLOT_8CH 0x00FF | ||
36 | #define RX_SLOT_8CH 0x00FF | ||
37 | |||
38 | #define DEF_TX_SLOTS TX_SLOT_STEREO | ||
39 | #define DEF_RX_SLOTS RX_SLOT_MONO | ||
40 | |||
41 | #define DRIVERMODE_NORMAL 0 | ||
42 | #define DRIVERMODE_CODEC_ONLY 1 | ||
43 | |||
44 | /* Slot configuration */ | ||
45 | static unsigned int tx_slots = DEF_TX_SLOTS; | ||
46 | static unsigned int rx_slots = DEF_RX_SLOTS; | ||
47 | |||
48 | /* Clocks */ | ||
49 | static const char * const enum_mclk[] = { | ||
50 | "SYSCLK", | ||
51 | "ULPCLK" | ||
52 | }; | ||
53 | enum mclk { | ||
54 | MCLK_SYSCLK, | ||
55 | MCLK_ULPCLK, | ||
56 | }; | ||
57 | |||
58 | static SOC_ENUM_SINGLE_EXT_DECL(soc_enum_mclk, enum_mclk); | ||
59 | |||
60 | /* Private data for machine-part MOP500<->AB8500 */ | ||
61 | struct mop500_ab8500_drvdata { | ||
62 | /* Clocks */ | ||
63 | enum mclk mclk_sel; | ||
64 | struct clk *clk_ptr_intclk; | ||
65 | struct clk *clk_ptr_sysclk; | ||
66 | struct clk *clk_ptr_ulpclk; | ||
67 | }; | ||
68 | |||
69 | static inline const char *get_mclk_str(enum mclk mclk_sel) | ||
70 | { | ||
71 | switch (mclk_sel) { | ||
72 | case MCLK_SYSCLK: | ||
73 | return "SYSCLK"; | ||
74 | case MCLK_ULPCLK: | ||
75 | return "ULPCLK"; | ||
76 | default: | ||
77 | return "Unknown"; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | static int mop500_ab8500_set_mclk(struct device *dev, | ||
82 | struct mop500_ab8500_drvdata *drvdata) | ||
83 | { | ||
84 | int status; | ||
85 | struct clk *clk_ptr; | ||
86 | |||
87 | if (IS_ERR(drvdata->clk_ptr_intclk)) { | ||
88 | dev_err(dev, | ||
89 | "%s: ERROR: intclk not initialized!\n", __func__); | ||
90 | return -EIO; | ||
91 | } | ||
92 | |||
93 | switch (drvdata->mclk_sel) { | ||
94 | case MCLK_SYSCLK: | ||
95 | clk_ptr = drvdata->clk_ptr_sysclk; | ||
96 | break; | ||
97 | case MCLK_ULPCLK: | ||
98 | clk_ptr = drvdata->clk_ptr_ulpclk; | ||
99 | break; | ||
100 | default: | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | if (IS_ERR(clk_ptr)) { | ||
105 | dev_err(dev, "%s: ERROR: %s not initialized!\n", __func__, | ||
106 | get_mclk_str(drvdata->mclk_sel)); | ||
107 | return -EIO; | ||
108 | } | ||
109 | |||
110 | status = clk_set_parent(drvdata->clk_ptr_intclk, clk_ptr); | ||
111 | if (status) | ||
112 | dev_err(dev, | ||
113 | "%s: ERROR: Setting intclk parent to %s failed (ret = %d)!", | ||
114 | __func__, get_mclk_str(drvdata->mclk_sel), status); | ||
115 | else | ||
116 | dev_dbg(dev, | ||
117 | "%s: intclk parent changed to %s.\n", | ||
118 | __func__, get_mclk_str(drvdata->mclk_sel)); | ||
119 | |||
120 | return status; | ||
121 | } | ||
122 | |||
123 | /* | ||
124 | * Control-events | ||
125 | */ | ||
126 | |||
127 | static int mclk_input_control_get(struct snd_kcontrol *kcontrol, | ||
128 | struct snd_ctl_elem_value *ucontrol) | ||
129 | { | ||
130 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
131 | struct mop500_ab8500_drvdata *drvdata = | ||
132 | snd_soc_card_get_drvdata(codec->card); | ||
133 | |||
134 | ucontrol->value.enumerated.item[0] = drvdata->mclk_sel; | ||
135 | |||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | static int mclk_input_control_put(struct snd_kcontrol *kcontrol, | ||
140 | struct snd_ctl_elem_value *ucontrol) | ||
141 | { | ||
142 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
143 | struct mop500_ab8500_drvdata *drvdata = | ||
144 | snd_soc_card_get_drvdata(codec->card); | ||
145 | unsigned int val = ucontrol->value.enumerated.item[0]; | ||
146 | |||
147 | if (val > (unsigned int)MCLK_ULPCLK) | ||
148 | return -EINVAL; | ||
149 | if (drvdata->mclk_sel == val) | ||
150 | return 0; | ||
151 | |||
152 | drvdata->mclk_sel = val; | ||
153 | |||
154 | return 1; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * Controls | ||
159 | */ | ||
160 | |||
161 | static struct snd_kcontrol_new mop500_ab8500_ctrls[] = { | ||
162 | SOC_ENUM_EXT("Master Clock Select", | ||
163 | soc_enum_mclk, | ||
164 | mclk_input_control_get, mclk_input_control_put), | ||
165 | /* Digital interface - Clocks */ | ||
166 | SOC_SINGLE("Digital Interface Master Generator Switch", | ||
167 | AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENMASTGEN, | ||
168 | 1, 0), | ||
169 | SOC_SINGLE("Digital Interface 0 Bit-clock Switch", | ||
170 | AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK0, | ||
171 | 1, 0), | ||
172 | SOC_SINGLE("Digital Interface 1 Bit-clock Switch", | ||
173 | AB8500_DIGIFCONF1, AB8500_DIGIFCONF1_ENFSBITCLK1, | ||
174 | 1, 0), | ||
175 | SOC_DAPM_PIN_SWITCH("Headset Left"), | ||
176 | SOC_DAPM_PIN_SWITCH("Headset Right"), | ||
177 | SOC_DAPM_PIN_SWITCH("Earpiece"), | ||
178 | SOC_DAPM_PIN_SWITCH("Speaker Left"), | ||
179 | SOC_DAPM_PIN_SWITCH("Speaker Right"), | ||
180 | SOC_DAPM_PIN_SWITCH("LineOut Left"), | ||
181 | SOC_DAPM_PIN_SWITCH("LineOut Right"), | ||
182 | SOC_DAPM_PIN_SWITCH("Vibra 1"), | ||
183 | SOC_DAPM_PIN_SWITCH("Vibra 2"), | ||
184 | SOC_DAPM_PIN_SWITCH("Mic 1"), | ||
185 | SOC_DAPM_PIN_SWITCH("Mic 2"), | ||
186 | SOC_DAPM_PIN_SWITCH("LineIn Left"), | ||
187 | SOC_DAPM_PIN_SWITCH("LineIn Right"), | ||
188 | SOC_DAPM_PIN_SWITCH("DMic 1"), | ||
189 | SOC_DAPM_PIN_SWITCH("DMic 2"), | ||
190 | SOC_DAPM_PIN_SWITCH("DMic 3"), | ||
191 | SOC_DAPM_PIN_SWITCH("DMic 4"), | ||
192 | SOC_DAPM_PIN_SWITCH("DMic 5"), | ||
193 | SOC_DAPM_PIN_SWITCH("DMic 6"), | ||
194 | }; | ||
195 | |||
196 | /* ASoC */ | ||
197 | |||
198 | int mop500_ab8500_startup(struct snd_pcm_substream *substream) | ||
199 | { | ||
200 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
201 | |||
202 | /* Set audio-clock source */ | ||
203 | return mop500_ab8500_set_mclk(rtd->card->dev, | ||
204 | snd_soc_card_get_drvdata(rtd->card)); | ||
205 | } | ||
206 | |||
207 | void mop500_ab8500_shutdown(struct snd_pcm_substream *substream) | ||
208 | { | ||
209 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
210 | struct device *dev = rtd->card->dev; | ||
211 | |||
212 | dev_dbg(dev, "%s: Enter\n", __func__); | ||
213 | |||
214 | /* Reset slots configuration to default(s) */ | ||
215 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
216 | tx_slots = DEF_TX_SLOTS; | ||
217 | else | ||
218 | rx_slots = DEF_RX_SLOTS; | ||
219 | } | ||
220 | |||
221 | int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, | ||
222 | struct snd_pcm_hw_params *params) | ||
223 | { | ||
224 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
225 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
226 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
227 | struct device *dev = rtd->card->dev; | ||
228 | unsigned int fmt; | ||
229 | int channels, ret = 0, driver_mode, slots; | ||
230 | unsigned int sw_codec, sw_cpu; | ||
231 | bool is_playback; | ||
232 | |||
233 | dev_dbg(dev, "%s: Enter\n", __func__); | ||
234 | |||
235 | dev_dbg(dev, "%s: substream->pcm->name = %s\n" | ||
236 | "substream->pcm->id = %s.\n" | ||
237 | "substream->name = %s.\n" | ||
238 | "substream->number = %d.\n", | ||
239 | __func__, | ||
240 | substream->pcm->name, | ||
241 | substream->pcm->id, | ||
242 | substream->name, | ||
243 | substream->number); | ||
244 | |||
245 | channels = params_channels(params); | ||
246 | |||
247 | switch (params_format(params)) { | ||
248 | case SNDRV_PCM_FORMAT_S32_LE: | ||
249 | sw_cpu = 32; | ||
250 | break; | ||
251 | |||
252 | case SNDRV_PCM_FORMAT_S16_LE: | ||
253 | sw_cpu = 16; | ||
254 | break; | ||
255 | |||
256 | default: | ||
257 | return -EINVAL; | ||
258 | } | ||
259 | |||
260 | /* Setup codec depending on driver-mode */ | ||
261 | if (channels == 8) | ||
262 | driver_mode = DRIVERMODE_CODEC_ONLY; | ||
263 | else | ||
264 | driver_mode = DRIVERMODE_NORMAL; | ||
265 | dev_dbg(dev, "%s: Driver-mode: %s.\n", __func__, | ||
266 | (driver_mode == DRIVERMODE_NORMAL) ? "NORMAL" : "CODEC_ONLY"); | ||
267 | |||
268 | /* Setup format */ | ||
269 | |||
270 | if (driver_mode == DRIVERMODE_NORMAL) { | ||
271 | fmt = SND_SOC_DAIFMT_DSP_A | | ||
272 | SND_SOC_DAIFMT_CBM_CFM | | ||
273 | SND_SOC_DAIFMT_NB_NF | | ||
274 | SND_SOC_DAIFMT_CONT; | ||
275 | } else { | ||
276 | fmt = SND_SOC_DAIFMT_DSP_A | | ||
277 | SND_SOC_DAIFMT_CBM_CFM | | ||
278 | SND_SOC_DAIFMT_NB_NF | | ||
279 | SND_SOC_DAIFMT_GATED; | ||
280 | } | ||
281 | |||
282 | ret = snd_soc_dai_set_fmt(codec_dai, fmt); | ||
283 | if (ret < 0) { | ||
284 | dev_err(dev, | ||
285 | "%s: ERROR: snd_soc_dai_set_fmt failed for codec_dai (ret = %d)!\n", | ||
286 | __func__, ret); | ||
287 | return ret; | ||
288 | } | ||
289 | |||
290 | ret = snd_soc_dai_set_fmt(cpu_dai, fmt); | ||
291 | if (ret < 0) { | ||
292 | dev_err(dev, | ||
293 | "%s: ERROR: snd_soc_dai_set_fmt failed for cpu_dai (ret = %d)!\n", | ||
294 | __func__, ret); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | /* Setup TDM-slots */ | ||
299 | |||
300 | is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
301 | switch (channels) { | ||
302 | case 1: | ||
303 | slots = 16; | ||
304 | tx_slots = (is_playback) ? TX_SLOT_MONO : 0; | ||
305 | rx_slots = (is_playback) ? 0 : RX_SLOT_MONO; | ||
306 | break; | ||
307 | case 2: | ||
308 | slots = 16; | ||
309 | tx_slots = (is_playback) ? TX_SLOT_STEREO : 0; | ||
310 | rx_slots = (is_playback) ? 0 : RX_SLOT_STEREO; | ||
311 | break; | ||
312 | case 8: | ||
313 | slots = 16; | ||
314 | tx_slots = (is_playback) ? TX_SLOT_8CH : 0; | ||
315 | rx_slots = (is_playback) ? 0 : RX_SLOT_8CH; | ||
316 | break; | ||
317 | default: | ||
318 | return -EINVAL; | ||
319 | } | ||
320 | |||
321 | if (driver_mode == DRIVERMODE_NORMAL) | ||
322 | sw_codec = sw_cpu; | ||
323 | else | ||
324 | sw_codec = 20; | ||
325 | |||
326 | dev_dbg(dev, "%s: CPU-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__, | ||
327 | tx_slots, rx_slots); | ||
328 | ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_slots, rx_slots, slots, | ||
329 | sw_cpu); | ||
330 | if (ret) | ||
331 | return ret; | ||
332 | |||
333 | dev_dbg(dev, "%s: CODEC-DAI TDM: TX=0x%04X RX=0x%04x\n", __func__, | ||
334 | tx_slots, rx_slots); | ||
335 | ret = snd_soc_dai_set_tdm_slot(codec_dai, tx_slots, rx_slots, slots, | ||
336 | sw_codec); | ||
337 | if (ret) | ||
338 | return ret; | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | struct snd_soc_ops mop500_ab8500_ops[] = { | ||
344 | { | ||
345 | .hw_params = mop500_ab8500_hw_params, | ||
346 | .startup = mop500_ab8500_startup, | ||
347 | .shutdown = mop500_ab8500_shutdown, | ||
348 | } | ||
349 | }; | ||
350 | |||
351 | int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *rtd) | ||
352 | { | ||
353 | struct snd_soc_codec *codec = rtd->codec; | ||
354 | struct device *dev = rtd->card->dev; | ||
355 | struct mop500_ab8500_drvdata *drvdata; | ||
356 | int ret; | ||
357 | |||
358 | dev_dbg(dev, "%s Enter.\n", __func__); | ||
359 | |||
360 | /* Create driver private-data struct */ | ||
361 | drvdata = devm_kzalloc(dev, sizeof(struct mop500_ab8500_drvdata), | ||
362 | GFP_KERNEL); | ||
363 | snd_soc_card_set_drvdata(rtd->card, drvdata); | ||
364 | |||
365 | /* Setup clocks */ | ||
366 | |||
367 | drvdata->clk_ptr_sysclk = clk_get(dev, "sysclk"); | ||
368 | if (IS_ERR(drvdata->clk_ptr_sysclk)) | ||
369 | dev_warn(dev, "%s: WARNING: clk_get failed for 'sysclk'!\n", | ||
370 | __func__); | ||
371 | drvdata->clk_ptr_ulpclk = clk_get(dev, "ulpclk"); | ||
372 | if (IS_ERR(drvdata->clk_ptr_ulpclk)) | ||
373 | dev_warn(dev, "%s: WARNING: clk_get failed for 'ulpclk'!\n", | ||
374 | __func__); | ||
375 | drvdata->clk_ptr_intclk = clk_get(dev, "intclk"); | ||
376 | if (IS_ERR(drvdata->clk_ptr_intclk)) | ||
377 | dev_warn(dev, "%s: WARNING: clk_get failed for 'intclk'!\n", | ||
378 | __func__); | ||
379 | |||
380 | /* Set intclk default parent to ulpclk */ | ||
381 | drvdata->mclk_sel = MCLK_ULPCLK; | ||
382 | ret = mop500_ab8500_set_mclk(dev, drvdata); | ||
383 | if (ret < 0) | ||
384 | dev_warn(dev, "%s: WARNING: mop500_ab8500_set_mclk!\n", | ||
385 | __func__); | ||
386 | |||
387 | drvdata->mclk_sel = MCLK_ULPCLK; | ||
388 | |||
389 | /* Add controls */ | ||
390 | ret = snd_soc_add_codec_controls(codec, mop500_ab8500_ctrls, | ||
391 | ARRAY_SIZE(mop500_ab8500_ctrls)); | ||
392 | if (ret < 0) { | ||
393 | pr_err("%s: Failed to add machine-controls (%d)!\n", | ||
394 | __func__, ret); | ||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | ret = snd_soc_dapm_disable_pin(&codec->dapm, "Earpiece"); | ||
399 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Left"); | ||
400 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Speaker Right"); | ||
401 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Left"); | ||
402 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineOut Right"); | ||
403 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 1"); | ||
404 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Vibra 2"); | ||
405 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 1"); | ||
406 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "Mic 2"); | ||
407 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Left"); | ||
408 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "LineIn Right"); | ||
409 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 1"); | ||
410 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 2"); | ||
411 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 3"); | ||
412 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 4"); | ||
413 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 5"); | ||
414 | ret |= snd_soc_dapm_disable_pin(&codec->dapm, "DMic 6"); | ||
415 | |||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | void mop500_ab8500_remove(struct snd_soc_card *card) | ||
420 | { | ||
421 | struct mop500_ab8500_drvdata *drvdata = snd_soc_card_get_drvdata(card); | ||
422 | |||
423 | if (drvdata->clk_ptr_sysclk != NULL) | ||
424 | clk_put(drvdata->clk_ptr_sysclk); | ||
425 | if (drvdata->clk_ptr_ulpclk != NULL) | ||
426 | clk_put(drvdata->clk_ptr_ulpclk); | ||
427 | if (drvdata->clk_ptr_intclk != NULL) | ||
428 | clk_put(drvdata->clk_ptr_intclk); | ||
429 | |||
430 | snd_soc_card_set_drvdata(card, drvdata); | ||
431 | } | ||
diff --git a/sound/soc/ux500/mop500_ab8500.h b/sound/soc/ux500/mop500_ab8500.h new file mode 100644 index 000000000000..cca5b33964b6 --- /dev/null +++ b/sound/soc/ux500/mop500_ab8500.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com> | ||
5 | * for ST-Ericsson. | ||
6 | * | ||
7 | * License terms: | ||
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 published | ||
11 | * by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #ifndef MOP500_AB8500_H | ||
15 | #define MOP500_AB8500_H | ||
16 | |||
17 | extern struct snd_soc_ops mop500_ab8500_ops[]; | ||
18 | |||
19 | int mop500_ab8500_machine_init(struct snd_soc_pcm_runtime *runtime); | ||
20 | void mop500_ab8500_remove(struct snd_soc_card *card); | ||
21 | |||
22 | #endif | ||
diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 93c6c40e724c..62ac0285bfaf 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c | |||
@@ -840,4 +840,4 @@ static struct platform_driver msp_i2s_driver = { | |||
840 | }; | 840 | }; |
841 | module_platform_driver(msp_i2s_driver); | 841 | module_platform_driver(msp_i2s_driver); |
842 | 842 | ||
843 | MODULE_LICENSE("GPLv2"); | 843 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/soc/ux500/ux500_msp_i2s.c b/sound/soc/ux500/ux500_msp_i2s.c index 496dec10c96e..ee14d2dac2f5 100644 --- a/sound/soc/ux500/ux500_msp_i2s.c +++ b/sound/soc/ux500/ux500_msp_i2s.c | |||
@@ -739,4 +739,4 @@ void ux500_msp_i2s_cleanup_msp(struct platform_device *pdev, | |||
739 | devm_kfree(&pdev->dev, msp); | 739 | devm_kfree(&pdev->dev, msp); |
740 | } | 740 | } |
741 | 741 | ||
742 | MODULE_LICENSE("GPLv2"); | 742 | MODULE_LICENSE("GPL v2"); |
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c new file mode 100644 index 000000000000..1a04e248453c --- /dev/null +++ b/sound/soc/ux500/ux500_pcm.c | |||
@@ -0,0 +1,318 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | ||
5 | * Roger Nilsson <roger.xr.nilsson@stericsson.com> | ||
6 | * for ST-Ericsson. | ||
7 | * | ||
8 | * License terms: | ||
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 published | ||
12 | * by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <asm/page.h> | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/dmaengine.h> | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | #include <plat/ste_dma40.h> | ||
23 | |||
24 | #include <sound/pcm.h> | ||
25 | #include <sound/pcm_params.h> | ||
26 | #include <sound/soc.h> | ||
27 | #include <sound/dmaengine_pcm.h> | ||
28 | |||
29 | #include "ux500_msp_i2s.h" | ||
30 | #include "ux500_pcm.h" | ||
31 | |||
32 | static struct snd_pcm_hardware ux500_pcm_hw_playback = { | ||
33 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
34 | SNDRV_PCM_INFO_MMAP | | ||
35 | SNDRV_PCM_INFO_RESUME | | ||
36 | SNDRV_PCM_INFO_PAUSE, | ||
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
38 | SNDRV_PCM_FMTBIT_U16_LE | | ||
39 | SNDRV_PCM_FMTBIT_S16_BE | | ||
40 | SNDRV_PCM_FMTBIT_U16_BE, | ||
41 | .rates = SNDRV_PCM_RATE_KNOT, | ||
42 | .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK, | ||
43 | .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK, | ||
44 | .channels_min = UX500_PLATFORM_MIN_CHANNELS, | ||
45 | .channels_max = UX500_PLATFORM_MAX_CHANNELS, | ||
46 | .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, | ||
47 | .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, | ||
48 | .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, | ||
49 | .periods_min = UX500_PLATFORM_PERIODS_MIN, | ||
50 | .periods_max = UX500_PLATFORM_PERIODS_MAX, | ||
51 | }; | ||
52 | |||
53 | static struct snd_pcm_hardware ux500_pcm_hw_capture = { | ||
54 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
55 | SNDRV_PCM_INFO_MMAP | | ||
56 | SNDRV_PCM_INFO_RESUME | | ||
57 | SNDRV_PCM_INFO_PAUSE, | ||
58 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
59 | SNDRV_PCM_FMTBIT_U16_LE | | ||
60 | SNDRV_PCM_FMTBIT_S16_BE | | ||
61 | SNDRV_PCM_FMTBIT_U16_BE, | ||
62 | .rates = SNDRV_PCM_RATE_KNOT, | ||
63 | .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE, | ||
64 | .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE, | ||
65 | .channels_min = UX500_PLATFORM_MIN_CHANNELS, | ||
66 | .channels_max = UX500_PLATFORM_MAX_CHANNELS, | ||
67 | .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, | ||
68 | .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN, | ||
69 | .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX, | ||
70 | .periods_min = UX500_PLATFORM_PERIODS_MIN, | ||
71 | .periods_max = UX500_PLATFORM_PERIODS_MAX, | ||
72 | }; | ||
73 | |||
74 | static void ux500_pcm_dma_hw_free(struct device *dev, | ||
75 | struct snd_pcm_substream *substream) | ||
76 | { | ||
77 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
78 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
79 | |||
80 | if (runtime->dma_area == NULL) | ||
81 | return; | ||
82 | |||
83 | if (buf != &substream->dma_buffer) { | ||
84 | dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, | ||
85 | buf->addr); | ||
86 | kfree(runtime->dma_buffer_p); | ||
87 | } | ||
88 | |||
89 | snd_pcm_set_runtime_buffer(substream, NULL); | ||
90 | } | ||
91 | |||
92 | static int ux500_pcm_open(struct snd_pcm_substream *substream) | ||
93 | { | ||
94 | int stream_id = substream->pstr->stream; | ||
95 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
96 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
97 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
98 | struct device *dev = dai->dev; | ||
99 | int ret; | ||
100 | struct ux500_msp_dma_params *dma_params; | ||
101 | u16 per_data_width, mem_data_width; | ||
102 | struct stedma40_chan_cfg *dma_cfg; | ||
103 | |||
104 | dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, | ||
105 | snd_pcm_stream_str(substream)); | ||
106 | |||
107 | dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); | ||
108 | if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) | ||
109 | snd_soc_set_runtime_hwparams(substream, | ||
110 | &ux500_pcm_hw_playback); | ||
111 | else | ||
112 | snd_soc_set_runtime_hwparams(substream, | ||
113 | &ux500_pcm_hw_capture); | ||
114 | |||
115 | /* ensure that buffer size is a multiple of period size */ | ||
116 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
117 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
118 | if (ret < 0) { | ||
119 | dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n", | ||
120 | __func__, ret); | ||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__, | ||
125 | snd_pcm_stream_str(substream)); | ||
126 | runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ? | ||
127 | ux500_pcm_hw_playback : ux500_pcm_hw_capture; | ||
128 | |||
129 | mem_data_width = STEDMA40_HALFWORD_WIDTH; | ||
130 | |||
131 | dma_params = snd_soc_dai_get_dma_data(dai, substream); | ||
132 | switch (dma_params->data_size) { | ||
133 | case 32: | ||
134 | per_data_width = STEDMA40_WORD_WIDTH; | ||
135 | break; | ||
136 | case 16: | ||
137 | per_data_width = STEDMA40_HALFWORD_WIDTH; | ||
138 | break; | ||
139 | case 8: | ||
140 | per_data_width = STEDMA40_BYTE_WIDTH; | ||
141 | break; | ||
142 | default: | ||
143 | per_data_width = STEDMA40_WORD_WIDTH; | ||
144 | dev_warn(rtd->platform->dev, | ||
145 | "%s: Unknown data-size (%d)! Assuming 32 bits.\n", | ||
146 | __func__, dma_params->data_size); | ||
147 | } | ||
148 | |||
149 | dma_cfg = dma_params->dma_cfg; | ||
150 | |||
151 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
152 | dma_cfg->src_info.data_width = mem_data_width; | ||
153 | dma_cfg->dst_info.data_width = per_data_width; | ||
154 | } else { | ||
155 | dma_cfg->src_info.data_width = per_data_width; | ||
156 | dma_cfg->dst_info.data_width = mem_data_width; | ||
157 | } | ||
158 | |||
159 | |||
160 | ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg); | ||
161 | if (ret) { | ||
162 | dev_dbg(dai->dev, | ||
163 | "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n", | ||
164 | __func__, ret); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | snd_dmaengine_pcm_set_data(substream, dma_cfg); | ||
169 | |||
170 | return 0; | ||
171 | } | ||
172 | |||
173 | static int ux500_pcm_close(struct snd_pcm_substream *substream) | ||
174 | { | ||
175 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
176 | struct snd_soc_dai *dai = rtd->cpu_dai; | ||
177 | |||
178 | dev_dbg(dai->dev, "%s: Enter\n", __func__); | ||
179 | |||
180 | snd_dmaengine_pcm_close(substream); | ||
181 | |||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, | ||
186 | struct snd_pcm_hw_params *hw_params) | ||
187 | { | ||
188 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
189 | struct snd_dma_buffer *buf = runtime->dma_buffer_p; | ||
190 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
191 | int ret = 0; | ||
192 | int size; | ||
193 | |||
194 | dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); | ||
195 | |||
196 | size = params_buffer_bytes(hw_params); | ||
197 | |||
198 | if (buf) { | ||
199 | if (buf->bytes >= size) | ||
200 | goto out; | ||
201 | ux500_pcm_dma_hw_free(NULL, substream); | ||
202 | } | ||
203 | |||
204 | if (substream->dma_buffer.area != NULL && | ||
205 | substream->dma_buffer.bytes >= size) { | ||
206 | buf = &substream->dma_buffer; | ||
207 | } else { | ||
208 | buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); | ||
209 | if (!buf) | ||
210 | goto nomem; | ||
211 | |||
212 | buf->dev.type = SNDRV_DMA_TYPE_DEV; | ||
213 | buf->dev.dev = NULL; | ||
214 | buf->area = dma_alloc_coherent(NULL, size, &buf->addr, | ||
215 | GFP_KERNEL); | ||
216 | buf->bytes = size; | ||
217 | buf->private_data = NULL; | ||
218 | |||
219 | if (!buf->area) | ||
220 | goto free; | ||
221 | } | ||
222 | snd_pcm_set_runtime_buffer(substream, buf); | ||
223 | ret = 1; | ||
224 | out: | ||
225 | runtime->dma_bytes = size; | ||
226 | return ret; | ||
227 | |||
228 | free: | ||
229 | kfree(buf); | ||
230 | nomem: | ||
231 | return -ENOMEM; | ||
232 | } | ||
233 | |||
234 | static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) | ||
235 | { | ||
236 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
237 | |||
238 | dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__); | ||
239 | |||
240 | ux500_pcm_dma_hw_free(NULL, substream); | ||
241 | |||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int ux500_pcm_mmap(struct snd_pcm_substream *substream, | ||
246 | struct vm_area_struct *vma) | ||
247 | { | ||
248 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
249 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
250 | |||
251 | dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__); | ||
252 | |||
253 | return dma_mmap_coherent(NULL, vma, runtime->dma_area, | ||
254 | runtime->dma_addr, runtime->dma_bytes); | ||
255 | } | ||
256 | |||
257 | static struct snd_pcm_ops ux500_pcm_ops = { | ||
258 | .open = ux500_pcm_open, | ||
259 | .close = ux500_pcm_close, | ||
260 | .ioctl = snd_pcm_lib_ioctl, | ||
261 | .hw_params = ux500_pcm_hw_params, | ||
262 | .hw_free = ux500_pcm_hw_free, | ||
263 | .trigger = snd_dmaengine_pcm_trigger, | ||
264 | .pointer = snd_dmaengine_pcm_pointer_no_residue, | ||
265 | .mmap = ux500_pcm_mmap | ||
266 | }; | ||
267 | |||
268 | int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
269 | { | ||
270 | struct snd_pcm *pcm = rtd->pcm; | ||
271 | |||
272 | dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__, | ||
273 | pcm->id); | ||
274 | |||
275 | pcm->info_flags = 0; | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static struct snd_soc_platform_driver ux500_pcm_soc_drv = { | ||
281 | .ops = &ux500_pcm_ops, | ||
282 | .pcm_new = ux500_pcm_new, | ||
283 | }; | ||
284 | |||
285 | static int __devexit ux500_pcm_drv_probe(struct platform_device *pdev) | ||
286 | { | ||
287 | int ret; | ||
288 | |||
289 | ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); | ||
290 | if (ret < 0) { | ||
291 | dev_err(&pdev->dev, | ||
292 | "%s: ERROR: Failed to register platform '%s' (%d)!\n", | ||
293 | __func__, pdev->name, ret); | ||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int __devinit ux500_pcm_drv_remove(struct platform_device *pdev) | ||
301 | { | ||
302 | snd_soc_unregister_platform(&pdev->dev); | ||
303 | |||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static struct platform_driver ux500_pcm_driver = { | ||
308 | .driver = { | ||
309 | .name = "ux500-pcm", | ||
310 | .owner = THIS_MODULE, | ||
311 | }, | ||
312 | |||
313 | .probe = ux500_pcm_drv_probe, | ||
314 | .remove = __devexit_p(ux500_pcm_drv_remove), | ||
315 | }; | ||
316 | module_platform_driver(ux500_pcm_driver); | ||
317 | |||
318 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h new file mode 100644 index 000000000000..77ed44d371e9 --- /dev/null +++ b/sound/soc/ux500/ux500_pcm.h | |||
@@ -0,0 +1,35 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2012 | ||
3 | * | ||
4 | * Author: Ola Lilja <ola.o.lilja@stericsson.com>, | ||
5 | * Roger Nilsson <roger.xr.nilsson@stericsson.com> | ||
6 | * for ST-Ericsson. | ||
7 | * | ||
8 | * License terms: | ||
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 published | ||
12 | * by the Free Software Foundation. | ||
13 | */ | ||
14 | #ifndef UX500_PCM_H | ||
15 | #define UX500_PCM_H | ||
16 | |||
17 | #include <asm/page.h> | ||
18 | |||
19 | #include <linux/workqueue.h> | ||
20 | |||
21 | #define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000 | ||
22 | #define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000 | ||
23 | #define UX500_PLATFORM_MIN_RATE_CAPTURE 8000 | ||
24 | #define UX500_PLATFORM_MAX_RATE_CAPTURE 48000 | ||
25 | |||
26 | #define UX500_PLATFORM_MIN_CHANNELS 1 | ||
27 | #define UX500_PLATFORM_MAX_CHANNELS 8 | ||
28 | |||
29 | #define UX500_PLATFORM_PERIODS_BYTES_MIN 128 | ||
30 | #define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE) | ||
31 | #define UX500_PLATFORM_PERIODS_MIN 2 | ||
32 | #define UX500_PLATFORM_PERIODS_MAX 48 | ||
33 | #define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) | ||
34 | |||
35 | #endif | ||