diff options
author | Barry Song <barry.song@analog.com> | 2011-03-28 01:45:10 -0400 |
---|---|---|
committer | Mark Brown <broonie@opensource.wolfsonmicro.com> | 2011-03-29 18:20:05 -0400 |
commit | 2c66cb99d134d787827ed1cd93cc59351ab66a95 (patch) | |
tree | 4c67200205b224947e9500b17af9537e54254a65 /sound/soc/blackfin/bf5xx-i2s.c | |
parent | bfe4ee0a935dccf5980ecb5605c66fe50feb9056 (diff) |
ASoC: Blackfin: push down SPORT settings from global variables
Now that we have multi-component support, take the time to unify the
SPORT implementations a bit and make the setup dynamic. This kills
off the global sport_handle which was shared across all the Blackfin
machine drivers. The pin management aspect is off loaded to platform
resources, and now multiple SPORTs can be instantiated simultaneously.
Signed-off-by: Barry Song <barry.song@analog.com>
Signed-off-by: Scott Jiang <scott.jiang@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Acked-by: Liam Girdwood <lrg@ti.com>
Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'sound/soc/blackfin/bf5xx-i2s.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s.c | 159 |
1 files changed, 63 insertions, 96 deletions
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index dacd86c2ead4..00cc3e00b2fe 100644 --- a/sound/soc/blackfin/bf5xx-i2s.c +++ b/sound/soc/blackfin/bf5xx-i2s.c | |||
@@ -51,59 +51,24 @@ struct bf5xx_i2s_port { | |||
51 | int configured; | 51 | int configured; |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static struct bf5xx_i2s_port bf5xx_i2s; | ||
55 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | ||
56 | |||
57 | static struct sport_param sport_params[2] = { | ||
58 | { | ||
59 | .dma_rx_chan = CH_SPORT0_RX, | ||
60 | .dma_tx_chan = CH_SPORT0_TX, | ||
61 | .err_irq = IRQ_SPORT0_ERROR, | ||
62 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
63 | }, | ||
64 | { | ||
65 | .dma_rx_chan = CH_SPORT1_RX, | ||
66 | .dma_tx_chan = CH_SPORT1_TX, | ||
67 | .err_irq = IRQ_SPORT1_ERROR, | ||
68 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
69 | } | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * Setting the TFS pin selector for SPORT 0 based on whether the selected | ||
74 | * port id F or G. If the port is F then no conflict should exist for the | ||
75 | * TFS. When Port G is selected and EMAC then there is a conflict between | ||
76 | * the PHY interrupt line and TFS. Current settings prevent the conflict | ||
77 | * by ignoring the TFS pin when Port G is selected. This allows both | ||
78 | * codecs and EMAC using Port G concurrently. | ||
79 | */ | ||
80 | #ifdef CONFIG_BF527_SPORT0_PORTG | ||
81 | #define LOCAL_SPORT0_TFS (0) | ||
82 | #else | ||
83 | #define LOCAL_SPORT0_TFS (P_SPORT0_TFS) | ||
84 | #endif | ||
85 | |||
86 | static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
87 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, | ||
88 | {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, | ||
89 | P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; | ||
90 | |||
91 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 54 | static int bf5xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
92 | unsigned int fmt) | 55 | unsigned int fmt) |
93 | { | 56 | { |
57 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(cpu_dai); | ||
58 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
94 | int ret = 0; | 59 | int ret = 0; |
95 | 60 | ||
96 | /* interface format:support I2S,slave mode */ | 61 | /* interface format:support I2S,slave mode */ |
97 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 62 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
98 | case SND_SOC_DAIFMT_I2S: | 63 | case SND_SOC_DAIFMT_I2S: |
99 | bf5xx_i2s.tcr1 |= TFSR | TCKFE; | 64 | bf5xx_i2s->tcr1 |= TFSR | TCKFE; |
100 | bf5xx_i2s.rcr1 |= RFSR | RCKFE; | 65 | bf5xx_i2s->rcr1 |= RFSR | RCKFE; |
101 | bf5xx_i2s.tcr2 |= TSFSE; | 66 | bf5xx_i2s->tcr2 |= TSFSE; |
102 | bf5xx_i2s.rcr2 |= RSFSE; | 67 | bf5xx_i2s->rcr2 |= RSFSE; |
103 | break; | 68 | break; |
104 | case SND_SOC_DAIFMT_DSP_A: | 69 | case SND_SOC_DAIFMT_DSP_A: |
105 | bf5xx_i2s.tcr1 |= TFSR; | 70 | bf5xx_i2s->tcr1 |= TFSR; |
106 | bf5xx_i2s.rcr1 |= RFSR; | 71 | bf5xx_i2s->rcr1 |= RFSR; |
107 | break; | 72 | break; |
108 | case SND_SOC_DAIFMT_LEFT_J: | 73 | case SND_SOC_DAIFMT_LEFT_J: |
109 | ret = -EINVAL; | 74 | ret = -EINVAL; |
@@ -135,33 +100,35 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
135 | struct snd_pcm_hw_params *params, | 100 | struct snd_pcm_hw_params *params, |
136 | struct snd_soc_dai *dai) | 101 | struct snd_soc_dai *dai) |
137 | { | 102 | { |
103 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
104 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
138 | int ret = 0; | 105 | int ret = 0; |
139 | 106 | ||
140 | bf5xx_i2s.tcr2 &= ~0x1f; | 107 | bf5xx_i2s->tcr2 &= ~0x1f; |
141 | bf5xx_i2s.rcr2 &= ~0x1f; | 108 | bf5xx_i2s->rcr2 &= ~0x1f; |
142 | switch (params_format(params)) { | 109 | switch (params_format(params)) { |
143 | case SNDRV_PCM_FORMAT_S8: | 110 | case SNDRV_PCM_FORMAT_S8: |
144 | bf5xx_i2s->tcr2 |= 7; | 111 | bf5xx_i2s->tcr2 |= 7; |
145 | bf5xx_i2s->rcr2 |= 7; | 112 | bf5xx_i2s->rcr2 |= 7; |
146 | sport_handle->wdsize = 1; | 113 | sport_handle->wdsize = 1; |
147 | case SNDRV_PCM_FORMAT_S16_LE: | 114 | case SNDRV_PCM_FORMAT_S16_LE: |
148 | bf5xx_i2s.tcr2 |= 15; | 115 | bf5xx_i2s->tcr2 |= 15; |
149 | bf5xx_i2s.rcr2 |= 15; | 116 | bf5xx_i2s->rcr2 |= 15; |
150 | sport_handle->wdsize = 2; | 117 | sport_handle->wdsize = 2; |
151 | break; | 118 | break; |
152 | case SNDRV_PCM_FORMAT_S24_LE: | 119 | case SNDRV_PCM_FORMAT_S24_LE: |
153 | bf5xx_i2s.tcr2 |= 23; | 120 | bf5xx_i2s->tcr2 |= 23; |
154 | bf5xx_i2s.rcr2 |= 23; | 121 | bf5xx_i2s->rcr2 |= 23; |
155 | sport_handle->wdsize = 3; | 122 | sport_handle->wdsize = 3; |
156 | break; | 123 | break; |
157 | case SNDRV_PCM_FORMAT_S32_LE: | 124 | case SNDRV_PCM_FORMAT_S32_LE: |
158 | bf5xx_i2s.tcr2 |= 31; | 125 | bf5xx_i2s->tcr2 |= 31; |
159 | bf5xx_i2s.rcr2 |= 31; | 126 | bf5xx_i2s->rcr2 |= 31; |
160 | sport_handle->wdsize = 4; | 127 | sport_handle->wdsize = 4; |
161 | break; | 128 | break; |
162 | } | 129 | } |
163 | 130 | ||
164 | if (!bf5xx_i2s.configured) { | 131 | if (!bf5xx_i2s->configured) { |
165 | /* | 132 | /* |
166 | * TX and RX are not independent,they are enabled at the | 133 | * TX and RX are not independent,they are enabled at the |
167 | * same time, even if only one side is running. So, we | 134 | * same time, even if only one side is running. So, we |
@@ -170,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
170 | * | 137 | * |
171 | * CPU DAI:slave mode. | 138 | * CPU DAI:slave mode. |
172 | */ | 139 | */ |
173 | bf5xx_i2s.configured = 1; | 140 | bf5xx_i2s->configured = 1; |
174 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, | 141 | ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, |
175 | bf5xx_i2s.rcr2, 0, 0); | 142 | bf5xx_i2s->rcr2, 0, 0); |
176 | if (ret) { | 143 | if (ret) { |
177 | pr_err("SPORT is busy!\n"); | 144 | pr_err("SPORT is busy!\n"); |
178 | return -EBUSY; | 145 | return -EBUSY; |
179 | } | 146 | } |
180 | 147 | ||
181 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, | 148 | ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, |
182 | bf5xx_i2s.tcr2, 0, 0); | 149 | bf5xx_i2s->tcr2, 0, 0); |
183 | if (ret) { | 150 | if (ret) { |
184 | pr_err("SPORT is busy!\n"); | 151 | pr_err("SPORT is busy!\n"); |
185 | return -EBUSY; | 152 | return -EBUSY; |
@@ -192,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
192 | static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, | 159 | static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, |
193 | struct snd_soc_dai *dai) | 160 | struct snd_soc_dai *dai) |
194 | { | 161 | { |
162 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
163 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
164 | |||
195 | pr_debug("%s enter\n", __func__); | 165 | pr_debug("%s enter\n", __func__); |
196 | /* No active stream, SPORT is allowed to be configured again. */ | 166 | /* No active stream, SPORT is allowed to be configured again. */ |
197 | if (!dai->active) | 167 | if (!dai->active) |
198 | bf5xx_i2s.configured = 0; | 168 | bf5xx_i2s->configured = 0; |
199 | } | ||
200 | |||
201 | static int bf5xx_i2s_probe(struct snd_soc_dai *dai) | ||
202 | { | ||
203 | pr_debug("%s enter\n", __func__); | ||
204 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | ||
205 | pr_err("Requesting Peripherals failed\n"); | ||
206 | return -EFAULT; | ||
207 | } | ||
208 | |||
209 | /* request DMA for SPORT */ | ||
210 | sport_handle = sport_init(&sport_params[sport_num], 4, \ | ||
211 | 2 * sizeof(u32), NULL); | ||
212 | if (!sport_handle) { | ||
213 | peripheral_free_list(&sport_req[sport_num][0]); | ||
214 | return -ENODEV; | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int bf5xx_i2s_remove(struct snd_soc_dai *dai) | ||
221 | { | ||
222 | pr_debug("%s enter\n", __func__); | ||
223 | peripheral_free_list(&sport_req[sport_num][0]); | ||
224 | return 0; | ||
225 | } | 169 | } |
226 | 170 | ||
227 | #ifdef CONFIG_PM | 171 | #ifdef CONFIG_PM |
228 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | 172 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) |
229 | { | 173 | { |
174 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
230 | 175 | ||
231 | pr_debug("%s : sport %d\n", __func__, dai->id); | 176 | pr_debug("%s : sport %d\n", __func__, dai->id); |
232 | 177 | ||
@@ -239,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | |||
239 | 184 | ||
240 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | 185 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) |
241 | { | 186 | { |
187 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
188 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
242 | int ret; | 189 | int ret; |
243 | 190 | ||
244 | pr_debug("%s : sport %d\n", __func__, dai->id); | 191 | pr_debug("%s : sport %d\n", __func__, dai->id); |
245 | 192 | ||
246 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, | 193 | ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, |
247 | bf5xx_i2s.rcr2, 0, 0); | 194 | bf5xx_i2s->rcr2, 0, 0); |
248 | if (ret) { | 195 | if (ret) { |
249 | pr_err("SPORT is busy!\n"); | 196 | pr_err("SPORT is busy!\n"); |
250 | return -EBUSY; | 197 | return -EBUSY; |
251 | } | 198 | } |
252 | 199 | ||
253 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, | 200 | ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, |
254 | bf5xx_i2s.tcr2, 0, 0); | 201 | bf5xx_i2s->tcr2, 0, 0); |
255 | if (ret) { | 202 | if (ret) { |
256 | pr_err("SPORT is busy!\n"); | 203 | pr_err("SPORT is busy!\n"); |
257 | return -EBUSY; | 204 | return -EBUSY; |
@@ -283,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | |||
283 | }; | 230 | }; |
284 | 231 | ||
285 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { | 232 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { |
286 | .probe = bf5xx_i2s_probe, | ||
287 | .remove = bf5xx_i2s_remove, | ||
288 | .suspend = bf5xx_i2s_suspend, | 233 | .suspend = bf5xx_i2s_suspend, |
289 | .resume = bf5xx_i2s_resume, | 234 | .resume = bf5xx_i2s_resume, |
290 | .playback = { | 235 | .playback = { |
@@ -300,21 +245,43 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { | |||
300 | .ops = &bf5xx_i2s_dai_ops, | 245 | .ops = &bf5xx_i2s_dai_ops, |
301 | }; | 246 | }; |
302 | 247 | ||
303 | static int bfin_i2s_drv_probe(struct platform_device *pdev) | 248 | static int __devinit bf5xx_i2s_probe(struct platform_device *pdev) |
304 | { | 249 | { |
305 | return snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); | 250 | struct sport_device *sport_handle; |
251 | int ret; | ||
252 | |||
253 | /* configure SPORT for I2S */ | ||
254 | sport_handle = sport_init(pdev, 4, 2 * sizeof(u32), | ||
255 | sizeof(struct bf5xx_i2s_port)); | ||
256 | if (!sport_handle) | ||
257 | return -ENODEV; | ||
258 | |||
259 | /* register with the ASoC layers */ | ||
260 | ret = snd_soc_register_dai(&pdev->dev, &bf5xx_i2s_dai); | ||
261 | if (ret) { | ||
262 | pr_err("Failed to register DAI: %d\n", ret); | ||
263 | sport_done(sport_handle); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | return 0; | ||
306 | } | 268 | } |
307 | 269 | ||
308 | static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev) | 270 | static int __devexit bf5xx_i2s_remove(struct platform_device *pdev) |
309 | { | 271 | { |
272 | struct sport_device *sport_handle = platform_get_drvdata(pdev); | ||
273 | |||
274 | pr_debug("%s enter\n", __func__); | ||
275 | |||
310 | snd_soc_unregister_dai(&pdev->dev); | 276 | snd_soc_unregister_dai(&pdev->dev); |
277 | sport_done(sport_handle); | ||
278 | |||
311 | return 0; | 279 | return 0; |
312 | } | 280 | } |
313 | 281 | ||
314 | static struct platform_driver bfin_i2s_driver = { | 282 | static struct platform_driver bfin_i2s_driver = { |
315 | .probe = bfin_i2s_drv_probe, | 283 | .probe = bf5xx_i2s_probe, |
316 | .remove = __devexit_p(bfin_i2s_drv_remove), | 284 | .remove = __devexit_p(bf5xx_i2s_remove), |
317 | |||
318 | .driver = { | 285 | .driver = { |
319 | .name = "bfin-i2s", | 286 | .name = "bfin-i2s", |
320 | .owner = THIS_MODULE, | 287 | .owner = THIS_MODULE, |