Fix caching buffer for tx and rx when slice len==2.
[bertos.git] / bertos / cpu / cortex-m3 / drv / i2s_sam3.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2011 Develer S.r.l. (http://www.develer.com/)
30  * -->
31  *
32  * \brief I2S driver implementation.
33  *
34  * \author Daniele Basile <asterix@develer.com>
35  */
36
37
38
39 #include "hw/hw_i2s.h"
40
41 #include "cfg/cfg_i2s.h"
42
43 // Define log settings for cfg/log.h.
44 #define LOG_LEVEL         I2S_LOG_LEVEL
45 #define LOG_FORMAT        I2S_LOG_FORMAT
46 #include <cfg/log.h>
47
48 #include <drv/timer.h>
49 #include <drv/i2s.h>
50 #include <drv/dmac_sam3.h>
51
52 #include <mware/event.h>
53
54 #include <cpu/irq.h>
55
56 #include <io/cm3.h>
57
58 #include <string.h>
59
60
61 #define I2S_DMAC_CH    0
62 #define I2S_CACHED_CHUNK_SIZE 2
63
64
65 #define I2S_TX_DMAC_CFG  (BV(DMAC_CFG_DST_H2SEL) | \
66                                                   BV(DMAC_CFG_SOD) | \
67                                                 ((3 << DMAC_CFG_DST_PER_SHIFT) & DMAC_CFG_DST_PER_MASK) | \
68                                                  (4 & DMAC_CFG_SRC_PER_MASK))
69
70 #define I2S_TX_DMAC_CTRLB  (DMAC_CTRLB_FC_MEM2PER_DMA_FC | \
71                                                         DMAC_CTRLB_DST_INCR_FIXED | \
72                                                         DMAC_CTRLB_SRC_INCR_INCREMENTING)
73
74
75 #define I2S_RX_DMAC_CFG  (BV(DMAC_CFG_SRC_H2SEL) | \
76                                                   BV(DMAC_CFG_SOD) | \
77                                                 ((3 << DMAC_CFG_DST_PER_SHIFT) & DMAC_CFG_DST_PER_MASK) | \
78                                                  (4 & DMAC_CFG_SRC_PER_MASK))
79
80 #define I2S_RX_DMAC_CTRLB  (DMAC_CTRLB_FC_PER2MEM_DMA_FC | \
81                                                     DMAC_CTRLB_DST_INCR_INCREMENTING | \
82                                                         DMAC_CTRLB_SRC_INCR_FIXED)
83
84
85 #if CONFIG_WORD_BIT_SIZE == 32
86         #define I2S_TX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_WORD | \
87                                                                 DMAC_CTRLA_DST_WIDTH_WORD)
88         #define I2S_RX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_WORD | \
89                                                                 DMAC_CTRLA_DST_WIDTH_WORD)
90         #define I2S_WORD_BYTE_SIZE      4
91 #elif CONFIG_WORD_BIT_SIZE == 16
92
93         #define I2S_TX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_HALF_WORD | \
94                                                                 DMAC_CTRLA_DST_WIDTH_HALF_WORD)
95         #define I2S_RX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_HALF_WORD | \
96                                                                 DMAC_CTRLA_DST_WIDTH_HALF_WORD)
97         #define I2S_WORD_BYTE_SIZE      2
98
99 #elif  CONFIG_WORD_BIT_SIZE == 8
100
101         #define I2S_TX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_BYTE | \
102                                                                 DMAC_CTRLA_DST_WIDTH_BYTE)
103         #define I2S_RX_DMAC_CTRLA  (DMAC_CTRLA_SRC_WIDTH_BYTE | \
104                                                                 DMAC_CTRLA_DST_WIDTH_BYTE)
105         #define I2S_WORD_BYTE_SIZE      1
106
107 #else
108         #error Wrong i2s word size.
109 #endif
110
111
112 #define I2S_STATUS_ERR              BV(0)
113 #define I2S_STATUS_SINGLE_TRASF     BV(1)
114 #define I2S_STATUS_TX               BV(2)
115 #define I2S_STATUS_END_TX           BV(3)
116 #define I2S_STATUS_RX               BV(4)
117 #define I2S_STATUS_END_RX           BV(5)
118
119
120 static Event data_ready;
121
122 DmacDesc lli0;
123 DmacDesc lli1;
124 DmacDesc *curr;
125 DmacDesc *next;
126 DmacDesc *prev;
127
128 static uint8_t i2s_status;
129 static uint8_t *sample_buff;
130 static size_t next_idx = 0;
131 static size_t chunk_size = 0;
132 static size_t transfer_size = 0;
133
134 static void sam3_i2s_txStop(I2s *i2s)
135 {
136         (void)i2s;
137         SSC_CR = BV(SSC_TXDIS);
138         dmac_stop(I2S_DMAC_CH);
139
140         next_idx = 0;
141         transfer_size = 0;
142
143         i2s_status |= I2S_STATUS_END_TX;
144         i2s_status &= ~I2S_STATUS_TX;
145         event_do(&data_ready);
146 }
147
148 static void sam3_i2s_txWait(I2s *i2s)
149 {
150         (void)i2s;
151         event_wait(&data_ready);
152 }
153
154 static void i2s_dmac_irq(uint32_t status)
155 {
156         if (i2s_status & I2S_STATUS_SINGLE_TRASF)
157         {
158                 i2s_status &= ~I2S_STATUS_SINGLE_TRASF;
159         }
160         else
161         {
162                 if (status & (BV(I2S_DMAC_CH) << DMAC_EBCIDR_ERR0))
163                 {
164                         i2s_status |= I2S_STATUS_ERR;
165                         // Disable to reset channel and clear fifo
166                         dmac_stop(I2S_DMAC_CH);
167                 }
168                 else
169                 {
170                         prev = curr;
171                         curr = next;
172                         next = prev;
173
174                         if (i2s_status & I2S_STATUS_TX)
175                         {
176                                 curr->src_addr = (uint32_t)&sample_buff[next_idx];
177                                 curr->dst_addr = (uint32_t)&SSC_THR;
178                                 curr->dsc_addr = (uint32_t)next;
179                                 curr->ctrla    = I2S_TX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
180                                 curr->ctrlb    = I2S_TX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
181                         }
182                         else
183                         {
184                                 curr->src_addr = (uint32_t)&SSC_RHR;
185                                 curr->dst_addr = (uint32_t)&sample_buff[next_idx];
186                                 curr->dsc_addr = (uint32_t)next;
187                                 curr->ctrla    = I2S_RX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
188                                 curr->ctrlb    = I2S_RX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
189                         }
190
191                 }
192         }
193         event_do(&data_ready);
194 }
195
196
197 static void sam3_i2s_txStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
198 {
199         ASSERT(buf);
200         ASSERT(len >= slice_len);
201         ASSERT(!(len % slice_len));
202
203         i2s_status &= ~(I2S_STATUS_END_TX | I2S_STATUS_SINGLE_TRASF);
204
205         sample_buff = (uint8_t *)buf;
206         next_idx = 0;
207         chunk_size = slice_len;
208         size_t remaing_size = len;
209         transfer_size = len;
210
211
212         memset(&lli0, 0, sizeof(DmacDesc));
213         memset(&lli1, 0, sizeof(DmacDesc));
214
215         prev = 0;
216         curr = &lli1;
217         next = &lli0;
218
219         for (int i = 0; i < I2S_CACHED_CHUNK_SIZE; i++)
220         {
221                 prev = curr;
222                 curr = next;
223                 next = prev;
224
225                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size);
226
227                 curr->src_addr = (uint32_t)&sample_buff[next_idx];
228                 curr->dst_addr = (uint32_t)&SSC_THR;
229                 curr->dsc_addr = (uint32_t)next;
230                 curr->ctrla    = I2S_TX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
231                 curr->ctrlb    = I2S_TX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
232
233                 remaing_size -= chunk_size;
234                 next_idx += chunk_size;
235
236                 if (remaing_size <= 0)
237                 {
238                         remaing_size = transfer_size;
239                         next_idx = 0;
240                 }
241         }
242
243         dmac_setLLITransfer(I2S_DMAC_CH, prev, I2S_TX_DMAC_CFG);
244
245         if (dmac_start(I2S_DMAC_CH) < 0)
246         {
247                 LOG_ERR("DMAC start[%x]\n", dmac_error(I2S_DMAC_CH));
248                 return;
249         }
250
251         i2s_status &= ~I2S_STATUS_ERR;
252         i2s_status |= I2S_STATUS_TX;
253
254         SSC_CR = BV(SSC_TXEN);
255
256         while (1)
257         {
258                 event_wait(&data_ready);
259                 I2S_STROBE_ON();
260                 remaing_size -= chunk_size;
261                 next_idx += chunk_size;
262
263                 if (remaing_size <= 0)
264                 {
265                         remaing_size = transfer_size;
266                         next_idx = 0;
267                 }
268
269                 if (i2s_status & I2S_STATUS_ERR)
270                 {
271                         LOG_ERR("Error while streaming.\n");
272                         break;
273                 }
274
275                 if (i2s_status & I2S_STATUS_END_TX)
276                 {
277                         LOG_INFO("Stop streaming.\n");
278                         break;
279                 }
280
281                 i2s->ctx.tx_callback(i2s, &sample_buff[next_idx], chunk_size);
282                 I2S_STROBE_OFF();
283         }
284 }
285
286 static void sam3_i2s_rxStop(I2s *i2s)
287 {
288         (void)i2s;
289         SSC_CR = BV(SSC_RXDIS) | BV(SSC_TXDIS);
290         dmac_stop(I2S_DMAC_CH);
291
292         i2s_status |= I2S_STATUS_END_RX;
293         next_idx = 0;
294         transfer_size = 0;
295
296         i2s_status &= ~I2S_STATUS_RX;
297
298         event_do(&data_ready);
299 }
300
301 static void sam3_i2s_rxWait(I2s *i2s)
302 {
303         (void)i2s;
304         event_wait(&data_ready);
305 }
306
307 static void sam3_i2s_rxStart(I2s *i2s, void *buf, size_t len, size_t slice_len)
308 {
309         ASSERT(buf);
310         ASSERT(len >= slice_len);
311         ASSERT(!(len % slice_len));
312
313         i2s_status &= ~(I2S_STATUS_END_RX | I2S_STATUS_SINGLE_TRASF);
314
315         sample_buff = (uint8_t *)buf;
316         next_idx = 0;
317         chunk_size = slice_len;
318         size_t remaing_size = len;
319         transfer_size = len;
320
321         memset(&lli0, 0, sizeof(DmacDesc));
322         memset(&lli1, 0, sizeof(DmacDesc));
323
324         prev = 0;
325         curr = &lli1;
326         next = &lli0;
327
328         for (int i = 0; i < I2S_CACHED_CHUNK_SIZE; i++)
329         {
330                 prev = curr;
331                 curr = next;
332                 next = prev;
333
334                 curr->src_addr = (uint32_t)&SSC_RHR;
335                 curr->dst_addr = (uint32_t)&sample_buff[next_idx];
336                 curr->dsc_addr = (uint32_t)next;
337                 curr->ctrla    = I2S_RX_DMAC_CTRLA | ((chunk_size / I2S_WORD_BYTE_SIZE) & 0xffff);
338                 curr->ctrlb    = I2S_RX_DMAC_CTRLB & ~BV(DMAC_CTRLB_IEN);
339
340                 remaing_size -= chunk_size;
341                 next_idx += chunk_size;
342
343                 if (remaing_size <= 0)
344                 {
345                         remaing_size = transfer_size;
346                         next_idx = 0;
347                 }
348         }
349
350         dmac_setLLITransfer(I2S_DMAC_CH, prev, I2S_RX_DMAC_CFG);
351
352         if (dmac_start(I2S_DMAC_CH) < 0)
353         {
354                 LOG_ERR("DMAC start[%x]\n", dmac_error(I2S_DMAC_CH));
355                 return;
356         }
357
358         i2s_status &= ~I2S_STATUS_ERR;
359         i2s_status |= I2S_STATUS_RX;
360
361         SSC_CR = BV(SSC_TXEN) | BV(SSC_RXEN);
362
363         while (1)
364         {
365                 event_wait(&data_ready);
366                 I2S_STROBE_ON();
367                 i2s->ctx.rx_callback(i2s, &sample_buff[next_idx], chunk_size);
368
369                 remaing_size -= chunk_size;
370                 next_idx += chunk_size;
371
372                 if (remaing_size <= 0)
373                 {
374                         remaing_size = transfer_size;
375                         next_idx = 0;
376                 }
377
378                 if (i2s_status & I2S_STATUS_ERR)
379                 {
380                         LOG_ERR("Error while streaming.\n");
381                         break;
382                 }
383
384                 if (i2s_status & I2S_STATUS_END_RX)
385                 {
386                         LOG_INFO("Stop streaming.\n");
387                         break;
388                 }
389                 I2S_STROBE_OFF();
390         }
391 }
392
393
394 static bool sam3_i2s_isTxFinish(struct I2s *i2s)
395 {
396         (void)i2s;
397         return (i2s_status & I2S_STATUS_END_TX);
398 }
399
400 static bool sam3_i2s_isRxFinish(struct I2s *i2s)
401 {
402         (void)i2s;
403         return (i2s_status & I2S_STATUS_END_RX);
404 }
405
406 static void sam3_i2s_txBuf(struct I2s *i2s, void *buf, size_t len)
407 {
408         (void)i2s;
409         i2s_status |= I2S_STATUS_SINGLE_TRASF;
410
411         dmac_setSources(I2S_DMAC_CH, (uint32_t)buf, (uint32_t)&SSC_THR);
412         dmac_configureDmac(I2S_DMAC_CH, len / I2S_WORD_BYTE_SIZE, I2S_TX_DMAC_CFG, I2S_TX_DMAC_CTRLA, I2S_TX_DMAC_CTRLB);
413         dmac_start(I2S_DMAC_CH);
414
415         SSC_CR = BV(SSC_TXEN);
416 }
417
418 static void sam3_i2s_rxBuf(struct I2s *i2s, void *buf, size_t len)
419 {
420         (void)i2s;
421
422         i2s_status |= I2S_STATUS_SINGLE_TRASF;
423
424         dmac_setSources(I2S_DMAC_CH, (uint32_t)&SSC_RHR, (uint32_t)buf);
425         dmac_configureDmac(I2S_DMAC_CH, len / I2S_WORD_BYTE_SIZE, I2S_RX_DMAC_CFG, I2S_RX_DMAC_CTRLA, I2S_RX_DMAC_CTRLB);
426         dmac_start(I2S_DMAC_CH);
427
428         SSC_CR = BV(SSC_TXEN) | BV(SSC_RXEN);
429 }
430
431 static int sam3_i2s_write(struct I2s *i2s, uint32_t sample)
432 {
433         (void)i2s;
434
435         SSC_CR = BV(SSC_TXEN);
436         while(!(SSC_SR & BV(SSC_TXRDY)))
437                 cpu_relax();
438
439         SSC_THR = sample;
440         return 0;
441 }
442
443 static uint32_t sam3_i2s_read(struct I2s *i2s)
444 {
445         (void)i2s;
446
447         SSC_CR = BV(SSC_RXEN);
448         while(!(SSC_SR & BV(SSC_RXRDY)))
449                 cpu_relax();
450
451         return SSC_RHR;
452 }
453
454
455 /* We divite for 2 because the min clock for i2s i MCLK/2 */
456 #define MCK_DIV     (CPU_FREQ / (CONFIG_SAMPLE_FREQ * CONFIG_WORD_BIT_SIZE * CONFIG_CHANNEL_NUM * 2))
457 #define DATALEN     ((CONFIG_WORD_BIT_SIZE - 1) & SSC_DATLEN_MASK)
458 #define DELAY       ((CONFIG_DELAY << SSC_STTDLY_SHIFT) & SSC_STTDLY_MASK)
459 #define PERIOD      ((CONFIG_PERIOD << (SSC_PERIOD_SHIFT)) & SSC_PERIOD_MASK)
460 #define DATNB       ((CONFIG_WORD_PER_FRAME << SSC_DATNB_SHIFT) & SSC_DATNB_MASK)
461 #define FSLEN       ((CONFIG_FRAME_SYNC_SIZE << SSC_FSLEN_SHIFT) & SSC_FSLEN_MASK)
462 #define EXTRA_FSLEN (CONFIG_EXTRA_FRAME_SYNC_SIZE << SSC_FSLEN_EXT)
463
464 void i2s_init(I2s *i2s, int channel)
465 {
466         (void)channel;
467         i2s->ctx.write = sam3_i2s_write;
468         i2s->ctx.tx_buf = sam3_i2s_txBuf;
469         i2s->ctx.tx_isFinish = sam3_i2s_isTxFinish;
470         i2s->ctx.tx_start = sam3_i2s_txStart;
471         i2s->ctx.tx_wait = sam3_i2s_txWait;
472         i2s->ctx.tx_stop = sam3_i2s_txStop;
473
474         i2s->ctx.read = sam3_i2s_read;
475         i2s->ctx.rx_buf = sam3_i2s_rxBuf;
476         i2s->ctx.rx_isFinish = sam3_i2s_isRxFinish;
477         i2s->ctx.rx_start = sam3_i2s_rxStart;
478         i2s->ctx.rx_wait = sam3_i2s_rxWait;
479         i2s->ctx.rx_stop = sam3_i2s_rxStop;
480
481         DB(i2s->ctx._type = I2S_SAM3X;)
482
483         I2S_STROBE_INIT();
484
485         PIOA_PDR = BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD);
486         PIO_PERIPH_SEL(PIOA_BASE, BV(SSC_TK) | BV(SSC_TF) | BV(SSC_TD), PIO_PERIPH_B);
487
488         PIOB_PDR = BV(SSC_RD) | BV(SSC_RF);
489         PIO_PERIPH_SEL(PIOB_BASE, BV(SSC_RD) | BV(SSC_RF), PIO_PERIPH_A);
490
491         /* clock the ssc */
492         pmc_periphEnable(SSC_ID);
493
494         /* reset device */
495         SSC_CR = BV(SSC_SWRST) | BV(SSC_TXDIS) | BV(SSC_RXDIS);
496
497         /* Set transmission clock */
498         SSC_CMR = MCK_DIV & SSC_DIV_MASK;
499         /* Set the transmission mode:
500          * - the clk is generate from master clock
501          * - clock only during transfer
502          * - transmit Clock Gating Selection none
503          * - DELAY cycle insert before starting transmission
504          * - generate frame sync each 2*(PERIOD + 1) tramit clock
505          * - Receive start on falling edge RF
506          */
507         SSC_TCMR = SSC_CKS_DIV | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_FALL_F;
508         /* Set the transmission frame mode:
509          * - data len DATALEN + 1
510          * - word per frame DATNB + 1
511          * - frame sync len FSLEN + (FSLEN_EXT * 16) + 1
512          * - DELAY cycle insert before starting transmission
513          * - MSB
514          * - Frame sync output selection negative
515          */
516         SSC_TFMR = DATALEN | DATNB | FSLEN | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
517
518
519         // Receiver should start on TX and take the clock from TK
520     SSC_RCMR = SSC_CKS_CLK | BV(SSC_CKI) | SSC_CKO_CONT | SSC_CKG_NONE | DELAY | PERIOD | SSC_START_TX;
521     SSC_RFMR = DATALEN | DATNB | FSLEN  | EXTRA_FSLEN | BV(SSC_MSBF) | SSC_FSOS_NEGATIVE;
522
523
524         SSC_IDR = 0xFFFFFFFF;
525
526         dmac_enableCh(I2S_DMAC_CH, i2s_dmac_irq);
527         event_initGeneric(&data_ready);
528 }