diff options
Diffstat (limited to 'sound/soc/blackfin/bf5xx-i2s.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-i2s.c | 172 |
1 files changed, 73 insertions, 99 deletions
diff --git a/sound/soc/blackfin/bf5xx-i2s.c b/sound/soc/blackfin/bf5xx-i2s.c index d453b1e9d607..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,29 +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)) { |
110 | case SNDRV_PCM_FORMAT_S8: | ||
111 | bf5xx_i2s->tcr2 |= 7; | ||
112 | bf5xx_i2s->rcr2 |= 7; | ||
113 | sport_handle->wdsize = 1; | ||
143 | case SNDRV_PCM_FORMAT_S16_LE: | 114 | case SNDRV_PCM_FORMAT_S16_LE: |
144 | bf5xx_i2s.tcr2 |= 15; | 115 | bf5xx_i2s->tcr2 |= 15; |
145 | bf5xx_i2s.rcr2 |= 15; | 116 | bf5xx_i2s->rcr2 |= 15; |
146 | sport_handle->wdsize = 2; | 117 | sport_handle->wdsize = 2; |
147 | break; | 118 | break; |
148 | case SNDRV_PCM_FORMAT_S24_LE: | 119 | case SNDRV_PCM_FORMAT_S24_LE: |
149 | bf5xx_i2s.tcr2 |= 23; | 120 | bf5xx_i2s->tcr2 |= 23; |
150 | bf5xx_i2s.rcr2 |= 23; | 121 | bf5xx_i2s->rcr2 |= 23; |
151 | sport_handle->wdsize = 3; | 122 | sport_handle->wdsize = 3; |
152 | break; | 123 | break; |
153 | case SNDRV_PCM_FORMAT_S32_LE: | 124 | case SNDRV_PCM_FORMAT_S32_LE: |
154 | bf5xx_i2s.tcr2 |= 31; | 125 | bf5xx_i2s->tcr2 |= 31; |
155 | bf5xx_i2s.rcr2 |= 31; | 126 | bf5xx_i2s->rcr2 |= 31; |
156 | sport_handle->wdsize = 4; | 127 | sport_handle->wdsize = 4; |
157 | break; | 128 | break; |
158 | } | 129 | } |
159 | 130 | ||
160 | if (!bf5xx_i2s.configured) { | 131 | if (!bf5xx_i2s->configured) { |
161 | /* | 132 | /* |
162 | * TX and RX are not independent,they are enabled at the | 133 | * TX and RX are not independent,they are enabled at the |
163 | * same time, even if only one side is running. So, we | 134 | * same time, even if only one side is running. So, we |
@@ -166,16 +137,16 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
166 | * | 137 | * |
167 | * CPU DAI:slave mode. | 138 | * CPU DAI:slave mode. |
168 | */ | 139 | */ |
169 | bf5xx_i2s.configured = 1; | 140 | bf5xx_i2s->configured = 1; |
170 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, | 141 | ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, |
171 | bf5xx_i2s.rcr2, 0, 0); | 142 | bf5xx_i2s->rcr2, 0, 0); |
172 | if (ret) { | 143 | if (ret) { |
173 | pr_err("SPORT is busy!\n"); | 144 | pr_err("SPORT is busy!\n"); |
174 | return -EBUSY; | 145 | return -EBUSY; |
175 | } | 146 | } |
176 | 147 | ||
177 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, | 148 | ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, |
178 | bf5xx_i2s.tcr2, 0, 0); | 149 | bf5xx_i2s->tcr2, 0, 0); |
179 | if (ret) { | 150 | if (ret) { |
180 | pr_err("SPORT is busy!\n"); | 151 | pr_err("SPORT is busy!\n"); |
181 | return -EBUSY; | 152 | return -EBUSY; |
@@ -188,41 +159,19 @@ static int bf5xx_i2s_hw_params(struct snd_pcm_substream *substream, | |||
188 | static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, | 159 | static void bf5xx_i2s_shutdown(struct snd_pcm_substream *substream, |
189 | struct snd_soc_dai *dai) | 160 | struct snd_soc_dai *dai) |
190 | { | 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 | |||
191 | pr_debug("%s enter\n", __func__); | 165 | pr_debug("%s enter\n", __func__); |
192 | /* No active stream, SPORT is allowed to be configured again. */ | 166 | /* No active stream, SPORT is allowed to be configured again. */ |
193 | if (!dai->active) | 167 | if (!dai->active) |
194 | bf5xx_i2s.configured = 0; | 168 | bf5xx_i2s->configured = 0; |
195 | } | ||
196 | |||
197 | static int bf5xx_i2s_probe(struct snd_soc_dai *dai) | ||
198 | { | ||
199 | pr_debug("%s enter\n", __func__); | ||
200 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | ||
201 | pr_err("Requesting Peripherals failed\n"); | ||
202 | return -EFAULT; | ||
203 | } | ||
204 | |||
205 | /* request DMA for SPORT */ | ||
206 | sport_handle = sport_init(&sport_params[sport_num], 4, \ | ||
207 | 2 * sizeof(u32), NULL); | ||
208 | if (!sport_handle) { | ||
209 | peripheral_free_list(&sport_req[sport_num][0]); | ||
210 | return -ENODEV; | ||
211 | } | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int bf5xx_i2s_remove(struct snd_soc_dai *dai) | ||
217 | { | ||
218 | pr_debug("%s enter\n", __func__); | ||
219 | peripheral_free_list(&sport_req[sport_num][0]); | ||
220 | return 0; | ||
221 | } | 169 | } |
222 | 170 | ||
223 | #ifdef CONFIG_PM | 171 | #ifdef CONFIG_PM |
224 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | 172 | static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) |
225 | { | 173 | { |
174 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
226 | 175 | ||
227 | pr_debug("%s : sport %d\n", __func__, dai->id); | 176 | pr_debug("%s : sport %d\n", __func__, dai->id); |
228 | 177 | ||
@@ -235,19 +184,21 @@ static int bf5xx_i2s_suspend(struct snd_soc_dai *dai) | |||
235 | 184 | ||
236 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | 185 | static int bf5xx_i2s_resume(struct snd_soc_dai *dai) |
237 | { | 186 | { |
187 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
188 | struct bf5xx_i2s_port *bf5xx_i2s = sport_handle->private_data; | ||
238 | int ret; | 189 | int ret; |
239 | 190 | ||
240 | pr_debug("%s : sport %d\n", __func__, dai->id); | 191 | pr_debug("%s : sport %d\n", __func__, dai->id); |
241 | 192 | ||
242 | ret = sport_config_rx(sport_handle, bf5xx_i2s.rcr1, | 193 | ret = sport_config_rx(sport_handle, bf5xx_i2s->rcr1, |
243 | bf5xx_i2s.rcr2, 0, 0); | 194 | bf5xx_i2s->rcr2, 0, 0); |
244 | if (ret) { | 195 | if (ret) { |
245 | pr_err("SPORT is busy!\n"); | 196 | pr_err("SPORT is busy!\n"); |
246 | return -EBUSY; | 197 | return -EBUSY; |
247 | } | 198 | } |
248 | 199 | ||
249 | ret = sport_config_tx(sport_handle, bf5xx_i2s.tcr1, | 200 | ret = sport_config_tx(sport_handle, bf5xx_i2s->tcr1, |
250 | bf5xx_i2s.tcr2, 0, 0); | 201 | bf5xx_i2s->tcr2, 0, 0); |
251 | if (ret) { | 202 | if (ret) { |
252 | pr_err("SPORT is busy!\n"); | 203 | pr_err("SPORT is busy!\n"); |
253 | return -EBUSY; | 204 | return -EBUSY; |
@@ -266,8 +217,11 @@ static int bf5xx_i2s_resume(struct snd_soc_dai *dai) | |||
266 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ | 217 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \ |
267 | SNDRV_PCM_RATE_96000) | 218 | SNDRV_PCM_RATE_96000) |
268 | 219 | ||
269 | #define BF5XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE |\ | 220 | #define BF5XX_I2S_FORMATS \ |
270 | SNDRV_PCM_FMTBIT_S32_LE) | 221 | (SNDRV_PCM_FMTBIT_S8 | \ |
222 | SNDRV_PCM_FMTBIT_S16_LE | \ | ||
223 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
224 | SNDRV_PCM_FMTBIT_S32_LE) | ||
271 | 225 | ||
272 | static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | 226 | static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { |
273 | .shutdown = bf5xx_i2s_shutdown, | 227 | .shutdown = bf5xx_i2s_shutdown, |
@@ -276,8 +230,6 @@ static struct snd_soc_dai_ops bf5xx_i2s_dai_ops = { | |||
276 | }; | 230 | }; |
277 | 231 | ||
278 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { | 232 | static struct snd_soc_dai_driver bf5xx_i2s_dai = { |
279 | .probe = bf5xx_i2s_probe, | ||
280 | .remove = bf5xx_i2s_remove, | ||
281 | .suspend = bf5xx_i2s_suspend, | 233 | .suspend = bf5xx_i2s_suspend, |
282 | .resume = bf5xx_i2s_resume, | 234 | .resume = bf5xx_i2s_resume, |
283 | .playback = { | 235 | .playback = { |
@@ -293,23 +245,45 @@ static struct snd_soc_dai_driver bf5xx_i2s_dai = { | |||
293 | .ops = &bf5xx_i2s_dai_ops, | 245 | .ops = &bf5xx_i2s_dai_ops, |
294 | }; | 246 | }; |
295 | 247 | ||
296 | static int bfin_i2s_drv_probe(struct platform_device *pdev) | 248 | static int __devinit bf5xx_i2s_probe(struct platform_device *pdev) |
297 | { | 249 | { |
298 | 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; | ||
299 | } | 268 | } |
300 | 269 | ||
301 | static int __devexit bfin_i2s_drv_remove(struct platform_device *pdev) | 270 | static int __devexit bf5xx_i2s_remove(struct platform_device *pdev) |
302 | { | 271 | { |
272 | struct sport_device *sport_handle = platform_get_drvdata(pdev); | ||
273 | |||
274 | pr_debug("%s enter\n", __func__); | ||
275 | |||
303 | snd_soc_unregister_dai(&pdev->dev); | 276 | snd_soc_unregister_dai(&pdev->dev); |
277 | sport_done(sport_handle); | ||
278 | |||
304 | return 0; | 279 | return 0; |
305 | } | 280 | } |
306 | 281 | ||
307 | static struct platform_driver bfin_i2s_driver = { | 282 | static struct platform_driver bfin_i2s_driver = { |
308 | .probe = bfin_i2s_drv_probe, | 283 | .probe = bf5xx_i2s_probe, |
309 | .remove = __devexit_p(bfin_i2s_drv_remove), | 284 | .remove = __devexit_p(bf5xx_i2s_remove), |
310 | |||
311 | .driver = { | 285 | .driver = { |
312 | .name = "bf5xx-i2s", | 286 | .name = "bfin-i2s", |
313 | .owner = THIS_MODULE, | 287 | .owner = THIS_MODULE, |
314 | }, | 288 | }, |
315 | }; | 289 | }; |