diff options
Diffstat (limited to 'sound/soc/blackfin/bf5xx-tdm.c')
-rw-r--r-- | sound/soc/blackfin/bf5xx-tdm.c | 110 |
1 files changed, 38 insertions, 72 deletions
diff --git a/sound/soc/blackfin/bf5xx-tdm.c b/sound/soc/blackfin/bf5xx-tdm.c index 5515ac9e05c7..a822d1ee1380 100644 --- a/sound/soc/blackfin/bf5xx-tdm.c +++ b/sound/soc/blackfin/bf5xx-tdm.c | |||
@@ -46,43 +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 | static struct bf5xx_tdm_port bf5xx_tdm; | ||
50 | static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; | ||
51 | |||
52 | static struct sport_param sport_params[2] = { | ||
53 | { | ||
54 | .dma_rx_chan = CH_SPORT0_RX, | ||
55 | .dma_tx_chan = CH_SPORT0_TX, | ||
56 | .err_irq = IRQ_SPORT0_ERROR, | ||
57 | .regs = (struct sport_register *)SPORT0_TCR1, | ||
58 | }, | ||
59 | { | ||
60 | .dma_rx_chan = CH_SPORT1_RX, | ||
61 | .dma_tx_chan = CH_SPORT1_TX, | ||
62 | .err_irq = IRQ_SPORT1_ERROR, | ||
63 | .regs = (struct sport_register *)SPORT1_TCR1, | ||
64 | } | ||
65 | }; | ||
66 | |||
67 | /* | ||
68 | * Setting the TFS pin selector for SPORT 0 based on whether the selected | ||
69 | * port id F or G. If the port is F then no conflict should exist for the | ||
70 | * TFS. When Port G is selected and EMAC then there is a conflict between | ||
71 | * the PHY interrupt line and TFS. Current settings prevent the conflict | ||
72 | * by ignoring the TFS pin when Port G is selected. This allows both | ||
73 | * codecs and EMAC using Port G concurrently. | ||
74 | */ | ||
75 | #ifdef CONFIG_BF527_SPORT0_PORTG | ||
76 | #define LOCAL_SPORT0_TFS (0) | ||
77 | #else | ||
78 | #define LOCAL_SPORT0_TFS (P_SPORT0_TFS) | ||
79 | #endif | ||
80 | |||
81 | static u16 sport_req[][7] = { {P_SPORT0_DTPRI, P_SPORT0_TSCLK, P_SPORT0_RFS, | ||
82 | P_SPORT0_DRPRI, P_SPORT0_RSCLK, LOCAL_SPORT0_TFS, 0}, | ||
83 | {P_SPORT1_DTPRI, P_SPORT1_TSCLK, P_SPORT1_RFS, P_SPORT1_DRPRI, | ||
84 | P_SPORT1_RSCLK, P_SPORT1_TFS, 0} }; | ||
85 | |||
86 | static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 49 | static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
87 | unsigned int fmt) | 50 | unsigned int fmt) |
88 | { | 51 | { |
@@ -119,14 +82,16 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, | |||
119 | struct snd_pcm_hw_params *params, | 82 | struct snd_pcm_hw_params *params, |
120 | struct snd_soc_dai *dai) | 83 | struct snd_soc_dai *dai) |
121 | { | 84 | { |
85 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
86 | struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; | ||
122 | int ret = 0; | 87 | int ret = 0; |
123 | 88 | ||
124 | bf5xx_tdm.tcr2 &= ~0x1f; | 89 | bf5xx_tdm->tcr2 &= ~0x1f; |
125 | bf5xx_tdm.rcr2 &= ~0x1f; | 90 | bf5xx_tdm->rcr2 &= ~0x1f; |
126 | switch (params_format(params)) { | 91 | switch (params_format(params)) { |
127 | case SNDRV_PCM_FORMAT_S32_LE: | 92 | case SNDRV_PCM_FORMAT_S32_LE: |
128 | bf5xx_tdm.tcr2 |= 31; | 93 | bf5xx_tdm->tcr2 |= 31; |
129 | bf5xx_tdm.rcr2 |= 31; | 94 | bf5xx_tdm->rcr2 |= 31; |
130 | sport_handle->wdsize = 4; | 95 | sport_handle->wdsize = 4; |
131 | break; | 96 | break; |
132 | /* at present, we only support 32bit transfer */ | 97 | /* at present, we only support 32bit transfer */ |
@@ -136,7 +101,7 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, | |||
136 | break; | 101 | break; |
137 | } | 102 | } |
138 | 103 | ||
139 | if (!bf5xx_tdm.configured) { | 104 | if (!bf5xx_tdm->configured) { |
140 | /* | 105 | /* |
141 | * TX and RX are not independent,they are enabled at the | 106 | * TX and RX are not independent,they are enabled at the |
142 | * same time, even if only one side is running. So, we | 107 | * same time, even if only one side is running. So, we |
@@ -145,21 +110,21 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, | |||
145 | * | 110 | * |
146 | * CPU DAI:slave mode. | 111 | * CPU DAI:slave mode. |
147 | */ | 112 | */ |
148 | ret = sport_config_rx(sport_handle, bf5xx_tdm.rcr1, | 113 | ret = sport_config_rx(sport_handle, bf5xx_tdm->rcr1, |
149 | bf5xx_tdm.rcr2, 0, 0); | 114 | bf5xx_tdm->rcr2, 0, 0); |
150 | if (ret) { | 115 | if (ret) { |
151 | pr_err("SPORT is busy!\n"); | 116 | pr_err("SPORT is busy!\n"); |
152 | return -EBUSY; | 117 | return -EBUSY; |
153 | } | 118 | } |
154 | 119 | ||
155 | ret = sport_config_tx(sport_handle, bf5xx_tdm.tcr1, | 120 | ret = sport_config_tx(sport_handle, bf5xx_tdm->tcr1, |
156 | bf5xx_tdm.tcr2, 0, 0); | 121 | bf5xx_tdm->tcr2, 0, 0); |
157 | if (ret) { | 122 | if (ret) { |
158 | pr_err("SPORT is busy!\n"); | 123 | pr_err("SPORT is busy!\n"); |
159 | return -EBUSY; | 124 | return -EBUSY; |
160 | } | 125 | } |
161 | 126 | ||
162 | bf5xx_tdm.configured = 1; | 127 | bf5xx_tdm->configured = 1; |
163 | } | 128 | } |
164 | 129 | ||
165 | return 0; | 130 | return 0; |
@@ -168,15 +133,20 @@ static int bf5xx_tdm_hw_params(struct snd_pcm_substream *substream, | |||
168 | static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, | 133 | static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, |
169 | struct snd_soc_dai *dai) | 134 | struct snd_soc_dai *dai) |
170 | { | 135 | { |
136 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
137 | struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; | ||
138 | |||
171 | /* No active stream, SPORT is allowed to be configured again. */ | 139 | /* No active stream, SPORT is allowed to be configured again. */ |
172 | if (!dai->active) | 140 | if (!dai->active) |
173 | bf5xx_tdm.configured = 0; | 141 | bf5xx_tdm->configured = 0; |
174 | } | 142 | } |
175 | 143 | ||
176 | static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | 144 | static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, |
177 | unsigned int tx_num, unsigned int *tx_slot, | 145 | unsigned int tx_num, unsigned int *tx_slot, |
178 | unsigned int rx_num, unsigned int *rx_slot) | 146 | unsigned int rx_num, unsigned int *rx_slot) |
179 | { | 147 | { |
148 | struct sport_device *sport_handle = snd_soc_dai_get_drvdata(dai); | ||
149 | struct bf5xx_tdm_port *bf5xx_tdm = sport_handle->private_data; | ||
180 | int i; | 150 | int i; |
181 | unsigned int slot; | 151 | unsigned int slot; |
182 | unsigned int tx_mapped = 0, rx_mapped = 0; | 152 | unsigned int tx_mapped = 0, rx_mapped = 0; |
@@ -189,7 +159,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | |||
189 | slot = tx_slot[i]; | 159 | slot = tx_slot[i]; |
190 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | 160 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && |
191 | (!(tx_mapped & (1 << slot)))) { | 161 | (!(tx_mapped & (1 << slot)))) { |
192 | bf5xx_tdm.tx_map[i] = slot; | 162 | bf5xx_tdm->tx_map[i] = slot; |
193 | tx_mapped |= 1 << slot; | 163 | tx_mapped |= 1 << slot; |
194 | } else | 164 | } else |
195 | return -EINVAL; | 165 | return -EINVAL; |
@@ -198,7 +168,7 @@ static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, | |||
198 | slot = rx_slot[i]; | 168 | slot = rx_slot[i]; |
199 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && | 169 | if ((slot < BFIN_TDM_DAI_MAX_SLOTS) && |
200 | (!(rx_mapped & (1 << slot)))) { | 170 | (!(rx_mapped & (1 << slot)))) { |
201 | bf5xx_tdm.rx_map[i] = slot; | 171 | bf5xx_tdm->rx_map[i] = slot; |
202 | rx_mapped |= 1 << slot; | 172 | rx_mapped |= 1 << slot; |
203 | } else | 173 | } else |
204 | return -EINVAL; | 174 | return -EINVAL; |
@@ -212,12 +182,14 @@ static int bf5xx_tdm_suspend(struct snd_soc_dai *dai) | |||
212 | { | 182 | { |
213 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | 183 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); |
214 | 184 | ||
215 | if (!dai->active) | ||
216 | return 0; | ||
217 | if (dai->capture_active) | ||
218 | sport_rx_stop(sport); | ||
219 | if (dai->playback_active) | 185 | if (dai->playback_active) |
220 | sport_tx_stop(sport); | 186 | sport_tx_stop(sport); |
187 | if (dai->capture_active) | ||
188 | sport_rx_stop(sport); | ||
189 | |||
190 | /* isolate sync/clock pins from codec while sports resume */ | ||
191 | peripheral_free_list(sport->pin_req); | ||
192 | |||
221 | return 0; | 193 | return 0; |
222 | } | 194 | } |
223 | 195 | ||
@@ -226,9 +198,6 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai) | |||
226 | int ret; | 198 | int ret; |
227 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | 199 | struct sport_device *sport = snd_soc_dai_get_drvdata(dai); |
228 | 200 | ||
229 | if (!dai->active) | ||
230 | return 0; | ||
231 | |||
232 | ret = sport_set_multichannel(sport, 8, 0xFF, 1); | 201 | ret = sport_set_multichannel(sport, 8, 0xFF, 1); |
233 | if (ret) { | 202 | if (ret) { |
234 | pr_err("SPORT is busy!\n"); | 203 | pr_err("SPORT is busy!\n"); |
@@ -247,6 +216,8 @@ static int bf5xx_tdm_resume(struct snd_soc_dai *dai) | |||
247 | ret = -EBUSY; | 216 | ret = -EBUSY; |
248 | } | 217 | } |
249 | 218 | ||
219 | peripheral_request_list(sport->pin_req, "soc-audio"); | ||
220 | |||
250 | return 0; | 221 | return 0; |
251 | } | 222 | } |
252 | 223 | ||
@@ -280,20 +251,14 @@ static struct snd_soc_dai_driver bf5xx_tdm_dai = { | |||
280 | 251 | ||
281 | static int __devinit bfin_tdm_probe(struct platform_device *pdev) | 252 | static int __devinit bfin_tdm_probe(struct platform_device *pdev) |
282 | { | 253 | { |
283 | int ret = 0; | 254 | struct sport_device *sport_handle; |
284 | 255 | int ret; | |
285 | if (peripheral_request_list(&sport_req[sport_num][0], "soc-audio")) { | ||
286 | pr_err("Requesting Peripherals failed\n"); | ||
287 | return -EFAULT; | ||
288 | } | ||
289 | 256 | ||
290 | /* request DMA for SPORT */ | 257 | /* configure SPORT for TDM */ |
291 | sport_handle = sport_init(&sport_params[sport_num], 4, \ | 258 | sport_handle = sport_init(pdev, 4, 8 * sizeof(u32), |
292 | 8 * sizeof(u32), NULL); | 259 | sizeof(struct bf5xx_tdm_port)); |
293 | if (!sport_handle) { | 260 | if (!sport_handle) |
294 | peripheral_free_list(&sport_req[sport_num][0]); | ||
295 | return -ENODEV; | 261 | return -ENODEV; |
296 | } | ||
297 | 262 | ||
298 | /* SPORT works in TDM mode */ | 263 | /* SPORT works in TDM mode */ |
299 | ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1); | 264 | ret = sport_set_multichannel(sport_handle, 8, 0xFF, 1); |
@@ -323,18 +288,19 @@ static int __devinit bfin_tdm_probe(struct platform_device *pdev) | |||
323 | goto sport_config_err; | 288 | goto sport_config_err; |
324 | } | 289 | } |
325 | 290 | ||
326 | sport_handle->private_data = &bf5xx_tdm; | ||
327 | return 0; | 291 | return 0; |
328 | 292 | ||
329 | sport_config_err: | 293 | sport_config_err: |
330 | peripheral_free_list(&sport_req[sport_num][0]); | 294 | sport_done(sport_handle); |
331 | return ret; | 295 | return ret; |
332 | } | 296 | } |
333 | 297 | ||
334 | static int __devexit bfin_tdm_remove(struct platform_device *pdev) | 298 | static int __devexit bfin_tdm_remove(struct platform_device *pdev) |
335 | { | 299 | { |
336 | peripheral_free_list(&sport_req[sport_num][0]); | 300 | struct sport_device *sport_handle = platform_get_drvdata(pdev); |
301 | |||
337 | snd_soc_unregister_dai(&pdev->dev); | 302 | snd_soc_unregister_dai(&pdev->dev); |
303 | sport_done(sport_handle); | ||
338 | 304 | ||
339 | return 0; | 305 | return 0; |
340 | } | 306 | } |