diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt | 2 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.c | 124 | ||||
-rw-r--r-- | sound/soc/davinci/davinci-mcasp.h | 11 |
3 files changed, 136 insertions, 1 deletions
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt index 60ca07996458..46bc9829c71a 100644 --- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt +++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt | |||
@@ -32,7 +32,7 @@ Optional properties: | |||
32 | - rx-num-evt : FIFO levels. | 32 | - rx-num-evt : FIFO levels. |
33 | - sram-size-playback : size of sram to be allocated during playback | 33 | - sram-size-playback : size of sram to be allocated during playback |
34 | - sram-size-capture : size of sram to be allocated during capture | 34 | - sram-size-capture : size of sram to be allocated during capture |
35 | - interrupts : Interrupt numbers for McASP, currently not used by the driver | 35 | - interrupts : Interrupt numbers for McASP |
36 | - interrupt-names : Known interrupt names are "tx" and "rx" | 36 | - interrupt-names : Known interrupt names are "tx" and "rx" |
37 | - pinctrl-0: Should specify pin control group used for this controller. | 37 | - pinctrl-0: Should specify pin control group used for this controller. |
38 | - pinctrl-names: Should contain only one value - "default", for more details | 38 | - pinctrl-names: Should contain only one value - "default", for more details |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index a9822c7bbb0b..e460f97c514e 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -70,6 +70,7 @@ struct davinci_mcasp { | |||
70 | void __iomem *base; | 70 | void __iomem *base; |
71 | u32 fifo_base; | 71 | u32 fifo_base; |
72 | struct device *dev; | 72 | struct device *dev; |
73 | struct snd_pcm_substream *substreams[2]; | ||
73 | 74 | ||
74 | /* McASP specific data */ | 75 | /* McASP specific data */ |
75 | int tdm_slots; | 76 | int tdm_slots; |
@@ -80,6 +81,7 @@ struct davinci_mcasp { | |||
80 | u8 bclk_div; | 81 | u8 bclk_div; |
81 | u16 bclk_lrclk_ratio; | 82 | u16 bclk_lrclk_ratio; |
82 | int streams; | 83 | int streams; |
84 | u32 irq_request[2]; | ||
83 | 85 | ||
84 | int sysclk_freq; | 86 | int sysclk_freq; |
85 | bool bclk_master; | 87 | bool bclk_master; |
@@ -185,6 +187,10 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp) | |||
185 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); | 187 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST); |
186 | if (mcasp_is_synchronous(mcasp)) | 188 | if (mcasp_is_synchronous(mcasp)) |
187 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 189 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); |
190 | |||
191 | /* enable receive IRQs */ | ||
192 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
193 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
188 | } | 194 | } |
189 | 195 | ||
190 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) | 196 | static void mcasp_start_tx(struct davinci_mcasp *mcasp) |
@@ -214,6 +220,10 @@ static void mcasp_start_tx(struct davinci_mcasp *mcasp) | |||
214 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); | 220 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST); |
215 | /* Release Frame Sync generator */ | 221 | /* Release Frame Sync generator */ |
216 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); | 222 | mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST); |
223 | |||
224 | /* enable transmit IRQs */ | ||
225 | mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
226 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
217 | } | 227 | } |
218 | 228 | ||
219 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | 229 | static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) |
@@ -228,6 +238,10 @@ static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream) | |||
228 | 238 | ||
229 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) | 239 | static void mcasp_stop_rx(struct davinci_mcasp *mcasp) |
230 | { | 240 | { |
241 | /* disable IRQ sources */ | ||
242 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG, | ||
243 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]); | ||
244 | |||
231 | /* | 245 | /* |
232 | * In synchronous mode stop the TX clocks if no other stream is | 246 | * In synchronous mode stop the TX clocks if no other stream is |
233 | * running | 247 | * running |
@@ -249,6 +263,10 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp) | |||
249 | { | 263 | { |
250 | u32 val = 0; | 264 | u32 val = 0; |
251 | 265 | ||
266 | /* disable IRQ sources */ | ||
267 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG, | ||
268 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]); | ||
269 | |||
252 | /* | 270 | /* |
253 | * In synchronous mode keep TX clocks running if the capture stream is | 271 | * In synchronous mode keep TX clocks running if the capture stream is |
254 | * still running. | 272 | * still running. |
@@ -276,6 +294,76 @@ static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream) | |||
276 | mcasp_stop_rx(mcasp); | 294 | mcasp_stop_rx(mcasp); |
277 | } | 295 | } |
278 | 296 | ||
297 | static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data) | ||
298 | { | ||
299 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
300 | struct snd_pcm_substream *substream; | ||
301 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]; | ||
302 | u32 handled_mask = 0; | ||
303 | u32 stat; | ||
304 | |||
305 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG); | ||
306 | if (stat & XUNDRN & irq_mask) { | ||
307 | dev_warn(mcasp->dev, "Transmit buffer underflow\n"); | ||
308 | handled_mask |= XUNDRN; | ||
309 | |||
310 | substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK]; | ||
311 | if (substream) { | ||
312 | snd_pcm_stream_lock_irq(substream); | ||
313 | if (snd_pcm_running(substream)) | ||
314 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
315 | snd_pcm_stream_unlock_irq(substream); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | if (!handled_mask) | ||
320 | dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n", | ||
321 | stat); | ||
322 | |||
323 | if (stat & XRERR) | ||
324 | handled_mask |= XRERR; | ||
325 | |||
326 | /* Ack the handled event only */ | ||
327 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask); | ||
328 | |||
329 | return IRQ_RETVAL(handled_mask); | ||
330 | } | ||
331 | |||
332 | static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data) | ||
333 | { | ||
334 | struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data; | ||
335 | struct snd_pcm_substream *substream; | ||
336 | u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]; | ||
337 | u32 handled_mask = 0; | ||
338 | u32 stat; | ||
339 | |||
340 | stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG); | ||
341 | if (stat & ROVRN & irq_mask) { | ||
342 | dev_warn(mcasp->dev, "Receive buffer overflow\n"); | ||
343 | handled_mask |= ROVRN; | ||
344 | |||
345 | substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE]; | ||
346 | if (substream) { | ||
347 | snd_pcm_stream_lock_irq(substream); | ||
348 | if (snd_pcm_running(substream)) | ||
349 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
350 | snd_pcm_stream_unlock_irq(substream); | ||
351 | } | ||
352 | } | ||
353 | |||
354 | if (!handled_mask) | ||
355 | dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n", | ||
356 | stat); | ||
357 | |||
358 | if (stat & XRERR) | ||
359 | handled_mask |= XRERR; | ||
360 | |||
361 | /* Ack the handled event only */ | ||
362 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask); | ||
363 | |||
364 | return IRQ_RETVAL(handled_mask); | ||
365 | } | ||
366 | |||
279 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | 367 | static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, |
280 | unsigned int fmt) | 368 | unsigned int fmt) |
281 | { | 369 | { |
@@ -869,6 +957,8 @@ static int davinci_mcasp_startup(struct snd_pcm_substream *substream, | |||
869 | u32 max_channels = 0; | 957 | u32 max_channels = 0; |
870 | int i, dir; | 958 | int i, dir; |
871 | 959 | ||
960 | mcasp->substreams[substream->stream] = substream; | ||
961 | |||
872 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 962 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
873 | return 0; | 963 | return 0; |
874 | 964 | ||
@@ -907,6 +997,8 @@ static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream, | |||
907 | { | 997 | { |
908 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | 998 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); |
909 | 999 | ||
1000 | mcasp->substreams[substream->stream] = NULL; | ||
1001 | |||
910 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 1002 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
911 | return; | 1003 | return; |
912 | 1004 | ||
@@ -1256,6 +1348,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1256 | struct resource *mem, *ioarea, *res, *dat; | 1348 | struct resource *mem, *ioarea, *res, *dat; |
1257 | struct davinci_mcasp_pdata *pdata; | 1349 | struct davinci_mcasp_pdata *pdata; |
1258 | struct davinci_mcasp *mcasp; | 1350 | struct davinci_mcasp *mcasp; |
1351 | char *irq_name; | ||
1352 | int irq; | ||
1259 | int ret; | 1353 | int ret; |
1260 | 1354 | ||
1261 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { | 1355 | if (!pdev->dev.platform_data && !pdev->dev.of_node) { |
@@ -1336,6 +1430,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1336 | 1430 | ||
1337 | mcasp->dev = &pdev->dev; | 1431 | mcasp->dev = &pdev->dev; |
1338 | 1432 | ||
1433 | irq = platform_get_irq_byname(pdev, "rx"); | ||
1434 | if (irq >= 0) { | ||
1435 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n", | ||
1436 | dev_name(&pdev->dev)); | ||
1437 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1438 | davinci_mcasp_rx_irq_handler, | ||
1439 | IRQF_ONESHOT, irq_name, mcasp); | ||
1440 | if (ret) { | ||
1441 | dev_err(&pdev->dev, "RX IRQ request failed\n"); | ||
1442 | goto err; | ||
1443 | } | ||
1444 | |||
1445 | mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN; | ||
1446 | } | ||
1447 | |||
1448 | irq = platform_get_irq_byname(pdev, "tx"); | ||
1449 | if (irq >= 0) { | ||
1450 | irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n", | ||
1451 | dev_name(&pdev->dev)); | ||
1452 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
1453 | davinci_mcasp_tx_irq_handler, | ||
1454 | IRQF_ONESHOT, irq_name, mcasp); | ||
1455 | if (ret) { | ||
1456 | dev_err(&pdev->dev, "TX IRQ request failed\n"); | ||
1457 | goto err; | ||
1458 | } | ||
1459 | |||
1460 | mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN; | ||
1461 | } | ||
1462 | |||
1339 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); | 1463 | dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); |
1340 | if (dat) | 1464 | if (dat) |
1341 | mcasp->dat_port = true; | 1465 | mcasp->dat_port = true; |
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h index 9737108f0305..79dc511180bf 100644 --- a/sound/soc/davinci/davinci-mcasp.h +++ b/sound/soc/davinci/davinci-mcasp.h | |||
@@ -256,6 +256,7 @@ | |||
256 | * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits | 256 | * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits |
257 | * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits | 257 | * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits |
258 | */ | 258 | */ |
259 | #define XRERR BIT(8) /* Transmit/Receive error */ | ||
259 | #define XRDATA BIT(5) /* Transmit/Receive data ready */ | 260 | #define XRDATA BIT(5) /* Transmit/Receive data ready */ |
260 | 261 | ||
261 | /* | 262 | /* |
@@ -285,6 +286,16 @@ | |||
285 | #define TXDATADMADIS BIT(0) | 286 | #define TXDATADMADIS BIT(0) |
286 | 287 | ||
287 | /* | 288 | /* |
289 | * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits | ||
290 | */ | ||
291 | #define ROVRN BIT(0) | ||
292 | |||
293 | /* | ||
294 | * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits | ||
295 | */ | ||
296 | #define XUNDRN BIT(0) | ||
297 | |||
298 | /* | ||
288 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits | 299 | * DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits |
289 | */ | 300 | */ |
290 | #define FIFO_ENABLE BIT(16) | 301 | #define FIFO_ENABLE BIT(16) |