aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/blackfin/bf5xx-tdm.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/blackfin/bf5xx-tdm.c')
-rw-r--r--sound/soc/blackfin/bf5xx-tdm.c110
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
49static struct bf5xx_tdm_port bf5xx_tdm;
50static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM;
51
52static 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
81static 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
86static int bf5xx_tdm_set_dai_fmt(struct snd_soc_dai *cpu_dai, 49static 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,
168static void bf5xx_tdm_shutdown(struct snd_pcm_substream *substream, 133static 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
176static int bf5xx_tdm_set_channel_map(struct snd_soc_dai *dai, 144static 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
281static int __devinit bfin_tdm_probe(struct platform_device *pdev) 252static 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
329sport_config_err: 293sport_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
334static int __devexit bfin_tdm_remove(struct platform_device *pdev) 298static 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}