diff options
Diffstat (limited to 'sound')
79 files changed, 4763 insertions, 335 deletions
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index 6c00ea45d5cb..4e34d19ddbc0 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c | |||
@@ -207,8 +207,8 @@ static int __devinit pxa2xx_ac97_probe(struct platform_device *dev) | |||
207 | snprintf(card->longname, sizeof(card->longname), | 207 | snprintf(card->longname, sizeof(card->longname), |
208 | "%s (%s)", dev->dev.driver->name, card->mixername); | 208 | "%s (%s)", dev->dev.driver->name, card->mixername); |
209 | 209 | ||
210 | if (pdata && pdata->codec_data) | 210 | if (pdata && pdata->codec_pdata[0]) |
211 | snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata); | 211 | snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]); |
212 | snd_card_set_dev(card, &dev->dev); | 212 | snd_card_set_dev(card, &dev->dev); |
213 | ret = snd_card_register(card); | 213 | ret = snd_card_register(card); |
214 | if (ret == 0) { | 214 | if (ret == 0) { |
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 6205f37d547c..743ac6a29065 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c | |||
@@ -136,6 +136,9 @@ int __pxa2xx_pcm_prepare(struct snd_pcm_substream *substream) | |||
136 | { | 136 | { |
137 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; | 137 | struct pxa2xx_runtime_data *prtd = substream->runtime->private_data; |
138 | 138 | ||
139 | if (!prtd || !prtd->params) | ||
140 | return 0; | ||
141 | |||
139 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; | 142 | DCSR(prtd->dma_ch) &= ~DCSR_RUN; |
140 | DCSR(prtd->dma_ch) = 0; | 143 | DCSR(prtd->dma_ch) = 0; |
141 | DCMD(prtd->dma_ch) = 0; | 144 | DCMD(prtd->dma_ch) = 0; |
diff --git a/sound/soc/atmel/playpaq_wm8510.c b/sound/soc/atmel/playpaq_wm8510.c index 9eb610c2ba91..9df4c68ef000 100644 --- a/sound/soc/atmel/playpaq_wm8510.c +++ b/sound/soc/atmel/playpaq_wm8510.c | |||
@@ -268,7 +268,7 @@ static int playpaq_wm8510_hw_params(struct snd_pcm_substream *substream, | |||
268 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ | 268 | #endif /* CONFIG_SND_AT32_SOC_PLAYPAQ_SLAVE */ |
269 | 269 | ||
270 | 270 | ||
271 | ret = snd_soc_dai_set_pll(codec_dai, 0, | 271 | ret = snd_soc_dai_set_pll(codec_dai, 0, 0, |
272 | clk_get_rate(CODEC_CLK), pll_out); | 272 | clk_get_rate(CODEC_CLK), pll_out); |
273 | if (ret < 0) { | 273 | if (ret < 0) { |
274 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", | 274 | pr_warning("playpaq_wm8510: Failed to set CODEC DAI PLL (%d)\n", |
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 479d7bdf1865..a521aa90ddee 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. | 2 | * Au12x0/Au1550 PSC ALSA ASoC audio support. |
3 | * | 3 | * |
4 | * (c) 2007-2008 MSC Vertriebsges.m.b.H., | 4 | * (c) 2007-2009 MSC Vertriebsges.m.b.H., |
5 | * Manuel Lauss <mano@roarinelk.homelinux.net> | 5 | * Manuel Lauss <manuel.lauss@gmail.com> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
20 | #include <linux/device.h> | 20 | #include <linux/device.h> |
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/mutex.h> | ||
22 | #include <linux/suspend.h> | 23 | #include <linux/suspend.h> |
23 | #include <sound/core.h> | 24 | #include <sound/core.h> |
24 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
@@ -29,6 +30,9 @@ | |||
29 | 30 | ||
30 | #include "psc.h" | 31 | #include "psc.h" |
31 | 32 | ||
33 | /* how often to retry failed codec register reads/writes */ | ||
34 | #define AC97_RW_RETRIES 5 | ||
35 | |||
32 | #define AC97_DIR \ | 36 | #define AC97_DIR \ |
33 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) | 37 | (SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE) |
34 | 38 | ||
@@ -45,6 +49,9 @@ | |||
45 | #define AC97PCR_CLRFIFO(stype) \ | 49 | #define AC97PCR_CLRFIFO(stype) \ |
46 | ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) | 50 | ((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC) |
47 | 51 | ||
52 | #define AC97STAT_BUSY(stype) \ | ||
53 | ((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB) | ||
54 | |||
48 | /* instance data. There can be only one, MacLeod!!!! */ | 55 | /* instance data. There can be only one, MacLeod!!!! */ |
49 | static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; | 56 | static struct au1xpsc_audio_data *au1xpsc_ac97_workdata; |
50 | 57 | ||
@@ -54,24 +61,33 @@ static unsigned short au1xpsc_ac97_read(struct snd_ac97 *ac97, | |||
54 | { | 61 | { |
55 | /* FIXME */ | 62 | /* FIXME */ |
56 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | 63 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; |
57 | unsigned short data, tmo; | 64 | unsigned short data, retry, tmo; |
58 | 65 | ||
59 | au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), AC97_CDC(pscdata)); | 66 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
60 | au_sync(); | 67 | au_sync(); |
61 | 68 | ||
62 | tmo = 1000; | 69 | retry = AC97_RW_RETRIES; |
63 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | 70 | do { |
64 | udelay(2); | 71 | mutex_lock(&pscdata->lock); |
72 | |||
73 | au_writel(PSC_AC97CDC_RD | PSC_AC97CDC_INDX(reg), | ||
74 | AC97_CDC(pscdata)); | ||
75 | au_sync(); | ||
76 | |||
77 | tmo = 2000; | ||
78 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) | ||
79 | && --tmo) | ||
80 | udelay(2); | ||
65 | 81 | ||
66 | if (!tmo) | ||
67 | data = 0xffff; | ||
68 | else | ||
69 | data = au_readl(AC97_CDC(pscdata)) & 0xffff; | 82 | data = au_readl(AC97_CDC(pscdata)) & 0xffff; |
70 | 83 | ||
71 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | 84 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
72 | au_sync(); | 85 | au_sync(); |
86 | |||
87 | mutex_unlock(&pscdata->lock); | ||
88 | } while (--retry && !tmo); | ||
73 | 89 | ||
74 | return data; | 90 | return retry ? data : 0xffff; |
75 | } | 91 | } |
76 | 92 | ||
77 | /* AC97 controller writes to codec register */ | 93 | /* AC97 controller writes to codec register */ |
@@ -80,16 +96,29 @@ static void au1xpsc_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | |||
80 | { | 96 | { |
81 | /* FIXME */ | 97 | /* FIXME */ |
82 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | 98 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; |
83 | unsigned int tmo; | 99 | unsigned int tmo, retry; |
84 | 100 | ||
85 | au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), AC97_CDC(pscdata)); | 101 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); |
86 | au_sync(); | 102 | au_sync(); |
87 | tmo = 1000; | 103 | |
88 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) && --tmo) | 104 | retry = AC97_RW_RETRIES; |
105 | do { | ||
106 | mutex_lock(&pscdata->lock); | ||
107 | |||
108 | au_writel(PSC_AC97CDC_INDX(reg) | (val & 0xffff), | ||
109 | AC97_CDC(pscdata)); | ||
89 | au_sync(); | 110 | au_sync(); |
90 | 111 | ||
91 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | 112 | tmo = 2000; |
92 | au_sync(); | 113 | while ((!(au_readl(AC97_EVNT(pscdata)) & PSC_AC97EVNT_CD)) |
114 | && --tmo) | ||
115 | udelay(2); | ||
116 | |||
117 | au_writel(PSC_AC97EVNT_CD, AC97_EVNT(pscdata)); | ||
118 | au_sync(); | ||
119 | |||
120 | mutex_unlock(&pscdata->lock); | ||
121 | } while (--retry && !tmo); | ||
93 | } | 122 | } |
94 | 123 | ||
95 | /* AC97 controller asserts a warm reset */ | 124 | /* AC97 controller asserts a warm reset */ |
@@ -129,9 +158,9 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) | |||
129 | au_sync(); | 158 | au_sync(); |
130 | 159 | ||
131 | /* wait for PSC to indicate it's ready */ | 160 | /* wait for PSC to indicate it's ready */ |
132 | i = 100000; | 161 | i = 1000; |
133 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) | 162 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_SR)) && (--i)) |
134 | au_sync(); | 163 | msleep(1); |
135 | 164 | ||
136 | if (i == 0) { | 165 | if (i == 0) { |
137 | printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); | 166 | printk(KERN_ERR "au1xpsc-ac97: PSC not ready!\n"); |
@@ -143,9 +172,9 @@ static void au1xpsc_ac97_cold_reset(struct snd_ac97 *ac97) | |||
143 | au_sync(); | 172 | au_sync(); |
144 | 173 | ||
145 | /* wait for AC97 core to become ready */ | 174 | /* wait for AC97 core to become ready */ |
146 | i = 100000; | 175 | i = 1000; |
147 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) | 176 | while (!((au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) && (--i)) |
148 | au_sync(); | 177 | msleep(1); |
149 | if (i == 0) | 178 | if (i == 0) |
150 | printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); | 179 | printk(KERN_ERR "au1xpsc-ac97: AC97 ctrl not ready\n"); |
151 | } | 180 | } |
@@ -165,12 +194,12 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, | |||
165 | { | 194 | { |
166 | /* FIXME */ | 195 | /* FIXME */ |
167 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; | 196 | struct au1xpsc_audio_data *pscdata = au1xpsc_ac97_workdata; |
168 | unsigned long r, stat; | 197 | unsigned long r, ro, stat; |
169 | int chans, stype = SUBSTREAM_TYPE(substream); | 198 | int chans, stype = SUBSTREAM_TYPE(substream); |
170 | 199 | ||
171 | chans = params_channels(params); | 200 | chans = params_channels(params); |
172 | 201 | ||
173 | r = au_readl(AC97_CFG(pscdata)); | 202 | r = ro = au_readl(AC97_CFG(pscdata)); |
174 | stat = au_readl(AC97_STAT(pscdata)); | 203 | stat = au_readl(AC97_STAT(pscdata)); |
175 | 204 | ||
176 | /* already active? */ | 205 | /* already active? */ |
@@ -180,9 +209,6 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, | |||
180 | (pscdata->rate != params_rate(params))) | 209 | (pscdata->rate != params_rate(params))) |
181 | return -EINVAL; | 210 | return -EINVAL; |
182 | } else { | 211 | } else { |
183 | /* disable AC97 device controller first */ | ||
184 | au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
185 | au_sync(); | ||
186 | 212 | ||
187 | /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ | 213 | /* set sample bitdepth: REG[24:21]=(BITS-2)/2 */ |
188 | r &= ~PSC_AC97CFG_LEN_MASK; | 214 | r &= ~PSC_AC97CFG_LEN_MASK; |
@@ -199,14 +225,40 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream, | |||
199 | r |= PSC_AC97CFG_RXSLOT_ENA(4); | 225 | r |= PSC_AC97CFG_RXSLOT_ENA(4); |
200 | } | 226 | } |
201 | 227 | ||
202 | /* finally enable the AC97 controller again */ | 228 | /* do we need to poke the hardware? */ |
229 | if (!(r ^ ro)) | ||
230 | goto out; | ||
231 | |||
232 | /* ac97 engine is about to be disabled */ | ||
233 | mutex_lock(&pscdata->lock); | ||
234 | |||
235 | /* disable AC97 device controller first... */ | ||
236 | au_writel(r & ~PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | ||
237 | au_sync(); | ||
238 | |||
239 | /* ...wait for it... */ | ||
240 | while (au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR) | ||
241 | asm volatile ("nop"); | ||
242 | |||
243 | /* ...write config... */ | ||
244 | au_writel(r, AC97_CFG(pscdata)); | ||
245 | au_sync(); | ||
246 | |||
247 | /* ...enable the AC97 controller again... */ | ||
203 | au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); | 248 | au_writel(r | PSC_AC97CFG_DE_ENABLE, AC97_CFG(pscdata)); |
204 | au_sync(); | 249 | au_sync(); |
205 | 250 | ||
251 | /* ...and wait for ready bit */ | ||
252 | while (!(au_readl(AC97_STAT(pscdata)) & PSC_AC97STAT_DR)) | ||
253 | asm volatile ("nop"); | ||
254 | |||
255 | mutex_unlock(&pscdata->lock); | ||
256 | |||
206 | pscdata->cfg = r; | 257 | pscdata->cfg = r; |
207 | pscdata->rate = params_rate(params); | 258 | pscdata->rate = params_rate(params); |
208 | } | 259 | } |
209 | 260 | ||
261 | out: | ||
210 | return 0; | 262 | return 0; |
211 | } | 263 | } |
212 | 264 | ||
@@ -222,6 +274,8 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, | |||
222 | switch (cmd) { | 274 | switch (cmd) { |
223 | case SNDRV_PCM_TRIGGER_START: | 275 | case SNDRV_PCM_TRIGGER_START: |
224 | case SNDRV_PCM_TRIGGER_RESUME: | 276 | case SNDRV_PCM_TRIGGER_RESUME: |
277 | au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); | ||
278 | au_sync(); | ||
225 | au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); | 279 | au_writel(AC97PCR_START(stype), AC97_PCR(pscdata)); |
226 | au_sync(); | 280 | au_sync(); |
227 | break; | 281 | break; |
@@ -229,6 +283,13 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream, | |||
229 | case SNDRV_PCM_TRIGGER_SUSPEND: | 283 | case SNDRV_PCM_TRIGGER_SUSPEND: |
230 | au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); | 284 | au_writel(AC97PCR_STOP(stype), AC97_PCR(pscdata)); |
231 | au_sync(); | 285 | au_sync(); |
286 | |||
287 | while (au_readl(AC97_STAT(pscdata)) & AC97STAT_BUSY(stype)) | ||
288 | asm volatile ("nop"); | ||
289 | |||
290 | au_writel(AC97PCR_CLRFIFO(stype), AC97_PCR(pscdata)); | ||
291 | au_sync(); | ||
292 | |||
232 | break; | 293 | break; |
233 | default: | 294 | default: |
234 | ret = -EINVAL; | 295 | ret = -EINVAL; |
@@ -251,6 +312,8 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev, | |||
251 | if (!au1xpsc_ac97_workdata) | 312 | if (!au1xpsc_ac97_workdata) |
252 | return -ENOMEM; | 313 | return -ENOMEM; |
253 | 314 | ||
315 | mutex_init(&au1xpsc_ac97_workdata->lock); | ||
316 | |||
254 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 317 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
255 | if (!r) { | 318 | if (!r) { |
256 | ret = -ENODEV; | 319 | ret = -ENODEV; |
@@ -269,9 +332,9 @@ static int au1xpsc_ac97_probe(struct platform_device *pdev, | |||
269 | goto out1; | 332 | goto out1; |
270 | 333 | ||
271 | /* configuration: max dma trigger threshold, enable ac97 */ | 334 | /* configuration: max dma trigger threshold, enable ac97 */ |
272 | au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | | 335 | au1xpsc_ac97_workdata->cfg = PSC_AC97CFG_RT_FIFO8 | |
273 | PSC_AC97CFG_TT_FIFO8 | | 336 | PSC_AC97CFG_TT_FIFO8 | |
274 | PSC_AC97CFG_DE_ENABLE; | 337 | PSC_AC97CFG_DE_ENABLE; |
275 | 338 | ||
276 | /* preserve PSC clock source set up by platform (dev.platform_data | 339 | /* preserve PSC clock source set up by platform (dev.platform_data |
277 | * is already occupied by soc layer) | 340 | * is already occupied by soc layer) |
@@ -386,4 +449,4 @@ module_exit(au1xpsc_ac97_exit); | |||
386 | 449 | ||
387 | MODULE_LICENSE("GPL"); | 450 | MODULE_LICENSE("GPL"); |
388 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); | 451 | MODULE_DESCRIPTION("Au12x0/Au1550 PSC AC97 ALSA ASoC audio driver"); |
389 | MODULE_AUTHOR("Manuel Lauss <mano@roarinelk.homelinux.net>"); | 452 | MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>"); |
diff --git a/sound/soc/au1x/psc.h b/sound/soc/au1x/psc.h index 8fdb1a04a07b..3f474e8ed4f6 100644 --- a/sound/soc/au1x/psc.h +++ b/sound/soc/au1x/psc.h | |||
@@ -29,6 +29,7 @@ struct au1xpsc_audio_data { | |||
29 | 29 | ||
30 | unsigned long pm[2]; | 30 | unsigned long pm[2]; |
31 | struct resource *ioarea; | 31 | struct resource *ioarea; |
32 | struct mutex lock; | ||
32 | }; | 33 | }; |
33 | 34 | ||
34 | #define PCM_TX 0 | 35 | #define PCM_TX 0 |
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 8a4de4de30f2..ac927ffdc961 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -88,6 +88,14 @@ config SND_BF5XX_SOC_AC97 | |||
88 | select SND_SOC_AC97_BUS | 88 | select SND_SOC_AC97_BUS |
89 | select SND_BF5XX_SOC_SPORT | 89 | select SND_BF5XX_SOC_SPORT |
90 | 90 | ||
91 | config SND_BF5XX_SOC_AD1836 | ||
92 | tristate "SoC AD1836 Audio support for BF5xx" | ||
93 | depends on SND_BF5XX_TDM | ||
94 | select SND_BF5XX_SOC_TDM | ||
95 | select SND_SOC_AD1836 | ||
96 | help | ||
97 | Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. | ||
98 | |||
91 | config SND_BF5XX_SOC_AD1980 | 99 | config SND_BF5XX_SOC_AD1980 |
92 | tristate "SoC AD1980/1 Audio support for BF5xx" | 100 | tristate "SoC AD1980/1 Audio support for BF5xx" |
93 | depends on SND_BF5XX_AC97 | 101 | depends on SND_BF5XX_AC97 |
diff --git a/sound/soc/blackfin/Makefile b/sound/soc/blackfin/Makefile index f4d760741fab..87e30423912f 100644 --- a/sound/soc/blackfin/Makefile +++ b/sound/soc/blackfin/Makefile | |||
@@ -16,11 +16,13 @@ obj-$(CONFIG_SND_BF5XX_SOC_I2S) += snd-soc-bf5xx-i2s.o | |||
16 | obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o | 16 | obj-$(CONFIG_SND_BF5XX_SOC_TDM) += snd-soc-bf5xx-tdm.o |
17 | 17 | ||
18 | # Blackfin Machine Support | 18 | # Blackfin Machine Support |
19 | snd-ad1836-objs := bf5xx-ad1836.o | ||
19 | snd-ad1980-objs := bf5xx-ad1980.o | 20 | snd-ad1980-objs := bf5xx-ad1980.o |
20 | snd-ssm2602-objs := bf5xx-ssm2602.o | 21 | snd-ssm2602-objs := bf5xx-ssm2602.o |
21 | snd-ad73311-objs := bf5xx-ad73311.o | 22 | snd-ad73311-objs := bf5xx-ad73311.o |
22 | snd-ad1938-objs := bf5xx-ad1938.o | 23 | snd-ad1938-objs := bf5xx-ad1938.o |
23 | 24 | ||
25 | obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o | ||
24 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o | 26 | obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o |
25 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o | 27 | obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o |
26 | obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o | 28 | obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o |
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c index 2758b9017a7f..e69322978739 100644 --- a/sound/soc/blackfin/bf5xx-ac97.c +++ b/sound/soc/blackfin/bf5xx-ac97.c | |||
@@ -277,7 +277,11 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai) | |||
277 | if (!dai->active) | 277 | if (!dai->active) |
278 | return 0; | 278 | return 0; |
279 | 279 | ||
280 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | ||
281 | ret = sport_set_multichannel(sport, 16, 0x3FF, 1); | ||
282 | #else | ||
280 | ret = sport_set_multichannel(sport, 16, 0x1F, 1); | 283 | ret = sport_set_multichannel(sport, 16, 0x1F, 1); |
284 | #endif | ||
281 | if (ret) { | 285 | if (ret) { |
282 | pr_err("SPORT is busy!\n"); | 286 | pr_err("SPORT is busy!\n"); |
283 | return -EBUSY; | 287 | return -EBUSY; |
@@ -334,7 +338,11 @@ static int bf5xx_ac97_probe(struct platform_device *pdev, | |||
334 | goto sport_err; | 338 | goto sport_err; |
335 | } | 339 | } |
336 | /*SPORT works in TDM mode to simulate AC97 transfers*/ | 340 | /*SPORT works in TDM mode to simulate AC97 transfers*/ |
341 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | ||
342 | ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1); | ||
343 | #else | ||
337 | ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); | 344 | ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); |
345 | #endif | ||
338 | if (ret) { | 346 | if (ret) { |
339 | pr_err("SPORT is busy!\n"); | 347 | pr_err("SPORT is busy!\n"); |
340 | ret = -EBUSY; | 348 | ret = -EBUSY; |
diff --git a/sound/soc/blackfin/bf5xx-ac97.h b/sound/soc/blackfin/bf5xx-ac97.h index 3f2a911fe0cb..a1f97dd809d6 100644 --- a/sound/soc/blackfin/bf5xx-ac97.h +++ b/sound/soc/blackfin/bf5xx-ac97.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/sound/arm/bf5xx-ac97.h | 2 | * sound/soc/blackfin/bf5xx-ac97.h |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
diff --git a/sound/soc/blackfin/bf5xx-ad1836.c b/sound/soc/blackfin/bf5xx-ad1836.c new file mode 100644 index 000000000000..0f45a3f56be8 --- /dev/null +++ b/sound/soc/blackfin/bf5xx-ad1836.c | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | * File: sound/soc/blackfin/bf5xx-ad1836.c | ||
3 | * Author: Barry Song <Barry.Song@analog.com> | ||
4 | * | ||
5 | * Created: Aug 4 2009 | ||
6 | * Description: Board driver for ad1836 sound chip | ||
7 | * | ||
8 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/moduleparam.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <sound/core.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/soc.h> | ||
23 | #include <sound/soc-dapm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | |||
26 | #include <asm/blackfin.h> | ||
27 | #include <asm/cacheflush.h> | ||
28 | #include <asm/irq.h> | ||
29 | #include <asm/dma.h> | ||
30 | #include <asm/portmux.h> | ||
31 | |||
32 | #include "../codecs/ad1836.h" | ||
33 | #include "bf5xx-sport.h" | ||
34 | |||
35 | #include "bf5xx-tdm-pcm.h" | ||
36 | #include "bf5xx-tdm.h" | ||
37 | |||
38 | static struct snd_soc_card bf5xx_ad1836; | ||
39 | |||
40 | static int bf5xx_ad1836_startup(struct snd_pcm_substream *substream) | ||
41 | { | ||
42 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
43 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
44 | |||
45 | cpu_dai->private_data = sport_handle; | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int bf5xx_ad1836_hw_params(struct snd_pcm_substream *substream, | ||
50 | struct snd_pcm_hw_params *params) | ||
51 | { | ||
52 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
53 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
54 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
55 | unsigned int channel_map[] = {0, 4, 1, 5, 2, 6, 3, 7}; | ||
56 | int ret = 0; | ||
57 | /* set cpu DAI configuration */ | ||
58 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | ||
59 | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); | ||
60 | if (ret < 0) | ||
61 | return ret; | ||
62 | |||
63 | /* set codec DAI configuration */ | ||
64 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_DSP_A | | ||
65 | SND_SOC_DAIFMT_IB_IF | SND_SOC_DAIFMT_CBM_CFM); | ||
66 | if (ret < 0) | ||
67 | return ret; | ||
68 | |||
69 | /* set cpu DAI channel mapping */ | ||
70 | ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), | ||
71 | channel_map, ARRAY_SIZE(channel_map), channel_map); | ||
72 | if (ret < 0) | ||
73 | return ret; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static struct snd_soc_ops bf5xx_ad1836_ops = { | ||
79 | .startup = bf5xx_ad1836_startup, | ||
80 | .hw_params = bf5xx_ad1836_hw_params, | ||
81 | }; | ||
82 | |||
83 | static struct snd_soc_dai_link bf5xx_ad1836_dai = { | ||
84 | .name = "ad1836", | ||
85 | .stream_name = "AD1836", | ||
86 | .cpu_dai = &bf5xx_tdm_dai, | ||
87 | .codec_dai = &ad1836_dai, | ||
88 | .ops = &bf5xx_ad1836_ops, | ||
89 | }; | ||
90 | |||
91 | static struct snd_soc_card bf5xx_ad1836 = { | ||
92 | .name = "bf5xx_ad1836", | ||
93 | .platform = &bf5xx_tdm_soc_platform, | ||
94 | .dai_link = &bf5xx_ad1836_dai, | ||
95 | .num_links = 1, | ||
96 | }; | ||
97 | |||
98 | static struct snd_soc_device bf5xx_ad1836_snd_devdata = { | ||
99 | .card = &bf5xx_ad1836, | ||
100 | .codec_dev = &soc_codec_dev_ad1836, | ||
101 | }; | ||
102 | |||
103 | static struct platform_device *bfxx_ad1836_snd_device; | ||
104 | |||
105 | static int __init bf5xx_ad1836_init(void) | ||
106 | { | ||
107 | int ret; | ||
108 | |||
109 | bfxx_ad1836_snd_device = platform_device_alloc("soc-audio", -1); | ||
110 | if (!bfxx_ad1836_snd_device) | ||
111 | return -ENOMEM; | ||
112 | |||
113 | platform_set_drvdata(bfxx_ad1836_snd_device, &bf5xx_ad1836_snd_devdata); | ||
114 | bf5xx_ad1836_snd_devdata.dev = &bfxx_ad1836_snd_device->dev; | ||
115 | ret = platform_device_add(bfxx_ad1836_snd_device); | ||
116 | |||
117 | if (ret) | ||
118 | platform_device_put(bfxx_ad1836_snd_device); | ||
119 | |||
120 | return ret; | ||
121 | } | ||
122 | |||
123 | static void __exit bf5xx_ad1836_exit(void) | ||
124 | { | ||
125 | platform_device_unregister(bfxx_ad1836_snd_device); | ||
126 | } | ||
127 | |||
128 | module_init(bf5xx_ad1836_init); | ||
129 | module_exit(bf5xx_ad1836_exit); | ||
130 | |||
131 | /* Module information */ | ||
132 | MODULE_AUTHOR("Barry Song"); | ||
133 | MODULE_DESCRIPTION("ALSA SoC AD1836 board driver"); | ||
134 | MODULE_LICENSE("GPL"); | ||
135 | |||
diff --git a/sound/soc/blackfin/bf5xx-ad1938.c b/sound/soc/blackfin/bf5xx-ad1938.c index 08269e91810c..2ef1e5013b8c 100644 --- a/sound/soc/blackfin/bf5xx-ad1938.c +++ b/sound/soc/blackfin/bf5xx-ad1938.c | |||
@@ -61,6 +61,7 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, | |||
61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 61 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
62 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 62 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
63 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | 63 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; |
64 | unsigned int channel_map[] = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
64 | int ret = 0; | 65 | int ret = 0; |
65 | /* set cpu DAI configuration */ | 66 | /* set cpu DAI configuration */ |
66 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | | 67 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_DSP_A | |
@@ -75,7 +76,13 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream, | |||
75 | return ret; | 76 | return ret; |
76 | 77 | ||
77 | /* set codec DAI slots, 8 channels, all channels are enabled */ | 78 | /* set codec DAI slots, 8 channels, all channels are enabled */ |
78 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 8); | 79 | ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xFF, 0xFF, 8, 32); |
80 | if (ret < 0) | ||
81 | return ret; | ||
82 | |||
83 | /* set cpu DAI channel mapping */ | ||
84 | ret = snd_soc_dai_set_channel_map(cpu_dai, ARRAY_SIZE(channel_map), | ||
85 | channel_map, ARRAY_SIZE(channel_map), channel_map); | ||
79 | if (ret < 0) | 86 | if (ret < 0) |
80 | return ret; | 87 | return ret; |
81 | 88 | ||
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index 876abade27e1..1e9d161c76c4 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -227,7 +227,8 @@ static int bf5xx_i2s_probe(struct platform_device *pdev, | |||
227 | return 0; | 227 | return 0; |
228 | } | 228 | } |
229 | 229 | ||
230 | static void bf5xx_i2s_remove(struct snd_soc_dai *dai) | 230 | static void bf5xx_i2s_remove(struct platform_device *pdev, |
231 | struct snd_soc_dai *dai) | ||
231 | { | 232 | { |
232 | pr_debug("%s enter\n", __func__); | 233 | pr_debug("%s enter\n", __func__); |
233 | peripheral_free_list(&sport_req[sport_num][0]); | 234 | peripheral_free_list(&sport_req[sport_num][0]); |
@@ -236,36 +237,31 @@ static void bf5xx_i2s_remove(struct snd_soc_dai *dai) | |||
236 | #ifdef CONFIG_PM | 237 | #ifdef CONFIG_PM |
237 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | 238 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) |
238 | { | 239 | { |
239 | struct sport_device *sport = | ||
240 | (struct sport_device *)dai->private_data; | ||
241 | 240 | ||
242 | pr_debug("%s : sport %d\n", __func__, dai->id); | 241 | pr_debug("%s : sport %d\n", __func__, dai->id); |
243 | if (!dai->active) | 242 | |
244 | return 0; | ||
245 | if (dai->capture.active) | 243 | if (dai->capture.active) |
246 | sport_rx_stop(sport); | 244 | sport_rx_stop(sport_handle); |
247 | if (dai->playback.active) | 245 | if (dai->playback.active) |
248 | sport_tx_stop(sport); | 246 | sport_tx_stop(sport_handle); |
249 | return 0; | 247 | return 0; |
250 | } | 248 | } |
251 | 249 | ||
252 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | 250 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) |
253 | { | 251 | { |
254 | int ret; | 252 | int ret; |
255 | struct sport_device *sport = | ||
256 | (struct sport_device *)dai->private_data; | ||
257 | 253 | ||
258 | pr_debug("%s : sport %d\n", __func__, dai->id); | 254 | pr_debug("%s : sport %d\n", __func__, dai->id); |
259 | if (!dai->active) | ||
260 | return 0; | ||
261 | 255 | ||
262 | ret = sport_config_rx(sport, RFSR | RCKFE, RSFSE|0x1f, 0, 0); | 256 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, |
257 | bf5xx_i2s.rcr2, 0, 0); | ||
263 | if (ret) { | 258 | if (ret) { |
264 | pr_err("SPORT is busy!\n"); | 259 | pr_err("SPORT is busy!\n"); |
265 | return -EBUSY; | 260 | return -EBUSY; |
266 | } | 261 | } |
267 | 262 | ||
268 | ret = sport_config_tx(sport, TFSR | TCKFE, TSFSE|0x1f, 0, 0); | 263 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, |
264 | bf5xx_i2s.tcr2, 0, 0); | ||
269 | if (ret) { | 265 | if (ret) { |
270 | pr_err("SPORT is busy!\n"); | 266 | pr_err("SPORT is busy!\n"); |
271 | return -EBUSY; | 267 | return -EBUSY; |
diff --git a/sound/soc/blackfin/bf5xx-i2s.h b/sound/soc/blackfin/bf5xx-i2s.h index 7107d1a0b06b..264ecdcba35a 100644 --- a/sound/soc/blackfin/bf5xx-i2s.h +++ b/sound/soc/blackfin/bf5xx-i2s.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * linux/sound/arm/bf5xx-i2s.h | 2 | * sound/soc/blackfin/bf5xx-i2s.h |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or modify | 4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License version 2 as | 5 | * it under the terms of the GNU General Public License version 2 as |
diff --git a/sound/soc/blackfin/bf5xx-sport.c b/sound/soc/blackfin/bf5xx-sport.c index 469ce7fab20c..99051ff0954e 100644 --- a/sound/soc/blackfin/bf5xx-sport.c +++ b/sound/soc/blackfin/bf5xx-sport.c | |||
@@ -326,7 +326,7 @@ static inline int sport_hook_tx_dummy(struct sport_device *sport) | |||
326 | 326 | ||
327 | int sport_tx_start(struct sport_device *sport) | 327 | int sport_tx_start(struct sport_device *sport) |
328 | { | 328 | { |
329 | unsigned flags; | 329 | unsigned long flags; |
330 | pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__, | 330 | pr_debug("%s: tx_run:%d, rx_run:%d\n", __func__, |
331 | sport->tx_run, sport->rx_run); | 331 | sport->tx_run, sport->rx_run); |
332 | if (sport->tx_run) | 332 | if (sport->tx_run) |
diff --git a/sound/soc/blackfin/bf5xx-tdm-pcm.c b/sound/soc/blackfin/bf5xx-tdm-pcm.c index ccb5e823bd18..a8c73cbbd685 100644 --- a/sound/soc/blackfin/bf5xx-tdm-pcm.c +++ b/sound/soc/blackfin/bf5xx-tdm-pcm.c | |||
@@ -43,7 +43,7 @@ | |||
43 | #include "bf5xx-tdm.h" | 43 | #include "bf5xx-tdm.h" |
44 | #include "bf5xx-sport.h" | 44 | #include "bf5xx-sport.h" |
45 | 45 | ||
46 | #define PCM_BUFFER_MAX 0x10000 | 46 | #define PCM_BUFFER_MAX 0x8000 |
47 | #define FRAGMENT_SIZE_MIN (4*1024) | 47 | #define FRAGMENT_SIZE_MIN (4*1024) |
48 | #define FRAGMENTS_MIN 2 | 48 | #define FRAGMENTS_MIN 2 |
49 | #define FRAGMENTS_MAX 32 | 49 | #define FRAGMENTS_MAX 32 |
@@ -177,6 +177,9 @@ out: | |||
177 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | 177 | static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, |
178 | snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) | 178 | snd_pcm_uframes_t pos, void *buf, snd_pcm_uframes_t count) |
179 | { | 179 | { |
180 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
181 | struct sport_device *sport = runtime->private_data; | ||
182 | struct bf5xx_tdm_port *tdm_port = sport->private_data; | ||
180 | unsigned int *src; | 183 | unsigned int *src; |
181 | unsigned int *dst; | 184 | unsigned int *dst; |
182 | int i; | 185 | int i; |
@@ -188,7 +191,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
188 | dst += pos * 8; | 191 | dst += pos * 8; |
189 | while (count--) { | 192 | while (count--) { |
190 | for (i = 0; i < substream->runtime->channels; i++) | 193 | for (i = 0; i < substream->runtime->channels; i++) |
191 | *(dst + i) = *src++; | 194 | *(dst + tdm_port->tx_map[i]) = *src++; |
192 | dst += 8; | 195 | dst += 8; |
193 | } | 196 | } |
194 | } else { | 197 | } else { |
@@ -198,7 +201,7 @@ static int bf5xx_pcm_copy(struct snd_pcm_substream *substream, int channel, | |||
198 | src += pos * 8; | 201 | src += pos * 8; |
199 | while (count--) { | 202 | while (count--) { |
200 | for (i = 0; i < substream->runtime->channels; i++) | 203 | for (i = 0; i < substream->runtime->channels; i++) |
201 | *dst++ = *(src+i); | 204 | *dst++ = *(src + tdm_port->rx_map[i]); |
202 | src += 8; | 205 | src += 8; |
203 | } | 206 | } |
204 | } | 207 | } |
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 3096badf09a5..600987d8a871 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c | |||
@@ -46,14 +46,6 @@ | |||
46 | #include "bf5xx-sport.h" | 46 | #include "bf5xx-sport.h" |
47 | #include "bf5xx-tdm.h" | 47 | #include "bf5xx-tdm.h" |
48 | 48 | ||
49 | struct bf5xx_tdm_port { | ||
50 | u16 tcr1; | ||
51 | u16 rcr1; | ||
52 | u16 tcr2; | ||
53 | u16 rcr2; | ||
54 | int configured; | ||
55 | }; | ||
56 | |||
57 | static struct bf5xx_tdm_port bf5xx_tdm; | 49 | static struct bf5xx_tdm_port bf5xx_tdm; |
58 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | 50 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; |
59 | 51 | ||
@@ -181,6 +173,40 @@ static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, | |||
181 | bf5xx_tdm.configured = 0; | 173 | bf5xx_tdm.configured = 0; |
182 | } | 174 | } |
183 | 175 | ||
176 | static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | ||
177 | unsigned int tx_num, unsigned int *tx_slot, | ||
178 | unsigned int rx_num, unsigned int *rx_slot) | ||
179 | { | ||
180 | int i; | ||
181 | unsigned int slot; | ||
182 | unsigned int tx_mapped = 0, rx_mapped = 0; | ||
183 | |||
184 | if ((tx_num > BFIN_TDM_DAI_MAX_SLOTS) || | ||
185 | (rx_num > BFIN_TDM_DAI_MAX_SLOTS)) | ||
186 | return -EINVAL; | ||
187 | |||
188 | for (i = 0; i < tx_num; i++) { | ||
189 | slot = tx_slot[i]; | ||
190 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
191 | (!(tx_mapped & (1 << slot)))) { | ||
192 | bf5xx_tdm.tx_map[i] = slot; | ||
193 | tx_mapped |= 1 << slot; | ||
194 | } else | ||
195 | return -EINVAL; | ||
196 | } | ||
197 | for (i = 0; i < rx_num; i++) { | ||
198 | slot = rx_slot[i]; | ||
199 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | ||
200 | (!(rx_mapped & (1 << slot)))) { | ||
201 | bf5xx_tdm.rx_map[i] = slot; | ||
202 | rx_mapped |= 1 << slot; | ||
203 | } else | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
184 | #ifdef CONFIG_PM | 210 | #ifdef CONFIG_PM |
185 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) | 211 | static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) |
186 | { | 212 | { |
@@ -235,6 +261,7 @@ static struct snd_soc_dai_ops bf5xx_tdm_dai_ops = { | |||
235 | .hw_params = bf5xx_tdm_hw_params, | 261 | .hw_params = bf5xx_tdm_hw_params, |
236 | .set_fmt = bf5xx_tdm_set_dai_fmt, | 262 | .set_fmt = bf5xx_tdm_set_dai_fmt, |
237 | .shutdown = bf5xx_tdm_shutdown, | 263 | .shutdown = bf5xx_tdm_shutdown, |
264 | .set_channel_map = bf5xx_tdm_set_channel_map, | ||
238 | }; | 265 | }; |
239 | 266 | ||
240 | struct snd_soc_dai bf5xx_tdm_dai = { | 267 | struct snd_soc_dai bf5xx_tdm_dai = { |
@@ -300,6 +327,8 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev) | |||
300 | pr_err("Failed to register DAI: %d\n", ret); | 327 | pr_err("Failed to register DAI: %d\n", ret); |
301 | goto sport_config_err; | 328 | goto sport_config_err; |
302 | } | 329 | } |
330 | |||
331 | sport_handle->private_data = &bf5xx_tdm; | ||
303 | return 0; | 332 | return 0; |
304 | 333 | ||
305 | sport_config_err: | 334 | sport_config_err: |
diff --git a/sound/soc/blackfin/bf5xx-tdm.h b/sound/soc/blackfin/bf5xx-tdm.h index 618ec3d90cd4..04189a18c1ba 100644 --- a/sound/soc/blackfin/bf5xx-tdm.h +++ b/sound/soc/blackfin/bf5xx-tdm.h | |||
@@ -9,6 +9,17 @@ | |||
9 | #ifndef _BF5XX_TDM_H | 9 | #ifndef _BF5XX_TDM_H |
10 | #define _BF5XX_TDM_H | 10 | #define _BF5XX_TDM_H |
11 | 11 | ||
12 | #define BFIN_TDM_DAI_MAX_SLOTS 8 | ||
13 | struct bf5xx_tdm_port { | ||
14 | u16 tcr1; | ||
15 | u16 rcr1; | ||
16 | u16 tcr2; | ||
17 | u16 rcr2; | ||
18 | unsigned int tx_map[BFIN_TDM_DAI_MAX_SLOTS]; | ||
19 | unsigned int rx_map[BFIN_TDM_DAI_MAX_SLOTS]; | ||
20 | int configured; | ||
21 | }; | ||
22 | |||
12 | extern struct snd_soc_dai bf5xx_tdm_dai; | 23 | extern struct snd_soc_dai bf5xx_tdm_dai; |
13 | 24 | ||
14 | #endif | 25 | #endif |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 20ebf7437f98..3c46f34928ec 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -18,6 +18,8 @@ config SND_SOC_ALL_CODECS | |||
18 | select SND_SOC_AD73311 if I2C | 18 | select SND_SOC_AD73311 if I2C |
19 | select SND_SOC_AK4104 if SPI_MASTER | 19 | select SND_SOC_AK4104 if SPI_MASTER |
20 | select SND_SOC_AK4535 if I2C | 20 | select SND_SOC_AK4535 if I2C |
21 | select SND_SOC_AK4642 if I2C | ||
22 | select SND_SOC_AK4671 if I2C | ||
21 | select SND_SOC_CS4270 if I2C | 23 | select SND_SOC_CS4270 if I2C |
22 | select SND_SOC_MAX9877 if I2C | 24 | select SND_SOC_MAX9877 if I2C |
23 | select SND_SOC_PCM3008 | 25 | select SND_SOC_PCM3008 |
@@ -93,6 +95,12 @@ config SND_SOC_AK4104 | |||
93 | config SND_SOC_AK4535 | 95 | config SND_SOC_AK4535 |
94 | tristate | 96 | tristate |
95 | 97 | ||
98 | config SND_SOC_AK4642 | ||
99 | tristate | ||
100 | |||
101 | config SND_SOC_AK4671 | ||
102 | tristate | ||
103 | |||
96 | # Cirrus Logic CS4270 Codec | 104 | # Cirrus Logic CS4270 Codec |
97 | config SND_SOC_CS4270 | 105 | config SND_SOC_CS4270 |
98 | tristate | 106 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 711d8f5887de..fc1c458cbe2f 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -5,6 +5,8 @@ snd-soc-ad1980-objs := ad1980.o | |||
5 | snd-soc-ad73311-objs := ad73311.o | 5 | snd-soc-ad73311-objs := ad73311.o |
6 | snd-soc-ak4104-objs := ak4104.o | 6 | snd-soc-ak4104-objs := ak4104.o |
7 | snd-soc-ak4535-objs := ak4535.o | 7 | snd-soc-ak4535-objs := ak4535.o |
8 | snd-soc-ak4642-objs := ak4642.o | ||
9 | snd-soc-ak4671-objs := ak4671.o | ||
8 | snd-soc-cs4270-objs := cs4270.o | 10 | snd-soc-cs4270-objs := cs4270.o |
9 | snd-soc-cx20442-objs := cx20442.o | 11 | snd-soc-cx20442-objs := cx20442.o |
10 | snd-soc-l3-objs := l3.o | 12 | snd-soc-l3-objs := l3.o |
@@ -55,6 +57,8 @@ obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | |||
55 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 57 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
56 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 58 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
57 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 59 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
60 | obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o | ||
61 | obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o | ||
58 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o | 62 | obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o |
59 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o | 63 | obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o |
60 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 64 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 3612bb92df90..01343dc984fd 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #include <linux/init.h> | 19 | #include <linux/init.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/version.h> | ||
22 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
23 | #include <linux/device.h> | 22 | #include <linux/device.h> |
24 | #include <sound/core.h> | 23 | #include <sound/core.h> |
diff --git a/sound/soc/codecs/ad1938.c b/sound/soc/codecs/ad1938.c index e62b27701a49..9a049a1995a3 100644 --- a/sound/soc/codecs/ad1938.c +++ b/sound/soc/codecs/ad1938.c | |||
@@ -28,7 +28,6 @@ | |||
28 | 28 | ||
29 | #include <linux/init.h> | 29 | #include <linux/init.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/version.h> | ||
32 | #include <linux/kernel.h> | 31 | #include <linux/kernel.h> |
33 | #include <linux/device.h> | 32 | #include <linux/device.h> |
34 | #include <sound/core.h> | 33 | #include <sound/core.h> |
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c new file mode 100644 index 000000000000..e057c7b578df --- /dev/null +++ b/sound/soc/codecs/ak4642.c | |||
@@ -0,0 +1,502 @@ | |||
1 | /* | ||
2 | * ak4642.c -- AK4642/AK4643 ALSA Soc Audio driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * Based on wm8731.c by Richard Purdie | ||
8 | * Based on ak4535.c by Richard Purdie | ||
9 | * Based on wm8753.c by Liam Girdwood | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | /* ** CAUTION ** | ||
17 | * | ||
18 | * This is very simple driver. | ||
19 | * It can use headphone output / stereo input only | ||
20 | * | ||
21 | * AK4642 is not tested. | ||
22 | * AK4643 is tested. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/pm.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/platform_device.h> | ||
32 | #include <sound/core.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/soc.h> | ||
36 | #include <sound/soc-dapm.h> | ||
37 | #include <sound/initval.h> | ||
38 | |||
39 | #include "ak4642.h" | ||
40 | |||
41 | #define AK4642_VERSION "0.0.1" | ||
42 | |||
43 | #define PW_MGMT1 0x00 | ||
44 | #define PW_MGMT2 0x01 | ||
45 | #define SG_SL1 0x02 | ||
46 | #define SG_SL2 0x03 | ||
47 | #define MD_CTL1 0x04 | ||
48 | #define MD_CTL2 0x05 | ||
49 | #define TIMER 0x06 | ||
50 | #define ALC_CTL1 0x07 | ||
51 | #define ALC_CTL2 0x08 | ||
52 | #define L_IVC 0x09 | ||
53 | #define L_DVC 0x0a | ||
54 | #define ALC_CTL3 0x0b | ||
55 | #define R_IVC 0x0c | ||
56 | #define R_DVC 0x0d | ||
57 | #define MD_CTL3 0x0e | ||
58 | #define MD_CTL4 0x0f | ||
59 | #define PW_MGMT3 0x10 | ||
60 | #define DF_S 0x11 | ||
61 | #define FIL3_0 0x12 | ||
62 | #define FIL3_1 0x13 | ||
63 | #define FIL3_2 0x14 | ||
64 | #define FIL3_3 0x15 | ||
65 | #define EQ_0 0x16 | ||
66 | #define EQ_1 0x17 | ||
67 | #define EQ_2 0x18 | ||
68 | #define EQ_3 0x19 | ||
69 | #define EQ_4 0x1a | ||
70 | #define EQ_5 0x1b | ||
71 | #define FIL1_0 0x1c | ||
72 | #define FIL1_1 0x1d | ||
73 | #define FIL1_2 0x1e | ||
74 | #define FIL1_3 0x1f | ||
75 | #define PW_MGMT4 0x20 | ||
76 | #define MD_CTL5 0x21 | ||
77 | #define LO_MS 0x22 | ||
78 | #define HP_MS 0x23 | ||
79 | #define SPK_MS 0x24 | ||
80 | |||
81 | #define AK4642_CACHEREGNUM 0x25 | ||
82 | |||
83 | struct snd_soc_codec_device soc_codec_dev_ak4642; | ||
84 | |||
85 | /* codec private data */ | ||
86 | struct ak4642_priv { | ||
87 | struct snd_soc_codec codec; | ||
88 | unsigned int sysclk; | ||
89 | }; | ||
90 | |||
91 | static struct snd_soc_codec *ak4642_codec; | ||
92 | |||
93 | /* | ||
94 | * ak4642 register cache | ||
95 | */ | ||
96 | static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { | ||
97 | 0x0000, 0x0000, 0x0001, 0x0000, | ||
98 | 0x0002, 0x0000, 0x0000, 0x0000, | ||
99 | 0x00e1, 0x00e1, 0x0018, 0x0000, | ||
100 | 0x00e1, 0x0018, 0x0011, 0x0008, | ||
101 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
102 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
103 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
104 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
105 | 0x0000, 0x0000, 0x0000, 0x0000, | ||
106 | 0x0000, | ||
107 | }; | ||
108 | |||
109 | /* | ||
110 | * read ak4642 register cache | ||
111 | */ | ||
112 | static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec, | ||
113 | unsigned int reg) | ||
114 | { | ||
115 | u16 *cache = codec->reg_cache; | ||
116 | if (reg >= AK4642_CACHEREGNUM) | ||
117 | return -1; | ||
118 | return cache[reg]; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * write ak4642 register cache | ||
123 | */ | ||
124 | static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec, | ||
125 | u16 reg, unsigned int value) | ||
126 | { | ||
127 | u16 *cache = codec->reg_cache; | ||
128 | if (reg >= AK4642_CACHEREGNUM) | ||
129 | return; | ||
130 | |||
131 | cache[reg] = value; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * write to the AK4642 register space | ||
136 | */ | ||
137 | static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg, | ||
138 | unsigned int value) | ||
139 | { | ||
140 | u8 data[2]; | ||
141 | |||
142 | /* data is | ||
143 | * D15..D8 AK4642 register offset | ||
144 | * D7...D0 register data | ||
145 | */ | ||
146 | data[0] = reg & 0xff; | ||
147 | data[1] = value & 0xff; | ||
148 | |||
149 | if (codec->hw_write(codec->control_data, data, 2) == 2) { | ||
150 | ak4642_write_reg_cache(codec, reg, value); | ||
151 | return 0; | ||
152 | } else | ||
153 | return -EIO; | ||
154 | } | ||
155 | |||
156 | static int ak4642_sync(struct snd_soc_codec *codec) | ||
157 | { | ||
158 | u16 *cache = codec->reg_cache; | ||
159 | int i, r = 0; | ||
160 | |||
161 | for (i = 0; i < AK4642_CACHEREGNUM; i++) | ||
162 | r |= ak4642_write(codec, i, cache[i]); | ||
163 | |||
164 | return r; | ||
165 | }; | ||
166 | |||
167 | static int ak4642_dai_startup(struct snd_pcm_substream *substream, | ||
168 | struct snd_soc_dai *dai) | ||
169 | { | ||
170 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
171 | struct snd_soc_codec *codec = dai->codec; | ||
172 | |||
173 | if (is_play) { | ||
174 | /* | ||
175 | * start headphone output | ||
176 | * | ||
177 | * PLL, Master Mode | ||
178 | * Audio I/F Format :MSB justified (ADC & DAC) | ||
179 | * Sampling Frequency: 44.1kHz | ||
180 | * Digital Volume: −8dB | ||
181 | * Bass Boost Level : Middle | ||
182 | * | ||
183 | * This operation came from example code of | ||
184 | * "ASAHI KASEI AK4642" (japanese) manual p97. | ||
185 | * | ||
186 | * Example code use 0x39, 0x79 value for 0x01 address, | ||
187 | * But we need MCKO (0x02) bit now | ||
188 | */ | ||
189 | ak4642_write(codec, 0x05, 0x27); | ||
190 | ak4642_write(codec, 0x0f, 0x09); | ||
191 | ak4642_write(codec, 0x0e, 0x19); | ||
192 | ak4642_write(codec, 0x09, 0x91); | ||
193 | ak4642_write(codec, 0x0c, 0x91); | ||
194 | ak4642_write(codec, 0x0a, 0x28); | ||
195 | ak4642_write(codec, 0x0d, 0x28); | ||
196 | ak4642_write(codec, 0x00, 0x64); | ||
197 | ak4642_write(codec, 0x01, 0x3b); /* + MCKO bit */ | ||
198 | ak4642_write(codec, 0x01, 0x7b); /* + MCKO bit */ | ||
199 | } else { | ||
200 | /* | ||
201 | * start stereo input | ||
202 | * | ||
203 | * PLL Master Mode | ||
204 | * Audio I/F Format:MSB justified (ADC & DAC) | ||
205 | * Sampling Frequency:44.1kHz | ||
206 | * Pre MIC AMP:+20dB | ||
207 | * MIC Power On | ||
208 | * ALC setting:Refer to Table 35 | ||
209 | * ALC bit=“1” | ||
210 | * | ||
211 | * This operation came from example code of | ||
212 | * "ASAHI KASEI AK4642" (japanese) manual p94. | ||
213 | */ | ||
214 | ak4642_write(codec, 0x05, 0x27); | ||
215 | ak4642_write(codec, 0x02, 0x05); | ||
216 | ak4642_write(codec, 0x06, 0x3c); | ||
217 | ak4642_write(codec, 0x08, 0xe1); | ||
218 | ak4642_write(codec, 0x0b, 0x00); | ||
219 | ak4642_write(codec, 0x07, 0x21); | ||
220 | ak4642_write(codec, 0x00, 0x41); | ||
221 | ak4642_write(codec, 0x10, 0x01); | ||
222 | } | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static void ak4642_dai_shutdown(struct snd_pcm_substream *substream, | ||
228 | struct snd_soc_dai *dai) | ||
229 | { | ||
230 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
231 | struct snd_soc_codec *codec = dai->codec; | ||
232 | |||
233 | if (is_play) { | ||
234 | /* stop headphone output */ | ||
235 | ak4642_write(codec, 0x01, 0x3b); | ||
236 | ak4642_write(codec, 0x01, 0x0b); | ||
237 | ak4642_write(codec, 0x00, 0x40); | ||
238 | ak4642_write(codec, 0x0e, 0x11); | ||
239 | ak4642_write(codec, 0x0f, 0x08); | ||
240 | } else { | ||
241 | /* stop stereo input */ | ||
242 | ak4642_write(codec, 0x00, 0x40); | ||
243 | ak4642_write(codec, 0x10, 0x00); | ||
244 | ak4642_write(codec, 0x07, 0x01); | ||
245 | } | ||
246 | } | ||
247 | |||
248 | static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, | ||
249 | int clk_id, unsigned int freq, int dir) | ||
250 | { | ||
251 | struct snd_soc_codec *codec = codec_dai->codec; | ||
252 | struct ak4642_priv *ak4642 = codec->private_data; | ||
253 | |||
254 | ak4642->sysclk = freq; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static struct snd_soc_dai_ops ak4642_dai_ops = { | ||
259 | .startup = ak4642_dai_startup, | ||
260 | .shutdown = ak4642_dai_shutdown, | ||
261 | .set_sysclk = ak4642_dai_set_sysclk, | ||
262 | }; | ||
263 | |||
264 | struct snd_soc_dai ak4642_dai = { | ||
265 | .name = "AK4642", | ||
266 | .playback = { | ||
267 | .stream_name = "Playback", | ||
268 | .channels_min = 1, | ||
269 | .channels_max = 2, | ||
270 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
271 | .formats = SNDRV_PCM_FMTBIT_S16_LE }, | ||
272 | .capture = { | ||
273 | .stream_name = "Capture", | ||
274 | .channels_min = 1, | ||
275 | .channels_max = 2, | ||
276 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
277 | .formats = SNDRV_PCM_FMTBIT_S16_LE }, | ||
278 | .ops = &ak4642_dai_ops, | ||
279 | }; | ||
280 | EXPORT_SYMBOL_GPL(ak4642_dai); | ||
281 | |||
282 | static int ak4642_resume(struct platform_device *pdev) | ||
283 | { | ||
284 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
285 | struct snd_soc_codec *codec = socdev->card->codec; | ||
286 | |||
287 | ak4642_sync(codec); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | /* | ||
292 | * initialise the AK4642 driver | ||
293 | * register the mixer and dsp interfaces with the kernel | ||
294 | */ | ||
295 | static int ak4642_init(struct ak4642_priv *ak4642) | ||
296 | { | ||
297 | struct snd_soc_codec *codec = &ak4642->codec; | ||
298 | int ret = 0; | ||
299 | |||
300 | if (ak4642_codec) { | ||
301 | dev_err(codec->dev, "Another ak4642 is registered\n"); | ||
302 | return -EINVAL; | ||
303 | } | ||
304 | |||
305 | mutex_init(&codec->mutex); | ||
306 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
307 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
308 | |||
309 | codec->private_data = ak4642; | ||
310 | codec->name = "AK4642"; | ||
311 | codec->owner = THIS_MODULE; | ||
312 | codec->read = ak4642_read_reg_cache; | ||
313 | codec->write = ak4642_write; | ||
314 | codec->dai = &ak4642_dai; | ||
315 | codec->num_dai = 1; | ||
316 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
317 | codec->reg_cache_size = ARRAY_SIZE(ak4642_reg); | ||
318 | codec->reg_cache = kmemdup(ak4642_reg, | ||
319 | sizeof(ak4642_reg), GFP_KERNEL); | ||
320 | |||
321 | if (!codec->reg_cache) | ||
322 | return -ENOMEM; | ||
323 | |||
324 | ak4642_dai.dev = codec->dev; | ||
325 | ak4642_codec = codec; | ||
326 | |||
327 | ret = snd_soc_register_codec(codec); | ||
328 | if (ret) { | ||
329 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
330 | goto reg_cache_err; | ||
331 | } | ||
332 | |||
333 | ret = snd_soc_register_dai(&ak4642_dai); | ||
334 | if (ret) { | ||
335 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
336 | snd_soc_unregister_codec(codec); | ||
337 | goto reg_cache_err; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * clock setting | ||
342 | * | ||
343 | * Audio I/F Format: MSB justified (ADC & DAC) | ||
344 | * BICK frequency at Master Mode: 64fs | ||
345 | * Input Master Clock Select at PLL Mode: 11.2896MHz | ||
346 | * MCKO: Enable | ||
347 | * Sampling Frequency: 44.1kHz | ||
348 | * | ||
349 | * This operation came from example code of | ||
350 | * "ASAHI KASEI AK4642" (japanese) manual p89. | ||
351 | * | ||
352 | * please fix-me | ||
353 | */ | ||
354 | ak4642_write(codec, 0x01, 0x08); | ||
355 | ak4642_write(codec, 0x04, 0x4a); | ||
356 | ak4642_write(codec, 0x05, 0x27); | ||
357 | ak4642_write(codec, 0x00, 0x40); | ||
358 | ak4642_write(codec, 0x01, 0x0b); | ||
359 | |||
360 | return ret; | ||
361 | |||
362 | reg_cache_err: | ||
363 | kfree(codec->reg_cache); | ||
364 | codec->reg_cache = NULL; | ||
365 | |||
366 | return ret; | ||
367 | } | ||
368 | |||
369 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
370 | static int ak4642_i2c_probe(struct i2c_client *i2c, | ||
371 | const struct i2c_device_id *id) | ||
372 | { | ||
373 | struct ak4642_priv *ak4642; | ||
374 | struct snd_soc_codec *codec; | ||
375 | int ret; | ||
376 | |||
377 | ak4642 = kzalloc(sizeof(struct ak4642_priv), GFP_KERNEL); | ||
378 | if (!ak4642) | ||
379 | return -ENOMEM; | ||
380 | |||
381 | codec = &ak4642->codec; | ||
382 | codec->dev = &i2c->dev; | ||
383 | |||
384 | i2c_set_clientdata(i2c, ak4642); | ||
385 | codec->control_data = i2c; | ||
386 | |||
387 | ret = ak4642_init(ak4642); | ||
388 | if (ret < 0) | ||
389 | printk(KERN_ERR "failed to initialise AK4642\n"); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | static int ak4642_i2c_remove(struct i2c_client *client) | ||
395 | { | ||
396 | struct ak4642_priv *ak4642 = i2c_get_clientdata(client); | ||
397 | |||
398 | snd_soc_unregister_dai(&ak4642_dai); | ||
399 | snd_soc_unregister_codec(&ak4642->codec); | ||
400 | kfree(ak4642->codec.reg_cache); | ||
401 | kfree(ak4642); | ||
402 | ak4642_codec = NULL; | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static const struct i2c_device_id ak4642_i2c_id[] = { | ||
408 | { "ak4642", 0 }, | ||
409 | { "ak4643", 0 }, | ||
410 | { } | ||
411 | }; | ||
412 | MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); | ||
413 | |||
414 | static struct i2c_driver ak4642_i2c_driver = { | ||
415 | .driver = { | ||
416 | .name = "AK4642 I2C Codec", | ||
417 | .owner = THIS_MODULE, | ||
418 | }, | ||
419 | .probe = ak4642_i2c_probe, | ||
420 | .remove = ak4642_i2c_remove, | ||
421 | .id_table = ak4642_i2c_id, | ||
422 | }; | ||
423 | |||
424 | #endif | ||
425 | |||
426 | static int ak4642_probe(struct platform_device *pdev) | ||
427 | { | ||
428 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
429 | int ret; | ||
430 | |||
431 | if (!ak4642_codec) { | ||
432 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
433 | return -ENODEV; | ||
434 | } | ||
435 | |||
436 | socdev->card->codec = ak4642_codec; | ||
437 | |||
438 | /* register pcms */ | ||
439 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
440 | if (ret < 0) { | ||
441 | printk(KERN_ERR "ak4642: failed to create pcms\n"); | ||
442 | goto pcm_err; | ||
443 | } | ||
444 | |||
445 | ret = snd_soc_init_card(socdev); | ||
446 | if (ret < 0) { | ||
447 | printk(KERN_ERR "ak4642: failed to register card\n"); | ||
448 | goto card_err; | ||
449 | } | ||
450 | |||
451 | dev_info(&pdev->dev, "AK4642 Audio Codec %s", AK4642_VERSION); | ||
452 | return ret; | ||
453 | |||
454 | card_err: | ||
455 | snd_soc_free_pcms(socdev); | ||
456 | snd_soc_dapm_free(socdev); | ||
457 | pcm_err: | ||
458 | return ret; | ||
459 | |||
460 | } | ||
461 | |||
462 | /* power down chip */ | ||
463 | static int ak4642_remove(struct platform_device *pdev) | ||
464 | { | ||
465 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
466 | |||
467 | snd_soc_free_pcms(socdev); | ||
468 | snd_soc_dapm_free(socdev); | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | struct snd_soc_codec_device soc_codec_dev_ak4642 = { | ||
474 | .probe = ak4642_probe, | ||
475 | .remove = ak4642_remove, | ||
476 | .resume = ak4642_resume, | ||
477 | }; | ||
478 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4642); | ||
479 | |||
480 | static int __init ak4642_modinit(void) | ||
481 | { | ||
482 | int ret; | ||
483 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
484 | ret = i2c_add_driver(&ak4642_i2c_driver); | ||
485 | #endif | ||
486 | return ret; | ||
487 | |||
488 | } | ||
489 | module_init(ak4642_modinit); | ||
490 | |||
491 | static void __exit ak4642_exit(void) | ||
492 | { | ||
493 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
494 | i2c_del_driver(&ak4642_i2c_driver); | ||
495 | #endif | ||
496 | |||
497 | } | ||
498 | module_exit(ak4642_exit); | ||
499 | |||
500 | MODULE_DESCRIPTION("Soc AK4642 driver"); | ||
501 | MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); | ||
502 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4642.h b/sound/soc/codecs/ak4642.h new file mode 100644 index 000000000000..e476833d314e --- /dev/null +++ b/sound/soc/codecs/ak4642.h | |||
@@ -0,0 +1,20 @@ | |||
1 | /* | ||
2 | * ak4642.h -- AK4642 Soc Audio driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * Based on ak4535.c | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #ifndef _AK4642_H | ||
15 | #define _AK4642_H | ||
16 | |||
17 | extern struct snd_soc_dai ak4642_dai; | ||
18 | extern struct snd_soc_codec_device soc_codec_dev_ak4642; | ||
19 | |||
20 | #endif | ||
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c new file mode 100644 index 000000000000..b61214d1c5de --- /dev/null +++ b/sound/soc/codecs/ak4671.c | |||
@@ -0,0 +1,825 @@ | |||
1 | /* | ||
2 | * ak4671.c -- audio driver for AK4671 | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/delay.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | #include <sound/initval.h> | ||
21 | #include <sound/tlv.h> | ||
22 | |||
23 | #include "ak4671.h" | ||
24 | |||
25 | static struct snd_soc_codec *ak4671_codec; | ||
26 | |||
27 | /* codec private data */ | ||
28 | struct ak4671_priv { | ||
29 | struct snd_soc_codec codec; | ||
30 | u8 reg_cache[AK4671_CACHEREGNUM]; | ||
31 | }; | ||
32 | |||
33 | /* ak4671 register cache & default register settings */ | ||
34 | static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { | ||
35 | 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ | ||
36 | 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ | ||
37 | 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ | ||
38 | 0x02, /* AK4671_FORMAT_SELECT (0x03) */ | ||
39 | 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ | ||
40 | 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ | ||
41 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ | ||
42 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ | ||
43 | 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ | ||
44 | 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ | ||
45 | 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ | ||
46 | 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ | ||
47 | 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ | ||
48 | 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ | ||
49 | 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ | ||
50 | 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ | ||
51 | 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ | ||
52 | 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ | ||
53 | 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ | ||
54 | 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ | ||
55 | 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ | ||
56 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ | ||
57 | 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ | ||
58 | 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ | ||
59 | 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ | ||
60 | 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ | ||
61 | 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ | ||
62 | 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ | ||
63 | 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ | ||
64 | 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ | ||
65 | 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ | ||
66 | 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ | ||
67 | 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ | ||
68 | 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ | ||
69 | 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ | ||
70 | 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ | ||
71 | 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ | ||
72 | 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ | ||
73 | 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ | ||
74 | 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ | ||
75 | 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ | ||
76 | 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ | ||
77 | 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ | ||
78 | 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ | ||
79 | 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ | ||
80 | 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ | ||
81 | 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ | ||
82 | 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ | ||
83 | 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ | ||
84 | 0x00, /* this register not used */ | ||
85 | 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ | ||
86 | 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ | ||
87 | 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ | ||
88 | 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ | ||
89 | 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ | ||
90 | 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ | ||
91 | 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ | ||
92 | 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ | ||
93 | 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ | ||
94 | 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ | ||
95 | 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ | ||
96 | 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ | ||
97 | 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ | ||
98 | 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ | ||
99 | 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ | ||
100 | 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ | ||
101 | 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ | ||
102 | 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ | ||
103 | 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ | ||
104 | 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ | ||
105 | 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ | ||
106 | 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ | ||
107 | 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ | ||
108 | 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ | ||
109 | 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ | ||
110 | 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ | ||
111 | 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ | ||
112 | 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ | ||
113 | 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ | ||
114 | 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ | ||
115 | 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ | ||
116 | 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ | ||
117 | 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ | ||
118 | 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ | ||
119 | 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ | ||
120 | 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ | ||
121 | 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ | ||
122 | 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ | ||
123 | 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ | ||
124 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ | ||
125 | 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ | ||
126 | }; | ||
127 | |||
128 | /* | ||
129 | * LOUT1/ROUT1 output volume control: | ||
130 | * from -24 to 6 dB in 6 dB steps (mute instead of -30 dB) | ||
131 | */ | ||
132 | static DECLARE_TLV_DB_SCALE(out1_tlv, -3000, 600, 1); | ||
133 | |||
134 | /* | ||
135 | * LOUT2/ROUT2 output volume control: | ||
136 | * from -33 to 6 dB in 3 dB steps (mute instead of -33 dB) | ||
137 | */ | ||
138 | static DECLARE_TLV_DB_SCALE(out2_tlv, -3300, 300, 1); | ||
139 | |||
140 | /* | ||
141 | * LOUT3/ROUT3 output volume control: | ||
142 | * from -6 to 3 dB in 3 dB steps | ||
143 | */ | ||
144 | static DECLARE_TLV_DB_SCALE(out3_tlv, -600, 300, 0); | ||
145 | |||
146 | /* | ||
147 | * Mic amp gain control: | ||
148 | * from -15 to 30 dB in 3 dB steps | ||
149 | * REVISIT: The actual min value(0x01) is -12 dB and the reg value 0x00 is not | ||
150 | * available | ||
151 | */ | ||
152 | static DECLARE_TLV_DB_SCALE(mic_amp_tlv, -1500, 300, 0); | ||
153 | |||
154 | static const struct snd_kcontrol_new ak4671_snd_controls[] = { | ||
155 | /* Common playback gain controls */ | ||
156 | SOC_SINGLE_TLV("Line Output1 Playback Volume", | ||
157 | AK4671_OUTPUT_VOLUME_CONTROL, 0, 0x6, 0, out1_tlv), | ||
158 | SOC_SINGLE_TLV("Headphone Output2 Playback Volume", | ||
159 | AK4671_OUTPUT_VOLUME_CONTROL, 4, 0xd, 0, out2_tlv), | ||
160 | SOC_SINGLE_TLV("Line Output3 Playback Volume", | ||
161 | AK4671_LOUT3_POWER_MANAGERMENT, 6, 0x3, 0, out3_tlv), | ||
162 | |||
163 | /* Common capture gain controls */ | ||
164 | SOC_DOUBLE_TLV("Mic Amp Capture Volume", | ||
165 | AK4671_MIC_AMP_GAIN, 0, 4, 0xf, 0, mic_amp_tlv), | ||
166 | }; | ||
167 | |||
168 | /* event handlers */ | ||
169 | static int ak4671_out2_event(struct snd_soc_dapm_widget *w, | ||
170 | struct snd_kcontrol *kcontrol, int event) | ||
171 | { | ||
172 | struct snd_soc_codec *codec = w->codec; | ||
173 | u8 reg; | ||
174 | |||
175 | switch (event) { | ||
176 | case SND_SOC_DAPM_POST_PMU: | ||
177 | reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); | ||
178 | reg |= AK4671_MUTEN; | ||
179 | snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); | ||
180 | break; | ||
181 | case SND_SOC_DAPM_PRE_PMD: | ||
182 | reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); | ||
183 | reg &= ~AK4671_MUTEN; | ||
184 | snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg); | ||
185 | break; | ||
186 | } | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | /* Output Mixers */ | ||
192 | static const struct snd_kcontrol_new ak4671_lout1_mixer_controls[] = { | ||
193 | SOC_DAPM_SINGLE("DACL", AK4671_LOUT1_SIGNAL_SELECT, 0, 1, 0), | ||
194 | SOC_DAPM_SINGLE("LINL1", AK4671_LOUT1_SIGNAL_SELECT, 1, 1, 0), | ||
195 | SOC_DAPM_SINGLE("LINL2", AK4671_LOUT1_SIGNAL_SELECT, 2, 1, 0), | ||
196 | SOC_DAPM_SINGLE("LINL3", AK4671_LOUT1_SIGNAL_SELECT, 3, 1, 0), | ||
197 | SOC_DAPM_SINGLE("LINL4", AK4671_LOUT1_SIGNAL_SELECT, 4, 1, 0), | ||
198 | SOC_DAPM_SINGLE("LOOPL", AK4671_LOUT1_SIGNAL_SELECT, 5, 1, 0), | ||
199 | }; | ||
200 | |||
201 | static const struct snd_kcontrol_new ak4671_rout1_mixer_controls[] = { | ||
202 | SOC_DAPM_SINGLE("DACR", AK4671_ROUT1_SIGNAL_SELECT, 0, 1, 0), | ||
203 | SOC_DAPM_SINGLE("RINR1", AK4671_ROUT1_SIGNAL_SELECT, 1, 1, 0), | ||
204 | SOC_DAPM_SINGLE("RINR2", AK4671_ROUT1_SIGNAL_SELECT, 2, 1, 0), | ||
205 | SOC_DAPM_SINGLE("RINR3", AK4671_ROUT1_SIGNAL_SELECT, 3, 1, 0), | ||
206 | SOC_DAPM_SINGLE("RINR4", AK4671_ROUT1_SIGNAL_SELECT, 4, 1, 0), | ||
207 | SOC_DAPM_SINGLE("LOOPR", AK4671_ROUT1_SIGNAL_SELECT, 5, 1, 0), | ||
208 | }; | ||
209 | |||
210 | static const struct snd_kcontrol_new ak4671_lout2_mixer_controls[] = { | ||
211 | SOC_DAPM_SINGLE("DACHL", AK4671_LOUT2_SIGNAL_SELECT, 0, 1, 0), | ||
212 | SOC_DAPM_SINGLE("LINH1", AK4671_LOUT2_SIGNAL_SELECT, 1, 1, 0), | ||
213 | SOC_DAPM_SINGLE("LINH2", AK4671_LOUT2_SIGNAL_SELECT, 2, 1, 0), | ||
214 | SOC_DAPM_SINGLE("LINH3", AK4671_LOUT2_SIGNAL_SELECT, 3, 1, 0), | ||
215 | SOC_DAPM_SINGLE("LINH4", AK4671_LOUT2_SIGNAL_SELECT, 4, 1, 0), | ||
216 | SOC_DAPM_SINGLE("LOOPHL", AK4671_LOUT2_SIGNAL_SELECT, 5, 1, 0), | ||
217 | }; | ||
218 | |||
219 | static const struct snd_kcontrol_new ak4671_rout2_mixer_controls[] = { | ||
220 | SOC_DAPM_SINGLE("DACHR", AK4671_ROUT2_SIGNAL_SELECT, 0, 1, 0), | ||
221 | SOC_DAPM_SINGLE("RINH1", AK4671_ROUT2_SIGNAL_SELECT, 1, 1, 0), | ||
222 | SOC_DAPM_SINGLE("RINH2", AK4671_ROUT2_SIGNAL_SELECT, 2, 1, 0), | ||
223 | SOC_DAPM_SINGLE("RINH3", AK4671_ROUT2_SIGNAL_SELECT, 3, 1, 0), | ||
224 | SOC_DAPM_SINGLE("RINH4", AK4671_ROUT2_SIGNAL_SELECT, 4, 1, 0), | ||
225 | SOC_DAPM_SINGLE("LOOPHR", AK4671_ROUT2_SIGNAL_SELECT, 5, 1, 0), | ||
226 | }; | ||
227 | |||
228 | static const struct snd_kcontrol_new ak4671_lout3_mixer_controls[] = { | ||
229 | SOC_DAPM_SINGLE("DACSL", AK4671_LOUT3_SIGNAL_SELECT, 0, 1, 0), | ||
230 | SOC_DAPM_SINGLE("LINS1", AK4671_LOUT3_SIGNAL_SELECT, 1, 1, 0), | ||
231 | SOC_DAPM_SINGLE("LINS2", AK4671_LOUT3_SIGNAL_SELECT, 2, 1, 0), | ||
232 | SOC_DAPM_SINGLE("LINS3", AK4671_LOUT3_SIGNAL_SELECT, 3, 1, 0), | ||
233 | SOC_DAPM_SINGLE("LINS4", AK4671_LOUT3_SIGNAL_SELECT, 4, 1, 0), | ||
234 | SOC_DAPM_SINGLE("LOOPSL", AK4671_LOUT3_SIGNAL_SELECT, 5, 1, 0), | ||
235 | }; | ||
236 | |||
237 | static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { | ||
238 | SOC_DAPM_SINGLE("DACSR", AK4671_ROUT3_SIGNAL_SELECT, 0, 1, 0), | ||
239 | SOC_DAPM_SINGLE("RINS1", AK4671_ROUT3_SIGNAL_SELECT, 1, 1, 0), | ||
240 | SOC_DAPM_SINGLE("RINS2", AK4671_ROUT3_SIGNAL_SELECT, 2, 1, 0), | ||
241 | SOC_DAPM_SINGLE("RINS3", AK4671_ROUT3_SIGNAL_SELECT, 3, 1, 0), | ||
242 | SOC_DAPM_SINGLE("RINS4", AK4671_ROUT3_SIGNAL_SELECT, 4, 1, 0), | ||
243 | SOC_DAPM_SINGLE("LOOPSR", AK4671_ROUT3_SIGNAL_SELECT, 5, 1, 0), | ||
244 | }; | ||
245 | |||
246 | /* Input MUXs */ | ||
247 | static const char *ak4671_lin_mux_texts[] = | ||
248 | {"LIN1", "LIN2", "LIN3", "LIN4"}; | ||
249 | static const struct soc_enum ak4671_lin_mux_enum = | ||
250 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, | ||
251 | ARRAY_SIZE(ak4671_lin_mux_texts), | ||
252 | ak4671_lin_mux_texts); | ||
253 | static const struct snd_kcontrol_new ak4671_lin_mux_control = | ||
254 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); | ||
255 | |||
256 | static const char *ak4671_rin_mux_texts[] = | ||
257 | {"RIN1", "RIN2", "RIN3", "RIN4"}; | ||
258 | static const struct soc_enum ak4671_rin_mux_enum = | ||
259 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, | ||
260 | ARRAY_SIZE(ak4671_rin_mux_texts), | ||
261 | ak4671_rin_mux_texts); | ||
262 | static const struct snd_kcontrol_new ak4671_rin_mux_control = | ||
263 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); | ||
264 | |||
265 | static const struct snd_soc_dapm_widget ak4671_dapm_widgets[] = { | ||
266 | /* Inputs */ | ||
267 | SND_SOC_DAPM_INPUT("LIN1"), | ||
268 | SND_SOC_DAPM_INPUT("RIN1"), | ||
269 | SND_SOC_DAPM_INPUT("LIN2"), | ||
270 | SND_SOC_DAPM_INPUT("RIN2"), | ||
271 | SND_SOC_DAPM_INPUT("LIN3"), | ||
272 | SND_SOC_DAPM_INPUT("RIN3"), | ||
273 | SND_SOC_DAPM_INPUT("LIN4"), | ||
274 | SND_SOC_DAPM_INPUT("RIN4"), | ||
275 | |||
276 | /* Outputs */ | ||
277 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
278 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
279 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
280 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
281 | SND_SOC_DAPM_OUTPUT("LOUT3"), | ||
282 | SND_SOC_DAPM_OUTPUT("ROUT3"), | ||
283 | |||
284 | /* DAC */ | ||
285 | SND_SOC_DAPM_DAC("DAC Left", "Left HiFi Playback", | ||
286 | AK4671_AD_DA_POWER_MANAGEMENT, 6, 0), | ||
287 | SND_SOC_DAPM_DAC("DAC Right", "Right HiFi Playback", | ||
288 | AK4671_AD_DA_POWER_MANAGEMENT, 7, 0), | ||
289 | |||
290 | /* ADC */ | ||
291 | SND_SOC_DAPM_ADC("ADC Left", "Left HiFi Capture", | ||
292 | AK4671_AD_DA_POWER_MANAGEMENT, 4, 0), | ||
293 | SND_SOC_DAPM_ADC("ADC Right", "Right HiFi Capture", | ||
294 | AK4671_AD_DA_POWER_MANAGEMENT, 5, 0), | ||
295 | |||
296 | /* PGA */ | ||
297 | SND_SOC_DAPM_PGA("LOUT2 Mix Amp", | ||
298 | AK4671_LOUT2_POWER_MANAGERMENT, 5, 0, NULL, 0), | ||
299 | SND_SOC_DAPM_PGA("ROUT2 Mix Amp", | ||
300 | AK4671_LOUT2_POWER_MANAGERMENT, 6, 0, NULL, 0), | ||
301 | |||
302 | SND_SOC_DAPM_PGA("LIN1 Mixing Circuit", | ||
303 | AK4671_MIXING_POWER_MANAGEMENT1, 0, 0, NULL, 0), | ||
304 | SND_SOC_DAPM_PGA("RIN1 Mixing Circuit", | ||
305 | AK4671_MIXING_POWER_MANAGEMENT1, 1, 0, NULL, 0), | ||
306 | SND_SOC_DAPM_PGA("LIN2 Mixing Circuit", | ||
307 | AK4671_MIXING_POWER_MANAGEMENT1, 2, 0, NULL, 0), | ||
308 | SND_SOC_DAPM_PGA("RIN2 Mixing Circuit", | ||
309 | AK4671_MIXING_POWER_MANAGEMENT1, 3, 0, NULL, 0), | ||
310 | SND_SOC_DAPM_PGA("LIN3 Mixing Circuit", | ||
311 | AK4671_MIXING_POWER_MANAGEMENT1, 4, 0, NULL, 0), | ||
312 | SND_SOC_DAPM_PGA("RIN3 Mixing Circuit", | ||
313 | AK4671_MIXING_POWER_MANAGEMENT1, 5, 0, NULL, 0), | ||
314 | SND_SOC_DAPM_PGA("LIN4 Mixing Circuit", | ||
315 | AK4671_MIXING_POWER_MANAGEMENT1, 6, 0, NULL, 0), | ||
316 | SND_SOC_DAPM_PGA("RIN4 Mixing Circuit", | ||
317 | AK4671_MIXING_POWER_MANAGEMENT1, 7, 0, NULL, 0), | ||
318 | |||
319 | /* Output Mixers */ | ||
320 | SND_SOC_DAPM_MIXER("LOUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 0, 0, | ||
321 | &ak4671_lout1_mixer_controls[0], | ||
322 | ARRAY_SIZE(ak4671_lout1_mixer_controls)), | ||
323 | SND_SOC_DAPM_MIXER("ROUT1 Mixer", AK4671_LOUT1_POWER_MANAGERMENT, 1, 0, | ||
324 | &ak4671_rout1_mixer_controls[0], | ||
325 | ARRAY_SIZE(ak4671_rout1_mixer_controls)), | ||
326 | SND_SOC_DAPM_MIXER_E("LOUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, | ||
327 | 0, 0, &ak4671_lout2_mixer_controls[0], | ||
328 | ARRAY_SIZE(ak4671_lout2_mixer_controls), | ||
329 | ak4671_out2_event, | ||
330 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), | ||
331 | SND_SOC_DAPM_MIXER_E("ROUT2 Mixer", AK4671_LOUT2_POWER_MANAGERMENT, | ||
332 | 1, 0, &ak4671_rout2_mixer_controls[0], | ||
333 | ARRAY_SIZE(ak4671_rout2_mixer_controls), | ||
334 | ak4671_out2_event, | ||
335 | SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_PRE_PMD), | ||
336 | SND_SOC_DAPM_MIXER("LOUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 0, 0, | ||
337 | &ak4671_lout3_mixer_controls[0], | ||
338 | ARRAY_SIZE(ak4671_lout3_mixer_controls)), | ||
339 | SND_SOC_DAPM_MIXER("ROUT3 Mixer", AK4671_LOUT3_POWER_MANAGERMENT, 1, 0, | ||
340 | &ak4671_rout3_mixer_controls[0], | ||
341 | ARRAY_SIZE(ak4671_rout3_mixer_controls)), | ||
342 | |||
343 | /* Input MUXs */ | ||
344 | SND_SOC_DAPM_MUX("LIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 2, 0, | ||
345 | &ak4671_lin_mux_control), | ||
346 | SND_SOC_DAPM_MUX("RIN MUX", AK4671_AD_DA_POWER_MANAGEMENT, 3, 0, | ||
347 | &ak4671_rin_mux_control), | ||
348 | |||
349 | /* Mic Power */ | ||
350 | SND_SOC_DAPM_MICBIAS("Mic Bias", AK4671_AD_DA_POWER_MANAGEMENT, 1, 0), | ||
351 | |||
352 | /* Supply */ | ||
353 | SND_SOC_DAPM_SUPPLY("PMPLL", AK4671_PLL_MODE_SELECT1, 0, 0, NULL, 0), | ||
354 | }; | ||
355 | |||
356 | static const struct snd_soc_dapm_route intercon[] = { | ||
357 | {"DAC Left", "NULL", "PMPLL"}, | ||
358 | {"DAC Right", "NULL", "PMPLL"}, | ||
359 | {"ADC Left", "NULL", "PMPLL"}, | ||
360 | {"ADC Right", "NULL", "PMPLL"}, | ||
361 | |||
362 | /* Outputs */ | ||
363 | {"LOUT1", "NULL", "LOUT1 Mixer"}, | ||
364 | {"ROUT1", "NULL", "ROUT1 Mixer"}, | ||
365 | {"LOUT2", "NULL", "LOUT2 Mix Amp"}, | ||
366 | {"ROUT2", "NULL", "ROUT2 Mix Amp"}, | ||
367 | {"LOUT3", "NULL", "LOUT3 Mixer"}, | ||
368 | {"ROUT3", "NULL", "ROUT3 Mixer"}, | ||
369 | |||
370 | {"LOUT1 Mixer", "DACL", "DAC Left"}, | ||
371 | {"ROUT1 Mixer", "DACR", "DAC Right"}, | ||
372 | {"LOUT2 Mixer", "DACHL", "DAC Left"}, | ||
373 | {"ROUT2 Mixer", "DACHR", "DAC Right"}, | ||
374 | {"LOUT2 Mix Amp", "NULL", "LOUT2 Mixer"}, | ||
375 | {"ROUT2 Mix Amp", "NULL", "ROUT2 Mixer"}, | ||
376 | {"LOUT3 Mixer", "DACSL", "DAC Left"}, | ||
377 | {"ROUT3 Mixer", "DACSR", "DAC Right"}, | ||
378 | |||
379 | /* Inputs */ | ||
380 | {"LIN MUX", "LIN1", "LIN1"}, | ||
381 | {"LIN MUX", "LIN2", "LIN2"}, | ||
382 | {"LIN MUX", "LIN3", "LIN3"}, | ||
383 | {"LIN MUX", "LIN4", "LIN4"}, | ||
384 | |||
385 | {"RIN MUX", "RIN1", "RIN1"}, | ||
386 | {"RIN MUX", "RIN2", "RIN2"}, | ||
387 | {"RIN MUX", "RIN3", "RIN3"}, | ||
388 | {"RIN MUX", "RIN4", "RIN4"}, | ||
389 | |||
390 | {"LIN1", NULL, "Mic Bias"}, | ||
391 | {"RIN1", NULL, "Mic Bias"}, | ||
392 | {"LIN2", NULL, "Mic Bias"}, | ||
393 | {"RIN2", NULL, "Mic Bias"}, | ||
394 | |||
395 | {"ADC Left", "NULL", "LIN MUX"}, | ||
396 | {"ADC Right", "NULL", "RIN MUX"}, | ||
397 | |||
398 | /* Analog Loops */ | ||
399 | {"LIN1 Mixing Circuit", "NULL", "LIN1"}, | ||
400 | {"RIN1 Mixing Circuit", "NULL", "RIN1"}, | ||
401 | {"LIN2 Mixing Circuit", "NULL", "LIN2"}, | ||
402 | {"RIN2 Mixing Circuit", "NULL", "RIN2"}, | ||
403 | {"LIN3 Mixing Circuit", "NULL", "LIN3"}, | ||
404 | {"RIN3 Mixing Circuit", "NULL", "RIN3"}, | ||
405 | {"LIN4 Mixing Circuit", "NULL", "LIN4"}, | ||
406 | {"RIN4 Mixing Circuit", "NULL", "RIN4"}, | ||
407 | |||
408 | {"LOUT1 Mixer", "LINL1", "LIN1 Mixing Circuit"}, | ||
409 | {"ROUT1 Mixer", "RINR1", "RIN1 Mixing Circuit"}, | ||
410 | {"LOUT2 Mixer", "LINH1", "LIN1 Mixing Circuit"}, | ||
411 | {"ROUT2 Mixer", "RINH1", "RIN1 Mixing Circuit"}, | ||
412 | {"LOUT3 Mixer", "LINS1", "LIN1 Mixing Circuit"}, | ||
413 | {"ROUT3 Mixer", "RINS1", "RIN1 Mixing Circuit"}, | ||
414 | |||
415 | {"LOUT1 Mixer", "LINL2", "LIN2 Mixing Circuit"}, | ||
416 | {"ROUT1 Mixer", "RINR2", "RIN2 Mixing Circuit"}, | ||
417 | {"LOUT2 Mixer", "LINH2", "LIN2 Mixing Circuit"}, | ||
418 | {"ROUT2 Mixer", "RINH2", "RIN2 Mixing Circuit"}, | ||
419 | {"LOUT3 Mixer", "LINS2", "LIN2 Mixing Circuit"}, | ||
420 | {"ROUT3 Mixer", "RINS2", "RIN2 Mixing Circuit"}, | ||
421 | |||
422 | {"LOUT1 Mixer", "LINL3", "LIN3 Mixing Circuit"}, | ||
423 | {"ROUT1 Mixer", "RINR3", "RIN3 Mixing Circuit"}, | ||
424 | {"LOUT2 Mixer", "LINH3", "LIN3 Mixing Circuit"}, | ||
425 | {"ROUT2 Mixer", "RINH3", "RIN3 Mixing Circuit"}, | ||
426 | {"LOUT3 Mixer", "LINS3", "LIN3 Mixing Circuit"}, | ||
427 | {"ROUT3 Mixer", "RINS3", "RIN3 Mixing Circuit"}, | ||
428 | |||
429 | {"LOUT1 Mixer", "LINL4", "LIN4 Mixing Circuit"}, | ||
430 | {"ROUT1 Mixer", "RINR4", "RIN4 Mixing Circuit"}, | ||
431 | {"LOUT2 Mixer", "LINH4", "LIN4 Mixing Circuit"}, | ||
432 | {"ROUT2 Mixer", "RINH4", "RIN4 Mixing Circuit"}, | ||
433 | {"LOUT3 Mixer", "LINS4", "LIN4 Mixing Circuit"}, | ||
434 | {"ROUT3 Mixer", "RINS4", "RIN4 Mixing Circuit"}, | ||
435 | }; | ||
436 | |||
437 | static int ak4671_add_widgets(struct snd_soc_codec *codec) | ||
438 | { | ||
439 | snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets, | ||
440 | ARRAY_SIZE(ak4671_dapm_widgets)); | ||
441 | |||
442 | snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon)); | ||
443 | |||
444 | snd_soc_dapm_new_widgets(codec); | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | static int ak4671_hw_params(struct snd_pcm_substream *substream, | ||
449 | struct snd_pcm_hw_params *params, | ||
450 | struct snd_soc_dai *dai) | ||
451 | { | ||
452 | struct snd_soc_codec *codec = dai->codec; | ||
453 | u8 fs; | ||
454 | |||
455 | fs = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); | ||
456 | fs &= ~AK4671_FS; | ||
457 | |||
458 | switch (params_rate(params)) { | ||
459 | case 8000: | ||
460 | fs |= AK4671_FS_8KHZ; | ||
461 | break; | ||
462 | case 12000: | ||
463 | fs |= AK4671_FS_12KHZ; | ||
464 | break; | ||
465 | case 16000: | ||
466 | fs |= AK4671_FS_16KHZ; | ||
467 | break; | ||
468 | case 24000: | ||
469 | fs |= AK4671_FS_24KHZ; | ||
470 | break; | ||
471 | case 11025: | ||
472 | fs |= AK4671_FS_11_025KHZ; | ||
473 | break; | ||
474 | case 22050: | ||
475 | fs |= AK4671_FS_22_05KHZ; | ||
476 | break; | ||
477 | case 32000: | ||
478 | fs |= AK4671_FS_32KHZ; | ||
479 | break; | ||
480 | case 44100: | ||
481 | fs |= AK4671_FS_44_1KHZ; | ||
482 | break; | ||
483 | case 48000: | ||
484 | fs |= AK4671_FS_48KHZ; | ||
485 | break; | ||
486 | default: | ||
487 | return -EINVAL; | ||
488 | } | ||
489 | |||
490 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, fs); | ||
491 | |||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | static int ak4671_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
496 | unsigned int freq, int dir) | ||
497 | { | ||
498 | struct snd_soc_codec *codec = dai->codec; | ||
499 | u8 pll; | ||
500 | |||
501 | pll = snd_soc_read(codec, AK4671_PLL_MODE_SELECT0); | ||
502 | pll &= ~AK4671_PLL; | ||
503 | |||
504 | switch (freq) { | ||
505 | case 11289600: | ||
506 | pll |= AK4671_PLL_11_2896MHZ; | ||
507 | break; | ||
508 | case 12000000: | ||
509 | pll |= AK4671_PLL_12MHZ; | ||
510 | break; | ||
511 | case 12288000: | ||
512 | pll |= AK4671_PLL_12_288MHZ; | ||
513 | break; | ||
514 | case 13000000: | ||
515 | pll |= AK4671_PLL_13MHZ; | ||
516 | break; | ||
517 | case 13500000: | ||
518 | pll |= AK4671_PLL_13_5MHZ; | ||
519 | break; | ||
520 | case 19200000: | ||
521 | pll |= AK4671_PLL_19_2MHZ; | ||
522 | break; | ||
523 | case 24000000: | ||
524 | pll |= AK4671_PLL_24MHZ; | ||
525 | break; | ||
526 | case 26000000: | ||
527 | pll |= AK4671_PLL_26MHZ; | ||
528 | break; | ||
529 | case 27000000: | ||
530 | pll |= AK4671_PLL_27MHZ; | ||
531 | break; | ||
532 | default: | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT0, pll); | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
542 | { | ||
543 | struct snd_soc_codec *codec = dai->codec; | ||
544 | u8 mode; | ||
545 | u8 format; | ||
546 | |||
547 | /* set master/slave audio interface */ | ||
548 | mode = snd_soc_read(codec, AK4671_PLL_MODE_SELECT1); | ||
549 | |||
550 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
551 | case SND_SOC_DAIFMT_CBM_CFM: | ||
552 | mode |= AK4671_M_S; | ||
553 | break; | ||
554 | case SND_SOC_DAIFMT_CBM_CFS: | ||
555 | mode &= ~(AK4671_M_S); | ||
556 | break; | ||
557 | default: | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | /* interface format */ | ||
562 | format = snd_soc_read(codec, AK4671_FORMAT_SELECT); | ||
563 | format &= ~AK4671_DIF; | ||
564 | |||
565 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
566 | case SND_SOC_DAIFMT_I2S: | ||
567 | format |= AK4671_DIF_I2S_MODE; | ||
568 | break; | ||
569 | case SND_SOC_DAIFMT_LEFT_J: | ||
570 | format |= AK4671_DIF_MSB_MODE; | ||
571 | break; | ||
572 | case SND_SOC_DAIFMT_DSP_A: | ||
573 | format |= AK4671_DIF_DSP_MODE; | ||
574 | format |= AK4671_BCKP; | ||
575 | format |= AK4671_MSBS; | ||
576 | break; | ||
577 | default: | ||
578 | return -EINVAL; | ||
579 | } | ||
580 | |||
581 | /* set mode and format */ | ||
582 | snd_soc_write(codec, AK4671_PLL_MODE_SELECT1, mode); | ||
583 | snd_soc_write(codec, AK4671_FORMAT_SELECT, format); | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int ak4671_set_bias_level(struct snd_soc_codec *codec, | ||
589 | enum snd_soc_bias_level level) | ||
590 | { | ||
591 | u8 reg; | ||
592 | |||
593 | switch (level) { | ||
594 | case SND_SOC_BIAS_ON: | ||
595 | case SND_SOC_BIAS_PREPARE: | ||
596 | case SND_SOC_BIAS_STANDBY: | ||
597 | reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT); | ||
598 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, | ||
599 | reg | AK4671_PMVCM); | ||
600 | break; | ||
601 | case SND_SOC_BIAS_OFF: | ||
602 | snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); | ||
603 | break; | ||
604 | } | ||
605 | codec->bias_level = level; | ||
606 | return 0; | ||
607 | } | ||
608 | |||
609 | #define AK4671_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | ||
610 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
611 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | ||
612 | SNDRV_PCM_RATE_48000) | ||
613 | |||
614 | #define AK4671_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
615 | |||
616 | static struct snd_soc_dai_ops ak4671_dai_ops = { | ||
617 | .hw_params = ak4671_hw_params, | ||
618 | .set_sysclk = ak4671_set_dai_sysclk, | ||
619 | .set_fmt = ak4671_set_dai_fmt, | ||
620 | }; | ||
621 | |||
622 | struct snd_soc_dai ak4671_dai = { | ||
623 | .name = "AK4671", | ||
624 | .playback = { | ||
625 | .stream_name = "Playback", | ||
626 | .channels_min = 1, | ||
627 | .channels_max = 2, | ||
628 | .rates = AK4671_RATES, | ||
629 | .formats = AK4671_FORMATS,}, | ||
630 | .capture = { | ||
631 | .stream_name = "Capture", | ||
632 | .channels_min = 1, | ||
633 | .channels_max = 2, | ||
634 | .rates = AK4671_RATES, | ||
635 | .formats = AK4671_FORMATS,}, | ||
636 | .ops = &ak4671_dai_ops, | ||
637 | }; | ||
638 | EXPORT_SYMBOL_GPL(ak4671_dai); | ||
639 | |||
640 | static int ak4671_probe(struct platform_device *pdev) | ||
641 | { | ||
642 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
643 | struct snd_soc_codec *codec; | ||
644 | int ret = 0; | ||
645 | |||
646 | if (ak4671_codec == NULL) { | ||
647 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
648 | return -ENODEV; | ||
649 | } | ||
650 | |||
651 | socdev->card->codec = ak4671_codec; | ||
652 | codec = ak4671_codec; | ||
653 | |||
654 | /* register pcms */ | ||
655 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
656 | if (ret < 0) { | ||
657 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
658 | goto pcm_err; | ||
659 | } | ||
660 | |||
661 | snd_soc_add_controls(codec, ak4671_snd_controls, | ||
662 | ARRAY_SIZE(ak4671_snd_controls)); | ||
663 | ak4671_add_widgets(codec); | ||
664 | |||
665 | ret = snd_soc_init_card(socdev); | ||
666 | if (ret < 0) { | ||
667 | dev_err(codec->dev, "failed to register card: %d\n", ret); | ||
668 | goto card_err; | ||
669 | } | ||
670 | |||
671 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
672 | |||
673 | return ret; | ||
674 | |||
675 | card_err: | ||
676 | snd_soc_free_pcms(socdev); | ||
677 | snd_soc_dapm_free(socdev); | ||
678 | pcm_err: | ||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | static int ak4671_remove(struct platform_device *pdev) | ||
683 | { | ||
684 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
685 | |||
686 | snd_soc_free_pcms(socdev); | ||
687 | snd_soc_dapm_free(socdev); | ||
688 | |||
689 | return 0; | ||
690 | } | ||
691 | |||
692 | struct snd_soc_codec_device soc_codec_dev_ak4671 = { | ||
693 | .probe = ak4671_probe, | ||
694 | .remove = ak4671_remove, | ||
695 | }; | ||
696 | EXPORT_SYMBOL_GPL(soc_codec_dev_ak4671); | ||
697 | |||
698 | static int ak4671_register(struct ak4671_priv *ak4671, | ||
699 | enum snd_soc_control_type control) | ||
700 | { | ||
701 | int ret; | ||
702 | struct snd_soc_codec *codec = &ak4671->codec; | ||
703 | |||
704 | if (ak4671_codec) { | ||
705 | dev_err(codec->dev, "Another AK4671 is registered\n"); | ||
706 | ret = -EINVAL; | ||
707 | goto err; | ||
708 | } | ||
709 | |||
710 | mutex_init(&codec->mutex); | ||
711 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
712 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
713 | |||
714 | codec->private_data = ak4671; | ||
715 | codec->name = "AK4671"; | ||
716 | codec->owner = THIS_MODULE; | ||
717 | codec->bias_level = SND_SOC_BIAS_OFF; | ||
718 | codec->set_bias_level = ak4671_set_bias_level; | ||
719 | codec->dai = &ak4671_dai; | ||
720 | codec->num_dai = 1; | ||
721 | codec->reg_cache_size = AK4671_CACHEREGNUM; | ||
722 | codec->reg_cache = &ak4671->reg_cache; | ||
723 | |||
724 | memcpy(codec->reg_cache, ak4671_reg, sizeof(ak4671_reg)); | ||
725 | |||
726 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, control); | ||
727 | if (ret < 0) { | ||
728 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | ||
729 | goto err; | ||
730 | } | ||
731 | |||
732 | ak4671_dai.dev = codec->dev; | ||
733 | ak4671_codec = codec; | ||
734 | |||
735 | ret = snd_soc_register_codec(codec); | ||
736 | if (ret != 0) { | ||
737 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
738 | goto err; | ||
739 | } | ||
740 | |||
741 | ret = snd_soc_register_dai(&ak4671_dai); | ||
742 | if (ret != 0) { | ||
743 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
744 | goto err_codec; | ||
745 | } | ||
746 | |||
747 | return 0; | ||
748 | |||
749 | err_codec: | ||
750 | snd_soc_unregister_codec(codec); | ||
751 | err: | ||
752 | kfree(ak4671); | ||
753 | return ret; | ||
754 | } | ||
755 | |||
756 | static void ak4671_unregister(struct ak4671_priv *ak4671) | ||
757 | { | ||
758 | ak4671_set_bias_level(&ak4671->codec, SND_SOC_BIAS_OFF); | ||
759 | snd_soc_unregister_dai(&ak4671_dai); | ||
760 | snd_soc_unregister_codec(&ak4671->codec); | ||
761 | kfree(ak4671); | ||
762 | ak4671_codec = NULL; | ||
763 | } | ||
764 | |||
765 | static int __devinit ak4671_i2c_probe(struct i2c_client *client, | ||
766 | const struct i2c_device_id *id) | ||
767 | { | ||
768 | struct ak4671_priv *ak4671; | ||
769 | struct snd_soc_codec *codec; | ||
770 | |||
771 | ak4671 = kzalloc(sizeof(struct ak4671_priv), GFP_KERNEL); | ||
772 | if (ak4671 == NULL) | ||
773 | return -ENOMEM; | ||
774 | |||
775 | codec = &ak4671->codec; | ||
776 | codec->hw_write = (hw_write_t)i2c_master_send; | ||
777 | |||
778 | i2c_set_clientdata(client, ak4671); | ||
779 | codec->control_data = client; | ||
780 | |||
781 | codec->dev = &client->dev; | ||
782 | |||
783 | return ak4671_register(ak4671, SND_SOC_I2C); | ||
784 | } | ||
785 | |||
786 | static __devexit int ak4671_i2c_remove(struct i2c_client *client) | ||
787 | { | ||
788 | struct ak4671_priv *ak4671 = i2c_get_clientdata(client); | ||
789 | |||
790 | ak4671_unregister(ak4671); | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static const struct i2c_device_id ak4671_i2c_id[] = { | ||
796 | { "ak4671", 0 }, | ||
797 | { } | ||
798 | }; | ||
799 | MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); | ||
800 | |||
801 | static struct i2c_driver ak4671_i2c_driver = { | ||
802 | .driver = { | ||
803 | .name = "ak4671", | ||
804 | .owner = THIS_MODULE, | ||
805 | }, | ||
806 | .probe = ak4671_i2c_probe, | ||
807 | .remove = __devexit_p(ak4671_i2c_remove), | ||
808 | .id_table = ak4671_i2c_id, | ||
809 | }; | ||
810 | |||
811 | static int __init ak4671_modinit(void) | ||
812 | { | ||
813 | return i2c_add_driver(&ak4671_i2c_driver); | ||
814 | } | ||
815 | module_init(ak4671_modinit); | ||
816 | |||
817 | static void __exit ak4671_exit(void) | ||
818 | { | ||
819 | i2c_del_driver(&ak4671_i2c_driver); | ||
820 | } | ||
821 | module_exit(ak4671_exit); | ||
822 | |||
823 | MODULE_DESCRIPTION("ASoC AK4671 codec driver"); | ||
824 | MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>"); | ||
825 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h new file mode 100644 index 000000000000..e2fad964e88b --- /dev/null +++ b/sound/soc/codecs/ak4671.h | |||
@@ -0,0 +1,156 @@ | |||
1 | /* | ||
2 | * ak4671.h -- audio driver for AK4671 | ||
3 | * | ||
4 | * Copyright (C) 2009 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _AK4671_H | ||
15 | #define _AK4671_H | ||
16 | |||
17 | #define AK4671_AD_DA_POWER_MANAGEMENT 0x00 | ||
18 | #define AK4671_PLL_MODE_SELECT0 0x01 | ||
19 | #define AK4671_PLL_MODE_SELECT1 0x02 | ||
20 | #define AK4671_FORMAT_SELECT 0x03 | ||
21 | #define AK4671_MIC_SIGNAL_SELECT 0x04 | ||
22 | #define AK4671_MIC_AMP_GAIN 0x05 | ||
23 | #define AK4671_MIXING_POWER_MANAGEMENT0 0x06 | ||
24 | #define AK4671_MIXING_POWER_MANAGEMENT1 0x07 | ||
25 | #define AK4671_OUTPUT_VOLUME_CONTROL 0x08 | ||
26 | #define AK4671_LOUT1_SIGNAL_SELECT 0x09 | ||
27 | #define AK4671_ROUT1_SIGNAL_SELECT 0x0a | ||
28 | #define AK4671_LOUT2_SIGNAL_SELECT 0x0b | ||
29 | #define AK4671_ROUT2_SIGNAL_SELECT 0x0c | ||
30 | #define AK4671_LOUT3_SIGNAL_SELECT 0x0d | ||
31 | #define AK4671_ROUT3_SIGNAL_SELECT 0x0e | ||
32 | #define AK4671_LOUT1_POWER_MANAGERMENT 0x0f | ||
33 | #define AK4671_LOUT2_POWER_MANAGERMENT 0x10 | ||
34 | #define AK4671_LOUT3_POWER_MANAGERMENT 0x11 | ||
35 | #define AK4671_LCH_INPUT_VOLUME_CONTROL 0x12 | ||
36 | #define AK4671_RCH_INPUT_VOLUME_CONTROL 0x13 | ||
37 | #define AK4671_ALC_REFERENCE_SELECT 0x14 | ||
38 | #define AK4671_DIGITAL_MIXING_CONTROL 0x15 | ||
39 | #define AK4671_ALC_TIMER_SELECT 0x16 | ||
40 | #define AK4671_ALC_MODE_CONTROL 0x17 | ||
41 | #define AK4671_MODE_CONTROL1 0x18 | ||
42 | #define AK4671_MODE_CONTROL2 0x19 | ||
43 | #define AK4671_LCH_OUTPUT_VOLUME_CONTROL 0x1a | ||
44 | #define AK4671_RCH_OUTPUT_VOLUME_CONTROL 0x1b | ||
45 | #define AK4671_SIDETONE_A_CONTROL 0x1c | ||
46 | #define AK4671_DIGITAL_FILTER_SELECT 0x1d | ||
47 | #define AK4671_FIL3_COEFFICIENT0 0x1e | ||
48 | #define AK4671_FIL3_COEFFICIENT1 0x1f | ||
49 | #define AK4671_FIL3_COEFFICIENT2 0x20 | ||
50 | #define AK4671_FIL3_COEFFICIENT3 0x21 | ||
51 | #define AK4671_EQ_COEFFICIENT0 0x22 | ||
52 | #define AK4671_EQ_COEFFICIENT1 0x23 | ||
53 | #define AK4671_EQ_COEFFICIENT2 0x24 | ||
54 | #define AK4671_EQ_COEFFICIENT3 0x25 | ||
55 | #define AK4671_EQ_COEFFICIENT4 0x26 | ||
56 | #define AK4671_EQ_COEFFICIENT5 0x27 | ||
57 | #define AK4671_FIL1_COEFFICIENT0 0x28 | ||
58 | #define AK4671_FIL1_COEFFICIENT1 0x29 | ||
59 | #define AK4671_FIL1_COEFFICIENT2 0x2a | ||
60 | #define AK4671_FIL1_COEFFICIENT3 0x2b | ||
61 | #define AK4671_FIL2_COEFFICIENT0 0x2c | ||
62 | #define AK4671_FIL2_COEFFICIENT1 0x2d | ||
63 | #define AK4671_FIL2_COEFFICIENT2 0x2e | ||
64 | #define AK4671_FIL2_COEFFICIENT3 0x2f | ||
65 | #define AK4671_DIGITAL_FILTER_SELECT2 0x30 | ||
66 | #define AK4671_E1_COEFFICIENT0 0x32 | ||
67 | #define AK4671_E1_COEFFICIENT1 0x33 | ||
68 | #define AK4671_E1_COEFFICIENT2 0x34 | ||
69 | #define AK4671_E1_COEFFICIENT3 0x35 | ||
70 | #define AK4671_E1_COEFFICIENT4 0x36 | ||
71 | #define AK4671_E1_COEFFICIENT5 0x37 | ||
72 | #define AK4671_E2_COEFFICIENT0 0x38 | ||
73 | #define AK4671_E2_COEFFICIENT1 0x39 | ||
74 | #define AK4671_E2_COEFFICIENT2 0x3a | ||
75 | #define AK4671_E2_COEFFICIENT3 0x3b | ||
76 | #define AK4671_E2_COEFFICIENT4 0x3c | ||
77 | #define AK4671_E2_COEFFICIENT5 0x3d | ||
78 | #define AK4671_E3_COEFFICIENT0 0x3e | ||
79 | #define AK4671_E3_COEFFICIENT1 0x3f | ||
80 | #define AK4671_E3_COEFFICIENT2 0x40 | ||
81 | #define AK4671_E3_COEFFICIENT3 0x41 | ||
82 | #define AK4671_E3_COEFFICIENT4 0x42 | ||
83 | #define AK4671_E3_COEFFICIENT5 0x43 | ||
84 | #define AK4671_E4_COEFFICIENT0 0x44 | ||
85 | #define AK4671_E4_COEFFICIENT1 0x45 | ||
86 | #define AK4671_E4_COEFFICIENT2 0x46 | ||
87 | #define AK4671_E4_COEFFICIENT3 0x47 | ||
88 | #define AK4671_E4_COEFFICIENT4 0x48 | ||
89 | #define AK4671_E4_COEFFICIENT5 0x49 | ||
90 | #define AK4671_E5_COEFFICIENT0 0x4a | ||
91 | #define AK4671_E5_COEFFICIENT1 0x4b | ||
92 | #define AK4671_E5_COEFFICIENT2 0x4c | ||
93 | #define AK4671_E5_COEFFICIENT3 0x4d | ||
94 | #define AK4671_E5_COEFFICIENT4 0x4e | ||
95 | #define AK4671_E5_COEFFICIENT5 0x4f | ||
96 | #define AK4671_EQ_CONTROL_250HZ_100HZ 0x50 | ||
97 | #define AK4671_EQ_CONTROL_3500HZ_1KHZ 0x51 | ||
98 | #define AK4671_EQ_CONTRO_10KHZ 0x52 | ||
99 | #define AK4671_PCM_IF_CONTROL0 0x53 | ||
100 | #define AK4671_PCM_IF_CONTROL1 0x54 | ||
101 | #define AK4671_PCM_IF_CONTROL2 0x55 | ||
102 | #define AK4671_DIGITAL_VOLUME_B_CONTROL 0x56 | ||
103 | #define AK4671_DIGITAL_VOLUME_C_CONTROL 0x57 | ||
104 | #define AK4671_SIDETONE_VOLUME_CONTROL 0x58 | ||
105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 | ||
106 | #define AK4671_SAR_ADC_CONTROL 0x5a | ||
107 | |||
108 | #define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) | ||
109 | |||
110 | /* Bitfield Definitions */ | ||
111 | |||
112 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ | ||
113 | #define AK4671_PMVCM 0x01 | ||
114 | |||
115 | /* AK4671_PLL_MODE_SELECT0 (0x01) Fields */ | ||
116 | #define AK4671_PLL 0x0f | ||
117 | #define AK4671_PLL_11_2896MHZ (4 << 0) | ||
118 | #define AK4671_PLL_12_288MHZ (5 << 0) | ||
119 | #define AK4671_PLL_12MHZ (6 << 0) | ||
120 | #define AK4671_PLL_24MHZ (7 << 0) | ||
121 | #define AK4671_PLL_19_2MHZ (8 << 0) | ||
122 | #define AK4671_PLL_13_5MHZ (12 << 0) | ||
123 | #define AK4671_PLL_27MHZ (13 << 0) | ||
124 | #define AK4671_PLL_13MHZ (14 << 0) | ||
125 | #define AK4671_PLL_26MHZ (15 << 0) | ||
126 | #define AK4671_FS 0xf0 | ||
127 | #define AK4671_FS_8KHZ (0 << 4) | ||
128 | #define AK4671_FS_12KHZ (1 << 4) | ||
129 | #define AK4671_FS_16KHZ (2 << 4) | ||
130 | #define AK4671_FS_24KHZ (3 << 4) | ||
131 | #define AK4671_FS_11_025KHZ (5 << 4) | ||
132 | #define AK4671_FS_22_05KHZ (7 << 4) | ||
133 | #define AK4671_FS_32KHZ (10 << 4) | ||
134 | #define AK4671_FS_48KHZ (11 << 4) | ||
135 | #define AK4671_FS_44_1KHZ (15 << 4) | ||
136 | |||
137 | /* AK4671_PLL_MODE_SELECT1 (0x02) Fields */ | ||
138 | #define AK4671_PMPLL 0x01 | ||
139 | #define AK4671_M_S 0x02 | ||
140 | |||
141 | /* AK4671_FORMAT_SELECT (0x03) Fields */ | ||
142 | #define AK4671_DIF 0x03 | ||
143 | #define AK4671_DIF_DSP_MODE (0 << 0) | ||
144 | #define AK4671_DIF_MSB_MODE (2 << 0) | ||
145 | #define AK4671_DIF_I2S_MODE (3 << 0) | ||
146 | #define AK4671_BCKP 0x04 | ||
147 | #define AK4671_MSBS 0x08 | ||
148 | #define AK4671_SDOD 0x10 | ||
149 | |||
150 | /* AK4671_LOUT2_POWER_MANAGEMENT (0x10) Fields */ | ||
151 | #define AK4671_MUTEN 0x04 | ||
152 | |||
153 | extern struct snd_soc_dai ak4671_dai; | ||
154 | extern struct snd_soc_codec_device soc_codec_dev_ak4671; | ||
155 | |||
156 | #endif | ||
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 126b15b18aeb..3395cf945d56 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -53,6 +53,7 @@ | |||
53 | 53 | ||
54 | /* codec private data */ | 54 | /* codec private data */ |
55 | struct aic3x_priv { | 55 | struct aic3x_priv { |
56 | struct snd_soc_codec codec; | ||
56 | unsigned int sysclk; | 57 | unsigned int sysclk; |
57 | int master; | 58 | int master; |
58 | }; | 59 | }; |
@@ -1156,11 +1157,13 @@ static int aic3x_resume(struct platform_device *pdev) | |||
1156 | * initialise the AIC3X driver | 1157 | * initialise the AIC3X driver |
1157 | * register the mixer and dsp interfaces with the kernel | 1158 | * register the mixer and dsp interfaces with the kernel |
1158 | */ | 1159 | */ |
1159 | static int aic3x_init(struct snd_soc_device *socdev) | 1160 | static int aic3x_init(struct snd_soc_codec *codec) |
1160 | { | 1161 | { |
1161 | struct snd_soc_codec *codec = socdev->card->codec; | 1162 | int reg; |
1162 | struct aic3x_setup_data *setup = socdev->codec_data; | 1163 | |
1163 | int reg, ret = 0; | 1164 | mutex_init(&codec->mutex); |
1165 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
1166 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
1164 | 1167 | ||
1165 | codec->name = "tlv320aic3x"; | 1168 | codec->name = "tlv320aic3x"; |
1166 | codec->owner = THIS_MODULE; | 1169 | codec->owner = THIS_MODULE; |
@@ -1177,13 +1180,6 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1177 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); | 1180 | aic3x_write(codec, AIC3X_PAGE_SELECT, PAGE0_SELECT); |
1178 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); | 1181 | aic3x_write(codec, AIC3X_RESET, SOFT_RESET); |
1179 | 1182 | ||
1180 | /* register pcms */ | ||
1181 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
1182 | if (ret < 0) { | ||
1183 | printk(KERN_ERR "aic3x: failed to create pcms\n"); | ||
1184 | goto pcm_err; | ||
1185 | } | ||
1186 | |||
1187 | /* DAC default volume and mute */ | 1183 | /* DAC default volume and mute */ |
1188 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1184 | aic3x_write(codec, LDAC_VOL, DEFAULT_VOL | MUTE_ON); |
1189 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); | 1185 | aic3x_write(codec, RDAC_VOL, DEFAULT_VOL | MUTE_ON); |
@@ -1250,30 +1246,51 @@ static int aic3x_init(struct snd_soc_device *socdev) | |||
1250 | /* off, with power on */ | 1246 | /* off, with power on */ |
1251 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 1247 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
1252 | 1248 | ||
1253 | /* setup GPIO functions */ | 1249 | return 0; |
1254 | aic3x_write(codec, AIC3X_GPIO1_REG, (setup->gpio_func[0] & 0xf) << 4); | 1250 | } |
1255 | aic3x_write(codec, AIC3X_GPIO2_REG, (setup->gpio_func[1] & 0xf) << 4); | ||
1256 | 1251 | ||
1257 | snd_soc_add_controls(codec, aic3x_snd_controls, | 1252 | static struct snd_soc_codec *aic3x_codec; |
1258 | ARRAY_SIZE(aic3x_snd_controls)); | 1253 | |
1259 | aic3x_add_widgets(codec); | 1254 | static int aic3x_register(struct snd_soc_codec *codec) |
1260 | ret = snd_soc_init_card(socdev); | 1255 | { |
1256 | int ret; | ||
1257 | |||
1258 | ret = aic3x_init(codec); | ||
1261 | if (ret < 0) { | 1259 | if (ret < 0) { |
1262 | printk(KERN_ERR "aic3x: failed to register card\n"); | 1260 | dev_err(codec->dev, "Failed to initialise device\n"); |
1263 | goto card_err; | 1261 | return ret; |
1264 | } | 1262 | } |
1265 | 1263 | ||
1266 | return ret; | 1264 | aic3x_codec = codec; |
1267 | 1265 | ||
1268 | card_err: | 1266 | ret = snd_soc_register_codec(codec); |
1269 | snd_soc_free_pcms(socdev); | 1267 | if (ret) { |
1270 | snd_soc_dapm_free(socdev); | 1268 | dev_err(codec->dev, "Failed to register codec\n"); |
1271 | pcm_err: | 1269 | return ret; |
1272 | kfree(codec->reg_cache); | 1270 | } |
1273 | return ret; | 1271 | |
1272 | ret = snd_soc_register_dai(&aic3x_dai); | ||
1273 | if (ret) { | ||
1274 | dev_err(codec->dev, "Failed to register dai\n"); | ||
1275 | snd_soc_unregister_codec(codec); | ||
1276 | return ret; | ||
1277 | } | ||
1278 | |||
1279 | return 0; | ||
1274 | } | 1280 | } |
1275 | 1281 | ||
1276 | static struct snd_soc_device *aic3x_socdev; | 1282 | static int aic3x_unregister(struct aic3x_priv *aic3x) |
1283 | { | ||
1284 | aic3x_set_bias_level(&aic3x->codec, SND_SOC_BIAS_OFF); | ||
1285 | |||
1286 | snd_soc_unregister_dai(&aic3x_dai); | ||
1287 | snd_soc_unregister_codec(&aic3x->codec); | ||
1288 | |||
1289 | kfree(aic3x); | ||
1290 | aic3x_codec = NULL; | ||
1291 | |||
1292 | return 0; | ||
1293 | } | ||
1277 | 1294 | ||
1278 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1295 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
1279 | /* | 1296 | /* |
@@ -1288,28 +1305,36 @@ static struct snd_soc_device *aic3x_socdev; | |||
1288 | static int aic3x_i2c_probe(struct i2c_client *i2c, | 1305 | static int aic3x_i2c_probe(struct i2c_client *i2c, |
1289 | const struct i2c_device_id *id) | 1306 | const struct i2c_device_id *id) |
1290 | { | 1307 | { |
1291 | struct snd_soc_device *socdev = aic3x_socdev; | 1308 | struct snd_soc_codec *codec; |
1292 | struct snd_soc_codec *codec = socdev->card->codec; | 1309 | struct aic3x_priv *aic3x; |
1293 | int ret; | 1310 | |
1311 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | ||
1312 | if (aic3x == NULL) { | ||
1313 | dev_err(&i2c->dev, "failed to create private data\n"); | ||
1314 | return -ENOMEM; | ||
1315 | } | ||
1294 | 1316 | ||
1295 | i2c_set_clientdata(i2c, codec); | 1317 | codec = &aic3x->codec; |
1318 | codec->dev = &i2c->dev; | ||
1319 | codec->private_data = aic3x; | ||
1296 | codec->control_data = i2c; | 1320 | codec->control_data = i2c; |
1321 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
1297 | 1322 | ||
1298 | ret = aic3x_init(socdev); | 1323 | i2c_set_clientdata(i2c, aic3x); |
1299 | if (ret < 0) | 1324 | |
1300 | printk(KERN_ERR "aic3x: failed to initialise AIC3X\n"); | 1325 | return aic3x_register(codec); |
1301 | return ret; | ||
1302 | } | 1326 | } |
1303 | 1327 | ||
1304 | static int aic3x_i2c_remove(struct i2c_client *client) | 1328 | static int aic3x_i2c_remove(struct i2c_client *client) |
1305 | { | 1329 | { |
1306 | struct snd_soc_codec *codec = i2c_get_clientdata(client); | 1330 | struct aic3x_priv *aic3x = i2c_get_clientdata(client); |
1307 | kfree(codec->reg_cache); | 1331 | |
1308 | return 0; | 1332 | return aic3x_unregister(aic3x); |
1309 | } | 1333 | } |
1310 | 1334 | ||
1311 | static const struct i2c_device_id aic3x_i2c_id[] = { | 1335 | static const struct i2c_device_id aic3x_i2c_id[] = { |
1312 | { "tlv320aic3x", 0 }, | 1336 | { "tlv320aic3x", 0 }, |
1337 | { "tlv320aic33", 0 }, | ||
1313 | { } | 1338 | { } |
1314 | }; | 1339 | }; |
1315 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); | 1340 | MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); |
@@ -1320,50 +1345,28 @@ static struct i2c_driver aic3x_i2c_driver = { | |||
1320 | .name = "aic3x I2C Codec", | 1345 | .name = "aic3x I2C Codec", |
1321 | .owner = THIS_MODULE, | 1346 | .owner = THIS_MODULE, |
1322 | }, | 1347 | }, |
1323 | .probe = aic3x_i2c_probe, | 1348 | .probe = aic3x_i2c_probe, |
1324 | .remove = aic3x_i2c_remove, | 1349 | .remove = aic3x_i2c_remove, |
1325 | .id_table = aic3x_i2c_id, | 1350 | .id_table = aic3x_i2c_id, |
1326 | }; | 1351 | }; |
1327 | 1352 | ||
1328 | static int aic3x_add_i2c_device(struct platform_device *pdev, | 1353 | static inline void aic3x_i2c_init(void) |
1329 | const struct aic3x_setup_data *setup) | ||
1330 | { | 1354 | { |
1331 | struct i2c_board_info info; | ||
1332 | struct i2c_adapter *adapter; | ||
1333 | struct i2c_client *client; | ||
1334 | int ret; | 1355 | int ret; |
1335 | 1356 | ||
1336 | ret = i2c_add_driver(&aic3x_i2c_driver); | 1357 | ret = i2c_add_driver(&aic3x_i2c_driver); |
1337 | if (ret != 0) { | 1358 | if (ret) |
1338 | dev_err(&pdev->dev, "can't add i2c driver\n"); | 1359 | printk(KERN_ERR "%s: error regsitering i2c driver, %d\n", |
1339 | return ret; | 1360 | __func__, ret); |
1340 | } | 1361 | } |
1341 | |||
1342 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
1343 | info.addr = setup->i2c_address; | ||
1344 | strlcpy(info.type, "tlv320aic3x", I2C_NAME_SIZE); | ||
1345 | |||
1346 | adapter = i2c_get_adapter(setup->i2c_bus); | ||
1347 | if (!adapter) { | ||
1348 | dev_err(&pdev->dev, "can't get i2c adapter %d\n", | ||
1349 | setup->i2c_bus); | ||
1350 | goto err_driver; | ||
1351 | } | ||
1352 | |||
1353 | client = i2c_new_device(adapter, &info); | ||
1354 | i2c_put_adapter(adapter); | ||
1355 | if (!client) { | ||
1356 | dev_err(&pdev->dev, "can't add i2c device at 0x%x\n", | ||
1357 | (unsigned int)info.addr); | ||
1358 | goto err_driver; | ||
1359 | } | ||
1360 | |||
1361 | return 0; | ||
1362 | 1362 | ||
1363 | err_driver: | 1363 | static inline void aic3x_i2c_exit(void) |
1364 | { | ||
1364 | i2c_del_driver(&aic3x_i2c_driver); | 1365 | i2c_del_driver(&aic3x_i2c_driver); |
1365 | return -ENODEV; | ||
1366 | } | 1366 | } |
1367 | #else | ||
1368 | static inline void aic3x_i2c_init(void) { } | ||
1369 | static inline void aic3x_i2c_exit(void) { } | ||
1367 | #endif | 1370 | #endif |
1368 | 1371 | ||
1369 | static int aic3x_probe(struct platform_device *pdev) | 1372 | static int aic3x_probe(struct platform_device *pdev) |
@@ -1371,42 +1374,51 @@ static int aic3x_probe(struct platform_device *pdev) | |||
1371 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 1374 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); |
1372 | struct aic3x_setup_data *setup; | 1375 | struct aic3x_setup_data *setup; |
1373 | struct snd_soc_codec *codec; | 1376 | struct snd_soc_codec *codec; |
1374 | struct aic3x_priv *aic3x; | ||
1375 | int ret = 0; | 1377 | int ret = 0; |
1376 | 1378 | ||
1377 | printk(KERN_INFO "AIC3X Audio Codec %s\n", AIC3X_VERSION); | 1379 | codec = aic3x_codec; |
1380 | if (!codec) { | ||
1381 | dev_err(&pdev->dev, "Codec not registered\n"); | ||
1382 | return -ENODEV; | ||
1383 | } | ||
1378 | 1384 | ||
1385 | socdev->card->codec = codec; | ||
1379 | setup = socdev->codec_data; | 1386 | setup = socdev->codec_data; |
1380 | codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL); | ||
1381 | if (codec == NULL) | ||
1382 | return -ENOMEM; | ||
1383 | 1387 | ||
1384 | aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); | 1388 | if (setup) { |
1385 | if (aic3x == NULL) { | 1389 | /* setup GPIO functions */ |
1386 | kfree(codec); | 1390 | aic3x_write(codec, AIC3X_GPIO1_REG, |
1387 | return -ENOMEM; | 1391 | (setup->gpio_func[0] & 0xf) << 4); |
1392 | aic3x_write(codec, AIC3X_GPIO2_REG, | ||
1393 | (setup->gpio_func[1] & 0xf) << 4); | ||
1388 | } | 1394 | } |
1389 | 1395 | ||
1390 | codec->private_data = aic3x; | 1396 | /* register pcms */ |
1391 | socdev->card->codec = codec; | 1397 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); |
1392 | mutex_init(&codec->mutex); | 1398 | if (ret < 0) { |
1393 | INIT_LIST_HEAD(&codec->dapm_widgets); | 1399 | printk(KERN_ERR "aic3x: failed to create pcms\n"); |
1394 | INIT_LIST_HEAD(&codec->dapm_paths); | 1400 | goto pcm_err; |
1395 | |||
1396 | aic3x_socdev = socdev; | ||
1397 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | ||
1398 | if (setup->i2c_address) { | ||
1399 | codec->hw_write = (hw_write_t) i2c_master_send; | ||
1400 | ret = aic3x_add_i2c_device(pdev, setup); | ||
1401 | } | 1401 | } |
1402 | #else | ||
1403 | /* Add other interfaces here */ | ||
1404 | #endif | ||
1405 | 1402 | ||
1406 | if (ret != 0) { | 1403 | snd_soc_add_controls(codec, aic3x_snd_controls, |
1407 | kfree(codec->private_data); | 1404 | ARRAY_SIZE(aic3x_snd_controls)); |
1408 | kfree(codec); | 1405 | |
1406 | aic3x_add_widgets(codec); | ||
1407 | |||
1408 | ret = snd_soc_init_card(socdev); | ||
1409 | if (ret < 0) { | ||
1410 | printk(KERN_ERR "aic3x: failed to register card\n"); | ||
1411 | goto card_err; | ||
1409 | } | 1412 | } |
1413 | |||
1414 | return ret; | ||
1415 | |||
1416 | card_err: | ||
1417 | snd_soc_free_pcms(socdev); | ||
1418 | snd_soc_dapm_free(socdev); | ||
1419 | |||
1420 | pcm_err: | ||
1421 | kfree(codec->reg_cache); | ||
1410 | return ret; | 1422 | return ret; |
1411 | } | 1423 | } |
1412 | 1424 | ||
@@ -1421,12 +1433,8 @@ static int aic3x_remove(struct platform_device *pdev) | |||
1421 | 1433 | ||
1422 | snd_soc_free_pcms(socdev); | 1434 | snd_soc_free_pcms(socdev); |
1423 | snd_soc_dapm_free(socdev); | 1435 | snd_soc_dapm_free(socdev); |
1424 | #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 1436 | |
1425 | i2c_unregister_device(codec->control_data); | 1437 | kfree(codec->reg_cache); |
1426 | i2c_del_driver(&aic3x_i2c_driver); | ||
1427 | #endif | ||
1428 | kfree(codec->private_data); | ||
1429 | kfree(codec); | ||
1430 | 1438 | ||
1431 | return 0; | 1439 | return 0; |
1432 | } | 1440 | } |
@@ -1441,13 +1449,15 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_aic3x); | |||
1441 | 1449 | ||
1442 | static int __init aic3x_modinit(void) | 1450 | static int __init aic3x_modinit(void) |
1443 | { | 1451 | { |
1444 | return snd_soc_register_dai(&aic3x_dai); | 1452 | aic3x_i2c_init(); |
1453 | |||
1454 | return 0; | ||
1445 | } | 1455 | } |
1446 | module_init(aic3x_modinit); | 1456 | module_init(aic3x_modinit); |
1447 | 1457 | ||
1448 | static void __exit aic3x_exit(void) | 1458 | static void __exit aic3x_exit(void) |
1449 | { | 1459 | { |
1450 | snd_soc_unregister_dai(&aic3x_dai); | 1460 | aic3x_i2c_exit(); |
1451 | } | 1461 | } |
1452 | module_exit(aic3x_exit); | 1462 | module_exit(aic3x_exit); |
1453 | 1463 | ||
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h index ac827e578c4d..9af1c886213c 100644 --- a/sound/soc/codecs/tlv320aic3x.h +++ b/sound/soc/codecs/tlv320aic3x.h | |||
@@ -282,8 +282,6 @@ int aic3x_headset_detected(struct snd_soc_codec *codec); | |||
282 | int aic3x_button_pressed(struct snd_soc_codec *codec); | 282 | int aic3x_button_pressed(struct snd_soc_codec *codec); |
283 | 283 | ||
284 | struct aic3x_setup_data { | 284 | struct aic3x_setup_data { |
285 | int i2c_bus; | ||
286 | unsigned short i2c_address; | ||
287 | unsigned int gpio_func[2]; | 285 | unsigned int gpio_func[2]; |
288 | }; | 286 | }; |
289 | 287 | ||
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 4ded0e3a35e0..3f7e8a8b387e 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -63,6 +63,8 @@ struct wm8350_data { | |||
63 | struct wm8350_jack_data hpl; | 63 | struct wm8350_jack_data hpl; |
64 | struct wm8350_jack_data hpr; | 64 | struct wm8350_jack_data hpr; |
65 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; | 65 | struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)]; |
66 | int fll_freq_out; | ||
67 | int fll_freq_in; | ||
66 | }; | 68 | }; |
67 | 69 | ||
68 | static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, | 70 | static unsigned int wm8350_codec_cache_read(struct snd_soc_codec *codec, |
@@ -610,7 +612,7 @@ SOC_DAPM_SINGLE("Switch", WM8350_BEEP_VOLUME, 15, 1, 1); | |||
610 | 612 | ||
611 | /* Out4 Capture Mux */ | 613 | /* Out4 Capture Mux */ |
612 | static const struct snd_kcontrol_new wm8350_out4_capture_controls = | 614 | static const struct snd_kcontrol_new wm8350_out4_capture_controls = |
613 | SOC_DAPM_ENUM("Route", wm8350_enum[8]); | 615 | SOC_DAPM_ENUM("Route", wm8350_enum[7]); |
614 | 616 | ||
615 | static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { | 617 | static const struct snd_soc_dapm_widget wm8350_dapm_widgets[] = { |
616 | 618 | ||
@@ -1099,15 +1101,19 @@ static inline int fll_factors(struct _fll_div *fll_div, unsigned int input, | |||
1099 | } | 1101 | } |
1100 | 1102 | ||
1101 | static int wm8350_set_fll(struct snd_soc_dai *codec_dai, | 1103 | static int wm8350_set_fll(struct snd_soc_dai *codec_dai, |
1102 | int pll_id, unsigned int freq_in, | 1104 | int pll_id, int source, unsigned int freq_in, |
1103 | unsigned int freq_out) | 1105 | unsigned int freq_out) |
1104 | { | 1106 | { |
1105 | struct snd_soc_codec *codec = codec_dai->codec; | 1107 | struct snd_soc_codec *codec = codec_dai->codec; |
1106 | struct wm8350 *wm8350 = codec->control_data; | 1108 | struct wm8350 *wm8350 = codec->control_data; |
1109 | struct wm8350_data *priv = codec->private_data; | ||
1107 | struct _fll_div fll_div; | 1110 | struct _fll_div fll_div; |
1108 | int ret = 0; | 1111 | int ret = 0; |
1109 | u16 fll_1, fll_4; | 1112 | u16 fll_1, fll_4; |
1110 | 1113 | ||
1114 | if (freq_in == priv->fll_freq_in && freq_out == priv->fll_freq_out) | ||
1115 | return 0; | ||
1116 | |||
1111 | /* power down FLL - we need to do this for reconfiguration */ | 1117 | /* power down FLL - we need to do this for reconfiguration */ |
1112 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, | 1118 | wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, |
1113 | WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); | 1119 | WM8350_FLL_ENA | WM8350_FLL_OSC_ENA); |
@@ -1142,6 +1148,9 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai, | |||
1142 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); | 1148 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_OSC_ENA); |
1143 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); | 1149 | wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_FLL_ENA); |
1144 | 1150 | ||
1151 | priv->fll_freq_out = freq_out; | ||
1152 | priv->fll_freq_in = freq_in; | ||
1153 | |||
1145 | return 0; | 1154 | return 0; |
1146 | } | 1155 | } |
1147 | 1156 | ||
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index b9ef4d915221..9cb8e50f0fbb 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -1011,7 +1011,8 @@ static int fll_factors(struct wm8400_priv *wm8400, struct fll_factors *factors, | |||
1011 | } | 1011 | } |
1012 | 1012 | ||
1013 | static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, | 1013 | static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
1014 | unsigned int freq_in, unsigned int freq_out) | 1014 | int source, unsigned int freq_in, |
1015 | unsigned int freq_out) | ||
1015 | { | 1016 | { |
1016 | struct snd_soc_codec *codec = codec_dai->codec; | 1017 | struct snd_soc_codec *codec = codec_dai->codec; |
1017 | struct wm8400_priv *wm8400 = codec->private_data; | 1018 | struct wm8400_priv *wm8400 = codec->private_data; |
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 060d5d06ba95..5702435af81b 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c | |||
@@ -271,8 +271,8 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
271 | pll_div.k = K; | 271 | pll_div.k = K; |
272 | } | 272 | } |
273 | 273 | ||
274 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, | 274 | static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
275 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 275 | int source, unsigned int freq_in, unsigned int freq_out) |
276 | { | 276 | { |
277 | struct snd_soc_codec *codec = codec_dai->codec; | 277 | struct snd_soc_codec *codec = codec_dai->codec; |
278 | u16 reg; | 278 | u16 reg; |
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index d5473473a1e3..3be5c0b2552c 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c | |||
@@ -407,8 +407,8 @@ static int pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | 409 | ||
410 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | 410 | static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
411 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 411 | int source, unsigned int freq_in, unsigned int freq_out) |
412 | { | 412 | { |
413 | int offset; | 413 | int offset; |
414 | struct snd_soc_codec *codec = codec_dai->codec; | 414 | struct snd_soc_codec *codec = codec_dai->codec; |
@@ -458,12 +458,12 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, | |||
458 | return 0; | 458 | return 0; |
459 | 459 | ||
460 | snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); | 460 | snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); |
461 | snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); | 461 | snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0x1ff); |
462 | snd_soc_write(codec, WM8580_PLLA3 + offset, | 462 | snd_soc_write(codec, WM8580_PLLA3 + offset, |
463 | (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); | 463 | (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); |
464 | 464 | ||
465 | reg = snd_soc_read(codec, WM8580_PLLA4 + offset); | 465 | reg = snd_soc_read(codec, WM8580_PLLA4 + offset); |
466 | reg &= ~0x3f; | 466 | reg &= ~0x1b; |
467 | reg |= pll_div.prescale | pll_div.postscale << 1 | | 467 | reg |= pll_div.prescale | pll_div.postscale << 1 | |
468 | pll_div.freqmode << 3; | 468 | pll_div.freqmode << 3; |
469 | 469 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index d80d414cfbbd..f60f3a02d1f8 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -723,8 +723,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
723 | pll_div->k = K; | 723 | pll_div->k = K; |
724 | } | 724 | } |
725 | 725 | ||
726 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, | 726 | static int wm8753_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
727 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 727 | int source, unsigned int freq_in, unsigned int freq_out) |
728 | { | 728 | { |
729 | u16 reg, enable; | 729 | u16 reg, enable; |
730 | int offset; | 730 | int offset; |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index 5e9c855c0036..882604ef768c 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -814,8 +814,8 @@ reenable: | |||
814 | return 0; | 814 | return 0; |
815 | } | 815 | } |
816 | 816 | ||
817 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, | 817 | static int wm8900_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
818 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 818 | int source, unsigned int freq_in, unsigned int freq_out) |
819 | { | 819 | { |
820 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); | 820 | return wm8900_set_fll(codec_dai->codec, pll_id, freq_in, freq_out); |
821 | } | 821 | } |
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index da97aae475a2..914d788a2b76 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c | |||
@@ -536,8 +536,8 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
536 | } | 536 | } |
537 | 537 | ||
538 | /* Untested at the moment */ | 538 | /* Untested at the moment */ |
539 | static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, | 539 | static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
540 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 540 | int source, unsigned int freq_in, unsigned int freq_out) |
541 | { | 541 | { |
542 | struct snd_soc_codec *codec = codec_dai->codec; | 542 | struct snd_soc_codec *codec = codec_dai->codec; |
543 | u16 reg; | 543 | u16 reg; |
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index f59703be61c8..416fb3c17018 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c | |||
@@ -540,8 +540,8 @@ static int pll_factors(unsigned int source, unsigned int target, | |||
540 | return 0; | 540 | return 0; |
541 | } | 541 | } |
542 | 542 | ||
543 | static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, | 543 | static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
544 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 544 | int source, unsigned int freq_in, unsigned int freq_out) |
545 | { | 545 | { |
546 | struct snd_soc_codec *codec = codec_dai->codec; | 546 | struct snd_soc_codec *codec = codec_dai->codec; |
547 | u16 reg; | 547 | u16 reg; |
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index d8a013ab3177..93d66e30f109 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.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> |
@@ -329,8 +328,8 @@ static void pll_factors(unsigned int target, unsigned int source) | |||
329 | pll_div.k = K; | 328 | pll_div.k = K; |
330 | } | 329 | } |
331 | 330 | ||
332 | static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, | 331 | static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
333 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 332 | int source, unsigned int freq_in, unsigned int freq_out) |
334 | { | 333 | { |
335 | struct snd_soc_codec *codec = codec_dai->codec; | 334 | struct snd_soc_codec *codec = codec_dai->codec; |
336 | u16 reg; | 335 | u16 reg; |
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 2d702db4131d..f657e9a5fe26 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c | |||
@@ -972,8 +972,8 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target, | |||
972 | pll_div->k = K; | 972 | pll_div->k = K; |
973 | } | 973 | } |
974 | 974 | ||
975 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, | 975 | static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
976 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 976 | int source, unsigned int freq_in, unsigned int freq_out) |
977 | { | 977 | { |
978 | u16 reg; | 978 | u16 reg; |
979 | struct snd_soc_codec *codec = codec_dai->codec; | 979 | struct snd_soc_codec *codec = codec_dai->codec; |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 13befa338247..6b32a2852603 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -422,7 +422,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref, | |||
422 | return 0; | 422 | return 0; |
423 | } | 423 | } |
424 | 424 | ||
425 | static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, | 425 | static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source, |
426 | unsigned int Fref, unsigned int Fout) | 426 | unsigned int Fref, unsigned int Fout) |
427 | { | 427 | { |
428 | struct snd_soc_codec *codec = dai->codec; | 428 | struct snd_soc_codec *codec = dai->codec; |
@@ -846,18 +846,76 @@ SOC_DAPM_SINGLE("Output Switch", WM8993_SPEAKER_MIXER, 2, 1, 0), | |||
846 | SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), | 846 | SOC_DAPM_SINGLE("DAC Switch", WM8993_SPEAKER_MIXER, 0, 1, 0), |
847 | }; | 847 | }; |
848 | 848 | ||
849 | static const char *aif_text[] = { | ||
850 | "Left", "Right" | ||
851 | }; | ||
852 | |||
853 | static const struct soc_enum aifoutl_enum = | ||
854 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 15, 2, aif_text); | ||
855 | |||
856 | static const struct snd_kcontrol_new aifoutl_mux = | ||
857 | SOC_DAPM_ENUM("AIFOUTL Mux", aifoutl_enum); | ||
858 | |||
859 | static const struct soc_enum aifoutr_enum = | ||
860 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_1, 14, 2, aif_text); | ||
861 | |||
862 | static const struct snd_kcontrol_new aifoutr_mux = | ||
863 | SOC_DAPM_ENUM("AIFOUTR Mux", aifoutr_enum); | ||
864 | |||
865 | static const struct soc_enum aifinl_enum = | ||
866 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 15, 2, aif_text); | ||
867 | |||
868 | static const struct snd_kcontrol_new aifinl_mux = | ||
869 | SOC_DAPM_ENUM("AIFINL Mux", aifinl_enum); | ||
870 | |||
871 | static const struct soc_enum aifinr_enum = | ||
872 | SOC_ENUM_SINGLE(WM8993_AUDIO_INTERFACE_2, 14, 2, aif_text); | ||
873 | |||
874 | static const struct snd_kcontrol_new aifinr_mux = | ||
875 | SOC_DAPM_ENUM("AIFINR Mux", aifinr_enum); | ||
876 | |||
877 | static const char *sidetone_text[] = { | ||
878 | "None", "Left", "Right" | ||
879 | }; | ||
880 | |||
881 | static const struct soc_enum sidetonel_enum = | ||
882 | SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 2, 3, sidetone_text); | ||
883 | |||
884 | static const struct snd_kcontrol_new sidetonel_mux = | ||
885 | SOC_DAPM_ENUM("Left Sidetone", sidetonel_enum); | ||
886 | |||
887 | static const struct soc_enum sidetoner_enum = | ||
888 | SOC_ENUM_SINGLE(WM8993_DIGITAL_SIDE_TONE, 0, 3, sidetone_text); | ||
889 | |||
890 | static const struct snd_kcontrol_new sidetoner_mux = | ||
891 | SOC_DAPM_ENUM("Right Sidetone", sidetoner_enum); | ||
892 | |||
849 | static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { | 893 | static const struct snd_soc_dapm_widget wm8993_dapm_widgets[] = { |
850 | SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, | 894 | SND_SOC_DAPM_SUPPLY("CLK_SYS", WM8993_BUS_CONTROL_1, 1, 0, clk_sys_event, |
851 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), | 895 | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), |
852 | SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), | 896 | SND_SOC_DAPM_SUPPLY("TOCLK", WM8993_CLOCKING_1, 14, 0, NULL, 0), |
853 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), | 897 | SND_SOC_DAPM_SUPPLY("CLK_DSP", WM8993_CLOCKING_3, 0, 0, NULL, 0), |
854 | 898 | ||
899 | SND_SOC_DAPM_ADC("ADCL", NULL, WM8993_POWER_MANAGEMENT_2, 1, 0), | ||
900 | SND_SOC_DAPM_ADC("ADCR", NULL, WM8993_POWER_MANAGEMENT_2, 0, 0), | ||
901 | |||
902 | SND_SOC_DAPM_MUX("AIFOUTL Mux", SND_SOC_NOPM, 0, 0, &aifoutl_mux), | ||
903 | SND_SOC_DAPM_MUX("AIFOUTR Mux", SND_SOC_NOPM, 0, 0, &aifoutr_mux), | ||
904 | |||
905 | SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), | ||
906 | SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), | ||
855 | 907 | ||
856 | SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), | 908 | SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), |
857 | SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), | 909 | SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), |
858 | 910 | ||
859 | SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), | 911 | SND_SOC_DAPM_MUX("DACL Mux", SND_SOC_NOPM, 0, 0, &aifinl_mux), |
860 | SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), | 912 | SND_SOC_DAPM_MUX("DACR Mux", SND_SOC_NOPM, 0, 0, &aifinr_mux), |
913 | |||
914 | SND_SOC_DAPM_MUX("DACL Sidetone", SND_SOC_NOPM, 0, 0, &sidetonel_mux), | ||
915 | SND_SOC_DAPM_MUX("DACR Sidetone", SND_SOC_NOPM, 0, 0, &sidetoner_mux), | ||
916 | |||
917 | SND_SOC_DAPM_DAC("DACL", NULL, WM8993_POWER_MANAGEMENT_3, 1, 0), | ||
918 | SND_SOC_DAPM_DAC("DACR", NULL, WM8993_POWER_MANAGEMENT_3, 0, 0), | ||
861 | 919 | ||
862 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), | 920 | SND_SOC_DAPM_MUX("Left Headphone Mux", SND_SOC_NOPM, 0, 0, &hpl_mux), |
863 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), | 921 | SND_SOC_DAPM_MUX("Right Headphone Mux", SND_SOC_NOPM, 0, 0, &hpr_mux), |
@@ -875,10 +933,32 @@ static const struct snd_soc_dapm_route routes[] = { | |||
875 | { "ADCR", NULL, "CLK_SYS" }, | 933 | { "ADCR", NULL, "CLK_SYS" }, |
876 | { "ADCR", NULL, "CLK_DSP" }, | 934 | { "ADCR", NULL, "CLK_DSP" }, |
877 | 935 | ||
936 | { "AIFOUTL Mux", "Left", "ADCL" }, | ||
937 | { "AIFOUTL Mux", "Right", "ADCR" }, | ||
938 | { "AIFOUTR Mux", "Left", "ADCL" }, | ||
939 | { "AIFOUTR Mux", "Right", "ADCR" }, | ||
940 | |||
941 | { "AIFOUTL", NULL, "AIFOUTL Mux" }, | ||
942 | { "AIFOUTR", NULL, "AIFOUTR Mux" }, | ||
943 | |||
944 | { "DACL Mux", "Left", "AIFINL" }, | ||
945 | { "DACL Mux", "Right", "AIFINR" }, | ||
946 | { "DACR Mux", "Left", "AIFINL" }, | ||
947 | { "DACR Mux", "Right", "AIFINR" }, | ||
948 | |||
949 | { "DACL Sidetone", "Left", "ADCL" }, | ||
950 | { "DACL Sidetone", "Right", "ADCR" }, | ||
951 | { "DACR Sidetone", "Left", "ADCL" }, | ||
952 | { "DACR Sidetone", "Right", "ADCR" }, | ||
953 | |||
878 | { "DACL", NULL, "CLK_SYS" }, | 954 | { "DACL", NULL, "CLK_SYS" }, |
879 | { "DACL", NULL, "CLK_DSP" }, | 955 | { "DACL", NULL, "CLK_DSP" }, |
956 | { "DACL", NULL, "DACL Mux" }, | ||
957 | { "DACL", NULL, "DACL Sidetone" }, | ||
880 | { "DACR", NULL, "CLK_SYS" }, | 958 | { "DACR", NULL, "CLK_SYS" }, |
881 | { "DACR", NULL, "CLK_DSP" }, | 959 | { "DACR", NULL, "CLK_DSP" }, |
960 | { "DACR", NULL, "DACR Mux" }, | ||
961 | { "DACR", NULL, "DACR Sidetone" }, | ||
882 | 962 | ||
883 | { "Left Output Mixer", "DAC Switch", "DACL" }, | 963 | { "Left Output Mixer", "DAC Switch", "DACL" }, |
884 | 964 | ||
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index fa88b463e71f..e7d2840d9e59 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c | |||
@@ -406,7 +406,7 @@ static int wm9705_soc_probe(struct platform_device *pdev) | |||
406 | ret = snd_soc_init_card(socdev); | 406 | ret = snd_soc_init_card(socdev); |
407 | if (ret < 0) { | 407 | if (ret < 0) { |
408 | printk(KERN_ERR "wm9705: failed to register card\n"); | 408 | printk(KERN_ERR "wm9705: failed to register card\n"); |
409 | goto pcm_err; | 409 | goto reset_err; |
410 | } | 410 | } |
411 | 411 | ||
412 | return 0; | 412 | return 0; |
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index abed37acf787..ca3d449ed89e 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c | |||
@@ -800,8 +800,8 @@ static int wm9713_set_pll(struct snd_soc_codec *codec, | |||
800 | return 0; | 800 | return 0; |
801 | } | 801 | } |
802 | 802 | ||
803 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, | 803 | static int wm9713_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, |
804 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 804 | int source, unsigned int freq_in, unsigned int freq_out) |
805 | { | 805 | { |
806 | struct snd_soc_codec *codec = codec_dai->codec; | 806 | struct snd_soc_codec *codec = codec_dai->codec; |
807 | return wm9713_set_pll(codec, pll_id, freq_in, freq_out); | 807 | return wm9713_set_pll(codec, pll_id, freq_in, freq_out); |
diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index e8fc474ba5cf..e542027eea89 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/pm.h> | 18 | #include <linux/pm.h> |
19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
21 | #include <linux/regulator/consumer.h> | ||
22 | #include <sound/core.h> | 21 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
@@ -274,17 +273,12 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
274 | 273 | ||
275 | /* Start the DC servo */ | 274 | /* Start the DC servo */ |
276 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 275 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, |
277 | WM8993_DCS_ENA_CHAN_0 | | 276 | 0xFFFF, |
278 | WM8993_DCS_ENA_CHAN_1 | | ||
279 | WM8993_DCS_TRIG_STARTUP_1 | | ||
280 | WM8993_DCS_TRIG_STARTUP_0, | ||
281 | WM8993_DCS_ENA_CHAN_0 | | 277 | WM8993_DCS_ENA_CHAN_0 | |
282 | WM8993_DCS_ENA_CHAN_1 | | 278 | WM8993_DCS_ENA_CHAN_1 | |
283 | WM8993_DCS_TRIG_STARTUP_1 | | 279 | WM8993_DCS_TRIG_STARTUP_1 | |
284 | WM8993_DCS_TRIG_STARTUP_0); | 280 | WM8993_DCS_TRIG_STARTUP_0); |
285 | wait_for_dc_servo(codec); | 281 | wait_for_dc_servo(codec); |
286 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, | ||
287 | WM8993_DCS_TIMER_PERIOD_01_MASK, 0xa); | ||
288 | 282 | ||
289 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | | 283 | reg |= WM8993_HPOUT1R_OUTP | WM8993_HPOUT1R_RMV_SHORT | |
290 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; | 284 | WM8993_HPOUT1L_OUTP | WM8993_HPOUT1L_RMV_SHORT; |
@@ -299,11 +293,8 @@ static int hp_event(struct snd_soc_dapm_widget *w, | |||
299 | WM8993_HPOUT1R_DLY | | 293 | WM8993_HPOUT1R_DLY | |
300 | WM8993_HPOUT1R_OUTP); | 294 | WM8993_HPOUT1R_OUTP); |
301 | 295 | ||
302 | snd_soc_update_bits(codec, WM8993_DC_SERVO_1, | ||
303 | WM8993_DCS_TIMER_PERIOD_01_MASK, 0); | ||
304 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, | 296 | snd_soc_update_bits(codec, WM8993_DC_SERVO_0, |
305 | WM8993_DCS_ENA_CHAN_0 | | 297 | 0xffff, 0); |
306 | WM8993_DCS_ENA_CHAN_1, 0); | ||
307 | 298 | ||
308 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); | 299 | snd_soc_write(codec, WM8993_ANALOGUE_HP_0, reg); |
309 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, | 300 | snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1, |
@@ -474,12 +465,6 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8993_POWER_MANAGEMENT_2, 9, 0, | |||
474 | SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, | 465 | SND_SOC_DAPM_MIXER("MIXINR", WM8993_POWER_MANAGEMENT_2, 8, 0, |
475 | mixinr, ARRAY_SIZE(mixinr)), | 466 | mixinr, ARRAY_SIZE(mixinr)), |
476 | 467 | ||
477 | SND_SOC_DAPM_ADC("ADCL", "Capture", WM8993_POWER_MANAGEMENT_2, 1, 0), | ||
478 | SND_SOC_DAPM_ADC("ADCR", "Capture", WM8993_POWER_MANAGEMENT_2, 0, 0), | ||
479 | |||
480 | SND_SOC_DAPM_DAC("DACL", "Playback", WM8993_POWER_MANAGEMENT_3, 1, 0), | ||
481 | SND_SOC_DAPM_DAC("DACR", "Playback", WM8993_POWER_MANAGEMENT_3, 0, 0), | ||
482 | |||
483 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, | 468 | SND_SOC_DAPM_MIXER("Left Output Mixer", WM8993_POWER_MANAGEMENT_3, 5, 0, |
484 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), | 469 | left_output_mixer, ARRAY_SIZE(left_output_mixer)), |
485 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, | 470 | SND_SOC_DAPM_MIXER("Right Output Mixer", WM8993_POWER_MANAGEMENT_3, 4, 0, |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index 4dfd4ad9d90e..047ee39418c0 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -13,9 +13,9 @@ config SND_DAVINCI_SOC_MCASP | |||
13 | tristate | 13 | tristate |
14 | 14 | ||
15 | config SND_DAVINCI_SOC_EVM | 15 | config SND_DAVINCI_SOC_EVM |
16 | tristate "SoC Audio support for DaVinci DM6446 or DM355 EVM" | 16 | tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" |
17 | depends on SND_DAVINCI_SOC | 17 | depends on SND_DAVINCI_SOC |
18 | depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM | 18 | depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM |
19 | select SND_DAVINCI_SOC_I2S | 19 | select SND_DAVINCI_SOC_I2S |
20 | select SND_SOC_TLV320AIC3X | 20 | select SND_SOC_TLV320AIC3X |
21 | help | 21 | help |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 46c1b0cb1d1b..7ccbe6684fc2 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/timer.h> | 14 | #include <linux/timer.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/i2c.h> | ||
17 | #include <sound/core.h> | 18 | #include <sound/core.h> |
18 | #include <sound/pcm.h> | 19 | #include <sound/pcm.h> |
19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
@@ -44,7 +45,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
44 | unsigned sysclk; | 45 | unsigned sysclk; |
45 | 46 | ||
46 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ | 47 | /* ASP1 on DM355 EVM is clocked by an external oscillator */ |
47 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm()) | 48 | if (machine_is_davinci_dm355_evm() || machine_is_davinci_dm6467_evm() || |
49 | machine_is_davinci_dm365_evm()) | ||
48 | sysclk = 27000000; | 50 | sysclk = 27000000; |
49 | 51 | ||
50 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by | 52 | /* ASP0 in DM6446 EVM is clocked by U55, as configured by |
@@ -175,7 +177,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = { | |||
175 | .ops = &evm_ops, | 177 | .ops = &evm_ops, |
176 | }; | 178 | }; |
177 | 179 | ||
178 | /* davinci-evm audio machine driver */ | 180 | /* davinci dm6446, dm355 or dm365 evm audio machine driver */ |
179 | static struct snd_soc_card snd_soc_card_evm = { | 181 | static struct snd_soc_card snd_soc_card_evm = { |
180 | .name = "DaVinci EVM", | 182 | .name = "DaVinci EVM", |
181 | .platform = &davinci_soc_platform, | 183 | .platform = &davinci_soc_platform, |
@@ -205,48 +207,33 @@ static struct snd_soc_card da850_snd_soc_card = { | |||
205 | .num_links = 1, | 207 | .num_links = 1, |
206 | }; | 208 | }; |
207 | 209 | ||
208 | /* evm audio private data */ | 210 | static struct aic3x_setup_data aic3x_setup; |
209 | static struct aic3x_setup_data evm_aic3x_setup = { | ||
210 | .i2c_bus = 1, | ||
211 | .i2c_address = 0x1b, | ||
212 | }; | ||
213 | |||
214 | /* dm6467 evm audio private data */ | ||
215 | static struct aic3x_setup_data dm6467_evm_aic3x_setup = { | ||
216 | .i2c_bus = 1, | ||
217 | .i2c_address = 0x18, | ||
218 | }; | ||
219 | |||
220 | static struct aic3x_setup_data da8xx_evm_aic3x_setup = { | ||
221 | .i2c_bus = 1, | ||
222 | .i2c_address = 0x18, | ||
223 | }; | ||
224 | 211 | ||
225 | /* evm audio subsystem */ | 212 | /* evm audio subsystem */ |
226 | static struct snd_soc_device evm_snd_devdata = { | 213 | static struct snd_soc_device evm_snd_devdata = { |
227 | .card = &snd_soc_card_evm, | 214 | .card = &snd_soc_card_evm, |
228 | .codec_dev = &soc_codec_dev_aic3x, | 215 | .codec_dev = &soc_codec_dev_aic3x, |
229 | .codec_data = &evm_aic3x_setup, | 216 | .codec_data = &aic3x_setup, |
230 | }; | 217 | }; |
231 | 218 | ||
232 | /* evm audio subsystem */ | 219 | /* evm audio subsystem */ |
233 | static struct snd_soc_device dm6467_evm_snd_devdata = { | 220 | static struct snd_soc_device dm6467_evm_snd_devdata = { |
234 | .card = &dm6467_snd_soc_card_evm, | 221 | .card = &dm6467_snd_soc_card_evm, |
235 | .codec_dev = &soc_codec_dev_aic3x, | 222 | .codec_dev = &soc_codec_dev_aic3x, |
236 | .codec_data = &dm6467_evm_aic3x_setup, | 223 | .codec_data = &aic3x_setup, |
237 | }; | 224 | }; |
238 | 225 | ||
239 | /* evm audio subsystem */ | 226 | /* evm audio subsystem */ |
240 | static struct snd_soc_device da830_evm_snd_devdata = { | 227 | static struct snd_soc_device da830_evm_snd_devdata = { |
241 | .card = &da830_snd_soc_card, | 228 | .card = &da830_snd_soc_card, |
242 | .codec_dev = &soc_codec_dev_aic3x, | 229 | .codec_dev = &soc_codec_dev_aic3x, |
243 | .codec_data = &da8xx_evm_aic3x_setup, | 230 | .codec_data = &aic3x_setup, |
244 | }; | 231 | }; |
245 | 232 | ||
246 | static struct snd_soc_device da850_evm_snd_devdata = { | 233 | static struct snd_soc_device da850_evm_snd_devdata = { |
247 | .card = &da850_snd_soc_card, | 234 | .card = &da850_snd_soc_card, |
248 | .codec_dev = &soc_codec_dev_aic3x, | 235 | .codec_dev = &soc_codec_dev_aic3x, |
249 | .codec_data = &da8xx_evm_aic3x_setup, | 236 | .codec_data = &aic3x_setup, |
250 | }; | 237 | }; |
251 | 238 | ||
252 | static struct platform_device *evm_snd_device; | 239 | static struct platform_device *evm_snd_device; |
@@ -257,7 +244,7 @@ static int __init evm_init(void) | |||
257 | int index; | 244 | int index; |
258 | int ret; | 245 | int ret; |
259 | 246 | ||
260 | if (machine_is_davinci_evm()) { | 247 | if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) { |
261 | evm_snd_dev_data = &evm_snd_devdata; | 248 | evm_snd_dev_data = &evm_snd_devdata; |
262 | index = 0; | 249 | index = 0; |
263 | } else if (machine_is_davinci_dm355_evm()) { | 250 | } else if (machine_is_davinci_dm355_evm()) { |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index eca22d7829d2..7a06c0a86665 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -512,34 +512,49 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, | |||
512 | int channel_size) | 512 | int channel_size) |
513 | { | 513 | { |
514 | u32 fmt = 0; | 514 | u32 fmt = 0; |
515 | u32 mask, rotate; | ||
515 | 516 | ||
516 | switch (channel_size) { | 517 | switch (channel_size) { |
517 | case DAVINCI_AUDIO_WORD_8: | 518 | case DAVINCI_AUDIO_WORD_8: |
518 | fmt = 0x03; | 519 | fmt = 0x03; |
520 | rotate = 6; | ||
521 | mask = 0x000000ff; | ||
519 | break; | 522 | break; |
520 | 523 | ||
521 | case DAVINCI_AUDIO_WORD_12: | 524 | case DAVINCI_AUDIO_WORD_12: |
522 | fmt = 0x05; | 525 | fmt = 0x05; |
526 | rotate = 5; | ||
527 | mask = 0x00000fff; | ||
523 | break; | 528 | break; |
524 | 529 | ||
525 | case DAVINCI_AUDIO_WORD_16: | 530 | case DAVINCI_AUDIO_WORD_16: |
526 | fmt = 0x07; | 531 | fmt = 0x07; |
532 | rotate = 4; | ||
533 | mask = 0x0000ffff; | ||
527 | break; | 534 | break; |
528 | 535 | ||
529 | case DAVINCI_AUDIO_WORD_20: | 536 | case DAVINCI_AUDIO_WORD_20: |
530 | fmt = 0x09; | 537 | fmt = 0x09; |
538 | rotate = 3; | ||
539 | mask = 0x000fffff; | ||
531 | break; | 540 | break; |
532 | 541 | ||
533 | case DAVINCI_AUDIO_WORD_24: | 542 | case DAVINCI_AUDIO_WORD_24: |
534 | fmt = 0x0B; | 543 | fmt = 0x0B; |
544 | rotate = 2; | ||
545 | mask = 0x00ffffff; | ||
535 | break; | 546 | break; |
536 | 547 | ||
537 | case DAVINCI_AUDIO_WORD_28: | 548 | case DAVINCI_AUDIO_WORD_28: |
538 | fmt = 0x0D; | 549 | fmt = 0x0D; |
550 | rotate = 1; | ||
551 | mask = 0x0fffffff; | ||
539 | break; | 552 | break; |
540 | 553 | ||
541 | case DAVINCI_AUDIO_WORD_32: | 554 | case DAVINCI_AUDIO_WORD_32: |
542 | fmt = 0x0F; | 555 | fmt = 0x0F; |
556 | rotate = 0; | ||
557 | mask = 0xffffffff; | ||
543 | break; | 558 | break; |
544 | 559 | ||
545 | default: | 560 | default: |
@@ -550,6 +565,13 @@ static int davinci_config_channel_size(struct davinci_audio_dev *dev, | |||
550 | RXSSZ(fmt), RXSSZ(0x0F)); | 565 | RXSSZ(fmt), RXSSZ(0x0F)); |
551 | mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, | 566 | mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, |
552 | TXSSZ(fmt), TXSSZ(0x0F)); | 567 | TXSSZ(fmt), TXSSZ(0x0F)); |
568 | mcasp_mod_bits(dev->base + DAVINCI_MCASP_TXFMT_REG, TXROT(rotate), | ||
569 | TXROT(7)); | ||
570 | mcasp_mod_bits(dev->base + DAVINCI_MCASP_RXFMT_REG, RXROT(rotate), | ||
571 | RXROT(7)); | ||
572 | mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, mask); | ||
573 | mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, mask); | ||
574 | |||
553 | return 0; | 575 | return 0; |
554 | } | 576 | } |
555 | 577 | ||
@@ -638,7 +660,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) | |||
638 | printk(KERN_ERR "playback tdm slot %d not supported\n", | 660 | printk(KERN_ERR "playback tdm slot %d not supported\n", |
639 | dev->tdm_slots); | 661 | dev->tdm_slots); |
640 | 662 | ||
641 | mcasp_set_reg(dev->base + DAVINCI_MCASP_TXMASK_REG, 0xFFFFFFFF); | ||
642 | mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); | 663 | mcasp_clr_bits(dev->base + DAVINCI_MCASP_TXFMCTL_REG, FSXDUR); |
643 | } else { | 664 | } else { |
644 | /* bit stream is MSB first with no delay */ | 665 | /* bit stream is MSB first with no delay */ |
@@ -655,7 +676,6 @@ static void davinci_hw_param(struct davinci_audio_dev *dev, int stream) | |||
655 | printk(KERN_ERR "capture tdm slot %d not supported\n", | 676 | printk(KERN_ERR "capture tdm slot %d not supported\n", |
656 | dev->tdm_slots); | 677 | dev->tdm_slots); |
657 | 678 | ||
658 | mcasp_set_reg(dev->base + DAVINCI_MCASP_RXMASK_REG, 0xFFFFFFFF); | ||
659 | mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); | 679 | mcasp_clr_bits(dev->base + DAVINCI_MCASP_RXFMCTL_REG, FSRDUR); |
660 | } | 680 | } |
661 | } | 681 | } |
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c index 9ff62e3a9b1d..6096d22283e6 100644 --- a/sound/soc/fsl/mpc5200_dma.c +++ b/sound/soc/fsl/mpc5200_dma.c | |||
@@ -447,6 +447,7 @@ int mpc5200_audio_dma_create(struct of_device *op) | |||
447 | int size, irq, rc; | 447 | int size, irq, rc; |
448 | const __be32 *prop; | 448 | const __be32 *prop; |
449 | void __iomem *regs; | 449 | void __iomem *regs; |
450 | int ret; | ||
450 | 451 | ||
451 | /* Fetch the registers and IRQ of the PSC */ | 452 | /* Fetch the registers and IRQ of the PSC */ |
452 | irq = irq_of_parse_and_map(op->node, 0); | 453 | irq = irq_of_parse_and_map(op->node, 0); |
@@ -463,14 +464,16 @@ int mpc5200_audio_dma_create(struct of_device *op) | |||
463 | /* Allocate and initialize the driver private data */ | 464 | /* Allocate and initialize the driver private data */ |
464 | psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); | 465 | psc_dma = kzalloc(sizeof *psc_dma, GFP_KERNEL); |
465 | if (!psc_dma) { | 466 | if (!psc_dma) { |
466 | iounmap(regs); | 467 | ret = -ENOMEM; |
467 | return -ENOMEM; | 468 | goto out_unmap; |
468 | } | 469 | } |
469 | 470 | ||
470 | /* Get the PSC ID */ | 471 | /* Get the PSC ID */ |
471 | prop = of_get_property(op->node, "cell-index", &size); | 472 | prop = of_get_property(op->node, "cell-index", &size); |
472 | if (!prop || size < sizeof *prop) | 473 | if (!prop || size < sizeof *prop) { |
473 | return -ENODEV; | 474 | ret = -ENODEV; |
475 | goto out_free; | ||
476 | } | ||
474 | 477 | ||
475 | spin_lock_init(&psc_dma->lock); | 478 | spin_lock_init(&psc_dma->lock); |
476 | mutex_init(&psc_dma->mutex); | 479 | mutex_init(&psc_dma->mutex); |
@@ -493,9 +496,8 @@ int mpc5200_audio_dma_create(struct of_device *op) | |||
493 | if (!psc_dma->capture.bcom_task || | 496 | if (!psc_dma->capture.bcom_task || |
494 | !psc_dma->playback.bcom_task) { | 497 | !psc_dma->playback.bcom_task) { |
495 | dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); | 498 | dev_err(&op->dev, "Could not allocate bestcomm tasks\n"); |
496 | iounmap(regs); | 499 | ret = -ENODEV; |
497 | kfree(psc_dma); | 500 | goto out_free; |
498 | return -ENODEV; | ||
499 | } | 501 | } |
500 | 502 | ||
501 | /* Disable all interrupts and reset the PSC */ | 503 | /* Disable all interrupts and reset the PSC */ |
@@ -537,12 +539,8 @@ int mpc5200_audio_dma_create(struct of_device *op) | |||
537 | &psc_dma_bcom_irq_tx, IRQF_SHARED, | 539 | &psc_dma_bcom_irq_tx, IRQF_SHARED, |
538 | "psc-dma-playback", &psc_dma->playback); | 540 | "psc-dma-playback", &psc_dma->playback); |
539 | if (rc) { | 541 | if (rc) { |
540 | free_irq(psc_dma->irq, psc_dma); | 542 | ret = -ENODEV; |
541 | free_irq(psc_dma->capture.irq, | 543 | goto out_irq; |
542 | &psc_dma->capture); | ||
543 | free_irq(psc_dma->playback.irq, | ||
544 | &psc_dma->playback); | ||
545 | return -ENODEV; | ||
546 | } | 544 | } |
547 | 545 | ||
548 | /* Save what we've done so it can be found again later */ | 546 | /* Save what we've done so it can be found again later */ |
@@ -550,6 +548,15 @@ int mpc5200_audio_dma_create(struct of_device *op) | |||
550 | 548 | ||
551 | /* Tell the ASoC OF helpers about it */ | 549 | /* Tell the ASoC OF helpers about it */ |
552 | return snd_soc_register_platform(&mpc5200_audio_dma_platform); | 550 | return snd_soc_register_platform(&mpc5200_audio_dma_platform); |
551 | out_irq: | ||
552 | free_irq(psc_dma->irq, psc_dma); | ||
553 | free_irq(psc_dma->capture.irq, &psc_dma->capture); | ||
554 | free_irq(psc_dma->playback.irq, &psc_dma->playback); | ||
555 | out_free: | ||
556 | kfree(psc_dma); | ||
557 | out_unmap: | ||
558 | iounmap(regs); | ||
559 | return ret; | ||
553 | } | 560 | } |
554 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); | 561 | EXPORT_SYMBOL_GPL(mpc5200_audio_dma_create); |
555 | 562 | ||
diff --git a/sound/soc/imx/mx27vis_wm8974.c b/sound/soc/imx/mx27vis_wm8974.c index e4dcb539108a..0267d2d91685 100644 --- a/sound/soc/imx/mx27vis_wm8974.c +++ b/sound/soc/imx/mx27vis_wm8974.c | |||
@@ -157,7 +157,7 @@ static int mx27vis_hifi_hw_params(struct snd_pcm_substream *substream, | |||
157 | 157 | ||
158 | 158 | ||
159 | /* codec PLL input is 25 MHz */ | 159 | /* codec PLL input is 25 MHz */ |
160 | ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, | 160 | ret = codec_dai->ops->set_pll(codec_dai, IGNORED_ARG, IGNORED_ARG, |
161 | 25000000, pll_out); | 161 | 25000000, pll_out); |
162 | if (ret < 0) { | 162 | if (ret < 0) { |
163 | printk(KERN_ERR "Error when setting PLL input\n"); | 163 | printk(KERN_ERR "Error when setting PLL input\n"); |
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index b60b1dfbc435..0a505938e42b 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -22,6 +22,7 @@ | |||
22 | */ | 22 | */ |
23 | 23 | ||
24 | #include <linux/clk.h> | 24 | #include <linux/clk.h> |
25 | #include <linux/i2c.h> | ||
25 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
@@ -322,8 +323,6 @@ static struct snd_soc_card snd_soc_n810 = { | |||
322 | 323 | ||
323 | /* Audio private data */ | 324 | /* Audio private data */ |
324 | static struct aic3x_setup_data n810_aic33_setup = { | 325 | static struct aic3x_setup_data n810_aic33_setup = { |
325 | .i2c_bus = 2, | ||
326 | .i2c_address = 0x18, | ||
327 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, | 326 | .gpio_func[0] = AIC3X_GPIO1_FUNC_DISABLED, |
328 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, | 327 | .gpio_func[1] = AIC3X_GPIO2_FUNC_DIGITAL_MIC_INPUT, |
329 | }; | 328 | }; |
@@ -337,6 +336,13 @@ static struct snd_soc_device n810_snd_devdata = { | |||
337 | 336 | ||
338 | static struct platform_device *n810_snd_device; | 337 | static struct platform_device *n810_snd_device; |
339 | 338 | ||
339 | /* temporary i2c device creation until this can be moved into the machine | ||
340 | * support file. | ||
341 | */ | ||
342 | static struct i2c_board_info i2c_device[] = { | ||
343 | { I2C_BOARD_INFO("tlv320aic3x", 0x1b), } | ||
344 | }; | ||
345 | |||
340 | static int __init n810_soc_init(void) | 346 | static int __init n810_soc_init(void) |
341 | { | 347 | { |
342 | int err; | 348 | int err; |
@@ -345,6 +351,8 @@ static int __init n810_soc_init(void) | |||
345 | if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) | 351 | if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) |
346 | return -ENODEV; | 352 | return -ENODEV; |
347 | 353 | ||
354 | i2c_register_board_info(1, i2c_device, ARRAY_SIZE(i2c_device)); | ||
355 | |||
348 | n810_snd_device = platform_device_alloc("soc-audio", -1); | 356 | n810_snd_device = platform_device_alloc("soc-audio", -1); |
349 | if (!n810_snd_device) | 357 | if (!n810_snd_device) |
350 | return -ENOMEM; | 358 | return -ENOMEM; |
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 6a837ffd5d0b..3341f49402ca 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c | |||
@@ -139,27 +139,67 @@ static const unsigned long omap34xx_mcbsp_port[][2] = { | |||
139 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; | 139 | static const unsigned long omap34xx_mcbsp_port[][2] = {}; |
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) | ||
143 | { | ||
144 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
145 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
146 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | ||
147 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(mcbsp_data->bus_id); | ||
148 | int samples; | ||
149 | |||
150 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
151 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | ||
152 | samples = snd_pcm_lib_period_bytes(substream) >> 1; | ||
153 | else | ||
154 | samples = 1; | ||
155 | |||
156 | /* Configure McBSP internal buffer usage */ | ||
157 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
158 | omap_mcbsp_set_tx_threshold(mcbsp_data->bus_id, samples - 1); | ||
159 | else | ||
160 | omap_mcbsp_set_rx_threshold(mcbsp_data->bus_id, samples - 1); | ||
161 | } | ||
162 | |||
142 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, | 163 | static int omap_mcbsp_dai_startup(struct snd_pcm_substream *substream, |
143 | struct snd_soc_dai *dai) | 164 | struct snd_soc_dai *dai) |
144 | { | 165 | { |
145 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 166 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
146 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | 167 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; |
147 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 168 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
169 | int bus_id = mcbsp_data->bus_id; | ||
148 | int err = 0; | 170 | int err = 0; |
149 | 171 | ||
150 | if (cpu_is_omap343x() && mcbsp_data->bus_id == 1) { | 172 | if (!cpu_dai->active) |
173 | err = omap_mcbsp_request(bus_id); | ||
174 | |||
175 | if (cpu_is_omap343x()) { | ||
176 | int dma_op_mode = omap_mcbsp_get_dma_op_mode(bus_id); | ||
177 | int max_period; | ||
178 | |||
151 | /* | 179 | /* |
152 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. | 180 | * McBSP2 in OMAP3 has 1024 * 32-bit internal audio buffer. |
153 | * Set constraint for minimum buffer size to the same than FIFO | 181 | * Set constraint for minimum buffer size to the same than FIFO |
154 | * size in order to avoid underruns in playback startup because | 182 | * size in order to avoid underruns in playback startup because |
155 | * HW is keeping the DMA request active until FIFO is filled. | 183 | * HW is keeping the DMA request active until FIFO is filled. |
156 | */ | 184 | */ |
157 | snd_pcm_hw_constraint_minmax(substream->runtime, | 185 | if (bus_id == 1) |
158 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX); | 186 | snd_pcm_hw_constraint_minmax(substream->runtime, |
159 | } | 187 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, |
188 | 4096, UINT_MAX); | ||
160 | 189 | ||
161 | if (!cpu_dai->active) | 190 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
162 | err = omap_mcbsp_request(mcbsp_data->bus_id); | 191 | max_period = omap_mcbsp_get_max_tx_threshold(bus_id); |
192 | else | ||
193 | max_period = omap_mcbsp_get_max_rx_threshold(bus_id); | ||
194 | |||
195 | max_period++; | ||
196 | max_period <<= 1; | ||
197 | |||
198 | if (dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) | ||
199 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
200 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
201 | 32, max_period); | ||
202 | } | ||
163 | 203 | ||
164 | return err; | 204 | return err; |
165 | } | 205 | } |
@@ -215,7 +255,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
215 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); | 255 | struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); |
216 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; | 256 | struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs; |
217 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; | 257 | int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id; |
218 | int wlen, channels, wpf; | 258 | int wlen, channels, wpf, sync_mode = OMAP_DMA_SYNC_ELEMENT; |
219 | unsigned long port; | 259 | unsigned long port; |
220 | unsigned int format; | 260 | unsigned int format; |
221 | 261 | ||
@@ -231,6 +271,12 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
231 | } else if (cpu_is_omap343x()) { | 271 | } else if (cpu_is_omap343x()) { |
232 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; | 272 | dma = omap24xx_dma_reqs[bus_id][substream->stream]; |
233 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; | 273 | port = omap34xx_mcbsp_port[bus_id][substream->stream]; |
274 | omap_mcbsp_dai_dma_params[id][substream->stream].set_threshold = | ||
275 | omap_mcbsp_set_threshold; | ||
276 | /* TODO: Currently, MODE_ELEMENT == MODE_FRAME */ | ||
277 | if (omap_mcbsp_get_dma_op_mode(bus_id) == | ||
278 | MCBSP_DMA_MODE_THRESHOLD) | ||
279 | sync_mode = OMAP_DMA_SYNC_FRAME; | ||
234 | } else { | 280 | } else { |
235 | return -ENODEV; | 281 | return -ENODEV; |
236 | } | 282 | } |
@@ -238,6 +284,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream, | |||
238 | substream->stream ? "Audio Capture" : "Audio Playback"; | 284 | substream->stream ? "Audio Capture" : "Audio Playback"; |
239 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; | 285 | omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma; |
240 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; | 286 | omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port; |
287 | omap_mcbsp_dai_dma_params[id][substream->stream].sync_mode = sync_mode; | ||
241 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; | 288 | cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream]; |
242 | 289 | ||
243 | if (mcbsp_data->configured) { | 290 | if (mcbsp_data->configured) { |
@@ -321,11 +368,14 @@ static int omap_mcbsp_dai_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
321 | /* Generic McBSP register settings */ | 368 | /* Generic McBSP register settings */ |
322 | regs->spcr2 |= XINTM(3) | FREE; | 369 | regs->spcr2 |= XINTM(3) | FREE; |
323 | regs->spcr1 |= RINTM(3); | 370 | regs->spcr1 |= RINTM(3); |
324 | regs->rcr2 |= RFIG; | 371 | /* RFIG and XFIG are not defined in 34xx */ |
325 | regs->xcr2 |= XFIG; | 372 | if (!cpu_is_omap34xx()) { |
373 | regs->rcr2 |= RFIG; | ||
374 | regs->xcr2 |= XFIG; | ||
375 | } | ||
326 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { | 376 | if (cpu_is_omap2430() || cpu_is_omap34xx()) { |
327 | regs->xccr = DXENDLY(1) | XDMAEN; | 377 | regs->xccr = DXENDLY(1) | XDMAEN | XDISABLE; |
328 | regs->rccr = RFULL_CYCLE | RDMAEN; | 378 | regs->rccr = RFULL_CYCLE | RDMAEN | RDISABLE; |
329 | } | 379 | } |
330 | 380 | ||
331 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 381 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
@@ -462,6 +512,40 @@ static int omap_mcbsp_dai_set_clks_src(struct omap_mcbsp_data *mcbsp_data, | |||
462 | return 0; | 512 | return 0; |
463 | } | 513 | } |
464 | 514 | ||
515 | static int omap_mcbsp_dai_set_rcvr_src(struct omap_mcbsp_data *mcbsp_data, | ||
516 | int clk_id) | ||
517 | { | ||
518 | int sel_bit, set = 0; | ||
519 | u16 reg = OMAP2_CONTROL_DEVCONF0; | ||
520 | |||
521 | if (cpu_class_is_omap1()) | ||
522 | return -EINVAL; /* TODO: Can this be implemented for OMAP1? */ | ||
523 | if (mcbsp_data->bus_id != 0) | ||
524 | return -EINVAL; | ||
525 | |||
526 | switch (clk_id) { | ||
527 | case OMAP_MCBSP_CLKR_SRC_CLKX: | ||
528 | set = 1; | ||
529 | case OMAP_MCBSP_CLKR_SRC_CLKR: | ||
530 | sel_bit = 3; | ||
531 | break; | ||
532 | case OMAP_MCBSP_FSR_SRC_FSX: | ||
533 | set = 1; | ||
534 | case OMAP_MCBSP_FSR_SRC_FSR: | ||
535 | sel_bit = 4; | ||
536 | break; | ||
537 | default: | ||
538 | return -EINVAL; | ||
539 | } | ||
540 | |||
541 | if (set) | ||
542 | omap_ctrl_writel(omap_ctrl_readl(reg) | (1 << sel_bit), reg); | ||
543 | else | ||
544 | omap_ctrl_writel(omap_ctrl_readl(reg) & ~(1 << sel_bit), reg); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
465 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | 549 | static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
466 | int clk_id, unsigned int freq, | 550 | int clk_id, unsigned int freq, |
467 | int dir) | 551 | int dir) |
@@ -484,6 +568,13 @@ static int omap_mcbsp_dai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | |||
484 | case OMAP_MCBSP_SYSCLK_CLKR_EXT: | 568 | case OMAP_MCBSP_SYSCLK_CLKR_EXT: |
485 | regs->pcr0 |= SCLKME; | 569 | regs->pcr0 |= SCLKME; |
486 | break; | 570 | break; |
571 | |||
572 | case OMAP_MCBSP_CLKR_SRC_CLKR: | ||
573 | case OMAP_MCBSP_CLKR_SRC_CLKX: | ||
574 | case OMAP_MCBSP_FSR_SRC_FSR: | ||
575 | case OMAP_MCBSP_FSR_SRC_FSX: | ||
576 | err = omap_mcbsp_dai_set_rcvr_src(mcbsp_data, clk_id); | ||
577 | break; | ||
487 | default: | 578 | default: |
488 | err = -ENODEV; | 579 | err = -ENODEV; |
489 | } | 580 | } |
diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index c8147aace813..647d2f981ab0 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h | |||
@@ -32,6 +32,10 @@ enum omap_mcbsp_clksrg_clk { | |||
32 | OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ | 32 | OMAP_MCBSP_SYSCLK_CLK, /* Internal ICLK */ |
33 | OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ | 33 | OMAP_MCBSP_SYSCLK_CLKX_EXT, /* External CLKX pin */ |
34 | OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ | 34 | OMAP_MCBSP_SYSCLK_CLKR_EXT, /* External CLKR pin */ |
35 | OMAP_MCBSP_CLKR_SRC_CLKR, /* CLKR from CLKR pin */ | ||
36 | OMAP_MCBSP_CLKR_SRC_CLKX, /* CLKR from CLKX pin */ | ||
37 | OMAP_MCBSP_FSR_SRC_FSR, /* FSR from FSR pin */ | ||
38 | OMAP_MCBSP_FSR_SRC_FSX, /* FSR from FSX pin */ | ||
35 | }; | 39 | }; |
36 | 40 | ||
37 | /* McBSP dividers */ | 41 | /* McBSP dividers */ |
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 12e14c01068e..5735945788bf 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c | |||
@@ -162,7 +162,7 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
162 | */ | 162 | */ |
163 | dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; | 163 | dma_params.data_type = OMAP_DMA_DATA_TYPE_S16; |
164 | dma_params.trigger = dma_data->dma_req; | 164 | dma_params.trigger = dma_data->dma_req; |
165 | dma_params.sync_mode = OMAP_DMA_SYNC_ELEMENT; | 165 | dma_params.sync_mode = dma_data->sync_mode; |
166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 166 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
167 | dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; | 167 | dma_params.src_amode = OMAP_DMA_AMODE_POST_INC; |
168 | dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; | 168 | dma_params.dst_amode = OMAP_DMA_AMODE_CONSTANT; |
@@ -195,6 +195,9 @@ static int omap_pcm_prepare(struct snd_pcm_substream *substream) | |||
195 | else | 195 | else |
196 | omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); | 196 | omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ); |
197 | 197 | ||
198 | omap_set_dma_src_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
199 | omap_set_dma_dest_burst_mode(prtd->dma_ch, OMAP_DMA_DATA_BURST_16); | ||
200 | |||
198 | return 0; | 201 | return 0; |
199 | } | 202 | } |
200 | 203 | ||
@@ -202,6 +205,7 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
202 | { | 205 | { |
203 | struct snd_pcm_runtime *runtime = substream->runtime; | 206 | struct snd_pcm_runtime *runtime = substream->runtime; |
204 | struct omap_runtime_data *prtd = runtime->private_data; | 207 | struct omap_runtime_data *prtd = runtime->private_data; |
208 | struct omap_pcm_dma_data *dma_data = prtd->dma_data; | ||
205 | unsigned long flags; | 209 | unsigned long flags; |
206 | int ret = 0; | 210 | int ret = 0; |
207 | 211 | ||
@@ -211,6 +215,10 @@ static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
211 | case SNDRV_PCM_TRIGGER_RESUME: | 215 | case SNDRV_PCM_TRIGGER_RESUME: |
212 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 216 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
213 | prtd->period_index = 0; | 217 | prtd->period_index = 0; |
218 | /* Configure McBSP internal buffer usage */ | ||
219 | if (dma_data->set_threshold) | ||
220 | dma_data->set_threshold(substream); | ||
221 | |||
214 | omap_start_dma(prtd->dma_ch); | 222 | omap_start_dma(prtd->dma_ch); |
215 | break; | 223 | break; |
216 | 224 | ||
@@ -307,7 +315,7 @@ static struct snd_pcm_ops omap_pcm_ops = { | |||
307 | .mmap = omap_pcm_mmap, | 315 | .mmap = omap_pcm_mmap, |
308 | }; | 316 | }; |
309 | 317 | ||
310 | static u64 omap_pcm_dmamask = DMA_BIT_MASK(32); | 318 | static u64 omap_pcm_dmamask = DMA_BIT_MASK(64); |
311 | 319 | ||
312 | static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, | 320 | static int omap_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, |
313 | int stream) | 321 | int stream) |
@@ -357,7 +365,7 @@ static int omap_pcm_new(struct snd_card *card, struct snd_soc_dai *dai, | |||
357 | if (!card->dev->dma_mask) | 365 | if (!card->dev->dma_mask) |
358 | card->dev->dma_mask = &omap_pcm_dmamask; | 366 | card->dev->dma_mask = &omap_pcm_dmamask; |
359 | if (!card->dev->coherent_dma_mask) | 367 | if (!card->dev->coherent_dma_mask) |
360 | card->dev->coherent_dma_mask = DMA_BIT_MASK(32); | 368 | card->dev->coherent_dma_mask = DMA_BIT_MASK(64); |
361 | 369 | ||
362 | if (dai->playback.channels_min) { | 370 | if (dai->playback.channels_min) { |
363 | ret = omap_pcm_preallocate_dma_buffer(pcm, | 371 | ret = omap_pcm_preallocate_dma_buffer(pcm, |
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h index 8d9d26916b05..38a821dd4118 100644 --- a/sound/soc/omap/omap-pcm.h +++ b/sound/soc/omap/omap-pcm.h | |||
@@ -29,6 +29,8 @@ struct omap_pcm_dma_data { | |||
29 | char *name; /* stream identifier */ | 29 | char *name; /* stream identifier */ |
30 | int dma_req; /* DMA request line */ | 30 | int dma_req; /* DMA request line */ |
31 | unsigned long port_addr; /* transmit/receive register */ | 31 | unsigned long port_addr; /* transmit/receive register */ |
32 | int sync_mode; /* DMA sync mode */ | ||
33 | void (*set_threshold)(struct snd_pcm_substream *substream); | ||
32 | }; | 34 | }; |
33 | 35 | ||
34 | extern struct snd_soc_platform omap_soc_platform; | 36 | extern struct snd_soc_platform omap_soc_platform; |
diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index f7e5b7488c35..4a3f62d1f295 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c | |||
@@ -40,8 +40,10 @@ | |||
40 | #include "omap-pcm.h" | 40 | #include "omap-pcm.h" |
41 | #include "../codecs/twl4030.h" | 41 | #include "../codecs/twl4030.h" |
42 | 42 | ||
43 | #define TWL4030_INTBR_PMBR1 0x0D | 43 | /* TWL4030 PMBR1 Register */ |
44 | #define EXTMUTE(value) (value << 2) | 44 | #define TWL4030_INTBR_PMBR1 0x0D |
45 | /* TWL4030 PMBR1 Register GPIO6 mux bit */ | ||
46 | #define TWL4030_GPIO6_PWM0_MUTE(value) (value << 2) | ||
45 | 47 | ||
46 | static struct snd_soc_card snd_soc_sdp3430; | 48 | static struct snd_soc_card snd_soc_sdp3430; |
47 | 49 | ||
@@ -299,6 +301,7 @@ static struct platform_device *sdp3430_snd_device; | |||
299 | static int __init sdp3430_soc_init(void) | 301 | static int __init sdp3430_soc_init(void) |
300 | { | 302 | { |
301 | int ret; | 303 | int ret; |
304 | u8 pin_mux; | ||
302 | 305 | ||
303 | if (!machine_is_omap_3430sdp()) { | 306 | if (!machine_is_omap_3430sdp()) { |
304 | pr_debug("Not SDP3430!\n"); | 307 | pr_debug("Not SDP3430!\n"); |
@@ -318,8 +321,12 @@ static int __init sdp3430_soc_init(void) | |||
318 | *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ | 321 | *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ |
319 | 322 | ||
320 | /* Set TWL4030 GPIO6 as EXTMUTE signal */ | 323 | /* Set TWL4030 GPIO6 as EXTMUTE signal */ |
321 | twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, EXTMUTE(0x02), | 324 | twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, |
322 | TWL4030_MODULE_INTBR); | 325 | TWL4030_INTBR_PMBR1); |
326 | pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); | ||
327 | pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); | ||
328 | twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, | ||
329 | TWL4030_INTBR_PMBR1); | ||
323 | 330 | ||
324 | ret = platform_device_add(sdp3430_snd_device); | 331 | ret = platform_device_add(sdp3430_snd_device); |
325 | if (ret) | 332 | if (ret) |
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index 9f7c61e23daf..4c8d99a8d386 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c | |||
@@ -213,7 +213,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, | |||
213 | return ret; | 213 | return ret; |
214 | 214 | ||
215 | /* set SSP audio pll clock */ | 215 | /* set SSP audio pll clock */ |
216 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, acps); | 216 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, acps); |
217 | if (ret < 0) | 217 | if (ret < 0) |
218 | return ret; | 218 | return ret; |
219 | 219 | ||
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 5b9ed6464789..57f201c94ca8 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -305,8 +305,8 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, | |||
305 | /* | 305 | /* |
306 | * Configure the PLL frequency pxa27x and (afaik - pxa320 only) | 306 | * Configure the PLL frequency pxa27x and (afaik - pxa320 only) |
307 | */ | 307 | */ |
308 | static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, | 308 | static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, |
309 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 309 | int source, unsigned int freq_in, unsigned int freq_out) |
310 | { | 310 | { |
311 | struct ssp_priv *priv = cpu_dai->private_data; | 311 | struct ssp_priv *priv = cpu_dai->private_data; |
312 | struct ssp_device *ssp = priv->dev.ssp; | 312 | struct ssp_device *ssp = priv->dev.ssp; |
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c index 7330e5c5b9df..e9ae7b3a7e00 100644 --- a/sound/soc/pxa/pxa2xx-ac97.c +++ b/sound/soc/pxa/pxa2xx-ac97.c | |||
@@ -251,8 +251,8 @@ static int __devinit pxa2xx_ac97_dev_probe(struct platform_device *pdev) | |||
251 | 251 | ||
252 | for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) { | 252 | for (i = 0; i < ARRAY_SIZE(pxa_ac97_dai); i++) { |
253 | pxa_ac97_dai[i].dev = &pdev->dev; | 253 | pxa_ac97_dai[i].dev = &pdev->dev; |
254 | if (pdata && pdata->codec_pdata) | 254 | if (pdata && pdata->codec_pdata[0]) |
255 | pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata; | 255 | pxa_ac97_dai[i].ac97_pdata = pdata->codec_pdata[0]; |
256 | } | 256 | } |
257 | 257 | ||
258 | /* Punt most of the init to the SoC probe; we may need the machine | 258 | /* Punt most of the init to the SoC probe; we may need the machine |
diff --git a/sound/soc/pxa/zylonite.c b/sound/soc/pxa/zylonite.c index 9a386b4c4ed1..dd678ae24398 100644 --- a/sound/soc/pxa/zylonite.c +++ b/sound/soc/pxa/zylonite.c | |||
@@ -74,7 +74,8 @@ static const struct snd_soc_dapm_route audio_map[] = { | |||
74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) | 74 | static int zylonite_wm9713_init(struct snd_soc_codec *codec) |
75 | { | 75 | { |
76 | if (clk_pout) | 76 | if (clk_pout) |
77 | snd_soc_dai_set_pll(&codec->dai[0], 0, clk_get_rate(pout), 0); | 77 | snd_soc_dai_set_pll(&codec->dai[0], 0, 0, |
78 | clk_get_rate(pout), 0); | ||
78 | 79 | ||
79 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, | 80 | snd_soc_dapm_new_controls(codec, zylonite_dapm_widgets, |
80 | ARRAY_SIZE(zylonite_dapm_widgets)); | 81 | ARRAY_SIZE(zylonite_dapm_widgets)); |
@@ -128,7 +129,7 @@ static int zylonite_voice_hw_params(struct snd_pcm_substream *substream, | |||
128 | if (ret < 0) | 129 | if (ret < 0) |
129 | return ret; | 130 | return ret; |
130 | 131 | ||
131 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, pll_out); | 132 | ret = snd_soc_dai_set_pll(cpu_dai, 0, 0, 0, pll_out); |
132 | if (ret < 0) | 133 | if (ret < 0) |
133 | return ret; | 134 | return ret; |
134 | 135 | ||
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig index 808de5c5caa7..d7912f1e4627 100644 --- a/sound/soc/s3c24xx/Kconfig +++ b/sound/soc/s3c24xx/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config SND_S3C24XX_SOC | 1 | config SND_S3C24XX_SOC |
2 | tristate "SoC Audio for the Samsung S3CXXXX chips" | 2 | tristate "SoC Audio for the Samsung S3CXXXX chips" |
3 | depends on ARCH_S3C2410 | 3 | depends on ARCH_S3C2410 || ARCH_S3C64XX |
4 | select S3C64XX_DMA if ARCH_S3C64XX | ||
4 | help | 5 | help |
5 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
6 | the S3C24XX AC97 or I2S interfaces. You will also need to | 7 | the S3C24XX AC97 or I2S interfaces. You will also need to |
@@ -55,6 +56,15 @@ config SND_S3C24XX_SOC_JIVE_WM8750 | |||
55 | help | 56 | help |
56 | Sat Y if you want to add support for SoC audio on the Jive. | 57 | Sat Y if you want to add support for SoC audio on the Jive. |
57 | 58 | ||
59 | config SND_S3C64XX_SOC_WM8580 | ||
60 | tristate "SoC I2S Audio support for WM8580 on SMDK64XX" | ||
61 | depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410) | ||
62 | depends on BROKEN | ||
63 | select SND_SOC_WM8580 | ||
64 | select SND_S3C64XX_SOC_I2S | ||
65 | help | ||
66 | Sat Y if you want to add support for SoC audio on the SMDK64XX. | ||
67 | |||
58 | config SND_S3C24XX_SOC_SMDK2443_WM9710 | 68 | config SND_S3C24XX_SOC_SMDK2443_WM9710 |
59 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" | 69 | tristate "SoC AC97 Audio support for SMDK2443 - WM9710" |
60 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 | 70 | depends on SND_S3C24XX_SOC && MACH_SMDK2443 |
@@ -79,3 +89,22 @@ config SND_S3C24XX_SOC_S3C24XX_UDA134X | |||
79 | select SND_S3C24XX_SOC_I2S | 89 | select SND_S3C24XX_SOC_I2S |
80 | select SND_SOC_L3 | 90 | select SND_SOC_L3 |
81 | select SND_SOC_UDA134X | 91 | select SND_SOC_UDA134X |
92 | |||
93 | config SND_S3C24XX_SOC_SIMTEC | ||
94 | tristate | ||
95 | help | ||
96 | Internal node for common S3C24XX/Simtec suppor | ||
97 | |||
98 | config SND_S3C24XX_SOC_SIMTEC_TLV320AIC23 | ||
99 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" | ||
100 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 | ||
101 | select SND_S3C24XX_SOC_I2S | ||
102 | select SND_SOC_TLV320AIC23 | ||
103 | select SND_S3C24XX_SOC_SIMTEC | ||
104 | |||
105 | config SND_S3C24XX_SOC_SIMTEC_HERMES | ||
106 | tristate "SoC I2S Audio support for Simtec Hermes board" | ||
107 | depends on SND_S3C24XX_SOC && ARCH_S3C2410 | ||
108 | select SND_S3C24XX_SOC_I2S | ||
109 | select SND_SOC_TLV320AIC3X | ||
110 | select SND_S3C24XX_SOC_SIMTEC | ||
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile index eb219b016499..7790406f90b7 100644 --- a/sound/soc/s3c24xx/Makefile +++ b/sound/soc/s3c24xx/Makefile | |||
@@ -20,6 +20,10 @@ snd-soc-neo1973-gta02-wm8753-objs := neo1973_gta02_wm8753.o | |||
20 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o | 20 | snd-soc-smdk2443-wm9710-objs := smdk2443_wm9710.o |
21 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o | 21 | snd-soc-ln2440sbc-alc650-objs := ln2440sbc_alc650.o |
22 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o | 22 | snd-soc-s3c24xx-uda134x-objs := s3c24xx_uda134x.o |
23 | snd-soc-s3c24xx-simtec-objs := s3c24xx_simtec.o | ||
24 | snd-soc-s3c24xx-simtec-hermes-objs := s3c24xx_simtec_hermes.o | ||
25 | snd-soc-s3c24xx-simtec-tlv320aic23-objs := s3c24xx_simtec_tlv320aic23.o | ||
26 | snd-soc-smdk64xx-wm8580-objs := smdk64xx_wm8580.o | ||
23 | 27 | ||
24 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o | 28 | obj-$(CONFIG_SND_S3C24XX_SOC_JIVE_WM8750) += snd-soc-jive-wm8750.o |
25 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o | 29 | obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o |
@@ -27,3 +31,8 @@ obj-$(CONFIG_SND_S3C24XX_SOC_NEO1973_GTA02_WM8753) += snd-soc-neo1973-gta02-wm87 | |||
27 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o | 31 | obj-$(CONFIG_SND_S3C24XX_SOC_SMDK2443_WM9710) += snd-soc-smdk2443-wm9710.o |
28 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o | 32 | obj-$(CONFIG_SND_S3C24XX_SOC_LN2440SBC_ALC650) += snd-soc-ln2440sbc-alc650.o |
29 | obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o | 33 | obj-$(CONFIG_SND_S3C24XX_SOC_S3C24XX_UDA134X) += snd-soc-s3c24xx-uda134x.o |
34 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC) += snd-soc-s3c24xx-simtec.o | ||
35 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_HERMES) += snd-soc-s3c24xx-simtec-hermes.o | ||
36 | obj-$(CONFIG_SND_S3C24XX_SOC_SIMTEC_TLV320AIC23) += snd-soc-s3c24xx-simtec-tlv320aic23.o | ||
37 | obj-$(CONFIG_SND_S3C64XX_SOC_WM8580) += snd-soc-smdk64xx-wm8580.o | ||
38 | |||
diff --git a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c index 0c52e36ddd87..6ddd1b3b16b3 100644 --- a/sound/soc/s3c24xx/neo1973_gta02_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_gta02_wm8753.c | |||
@@ -119,7 +119,7 @@ static int neo1973_gta02_hifi_hw_params(struct snd_pcm_substream *substream, | |||
119 | return ret; | 119 | return ret; |
120 | 120 | ||
121 | /* codec PLL input is PCLK/4 */ | 121 | /* codec PLL input is PCLK/4 */ |
122 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, | 122 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, |
123 | iis_clkrate / 4, pll_out); | 123 | iis_clkrate / 4, pll_out); |
124 | if (ret < 0) | 124 | if (ret < 0) |
125 | return ret; | 125 | return ret; |
diff --git a/sound/soc/s3c24xx/neo1973_wm8753.c b/sound/soc/s3c24xx/neo1973_wm8753.c index 906709e6dd5f..16009eba9cba 100644 --- a/sound/soc/s3c24xx/neo1973_wm8753.c +++ b/sound/soc/s3c24xx/neo1973_wm8753.c | |||
@@ -137,7 +137,7 @@ static int neo1973_hifi_hw_params(struct snd_pcm_substream *substream, | |||
137 | return ret; | 137 | return ret; |
138 | 138 | ||
139 | /* codec PLL input is PCLK/4 */ | 139 | /* codec PLL input is PCLK/4 */ |
140 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, | 140 | ret = snd_soc_dai_set_pll(codec_dai, WM8753_PLL1, 0, |
141 | iis_clkrate / 4, pll_out); | 141 | iis_clkrate / 4, pll_out); |
142 | if (ret < 0) | 142 | if (ret < 0) |
143 | return ret; | 143 | return ret; |
diff --git a/sound/soc/s3c24xx/s3c-i2s-v2.c b/sound/soc/s3c24xx/s3c-i2s-v2.c index 1a283170ca92..11c45a37c631 100644 --- a/sound/soc/s3c24xx/s3c-i2s-v2.c +++ b/sound/soc/s3c24xx/s3c-i2s-v2.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <mach/dma.h> | 36 | #include <mach/dma.h> |
37 | 37 | ||
38 | #include "s3c-i2s-v2.h" | 38 | #include "s3c-i2s-v2.h" |
39 | #include "s3c24xx-pcm.h" | ||
39 | 40 | ||
40 | #undef S3C_IIS_V2_SUPPORTED | 41 | #undef S3C_IIS_V2_SUPPORTED |
41 | 42 | ||
@@ -229,6 +230,8 @@ static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | |||
229 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); | 230 | pr_debug("%s: IIS: CON=%x MOD=%x FIC=%x\n", __func__, con, mod, fic); |
230 | } | 231 | } |
231 | 232 | ||
233 | #define msecs_to_loops(t) (loops_per_jiffy / 1000 * HZ * t) | ||
234 | |||
232 | /* | 235 | /* |
233 | * Wait for the LR signal to allow synchronisation to the L/R clock | 236 | * Wait for the LR signal to allow synchronisation to the L/R clock |
234 | * from the codec. May only be needed for slave mode. | 237 | * from the codec. May only be needed for slave mode. |
@@ -236,19 +239,21 @@ static void s3c2412_snd_rxctrl(struct s3c_i2sv2_info *i2s, int on) | |||
236 | static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s) | 239 | static int s3c2412_snd_lrsync(struct s3c_i2sv2_info *i2s) |
237 | { | 240 | { |
238 | u32 iiscon; | 241 | u32 iiscon; |
239 | unsigned long timeout = jiffies + msecs_to_jiffies(5); | 242 | unsigned long loops = msecs_to_loops(5); |
240 | 243 | ||
241 | pr_debug("Entered %s\n", __func__); | 244 | pr_debug("Entered %s\n", __func__); |
242 | 245 | ||
243 | while (1) { | 246 | while (--loops) { |
244 | iiscon = readl(i2s->regs + S3C2412_IISCON); | 247 | iiscon = readl(i2s->regs + S3C2412_IISCON); |
245 | if (iiscon & S3C2412_IISCON_LRINDEX) | 248 | if (iiscon & S3C2412_IISCON_LRINDEX) |
246 | break; | 249 | break; |
247 | 250 | ||
248 | if (timeout < jiffies) { | 251 | cpu_relax(); |
249 | printk(KERN_ERR "%s: timeout\n", __func__); | 252 | } |
250 | return -ETIMEDOUT; | 253 | |
251 | } | 254 | if (!loops) { |
255 | printk(KERN_ERR "%s: timeout\n", __func__); | ||
256 | return -ETIMEDOUT; | ||
252 | } | 257 | } |
253 | 258 | ||
254 | return 0; | 259 | return 0; |
@@ -307,12 +312,15 @@ static int s3c2412_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
307 | 312 | ||
308 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 313 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
309 | case SND_SOC_DAIFMT_RIGHT_J: | 314 | case SND_SOC_DAIFMT_RIGHT_J: |
315 | iismod |= S3C2412_IISMOD_LR_RLOW; | ||
310 | iismod |= S3C2412_IISMOD_SDF_MSB; | 316 | iismod |= S3C2412_IISMOD_SDF_MSB; |
311 | break; | 317 | break; |
312 | case SND_SOC_DAIFMT_LEFT_J: | 318 | case SND_SOC_DAIFMT_LEFT_J: |
319 | iismod |= S3C2412_IISMOD_LR_RLOW; | ||
313 | iismod |= S3C2412_IISMOD_SDF_LSB; | 320 | iismod |= S3C2412_IISMOD_SDF_LSB; |
314 | break; | 321 | break; |
315 | case SND_SOC_DAIFMT_I2S: | 322 | case SND_SOC_DAIFMT_I2S: |
323 | iismod &= ~S3C2412_IISMOD_LR_RLOW; | ||
316 | iismod |= S3C2412_IISMOD_SDF_IIS; | 324 | iismod |= S3C2412_IISMOD_SDF_IIS; |
317 | break; | 325 | break; |
318 | default: | 326 | default: |
@@ -357,19 +365,19 @@ static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream, | |||
357 | #endif | 365 | #endif |
358 | 366 | ||
359 | #ifdef CONFIG_PLAT_S3C64XX | 367 | #ifdef CONFIG_PLAT_S3C64XX |
360 | iismod &= ~0x606; | 368 | iismod &= ~(S3C64XX_IISMOD_BLC_MASK | S3C2412_IISMOD_BCLK_MASK); |
361 | /* Sample size */ | 369 | /* Sample size */ |
362 | switch (params_format(params)) { | 370 | switch (params_format(params)) { |
363 | case SNDRV_PCM_FORMAT_S8: | 371 | case SNDRV_PCM_FORMAT_S8: |
364 | /* 8 bit sample, 16fs BCLK */ | 372 | /* 8 bit sample, 16fs BCLK */ |
365 | iismod |= 0x2004; | 373 | iismod |= (S3C64XX_IISMOD_BLC_8BIT | S3C2412_IISMOD_BCLK_16FS); |
366 | break; | 374 | break; |
367 | case SNDRV_PCM_FORMAT_S16_LE: | 375 | case SNDRV_PCM_FORMAT_S16_LE: |
368 | /* 16 bit sample, 32fs BCLK */ | 376 | /* 16 bit sample, 32fs BCLK */ |
369 | break; | 377 | break; |
370 | case SNDRV_PCM_FORMAT_S24_LE: | 378 | case SNDRV_PCM_FORMAT_S24_LE: |
371 | /* 24 bit sample, 48fs BCLK */ | 379 | /* 24 bit sample, 48fs BCLK */ |
372 | iismod |= 0x4002; | 380 | iismod |= (S3C64XX_IISMOD_BLC_24BIT | S3C2412_IISMOD_BCLK_48FS); |
373 | break; | 381 | break; |
374 | } | 382 | } |
375 | #endif | 383 | #endif |
@@ -387,6 +395,8 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
387 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | 395 | int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); |
388 | unsigned long irqs; | 396 | unsigned long irqs; |
389 | int ret = 0; | 397 | int ret = 0; |
398 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
399 | rtd->dai->cpu_dai->dma_data)->channel; | ||
390 | 400 | ||
391 | pr_debug("Entered %s\n", __func__); | 401 | pr_debug("Entered %s\n", __func__); |
392 | 402 | ||
@@ -416,6 +426,14 @@ static int s3c2412_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
416 | s3c2412_snd_txctrl(i2s, 1); | 426 | s3c2412_snd_txctrl(i2s, 1); |
417 | 427 | ||
418 | local_irq_restore(irqs); | 428 | local_irq_restore(irqs); |
429 | |||
430 | /* | ||
431 | * Load the next buffer to DMA to meet the reqirement | ||
432 | * of the auto reload mechanism of S3C24XX. | ||
433 | * This call won't bother S3C64XX. | ||
434 | */ | ||
435 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
436 | |||
419 | break; | 437 | break; |
420 | 438 | ||
421 | case SNDRV_PCM_TRIGGER_STOP: | 439 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -452,6 +470,31 @@ static int s3c2412_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai, | |||
452 | 470 | ||
453 | switch (div_id) { | 471 | switch (div_id) { |
454 | case S3C_I2SV2_DIV_BCLK: | 472 | case S3C_I2SV2_DIV_BCLK: |
473 | if (div > 3) { | ||
474 | /* convert value to bit field */ | ||
475 | |||
476 | switch (div) { | ||
477 | case 16: | ||
478 | div = S3C2412_IISMOD_BCLK_16FS; | ||
479 | break; | ||
480 | |||
481 | case 32: | ||
482 | div = S3C2412_IISMOD_BCLK_32FS; | ||
483 | break; | ||
484 | |||
485 | case 24: | ||
486 | div = S3C2412_IISMOD_BCLK_24FS; | ||
487 | break; | ||
488 | |||
489 | case 48: | ||
490 | div = S3C2412_IISMOD_BCLK_48FS; | ||
491 | break; | ||
492 | |||
493 | default: | ||
494 | return -EINVAL; | ||
495 | } | ||
496 | } | ||
497 | |||
455 | reg = readl(i2s->regs + S3C2412_IISMOD); | 498 | reg = readl(i2s->regs + S3C2412_IISMOD); |
456 | reg &= ~S3C2412_IISMOD_BCLK_MASK; | 499 | reg &= ~S3C2412_IISMOD_BCLK_MASK; |
457 | writel(reg | div, i2s->regs + S3C2412_IISMOD); | 500 | writel(reg | div, i2s->regs + S3C2412_IISMOD); |
@@ -611,7 +654,7 @@ int s3c_i2sv2_probe(struct platform_device *pdev, | |||
611 | } | 654 | } |
612 | 655 | ||
613 | i2s->iis_pclk = clk_get(dev, "iis"); | 656 | i2s->iis_pclk = clk_get(dev, "iis"); |
614 | if (i2s->iis_pclk == NULL) { | 657 | if (IS_ERR(i2s->iis_pclk)) { |
615 | dev_err(dev, "failed to get iis_clock\n"); | 658 | dev_err(dev, "failed to get iis_clock\n"); |
616 | iounmap(i2s->regs); | 659 | iounmap(i2s->regs); |
617 | return -ENOENT; | 660 | return -ENOENT; |
diff --git a/sound/soc/s3c24xx/s3c2443-ac97.c b/sound/soc/s3c24xx/s3c2443-ac97.c index bf16f20fcbb3..fc1beb0930b9 100644 --- a/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/sound/soc/s3c24xx/s3c2443-ac97.c | |||
@@ -290,6 +290,9 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | |||
290 | struct snd_soc_dai *dai) | 290 | struct snd_soc_dai *dai) |
291 | { | 291 | { |
292 | u32 ac_glbctrl; | 292 | u32 ac_glbctrl; |
293 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
294 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
295 | rtd->dai->cpu_dai->dma_data)->channel; | ||
293 | 296 | ||
294 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 297 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
295 | switch (cmd) { | 298 | switch (cmd) { |
@@ -312,6 +315,8 @@ static int s3c2443_ac97_trigger(struct snd_pcm_substream *substream, int cmd, | |||
312 | } | 315 | } |
313 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 316 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
314 | 317 | ||
318 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
319 | |||
315 | return 0; | 320 | return 0; |
316 | } | 321 | } |
317 | 322 | ||
@@ -334,6 +339,9 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
334 | int cmd, struct snd_soc_dai *dai) | 339 | int cmd, struct snd_soc_dai *dai) |
335 | { | 340 | { |
336 | u32 ac_glbctrl; | 341 | u32 ac_glbctrl; |
342 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
343 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
344 | rtd->dai->cpu_dai->dma_data)->channel; | ||
337 | 345 | ||
338 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 346 | ac_glbctrl = readl(s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
339 | switch (cmd) { | 347 | switch (cmd) { |
@@ -349,6 +357,8 @@ static int s3c2443_ac97_mic_trigger(struct snd_pcm_substream *substream, | |||
349 | } | 357 | } |
350 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); | 358 | writel(ac_glbctrl, s3c24xx_ac97.regs + S3C_AC97_GLBCTRL); |
351 | 359 | ||
360 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
361 | |||
352 | return 0; | 362 | return 0; |
353 | } | 363 | } |
354 | 364 | ||
diff --git a/sound/soc/s3c24xx/s3c24xx-i2s.c b/sound/soc/s3c24xx/s3c24xx-i2s.c index 556e35f0ab73..40e2c4790f0d 100644 --- a/sound/soc/s3c24xx/s3c24xx-i2s.c +++ b/sound/soc/s3c24xx/s3c24xx-i2s.c | |||
@@ -279,6 +279,9 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
279 | struct snd_soc_dai *dai) | 279 | struct snd_soc_dai *dai) |
280 | { | 280 | { |
281 | int ret = 0; | 281 | int ret = 0; |
282 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
283 | int channel = ((struct s3c24xx_pcm_dma_params *) | ||
284 | rtd->dai->cpu_dai->dma_data)->channel; | ||
282 | 285 | ||
283 | pr_debug("Entered %s\n", __func__); | 286 | pr_debug("Entered %s\n", __func__); |
284 | 287 | ||
@@ -296,6 +299,8 @@ static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd, | |||
296 | s3c24xx_snd_rxctrl(1); | 299 | s3c24xx_snd_rxctrl(1); |
297 | else | 300 | else |
298 | s3c24xx_snd_txctrl(1); | 301 | s3c24xx_snd_txctrl(1); |
302 | |||
303 | s3c2410_dma_ctrl(channel, S3C2410_DMAOP_STARTED); | ||
299 | break; | 304 | break; |
300 | case SNDRV_PCM_TRIGGER_STOP: | 305 | case SNDRV_PCM_TRIGGER_STOP: |
301 | case SNDRV_PCM_TRIGGER_SUSPEND: | 306 | case SNDRV_PCM_TRIGGER_SUSPEND: |
diff --git a/sound/soc/s3c24xx/s3c24xx-pcm.c b/sound/soc/s3c24xx/s3c24xx-pcm.c index eecfa5eba06b..5cbbdc80fde3 100644 --- a/sound/soc/s3c24xx/s3c24xx-pcm.c +++ b/sound/soc/s3c24xx/s3c24xx-pcm.c | |||
@@ -255,7 +255,6 @@ static int s3c24xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
255 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 255 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
256 | prtd->state |= ST_RUNNING; | 256 | prtd->state |= ST_RUNNING; |
257 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); | 257 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_START); |
258 | s3c2410_dma_ctrl(prtd->params->channel, S3C2410_DMAOP_STARTED); | ||
259 | break; | 258 | break; |
260 | 259 | ||
261 | case SNDRV_PCM_TRIGGER_STOP: | 260 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -318,6 +317,7 @@ static int s3c24xx_pcm_open(struct snd_pcm_substream *substream) | |||
318 | 317 | ||
319 | pr_debug("Entered %s\n", __func__); | 318 | pr_debug("Entered %s\n", __func__); |
320 | 319 | ||
320 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
321 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); | 321 | snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware); |
322 | 322 | ||
323 | prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); | 323 | prtd = kzalloc(sizeof(struct s3c24xx_runtime_data), GFP_KERNEL); |
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c new file mode 100644 index 000000000000..1966e0d5652d --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c | |||
@@ -0,0 +1,394 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <linux/i2c.h> | ||
16 | |||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | |||
22 | #include <plat/audio-simtec.h> | ||
23 | |||
24 | #include "s3c24xx-pcm.h" | ||
25 | #include "s3c24xx-i2s.h" | ||
26 | #include "s3c24xx_simtec.h" | ||
27 | |||
28 | static struct s3c24xx_audio_simtec_pdata *pdata; | ||
29 | static struct clk *xtal_clk; | ||
30 | |||
31 | static int spk_gain; | ||
32 | static int spk_unmute; | ||
33 | |||
34 | /** | ||
35 | * speaker_gain_get - read the speaker gain setting. | ||
36 | * @kcontrol: The control for the speaker gain. | ||
37 | * @ucontrol: The value that needs to be updated. | ||
38 | * | ||
39 | * Read the value for the AMP gain control. | ||
40 | */ | ||
41 | static int speaker_gain_get(struct snd_kcontrol *kcontrol, | ||
42 | struct snd_ctl_elem_value *ucontrol) | ||
43 | { | ||
44 | ucontrol->value.integer.value[0] = spk_gain; | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | /** | ||
49 | * speaker_gain_set - set the value of the speaker amp gain | ||
50 | * @value: The value to write. | ||
51 | */ | ||
52 | static void speaker_gain_set(int value) | ||
53 | { | ||
54 | gpio_set_value_cansleep(pdata->amp_gain[0], value & 1); | ||
55 | gpio_set_value_cansleep(pdata->amp_gain[1], value >> 1); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * speaker_gain_put - set the speaker gain setting. | ||
60 | * @kcontrol: The control for the speaker gain. | ||
61 | * @ucontrol: The value that needs to be set. | ||
62 | * | ||
63 | * Set the value of the speaker gain from the specified | ||
64 | * @ucontrol setting. | ||
65 | * | ||
66 | * Note, if the speaker amp is muted, then we do not set a gain value | ||
67 | * as at-least one of the ICs that is fitted will try and power up even | ||
68 | * if the main control is set to off. | ||
69 | */ | ||
70 | static int speaker_gain_put(struct snd_kcontrol *kcontrol, | ||
71 | struct snd_ctl_elem_value *ucontrol) | ||
72 | { | ||
73 | int value = ucontrol->value.integer.value[0]; | ||
74 | |||
75 | spk_gain = value; | ||
76 | |||
77 | if (!spk_unmute) | ||
78 | speaker_gain_set(value); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static const struct snd_kcontrol_new amp_gain_controls[] = { | ||
84 | SOC_SINGLE_EXT("Speaker Gain", 0, 0, 3, 0, | ||
85 | speaker_gain_get, speaker_gain_put), | ||
86 | }; | ||
87 | |||
88 | /** | ||
89 | * spk_unmute_state - set the unmute state of the speaker | ||
90 | * @to: zero to unmute, non-zero to ununmute. | ||
91 | */ | ||
92 | static void spk_unmute_state(int to) | ||
93 | { | ||
94 | pr_debug("%s: to=%d\n", __func__, to); | ||
95 | |||
96 | spk_unmute = to; | ||
97 | gpio_set_value(pdata->amp_gpio, to); | ||
98 | |||
99 | /* if we're umuting, also re-set the gain */ | ||
100 | if (to && pdata->amp_gain[0] > 0) | ||
101 | speaker_gain_set(spk_gain); | ||
102 | } | ||
103 | |||
104 | /** | ||
105 | * speaker_unmute_get - read the speaker unmute setting. | ||
106 | * @kcontrol: The control for the speaker gain. | ||
107 | * @ucontrol: The value that needs to be updated. | ||
108 | * | ||
109 | * Read the value for the AMP gain control. | ||
110 | */ | ||
111 | static int speaker_unmute_get(struct snd_kcontrol *kcontrol, | ||
112 | struct snd_ctl_elem_value *ucontrol) | ||
113 | { | ||
114 | ucontrol->value.integer.value[0] = spk_unmute; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * speaker_unmute_put - set the speaker unmute setting. | ||
120 | * @kcontrol: The control for the speaker gain. | ||
121 | * @ucontrol: The value that needs to be set. | ||
122 | * | ||
123 | * Set the value of the speaker gain from the specified | ||
124 | * @ucontrol setting. | ||
125 | */ | ||
126 | static int speaker_unmute_put(struct snd_kcontrol *kcontrol, | ||
127 | struct snd_ctl_elem_value *ucontrol) | ||
128 | { | ||
129 | spk_unmute_state(ucontrol->value.integer.value[0]); | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | /* This is added as a manual control as the speaker amps create clicks | ||
134 | * when their power state is changed, which are far more noticeable than | ||
135 | * anything produced by the CODEC itself. | ||
136 | */ | ||
137 | static const struct snd_kcontrol_new amp_unmute_controls[] = { | ||
138 | SOC_SINGLE_EXT("Speaker Switch", 0, 0, 1, 0, | ||
139 | speaker_unmute_get, speaker_unmute_put), | ||
140 | }; | ||
141 | |||
142 | void simtec_audio_init(struct snd_soc_codec *codec) | ||
143 | { | ||
144 | if (pdata->amp_gpio > 0) { | ||
145 | pr_debug("%s: adding amp routes\n", __func__); | ||
146 | |||
147 | snd_soc_add_controls(codec, amp_unmute_controls, | ||
148 | ARRAY_SIZE(amp_unmute_controls)); | ||
149 | } | ||
150 | |||
151 | if (pdata->amp_gain[0] > 0) { | ||
152 | pr_debug("%s: adding amp controls\n", __func__); | ||
153 | snd_soc_add_controls(codec, amp_gain_controls, | ||
154 | ARRAY_SIZE(amp_gain_controls)); | ||
155 | } | ||
156 | } | ||
157 | EXPORT_SYMBOL_GPL(simtec_audio_init); | ||
158 | |||
159 | #define CODEC_CLOCK 12000000 | ||
160 | |||
161 | /** | ||
162 | * simtec_hw_params - update hardware parameters | ||
163 | * @substream: The audio substream instance. | ||
164 | * @params: The parameters requested. | ||
165 | * | ||
166 | * Update the codec data routing and configuration settings | ||
167 | * from the supplied data. | ||
168 | */ | ||
169 | static int simtec_hw_params(struct snd_pcm_substream *substream, | ||
170 | struct snd_pcm_hw_params *params) | ||
171 | { | ||
172 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
173 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
174 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
175 | int ret; | ||
176 | |||
177 | /* Set the CODEC as the bus clock master, I2S */ | ||
178 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | ||
179 | SND_SOC_DAIFMT_NB_NF | | ||
180 | SND_SOC_DAIFMT_CBM_CFM); | ||
181 | if (ret) { | ||
182 | pr_err("%s: failed set cpu dai format\n", __func__); | ||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | /* Set the CODEC as the bus clock master */ | ||
187 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | | ||
188 | SND_SOC_DAIFMT_NB_NF | | ||
189 | SND_SOC_DAIFMT_CBM_CFM); | ||
190 | if (ret) { | ||
191 | pr_err("%s: failed set codec dai format\n", __func__); | ||
192 | return ret; | ||
193 | } | ||
194 | |||
195 | ret = snd_soc_dai_set_sysclk(codec_dai, 0, | ||
196 | CODEC_CLOCK, SND_SOC_CLOCK_IN); | ||
197 | if (ret) { | ||
198 | pr_err( "%s: failed setting codec sysclk\n", __func__); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | if (pdata->use_mpllin) { | ||
203 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C24XX_CLKSRC_MPLL, | ||
204 | 0, SND_SOC_CLOCK_OUT); | ||
205 | |||
206 | if (ret) { | ||
207 | pr_err("%s: failed to set MPLLin as clksrc\n", | ||
208 | __func__); | ||
209 | return ret; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | if (pdata->output_cdclk) { | ||
214 | int cdclk_scale; | ||
215 | |||
216 | cdclk_scale = clk_get_rate(xtal_clk) / CODEC_CLOCK; | ||
217 | cdclk_scale--; | ||
218 | |||
219 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER, | ||
220 | cdclk_scale); | ||
221 | } | ||
222 | |||
223 | return 0; | ||
224 | } | ||
225 | |||
226 | static int simtec_call_startup(struct s3c24xx_audio_simtec_pdata *pd) | ||
227 | { | ||
228 | /* call any board supplied startup code, this currently only | ||
229 | * covers the bast/vr1000 which have a CPLD in the way of the | ||
230 | * LRCLK */ | ||
231 | if (pd->startup) | ||
232 | pd->startup(); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | static struct snd_soc_ops simtec_snd_ops = { | ||
238 | .hw_params = simtec_hw_params, | ||
239 | }; | ||
240 | |||
241 | /** | ||
242 | * attach_gpio_amp - get and configure the necessary gpios | ||
243 | * @dev: The device we're probing. | ||
244 | * @pd: The platform data supplied by the board. | ||
245 | * | ||
246 | * If there is a GPIO based amplifier attached to the board, claim | ||
247 | * the necessary GPIO lines for it, and set default values. | ||
248 | */ | ||
249 | static int attach_gpio_amp(struct device *dev, | ||
250 | struct s3c24xx_audio_simtec_pdata *pd) | ||
251 | { | ||
252 | int ret; | ||
253 | |||
254 | /* attach gpio amp gain (if any) */ | ||
255 | if (pdata->amp_gain[0] > 0) { | ||
256 | ret = gpio_request(pd->amp_gain[0], "gpio-amp-gain0"); | ||
257 | if (ret) { | ||
258 | dev_err(dev, "cannot get amp gpio gain0\n"); | ||
259 | return ret; | ||
260 | } | ||
261 | |||
262 | ret = gpio_request(pd->amp_gain[1], "gpio-amp-gain1"); | ||
263 | if (ret) { | ||
264 | dev_err(dev, "cannot get amp gpio gain1\n"); | ||
265 | gpio_free(pdata->amp_gain[0]); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | gpio_direction_output(pd->amp_gain[0], 0); | ||
270 | gpio_direction_output(pd->amp_gain[1], 0); | ||
271 | } | ||
272 | |||
273 | /* note, curently we assume GPA0 isn't valid amp */ | ||
274 | if (pdata->amp_gpio > 0) { | ||
275 | ret = gpio_request(pd->amp_gpio, "gpio-amp"); | ||
276 | if (ret) { | ||
277 | dev_err(dev, "cannot get amp gpio %d (%d)\n", | ||
278 | pd->amp_gpio, ret); | ||
279 | goto err_amp; | ||
280 | } | ||
281 | |||
282 | /* set the amp off at startup */ | ||
283 | spk_unmute_state(0); | ||
284 | } | ||
285 | |||
286 | return 0; | ||
287 | |||
288 | err_amp: | ||
289 | if (pd->amp_gain[0] > 0) { | ||
290 | gpio_free(pd->amp_gain[0]); | ||
291 | gpio_free(pd->amp_gain[1]); | ||
292 | } | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | static void detach_gpio_amp(struct s3c24xx_audio_simtec_pdata *pd) | ||
298 | { | ||
299 | if (pd->amp_gain[0] > 0) { | ||
300 | gpio_free(pd->amp_gain[0]); | ||
301 | gpio_free(pd->amp_gain[1]); | ||
302 | } | ||
303 | |||
304 | if (pd->amp_gpio > 0) | ||
305 | gpio_free(pd->amp_gpio); | ||
306 | } | ||
307 | |||
308 | #ifdef CONFIG_PM | ||
309 | int simtec_audio_resume(struct device *dev) | ||
310 | { | ||
311 | simtec_call_startup(pdata); | ||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | struct dev_pm_ops simtec_audio_pmops = { | ||
316 | .resume = simtec_audio_resume, | ||
317 | }; | ||
318 | EXPORT_SYMBOL_GPL(simtec_audio_pmops); | ||
319 | #endif | ||
320 | |||
321 | int __devinit simtec_audio_core_probe(struct platform_device *pdev, | ||
322 | struct snd_soc_device *socdev) | ||
323 | { | ||
324 | struct platform_device *snd_dev; | ||
325 | int ret; | ||
326 | |||
327 | socdev->card->dai_link->ops = &simtec_snd_ops; | ||
328 | |||
329 | pdata = pdev->dev.platform_data; | ||
330 | if (!pdata) { | ||
331 | dev_err(&pdev->dev, "no platform data supplied\n"); | ||
332 | return -EINVAL; | ||
333 | } | ||
334 | |||
335 | simtec_call_startup(pdata); | ||
336 | |||
337 | xtal_clk = clk_get(&pdev->dev, "xtal"); | ||
338 | if (IS_ERR(xtal_clk)) { | ||
339 | dev_err(&pdev->dev, "could not get clkout0\n"); | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | |||
343 | dev_info(&pdev->dev, "xtal rate is %ld\n", clk_get_rate(xtal_clk)); | ||
344 | |||
345 | ret = attach_gpio_amp(&pdev->dev, pdata); | ||
346 | if (ret) | ||
347 | goto err_clk; | ||
348 | |||
349 | snd_dev = platform_device_alloc("soc-audio", -1); | ||
350 | if (!snd_dev) { | ||
351 | dev_err(&pdev->dev, "failed to alloc soc-audio devicec\n"); | ||
352 | ret = -ENOMEM; | ||
353 | goto err_gpio; | ||
354 | } | ||
355 | |||
356 | platform_set_drvdata(snd_dev, socdev); | ||
357 | socdev->dev = &snd_dev->dev; | ||
358 | |||
359 | ret = platform_device_add(snd_dev); | ||
360 | if (ret) { | ||
361 | dev_err(&pdev->dev, "failed to add soc-audio dev\n"); | ||
362 | goto err_pdev; | ||
363 | } | ||
364 | |||
365 | platform_set_drvdata(pdev, snd_dev); | ||
366 | return 0; | ||
367 | |||
368 | err_pdev: | ||
369 | platform_device_put(snd_dev); | ||
370 | |||
371 | err_gpio: | ||
372 | detach_gpio_amp(pdata); | ||
373 | |||
374 | err_clk: | ||
375 | clk_put(xtal_clk); | ||
376 | return ret; | ||
377 | } | ||
378 | EXPORT_SYMBOL_GPL(simtec_audio_core_probe); | ||
379 | |||
380 | int __devexit simtec_audio_remove(struct platform_device *pdev) | ||
381 | { | ||
382 | struct platform_device *snd_dev = platform_get_drvdata(pdev); | ||
383 | |||
384 | platform_device_unregister(snd_dev); | ||
385 | |||
386 | detach_gpio_amp(pdata); | ||
387 | clk_put(xtal_clk); | ||
388 | return 0; | ||
389 | } | ||
390 | EXPORT_SYMBOL_GPL(simtec_audio_remove); | ||
391 | |||
392 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
393 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio common support"); | ||
394 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h new file mode 100644 index 000000000000..2714203af161 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec.h | |||
@@ -0,0 +1,22 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec.h | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | extern void simtec_audio_init(struct snd_soc_codec *codec); | ||
11 | |||
12 | extern int simtec_audio_core_probe(struct platform_device *pdev, | ||
13 | struct snd_soc_device *socdev); | ||
14 | |||
15 | extern int simtec_audio_remove(struct platform_device *pdev); | ||
16 | |||
17 | #ifdef CONFIG_PM | ||
18 | extern struct dev_pm_ops simtec_audio_pmops; | ||
19 | #define simtec_audio_pm &simtec_audio_pmops | ||
20 | #else | ||
21 | #define simtec_audio_pm NULL | ||
22 | #endif | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c new file mode 100644 index 000000000000..8346bd96eaf5 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec_hermes.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <sound/soc-dapm.h> | ||
18 | |||
19 | #include <plat/audio-simtec.h> | ||
20 | |||
21 | #include "s3c24xx-pcm.h" | ||
22 | #include "s3c24xx-i2s.h" | ||
23 | #include "s3c24xx_simtec.h" | ||
24 | |||
25 | #include "../codecs/tlv320aic3x.h" | ||
26 | |||
27 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | ||
28 | SND_SOC_DAPM_LINE("GSM Out", NULL), | ||
29 | SND_SOC_DAPM_LINE("GSM In", NULL), | ||
30 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
31 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
32 | SND_SOC_DAPM_LINE("ZV", NULL), | ||
33 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
34 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
35 | }; | ||
36 | |||
37 | static const struct snd_soc_dapm_route base_map[] = { | ||
38 | /* Headphone connected to HP{L,R}OUT and HP{L,R}COM */ | ||
39 | |||
40 | { "Headphone Jack", NULL, "HPLOUT" }, | ||
41 | { "Headphone Jack", NULL, "HPLCOM" }, | ||
42 | { "Headphone Jack", NULL, "HPROUT" }, | ||
43 | { "Headphone Jack", NULL, "HPRCOM" }, | ||
44 | |||
45 | /* ZV connected to Line1 */ | ||
46 | |||
47 | { "LINE1L", NULL, "ZV" }, | ||
48 | { "LINE1R", NULL, "ZV" }, | ||
49 | |||
50 | /* Line In connected to Line2 */ | ||
51 | |||
52 | { "LINE2L", NULL, "Line In" }, | ||
53 | { "LINE2R", NULL, "Line In" }, | ||
54 | |||
55 | /* Microphone connected to MIC3R and MIC_BIAS */ | ||
56 | |||
57 | { "MIC3L", NULL, "Mic Jack" }, | ||
58 | |||
59 | /* GSM connected to MONO_LOUT and MIC3L (in) */ | ||
60 | |||
61 | { "GSM Out", NULL, "MONO_LOUT" }, | ||
62 | { "MIC3L", NULL, "GSM In" }, | ||
63 | |||
64 | /* Speaker is connected to LINEOUT{LN,LP,RN,RP}, however we are | ||
65 | * not using the DAPM to power it up and down as there it makes | ||
66 | * a click when powering up. */ | ||
67 | }; | ||
68 | |||
69 | /** | ||
70 | * simtec_hermes_init - initialise and add controls | ||
71 | * @codec; The codec instance to attach to. | ||
72 | * | ||
73 | * Attach our controls and configure the necessary codec | ||
74 | * mappings for our sound card instance. | ||
75 | */ | ||
76 | static int simtec_hermes_init(struct snd_soc_codec *codec) | ||
77 | { | ||
78 | snd_soc_dapm_new_controls(codec, dapm_widgets, | ||
79 | ARRAY_SIZE(dapm_widgets)); | ||
80 | |||
81 | snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); | ||
82 | |||
83 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
84 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
85 | snd_soc_dapm_enable_pin(codec, "Line Out"); | ||
86 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
87 | |||
88 | simtec_audio_init(codec); | ||
89 | snd_soc_dapm_sync(codec); | ||
90 | |||
91 | return 0; | ||
92 | } | ||
93 | |||
94 | static struct aic3x_setup_data codec_setup = { | ||
95 | }; | ||
96 | |||
97 | static struct snd_soc_dai_link simtec_dai_aic33 = { | ||
98 | .name = "tlv320aic33", | ||
99 | .stream_name = "TLV320AIC33", | ||
100 | .cpu_dai = &s3c24xx_i2s_dai, | ||
101 | .codec_dai = &aic3x_dai, | ||
102 | .init = simtec_hermes_init, | ||
103 | }; | ||
104 | |||
105 | /* simtec audio machine driver */ | ||
106 | static struct snd_soc_card snd_soc_machine_simtec_aic33 = { | ||
107 | .name = "Simtec-Hermes", | ||
108 | .platform = &s3c24xx_soc_platform, | ||
109 | .dai_link = &simtec_dai_aic33, | ||
110 | .num_links = 1, | ||
111 | }; | ||
112 | |||
113 | /* simtec audio subsystem */ | ||
114 | static struct snd_soc_device simtec_snd_devdata_aic33 = { | ||
115 | .card = &snd_soc_machine_simtec_aic33, | ||
116 | .codec_dev = &soc_codec_dev_aic3x, | ||
117 | .codec_data = &codec_setup, | ||
118 | }; | ||
119 | |||
120 | static int __devinit simtec_audio_hermes_probe(struct platform_device *pd) | ||
121 | { | ||
122 | dev_info(&pd->dev, "probing....\n"); | ||
123 | return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic33); | ||
124 | } | ||
125 | |||
126 | static struct platform_driver simtec_audio_hermes_platdrv = { | ||
127 | .driver = { | ||
128 | .owner = THIS_MODULE, | ||
129 | .name = "s3c24xx-simtec-hermes-snd", | ||
130 | .pm = simtec_audio_pm, | ||
131 | }, | ||
132 | .probe = simtec_audio_hermes_probe, | ||
133 | .remove = __devexit_p(simtec_audio_remove), | ||
134 | }; | ||
135 | |||
136 | MODULE_ALIAS("platform:s3c24xx-simtec-hermes-snd"); | ||
137 | |||
138 | static int __init simtec_hermes_modinit(void) | ||
139 | { | ||
140 | return platform_driver_register(&simtec_audio_hermes_platdrv); | ||
141 | } | ||
142 | |||
143 | static void __exit simtec_hermes_modexit(void) | ||
144 | { | ||
145 | platform_driver_unregister(&simtec_audio_hermes_platdrv); | ||
146 | } | ||
147 | |||
148 | module_init(simtec_hermes_modinit); | ||
149 | module_exit(simtec_hermes_modexit); | ||
150 | |||
151 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
152 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | ||
153 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c new file mode 100644 index 000000000000..25797e096175 --- /dev/null +++ b/sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | |||
@@ -0,0 +1,137 @@ | |||
1 | /* sound/soc/s3c24xx/s3c24xx_simtec_tlv320aic23.c | ||
2 | * | ||
3 | * Copyright 2009 Simtec Electronics | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <linux/module.h> | ||
11 | #include <linux/clk.h> | ||
12 | #include <linux/platform_device.h> | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include <sound/soc-dapm.h> | ||
18 | |||
19 | #include <plat/audio-simtec.h> | ||
20 | |||
21 | #include "s3c24xx-pcm.h" | ||
22 | #include "s3c24xx-i2s.h" | ||
23 | #include "s3c24xx_simtec.h" | ||
24 | |||
25 | #include "../codecs/tlv320aic23.h" | ||
26 | |||
27 | /* supported machines: | ||
28 | * | ||
29 | * Machine Connections AMP | ||
30 | * ------- ----------- --- | ||
31 | * BAST MIC, HPOUT, LOUT, LIN TPA2001D1 (HPOUTL,R) (gain hardwired) | ||
32 | * VR1000 HPOUT, LIN None | ||
33 | * VR2000 LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | ||
34 | * DePicture LIN, LOUT, MIC, HP LM4871 (HPOUTL,R) | ||
35 | * Anubis LIN, LOUT, MIC, HP TPA2001D1 (HPOUTL,R) | ||
36 | */ | ||
37 | |||
38 | static const struct snd_soc_dapm_widget dapm_widgets[] = { | ||
39 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
40 | SND_SOC_DAPM_LINE("Line In", NULL), | ||
41 | SND_SOC_DAPM_LINE("Line Out", NULL), | ||
42 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
43 | }; | ||
44 | |||
45 | static const struct snd_soc_dapm_route base_map[] = { | ||
46 | { "Headphone Jack", NULL, "LHPOUT"}, | ||
47 | { "Headphone Jack", NULL, "RHPOUT"}, | ||
48 | |||
49 | { "Line Out", NULL, "LOUT" }, | ||
50 | { "Line Out", NULL, "ROUT" }, | ||
51 | |||
52 | { "LLINEIN", NULL, "Line In"}, | ||
53 | { "RLINEIN", NULL, "Line In"}, | ||
54 | |||
55 | { "MICIN", NULL, "Mic Jack"}, | ||
56 | }; | ||
57 | |||
58 | /** | ||
59 | * simtec_tlv320aic23_init - initialise and add controls | ||
60 | * @codec; The codec instance to attach to. | ||
61 | * | ||
62 | * Attach our controls and configure the necessary codec | ||
63 | * mappings for our sound card instance. | ||
64 | */ | ||
65 | static int simtec_tlv320aic23_init(struct snd_soc_codec *codec) | ||
66 | { | ||
67 | snd_soc_dapm_new_controls(codec, dapm_widgets, | ||
68 | ARRAY_SIZE(dapm_widgets)); | ||
69 | |||
70 | snd_soc_dapm_add_routes(codec, base_map, ARRAY_SIZE(base_map)); | ||
71 | |||
72 | snd_soc_dapm_enable_pin(codec, "Headphone Jack"); | ||
73 | snd_soc_dapm_enable_pin(codec, "Line In"); | ||
74 | snd_soc_dapm_enable_pin(codec, "Line Out"); | ||
75 | snd_soc_dapm_enable_pin(codec, "Mic Jack"); | ||
76 | |||
77 | simtec_audio_init(codec); | ||
78 | snd_soc_dapm_sync(codec); | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static struct snd_soc_dai_link simtec_dai_aic23 = { | ||
84 | .name = "tlv320aic23", | ||
85 | .stream_name = "TLV320AIC23", | ||
86 | .cpu_dai = &s3c24xx_i2s_dai, | ||
87 | .codec_dai = &tlv320aic23_dai, | ||
88 | .init = simtec_tlv320aic23_init, | ||
89 | }; | ||
90 | |||
91 | /* simtec audio machine driver */ | ||
92 | static struct snd_soc_card snd_soc_machine_simtec_aic23 = { | ||
93 | .name = "Simtec", | ||
94 | .platform = &s3c24xx_soc_platform, | ||
95 | .dai_link = &simtec_dai_aic23, | ||
96 | .num_links = 1, | ||
97 | }; | ||
98 | |||
99 | /* simtec audio subsystem */ | ||
100 | static struct snd_soc_device simtec_snd_devdata_aic23 = { | ||
101 | .card = &snd_soc_machine_simtec_aic23, | ||
102 | .codec_dev = &soc_codec_dev_tlv320aic23, | ||
103 | }; | ||
104 | |||
105 | static int __devinit simtec_audio_tlv320aic23_probe(struct platform_device *pd) | ||
106 | { | ||
107 | return simtec_audio_core_probe(pd, &simtec_snd_devdata_aic23); | ||
108 | } | ||
109 | |||
110 | static struct platform_driver simtec_audio_tlv320aic23_platdrv = { | ||
111 | .driver = { | ||
112 | .owner = THIS_MODULE, | ||
113 | .name = "s3c24xx-simtec-tlv320aic23", | ||
114 | .pm = simtec_audio_pm, | ||
115 | }, | ||
116 | .probe = simtec_audio_tlv320aic23_probe, | ||
117 | .remove = __devexit_p(simtec_audio_remove), | ||
118 | }; | ||
119 | |||
120 | MODULE_ALIAS("platform:s3c24xx-simtec-tlv320aic23"); | ||
121 | |||
122 | static int __init simtec_tlv320aic23_modinit(void) | ||
123 | { | ||
124 | return platform_driver_register(&simtec_audio_tlv320aic23_platdrv); | ||
125 | } | ||
126 | |||
127 | static void __exit simtec_tlv320aic23_modexit(void) | ||
128 | { | ||
129 | platform_driver_unregister(&simtec_audio_tlv320aic23_platdrv); | ||
130 | } | ||
131 | |||
132 | module_init(simtec_tlv320aic23_modinit); | ||
133 | module_exit(simtec_tlv320aic23_modexit); | ||
134 | |||
135 | MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); | ||
136 | MODULE_DESCRIPTION("ALSA SoC Simtec Audio support"); | ||
137 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 3c06c401d0fb..43fb253a3429 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c | |||
@@ -99,6 +99,19 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; | 99 | iismod |= S3C64XX_IISMOD_IMS_SYSMUX; |
100 | break; | 100 | break; |
101 | 101 | ||
102 | case S3C64XX_CLKSRC_CDCLK: | ||
103 | switch (dir) { | ||
104 | case SND_SOC_CLOCK_IN: | ||
105 | iismod |= S3C64XX_IISMOD_CDCLKCON; | ||
106 | break; | ||
107 | case SND_SOC_CLOCK_OUT: | ||
108 | iismod &= ~S3C64XX_IISMOD_CDCLKCON; | ||
109 | break; | ||
110 | default: | ||
111 | return -EINVAL; | ||
112 | } | ||
113 | break; | ||
114 | |||
102 | default: | 115 | default: |
103 | return -EINVAL; | 116 | return -EINVAL; |
104 | } | 117 | } |
@@ -111,8 +124,12 @@ static int s3c64xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, | |||
111 | struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) | 124 | struct clk *s3c64xx_i2s_get_clock(struct snd_soc_dai *dai) |
112 | { | 125 | { |
113 | struct s3c_i2sv2_info *i2s = to_info(dai); | 126 | struct s3c_i2sv2_info *i2s = to_info(dai); |
127 | u32 iismod = readl(i2s->regs + S3C2412_IISMOD); | ||
114 | 128 | ||
115 | return i2s->iis_cclk; | 129 | if (iismod & S3C64XX_IISMOD_IMS_SYSMUX) |
130 | return i2s->iis_cclk; | ||
131 | else | ||
132 | return i2s->iis_pclk; | ||
116 | } | 133 | } |
117 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); | 134 | EXPORT_SYMBOL_GPL(s3c64xx_i2s_get_clock); |
118 | 135 | ||
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h index 02148cee2613..abe7253b55fc 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.h +++ b/sound/soc/s3c24xx/s3c64xx-i2s.h | |||
@@ -25,6 +25,7 @@ struct clk; | |||
25 | 25 | ||
26 | #define S3C64XX_CLKSRC_PCLK (0) | 26 | #define S3C64XX_CLKSRC_PCLK (0) |
27 | #define S3C64XX_CLKSRC_MUX (1) | 27 | #define S3C64XX_CLKSRC_MUX (1) |
28 | #define S3C64XX_CLKSRC_CDCLK (2) | ||
28 | 29 | ||
29 | extern struct snd_soc_dai s3c64xx_i2s_dai[]; | 30 | extern struct snd_soc_dai s3c64xx_i2s_dai[]; |
30 | 31 | ||
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c new file mode 100644 index 000000000000..482aaf10eff6 --- /dev/null +++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * smdk64xx_wm8580.c | ||
3 | * | ||
4 | * Copyright (c) 2009 Samsung Electronics Co. Ltd | ||
5 | * Author: Jaswinder Singh <jassi.brar@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/clk.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/pcm.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | ||
19 | #include <sound/soc-dapm.h> | ||
20 | |||
21 | #include "../codecs/wm8580.h" | ||
22 | #include "s3c24xx-pcm.h" | ||
23 | #include "s3c64xx-i2s.h" | ||
24 | |||
25 | #define S3C64XX_I2S_V4 2 | ||
26 | |||
27 | /* SMDK64XX has a 12MHZ crystal attached to WM8580 */ | ||
28 | #define SMDK64XX_WM8580_FREQ 12000000 | ||
29 | |||
30 | static int smdk64xx_hw_params(struct snd_pcm_substream *substream, | ||
31 | struct snd_pcm_hw_params *params) | ||
32 | { | ||
33 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
34 | struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; | ||
35 | struct snd_soc_dai *codec_dai = rtd->dai->codec_dai; | ||
36 | unsigned int pll_out; | ||
37 | int bfs, rfs, ret; | ||
38 | |||
39 | switch (params_format(params)) { | ||
40 | case SNDRV_PCM_FORMAT_U8: | ||
41 | case SNDRV_PCM_FORMAT_S8: | ||
42 | bfs = 16; | ||
43 | break; | ||
44 | case SNDRV_PCM_FORMAT_U16_LE: | ||
45 | case SNDRV_PCM_FORMAT_S16_LE: | ||
46 | bfs = 32; | ||
47 | break; | ||
48 | default: | ||
49 | return -EINVAL; | ||
50 | } | ||
51 | |||
52 | /* The Fvco for WM8580 PLLs must fall within [90,100]MHz. | ||
53 | * This criterion can't be met if we request PLL output | ||
54 | * as {8000x256, 64000x256, 11025x256}Hz. | ||
55 | * As a wayout, we rather change rfs to a minimum value that | ||
56 | * results in (params_rate(params) * rfs), and itself, acceptable | ||
57 | * to both - the CODEC and the CPU. | ||
58 | */ | ||
59 | switch (params_rate(params)) { | ||
60 | case 16000: | ||
61 | case 22050: | ||
62 | case 32000: | ||
63 | case 44100: | ||
64 | case 48000: | ||
65 | case 88200: | ||
66 | case 96000: | ||
67 | rfs = 256; | ||
68 | break; | ||
69 | case 64000: | ||
70 | rfs = 384; | ||
71 | break; | ||
72 | case 8000: | ||
73 | case 11025: | ||
74 | rfs = 512; | ||
75 | break; | ||
76 | default: | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | pll_out = params_rate(params) * rfs; | ||
80 | |||
81 | /* Set the Codec DAI configuration */ | ||
82 | ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S | ||
83 | | SND_SOC_DAIFMT_NB_NF | ||
84 | | SND_SOC_DAIFMT_CBM_CFM); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | |||
88 | /* Set the AP DAI configuration */ | ||
89 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | ||
90 | | SND_SOC_DAIFMT_NB_NF | ||
91 | | SND_SOC_DAIFMT_CBM_CFM); | ||
92 | if (ret < 0) | ||
93 | return ret; | ||
94 | |||
95 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_CDCLK, | ||
96 | 0, SND_SOC_CLOCK_IN); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | /* We use PCLK for basic ops in SoC-Slave mode */ | ||
101 | ret = snd_soc_dai_set_sysclk(cpu_dai, S3C64XX_CLKSRC_PCLK, | ||
102 | 0, SND_SOC_CLOCK_IN); | ||
103 | if (ret < 0) | ||
104 | return ret; | ||
105 | |||
106 | /* Set WM8580 to drive MCLK from it's PLLA */ | ||
107 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_MCLK, | ||
108 | WM8580_CLKSRC_PLLA); | ||
109 | if (ret < 0) | ||
110 | return ret; | ||
111 | |||
112 | /* Explicitly set WM8580-DAC to source from MCLK */ | ||
113 | ret = snd_soc_dai_set_clkdiv(codec_dai, WM8580_DAC_CLKSEL, | ||
114 | WM8580_CLKSRC_MCLK); | ||
115 | if (ret < 0) | ||
116 | return ret; | ||
117 | |||
118 | /* Assuming the CODEC driver evaluates it's rfs too from this call */ | ||
119 | ret = snd_soc_dai_set_pll(codec_dai, 0, WM8580_PLLA, | ||
120 | SMDK64XX_WM8580_FREQ, pll_out); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | |||
124 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_BCLK, bfs); | ||
125 | if (ret < 0) | ||
126 | return ret; | ||
127 | |||
128 | ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C_I2SV2_DIV_RCLK, rfs); | ||
129 | if (ret < 0) | ||
130 | return ret; | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | /* | ||
136 | * SMDK64XX WM8580 DAI operations. | ||
137 | */ | ||
138 | static struct snd_soc_ops smdk64xx_ops = { | ||
139 | .hw_params = smdk64xx_hw_params, | ||
140 | }; | ||
141 | |||
142 | /* SMDK64xx Playback widgets */ | ||
143 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_pbk[] = { | ||
144 | SND_SOC_DAPM_HP("Front-L/R", NULL), | ||
145 | SND_SOC_DAPM_HP("Center/Sub", NULL), | ||
146 | SND_SOC_DAPM_HP("Rear-L/R", NULL), | ||
147 | }; | ||
148 | |||
149 | /* SMDK64xx Capture widgets */ | ||
150 | static const struct snd_soc_dapm_widget wm8580_dapm_widgets_cpt[] = { | ||
151 | SND_SOC_DAPM_MIC("MicIn", NULL), | ||
152 | SND_SOC_DAPM_LINE("LineIn", NULL), | ||
153 | }; | ||
154 | |||
155 | /* SMDK-PAIFTX connections */ | ||
156 | static const struct snd_soc_dapm_route audio_map_tx[] = { | ||
157 | /* MicIn feeds AINL */ | ||
158 | {"AINL", NULL, "MicIn"}, | ||
159 | |||
160 | /* LineIn feeds AINL/R */ | ||
161 | {"AINL", NULL, "LineIn"}, | ||
162 | {"AINR", NULL, "LineIn"}, | ||
163 | }; | ||
164 | |||
165 | /* SMDK-PAIFRX connections */ | ||
166 | static const struct snd_soc_dapm_route audio_map_rx[] = { | ||
167 | /* Front Left/Right are fed VOUT1L/R */ | ||
168 | {"Front-L/R", NULL, "VOUT1L"}, | ||
169 | {"Front-L/R", NULL, "VOUT1R"}, | ||
170 | |||
171 | /* Center/Sub are fed VOUT2L/R */ | ||
172 | {"Center/Sub", NULL, "VOUT2L"}, | ||
173 | {"Center/Sub", NULL, "VOUT2R"}, | ||
174 | |||
175 | /* Rear Left/Right are fed VOUT3L/R */ | ||
176 | {"Rear-L/R", NULL, "VOUT3L"}, | ||
177 | {"Rear-L/R", NULL, "VOUT3R"}, | ||
178 | }; | ||
179 | |||
180 | static int smdk64xx_wm8580_init_paiftx(struct snd_soc_codec *codec) | ||
181 | { | ||
182 | /* Add smdk64xx specific Capture widgets */ | ||
183 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_cpt, | ||
184 | ARRAY_SIZE(wm8580_dapm_widgets_cpt)); | ||
185 | |||
186 | /* Set up PAIFTX audio path */ | ||
187 | snd_soc_dapm_add_routes(codec, audio_map_tx, ARRAY_SIZE(audio_map_tx)); | ||
188 | |||
189 | /* All enabled by default */ | ||
190 | snd_soc_dapm_enable_pin(codec, "MicIn"); | ||
191 | snd_soc_dapm_enable_pin(codec, "LineIn"); | ||
192 | |||
193 | /* signal a DAPM event */ | ||
194 | snd_soc_dapm_sync(codec); | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int smdk64xx_wm8580_init_paifrx(struct snd_soc_codec *codec) | ||
200 | { | ||
201 | /* Add smdk64xx specific Playback widgets */ | ||
202 | snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets_pbk, | ||
203 | ARRAY_SIZE(wm8580_dapm_widgets_pbk)); | ||
204 | |||
205 | /* Set up PAIFRX audio path */ | ||
206 | snd_soc_dapm_add_routes(codec, audio_map_rx, ARRAY_SIZE(audio_map_rx)); | ||
207 | |||
208 | /* All enabled by default */ | ||
209 | snd_soc_dapm_enable_pin(codec, "Front-L/R"); | ||
210 | snd_soc_dapm_enable_pin(codec, "Center/Sub"); | ||
211 | snd_soc_dapm_enable_pin(codec, "Rear-L/R"); | ||
212 | |||
213 | /* signal a DAPM event */ | ||
214 | snd_soc_dapm_sync(codec); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static struct snd_soc_dai_link smdk64xx_dai[] = { | ||
220 | { /* Primary Playback i/f */ | ||
221 | .name = "WM8580 PAIF RX", | ||
222 | .stream_name = "Playback", | ||
223 | .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], | ||
224 | .codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX], | ||
225 | .init = smdk64xx_wm8580_init_paifrx, | ||
226 | .ops = &smdk64xx_ops, | ||
227 | }, | ||
228 | { /* Primary Capture i/f */ | ||
229 | .name = "WM8580 PAIF TX", | ||
230 | .stream_name = "Capture", | ||
231 | .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4], | ||
232 | .codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX], | ||
233 | .init = smdk64xx_wm8580_init_paiftx, | ||
234 | .ops = &smdk64xx_ops, | ||
235 | }, | ||
236 | }; | ||
237 | |||
238 | static struct snd_soc_card smdk64xx = { | ||
239 | .name = "smdk64xx", | ||
240 | .platform = &s3c24xx_soc_platform, | ||
241 | .dai_link = smdk64xx_dai, | ||
242 | .num_links = ARRAY_SIZE(smdk64xx_dai), | ||
243 | }; | ||
244 | |||
245 | static struct snd_soc_device smdk64xx_snd_devdata = { | ||
246 | .card = &smdk64xx, | ||
247 | .codec_dev = &soc_codec_dev_wm8580, | ||
248 | }; | ||
249 | |||
250 | static struct platform_device *smdk64xx_snd_device; | ||
251 | |||
252 | static int __init smdk64xx_audio_init(void) | ||
253 | { | ||
254 | int ret; | ||
255 | |||
256 | smdk64xx_snd_device = platform_device_alloc("soc-audio", -1); | ||
257 | if (!smdk64xx_snd_device) | ||
258 | return -ENOMEM; | ||
259 | |||
260 | platform_set_drvdata(smdk64xx_snd_device, &smdk64xx_snd_devdata); | ||
261 | smdk64xx_snd_devdata.dev = &smdk64xx_snd_device->dev; | ||
262 | ret = platform_device_add(smdk64xx_snd_device); | ||
263 | |||
264 | if (ret) | ||
265 | platform_device_put(smdk64xx_snd_device); | ||
266 | |||
267 | return ret; | ||
268 | } | ||
269 | module_init(smdk64xx_audio_init); | ||
270 | |||
271 | MODULE_AUTHOR("Jaswinder Singh, jassi.brar@samsung.com"); | ||
272 | MODULE_DESCRIPTION("ALSA SoC SMDK64XX WM8580"); | ||
273 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/s6000/s6105-ipcam.c b/sound/soc/s6000/s6105-ipcam.c index b5f95f9781c1..c1b40ac22c05 100644 --- a/sound/soc/s6000/s6105-ipcam.c +++ b/sound/soc/s6000/s6105-ipcam.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/timer.h> | 14 | #include <linux/timer.h> |
15 | #include <linux/interrupt.h> | 15 | #include <linux/interrupt.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/i2c.h> | ||
17 | #include <sound/core.h> | 18 | #include <sound/core.h> |
18 | #include <sound/pcm.h> | 19 | #include <sound/pcm.h> |
19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
@@ -189,8 +190,6 @@ static struct snd_soc_card snd_soc_card_s6105 = { | |||
189 | 190 | ||
190 | /* s6105 audio private data */ | 191 | /* s6105 audio private data */ |
191 | static struct aic3x_setup_data s6105_aic3x_setup = { | 192 | static struct aic3x_setup_data s6105_aic3x_setup = { |
192 | .i2c_bus = 0, | ||
193 | .i2c_address = 0x18, | ||
194 | }; | 193 | }; |
195 | 194 | ||
196 | /* s6105 audio subsystem */ | 195 | /* s6105 audio subsystem */ |
@@ -211,10 +210,19 @@ static struct s6000_snd_platform_data __initdata s6105_snd_data = { | |||
211 | 210 | ||
212 | static struct platform_device *s6105_snd_device; | 211 | static struct platform_device *s6105_snd_device; |
213 | 212 | ||
213 | /* temporary i2c device creation until this can be moved into the machine | ||
214 | * support file. | ||
215 | */ | ||
216 | static struct i2c_board_info i2c_device[] = { | ||
217 | { I2C_BOARD_INFO("tlv320aic33", 0x18), } | ||
218 | }; | ||
219 | |||
214 | static int __init s6105_init(void) | 220 | static int __init s6105_init(void) |
215 | { | 221 | { |
216 | int ret; | 222 | int ret; |
217 | 223 | ||
224 | i2c_register_board_info(0, i2c_device, ARRAY_SIZE(i2c_device)); | ||
225 | |||
218 | s6105_snd_device = platform_device_alloc("soc-audio", -1); | 226 | s6105_snd_device = platform_device_alloc("soc-audio", -1); |
219 | if (!s6105_snd_device) | 227 | if (!s6105_snd_device) |
220 | return -ENOMEM; | 228 | return -ENOMEM; |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 54bd604012af..9154b4363db3 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
@@ -20,7 +20,12 @@ config SND_SOC_SH4_HAC | |||
20 | config SND_SOC_SH4_SSI | 20 | config SND_SOC_SH4_SSI |
21 | tristate | 21 | tristate |
22 | 22 | ||
23 | 23 | config SND_SOC_SH4_FSI | |
24 | tristate "SH4 FSI support" | ||
25 | depends on CPU_SUBTYPE_SH7724 | ||
26 | select SH_DMA | ||
27 | help | ||
28 | This option enables FSI sound support | ||
24 | 29 | ||
25 | ## | 30 | ## |
26 | ## Boards | 31 | ## Boards |
@@ -35,4 +40,12 @@ config SND_SH7760_AC97 | |||
35 | This option enables generic sound support for the first | 40 | This option enables generic sound support for the first |
36 | AC97 unit of the SH7760. | 41 | AC97 unit of the SH7760. |
37 | 42 | ||
43 | config SND_FSI_AK4642 | ||
44 | bool "FSI-AK4642 sound support" | ||
45 | depends on SND_SOC_SH4_FSI | ||
46 | select SND_SOC_AK4642 | ||
47 | help | ||
48 | This option enables generic sound support for the | ||
49 | FSI - AK4642 unit | ||
50 | |||
38 | endmenu | 51 | endmenu |
diff --git a/sound/soc/sh/Makefile b/sound/soc/sh/Makefile index a8e8ab81cc6a..a6997872f24e 100644 --- a/sound/soc/sh/Makefile +++ b/sound/soc/sh/Makefile | |||
@@ -5,10 +5,14 @@ obj-$(CONFIG_SND_SOC_PCM_SH7760) += snd-soc-dma-sh7760.o | |||
5 | ## audio units found on some SH-4 | 5 | ## audio units found on some SH-4 |
6 | snd-soc-hac-objs := hac.o | 6 | snd-soc-hac-objs := hac.o |
7 | snd-soc-ssi-objs := ssi.o | 7 | snd-soc-ssi-objs := ssi.o |
8 | snd-soc-fsi-objs := fsi.o | ||
8 | obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o | 9 | obj-$(CONFIG_SND_SOC_SH4_HAC) += snd-soc-hac.o |
9 | obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o | 10 | obj-$(CONFIG_SND_SOC_SH4_SSI) += snd-soc-ssi.o |
11 | obj-$(CONFIG_SND_SOC_SH4_FSI) += snd-soc-fsi.o | ||
10 | 12 | ||
11 | ## boards | 13 | ## boards |
12 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o | 14 | snd-soc-sh7760-ac97-objs := sh7760-ac97.o |
15 | snd-soc-fsi-ak4642-objs := fsi-ak4642.o | ||
13 | 16 | ||
14 | obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o | 17 | obj-$(CONFIG_SND_SH7760_AC97) += snd-soc-sh7760-ac97.o |
18 | obj-$(CONFIG_SND_FSI_AK4642) += snd-soc-fsi-ak4642.o | ||
diff --git a/sound/soc/sh/fsi-ak4642.c b/sound/soc/sh/fsi-ak4642.c new file mode 100644 index 000000000000..c7af09729c6e --- /dev/null +++ b/sound/soc/sh/fsi-ak4642.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * FSI-AK464x sound support for ms7724se | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * This file is subject to the terms and conditions of the GNU General Public | ||
8 | * License. See the file "COPYING" in the main directory of this archive | ||
9 | * for more details. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/platform_device.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/io.h> | ||
17 | #include <sound/core.h> | ||
18 | #include <sound/pcm.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/soc-dapm.h> | ||
21 | |||
22 | #include <sound/sh_fsi.h> | ||
23 | #include <../sound/soc/codecs/ak4642.h> | ||
24 | |||
25 | static struct snd_soc_dai_link fsi_dai_link = { | ||
26 | .name = "AK4642", | ||
27 | .stream_name = "AK4642", | ||
28 | .cpu_dai = &fsi_soc_dai[0], /* fsi */ | ||
29 | .codec_dai = &ak4642_dai, | ||
30 | .ops = NULL, | ||
31 | }; | ||
32 | |||
33 | static struct snd_soc_card fsi_soc_card = { | ||
34 | .name = "FSI", | ||
35 | .platform = &fsi_soc_platform, | ||
36 | .dai_link = &fsi_dai_link, | ||
37 | .num_links = 1, | ||
38 | }; | ||
39 | |||
40 | static struct snd_soc_device fsi_snd_devdata = { | ||
41 | .card = &fsi_soc_card, | ||
42 | .codec_dev = &soc_codec_dev_ak4642, | ||
43 | }; | ||
44 | |||
45 | #define AK4642_BUS 0 | ||
46 | #define AK4642_ADR 0x12 | ||
47 | static int ak4642_add_i2c_device(void) | ||
48 | { | ||
49 | struct i2c_board_info info; | ||
50 | struct i2c_adapter *adapter; | ||
51 | struct i2c_client *client; | ||
52 | |||
53 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
54 | info.addr = AK4642_ADR; | ||
55 | strlcpy(info.type, "ak4642", I2C_NAME_SIZE); | ||
56 | |||
57 | adapter = i2c_get_adapter(AK4642_BUS); | ||
58 | if (!adapter) { | ||
59 | printk(KERN_DEBUG "can't get i2c adapter\n"); | ||
60 | return -ENODEV; | ||
61 | } | ||
62 | |||
63 | client = i2c_new_device(adapter, &info); | ||
64 | i2c_put_adapter(adapter); | ||
65 | if (!client) { | ||
66 | printk(KERN_DEBUG "can't add i2c device\n"); | ||
67 | return -ENODEV; | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static struct platform_device *fsi_snd_device; | ||
74 | |||
75 | static int __init fsi_ak4642_init(void) | ||
76 | { | ||
77 | int ret = -ENOMEM; | ||
78 | |||
79 | ak4642_add_i2c_device(); | ||
80 | |||
81 | fsi_snd_device = platform_device_alloc("soc-audio", -1); | ||
82 | if (!fsi_snd_device) | ||
83 | goto out; | ||
84 | |||
85 | platform_set_drvdata(fsi_snd_device, | ||
86 | &fsi_snd_devdata); | ||
87 | fsi_snd_devdata.dev = &fsi_snd_device->dev; | ||
88 | ret = platform_device_add(fsi_snd_device); | ||
89 | |||
90 | if (ret) | ||
91 | platform_device_put(fsi_snd_device); | ||
92 | |||
93 | out: | ||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | static void __exit fsi_ak4642_exit(void) | ||
98 | { | ||
99 | platform_device_unregister(fsi_snd_device); | ||
100 | } | ||
101 | |||
102 | module_init(fsi_ak4642_init); | ||
103 | module_exit(fsi_ak4642_exit); | ||
104 | |||
105 | MODULE_LICENSE("GPL"); | ||
106 | MODULE_DESCRIPTION("Generic SH4 FSI-AK4642 sound card"); | ||
107 | MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c new file mode 100644 index 000000000000..44123248b630 --- /dev/null +++ b/sound/soc/sh/fsi.c | |||
@@ -0,0 +1,1004 @@ | |||
1 | /* | ||
2 | * Fifo-attached Serial Interface (FSI) support for SH7724 | ||
3 | * | ||
4 | * Copyright (C) 2009 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <morimoto.kuninori@renesas.com> | ||
6 | * | ||
7 | * Based on ssi.c | ||
8 | * Copyright (c) 2007 Manuel Lauss <mano@roarinelk.homelinux.net> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/initval.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/sh_fsi.h> | ||
28 | #include <asm/atomic.h> | ||
29 | #include <asm/dma.h> | ||
30 | #include <asm/dma-sh.h> | ||
31 | |||
32 | #define DO_FMT 0x0000 | ||
33 | #define DOFF_CTL 0x0004 | ||
34 | #define DOFF_ST 0x0008 | ||
35 | #define DI_FMT 0x000C | ||
36 | #define DIFF_CTL 0x0010 | ||
37 | #define DIFF_ST 0x0014 | ||
38 | #define CKG1 0x0018 | ||
39 | #define CKG2 0x001C | ||
40 | #define DIDT 0x0020 | ||
41 | #define DODT 0x0024 | ||
42 | #define MUTE_ST 0x0028 | ||
43 | #define REG_END MUTE_ST | ||
44 | |||
45 | #define INT_ST 0x0200 | ||
46 | #define IEMSK 0x0204 | ||
47 | #define IMSK 0x0208 | ||
48 | #define MUTE 0x020C | ||
49 | #define CLK_RST 0x0210 | ||
50 | #define SOFT_RST 0x0214 | ||
51 | #define MREG_START INT_ST | ||
52 | #define MREG_END SOFT_RST | ||
53 | |||
54 | /* DO_FMT */ | ||
55 | /* DI_FMT */ | ||
56 | #define CR_FMT(param) ((param) << 4) | ||
57 | # define CR_MONO 0x0 | ||
58 | # define CR_MONO_D 0x1 | ||
59 | # define CR_PCM 0x2 | ||
60 | # define CR_I2S 0x3 | ||
61 | # define CR_TDM 0x4 | ||
62 | # define CR_TDM_D 0x5 | ||
63 | |||
64 | /* DOFF_CTL */ | ||
65 | /* DIFF_CTL */ | ||
66 | #define IRQ_HALF 0x00100000 | ||
67 | #define FIFO_CLR 0x00000001 | ||
68 | |||
69 | /* DOFF_ST */ | ||
70 | #define ERR_OVER 0x00000010 | ||
71 | #define ERR_UNDER 0x00000001 | ||
72 | |||
73 | /* CLK_RST */ | ||
74 | #define B_CLK 0x00000010 | ||
75 | #define A_CLK 0x00000001 | ||
76 | |||
77 | /* INT_ST */ | ||
78 | #define INT_B_IN (1 << 12) | ||
79 | #define INT_B_OUT (1 << 8) | ||
80 | #define INT_A_IN (1 << 4) | ||
81 | #define INT_A_OUT (1 << 0) | ||
82 | |||
83 | #define FSI_RATES SNDRV_PCM_RATE_8000_96000 | ||
84 | |||
85 | #define FSI_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | ||
86 | |||
87 | /************************************************************************ | ||
88 | |||
89 | |||
90 | struct | ||
91 | |||
92 | |||
93 | ************************************************************************/ | ||
94 | struct fsi_priv { | ||
95 | void __iomem *base; | ||
96 | struct snd_pcm_substream *substream; | ||
97 | |||
98 | int fifo_max; | ||
99 | int chan; | ||
100 | int dma_chan; | ||
101 | |||
102 | int byte_offset; | ||
103 | int period_len; | ||
104 | int buffer_len; | ||
105 | int periods; | ||
106 | }; | ||
107 | |||
108 | struct fsi_master { | ||
109 | void __iomem *base; | ||
110 | int irq; | ||
111 | struct clk *clk; | ||
112 | struct fsi_priv fsia; | ||
113 | struct fsi_priv fsib; | ||
114 | struct sh_fsi_platform_info *info; | ||
115 | }; | ||
116 | |||
117 | static struct fsi_master *master; | ||
118 | |||
119 | /************************************************************************ | ||
120 | |||
121 | |||
122 | basic read write function | ||
123 | |||
124 | |||
125 | ************************************************************************/ | ||
126 | static int __fsi_reg_write(u32 reg, u32 data) | ||
127 | { | ||
128 | /* valid data area is 24bit */ | ||
129 | data &= 0x00ffffff; | ||
130 | |||
131 | return ctrl_outl(data, reg); | ||
132 | } | ||
133 | |||
134 | static u32 __fsi_reg_read(u32 reg) | ||
135 | { | ||
136 | return ctrl_inl(reg); | ||
137 | } | ||
138 | |||
139 | static int __fsi_reg_mask_set(u32 reg, u32 mask, u32 data) | ||
140 | { | ||
141 | u32 val = __fsi_reg_read(reg); | ||
142 | |||
143 | val &= ~mask; | ||
144 | val |= data & mask; | ||
145 | |||
146 | return __fsi_reg_write(reg, val); | ||
147 | } | ||
148 | |||
149 | static int fsi_reg_write(struct fsi_priv *fsi, u32 reg, u32 data) | ||
150 | { | ||
151 | if (reg > REG_END) | ||
152 | return -1; | ||
153 | |||
154 | return __fsi_reg_write((u32)(fsi->base + reg), data); | ||
155 | } | ||
156 | |||
157 | static u32 fsi_reg_read(struct fsi_priv *fsi, u32 reg) | ||
158 | { | ||
159 | if (reg > REG_END) | ||
160 | return 0; | ||
161 | |||
162 | return __fsi_reg_read((u32)(fsi->base + reg)); | ||
163 | } | ||
164 | |||
165 | static int fsi_reg_mask_set(struct fsi_priv *fsi, u32 reg, u32 mask, u32 data) | ||
166 | { | ||
167 | if (reg > REG_END) | ||
168 | return -1; | ||
169 | |||
170 | return __fsi_reg_mask_set((u32)(fsi->base + reg), mask, data); | ||
171 | } | ||
172 | |||
173 | static int fsi_master_write(u32 reg, u32 data) | ||
174 | { | ||
175 | if ((reg < MREG_START) || | ||
176 | (reg > MREG_END)) | ||
177 | return -1; | ||
178 | |||
179 | return __fsi_reg_write((u32)(master->base + reg), data); | ||
180 | } | ||
181 | |||
182 | static u32 fsi_master_read(u32 reg) | ||
183 | { | ||
184 | if ((reg < MREG_START) || | ||
185 | (reg > MREG_END)) | ||
186 | return 0; | ||
187 | |||
188 | return __fsi_reg_read((u32)(master->base + reg)); | ||
189 | } | ||
190 | |||
191 | static int fsi_master_mask_set(u32 reg, u32 mask, u32 data) | ||
192 | { | ||
193 | if ((reg < MREG_START) || | ||
194 | (reg > MREG_END)) | ||
195 | return -1; | ||
196 | |||
197 | return __fsi_reg_mask_set((u32)(master->base + reg), mask, data); | ||
198 | } | ||
199 | |||
200 | /************************************************************************ | ||
201 | |||
202 | |||
203 | basic function | ||
204 | |||
205 | |||
206 | ************************************************************************/ | ||
207 | static struct fsi_priv *fsi_get(struct snd_pcm_substream *substream) | ||
208 | { | ||
209 | struct snd_soc_pcm_runtime *rtd; | ||
210 | struct fsi_priv *fsi = NULL; | ||
211 | |||
212 | if (!substream || !master) | ||
213 | return NULL; | ||
214 | |||
215 | rtd = substream->private_data; | ||
216 | switch (rtd->dai->cpu_dai->id) { | ||
217 | case 0: | ||
218 | fsi = &master->fsia; | ||
219 | break; | ||
220 | case 1: | ||
221 | fsi = &master->fsib; | ||
222 | break; | ||
223 | } | ||
224 | |||
225 | return fsi; | ||
226 | } | ||
227 | |||
228 | static int fsi_is_port_a(struct fsi_priv *fsi) | ||
229 | { | ||
230 | /* return | ||
231 | * 1 : port a | ||
232 | * 0 : port b | ||
233 | */ | ||
234 | |||
235 | if (fsi == &master->fsia) | ||
236 | return 1; | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static u32 fsi_get_info_flags(struct fsi_priv *fsi) | ||
242 | { | ||
243 | int is_porta = fsi_is_port_a(fsi); | ||
244 | |||
245 | return is_porta ? master->info->porta_flags : | ||
246 | master->info->portb_flags; | ||
247 | } | ||
248 | |||
249 | static int fsi_is_master_mode(struct fsi_priv *fsi, int is_play) | ||
250 | { | ||
251 | u32 mode; | ||
252 | u32 flags = fsi_get_info_flags(fsi); | ||
253 | |||
254 | mode = is_play ? SH_FSI_OUT_SLAVE_MODE : SH_FSI_IN_SLAVE_MODE; | ||
255 | |||
256 | /* return | ||
257 | * 1 : master mode | ||
258 | * 0 : slave mode | ||
259 | */ | ||
260 | |||
261 | return (mode & flags) != mode; | ||
262 | } | ||
263 | |||
264 | static u32 fsi_port_ab_io_bit(struct fsi_priv *fsi, int is_play) | ||
265 | { | ||
266 | int is_porta = fsi_is_port_a(fsi); | ||
267 | u32 data; | ||
268 | |||
269 | if (is_porta) | ||
270 | data = is_play ? (1 << 0) : (1 << 4); | ||
271 | else | ||
272 | data = is_play ? (1 << 8) : (1 << 12); | ||
273 | |||
274 | return data; | ||
275 | } | ||
276 | |||
277 | static void fsi_stream_push(struct fsi_priv *fsi, | ||
278 | struct snd_pcm_substream *substream, | ||
279 | u32 buffer_len, | ||
280 | u32 period_len) | ||
281 | { | ||
282 | fsi->substream = substream; | ||
283 | fsi->buffer_len = buffer_len; | ||
284 | fsi->period_len = period_len; | ||
285 | fsi->byte_offset = 0; | ||
286 | fsi->periods = 0; | ||
287 | } | ||
288 | |||
289 | static void fsi_stream_pop(struct fsi_priv *fsi) | ||
290 | { | ||
291 | fsi->substream = NULL; | ||
292 | fsi->buffer_len = 0; | ||
293 | fsi->period_len = 0; | ||
294 | fsi->byte_offset = 0; | ||
295 | fsi->periods = 0; | ||
296 | } | ||
297 | |||
298 | static int fsi_get_fifo_residue(struct fsi_priv *fsi, int is_play) | ||
299 | { | ||
300 | u32 status; | ||
301 | u32 reg = is_play ? DOFF_ST : DIFF_ST; | ||
302 | int residue; | ||
303 | |||
304 | status = fsi_reg_read(fsi, reg); | ||
305 | residue = 0x1ff & (status >> 8); | ||
306 | residue *= fsi->chan; | ||
307 | |||
308 | return residue; | ||
309 | } | ||
310 | |||
311 | static int fsi_get_residue(struct fsi_priv *fsi, int is_play) | ||
312 | { | ||
313 | int residue; | ||
314 | int width; | ||
315 | struct snd_pcm_runtime *runtime; | ||
316 | |||
317 | runtime = fsi->substream->runtime; | ||
318 | |||
319 | /* get 1 channel data width */ | ||
320 | width = frames_to_bytes(runtime, 1) / fsi->chan; | ||
321 | |||
322 | if (2 == width) | ||
323 | residue = fsi_get_fifo_residue(fsi, is_play); | ||
324 | else | ||
325 | residue = get_dma_residue(fsi->dma_chan); | ||
326 | |||
327 | return residue; | ||
328 | } | ||
329 | |||
330 | /************************************************************************ | ||
331 | |||
332 | |||
333 | basic dma function | ||
334 | |||
335 | |||
336 | ************************************************************************/ | ||
337 | #define PORTA_DMA 0 | ||
338 | #define PORTB_DMA 1 | ||
339 | |||
340 | static int fsi_get_dma_chan(void) | ||
341 | { | ||
342 | if (0 != request_dma(PORTA_DMA, "fsia")) | ||
343 | return -EIO; | ||
344 | |||
345 | if (0 != request_dma(PORTB_DMA, "fsib")) { | ||
346 | free_dma(PORTA_DMA); | ||
347 | return -EIO; | ||
348 | } | ||
349 | |||
350 | master->fsia.dma_chan = PORTA_DMA; | ||
351 | master->fsib.dma_chan = PORTB_DMA; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static void fsi_free_dma_chan(void) | ||
357 | { | ||
358 | dma_wait_for_completion(PORTA_DMA); | ||
359 | dma_wait_for_completion(PORTB_DMA); | ||
360 | free_dma(PORTA_DMA); | ||
361 | free_dma(PORTB_DMA); | ||
362 | |||
363 | master->fsia.dma_chan = -1; | ||
364 | master->fsib.dma_chan = -1; | ||
365 | } | ||
366 | |||
367 | /************************************************************************ | ||
368 | |||
369 | |||
370 | ctrl function | ||
371 | |||
372 | |||
373 | ************************************************************************/ | ||
374 | static void fsi_irq_enable(struct fsi_priv *fsi, int is_play) | ||
375 | { | ||
376 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | ||
377 | |||
378 | fsi_master_mask_set(IMSK, data, data); | ||
379 | fsi_master_mask_set(IEMSK, data, data); | ||
380 | } | ||
381 | |||
382 | static void fsi_irq_disable(struct fsi_priv *fsi, int is_play) | ||
383 | { | ||
384 | u32 data = fsi_port_ab_io_bit(fsi, is_play); | ||
385 | |||
386 | fsi_master_mask_set(IMSK, data, 0); | ||
387 | fsi_master_mask_set(IEMSK, data, 0); | ||
388 | } | ||
389 | |||
390 | static void fsi_clk_ctrl(struct fsi_priv *fsi, int enable) | ||
391 | { | ||
392 | u32 val = fsi_is_port_a(fsi) ? (1 << 0) : (1 << 4); | ||
393 | |||
394 | if (enable) | ||
395 | fsi_master_mask_set(CLK_RST, val, val); | ||
396 | else | ||
397 | fsi_master_mask_set(CLK_RST, val, 0); | ||
398 | } | ||
399 | |||
400 | static void fsi_irq_init(struct fsi_priv *fsi, int is_play) | ||
401 | { | ||
402 | u32 data; | ||
403 | u32 ctrl; | ||
404 | |||
405 | data = fsi_port_ab_io_bit(fsi, is_play); | ||
406 | ctrl = is_play ? DOFF_CTL : DIFF_CTL; | ||
407 | |||
408 | /* set IMSK */ | ||
409 | fsi_irq_disable(fsi, is_play); | ||
410 | |||
411 | /* set interrupt generation factor */ | ||
412 | fsi_reg_write(fsi, ctrl, IRQ_HALF); | ||
413 | |||
414 | /* clear FIFO */ | ||
415 | fsi_reg_mask_set(fsi, ctrl, FIFO_CLR, FIFO_CLR); | ||
416 | |||
417 | /* clear interrupt factor */ | ||
418 | fsi_master_mask_set(INT_ST, data, 0); | ||
419 | } | ||
420 | |||
421 | static void fsi_soft_all_reset(void) | ||
422 | { | ||
423 | u32 status = fsi_master_read(SOFT_RST); | ||
424 | |||
425 | /* port AB reset */ | ||
426 | status &= 0x000000ff; | ||
427 | fsi_master_write(SOFT_RST, status); | ||
428 | mdelay(10); | ||
429 | |||
430 | /* soft reset */ | ||
431 | status &= 0x000000f0; | ||
432 | fsi_master_write(SOFT_RST, status); | ||
433 | status |= 0x00000001; | ||
434 | fsi_master_write(SOFT_RST, status); | ||
435 | mdelay(10); | ||
436 | } | ||
437 | |||
438 | static void fsi_16data_push(struct fsi_priv *fsi, | ||
439 | struct snd_pcm_runtime *runtime, | ||
440 | int send) | ||
441 | { | ||
442 | u16 *dma_start; | ||
443 | u32 snd; | ||
444 | int i; | ||
445 | |||
446 | /* get dma start position for FSI */ | ||
447 | dma_start = (u16 *)runtime->dma_area; | ||
448 | dma_start += fsi->byte_offset / 2; | ||
449 | |||
450 | /* | ||
451 | * soft dma | ||
452 | * FSI can not use DMA when 16bpp | ||
453 | */ | ||
454 | for (i = 0; i < send; i++) { | ||
455 | snd = (u32)dma_start[i]; | ||
456 | fsi_reg_write(fsi, DODT, snd << 8); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | static void fsi_32data_push(struct fsi_priv *fsi, | ||
461 | struct snd_pcm_runtime *runtime, | ||
462 | int send) | ||
463 | { | ||
464 | u32 *dma_start; | ||
465 | |||
466 | /* get dma start position for FSI */ | ||
467 | dma_start = (u32 *)runtime->dma_area; | ||
468 | dma_start += fsi->byte_offset / 4; | ||
469 | |||
470 | dma_wait_for_completion(fsi->dma_chan); | ||
471 | dma_configure_channel(fsi->dma_chan, (SM_INC|0x400|TS_32|TM_BUR)); | ||
472 | dma_write(fsi->dma_chan, (u32)dma_start, | ||
473 | (u32)(fsi->base + DODT), send * 4); | ||
474 | } | ||
475 | |||
476 | /* playback interrupt */ | ||
477 | static int fsi_data_push(struct fsi_priv *fsi) | ||
478 | { | ||
479 | struct snd_pcm_runtime *runtime; | ||
480 | struct snd_pcm_substream *substream = NULL; | ||
481 | int send; | ||
482 | int fifo_free; | ||
483 | int width; | ||
484 | |||
485 | if (!fsi || | ||
486 | !fsi->substream || | ||
487 | !fsi->substream->runtime) | ||
488 | return -EINVAL; | ||
489 | |||
490 | runtime = fsi->substream->runtime; | ||
491 | |||
492 | /* FSI FIFO has limit. | ||
493 | * So, this driver can not send periods data at a time | ||
494 | */ | ||
495 | if (fsi->byte_offset >= | ||
496 | fsi->period_len * (fsi->periods + 1)) { | ||
497 | |||
498 | substream = fsi->substream; | ||
499 | fsi->periods = (fsi->periods + 1) % runtime->periods; | ||
500 | |||
501 | if (0 == fsi->periods) | ||
502 | fsi->byte_offset = 0; | ||
503 | } | ||
504 | |||
505 | /* get 1 channel data width */ | ||
506 | width = frames_to_bytes(runtime, 1) / fsi->chan; | ||
507 | |||
508 | /* get send size for alsa */ | ||
509 | send = (fsi->buffer_len - fsi->byte_offset) / width; | ||
510 | |||
511 | /* get FIFO free size */ | ||
512 | fifo_free = (fsi->fifo_max * fsi->chan) - fsi_get_fifo_residue(fsi, 1); | ||
513 | |||
514 | /* size check */ | ||
515 | if (fifo_free < send) | ||
516 | send = fifo_free; | ||
517 | |||
518 | if (2 == width) | ||
519 | fsi_16data_push(fsi, runtime, send); | ||
520 | else if (4 == width) | ||
521 | fsi_32data_push(fsi, runtime, send); | ||
522 | else | ||
523 | return -EINVAL; | ||
524 | |||
525 | fsi->byte_offset += send * width; | ||
526 | |||
527 | fsi_irq_enable(fsi, 1); | ||
528 | |||
529 | if (substream) | ||
530 | snd_pcm_period_elapsed(substream); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static irqreturn_t fsi_interrupt(int irq, void *data) | ||
536 | { | ||
537 | u32 status = fsi_master_read(SOFT_RST) & ~0x00000010; | ||
538 | u32 int_st = fsi_master_read(INT_ST); | ||
539 | |||
540 | /* clear irq status */ | ||
541 | fsi_master_write(SOFT_RST, status); | ||
542 | fsi_master_write(SOFT_RST, status | 0x00000010); | ||
543 | |||
544 | if (int_st & INT_A_OUT) | ||
545 | fsi_data_push(&master->fsia); | ||
546 | if (int_st & INT_B_OUT) | ||
547 | fsi_data_push(&master->fsib); | ||
548 | |||
549 | fsi_master_write(INT_ST, 0x0000000); | ||
550 | |||
551 | return IRQ_HANDLED; | ||
552 | } | ||
553 | |||
554 | /************************************************************************ | ||
555 | |||
556 | |||
557 | dai ops | ||
558 | |||
559 | |||
560 | ************************************************************************/ | ||
561 | static int fsi_dai_startup(struct snd_pcm_substream *substream, | ||
562 | struct snd_soc_dai *dai) | ||
563 | { | ||
564 | struct fsi_priv *fsi = fsi_get(substream); | ||
565 | const char *msg; | ||
566 | u32 flags = fsi_get_info_flags(fsi); | ||
567 | u32 fmt; | ||
568 | u32 reg; | ||
569 | u32 data; | ||
570 | int is_play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
571 | int is_master; | ||
572 | int ret = 0; | ||
573 | |||
574 | clk_enable(master->clk); | ||
575 | |||
576 | /* CKG1 */ | ||
577 | data = is_play ? (1 << 0) : (1 << 4); | ||
578 | is_master = fsi_is_master_mode(fsi, is_play); | ||
579 | if (is_master) | ||
580 | fsi_reg_mask_set(fsi, CKG1, data, data); | ||
581 | else | ||
582 | fsi_reg_mask_set(fsi, CKG1, data, 0); | ||
583 | |||
584 | /* clock inversion (CKG2) */ | ||
585 | data = 0; | ||
586 | switch (SH_FSI_INVERSION_MASK & flags) { | ||
587 | case SH_FSI_LRM_INV: | ||
588 | data = 1 << 12; | ||
589 | break; | ||
590 | case SH_FSI_BRM_INV: | ||
591 | data = 1 << 8; | ||
592 | break; | ||
593 | case SH_FSI_LRS_INV: | ||
594 | data = 1 << 4; | ||
595 | break; | ||
596 | case SH_FSI_BRS_INV: | ||
597 | data = 1 << 0; | ||
598 | break; | ||
599 | } | ||
600 | fsi_reg_write(fsi, CKG2, data); | ||
601 | |||
602 | /* do fmt, di fmt */ | ||
603 | data = 0; | ||
604 | reg = is_play ? DO_FMT : DI_FMT; | ||
605 | fmt = is_play ? SH_FSI_GET_OFMT(flags) : SH_FSI_GET_IFMT(flags); | ||
606 | switch (fmt) { | ||
607 | case SH_FSI_FMT_MONO: | ||
608 | msg = "MONO"; | ||
609 | data = CR_FMT(CR_MONO); | ||
610 | fsi->chan = 1; | ||
611 | break; | ||
612 | case SH_FSI_FMT_MONO_DELAY: | ||
613 | msg = "MONO Delay"; | ||
614 | data = CR_FMT(CR_MONO_D); | ||
615 | fsi->chan = 1; | ||
616 | break; | ||
617 | case SH_FSI_FMT_PCM: | ||
618 | msg = "PCM"; | ||
619 | data = CR_FMT(CR_PCM); | ||
620 | fsi->chan = 2; | ||
621 | break; | ||
622 | case SH_FSI_FMT_I2S: | ||
623 | msg = "I2S"; | ||
624 | data = CR_FMT(CR_I2S); | ||
625 | fsi->chan = 2; | ||
626 | break; | ||
627 | case SH_FSI_FMT_TDM: | ||
628 | msg = "TDM"; | ||
629 | data = CR_FMT(CR_TDM) | (fsi->chan - 1); | ||
630 | fsi->chan = is_play ? | ||
631 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
632 | break; | ||
633 | case SH_FSI_FMT_TDM_DELAY: | ||
634 | msg = "TDM Delay"; | ||
635 | data = CR_FMT(CR_TDM_D) | (fsi->chan - 1); | ||
636 | fsi->chan = is_play ? | ||
637 | SH_FSI_GET_CH_O(flags) : SH_FSI_GET_CH_I(flags); | ||
638 | break; | ||
639 | default: | ||
640 | dev_err(dai->dev, "unknown format.\n"); | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | switch (fsi->chan) { | ||
645 | case 1: | ||
646 | fsi->fifo_max = 256; | ||
647 | break; | ||
648 | case 2: | ||
649 | fsi->fifo_max = 128; | ||
650 | break; | ||
651 | case 3: | ||
652 | case 4: | ||
653 | fsi->fifo_max = 64; | ||
654 | break; | ||
655 | case 5: | ||
656 | case 6: | ||
657 | case 7: | ||
658 | case 8: | ||
659 | fsi->fifo_max = 32; | ||
660 | break; | ||
661 | default: | ||
662 | dev_err(dai->dev, "channel size error.\n"); | ||
663 | return -EINVAL; | ||
664 | } | ||
665 | |||
666 | fsi_reg_write(fsi, reg, data); | ||
667 | dev_dbg(dai->dev, "use %s format (%d channel) use %d DMAC\n", | ||
668 | msg, fsi->chan, fsi->dma_chan); | ||
669 | |||
670 | /* | ||
671 | * clear clk reset if master mode | ||
672 | */ | ||
673 | if (is_master) | ||
674 | fsi_clk_ctrl(fsi, 1); | ||
675 | |||
676 | /* irq setting */ | ||
677 | fsi_irq_init(fsi, is_play); | ||
678 | |||
679 | return ret; | ||
680 | } | ||
681 | |||
682 | static void fsi_dai_shutdown(struct snd_pcm_substream *substream, | ||
683 | struct snd_soc_dai *dai) | ||
684 | { | ||
685 | struct fsi_priv *fsi = fsi_get(substream); | ||
686 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
687 | |||
688 | fsi_irq_disable(fsi, is_play); | ||
689 | fsi_clk_ctrl(fsi, 0); | ||
690 | |||
691 | clk_disable(master->clk); | ||
692 | } | ||
693 | |||
694 | static int fsi_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
695 | struct snd_soc_dai *dai) | ||
696 | { | ||
697 | struct fsi_priv *fsi = fsi_get(substream); | ||
698 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
699 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
700 | int ret = 0; | ||
701 | |||
702 | /* capture not supported */ | ||
703 | if (!is_play) | ||
704 | return -ENODEV; | ||
705 | |||
706 | switch (cmd) { | ||
707 | case SNDRV_PCM_TRIGGER_START: | ||
708 | fsi_stream_push(fsi, substream, | ||
709 | frames_to_bytes(runtime, runtime->buffer_size), | ||
710 | frames_to_bytes(runtime, runtime->period_size)); | ||
711 | ret = fsi_data_push(fsi); | ||
712 | break; | ||
713 | case SNDRV_PCM_TRIGGER_STOP: | ||
714 | fsi_irq_disable(fsi, is_play); | ||
715 | fsi_stream_pop(fsi); | ||
716 | break; | ||
717 | } | ||
718 | |||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | static struct snd_soc_dai_ops fsi_dai_ops = { | ||
723 | .startup = fsi_dai_startup, | ||
724 | .shutdown = fsi_dai_shutdown, | ||
725 | .trigger = fsi_dai_trigger, | ||
726 | }; | ||
727 | |||
728 | /************************************************************************ | ||
729 | |||
730 | |||
731 | pcm ops | ||
732 | |||
733 | |||
734 | ************************************************************************/ | ||
735 | static struct snd_pcm_hardware fsi_pcm_hardware = { | ||
736 | .info = SNDRV_PCM_INFO_INTERLEAVED | | ||
737 | SNDRV_PCM_INFO_MMAP | | ||
738 | SNDRV_PCM_INFO_MMAP_VALID | | ||
739 | SNDRV_PCM_INFO_PAUSE, | ||
740 | .formats = FSI_FMTS, | ||
741 | .rates = FSI_RATES, | ||
742 | .rate_min = 8000, | ||
743 | .rate_max = 192000, | ||
744 | .channels_min = 1, | ||
745 | .channels_max = 2, | ||
746 | .buffer_bytes_max = 64 * 1024, | ||
747 | .period_bytes_min = 32, | ||
748 | .period_bytes_max = 8192, | ||
749 | .periods_min = 1, | ||
750 | .periods_max = 32, | ||
751 | .fifo_size = 256, | ||
752 | }; | ||
753 | |||
754 | static int fsi_pcm_open(struct snd_pcm_substream *substream) | ||
755 | { | ||
756 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
757 | int ret = 0; | ||
758 | |||
759 | snd_soc_set_runtime_hwparams(substream, &fsi_pcm_hardware); | ||
760 | |||
761 | ret = snd_pcm_hw_constraint_integer(runtime, | ||
762 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
763 | |||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | static int fsi_hw_params(struct snd_pcm_substream *substream, | ||
768 | struct snd_pcm_hw_params *hw_params) | ||
769 | { | ||
770 | return snd_pcm_lib_malloc_pages(substream, | ||
771 | params_buffer_bytes(hw_params)); | ||
772 | } | ||
773 | |||
774 | static int fsi_hw_free(struct snd_pcm_substream *substream) | ||
775 | { | ||
776 | return snd_pcm_lib_free_pages(substream); | ||
777 | } | ||
778 | |||
779 | static snd_pcm_uframes_t fsi_pointer(struct snd_pcm_substream *substream) | ||
780 | { | ||
781 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
782 | struct fsi_priv *fsi = fsi_get(substream); | ||
783 | int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
784 | long location; | ||
785 | |||
786 | location = (fsi->byte_offset - 1) - fsi_get_residue(fsi, is_play); | ||
787 | if (location < 0) | ||
788 | location = 0; | ||
789 | |||
790 | return bytes_to_frames(runtime, location); | ||
791 | } | ||
792 | |||
793 | static struct snd_pcm_ops fsi_pcm_ops = { | ||
794 | .open = fsi_pcm_open, | ||
795 | .ioctl = snd_pcm_lib_ioctl, | ||
796 | .hw_params = fsi_hw_params, | ||
797 | .hw_free = fsi_hw_free, | ||
798 | .pointer = fsi_pointer, | ||
799 | }; | ||
800 | |||
801 | /************************************************************************ | ||
802 | |||
803 | |||
804 | snd_soc_platform | ||
805 | |||
806 | |||
807 | ************************************************************************/ | ||
808 | #define PREALLOC_BUFFER (32 * 1024) | ||
809 | #define PREALLOC_BUFFER_MAX (32 * 1024) | ||
810 | |||
811 | static void fsi_pcm_free(struct snd_pcm *pcm) | ||
812 | { | ||
813 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
814 | } | ||
815 | |||
816 | static int fsi_pcm_new(struct snd_card *card, | ||
817 | struct snd_soc_dai *dai, | ||
818 | struct snd_pcm *pcm) | ||
819 | { | ||
820 | /* | ||
821 | * dont use SNDRV_DMA_TYPE_DEV, since it will oops the SH kernel | ||
822 | * in MMAP mode (i.e. aplay -M) | ||
823 | */ | ||
824 | return snd_pcm_lib_preallocate_pages_for_all( | ||
825 | pcm, | ||
826 | SNDRV_DMA_TYPE_CONTINUOUS, | ||
827 | snd_dma_continuous_data(GFP_KERNEL), | ||
828 | PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); | ||
829 | } | ||
830 | |||
831 | /************************************************************************ | ||
832 | |||
833 | |||
834 | alsa struct | ||
835 | |||
836 | |||
837 | ************************************************************************/ | ||
838 | struct snd_soc_dai fsi_soc_dai[] = { | ||
839 | { | ||
840 | .name = "FSIA", | ||
841 | .id = 0, | ||
842 | .playback = { | ||
843 | .rates = FSI_RATES, | ||
844 | .formats = FSI_FMTS, | ||
845 | .channels_min = 1, | ||
846 | .channels_max = 8, | ||
847 | }, | ||
848 | /* capture not supported */ | ||
849 | .ops = &fsi_dai_ops, | ||
850 | }, | ||
851 | { | ||
852 | .name = "FSIB", | ||
853 | .id = 1, | ||
854 | .playback = { | ||
855 | .rates = FSI_RATES, | ||
856 | .formats = FSI_FMTS, | ||
857 | .channels_min = 1, | ||
858 | .channels_max = 8, | ||
859 | }, | ||
860 | /* capture not supported */ | ||
861 | .ops = &fsi_dai_ops, | ||
862 | }, | ||
863 | }; | ||
864 | EXPORT_SYMBOL_GPL(fsi_soc_dai); | ||
865 | |||
866 | struct snd_soc_platform fsi_soc_platform = { | ||
867 | .name = "fsi-pcm", | ||
868 | .pcm_ops = &fsi_pcm_ops, | ||
869 | .pcm_new = fsi_pcm_new, | ||
870 | .pcm_free = fsi_pcm_free, | ||
871 | }; | ||
872 | EXPORT_SYMBOL_GPL(fsi_soc_platform); | ||
873 | |||
874 | /************************************************************************ | ||
875 | |||
876 | |||
877 | platform function | ||
878 | |||
879 | |||
880 | ************************************************************************/ | ||
881 | static int fsi_probe(struct platform_device *pdev) | ||
882 | { | ||
883 | struct resource *res; | ||
884 | char clk_name[8]; | ||
885 | unsigned int irq; | ||
886 | int ret; | ||
887 | |||
888 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
889 | irq = platform_get_irq(pdev, 0); | ||
890 | if (!res || !irq) { | ||
891 | dev_err(&pdev->dev, "Not enough FSI platform resources.\n"); | ||
892 | ret = -ENODEV; | ||
893 | goto exit; | ||
894 | } | ||
895 | |||
896 | master = kzalloc(sizeof(*master), GFP_KERNEL); | ||
897 | if (!master) { | ||
898 | dev_err(&pdev->dev, "Could not allocate master\n"); | ||
899 | ret = -ENOMEM; | ||
900 | goto exit; | ||
901 | } | ||
902 | |||
903 | master->base = ioremap_nocache(res->start, resource_size(res)); | ||
904 | if (!master->base) { | ||
905 | ret = -ENXIO; | ||
906 | dev_err(&pdev->dev, "Unable to ioremap FSI registers.\n"); | ||
907 | goto exit_kfree; | ||
908 | } | ||
909 | |||
910 | master->irq = irq; | ||
911 | master->info = pdev->dev.platform_data; | ||
912 | master->fsia.base = master->base; | ||
913 | master->fsib.base = master->base + 0x40; | ||
914 | |||
915 | master->fsia.dma_chan = -1; | ||
916 | master->fsib.dma_chan = -1; | ||
917 | |||
918 | ret = fsi_get_dma_chan(); | ||
919 | if (ret < 0) { | ||
920 | dev_err(&pdev->dev, "cannot get dma api\n"); | ||
921 | goto exit_iounmap; | ||
922 | } | ||
923 | |||
924 | /* FSI is based on SPU mstp */ | ||
925 | snprintf(clk_name, sizeof(clk_name), "spu%d", pdev->id); | ||
926 | master->clk = clk_get(NULL, clk_name); | ||
927 | if (IS_ERR(master->clk)) { | ||
928 | dev_err(&pdev->dev, "cannot get %s mstp\n", clk_name); | ||
929 | ret = -EIO; | ||
930 | goto exit_free_dma; | ||
931 | } | ||
932 | |||
933 | fsi_soc_dai[0].dev = &pdev->dev; | ||
934 | fsi_soc_dai[1].dev = &pdev->dev; | ||
935 | |||
936 | fsi_soft_all_reset(); | ||
937 | |||
938 | ret = request_irq(irq, &fsi_interrupt, IRQF_DISABLED, "fsi", master); | ||
939 | if (ret) { | ||
940 | dev_err(&pdev->dev, "irq request err\n"); | ||
941 | goto exit_free_dma; | ||
942 | } | ||
943 | |||
944 | ret = snd_soc_register_platform(&fsi_soc_platform); | ||
945 | if (ret < 0) { | ||
946 | dev_err(&pdev->dev, "cannot snd soc register\n"); | ||
947 | goto exit_free_irq; | ||
948 | } | ||
949 | |||
950 | return snd_soc_register_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); | ||
951 | |||
952 | exit_free_irq: | ||
953 | free_irq(irq, master); | ||
954 | exit_free_dma: | ||
955 | fsi_free_dma_chan(); | ||
956 | exit_iounmap: | ||
957 | iounmap(master->base); | ||
958 | exit_kfree: | ||
959 | kfree(master); | ||
960 | master = NULL; | ||
961 | exit: | ||
962 | return ret; | ||
963 | } | ||
964 | |||
965 | static int fsi_remove(struct platform_device *pdev) | ||
966 | { | ||
967 | snd_soc_unregister_dais(fsi_soc_dai, ARRAY_SIZE(fsi_soc_dai)); | ||
968 | snd_soc_unregister_platform(&fsi_soc_platform); | ||
969 | |||
970 | clk_put(master->clk); | ||
971 | |||
972 | fsi_free_dma_chan(); | ||
973 | |||
974 | free_irq(master->irq, master); | ||
975 | |||
976 | iounmap(master->base); | ||
977 | kfree(master); | ||
978 | master = NULL; | ||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static struct platform_driver fsi_driver = { | ||
983 | .driver = { | ||
984 | .name = "sh_fsi", | ||
985 | }, | ||
986 | .probe = fsi_probe, | ||
987 | .remove = fsi_remove, | ||
988 | }; | ||
989 | |||
990 | static int __init fsi_mobile_init(void) | ||
991 | { | ||
992 | return platform_driver_register(&fsi_driver); | ||
993 | } | ||
994 | |||
995 | static void __exit fsi_mobile_exit(void) | ||
996 | { | ||
997 | platform_driver_unregister(&fsi_driver); | ||
998 | } | ||
999 | module_init(fsi_mobile_init); | ||
1000 | module_exit(fsi_mobile_exit); | ||
1001 | |||
1002 | MODULE_LICENSE("GPL"); | ||
1003 | MODULE_DESCRIPTION("SuperH onchip FSI audio driver"); | ||
1004 | MODULE_AUTHOR("Kuninori Morimoto <morimoto.kuninori@renesas.com>"); | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index c8ceddc2a26c..d2505e8b06c9 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -77,6 +77,35 @@ static int snd_soc_7_9_spi_write(void *control_data, const char *data, | |||
77 | #define snd_soc_7_9_spi_write NULL | 77 | #define snd_soc_7_9_spi_write NULL |
78 | #endif | 78 | #endif |
79 | 79 | ||
80 | static int snd_soc_8_8_write(struct snd_soc_codec *codec, unsigned int reg, | ||
81 | unsigned int value) | ||
82 | { | ||
83 | u8 *cache = codec->reg_cache; | ||
84 | u8 data[2]; | ||
85 | |||
86 | BUG_ON(codec->volatile_register); | ||
87 | |||
88 | data[0] = reg & 0xff; | ||
89 | data[1] = value & 0xff; | ||
90 | |||
91 | if (reg < codec->reg_cache_size) | ||
92 | cache[reg] = value; | ||
93 | |||
94 | if (codec->hw_write(codec->control_data, data, 2) == 2) | ||
95 | return 0; | ||
96 | else | ||
97 | return -EIO; | ||
98 | } | ||
99 | |||
100 | static unsigned int snd_soc_8_8_read(struct snd_soc_codec *codec, | ||
101 | unsigned int reg) | ||
102 | { | ||
103 | u8 *cache = codec->reg_cache; | ||
104 | if (reg >= codec->reg_cache_size) | ||
105 | return -1; | ||
106 | return cache[reg]; | ||
107 | } | ||
108 | |||
80 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, | 109 | static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, |
81 | unsigned int value) | 110 | unsigned int value) |
82 | { | 111 | { |
@@ -150,9 +179,20 @@ static struct { | |||
150 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); | 179 | unsigned int (*read)(struct snd_soc_codec *, unsigned int); |
151 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); | 180 | unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); |
152 | } io_types[] = { | 181 | } io_types[] = { |
153 | { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, | 182 | { |
154 | { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, | 183 | .addr_bits = 7, .data_bits = 9, |
155 | snd_soc_8_16_read_i2c }, | 184 | .write = snd_soc_7_9_write, .read = snd_soc_7_9_read, |
185 | .spi_write = snd_soc_7_9_spi_write | ||
186 | }, | ||
187 | { | ||
188 | .addr_bits = 8, .data_bits = 8, | ||
189 | .write = snd_soc_8_8_write, .read = snd_soc_8_8_read, | ||
190 | }, | ||
191 | { | ||
192 | .addr_bits = 8, .data_bits = 16, | ||
193 | .write = snd_soc_8_16_write, .read = snd_soc_8_16_read, | ||
194 | .i2c_read = snd_soc_8_16_read_i2c, | ||
195 | }, | ||
156 | }; | 196 | }; |
157 | 197 | ||
158 | /** | 198 | /** |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index e984a17cd656..f5b356f8acfb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -1267,10 +1267,18 @@ static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | |||
1267 | if (!codec->debugfs_pop_time) | 1267 | if (!codec->debugfs_pop_time) |
1268 | printk(KERN_WARNING | 1268 | printk(KERN_WARNING |
1269 | "Failed to create pop time debugfs file\n"); | 1269 | "Failed to create pop time debugfs file\n"); |
1270 | |||
1271 | codec->debugfs_dapm = debugfs_create_dir("dapm", debugfs_root); | ||
1272 | if (!codec->debugfs_dapm) | ||
1273 | printk(KERN_WARNING | ||
1274 | "Failed to create DAPM debugfs directory\n"); | ||
1275 | |||
1276 | snd_soc_dapm_debugfs_init(codec); | ||
1270 | } | 1277 | } |
1271 | 1278 | ||
1272 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | 1279 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) |
1273 | { | 1280 | { |
1281 | debugfs_remove_recursive(codec->debugfs_dapm); | ||
1274 | debugfs_remove(codec->debugfs_pop_time); | 1282 | debugfs_remove(codec->debugfs_pop_time); |
1275 | debugfs_remove(codec->debugfs_reg); | 1283 | debugfs_remove(codec->debugfs_reg); |
1276 | } | 1284 | } |
@@ -2189,16 +2197,18 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); | |||
2189 | * snd_soc_dai_set_pll - configure DAI PLL. | 2197 | * snd_soc_dai_set_pll - configure DAI PLL. |
2190 | * @dai: DAI | 2198 | * @dai: DAI |
2191 | * @pll_id: DAI specific PLL ID | 2199 | * @pll_id: DAI specific PLL ID |
2200 | * @source: DAI specific source for the PLL | ||
2192 | * @freq_in: PLL input clock frequency in Hz | 2201 | * @freq_in: PLL input clock frequency in Hz |
2193 | * @freq_out: requested PLL output clock frequency in Hz | 2202 | * @freq_out: requested PLL output clock frequency in Hz |
2194 | * | 2203 | * |
2195 | * Configures and enables PLL to generate output clock based on input clock. | 2204 | * Configures and enables PLL to generate output clock based on input clock. |
2196 | */ | 2205 | */ |
2197 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, | 2206 | int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, int source, |
2198 | int pll_id, unsigned int freq_in, unsigned int freq_out) | 2207 | unsigned int freq_in, unsigned int freq_out) |
2199 | { | 2208 | { |
2200 | if (dai->ops && dai->ops->set_pll) | 2209 | if (dai->ops && dai->ops->set_pll) |
2201 | return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); | 2210 | return dai->ops->set_pll(dai, pll_id, source, |
2211 | freq_in, freq_out); | ||
2202 | else | 2212 | else |
2203 | return -EINVAL; | 2213 | return -EINVAL; |
2204 | } | 2214 | } |
@@ -2243,6 +2253,30 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | |||
2243 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 2253 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
2244 | 2254 | ||
2245 | /** | 2255 | /** |
2256 | * snd_soc_dai_set_channel_map - configure DAI audio channel map | ||
2257 | * @dai: DAI | ||
2258 | * @tx_num: how many TX channels | ||
2259 | * @tx_slot: pointer to an array which imply the TX slot number channel | ||
2260 | * 0~num-1 uses | ||
2261 | * @rx_num: how many RX channels | ||
2262 | * @rx_slot: pointer to an array which imply the RX slot number channel | ||
2263 | * 0~num-1 uses | ||
2264 | * | ||
2265 | * configure the relationship between channel number and TDM slot number. | ||
2266 | */ | ||
2267 | int snd_soc_dai_set_channel_map(struct snd_soc_dai *dai, | ||
2268 | unsigned int tx_num, unsigned int *tx_slot, | ||
2269 | unsigned int rx_num, unsigned int *rx_slot) | ||
2270 | { | ||
2271 | if (dai->ops && dai->ops->set_channel_map) | ||
2272 | return dai->ops->set_channel_map(dai, tx_num, tx_slot, | ||
2273 | rx_num, rx_slot); | ||
2274 | else | ||
2275 | return -EINVAL; | ||
2276 | } | ||
2277 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_channel_map); | ||
2278 | |||
2279 | /** | ||
2246 | * snd_soc_dai_set_tristate - configure DAI system or master clock. | 2280 | * snd_soc_dai_set_tristate - configure DAI system or master clock. |
2247 | * @dai: DAI | 2281 | * @dai: DAI |
2248 | * @tristate: tristate enable | 2282 | * @tristate: tristate enable |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 88461310dc96..9babda559c92 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/bitops.h> | 37 | #include <linux/bitops.h> |
38 | #include <linux/platform_device.h> | 38 | #include <linux/platform_device.h> |
39 | #include <linux/jiffies.h> | 39 | #include <linux/jiffies.h> |
40 | #include <linux/debugfs.h> | ||
40 | #include <sound/core.h> | 41 | #include <sound/core.h> |
41 | #include <sound/pcm.h> | 42 | #include <sound/pcm.h> |
42 | #include <sound/pcm_params.h> | 43 | #include <sound/pcm_params.h> |
@@ -55,17 +56,19 @@ static int dapm_up_seq[] = { | |||
55 | [snd_soc_dapm_pre] = 0, | 56 | [snd_soc_dapm_pre] = 0, |
56 | [snd_soc_dapm_supply] = 1, | 57 | [snd_soc_dapm_supply] = 1, |
57 | [snd_soc_dapm_micbias] = 2, | 58 | [snd_soc_dapm_micbias] = 2, |
58 | [snd_soc_dapm_mic] = 3, | 59 | [snd_soc_dapm_aif_in] = 3, |
59 | [snd_soc_dapm_mux] = 4, | 60 | [snd_soc_dapm_aif_out] = 3, |
60 | [snd_soc_dapm_value_mux] = 4, | 61 | [snd_soc_dapm_mic] = 4, |
61 | [snd_soc_dapm_dac] = 5, | 62 | [snd_soc_dapm_mux] = 5, |
62 | [snd_soc_dapm_mixer] = 6, | 63 | [snd_soc_dapm_value_mux] = 5, |
63 | [snd_soc_dapm_mixer_named_ctl] = 6, | 64 | [snd_soc_dapm_dac] = 6, |
64 | [snd_soc_dapm_pga] = 7, | 65 | [snd_soc_dapm_mixer] = 7, |
65 | [snd_soc_dapm_adc] = 8, | 66 | [snd_soc_dapm_mixer_named_ctl] = 7, |
66 | [snd_soc_dapm_hp] = 9, | 67 | [snd_soc_dapm_pga] = 8, |
67 | [snd_soc_dapm_spk] = 9, | 68 | [snd_soc_dapm_adc] = 9, |
68 | [snd_soc_dapm_post] = 10, | 69 | [snd_soc_dapm_hp] = 10, |
70 | [snd_soc_dapm_spk] = 10, | ||
71 | [snd_soc_dapm_post] = 11, | ||
69 | }; | 72 | }; |
70 | 73 | ||
71 | static int dapm_down_seq[] = { | 74 | static int dapm_down_seq[] = { |
@@ -81,8 +84,10 @@ static int dapm_down_seq[] = { | |||
81 | [snd_soc_dapm_micbias] = 8, | 84 | [snd_soc_dapm_micbias] = 8, |
82 | [snd_soc_dapm_mux] = 9, | 85 | [snd_soc_dapm_mux] = 9, |
83 | [snd_soc_dapm_value_mux] = 9, | 86 | [snd_soc_dapm_value_mux] = 9, |
84 | [snd_soc_dapm_supply] = 10, | 87 | [snd_soc_dapm_aif_in] = 10, |
85 | [snd_soc_dapm_post] = 11, | 88 | [snd_soc_dapm_aif_out] = 10, |
89 | [snd_soc_dapm_supply] = 11, | ||
90 | [snd_soc_dapm_post] = 12, | ||
86 | }; | 91 | }; |
87 | 92 | ||
88 | static void pop_wait(u32 pop_time) | 93 | static void pop_wait(u32 pop_time) |
@@ -148,8 +153,12 @@ static int snd_soc_dapm_set_bias_level(struct snd_soc_device *socdev, | |||
148 | 153 | ||
149 | if (card->set_bias_level) | 154 | if (card->set_bias_level) |
150 | ret = card->set_bias_level(card, level); | 155 | ret = card->set_bias_level(card, level); |
151 | if (ret == 0 && codec->set_bias_level) | 156 | if (ret == 0) { |
152 | ret = codec->set_bias_level(codec, level); | 157 | if (codec->set_bias_level) |
158 | ret = codec->set_bias_level(codec, level); | ||
159 | else | ||
160 | codec->bias_level = level; | ||
161 | } | ||
153 | 162 | ||
154 | return ret; | 163 | return ret; |
155 | } | 164 | } |
@@ -224,6 +233,8 @@ static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | |||
224 | case snd_soc_dapm_micbias: | 233 | case snd_soc_dapm_micbias: |
225 | case snd_soc_dapm_vmid: | 234 | case snd_soc_dapm_vmid: |
226 | case snd_soc_dapm_supply: | 235 | case snd_soc_dapm_supply: |
236 | case snd_soc_dapm_aif_in: | ||
237 | case snd_soc_dapm_aif_out: | ||
227 | p->connect = 1; | 238 | p->connect = 1; |
228 | break; | 239 | break; |
229 | /* does effect routing - dynamically connected */ | 240 | /* does effect routing - dynamically connected */ |
@@ -497,8 +508,14 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget) | |||
497 | if (widget->id == snd_soc_dapm_supply) | 508 | if (widget->id == snd_soc_dapm_supply) |
498 | return 0; | 509 | return 0; |
499 | 510 | ||
500 | if (widget->id == snd_soc_dapm_adc && widget->active) | 511 | switch (widget->id) { |
501 | return 1; | 512 | case snd_soc_dapm_adc: |
513 | case snd_soc_dapm_aif_out: | ||
514 | if (widget->active) | ||
515 | return 1; | ||
516 | default: | ||
517 | break; | ||
518 | } | ||
502 | 519 | ||
503 | if (widget->connected) { | 520 | if (widget->connected) { |
504 | /* connected pin ? */ | 521 | /* connected pin ? */ |
@@ -537,8 +554,14 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget) | |||
537 | return 0; | 554 | return 0; |
538 | 555 | ||
539 | /* active stream ? */ | 556 | /* active stream ? */ |
540 | if (widget->id == snd_soc_dapm_dac && widget->active) | 557 | switch (widget->id) { |
541 | return 1; | 558 | case snd_soc_dapm_dac: |
559 | case snd_soc_dapm_aif_in: | ||
560 | if (widget->active) | ||
561 | return 1; | ||
562 | default: | ||
563 | break; | ||
564 | } | ||
542 | 565 | ||
543 | if (widget->connected) { | 566 | if (widget->connected) { |
544 | /* connected pin ? */ | 567 | /* connected pin ? */ |
@@ -695,6 +718,10 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w) | |||
695 | 718 | ||
696 | /* Check if one of our outputs is connected */ | 719 | /* Check if one of our outputs is connected */ |
697 | list_for_each_entry(path, &w->sinks, list_source) { | 720 | list_for_each_entry(path, &w->sinks, list_source) { |
721 | if (path->connected && | ||
722 | !path->connected(path->source, path->sink)) | ||
723 | continue; | ||
724 | |||
698 | if (path->sink && path->sink->power_check && | 725 | if (path->sink && path->sink->power_check && |
699 | path->sink->power_check(path->sink)) { | 726 | path->sink->power_check(path->sink)) { |
700 | power = 1; | 727 | power = 1; |
@@ -1052,6 +1079,8 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
1052 | case snd_soc_dapm_mixer: | 1079 | case snd_soc_dapm_mixer: |
1053 | case snd_soc_dapm_mixer_named_ctl: | 1080 | case snd_soc_dapm_mixer_named_ctl: |
1054 | case snd_soc_dapm_supply: | 1081 | case snd_soc_dapm_supply: |
1082 | case snd_soc_dapm_aif_in: | ||
1083 | case snd_soc_dapm_aif_out: | ||
1055 | if (w->name) { | 1084 | if (w->name) { |
1056 | in = is_connected_input_ep(w); | 1085 | in = is_connected_input_ep(w); |
1057 | dapm_clear_walk(w->codec); | 1086 | dapm_clear_walk(w->codec); |
@@ -1077,6 +1106,99 @@ static void dbg_dump_dapm(struct snd_soc_codec* codec, const char *action) | |||
1077 | } | 1106 | } |
1078 | #endif | 1107 | #endif |
1079 | 1108 | ||
1109 | #ifdef CONFIG_DEBUG_FS | ||
1110 | static int dapm_widget_power_open_file(struct inode *inode, struct file *file) | ||
1111 | { | ||
1112 | file->private_data = inode->i_private; | ||
1113 | return 0; | ||
1114 | } | ||
1115 | |||
1116 | static ssize_t dapm_widget_power_read_file(struct file *file, | ||
1117 | char __user *user_buf, | ||
1118 | size_t count, loff_t *ppos) | ||
1119 | { | ||
1120 | struct snd_soc_dapm_widget *w = file->private_data; | ||
1121 | char *buf; | ||
1122 | int in, out; | ||
1123 | ssize_t ret; | ||
1124 | struct snd_soc_dapm_path *p = NULL; | ||
1125 | |||
1126 | buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
1127 | if (!buf) | ||
1128 | return -ENOMEM; | ||
1129 | |||
1130 | in = is_connected_input_ep(w); | ||
1131 | dapm_clear_walk(w->codec); | ||
1132 | out = is_connected_output_ep(w); | ||
1133 | dapm_clear_walk(w->codec); | ||
1134 | |||
1135 | ret = snprintf(buf, PAGE_SIZE, "%s: %s in %d out %d\n", | ||
1136 | w->name, w->power ? "On" : "Off", in, out); | ||
1137 | |||
1138 | if (w->sname) | ||
1139 | ret += snprintf(buf + ret, PAGE_SIZE - ret, " stream %s %s\n", | ||
1140 | w->sname, | ||
1141 | w->active ? "active" : "inactive"); | ||
1142 | |||
1143 | list_for_each_entry(p, &w->sources, list_sink) { | ||
1144 | if (p->connected && !p->connected(w, p->sink)) | ||
1145 | continue; | ||
1146 | |||
1147 | if (p->connect) | ||
1148 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1149 | " in %s %s\n", | ||
1150 | p->name ? p->name : "static", | ||
1151 | p->source->name); | ||
1152 | } | ||
1153 | list_for_each_entry(p, &w->sinks, list_source) { | ||
1154 | if (p->connected && !p->connected(w, p->sink)) | ||
1155 | continue; | ||
1156 | |||
1157 | if (p->connect) | ||
1158 | ret += snprintf(buf + ret, PAGE_SIZE - ret, | ||
1159 | " out %s %s\n", | ||
1160 | p->name ? p->name : "static", | ||
1161 | p->sink->name); | ||
1162 | } | ||
1163 | |||
1164 | ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); | ||
1165 | |||
1166 | kfree(buf); | ||
1167 | return ret; | ||
1168 | } | ||
1169 | |||
1170 | static const struct file_operations dapm_widget_power_fops = { | ||
1171 | .open = dapm_widget_power_open_file, | ||
1172 | .read = dapm_widget_power_read_file, | ||
1173 | }; | ||
1174 | |||
1175 | void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | ||
1176 | { | ||
1177 | struct snd_soc_dapm_widget *w; | ||
1178 | struct dentry *d; | ||
1179 | |||
1180 | if (!codec->debugfs_dapm) | ||
1181 | return; | ||
1182 | |||
1183 | list_for_each_entry(w, &codec->dapm_widgets, list) { | ||
1184 | if (!w->name) | ||
1185 | continue; | ||
1186 | |||
1187 | d = debugfs_create_file(w->name, 0444, | ||
1188 | codec->debugfs_dapm, w, | ||
1189 | &dapm_widget_power_fops); | ||
1190 | if (!d) | ||
1191 | printk(KERN_WARNING | ||
1192 | "ASoC: Failed to create %s debugfs file\n", | ||
1193 | w->name); | ||
1194 | } | ||
1195 | } | ||
1196 | #else | ||
1197 | void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec) | ||
1198 | { | ||
1199 | } | ||
1200 | #endif | ||
1201 | |||
1080 | /* test and update the power status of a mux widget */ | 1202 | /* test and update the power status of a mux widget */ |
1081 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, | 1203 | static int dapm_mux_update_power(struct snd_soc_dapm_widget *widget, |
1082 | struct snd_kcontrol *kcontrol, int mask, | 1204 | struct snd_kcontrol *kcontrol, int mask, |
@@ -1274,10 +1396,13 @@ int snd_soc_dapm_sync(struct snd_soc_codec *codec) | |||
1274 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); | 1396 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync); |
1275 | 1397 | ||
1276 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | 1398 | static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, |
1277 | const char *sink, const char *control, const char *source) | 1399 | const struct snd_soc_dapm_route *route) |
1278 | { | 1400 | { |
1279 | struct snd_soc_dapm_path *path; | 1401 | struct snd_soc_dapm_path *path; |
1280 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; | 1402 | struct snd_soc_dapm_widget *wsource = NULL, *wsink = NULL, *w; |
1403 | const char *sink = route->sink; | ||
1404 | const char *control = route->control; | ||
1405 | const char *source = route->source; | ||
1281 | int ret = 0; | 1406 | int ret = 0; |
1282 | 1407 | ||
1283 | /* find src and dest widgets */ | 1408 | /* find src and dest widgets */ |
@@ -1301,6 +1426,7 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1301 | 1426 | ||
1302 | path->source = wsource; | 1427 | path->source = wsource; |
1303 | path->sink = wsink; | 1428 | path->sink = wsink; |
1429 | path->connected = route->connected; | ||
1304 | INIT_LIST_HEAD(&path->list); | 1430 | INIT_LIST_HEAD(&path->list); |
1305 | INIT_LIST_HEAD(&path->list_source); | 1431 | INIT_LIST_HEAD(&path->list_source); |
1306 | INIT_LIST_HEAD(&path->list_sink); | 1432 | INIT_LIST_HEAD(&path->list_sink); |
@@ -1342,6 +1468,8 @@ static int snd_soc_dapm_add_route(struct snd_soc_codec *codec, | |||
1342 | case snd_soc_dapm_pre: | 1468 | case snd_soc_dapm_pre: |
1343 | case snd_soc_dapm_post: | 1469 | case snd_soc_dapm_post: |
1344 | case snd_soc_dapm_supply: | 1470 | case snd_soc_dapm_supply: |
1471 | case snd_soc_dapm_aif_in: | ||
1472 | case snd_soc_dapm_aif_out: | ||
1345 | list_add(&path->list, &codec->dapm_paths); | 1473 | list_add(&path->list, &codec->dapm_paths); |
1346 | list_add(&path->list_sink, &wsink->sources); | 1474 | list_add(&path->list_sink, &wsink->sources); |
1347 | list_add(&path->list_source, &wsource->sinks); | 1475 | list_add(&path->list_source, &wsource->sinks); |
@@ -1399,8 +1527,7 @@ int snd_soc_dapm_add_routes(struct snd_soc_codec *codec, | |||
1399 | int i, ret; | 1527 | int i, ret; |
1400 | 1528 | ||
1401 | for (i = 0; i < num; i++) { | 1529 | for (i = 0; i < num; i++) { |
1402 | ret = snd_soc_dapm_add_route(codec, route->sink, | 1530 | ret = snd_soc_dapm_add_route(codec, route); |
1403 | route->control, route->source); | ||
1404 | if (ret < 0) { | 1531 | if (ret < 0) { |
1405 | printk(KERN_ERR "Failed to add route %s->%s\n", | 1532 | printk(KERN_ERR "Failed to add route %s->%s\n", |
1406 | route->source, | 1533 | route->source, |
@@ -1444,9 +1571,11 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec) | |||
1444 | dapm_new_mux(codec, w); | 1571 | dapm_new_mux(codec, w); |
1445 | break; | 1572 | break; |
1446 | case snd_soc_dapm_adc: | 1573 | case snd_soc_dapm_adc: |
1574 | case snd_soc_dapm_aif_out: | ||
1447 | w->power_check = dapm_adc_check_power; | 1575 | w->power_check = dapm_adc_check_power; |
1448 | break; | 1576 | break; |
1449 | case snd_soc_dapm_dac: | 1577 | case snd_soc_dapm_dac: |
1578 | case snd_soc_dapm_aif_in: | ||
1450 | w->power_check = dapm_dac_check_power; | 1579 | w->power_check = dapm_dac_check_power; |
1451 | break; | 1580 | break; |
1452 | case snd_soc_dapm_pga: | 1581 | case snd_soc_dapm_pga: |